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