Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /* seterror.c - sasl_seterror split out because glue libraries
      9  *              can't pass varargs lists
     10  * Rob Siemborski
     11  * Tim Martin
     12  * split from common.c by Rolf Braun
     13  * $Id: seterror.c,v 1.7 2003/02/13 19:55:55 rjs3 Exp $
     14  */
     15 
     16 /*
     17  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     18  *
     19  * Redistribution and use in source and binary forms, with or without
     20  * modification, are permitted provided that the following conditions
     21  * are met:
     22  *
     23  * 1. Redistributions of source code must retain the above copyright
     24  *    notice, this list of conditions and the following disclaimer.
     25  *
     26  * 2. Redistributions in binary form must reproduce the above copyright
     27  *    notice, this list of conditions and the following disclaimer in
     28  *    the documentation and/or other materials provided with the
     29  *    distribution.
     30  *
     31  * 3. The name "Carnegie Mellon University" must not be used to
     32  *    endorse or promote products derived from this software without
     33  *    prior written permission. For permission or any other legal
     34  *    details, please contact
     35  *      Office of Technology Transfer
     36  *      Carnegie Mellon University
     37  *      5000 Forbes Avenue
     38  *      Pittsburgh, PA  15213-3890
     39  *      (412) 268-4387, fax: (412) 268-7395
     40  *      tech-transfer (at) andrew.cmu.edu
     41  *
     42  * 4. Redistributions of any form whatsoever must retain the following
     43  *    acknowledgment:
     44  *    "This product includes software developed by Computing Services
     45  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     46  *
     47  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     48  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     49  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     50  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     51  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     52  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     53  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     54  */
     55 
     56 #include <config.h>
     57 #include <stdio.h>
     58 #include <string.h>
     59 #include <stdlib.h>
     60 #include <limits.h>
     61 #ifdef HAVE_SYSLOG
     62 #include <syslog.h>
     63 #endif
     64 #include <stdarg.h>
     65 #include <ctype.h>
     66 
     67 #include <sasl.h>
     68 #include <saslutil.h>
     69 #include <saslplug.h>
     70 #include "saslint.h"
     71 
     72 #ifdef WIN32
     73 /* need to handle the fact that errno has been defined as a function
     74    in a dll, not an extern int */
     75 # ifdef errno
     76 #  undef errno
     77 # endif /* errno */
     78 #endif /* WIN32 */
     79 #ifdef HAVE_UNISTD_H
     80 #include <unistd.h>
     81 #endif
     82 
     83 #ifdef _SUN_SDK_
     84 #include "plugin_common.h"
     85 #include <wchar.h>
     86 #endif /* _SUN_SDK_ */
     87 
     88 /* this is apparently no longer a user function */
     89 static int _sasl_seterror_usererr(int saslerr)
     90 {
     91     /* Hide the difference in a username failure and a password failure */
     92     if (saslerr == SASL_NOUSER)
     93 	return SASL_BADAUTH;
     94 
     95     /* otherwise return the error given; no transform necessary */
     96     return saslerr;
     97 }
     98 
     99 /* set the error string which will be returned by sasl_errdetail() using
    100  *  syslog()-style formatting (e.g. printf-style with %m as the string form
    101  *  of an errno error)
    102  *
    103  *  primarily for use by server callbacks such as the sasl_authorize_t
    104  *  callback and internally to plug-ins
    105  *
    106  * This will also trigger a call to the SASL logging callback (if any)
    107  * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
    108  *
    109  * Messages should be sensitive to the current language setting.  If there
    110  * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
    111  * is used and use of RFC 2482 for mixed-language text is encouraged.
    112  *
    113  * if conn is NULL, function does nothing
    114  */
    115 void sasl_seterror(sasl_conn_t *conn,
    116 		   unsigned flags,
    117 		   const char *fmt, ...)
    118 {
    119   size_t outlen=0; /* current length of output buffer */
    120   int pos=0; /* current position in format string */
    121   int formatlen;
    122   int result;
    123   sasl_log_t *log_cb;
    124   void *log_ctx;
    125   int ival;
    126   char *cval;
    127   va_list ap; /* varargs thing */
    128   char **error_buf;
    129   size_t *error_buf_len;
    130 #ifdef _SUN_SDK_
    131   _sasl_global_context_t *gctx;
    132 #endif /* _SUN_SDK_ */
    133 #ifdef _INTEGRATED_SOLARIS_
    134   sasl_getsimple_t *simple_cb;
    135   void *simple_context;
    136   const char *lang = NULL;
    137   int ret;
    138   const sasl_utils_t *utils;
    139   int char_len;
    140   char *utf8_buf;
    141   const char *orig_fmt = fmt;
    142   int is_client;
    143 #endif /* _INTEGRATED_SOLARIS_ */
    144 
    145   if(!conn) {
    146 #ifndef SASL_OSX_CFMGLUE
    147       if(!(flags & SASL_NOLOG)) {
    148 	  /* See if we have a logging callback... */
    149 	  result = _sasl_getcallback(NULL, SASL_CB_LOG, &log_cb, &log_ctx);
    150 	  if (result == SASL_OK && ! log_cb)
    151 	      result = SASL_FAIL;
    152 	  if (result != SASL_OK)
    153 	      return;
    154 
    155 	  log_cb(log_ctx, SASL_LOG_FAIL,
    156 		 "No sasl_conn_t passed to sasl_seterror");
    157       }
    158 #endif /* SASL_OSX_CFMGLUE */
    159       return;
    160   } else if(!fmt) return;
    161 
    162 #ifdef _SUN_SDK_
    163   gctx = conn->gctx;
    164 #endif /* _SUN_SDK_ */
    165 
    166 #ifdef _INTEGRATED_SOLARIS_
    167   if (conn->type == SASL_CONN_SERVER) {
    168     utils = ((sasl_server_conn_t *)conn)->sparams->utils;
    169     is_client = 0;
    170   } else if (conn->type == SASL_CONN_CLIENT) {
    171     utils = ((sasl_client_conn_t *)conn)->cparams->utils;
    172     is_client = 1;
    173   } else
    174     utils = NULL;
    175 
    176   if (utils != NULL) {
    177     ret = utils->getcallback(conn, SASL_CB_LANGUAGE, &simple_cb,
    178 	&simple_context);
    179 
    180     if (ret == SASL_OK && simple_cb)
    181 	(void) simple_cb(simple_context, SASL_CB_LANGUAGE, &lang, NULL);
    182 
    183     if (use_locale(lang, is_client))
    184 	fmt = dgettext(TEXT_DOMAIN, fmt);
    185   }
    186 #endif /* _INTEGRATED_SOLARIS_ */
    187 
    188 /* we need to use a back end function to get the buffer because the
    189    cfm glue can't be rooting around in the internal structs */
    190   _sasl_get_errorbuf(conn, &error_buf, &error_buf_len);
    191 
    192   formatlen = strlen(fmt);
    193 
    194   va_start(ap, fmt); /* start varargs */
    195 
    196   while(pos<formatlen)
    197   {
    198     if (fmt[pos]!='%') /* regular character */
    199     {
    200 #ifdef _INTEGRATED_SOLARIS_
    201       char_len =  mbrlen(fmt + pos, formatlen - pos, NULL);
    202       result = _buf_alloc(error_buf, error_buf_len, outlen + char_len);
    203       if (result != SASL_OK)
    204 	return;
    205       while (char_len-- > 0) {
    206 	(*error_buf)[outlen]=fmt[pos];
    207 	outlen++;
    208 	pos++;
    209       }
    210 #else
    211       result = _buf_alloc(error_buf, error_buf_len, outlen+1);
    212       if (result != SASL_OK)
    213 	return;
    214       (*error_buf)[outlen]=fmt[pos];
    215       outlen++;
    216       pos++;
    217 #endif /* _INTEGRATED_SOLARIS_ */
    218     } else { /* formating thing */
    219       int done=0;
    220       char frmt[10];
    221       int frmtpos=1;
    222       char tempbuf[21];
    223       frmt[0]='%';
    224       pos++;
    225 
    226       while (done==0)
    227       {
    228 	switch(fmt[pos])
    229 	  {
    230 	  case 's': /* need to handle this */
    231 	    cval = va_arg(ap, char *); /* get the next arg */
    232 	    result = _sasl_add_string(error_buf, error_buf_len,
    233 				      &outlen, cval);
    234 
    235 	    if (result != SASL_OK) /* add the string */
    236 	      return;
    237 
    238 	    done=1;
    239 	    break;
    240 
    241 	  case '%': /* double % output the '%' character */
    242 	    result = _buf_alloc(error_buf, error_buf_len, outlen+1);
    243 	    if (result != SASL_OK)
    244 	      return;
    245 	    (*error_buf)[outlen]='%';
    246 	    outlen++;
    247 	    done=1;
    248 	    break;
    249 
    250 	  case 'm': /* insert the errno string */
    251 	    result = _sasl_add_string(error_buf, error_buf_len,
    252 				      &outlen,
    253 				      strerror(va_arg(ap, int)));
    254 	    if (result != SASL_OK)
    255 	      return;
    256 	    done=1;
    257 	    break;
    258 
    259 	  case 'z': /* insert the sasl error string */
    260 #ifdef _INTEGRATED_SOLARIS_
    261 	    result = _sasl_add_string(error_buf, error_buf_len,	&outlen,
    262 			 (char *)sasl_errstring(_sasl_seterror_usererr(
    263 					        va_arg(ap, int)), lang, NULL));
    264 #else
    265 	    result = _sasl_add_string(error_buf, error_buf_len,	&outlen,
    266 			 (char *)sasl_errstring(_sasl_seterror_usererr(
    267 					        va_arg(ap, int)),NULL,NULL));
    268 #endif /* _INTEGRATED_SOLARIS_ */
    269 	    if (result != SASL_OK)
    270 	      return;
    271 	    done=1;
    272 	    break;
    273 
    274 	  case 'c':
    275 #ifndef _SUN_SDK_
    276 	    frmt[frmtpos++]=fmt[pos];
    277 	    frmt[frmtpos]=0;
    278 #endif /* _SUN_SDK_ */
    279 	    tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
    280 	    tempbuf[1]='\0';
    281 
    282 	    /* now add the character */
    283 	    result = _sasl_add_string(error_buf, error_buf_len,
    284 				      &outlen, tempbuf);
    285 	    if (result != SASL_OK)
    286 	      return;
    287 	    done=1;
    288 	    break;
    289 
    290 	  case 'd':
    291 	  case 'i':
    292 	    frmt[frmtpos++]=fmt[pos];
    293 	    frmt[frmtpos]=0;
    294 	    ival = va_arg(ap, int); /* get the next arg */
    295 
    296 	    snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
    297 	    /* now add the string */
    298 	    result = _sasl_add_string(error_buf, error_buf_len,
    299 				      &outlen, tempbuf);
    300 	    if (result != SASL_OK)
    301 	      return;
    302 	    done=1;
    303 
    304 	    break;
    305 	  default:
    306 	    frmt[frmtpos++]=fmt[pos]; /* add to the formating */
    307 	    frmt[frmtpos]=0;
    308 #ifdef _SUN_SDK_
    309 	    if (frmtpos > sizeof (frmt) - 2)
    310 #else
    311 	    if (frmtpos>9)
    312 #endif	/* _SUN_SDK_ */
    313 	      done=1;
    314 	  }
    315 	pos++;
    316 	if (pos>formatlen)
    317 	  done=1;
    318       }
    319 
    320     }
    321   }
    322 
    323   (*error_buf)[outlen]='\0'; /* put 0 at end */
    324 
    325   va_end(ap);
    326 
    327 #ifdef _INTEGRATED_SOLARIS_
    328   if (orig_fmt != fmt) {
    329     utf8_buf = local_to_utf(utils, *error_buf);
    330     if (utf8_buf != NULL) {
    331       outlen = strlen(utf8_buf);
    332       result = SASL_OK;
    333       if (outlen >= *error_buf_len)
    334       result = _buf_alloc(error_buf, error_buf_len, outlen+1);
    335       if (result != SASL_OK) {
    336 	utils->free(utf8_buf);
    337 	return;
    338       }
    339       strcpy(*error_buf, utf8_buf);
    340       utils->free(utf8_buf);
    341     }
    342   }
    343 #endif /* _INTEGRATED_SOLARIS_ */
    344 
    345 #ifndef SASL_OSX_CFMGLUE
    346   if(!(flags & SASL_NOLOG)) {
    347       /* See if we have a logging callback... */
    348       result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
    349       if (result == SASL_OK && ! log_cb)
    350 	  result = SASL_FAIL;
    351       if (result != SASL_OK)
    352 	  return;
    353 
    354       result = log_cb(log_ctx, SASL_LOG_FAIL, conn->error_buf);
    355   }
    356 #endif /* SASL_OSX_CFMGLUE */
    357 }
    358