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