xref: /illumos-gate/usr/src/lib/libsasl/lib/seterror.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
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@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