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 */
_sasl_seterror_usererr(int saslerr)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 */
sasl_seterror(sasl_conn_t * conn,unsigned flags,const char * fmt,...)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