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