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 */ 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 */ 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