Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2007 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 /* common.c - Functions that are common to server and clinet
      9  * Rob Siemborski
     10  * Tim Martin
     11  * $Id: common.c,v 1.92 2003/04/16 19:36:00 rjs3 Exp $
     12  */
     13 /*
     14  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  *
     20  * 1. Redistributions of source code must retain the above copyright
     21  *    notice, this list of conditions and the following disclaimer.
     22  *
     23  * 2. Redistributions in binary form must reproduce the above copyright
     24  *    notice, this list of conditions and the following disclaimer in
     25  *    the documentation and/or other materials provided with the
     26  *    distribution.
     27  *
     28  * 3. The name "Carnegie Mellon University" must not be used to
     29  *    endorse or promote products derived from this software without
     30  *    prior written permission. For permission or any other legal
     31  *    details, please contact
     32  *      Office of Technology Transfer
     33  *      Carnegie Mellon University
     34  *      5000 Forbes Avenue
     35  *      Pittsburgh, PA  15213-3890
     36  *      (412) 268-4387, fax: (412) 268-7395
     37  *      tech-transfer (at) andrew.cmu.edu
     38  *
     39  * 4. Redistributions of any form whatsoever must retain the following
     40  *    acknowledgment:
     41  *    "This product includes software developed by Computing Services
     42  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     43  *
     44  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     45  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     46  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     47  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     48  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     49  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     50  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     51  */
     52 
     53 #include <config.h>
     54 #include <stdio.h>
     55 #include <string.h>
     56 #include <stdlib.h>
     57 #include <limits.h>
     58 #ifdef HAVE_SYSLOG
     59 #include <syslog.h>
     60 #endif
     61 #include <stdarg.h>
     62 #include <ctype.h>
     63 
     64 #include <sasl.h>
     65 #include <saslutil.h>
     66 #include <saslplug.h>
     67 #include "saslint.h"
     68 
     69 #ifdef _SUN_SDK_
     70 #include "md5_private.h"
     71 #include "hmac-md5.h"
     72 #include "plugin_common.h"
     73 #endif
     74 
     75 
     76 #ifdef WIN32
     77 /* need to handle the fact that errno has been defined as a function
     78    in a dll, not an extern int */
     79 # ifdef errno
     80 #  undef errno
     81 # endif /* errno */
     82 #endif /* WIN32 */
     83 #ifdef HAVE_UNISTD_H
     84 #include <unistd.h>
     85 #endif
     86 
     87 static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
     88 
     89 #ifdef _SUN_SDK_
     90 DEFINE_STATIC_MUTEX(global_mutex);
     91 DEFINE_STATIC_MUTEX(malloc_global_mutex);
     92 static void _sasl_dispose_context(_sasl_global_context_t *ctx);
     93 static int _sasl_getconf(void *context, const char **conf);
     94 
     95 #ifdef _INTEGRATED_SOLARIS_
     96 static pthread_key_t errstring_key = PTHREAD_ONCE_KEY_NP;
     97 #endif /* _INTEGRATED_SOLARIS_ */
     98 #else
     99 static const char build_ident[] = "$Build: libsasl " PACKAGE "-" VERSION " $";
    100 
    101 /* It turns out to be conveinent to have a shared sasl_utils_t */
    102 LIBSASL_VAR const sasl_utils_t *sasl_global_utils = NULL;
    103 
    104 /* Should be a null-terminated array that lists the available mechanisms */
    105 static char **global_mech_list = NULL;
    106 
    107 void *free_mutex = NULL;
    108 
    109 int (*_sasl_client_cleanup_hook)(void) = NULL;
    110 int (*_sasl_server_cleanup_hook)(void) = NULL;
    111 int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
    112 int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
    113 
    114 sasl_allocation_utils_t _sasl_allocation_utils={
    115   (sasl_malloc_t *)  &malloc,
    116   (sasl_calloc_t *)  &calloc,
    117   (sasl_realloc_t *) &realloc,
    118   (sasl_free_t *) &free
    119 };
    120 #endif /* _SUN_SDK_ */
    121 
    122 #ifdef USE_PTHREADS
    123 static void *sasl_mutex_alloc(void)
    124 {
    125     pthread_mutex_t *mutex =
    126 	(pthread_mutex_t *)malloc(sizeof (pthread_mutex_t));
    127 
    128     if (mutex != NULL) {
    129 	if (pthread_mutex_init(mutex, NULL) != 0) {
    130 	    free(mutex);
    131 	    mutex = NULL;
    132 	}
    133     }
    134     return (mutex);
    135 }
    136 
    137 static int sasl_mutex_lock(void *mutex)
    138 {
    139     int ret = SASL_BADPARAM;
    140 
    141     if (mutex != NULL)
    142 	ret = pthread_mutex_lock((pthread_mutex_t *)mutex);
    143 
    144     return ret;
    145 }
    146 
    147 static int sasl_mutex_unlock(void *mutex)
    148 {
    149     int ret = SASL_BADPARAM;
    150 
    151     if (mutex != NULL)
    152 	ret = pthread_mutex_unlock((pthread_mutex_t *)mutex);
    153 
    154     return ret;
    155 }
    156 
    157 static void sasl_mutex_free(void *mutex __attribute__((unused)))
    158 {
    159   if (mutex != NULL) {
    160      pthread_mutex_destroy((pthread_mutex_t *)mutex);
    161      free(mutex);
    162   }
    163 }
    164 #else
    165 /* Intenal mutex functions do as little as possible (no thread protection) */
    166 static void *sasl_mutex_alloc(void)
    167 {
    168   return (void *)0x1;
    169 }
    170 
    171 static int sasl_mutex_lock(void *mutex __attribute__((unused)))
    172 {
    173     return SASL_OK;
    174 }
    175 
    176 static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
    177 {
    178     return SASL_OK;
    179 }
    180 
    181 static void sasl_mutex_free(void *mutex __attribute__((unused)))
    182 {
    183     return;
    184 }
    185 #endif /* USE_PTHREADS */
    186 
    187 #ifndef _SUN_SDK_
    188 sasl_mutex_utils_t _sasl_mutex_utils={
    189   &sasl_mutex_alloc,
    190   &sasl_mutex_lock,
    191   &sasl_mutex_unlock,
    192   &sasl_mutex_free
    193 };
    194 #endif /* !_SUN_SDK_ */
    195 
    196 void sasl_set_mutex(sasl_mutex_alloc_t *n, sasl_mutex_lock_t *l,
    197 		    sasl_mutex_unlock_t *u, sasl_mutex_free_t *d)
    198 {
    199 #ifdef _SUN_SDK_
    200   _sasl_global_context_t *gctx =  _sasl_gbl_ctx();
    201 
    202   gctx->sasl_mutex_utils.alloc=n;
    203   gctx->sasl_mutex_utils.lock=l;
    204   gctx->sasl_mutex_utils.unlock=u;
    205   gctx->sasl_mutex_utils.free=d;
    206 #else
    207   _sasl_mutex_utils.alloc=n;
    208   _sasl_mutex_utils.lock=l;
    209   _sasl_mutex_utils.unlock=u;
    210   _sasl_mutex_utils.free=d;
    211 #endif
    212 }
    213 
    214 /* copy a string to malloced memory */
    215 #ifdef _SUN_SDK_
    216 int __sasl_strdup(const _sasl_global_context_t *gctx, const char *in,
    217 	char **out, size_t *outlen)
    218 #else
    219 int _sasl_strdup(const char *in, char **out, size_t *outlen)
    220 #endif /* _SUN_SDK_ */
    221 {
    222   size_t len = strlen(in);
    223   if (outlen) *outlen = len;
    224   *out=sasl_ALLOC(len + 1);
    225   if (! *out) return SASL_NOMEM;
    226   strcpy((char *) *out, in);
    227   return SASL_OK;
    228 }
    229 
    230 /* adds a string to the buffer; reallocing if need be */
    231 #ifdef _SUN_SDK_
    232 int __sasl_add_string(const _sasl_global_context_t *gctx, char **out,
    233 		     size_t *alloclen, size_t *outlen,
    234 		     const char *add)
    235 #else
    236 int _sasl_add_string(char **out, size_t *alloclen,
    237 		     size_t *outlen, const char *add)
    238 #endif /* _SUN_SDK_ */
    239 {
    240   size_t addlen;
    241 
    242   if (add==NULL) add = "(null)";
    243 
    244   addlen=strlen(add); /* only compute once */
    245   if (_buf_alloc(out, alloclen, (*outlen)+addlen)!=SASL_OK)
    246     return SASL_NOMEM;
    247 
    248   strncpy(*out + *outlen, add, addlen);
    249   *outlen += addlen;
    250 
    251   return SASL_OK;
    252 }
    253 
    254 /* return the version of the cyrus sasl library as compiled,
    255  * using 32 bits: high byte is major version, second byte is minor version,
    256  * low 16 bits are step # */
    257 void sasl_version(const char **implementation, int *version)
    258 {
    259 #ifdef _SUN_SDK_
    260     const char *implementation_string = "Sun SASL";
    261 #else
    262     const char *implementation_string = "Cyrus SASL";
    263 #endif /* _SUN_SDK_ */
    264     if(implementation) *implementation = implementation_string;
    265     if(version) *version = (SASL_VERSION_MAJOR << 24) |
    266 		           (SASL_VERSION_MINOR << 16) |
    267 		           (SASL_VERSION_STEP);
    268 }
    269 
    270 /* security-encode a regular string.  Mostly a wrapper for sasl_encodev */
    271 /* output is only valid until next call to sasl_encode or sasl_encodev */
    272 int sasl_encode(sasl_conn_t *conn, const char *input,
    273 		unsigned inputlen,
    274 		const char **output, unsigned *outputlen)
    275 {
    276     int result;
    277     struct iovec tmp;
    278 
    279     if(!conn) return SASL_BADPARAM;
    280     if(!input || !inputlen || !output || !outputlen)
    281 	PARAMERROR(conn);
    282 
    283     /* maxoutbuf checking is done in sasl_encodev */
    284 
    285     /* Note: We are casting a const pointer here, but it's okay
    286      * because we believe people downstream of us are well-behaved, and the
    287      * alternative is an absolute mess, performance-wise. */
    288     tmp.iov_base = (void *)input;
    289     tmp.iov_len = inputlen;
    290 
    291     result = sasl_encodev(conn, &tmp, 1, output, outputlen);
    292 
    293     RETURN(conn, result);
    294 }
    295 
    296 /* security-encode an iovec */
    297 /* output is only valid until next call to sasl_encode or sasl_encodev */
    298 int sasl_encodev(sasl_conn_t *conn,
    299 		 const struct iovec *invec, unsigned numiov,
    300 		 const char **output, unsigned *outputlen)
    301 {
    302 #ifdef _SUN_SDK_
    303     int result = SASL_FAIL;
    304 #else
    305     int result;
    306 #endif /* _SUN_SDK_ */
    307     unsigned i;
    308     size_t total_size = 0;
    309 
    310     /* EXPORT DELETE START */
    311     if (!conn) return SASL_BADPARAM;
    312     if (! invec || ! output || ! outputlen || numiov < 1)
    313 	PARAMERROR(conn);
    314 
    315     if(!conn->props.maxbufsize) {
    316 #ifdef _SUN_SDK_
    317 	_sasl_log(conn, SASL_LOG_ERR,
    318 		  "called sasl_encode[v] with application that does not support security layers");
    319 #else
    320 	sasl_seterror(conn, 0,
    321 		      "called sasl_encode[v] with application that does not support security layers");
    322 #endif /* _SUN_SDK_ */
    323 	return SASL_TOOWEAK;
    324     }
    325 
    326     /* This might be better to check on a per-plugin basis, but I think
    327      * it's cleaner and more effective here.  It also encourages plugins
    328      * to be honest about what they accept */
    329 
    330     for(i=0; i<numiov;i++) {
    331 #ifdef _SUN_SDK_
    332 	if (invec[i].iov_base == NULL)
    333 	    PARAMERROR(conn);
    334 #endif /* _SUN_SDK_ */
    335 	total_size += invec[i].iov_len;
    336     }
    337     if(total_size > conn->oparams.maxoutbuf)
    338 	PARAMERROR(conn);
    339 
    340     if(conn->oparams.encode == NULL)  {
    341 #ifdef _SUN_SDK_
    342 	result = _iovec_to_buf(conn->gctx, invec, numiov, &conn->encode_buf);
    343 #else
    344 	result = _iovec_to_buf(invec, numiov, &conn->encode_buf);
    345 #endif /* _SUN_SDK_ */
    346 	if(result != SASL_OK) INTERROR(conn, result);
    347 
    348 	*output = conn->encode_buf->data;
    349 	*outputlen = conn->encode_buf->curlen;
    350 
    351     /* CRYPT DELETE START */
    352 #ifdef _INTEGRATED_SOLARIS_
    353     } else if (!conn->sun_reg) {
    354 	    INTERROR(conn, SASL_FAIL);
    355 #endif /* _INTEGRATED_SOLARIS_ */
    356     /* CRYPT DELETE END */
    357     } else {
    358 	result = conn->oparams.encode(conn->context, invec, numiov,
    359 				      output, outputlen);
    360     }
    361     /* EXPORT DELETE END */
    362 
    363     RETURN(conn, result);
    364 }
    365 
    366 /* output is only valid until next call to sasl_decode */
    367 int sasl_decode(sasl_conn_t *conn,
    368 		const char *input, unsigned inputlen,
    369 		const char **output, unsigned *outputlen)
    370 {
    371     int result;
    372     /* EXPORT DELETE START */
    373 #ifdef _SUN_SDK_
    374     const _sasl_global_context_t *gctx;
    375 #endif /* _SUN_SDK_ */
    376 
    377     if(!conn) return SASL_BADPARAM;
    378     if(!input || !output || !outputlen)
    379 	PARAMERROR(conn);
    380 
    381 #ifdef _SUN_SDK_
    382     gctx = conn->gctx;
    383 #endif /* _SUN_SDK_ */
    384 
    385     if(!conn->props.maxbufsize) {
    386 #ifdef _SUN_SDK_
    387 	_sasl_log(conn, SASL_LOG_ERR,
    388 		  "called sasl_decode with application that does not support security layers");
    389 #else
    390 	sasl_seterror(conn, 0,
    391 		      "called sasl_decode with application that does not support security layers");
    392 #endif /* _SUN_SDK_ */
    393 	RETURN(conn, SASL_TOOWEAK);
    394     }
    395 
    396     if(conn->oparams.decode == NULL)
    397     {
    398 	/* Since we know how long the output is maximally, we can
    399 	 * just allocate it to begin with, and never need another
    400          * allocation! */
    401 
    402 	/* However, if they pass us more than they actually can take,
    403 	 * we cannot help them... */
    404 	if(inputlen > conn->props.maxbufsize) {
    405 #ifdef _SUN_SDK_
    406 	    _sasl_log(conn, SASL_LOG_ERR,
    407 		      "input too large for default sasl_decode");
    408 #else
    409 	    sasl_seterror(conn, 0,
    410 			  "input too large for default sasl_decode");
    411 #endif /* _SUN_SDK_ */
    412 	    RETURN(conn,SASL_BUFOVER);
    413 	}
    414 
    415 	if(!conn->decode_buf)
    416 	    conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
    417 	if(!conn->decode_buf)
    418 	    MEMERROR(conn);
    419 
    420 	memcpy(conn->decode_buf, input, inputlen);
    421 	conn->decode_buf[inputlen] = '\0';
    422 	*output = conn->decode_buf;
    423 	*outputlen = inputlen;
    424 
    425         return SASL_OK;
    426     /* CRYPT DELETE START */
    427 #ifdef _INTEGRATED_SOLARIS_
    428     } else if (!conn->sun_reg) {
    429 	    INTERROR(conn, SASL_FAIL);
    430 #endif /* _INTEGRATED_SOLARIS_ */
    431     /* CRYPT DELETE END */
    432     } else {
    433         result = conn->oparams.decode(conn->context, input, inputlen,
    434                                       output, outputlen);
    435 
    436 	/* NULL an empty buffer (for misbehaved applications) */
    437 	if (*outputlen == 0) *output = NULL;
    438 
    439         RETURN(conn, result);
    440     }
    441 
    442     /* EXPORT DELETE END */
    443 #ifdef _SUN_SDK_
    444     return SASL_FAIL;
    445 #else
    446     INTERROR(conn, SASL_FAIL);
    447 #endif	/* _SUN_SDK_ */
    448 }
    449 
    450 
    451 void
    452 sasl_set_alloc(sasl_malloc_t *m,
    453 	       sasl_calloc_t *c,
    454 	       sasl_realloc_t *r,
    455 	       sasl_free_t *f)
    456 {
    457 #ifdef _SUN_SDK_
    458   _sasl_global_context_t *gctx =  _sasl_gbl_ctx();
    459 
    460   LOCK_MUTEX(&malloc_global_mutex);
    461   gctx->sasl_allocation_utils.malloc=m;
    462   gctx->sasl_allocation_utils.calloc=c;
    463   gctx->sasl_allocation_utils.realloc=r;
    464   gctx->sasl_allocation_utils.free=f;
    465   UNLOCK_MUTEX(&malloc_global_mutex);
    466 #else
    467   _sasl_allocation_utils.malloc=m;
    468   _sasl_allocation_utils.calloc=c;
    469   _sasl_allocation_utils.realloc=r;
    470   _sasl_allocation_utils.free=f;
    471 #endif /* _SUN_SDK_ */
    472 }
    473 
    474 void sasl_done(void)
    475 {
    476 #ifdef _SUN_SDK_
    477    _sasl_dispose_context(_sasl_gbl_ctx());
    478 #else
    479     if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
    480 	_sasl_server_idle_hook = NULL;
    481 	_sasl_server_cleanup_hook = NULL;
    482     }
    483 
    484     if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
    485 	_sasl_client_idle_hook = NULL;
    486 	_sasl_client_cleanup_hook = NULL;
    487     }
    488 
    489     if(_sasl_server_cleanup_hook || _sasl_client_cleanup_hook)
    490 	return;
    491 
    492 
    493     _sasl_canonuser_free();
    494     _sasl_done_with_plugins();
    495 
    496 #ifdef _SUN_SDK_
    497     sasl_config_free();
    498 #endif /* _SUN_SDK_ */
    499 
    500     sasl_MUTEX_FREE(free_mutex);
    501     free_mutex = NULL;
    502 
    503     _sasl_free_utils(&sasl_global_utils);
    504 
    505     if(global_mech_list) sasl_FREE(global_mech_list);
    506     global_mech_list = NULL;
    507 #endif /* _SUN_SDK_ */
    508 }
    509 
    510 /* fills in the base sasl_conn_t info */
    511 int _sasl_conn_init(sasl_conn_t *conn,
    512 		    const char *service,
    513 		    unsigned int flags,
    514 		    enum Sasl_conn_type type,
    515 		    int (*idle_hook)(sasl_conn_t *conn),
    516 		    const char *serverFQDN,
    517 		    const char *iplocalport,
    518 		    const char *ipremoteport,
    519 		    const sasl_callback_t *callbacks,
    520 		    const sasl_global_callbacks_t *global_callbacks) {
    521   int result = SASL_OK;
    522 #ifdef _SUN_SDK_
    523   const _sasl_global_context_t *gctx = conn->gctx;
    524 #endif /* _SUN_SDK_ */
    525 
    526   conn->type = type;
    527 
    528   result = _sasl_strdup(service, &conn->service, NULL);
    529   if (result != SASL_OK)
    530       MEMERROR(conn);
    531 
    532   memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
    533   memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
    534 
    535   conn->flags = flags;
    536 
    537   result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
    538   if(result != SASL_OK)
    539       RETURN(conn, result);
    540 
    541   result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
    542   if(result != SASL_OK)
    543       RETURN(conn, result);
    544 
    545   conn->encode_buf = NULL;
    546   conn->context = NULL;
    547 #ifndef _SUN_SDK_
    548   conn->secret = NULL;
    549 #endif /* !_SUN_SDK_ */
    550   conn->idle_hook = idle_hook;
    551   conn->callbacks = callbacks;
    552   conn->global_callbacks = global_callbacks;
    553 
    554   memset(&conn->props, 0, sizeof(conn->props));
    555 
    556   /* Start this buffer out as an empty string */
    557   conn->error_code = SASL_OK;
    558   conn->errdetail_buf = conn->error_buf = NULL;
    559   conn->errdetail_buf_len = conn->error_buf_len = 150;
    560 
    561   result = _buf_alloc(&conn->error_buf, &conn->error_buf_len, 150);
    562   if(result != SASL_OK) MEMERROR(conn);
    563   result = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, 150);
    564   if(result != SASL_OK) MEMERROR(conn);
    565 
    566   conn->error_buf[0] = '\0';
    567   conn->errdetail_buf[0] = '\0';
    568 
    569   conn->decode_buf = NULL;
    570 
    571   if(serverFQDN) {
    572       result = _sasl_strdup(serverFQDN, &conn->serverFQDN, NULL);
    573   } else if (conn->type == SASL_CONN_SERVER) {
    574       /* We can fake it because we *are* the server */
    575       char name[MAXHOSTNAMELEN];
    576       memset(name, 0, sizeof(name));
    577       gethostname(name, MAXHOSTNAMELEN);
    578 
    579       result = _sasl_strdup(name, &conn->serverFQDN, NULL);
    580   } else {
    581       conn->serverFQDN = NULL;
    582   }
    583 
    584 
    585   if(result != SASL_OK) MEMERROR( conn );
    586 
    587 #ifdef _SUN_SDK_
    588   return (SASL_OK);
    589 #else
    590   RETURN(conn, SASL_OK);
    591 #endif /* _SUN_SDK_ */
    592 }
    593 
    594 #ifdef _SUN_SDK_
    595 int _sasl_common_init(_sasl_global_context_t *gctx,
    596 		      sasl_global_callbacks_t *global_callbacks,
    597 		      int server)
    598 {
    599     int result;
    600     sasl_utils_t *sasl_global_utils;
    601 
    602     sasl_global_utils = (sasl_utils_t *)gctx->sasl_canonusr_global_utils;
    603 
    604     if(!sasl_global_utils) {
    605         sasl_global_utils = _sasl_alloc_utils(gctx, NULL, global_callbacks);
    606         if(sasl_global_utils == NULL) return SASL_NOMEM;
    607 	gctx->sasl_canonusr_global_utils = sasl_global_utils;
    608     }
    609 
    610     if (server) {
    611 	sasl_global_utils = (sasl_utils_t *)gctx->sasl_server_global_utils;
    612 
    613 	if(!sasl_global_utils) {
    614             sasl_global_utils = _sasl_alloc_utils(gctx, NULL, global_callbacks);
    615             if(sasl_global_utils == NULL) return SASL_NOMEM;
    616 	    gctx->sasl_server_global_utils = sasl_global_utils;
    617 	}
    618     }
    619 
    620     /* Init the canon_user plugin */
    621     result = _sasl_canonuser_add_plugin(gctx, "INTERNAL",
    622 	internal_canonuser_init);
    623     if(result != SASL_OK) return result;
    624 
    625     if (!gctx->free_mutex)
    626         gctx->free_mutex = sasl_MUTEX_ALLOC();
    627     if (!gctx->free_mutex) return SASL_FAIL;
    628 
    629     return SASL_OK;
    630 }
    631 #else
    632 int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
    633 {
    634     int result;
    635 
    636     /* Setup the global utilities */
    637     if(!sasl_global_utils) {
    638 	sasl_global_utils = _sasl_alloc_utils(NULL, global_callbacks);
    639 	if(sasl_global_utils == NULL) return SASL_NOMEM;
    640     }
    641 
    642     /* Init the canon_user plugin */
    643     result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
    644     if(result != SASL_OK) return result;
    645 
    646     if (!free_mutex)
    647 	free_mutex = sasl_MUTEX_ALLOC();
    648     if (!free_mutex) return SASL_FAIL;
    649 
    650     return SASL_OK;
    651 }
    652 #endif /* _SUN_SDK_ */
    653 
    654 /* dispose connection state, sets it to NULL
    655  *  checks for pointer to NULL
    656  */
    657 void sasl_dispose(sasl_conn_t **pconn)
    658 {
    659   int result;
    660 #ifdef _SUN_SDK_
    661   _sasl_global_context_t *gctx;
    662   void *free_mutex;
    663 #endif /* _SUN_SDK_ */
    664 
    665   if (! pconn) return;
    666   if (! *pconn) return;
    667 
    668   /* serialize disposes. this is necessary because we can't
    669      dispose of conn->mutex if someone else is locked on it */
    670 #ifdef _SUN_SDK_
    671   gctx = (*pconn)->gctx;
    672   free_mutex = gctx->free_mutex;
    673 #endif /* _SUN_SDK_ */
    674   result = sasl_MUTEX_LOCK(free_mutex);
    675   if (result!=SASL_OK) return;
    676 
    677   /* *pconn might have become NULL by now */
    678 #ifdef _SUN_SDK_
    679   if (! (*pconn)) {
    680 	sasl_MUTEX_UNLOCK(free_mutex);
    681 	return;
    682   }
    683 #else
    684   if (! (*pconn)) return;
    685 #endif /* _SUN_SDK_ */
    686 
    687   (*pconn)->destroy_conn(*pconn);
    688   sasl_FREE(*pconn);
    689   *pconn=NULL;
    690 
    691   sasl_MUTEX_UNLOCK(free_mutex);
    692 }
    693 
    694 void _sasl_conn_dispose(sasl_conn_t *conn) {
    695 #ifdef _SUN_SDK_
    696   const _sasl_global_context_t *gctx = conn->gctx;
    697 #endif /* _SUN_SDK_ */
    698 
    699   if (conn->serverFQDN)
    700       sasl_FREE(conn->serverFQDN);
    701 
    702   if (conn->external.auth_id)
    703       sasl_FREE(conn->external.auth_id);
    704 
    705   if(conn->encode_buf) {
    706       if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
    707       sasl_FREE(conn->encode_buf);
    708   }
    709 
    710   if(conn->error_buf)
    711       sasl_FREE(conn->error_buf);
    712 
    713   if(conn->errdetail_buf)
    714       sasl_FREE(conn->errdetail_buf);
    715 
    716   if(conn->decode_buf)
    717       sasl_FREE(conn->decode_buf);
    718 
    719   if(conn->mechlist_buf)
    720       sasl_FREE(conn->mechlist_buf);
    721 
    722   if(conn->service)
    723       sasl_FREE(conn->service);
    724 
    725   /* oparams sub-members should be freed by the plugin, in so much
    726    * as they were allocated by the plugin */
    727 }
    728 
    729 
    730 /* get property from SASL connection state
    731  *  propnum       -- property number
    732  *  pvalue        -- pointer to value
    733  * returns:
    734  *  SASL_OK       -- no error
    735  *  SASL_NOTDONE  -- property not available yet
    736  *  SASL_BADPARAM -- bad property number
    737  */
    738 int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
    739 {
    740   int result = SASL_OK;
    741   sasl_getopt_t *getopt;
    742   void *context;
    743 
    744   if (! conn) return SASL_BADPARAM;
    745   if (! pvalue) PARAMERROR(conn);
    746 
    747   switch(propnum)
    748   {
    749   case SASL_SSF:
    750     /* EXPORT DELETE START */
    751     /* CRYPT DELETE START */
    752 #ifdef _INTEGRATED_SOLARIS_
    753       if (!conn->sun_reg)
    754 	conn->oparams.mech_ssf = 0;
    755 #endif /* _INTEGRATED_SOLARIS_ */
    756     /* CRYPT DELETE END */
    757     /* EXPORT DELETE END */
    758       *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
    759       break;
    760   case SASL_MAXOUTBUF:
    761       *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
    762       break;
    763   case SASL_GETOPTCTX:
    764       result = _sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context);
    765       if(result != SASL_OK) break;
    766 
    767       *(void **)pvalue = context;
    768       break;
    769   case SASL_CALLBACK:
    770       *(const sasl_callback_t **)pvalue = conn->callbacks;
    771       break;
    772   case SASL_IPLOCALPORT:
    773       if(conn->got_ip_local)
    774 	  *(const char **)pvalue = conn->iplocalport;
    775       else {
    776 	  *(const char **)pvalue = NULL;
    777 	  result = SASL_NOTDONE;
    778       }
    779       break;
    780   case SASL_IPREMOTEPORT:
    781       if(conn->got_ip_remote)
    782 	  *(const char **)pvalue = conn->ipremoteport;
    783       else {
    784 	  *(const char **)pvalue = NULL;
    785 	  result = SASL_NOTDONE;
    786       }
    787       break;
    788   case SASL_USERNAME:
    789       if(! conn->oparams.user)
    790 	  result = SASL_NOTDONE;
    791       else
    792 	  *((const char **)pvalue) = conn->oparams.user;
    793       break;
    794   case SASL_AUTHUSER:
    795       if(! conn->oparams.authid)
    796 	  result = SASL_NOTDONE;
    797       else
    798 	  *((const char **)pvalue) = conn->oparams.authid;
    799       break;
    800   case SASL_SERVERFQDN:
    801       *((const char **)pvalue) = conn->serverFQDN;
    802       break;
    803   case SASL_DEFUSERREALM:
    804       if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
    805       else
    806 	  *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
    807       break;
    808   case SASL_SERVICE:
    809       *((const char **)pvalue) = conn->service;
    810       break;
    811   case SASL_AUTHSOURCE: /* name of plugin (not name of mech) */
    812       if(conn->type == SASL_CONN_CLIENT) {
    813 	  if(!((sasl_client_conn_t *)conn)->mech) {
    814 	      result = SASL_NOTDONE;
    815 	      break;
    816 	  }
    817 	  *((const char **)pvalue) =
    818 	      ((sasl_client_conn_t *)conn)->mech->plugname;
    819       } else if (conn->type == SASL_CONN_SERVER) {
    820 	  if(!((sasl_server_conn_t *)conn)->mech) {
    821 	      result = SASL_NOTDONE;
    822 	      break;
    823 	  }
    824 	  *((const char **)pvalue) =
    825 	      ((sasl_server_conn_t *)conn)->mech->plugname;
    826       } else {
    827 	  result = SASL_BADPARAM;
    828       }
    829       break;
    830   case SASL_MECHNAME: /* name of mech */
    831       if(conn->type == SASL_CONN_CLIENT) {
    832 	  if(!((sasl_client_conn_t *)conn)->mech) {
    833 	      result = SASL_NOTDONE;
    834 	      break;
    835 	  }
    836 	  *((const char **)pvalue) =
    837 	      ((sasl_client_conn_t *)conn)->mech->plug->mech_name;
    838       } else if (conn->type == SASL_CONN_SERVER) {
    839 	  if(!((sasl_server_conn_t *)conn)->mech) {
    840 	      result = SASL_NOTDONE;
    841 	      break;
    842 	  }
    843 	  *((const char **)pvalue) =
    844 	      ((sasl_server_conn_t *)conn)->mech->plug->mech_name;
    845       } else {
    846 	  result = SASL_BADPARAM;
    847       }
    848 
    849       if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
    850       break;
    851   case SASL_PLUGERR:
    852       *((const char **)pvalue) = conn->error_buf;
    853       break;
    854   case SASL_SSF_EXTERNAL:
    855       *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
    856       break;
    857   case SASL_AUTH_EXTERNAL:
    858       *((const char **)pvalue) = conn->external.auth_id;
    859       break;
    860   case SASL_SEC_PROPS:
    861       *((const sasl_security_properties_t **)pvalue) = &conn->props;
    862       break;
    863   default:
    864       result = SASL_BADPARAM;
    865   }
    866 
    867   if(result == SASL_BADPARAM) {
    868       PARAMERROR(conn);
    869   } else if(result == SASL_NOTDONE) {
    870 #ifdef _SUN_SDK_
    871       _sasl_log(conn, SASL_LOG_NONE,
    872 		"Information that was requested is not yet available.");
    873 #else
    874       sasl_seterror(conn, SASL_NOLOG,
    875 		    "Information that was requested is not yet available.");
    876 #endif /* _SUN_SDK_ */
    877       RETURN(conn, result);
    878   } else if(result != SASL_OK) {
    879       INTERROR(conn, result);
    880   } else
    881       RETURN(conn, result);
    882 #ifdef _SUN_SDK_
    883   return SASL_OK;
    884 #endif /* _SUN_SDK_ */
    885 }
    886 
    887 /* set property in SASL connection state
    888  * returns:
    889  *  SASL_OK       -- value set
    890  *  SASL_BADPARAM -- invalid property or value
    891  */
    892 int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
    893 {
    894   int result = SASL_OK;
    895   char *str;
    896 #ifdef _SUN_SDK_
    897   const _sasl_global_context_t *gctx;
    898 #endif	/* _SUN_SDK_ */
    899 
    900   /* make sure the sasl context is valid */
    901   if (!conn)
    902     return SASL_BADPARAM;
    903 
    904 #ifdef _SUN_SDK_
    905   gctx = conn->gctx;
    906 #endif	/* _SUN_SDK_ */
    907 
    908   switch(propnum)
    909   {
    910   case SASL_SSF_EXTERNAL:
    911       conn->external.ssf = *((sasl_ssf_t *)value);
    912       if(conn->type == SASL_CONN_SERVER) {
    913 	((sasl_server_conn_t*)conn)->sparams->external_ssf =
    914 	  conn->external.ssf;
    915       } else {
    916 	((sasl_client_conn_t*)conn)->cparams->external_ssf =
    917 	  conn->external.ssf;
    918       }
    919       break;
    920 
    921   case SASL_AUTH_EXTERNAL:
    922       if(value && strlen(value)) {
    923 	  result = _sasl_strdup(value, &str, NULL);
    924 	  if(result != SASL_OK) MEMERROR(conn);
    925       } else {
    926 	  str = NULL;
    927       }
    928 
    929       if(conn->external.auth_id)
    930 	  sasl_FREE(conn->external.auth_id);
    931 
    932       conn->external.auth_id = str;
    933 
    934       break;
    935 
    936   case SASL_DEFUSERREALM:
    937       if(conn->type != SASL_CONN_SERVER) {
    938 #ifdef _SUN_SDK_
    939 	_sasl_log(conn, SASL_LOG_WARN,
    940 		  "Tried to set realm on non-server connection");
    941 #else
    942 	sasl_seterror(conn, 0, "Tried to set realm on non-server connection");
    943 #endif /* _SUN_SDK_ */
    944 	result = SASL_BADPROT;
    945 	break;
    946       }
    947 
    948       if(value && strlen(value)) {
    949 	  result = _sasl_strdup(value, &str, NULL);
    950 	  if(result != SASL_OK) MEMERROR(conn);
    951       } else {
    952 	  PARAMERROR(conn);
    953       }
    954 
    955       if(((sasl_server_conn_t *)conn)->user_realm)
    956       	  sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
    957 
    958       ((sasl_server_conn_t *)conn)->user_realm = str;
    959       ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
    960 
    961       break;
    962 
    963   case SASL_SEC_PROPS:
    964   {
    965       sasl_security_properties_t *props = (sasl_security_properties_t *)value;
    966 
    967       if(props->maxbufsize == 0 && props->min_ssf != 0) {
    968 #ifdef _SUN_SDK_
    969 	  _sasl_log(conn, SASL_LOG_ERR,
    970 		    "Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
    971 #else
    972 	  sasl_seterror(conn, 0,
    973 			"Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
    974 #endif /* _SUN_SDK_ */
    975 	  RETURN(conn, SASL_TOOWEAK);
    976       }
    977 
    978       conn->props = *props;
    979 
    980       if(conn->type == SASL_CONN_SERVER) {
    981 	((sasl_server_conn_t*)conn)->sparams->props = *props;
    982       } else {
    983 	((sasl_client_conn_t*)conn)->cparams->props = *props;
    984       }
    985 
    986       break;
    987   }
    988 
    989   case SASL_IPREMOTEPORT:
    990   {
    991       const char *ipremoteport = (const char *)value;
    992       if(!value) {
    993 	  conn->got_ip_remote = 0;
    994 #ifdef _SUN_SDK_
    995       } else if (strlen(ipremoteport) >= sizeof (conn->ipremoteport)) {
    996 	  RETURN(conn, SASL_BADPARAM);
    997 #endif /* _SUN_SDK_ */
    998       } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
    999 		 != SASL_OK) {
   1000 #ifdef _SUN_SDK_
   1001 	  _sasl_log(conn, SASL_LOG_ERR, "Bad IPREMOTEPORT value");
   1002 #else
   1003 	  sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
   1004 #endif /* _SUN_SDK_ */
   1005 	  RETURN(conn, SASL_BADPARAM);
   1006       } else {
   1007 	  strcpy(conn->ipremoteport, ipremoteport);
   1008 	  conn->got_ip_remote = 1;
   1009       }
   1010 
   1011       if(conn->got_ip_remote) {
   1012 	  if(conn->type == SASL_CONN_CLIENT) {
   1013 	      ((sasl_client_conn_t *)conn)->cparams->ipremoteport
   1014 		  = conn->ipremoteport;
   1015 	      ((sasl_client_conn_t *)conn)->cparams->ipremlen =
   1016 		  strlen(conn->ipremoteport);
   1017 	  } else if (conn->type == SASL_CONN_SERVER) {
   1018 	      ((sasl_server_conn_t *)conn)->sparams->ipremoteport
   1019 		  = conn->ipremoteport;
   1020 	      ((sasl_server_conn_t *)conn)->sparams->ipremlen =
   1021 		  strlen(conn->ipremoteport);
   1022 	  }
   1023       } else {
   1024 	  if(conn->type == SASL_CONN_CLIENT) {
   1025 	      ((sasl_client_conn_t *)conn)->cparams->ipremoteport
   1026 		  = NULL;
   1027 	      ((sasl_client_conn_t *)conn)->cparams->ipremlen = 0;
   1028 	  } else if (conn->type == SASL_CONN_SERVER) {
   1029 	      ((sasl_server_conn_t *)conn)->sparams->ipremoteport
   1030 		  = NULL;
   1031 	      ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
   1032 	  }
   1033       }
   1034 
   1035       break;
   1036   }
   1037 
   1038   case SASL_IPLOCALPORT:
   1039   {
   1040       const char *iplocalport = (const char *)value;
   1041       if(!value) {
   1042 	  conn->got_ip_local = 0;
   1043 #ifdef _SUN_SDK_
   1044       } else if (strlen(iplocalport) >= sizeof (conn->iplocalport)) {
   1045 	  RETURN(conn, SASL_BADPARAM);
   1046 #endif /* _SUN_SDK_ */
   1047       } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
   1048 		 != SASL_OK) {
   1049 #ifdef _SUN_SDK_
   1050 	  _sasl_log(conn, SASL_LOG_ERR, "Bad IPLOCALPORT value");
   1051 #else
   1052 	  sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
   1053 #endif /* _SUN_SDK_ */
   1054 	  RETURN(conn, SASL_BADPARAM);
   1055       } else {
   1056 	  strcpy(conn->iplocalport, iplocalport);
   1057 	  conn->got_ip_local = 1;
   1058       }
   1059 
   1060       if(conn->got_ip_local) {
   1061 	  if(conn->type == SASL_CONN_CLIENT) {
   1062 	      ((sasl_client_conn_t *)conn)->cparams->iplocalport
   1063 		  = conn->iplocalport;
   1064 	      ((sasl_client_conn_t *)conn)->cparams->iploclen
   1065 		  = strlen(conn->iplocalport);
   1066 	  } else if (conn->type == SASL_CONN_SERVER) {
   1067 	      ((sasl_server_conn_t *)conn)->sparams->iplocalport
   1068 		  = conn->iplocalport;
   1069 	      ((sasl_server_conn_t *)conn)->sparams->iploclen
   1070 		  = strlen(conn->iplocalport);
   1071 	  }
   1072       } else {
   1073 	  if(conn->type == SASL_CONN_CLIENT) {
   1074 	      ((sasl_client_conn_t *)conn)->cparams->iplocalport
   1075 		  = NULL;
   1076 	      ((sasl_client_conn_t *)conn)->cparams->iploclen = 0;
   1077 	  } else if (conn->type == SASL_CONN_SERVER) {
   1078 	      ((sasl_server_conn_t *)conn)->sparams->iplocalport
   1079 		  = NULL;
   1080 	      ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
   1081 	  }
   1082       }
   1083       break;
   1084   }
   1085 
   1086   default:
   1087 #ifdef _SUN_SDK_
   1088       _sasl_log(conn, SASL_LOG_WARN, "Unknown parameter type");
   1089 #else
   1090       sasl_seterror(conn, 0, "Unknown parameter type");
   1091 #endif /* _SUN_SDK_ */
   1092       result = SASL_BADPARAM;
   1093   }
   1094 
   1095   RETURN(conn, result);
   1096 }
   1097 
   1098 /* this is apparently no longer a user function */
   1099 static int sasl_usererr(int saslerr)
   1100 {
   1101     /* Hide the difference in a username failure and a password failure */
   1102     if (saslerr == SASL_NOUSER)
   1103 	return SASL_BADAUTH;
   1104 
   1105     /* otherwise return the error given; no transform necessary */
   1106     return saslerr;
   1107 }
   1108 
   1109 #ifdef _INTEGRATED_SOLARIS_
   1110 static void free_err_tsd(void *key)
   1111 {
   1112     free(key);
   1113 }
   1114 #endif /* _INTEGRATED_SOLARIS_ */
   1115 
   1116 const char *sasl_errstring(int saslerr,
   1117 #ifdef _SUN_SDK_
   1118 			   const char *langlist,
   1119 #else
   1120 			   const char *langlist __attribute__((unused)),
   1121 #endif /* _SUN_SDK_ */
   1122 			   const char **outlang)
   1123 {
   1124 #ifdef _INTEGRATED_SOLARIS_
   1125   const char *s;
   1126   const char *s_locale;
   1127   char *s_utf8;
   1128   void *tsd;
   1129 
   1130   if (outlang) *outlang="i-default";
   1131 #else
   1132   if (outlang) *outlang="en-us";
   1133 #endif /* _INTEGRATED_SOLARIS_ */
   1134 
   1135 #ifdef _INTEGRATED_SOLARIS_
   1136   switch(saslerr)
   1137     {
   1138     case SASL_CONTINUE: s = gettext("another step is needed in authentication");
   1139 	break;
   1140     case SASL_OK:       s = gettext("successful result");
   1141 	break;
   1142     case SASL_FAIL:     s = gettext("generic failure");
   1143 	break;
   1144     case SASL_NOMEM:    s = gettext("no memory available");
   1145 	break;
   1146     case SASL_BUFOVER:  s = gettext("overflowed buffer");
   1147 	break;
   1148     case SASL_NOMECH:   s = gettext("no mechanism available");
   1149 	break;
   1150     case SASL_BADPROT:  s = gettext("bad protocol / cancel");
   1151 	break;
   1152     case SASL_NOTDONE:  s = gettext("can't request info until later in exchange");
   1153 	break;
   1154     case SASL_BADPARAM: s = gettext("invalid parameter supplied");
   1155 	break;
   1156     case SASL_TRYAGAIN: s = gettext("transient failure (e.g., weak key)");
   1157 	break;
   1158     case SASL_BADMAC:   s = gettext("integrity check failed");
   1159 	break;
   1160     case SASL_NOTINIT:  s = gettext("SASL library not initialized");
   1161 	break;
   1162                              /* -- client only codes -- */
   1163     case SASL_INTERACT:   s = gettext("needs user interaction");
   1164 	break;
   1165     case SASL_BADSERV:    s = gettext("server failed mutual authentication step");
   1166 	break;
   1167     case SASL_WRONGMECH:  s = gettext("mechanism doesn't support requested feature");
   1168 	break;
   1169                              /* -- server only codes -- */
   1170     case SASL_BADAUTH:    s = gettext("authentication failure");
   1171 	break;
   1172     case SASL_NOAUTHZ:    s = gettext("authorization failure");
   1173 	break;
   1174     case SASL_TOOWEAK:    s = gettext("mechanism too weak for this user");
   1175 	break;
   1176     case SASL_ENCRYPT:    s = gettext("encryption needed to use mechanism");
   1177 	break;
   1178     case SASL_TRANS:      s = gettext("One time use of a plaintext password will enable requested mechanism for user");
   1179 	break;
   1180     case SASL_EXPIRED:    s = gettext("passphrase expired, has to be reset");
   1181 	break;
   1182     case SASL_DISABLED:   s = gettext("account disabled");
   1183 	break;
   1184     case SASL_NOUSER:     s = gettext("user not found");
   1185 	break;
   1186     case SASL_BADVERS:    s = gettext("version mismatch with plug-in");
   1187 	break;
   1188     case SASL_UNAVAIL:    s = gettext("remote authentication server unavailable");
   1189 	break;
   1190     case SASL_NOVERIFY:   s = gettext("user exists, but no verifier for user");
   1191 	break;
   1192     case SASL_PWLOCK:     s = gettext("passphrase locked");
   1193 	break;
   1194     case SASL_NOCHANGE:   s = gettext("requested change was not needed");
   1195 	break;
   1196     case SASL_WEAKPASS:   s = gettext("passphrase is too weak for security policy");
   1197 	break;
   1198     case SASL_NOUSERPASS: s = gettext("user supplied passwords are not permitted");
   1199 
   1200 	break;
   1201     default:   s = gettext("undefined error!");
   1202 	break;
   1203   }
   1204 
   1205   if (use_locale(langlist, 0))
   1206     s_locale = dgettext(TEXT_DOMAIN, s);
   1207   else
   1208     s_locale = s;
   1209 
   1210   if (s == s_locale)
   1211     return s;
   1212 
   1213   s_utf8 = local_to_utf(NULL, s_locale);
   1214   if (s_utf8 == NULL)
   1215     return s;
   1216 
   1217   if (pthread_key_create_once_np(&errstring_key, free_err_tsd) != 0) {
   1218     free(s_utf8);
   1219     return s;
   1220   }
   1221 
   1222   tsd = pthread_getspecific(errstring_key);
   1223   if (tsd != NULL)
   1224     free(tsd);
   1225   pthread_setspecific(errstring_key, s_utf8);
   1226 
   1227   if (outlang) *outlang="*";
   1228   return s_utf8;
   1229 #else
   1230   switch(saslerr)
   1231     {
   1232     case SASL_CONTINUE: return "another step is needed in authentication";
   1233     case SASL_OK:       return "successful result";
   1234     case SASL_FAIL:     return "generic failure";
   1235     case SASL_NOMEM:    return "no memory available";
   1236     case SASL_BUFOVER:  return "overflowed buffer";
   1237     case SASL_NOMECH:   return "no mechanism available";
   1238     case SASL_BADPROT:  return "bad protocol / cancel";
   1239     case SASL_NOTDONE:  return "can't request info until later in exchange";
   1240     case SASL_BADPARAM: return "invalid parameter supplied";
   1241     case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
   1242     case SASL_BADMAC:   return "integrity check failed";
   1243     case SASL_NOTINIT:  return "SASL library not initialized";
   1244                              /* -- client only codes -- */
   1245     case SASL_INTERACT:   return "needs user interaction";
   1246     case SASL_BADSERV:    return "server failed mutual authentication step";
   1247     case SASL_WRONGMECH:  return "mechanism doesn't support requested feature";
   1248                              /* -- server only codes -- */
   1249     case SASL_BADAUTH:    return "authentication failure";
   1250     case SASL_NOAUTHZ:    return "authorization failure";
   1251     case SASL_TOOWEAK:    return "mechanism too weak for this user";
   1252     case SASL_ENCRYPT:    return "encryption needed to use mechanism";
   1253     case SASL_TRANS:      return "One time use of a plaintext password will enable requested mechanism for user";
   1254     case SASL_EXPIRED:    return "passphrase expired, has to be reset";
   1255     case SASL_DISABLED:   return "account disabled";
   1256     case SASL_NOUSER:     return "user not found";
   1257     case SASL_BADVERS:    return "version mismatch with plug-in";
   1258     case SASL_UNAVAIL:    return "remote authentication server unavailable";
   1259     case SASL_NOVERIFY:   return "user exists, but no verifier for user";
   1260     case SASL_PWLOCK:     return "passphrase locked";
   1261     case SASL_NOCHANGE:   return "requested change was not needed";
   1262     case SASL_WEAKPASS:   return "passphrase is too weak for security policy";
   1263     case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
   1264 
   1265     default:   return "undefined error!";
   1266     }
   1267 #endif /* _INTEGRATED_SOLARIS_ */
   1268 
   1269 }
   1270 
   1271 /* Return the sanitized error detail about the last error that occured for
   1272  * a connection */
   1273 const char *sasl_errdetail(sasl_conn_t *conn)
   1274 {
   1275     unsigned need_len;
   1276     const char *errstr;
   1277     char leader[128];
   1278 #ifdef _SUN_SDK_
   1279     int ret;
   1280     const _sasl_global_context_t *gctx;
   1281 
   1282     if(!conn) return "invalid parameter supplied";
   1283 
   1284     gctx = conn->gctx;
   1285 #else
   1286     if(!conn) return NULL;
   1287 #endif /* _SUN_SDK_ */
   1288 
   1289     errstr = sasl_errstring(conn->error_code, NULL, NULL);
   1290     snprintf(leader,128,"SASL(%d): %s: ",
   1291 	     sasl_usererr(conn->error_code), errstr);
   1292 
   1293     need_len = strlen(leader) + strlen(conn->error_buf) + 12;
   1294 #ifdef _SUN_SDK_
   1295     ret = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
   1296     if (ret != SASL_OK)
   1297 	return "no memory available";
   1298 #else
   1299     _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
   1300 #endif /* _SUN_SDK_ */
   1301 
   1302     snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
   1303 
   1304     return conn->errdetail_buf;
   1305 }
   1306 
   1307 /* EXPORT DELETE START */
   1308 /* CRYPT DELETE START */
   1309 #ifdef _INTEGRATED_SOLARIS_
   1310 DEFINE_STATIC_MUTEX(reg_mutex);
   1311 typedef struct reg_list {
   1312 	struct reg_list *next;
   1313 	void *mech;
   1314 } reg_list_t;
   1315 
   1316 static reg_list_t *reg_list_base = NULL;
   1317 
   1318 int _is_sun_reg(void *mech)
   1319 {
   1320 	reg_list_t *r, *prev;
   1321 	int is_reg = 0;
   1322 
   1323 	LOCK_MUTEX(&reg_mutex);
   1324 	for (r = reg_list_base; r != NULL; r = r->next) {
   1325 		if (r->mech != mech) {
   1326 			prev = r;
   1327 			continue;
   1328 		}
   1329 		is_reg = 1;
   1330 		if (r == reg_list_base) {
   1331 			reg_list_base = reg_list_base->next;
   1332 		} else {
   1333 			prev->next = r->next;
   1334 		}
   1335 		free(r);
   1336 		break;
   1337 	}
   1338 	UNLOCK_MUTEX(&reg_mutex);
   1339 	return (is_reg);
   1340 }
   1341 
   1342 static void
   1343 _register_plugin(void *arg)
   1344 {
   1345 	reg_list_t *r = (reg_list_t *)calloc(1, sizeof (reg_list_t));
   1346 
   1347 	if (r != NULL) {
   1348 		r->mech = arg;
   1349 		LOCK_MUTEX(&reg_mutex);
   1350 		r->next = reg_list_base;
   1351 		reg_list_base = r;
   1352 		UNLOCK_MUTEX(&reg_mutex);
   1353 	}
   1354 }
   1355 #endif /* _INTEGRATED_SOLARIS_ */
   1356 /* CRYPT DELETE END */
   1357 /* EXPORT DELETE END */
   1358 
   1359 /* Note that this needs the global callbacks, so if you don't give getcallbacks
   1360  * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
   1361  * have client and server at the same time */
   1362 static int _sasl_global_getopt(void *context,
   1363 			       const char *plugin_name,
   1364 			       const char *option,
   1365 			       const char ** result,
   1366 			       unsigned *len)
   1367 {
   1368   const sasl_global_callbacks_t * global_callbacks;
   1369   const sasl_callback_t *callback;
   1370 #ifdef _SUN_SDK_
   1371   _sasl_global_context_t *gctx;
   1372 #endif /* _SUN_SDK_ */
   1373 
   1374   global_callbacks = (const sasl_global_callbacks_t *) context;
   1375 
   1376 #ifdef _SUN_SDK_
   1377   /* EXPORT DELETE START */
   1378   /* CRYPT DELETE START */
   1379 #ifdef _INTEGRATED_SOLARIS_
   1380   if (strcmp("reg_sun_plug", option) == 0) {
   1381         *result = (const char *)_register_plugin;
   1382         *len = 0;
   1383         return (SASL_OK);
   1384   }
   1385 #endif /* _INTEGRATED_SOLARIS_ */
   1386   /* CRYPT DELETE END */
   1387   /* EXPORT DELETE END */
   1388 
   1389   if (global_callbacks)
   1390     gctx = global_callbacks->gctx;
   1391   else
   1392     gctx = _sasl_gbl_ctx();
   1393 #endif /* _SUN_SDK_ */
   1394 
   1395   if (global_callbacks && global_callbacks->callbacks) {
   1396       for (callback = global_callbacks->callbacks;
   1397 	   callback->id != SASL_CB_LIST_END;
   1398 	   callback++) {
   1399 	if (callback->id == SASL_CB_GETOPT) {
   1400 	  if (!callback->proc) return SASL_FAIL;
   1401 	  if (((sasl_getopt_t *)(callback->proc))(callback->context,
   1402 						  plugin_name,
   1403 						  option,
   1404 						  result,
   1405 						  len)
   1406 	      == SASL_OK)
   1407 	    return SASL_OK;
   1408 	}
   1409       }
   1410   }
   1411 
   1412   /* look it up in our configuration file */
   1413 #ifdef _SUN_SDK_
   1414   *result = sasl_config_getstring(gctx, option, NULL);
   1415 #else
   1416   *result = sasl_config_getstring(option, NULL);
   1417 #endif /* _SUN_SDK_ */
   1418   if (*result != NULL) {
   1419       if (len) { *len = strlen(*result); }
   1420       return SASL_OK;
   1421   }
   1422 
   1423   return SASL_FAIL;
   1424 }
   1425 
   1426 static int
   1427 _sasl_conn_getopt(void *context,
   1428 		  const char *plugin_name,
   1429 		  const char *option,
   1430 		  const char ** result,
   1431 		  unsigned *len)
   1432 {
   1433   sasl_conn_t * conn;
   1434   const sasl_callback_t *callback;
   1435 
   1436   if (! context)
   1437     return SASL_BADPARAM;
   1438 
   1439   conn = (sasl_conn_t *) context;
   1440 
   1441   if (conn->callbacks)
   1442     for (callback = conn->callbacks;
   1443 	 callback->id != SASL_CB_LIST_END;
   1444 	 callback++)
   1445       if (callback->id == SASL_CB_GETOPT
   1446 	  && (((sasl_getopt_t *)(callback->proc))(callback->context,
   1447 						  plugin_name,
   1448 						  option,
   1449 						  result,
   1450 						  len)
   1451 	      == SASL_OK))
   1452 	return SASL_OK;
   1453 
   1454   /* If we made it here, we didn't find an appropriate callback
   1455    * in the connection's callback list, or the callback we did
   1456    * find didn't return SASL_OK.  So we attempt to use the
   1457    * global callback for this connection... */
   1458   return _sasl_global_getopt((void *)conn->global_callbacks,
   1459 			     plugin_name,
   1460 			     option,
   1461 			     result,
   1462 			     len);
   1463 }
   1464 
   1465 #ifdef HAVE_SYSLOG
   1466 /* this is the default logging */
   1467 static int _sasl_syslog(void *context __attribute__((unused)),
   1468 			int priority,
   1469 			const char *message)
   1470 {
   1471     int syslog_priority;
   1472 
   1473     /* set syslog priority */
   1474     switch(priority) {
   1475     case SASL_LOG_NONE:
   1476 	return SASL_OK;
   1477 	break;
   1478     case SASL_LOG_ERR:
   1479 	syslog_priority = LOG_ERR;
   1480 	break;
   1481     case SASL_LOG_WARN:
   1482 	syslog_priority = LOG_WARNING;
   1483 	break;
   1484     case SASL_LOG_NOTE:
   1485     case SASL_LOG_FAIL:
   1486 	syslog_priority = LOG_NOTICE;
   1487 	break;
   1488     case SASL_LOG_PASS:
   1489     case SASL_LOG_TRACE:
   1490     case SASL_LOG_DEBUG:
   1491     default:
   1492 	syslog_priority = LOG_DEBUG;
   1493 	break;
   1494     }
   1495 
   1496     /* do the syslog call. do not need to call openlog */
   1497     syslog(syslog_priority | LOG_AUTH, "%s", message);
   1498 
   1499     return SASL_OK;
   1500 }
   1501 #endif				/* HAVE_SYSLOG */
   1502 
   1503 static int
   1504 _sasl_getsimple(void *context,
   1505 		int id,
   1506 		const char ** result,
   1507 		size_t *len)
   1508 {
   1509   const char *userid;
   1510 #ifndef _SUN_SDK_
   1511   sasl_conn_t *conn;
   1512 #endif /* _SUN_SDK_ */
   1513 
   1514   if (! context || ! result) return SASL_BADPARAM;
   1515 
   1516 #ifndef _SUN_SDK_
   1517   conn = (sasl_conn_t *)context;
   1518 #endif /* _SUN_SDK_ */
   1519 
   1520   switch(id) {
   1521   case SASL_CB_AUTHNAME:
   1522 #ifdef _INTEGRATED_SOLARIS_
   1523     userid = getenv("LOGNAME");
   1524     if (userid != NULL) {
   1525 	*result = userid;
   1526 	if (len) *len = strlen(userid);
   1527 	return SASL_OK;
   1528     }
   1529 #else
   1530     userid = getenv("USER");
   1531     if (userid != NULL) {
   1532 	*result = userid;
   1533 	if (len) *len = strlen(userid);
   1534 	return SASL_OK;
   1535     }
   1536     userid = getenv("USERNAME");
   1537     if (userid != NULL) {
   1538 	*result = userid;
   1539 	if (len) *len = strlen(userid);
   1540 	return SASL_OK;
   1541     }
   1542 #endif /* _INTEGRATED_SOLARIS_ */
   1543 #ifdef WIN32
   1544     /* for win32, try using the GetUserName standard call */
   1545     {
   1546 	DWORD i;
   1547 	BOOL rval;
   1548 	static char sender[128];
   1549 
   1550 	i = sizeof(sender);
   1551 	rval = GetUserName(sender, &i);
   1552 	if ( rval) { /* got a userid */
   1553 		*result = sender;
   1554 		if (len) *len = strlen(sender);
   1555 		return SASL_OK;
   1556 	}
   1557     }
   1558 #endif /* WIN32 */
   1559     return SASL_FAIL;
   1560   default:
   1561     return SASL_BADPARAM;
   1562   }
   1563 }
   1564 
   1565 static int
   1566 _sasl_verifyfile(void *context __attribute__((unused)),
   1567 		 char *file  __attribute__((unused)),
   1568 		 int type  __attribute__((unused)))
   1569 {
   1570   /* always say ok */
   1571   return SASL_OK;
   1572 }
   1573 
   1574 
   1575 static int
   1576 _sasl_proxy_policy(sasl_conn_t *conn,
   1577 		   void *context __attribute__((unused)),
   1578 		   const char *requested_user, unsigned rlen,
   1579 		   const char *auth_identity, unsigned alen,
   1580 		   const char *def_realm __attribute__((unused)),
   1581 		   unsigned urlen __attribute__((unused)),
   1582 		   struct propctx *propctx __attribute__((unused)))
   1583 {
   1584     if (!conn)
   1585 	return SASL_BADPARAM;
   1586 
   1587     if (!requested_user || *requested_user == '\0')
   1588 	return SASL_OK;
   1589 
   1590     if (!auth_identity || !requested_user || rlen != alen ||
   1591 	(memcmp(auth_identity, requested_user, rlen) != 0)) {
   1592 #ifdef _INTEGRATED_SOLARIS_
   1593 	sasl_seterror(conn, 0,
   1594 		      gettext("Requested identity not authenticated identity"));
   1595 #else
   1596 	sasl_seterror(conn, 0,
   1597 		      "Requested identity not authenticated identity");
   1598 #endif /* _INTEGRATED_SOLARIS_ */
   1599 	RETURN(conn, SASL_BADAUTH);
   1600     }
   1601 
   1602     return SASL_OK;
   1603 }
   1604 
   1605 int _sasl_getcallback(sasl_conn_t * conn,
   1606 		      unsigned long callbackid,
   1607 		      int (**pproc)(),
   1608 		      void **pcontext)
   1609 {
   1610   const sasl_callback_t *callback;
   1611 
   1612   if (!pproc || !pcontext)
   1613       PARAMERROR(conn);
   1614 
   1615   /* Some callbacks are always provided by the library */
   1616   switch (callbackid) {
   1617   case SASL_CB_LIST_END:
   1618     /* Nothing ever gets to provide this */
   1619       INTERROR(conn, SASL_FAIL);
   1620 #ifdef _SUN_SDK_
   1621       break;
   1622 #endif /* _SUN_SDK_ */
   1623   case SASL_CB_GETOPT:
   1624       if (conn) {
   1625 	  *pproc = &_sasl_conn_getopt;
   1626 	  *pcontext = conn;
   1627       } else {
   1628 	  *pproc = &_sasl_global_getopt;
   1629 	  *pcontext = NULL;
   1630       }
   1631       return SASL_OK;
   1632   }
   1633 
   1634   /* If it's not always provided by the library, see if there's
   1635    * a version provided by the application for this connection... */
   1636   if (conn && conn->callbacks) {
   1637     for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
   1638 	 callback++) {
   1639 	if (callback->id == callbackid) {
   1640 	    *pproc = callback->proc;
   1641 	    *pcontext = callback->context;
   1642 	    if (callback->proc) {
   1643 		return SASL_OK;
   1644 	    } else {
   1645 		return SASL_INTERACT;
   1646 	    }
   1647 	}
   1648     }
   1649   }
   1650 
   1651   /* And, if not for this connection, see if there's one
   1652    * for all {server,client} connections... */
   1653   if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
   1654       for (callback = conn->global_callbacks->callbacks;
   1655 	   callback->id != SASL_CB_LIST_END;
   1656 	   callback++) {
   1657 	  if (callback->id == callbackid) {
   1658 	      *pproc = callback->proc;
   1659 	      *pcontext = callback->context;
   1660 	      if (callback->proc) {
   1661 		  return SASL_OK;
   1662 	      } else {
   1663 		  return SASL_INTERACT;
   1664 	      }
   1665 	  }
   1666       }
   1667   }
   1668 
   1669   /* Otherwise, see if the library provides a default callback. */
   1670   switch (callbackid) {
   1671 #ifdef HAVE_SYSLOG
   1672   case SASL_CB_LOG:
   1673     *pproc = (int (*)()) &_sasl_syslog;
   1674     *pcontext = NULL;
   1675     return SASL_OK;
   1676 #endif /* HAVE_SYSLOG */
   1677   case SASL_CB_GETPATH:
   1678     *pproc = (int (*)()) &_sasl_getpath;
   1679     *pcontext = NULL;
   1680     return SASL_OK;
   1681   case SASL_CB_AUTHNAME:
   1682     *pproc = (int (*)()) &_sasl_getsimple;
   1683     *pcontext = conn;
   1684     return SASL_OK;
   1685   case SASL_CB_VERIFYFILE:
   1686     *pproc = & _sasl_verifyfile;
   1687     *pcontext = NULL;
   1688     return SASL_OK;
   1689   case SASL_CB_PROXY_POLICY:
   1690     *pproc = (int (*)()) &_sasl_proxy_policy;
   1691     *pcontext = NULL;
   1692     return SASL_OK;
   1693   }
   1694 
   1695   /* Unable to find a callback... */
   1696   *pproc = NULL;
   1697   *pcontext = NULL;
   1698 #ifdef _SUN_SDK_
   1699   if (callbackid != SASL_CB_LANGUAGE)
   1700     _sasl_log(conn, SASL_LOG_NONE, "Unable to find a callback: %d", callbackid);
   1701 #else
   1702   sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
   1703 #endif /* _SUN_SDK_ */
   1704   RETURN(conn,SASL_FAIL);
   1705 }
   1706 
   1707 
   1708 #ifdef _SUN_SDK_
   1709 static void ___sasl_log (const _sasl_global_context_t *gctx,
   1710 			sasl_log_t *log_cb, void *log_ctx,
   1711 			int level, const char *fmt, va_list ap);
   1712 #endif /* _SUN_SDK_ */
   1713 /*
   1714  * This function is typically called from a plugin.
   1715  * It creates a string from the formatting and varargs given
   1716  * and calls the logging callback (syslog by default)
   1717  *
   1718  * %m will parse the value in the next argument as an errno string
   1719  * %z will parse the next argument as a SASL error code.
   1720  */
   1721 
   1722 void
   1723 _sasl_log (sasl_conn_t *conn,
   1724 	   int level,
   1725 	   const char *fmt,
   1726 	   ...)
   1727 #ifdef _SUN_SDK_
   1728 {
   1729   _sasl_global_context_t *gctx = conn==NULL ? _sasl_gbl_ctx() : conn->gctx;
   1730   sasl_log_t *log_cb;
   1731   void *log_ctx;
   1732   int result;
   1733   va_list ap;
   1734 
   1735   /* See if we have a logging callback... */
   1736   result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
   1737   if (result == SASL_OK && ! log_cb)
   1738     return;
   1739 
   1740   va_start(ap, fmt); /* start varargs */
   1741   ___sasl_log(gctx, log_cb, log_ctx, level, fmt, ap);
   1742   va_end(ap);
   1743 }
   1744 
   1745 void
   1746 __sasl_log(const _sasl_global_context_t *gctx,
   1747 	   const sasl_callback_t *callbacks,
   1748 	   int level,
   1749 	   const char *fmt,
   1750 	   ...)
   1751 {
   1752   sasl_log_t *log_cb = NULL;
   1753   void *log_ctx = NULL;
   1754   int result;
   1755   va_list ap;
   1756 
   1757   if (callbacks)
   1758     while (callbacks->id != SASL_CB_LIST_END) {
   1759       if (callbacks->id == SASL_CB_LOG) {
   1760 	log_cb = callbacks->proc;
   1761 	log_ctx = callbacks->context;
   1762 	break;
   1763       }
   1764       ++callbacks;
   1765     }
   1766 
   1767   if (log_cb == NULL) {
   1768     result = _sasl_getcallback(NULL, SASL_CB_LOG, &log_cb, &log_ctx);
   1769     if (result != SASL_OK || ! log_cb)
   1770 	return;
   1771   }
   1772 
   1773   if (gctx == NULL)
   1774     gctx = _sasl_gbl_ctx();
   1775 
   1776   va_start(ap, fmt); /* start varargs */
   1777   ___sasl_log(gctx, log_cb, log_ctx, level, fmt, ap);
   1778   va_end(ap);
   1779 }
   1780 
   1781 static void
   1782 ___sasl_log(const _sasl_global_context_t *gctx,
   1783 	    sasl_log_t *log_cb,
   1784 	    void *log_ctx,
   1785 	    int level,
   1786 	    const char *fmt,
   1787 	    va_list ap)
   1788 #endif /* _SUN_SDK_ */
   1789 {
   1790   char *out=(char *) sasl_ALLOC(250);
   1791   size_t alloclen=100; /* current allocated length */
   1792   size_t outlen=0; /* current length of output buffer */
   1793   size_t formatlen;
   1794   size_t pos=0; /* current position in format string */
   1795   int result;
   1796 #ifndef _SUN_SDK_
   1797   sasl_log_t *log_cb;
   1798   void *log_ctx;
   1799 #endif /* !_SUN_SDK_ */
   1800 
   1801   int ival;
   1802   char *cval;
   1803 #ifndef _SUN_SDK_
   1804   va_list ap; /* varargs thing */
   1805 #endif /* !_SUN_SDK_ */
   1806 
   1807   if(!fmt) goto done;
   1808   if(!out) return;
   1809 
   1810   formatlen = strlen(fmt);
   1811 
   1812 #ifndef _SUN_SDK_
   1813   /* See if we have a logging callback... */
   1814   result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
   1815   if (result == SASL_OK && ! log_cb)
   1816     result = SASL_FAIL;
   1817   if (result != SASL_OK) goto done;
   1818 
   1819   va_start(ap, fmt); /* start varargs */
   1820 #endif /* !_SUN_SDK_ */
   1821 
   1822   while(pos<formatlen)
   1823   {
   1824     if (fmt[pos]!='%') /* regular character */
   1825     {
   1826       result = _buf_alloc(&out, &alloclen, outlen+1);
   1827       if (result != SASL_OK) goto done;
   1828       out[outlen]=fmt[pos];
   1829       outlen++;
   1830       pos++;
   1831 
   1832     } else { /* formating thing */
   1833       int done=0;
   1834       char frmt[10];
   1835       int frmtpos=1;
   1836       char tempbuf[21];
   1837       frmt[0]='%';
   1838       pos++;
   1839 
   1840       while (done==0)
   1841       {
   1842 	switch(fmt[pos])
   1843 	  {
   1844 	  case 's': /* need to handle this */
   1845 	    cval = va_arg(ap, char *); /* get the next arg */
   1846 	    result = _sasl_add_string(&out, &alloclen,
   1847 				&outlen, cval);
   1848 
   1849 	    if (result != SASL_OK) /* add the string */
   1850 		goto done;
   1851 
   1852 	    done=1;
   1853 	    break;
   1854 
   1855 	  case '%': /* double % output the '%' character */
   1856 	    result = _buf_alloc(&out,&alloclen,outlen+1);
   1857 	    if (result != SASL_OK)
   1858 		goto done;
   1859 
   1860 	    out[outlen]='%';
   1861 	    outlen++;
   1862 	    done=1;
   1863 	    break;
   1864 
   1865 	  case 'm': /* insert the errno string */
   1866 	    result = _sasl_add_string(&out, &alloclen, &outlen,
   1867 				strerror(va_arg(ap, int)));
   1868 	    if (result != SASL_OK)
   1869 		goto done;
   1870 
   1871 	    done=1;
   1872 	    break;
   1873 
   1874 	  case 'z': /* insert the sasl error string */
   1875 	    result = _sasl_add_string(&out, &alloclen, &outlen,
   1876 				(char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
   1877 	    if (result != SASL_OK)
   1878 		goto done;
   1879 
   1880 	    done=1;
   1881 	    break;
   1882 
   1883 	  case 'c':
   1884 #ifndef _SUN_SDK_
   1885 	    frmt[frmtpos++]=fmt[pos];
   1886 	    frmt[frmtpos]=0;
   1887 #endif /* !_SUN_SDK_ */
   1888 	    tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
   1889 	    tempbuf[1]='\0';
   1890 
   1891 	    /* now add the character */
   1892 	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
   1893 	    if (result != SASL_OK)
   1894 		goto done;
   1895 
   1896 	    done=1;
   1897 	    break;
   1898 
   1899 	  case 'd':
   1900 	  case 'i':
   1901 	    frmt[frmtpos++]=fmt[pos];
   1902 	    frmt[frmtpos]=0;
   1903 	    ival = va_arg(ap, int); /* get the next arg */
   1904 
   1905 	    snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
   1906 	    /* now add the string */
   1907 	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
   1908 	    if (result != SASL_OK)
   1909 		goto done;
   1910 
   1911 	    done=1;
   1912 
   1913 	    break;
   1914 	  default:
   1915 	    frmt[frmtpos++]=fmt[pos]; /* add to the formating */
   1916 	    frmt[frmtpos]=0;
   1917 #ifdef _SUN_SDK_
   1918 	    if (frmtpos > sizeof (frmt) - 2)
   1919 #else
   1920 	    if (frmtpos>9)
   1921 #endif /* _SUN_SDK_ */
   1922 	      done=1;
   1923 	  }
   1924 	pos++;
   1925 	if (pos>formatlen)
   1926 	  done=1;
   1927       }
   1928 
   1929     }
   1930   }
   1931 
   1932   /* put 0 at end */
   1933   result = _buf_alloc(&out, &alloclen, outlen+1);
   1934   if (result != SASL_OK) goto done;
   1935   out[outlen]=0;
   1936 
   1937   va_end(ap);
   1938 
   1939   /* send log message */
   1940   result = log_cb(log_ctx, level, out);
   1941 
   1942  done:
   1943   if(out) sasl_FREE(out);
   1944 }
   1945 
   1946 
   1947 
   1948 /* Allocate and Init a sasl_utils_t structure */
   1949 #ifdef _SUN_SDK_
   1950 sasl_utils_t *
   1951 _sasl_alloc_utils(_sasl_global_context_t *gctx, sasl_conn_t *conn,
   1952 		  sasl_global_callbacks_t *global_callbacks)
   1953 #else
   1954 sasl_utils_t *
   1955 _sasl_alloc_utils(sasl_conn_t *conn,
   1956 		  sasl_global_callbacks_t *global_callbacks)
   1957 #endif /* _SUN_SDK_ */
   1958 {
   1959   sasl_utils_t *utils;
   1960 #ifdef _SUN_SDK_
   1961   sasl_allocation_utils_t alloc;
   1962   sasl_mutex_utils_t mutex;
   1963 
   1964   LOCK_MUTEX(&malloc_global_mutex);
   1965   alloc = gctx->sasl_allocation_utils;
   1966   mutex = gctx->sasl_mutex_utils;
   1967   UNLOCK_MUTEX(&malloc_global_mutex);
   1968 #endif /* _SUN_SDK_ */
   1969 
   1970   /* set util functions - need to do rest*/
   1971 #ifdef _SUN_SDK_
   1972   utils=alloc.malloc(sizeof(sasl_utils_t));
   1973 #else
   1974   utils=sasl_ALLOC(sizeof(sasl_utils_t));
   1975 #endif /* _SUN_SDK_ */
   1976   if (utils==NULL)
   1977     return NULL;
   1978 
   1979   utils->conn = conn;
   1980 
   1981   sasl_randcreate(&utils->rpool);
   1982 
   1983   if (conn) {
   1984     utils->getopt = &_sasl_conn_getopt;
   1985     utils->getopt_context = conn;
   1986   } else {
   1987     utils->getopt = &_sasl_global_getopt;
   1988     utils->getopt_context = global_callbacks;
   1989   }
   1990 
   1991 #ifdef _SUN_SDK_
   1992   utils->malloc=alloc.malloc;
   1993   utils->calloc=alloc.calloc;
   1994   utils->realloc=alloc.realloc;
   1995   utils->free=alloc.free;
   1996 
   1997   utils->mutex_alloc = mutex.alloc;
   1998   utils->mutex_lock = mutex.lock;
   1999   utils->mutex_unlock = mutex.unlock;
   2000   utils->mutex_free = mutex.free;
   2001 #else
   2002   utils->malloc=_sasl_allocation_utils.malloc;
   2003   utils->calloc=_sasl_allocation_utils.calloc;
   2004   utils->realloc=_sasl_allocation_utils.realloc;
   2005   utils->free=_sasl_allocation_utils.free;
   2006 
   2007   utils->mutex_alloc = _sasl_mutex_utils.alloc;
   2008   utils->mutex_lock = _sasl_mutex_utils.lock;
   2009   utils->mutex_unlock = _sasl_mutex_utils.unlock;
   2010   utils->mutex_free = _sasl_mutex_utils.free;
   2011 #endif /* _SUN_SDK_ */
   2012 
   2013 #ifdef _SUN_SDK_
   2014   utils->MD5Init  = (void (*)(MD5_CTX *))&MD5Init;
   2015   utils->MD5Update= (void (*)
   2016 	(MD5_CTX *, const unsigned char *, unsigned int ))&MD5Update;
   2017   utils->MD5Final = (void (*)(unsigned char [16], MD5_CTX *))&MD5Final;
   2018 #else
   2019   utils->MD5Init  = &_sasl_MD5Init;
   2020   utils->MD5Update= &_sasl_MD5Update;
   2021   utils->MD5Final = &_sasl_MD5Final;
   2022 #endif /* _SUN_SDK_ */
   2023   utils->hmac_md5 = &_sasl_hmac_md5;
   2024   utils->hmac_md5_init = &_sasl_hmac_md5_init;
   2025   utils->hmac_md5_final = &_sasl_hmac_md5_final;
   2026   utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
   2027   utils->hmac_md5_import = &_sasl_hmac_md5_import;
   2028   utils->mkchal = &sasl_mkchal;
   2029   utils->utf8verify = &sasl_utf8verify;
   2030   utils->rand=&sasl_rand;
   2031   utils->churn=&sasl_churn;
   2032   utils->checkpass=NULL;
   2033 
   2034   utils->encode64=&sasl_encode64;
   2035   utils->decode64=&sasl_decode64;
   2036 
   2037   utils->erasebuffer=&sasl_erasebuffer;
   2038 
   2039   utils->getprop=&sasl_getprop;
   2040   utils->setprop=&sasl_setprop;
   2041 
   2042   utils->getcallback=&_sasl_getcallback;
   2043 
   2044   utils->log=&_sasl_log;
   2045 
   2046   utils->seterror=&sasl_seterror;
   2047 
   2048 #ifndef macintosh
   2049   /* Aux Property Utilities */
   2050   utils->prop_new=&prop_new;
   2051   utils->prop_dup=&prop_dup;
   2052   utils->prop_request=&prop_request;
   2053   utils->prop_get=&prop_get;
   2054   utils->prop_getnames=&prop_getnames;
   2055   utils->prop_clear=&prop_clear;
   2056   utils->prop_dispose=&prop_dispose;
   2057   utils->prop_format=&prop_format;
   2058   utils->prop_set=&prop_set;
   2059   utils->prop_setvals=&prop_setvals;
   2060   utils->prop_erase=&prop_erase;
   2061 #endif
   2062 
   2063   /* Spares */
   2064   utils->spare_fptr = NULL;
   2065   utils->spare_fptr1 = utils->spare_fptr2 =
   2066       utils->spare_fptr3 = NULL;
   2067 
   2068   return utils;
   2069 }
   2070 
   2071 int
   2072 _sasl_free_utils(const sasl_utils_t ** utils)
   2073 {
   2074     sasl_utils_t *nonconst;
   2075 #ifdef _SUN_SDK_
   2076     sasl_free_t *free_func;
   2077 #endif /* _SUN_SDK_ */
   2078 
   2079     if(!utils) return SASL_BADPARAM;
   2080     if(!*utils) return SASL_OK;
   2081 
   2082     /* I wish we could avoid this cast, it's pretty gratuitous but it
   2083      * does make life easier to have it const everywhere else. */
   2084     nonconst = (sasl_utils_t *)(*utils);
   2085 
   2086     sasl_randfree(&(nonconst->rpool));
   2087 #ifdef _SUN_SDK_
   2088     free_func = (*utils)->free;
   2089     free_func(nonconst);
   2090 #else
   2091     sasl_FREE(nonconst);
   2092 #endif /* _SUN_SDK_ */
   2093 
   2094     *utils = NULL;
   2095     return SASL_OK;
   2096 }
   2097 
   2098 int sasl_idle(sasl_conn_t *conn)
   2099 {
   2100   if (! conn) {
   2101 #ifdef _SUN_SDK_
   2102     _sasl_global_context_t *gctx = _sasl_gbl_ctx();
   2103 
   2104     if (gctx->sasl_server_idle_hook
   2105         && gctx->sasl_server_idle_hook(NULL))
   2106       return 1;
   2107     if (gctx->sasl_client_idle_hook
   2108         && gctx->sasl_client_idle_hook(NULL))
   2109       return 1;
   2110 #else
   2111     if (_sasl_server_idle_hook
   2112 	&& _sasl_server_idle_hook(NULL))
   2113       return 1;
   2114     if (_sasl_client_idle_hook
   2115 	&& _sasl_client_idle_hook(NULL))
   2116       return 1;
   2117 #endif /* _SUN_SDK_ */
   2118     return 0;
   2119   }
   2120 
   2121   if (conn->idle_hook)
   2122     return conn->idle_hook(conn);
   2123 
   2124   return 0;
   2125 }
   2126 
   2127 const sasl_callback_t *
   2128 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
   2129 {
   2130   static const sasl_callback_t default_getpath_cb = {
   2131     SASL_CB_GETPATH,
   2132     &_sasl_getpath,
   2133     NULL
   2134   };
   2135 
   2136   if (callbacks)
   2137     while (callbacks->id != SASL_CB_LIST_END)
   2138     {
   2139       if (callbacks->id == SASL_CB_GETPATH)
   2140       {
   2141 	return callbacks;
   2142       } else {
   2143 	++callbacks;
   2144       }
   2145     }
   2146 
   2147   return &default_getpath_cb;
   2148 }
   2149 
   2150 #ifdef _SUN_SDK_
   2151 extern const sasl_callback_t *
   2152 _sasl_find_getconf_callback(const sasl_callback_t *callbacks)
   2153 {
   2154   static const sasl_callback_t default_getconf_cb = {
   2155     SASL_CB_GETCONF,
   2156     &_sasl_getconf,
   2157     NULL
   2158   };
   2159 
   2160   if (callbacks)
   2161     while (callbacks->id != SASL_CB_LIST_END)
   2162     {
   2163       if (callbacks->id == SASL_CB_GETCONF)
   2164       {
   2165 	return callbacks;
   2166       } else {
   2167 	++callbacks;
   2168       }
   2169     }
   2170 
   2171   return &default_getconf_cb;
   2172 }
   2173 #endif /* _SUN_SDK_ */
   2174 
   2175 const sasl_callback_t *
   2176 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
   2177 {
   2178   static const sasl_callback_t default_verifyfile_cb = {
   2179     SASL_CB_VERIFYFILE,
   2180     &_sasl_verifyfile,
   2181     NULL
   2182   };
   2183 
   2184   if (callbacks)
   2185     while (callbacks->id != SASL_CB_LIST_END)
   2186     {
   2187       if (callbacks->id == SASL_CB_VERIFYFILE)
   2188       {
   2189 	return callbacks;
   2190       } else {
   2191 	++callbacks;
   2192       }
   2193     }
   2194 
   2195   return &default_verifyfile_cb;
   2196 }
   2197 
   2198 /* Basically a conditional call to realloc(), if we need more */
   2199 #ifdef _SUN_SDK_
   2200 int __buf_alloc(const _sasl_global_context_t *gctx, char **rwbuf,
   2201 		size_t *curlen, size_t newlen)
   2202 #else
   2203 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
   2204 #endif /* _SUN_SDK_ */
   2205 {
   2206     if(!(*rwbuf)) {
   2207 	*rwbuf = sasl_ALLOC(newlen);
   2208 	if (*rwbuf == NULL) {
   2209 	    *curlen = 0;
   2210 	    return SASL_NOMEM;
   2211 	}
   2212 	*curlen = newlen;
   2213     } else if(*rwbuf && *curlen < newlen) {
   2214 	size_t needed = 2*(*curlen);
   2215 
   2216 	while(needed < newlen)
   2217 	    needed *= 2;
   2218 
   2219 	*rwbuf = sasl_REALLOC(*rwbuf, needed);
   2220 
   2221 	if (*rwbuf == NULL) {
   2222 	    *curlen = 0;
   2223 	    return SASL_NOMEM;
   2224 	}
   2225 	*curlen = needed;
   2226     }
   2227 
   2228     return SASL_OK;
   2229 }
   2230 
   2231 /* for the mac os x cfm glue: this lets the calling function
   2232    get pointers to the error buffer without having to touch the sasl_conn_t struct */
   2233 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
   2234 {
   2235 	*bufhdl = &conn->error_buf;
   2236 	*lenhdl = &conn->error_buf_len;
   2237 }
   2238 
   2239 /* convert an iovec to a single buffer */
   2240 #ifdef _SUN_SDK_
   2241 int _iovec_to_buf(const _sasl_global_context_t *gctx, const struct iovec *vec,
   2242 		  unsigned numiov, buffer_info_t **output)
   2243 #else
   2244 int _iovec_to_buf(const struct iovec *vec,
   2245 		  unsigned numiov, buffer_info_t **output)
   2246 #endif /* _SUN_SDK_ */
   2247 {
   2248     unsigned i;
   2249     int ret;
   2250     buffer_info_t *out;
   2251     char *pos;
   2252 
   2253     if(!vec || !output) return SASL_BADPARAM;
   2254 
   2255     if(!(*output)) {
   2256 	*output = sasl_ALLOC(sizeof(buffer_info_t));
   2257 	if(!*output) return SASL_NOMEM;
   2258 	memset(*output,0,sizeof(buffer_info_t));
   2259     }
   2260 
   2261     out = *output;
   2262 
   2263     out->curlen = 0;
   2264     for(i=0; i<numiov; i++)
   2265 	out->curlen += vec[i].iov_len;
   2266 
   2267     ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
   2268 
   2269     if(ret != SASL_OK) return SASL_NOMEM;
   2270 
   2271     memset(out->data, 0, out->reallen);
   2272     pos = out->data;
   2273 
   2274     for(i=0; i<numiov; i++) {
   2275 	memcpy(pos, vec[i].iov_base, vec[i].iov_len);
   2276 	pos += vec[i].iov_len;
   2277     }
   2278 
   2279     return SASL_OK;
   2280 }
   2281 
   2282 /* This code might be useful in the future, but it isn't now, so.... */
   2283 #if 0
   2284 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
   2285 		     char *out, unsigned outlen) {
   2286     char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
   2287 
   2288     if(!addr || !out) return SASL_BADPARAM;
   2289 
   2290     getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
   2291 		NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
   2292 
   2293     if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
   2294 	return SASL_BUFOVER;
   2295 
   2296     snprintf(out, outlen, "%s;%s", hbuf, pbuf);
   2297 
   2298     return SASL_OK;
   2299 }
   2300 #endif
   2301 
   2302 #ifdef _SUN_SDK_
   2303 /* An ipv6 address will contain at least two colons */
   2304 static int can_be_ipv6(const char *addr)
   2305 {
   2306    const char *p;
   2307 
   2308    if ((p = strchr(addr, ':')) == NULL)
   2309 	return (0);
   2310 
   2311    p = strchr(p + 1, ':');
   2312 
   2313    return (p != NULL);
   2314 }
   2315 #endif /* _SUN_SDK_ */
   2316 
   2317 int _sasl_ipfromstring(const char *addr,
   2318 		       struct sockaddr *out, socklen_t outlen)
   2319 {
   2320     int i, j;
   2321     struct addrinfo hints, *ai = NULL;
   2322     char hbuf[NI_MAXHOST];
   2323 #ifdef _SUN_SDK_
   2324     const char *start, *end, *p;
   2325     int addr_only = 1;
   2326 #endif /* _SUN_SDK_ */
   2327 
   2328     /* A NULL out pointer just implies we don't do a copy, just verify it */
   2329 
   2330     if(!addr) return SASL_BADPARAM;
   2331 
   2332 #ifdef _SUN_SDK_
   2333     end = strchr(addr, ']');
   2334     if (end != NULL) {
   2335 	/* This an rfc 2732 ipv6 address */
   2336 	start = strchr(addr, '[');
   2337 	if (start >= end || start == NULL)
   2338 	    return SASL_BADPARAM;
   2339 	for (i = 0, p = start + 1; p < end; p++) {
   2340 	    hbuf[i++] = *p;
   2341 	    if (i >= NI_MAXHOST)
   2342 		return SASL_BADPARAM;
   2343 	}
   2344 	p = strchr(end, ':');
   2345 	if (p == NULL)
   2346 		p = end + 1;
   2347 	else
   2348 		p = p + 1;
   2349     } else if (can_be_ipv6(addr) != 0) {
   2350 	/* Parse the address */
   2351 	for (i = 0; addr[i] != '\0' && addr[i] != ';'; ) {
   2352 	    hbuf[i] = addr[i];
   2353 	    if (++i >= NI_MAXHOST)
   2354 		return SASL_BADPARAM;
   2355 	}
   2356 	if (addr[i] == ';')
   2357 	     p = &addr[i+1];
   2358 	else
   2359 	     p = &addr[i];
   2360     } else {
   2361 	for (i = 0; addr[i] != '\0' && addr[i] != ';' && addr[i] != ':'; ) {
   2362 	    hbuf[i] = addr[i];
   2363 	    if (isalpha(addr[i]))
   2364 		addr_only = 0;
   2365 	    if (++i >= NI_MAXHOST)
   2366 		return SASL_BADPARAM;
   2367 	}
   2368 	if (addr[i] == ';' || addr[i] == ':')
   2369 	     p = &addr[i+1];
   2370 	else
   2371 	     p = &addr[i];
   2372     }
   2373     hbuf[i] = '\0';
   2374     for (j = 0; p[j] != '\0'; j++)
   2375 	if (!isdigit((int)(p[j])))
   2376 	    return SASL_BADPARAM;
   2377     if (atoi(p) == 0)
   2378 	p = NULL;
   2379 #else
   2380     /* Parse the address */
   2381     for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
   2382 	if (i >= NI_MAXHOST)
   2383 	    return SASL_BADPARAM;
   2384 	hbuf[i] = addr[i];
   2385     }
   2386     hbuf[i] = '\0';
   2387 
   2388     if (addr[i] == ';')
   2389 	i++;
   2390     /* XXX: Do we need this check? */
   2391     for (j = i; addr[j] != '\0'; j++)
   2392 	if (!isdigit((int)(addr[j])))
   2393 	    return SASL_BADPARAM;
   2394 #endif /* _SUN_SDK_ */
   2395 
   2396     memset(&hints, 0, sizeof(hints));
   2397     hints.ai_family = PF_UNSPEC;
   2398     hints.ai_socktype = SOCK_STREAM;
   2399 #ifdef _SUN_SDK_
   2400     hints.ai_flags = addr_only ? AI_PASSIVE | AI_NUMERICHOST : AI_PASSIVE;
   2401     if (getaddrinfo(hbuf, p, &hints, &ai) != 0)
   2402 #else
   2403     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
   2404     if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
   2405 #endif /* _SUN_SDK_ */
   2406 	return SASL_BADPARAM;
   2407 
   2408     if (out) {
   2409 	if (outlen < (socklen_t)ai->ai_addrlen) {
   2410 	    freeaddrinfo(ai);
   2411 	    return SASL_BUFOVER;
   2412 	}
   2413 	memcpy(out, ai->ai_addr, ai->ai_addrlen);
   2414     }
   2415 
   2416     freeaddrinfo(ai);
   2417 
   2418     return SASL_OK;
   2419 }
   2420 
   2421 #ifdef _SUN_SDK_
   2422 int _sasl_build_mechlist(_sasl_global_context_t *gctx)
   2423 #else
   2424 int _sasl_build_mechlist(void)
   2425 #endif /* _SUN_SDK_ */
   2426 {
   2427     int count = 0;
   2428     sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
   2429     sasl_string_list_t *p, *q, **last, *p_next;
   2430 
   2431 #ifdef _SUN_SDK_
   2432     char **global_mech_list;
   2433 
   2434     LOCK_MUTEX(&global_mutex);
   2435 
   2436     clist = _sasl_client_mechs(gctx);
   2437     slist = _sasl_server_mechs(gctx);
   2438 
   2439     global_mech_list = gctx->global_mech_list;
   2440 #else
   2441     clist = _sasl_client_mechs();
   2442     slist = _sasl_server_mechs();
   2443 #endif /* _SUN_SDK_ */
   2444 
   2445     if(!clist) {
   2446 	olist = slist;
   2447     } else {
   2448 	int flag;
   2449 
   2450 	/* append slist to clist, and set olist to clist */
   2451 	for(p = slist; p; p = p_next) {
   2452 	    flag = 0;
   2453 	    p_next = p->next;
   2454 
   2455 	    last = &clist;
   2456 	    for(q = clist; q; q = q->next) {
   2457 		if(!strcmp(q->d, p->d)) {
   2458 		    /* They match, set the flag */
   2459 		    flag = 1;
   2460 		    break;
   2461 		}
   2462 		last = &(q->next);
   2463 	    }
   2464 
   2465 	    if(!flag) {
   2466 		*last = p;
   2467 		p->next = NULL;
   2468 	    } else {
   2469 		sasl_FREE(p);
   2470 	    }
   2471 	}
   2472 
   2473 	olist = clist;
   2474     }
   2475 
   2476     if(!olist) {
   2477 #ifdef _SUN_SDK_
   2478 	UNLOCK_MUTEX(&global_mutex);
   2479 #else
   2480 	printf ("no olist");
   2481 #endif /* _SUN_SDK_ */
   2482 	return SASL_FAIL;
   2483     }
   2484 
   2485     for (p = olist; p; p = p->next) count++;
   2486 
   2487     if(global_mech_list) {
   2488 	sasl_FREE(global_mech_list);
   2489 #ifdef _SUN_SDK_
   2490 	gctx->global_mech_list = NULL;
   2491 #else
   2492 	global_mech_list = NULL;
   2493 #endif /* _SUN_SDK_ */
   2494     }
   2495 
   2496     global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
   2497     if(!global_mech_list) return SASL_NOMEM;
   2498 
   2499     memset(global_mech_list, 0, (count + 1) * sizeof(char *));
   2500 #ifdef _SUN_SDK_
   2501     gctx->global_mech_list = global_mech_list;
   2502 #endif /* _SUN_SDK_ */
   2503 
   2504     count = 0;
   2505     for (p = olist; p; p = p_next) {
   2506 	p_next = p->next;
   2507 
   2508 	global_mech_list[count++] = (char *) p->d;
   2509 
   2510     	sasl_FREE(p);
   2511     }
   2512 
   2513 #ifdef _SUN_SDK_
   2514     UNLOCK_MUTEX(&global_mutex);
   2515 #endif /* _SUN_SDK_ */
   2516 
   2517     return SASL_OK;
   2518 }
   2519 
   2520 const char ** sasl_global_listmech(void)
   2521 {
   2522 #ifdef _SUN_SDK_
   2523     _sasl_global_context_t *gctx = _sasl_gbl_ctx();
   2524 
   2525     return (const char **)gctx->global_mech_list;
   2526 #else
   2527     return (const char **)global_mech_list;
   2528 #endif /* _SUN_SDK_ */
   2529 }
   2530 
   2531 int sasl_listmech(sasl_conn_t *conn,
   2532 		  const char *user,
   2533 		  const char *prefix,
   2534 		  const char *sep,
   2535 		  const char *suffix,
   2536 		  const char **result,
   2537 		  unsigned *plen,
   2538 		  int *pcount)
   2539 {
   2540     if(!conn) {
   2541 	return SASL_BADPARAM;
   2542     } else if(conn->type == SASL_CONN_SERVER) {
   2543 	RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
   2544 					   result, plen, pcount));
   2545     } else if (conn->type == SASL_CONN_CLIENT) {
   2546 	RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
   2547 					   result, plen, pcount));
   2548     }
   2549 
   2550     PARAMERROR(conn);
   2551 }
   2552 
   2553 #ifdef _SUN_SDK_
   2554 /*
   2555  * Creates a context so that libraries may use libsasl independently
   2556  * of applications using libsasl.
   2557  * Returns NULL on failure.
   2558  *
   2559  * sasl_free_context frees the context
   2560  * To use libsasl independently of the default context, use
   2561  * _sasl_server_init()		instead of	sasl_server_init()
   2562  * _sasl_server_new()		instead of	sasl_server_new()
   2563  * _sasl_client_init()		instead of	sasl_client_init()
   2564  * _sasl_client_new()		instead of	sasl_client_new()
   2565  * _sasl_client_add_plugin()	instead of	sasl_client_add_plugin()
   2566  * _sasl_server_add_plugin()	instead of	sasl_server_add_plugin()
   2567  * _sasl_canonuser_add_plugin()	instead of	sasl_canonuser_add_plugin()
   2568  * _sasl_auxprop_add_plugin()	instead of	sasl_auxprop_add_plugin()
   2569  */
   2570 
   2571 void *sasl_create_context(void)
   2572 {
   2573   _sasl_global_context_t *gctx;
   2574 
   2575   gctx = (_sasl_global_context_t *)
   2576 	sasl_sun_ALLOC(sizeof(_sasl_global_context_t));
   2577 
   2578   if (gctx != NULL) {
   2579     memset(gctx, 0, sizeof(_sasl_global_context_t));
   2580 
   2581     gctx->server_global_callbacks.gctx = gctx;
   2582     gctx->client_global_callbacks.gctx = gctx;
   2583     LOCK_MUTEX(&malloc_global_mutex);
   2584     gctx->sasl_allocation_utils.malloc = (sasl_malloc_t *)&malloc;
   2585     gctx->sasl_allocation_utils.calloc = (sasl_calloc_t *)&calloc;
   2586     gctx->sasl_allocation_utils.realloc = (sasl_realloc_t *)&realloc;
   2587     gctx->sasl_allocation_utils.free = (sasl_free_t *)&free;
   2588     gctx->sasl_mutex_utils.alloc = sasl_mutex_alloc;
   2589     gctx->sasl_mutex_utils.lock = sasl_mutex_lock;
   2590     gctx->sasl_mutex_utils.unlock = sasl_mutex_unlock;
   2591     gctx->sasl_mutex_utils.free = sasl_mutex_free;
   2592     UNLOCK_MUTEX(&malloc_global_mutex);
   2593   }
   2594   return gctx;
   2595 }
   2596 
   2597 /* Frees the context created by sasl_create_context() */
   2598 void sasl_free_context(void *context)
   2599 {
   2600   _sasl_dispose_context(context);
   2601   if (context != NULL) {
   2602     sasl_sun_FREE(context);
   2603   }
   2604 }
   2605 
   2606 /* Used by both sasl_done() and sasl_free_context() to free context */
   2607 static void _sasl_dispose_context(_sasl_global_context_t *gctx)
   2608 {
   2609   if (gctx == NULL)
   2610         return;
   2611 
   2612   if (gctx->sasl_server_cleanup_hook &&
   2613 		gctx->sasl_server_cleanup_hook(gctx) == SASL_OK) {
   2614 	gctx->sasl_server_idle_hook = NULL;
   2615 	gctx->sasl_server_cleanup_hook = NULL;
   2616   }
   2617 
   2618   if (gctx->sasl_client_cleanup_hook &&
   2619 		gctx->sasl_client_cleanup_hook(gctx) == SASL_OK) {
   2620 	gctx->sasl_client_idle_hook = NULL;
   2621 	gctx->sasl_client_cleanup_hook = NULL;
   2622   }
   2623 
   2624   if(gctx->sasl_server_cleanup_hook || gctx->sasl_client_cleanup_hook)
   2625 	return;
   2626 
   2627   _sasl_canonuser_free(gctx);
   2628   _sasl_done_with_plugins(gctx);
   2629 
   2630   sasl_config_free(gctx);
   2631 
   2632   if (gctx->free_mutex != NULL)
   2633     sasl_MUTEX_FREE(gctx->free_mutex);
   2634   gctx->free_mutex = NULL;
   2635 
   2636   _sasl_free_utils(&(gctx->sasl_server_global_utils));
   2637   _sasl_free_utils(&(gctx->sasl_canonusr_global_utils));
   2638 
   2639   LOCK_MUTEX(&global_mutex);
   2640   sasl_FREE((void *)gctx->global_mech_list);
   2641   gctx->global_mech_list = NULL;
   2642   UNLOCK_MUTEX(&global_mutex);
   2643 
   2644   /* in case of another init/done */
   2645   gctx->sasl_server_cleanup_hook = NULL;
   2646   gctx->sasl_client_cleanup_hook = NULL;
   2647 
   2648   gctx->sasl_client_idle_hook = NULL;
   2649   gctx->sasl_server_idle_hook = NULL;
   2650 }
   2651 
   2652 _sasl_global_context_t *_sasl_gbl_ctx(void)
   2653 {
   2654   static _sasl_global_context_t gbl_ctx = {
   2655         0,                      /* sasl_server_active */
   2656         NULL,                   /* mechlist */
   2657 	NULL,			/* splug_path_info */
   2658         {NULL, NULL, &gbl_ctx}, /* server_global_callbacks */
   2659         NULL,                   /* sasl_server_cleanup_hook */
   2660         NULL,                   /* sasl_server_idle_hook */
   2661         NULL,                   /* cmechlist */
   2662 	NULL,			/* cplug_path_info */
   2663         {NULL, NULL, &gbl_ctx}, /* client_global_callbacks */
   2664         0,                      /* sasl_client_active */
   2665         NULL,                   /* sasl_client_cleanup_hook */
   2666         NULL,                   /* sasl_client_idle_hook */
   2667         NULL,                   /* sasl_server_global_utils */
   2668         NULL,                   /* sasl_client_global_utils */
   2669         NULL,                   /* configlist */
   2670         0,                      /* nconfiglist */
   2671 	NULL,			/* config_path */
   2672 	0,			/* config_last_read */
   2673         NULL,                   /* auxprop_head */
   2674         NULL,                   /* canonuser_head */
   2675         NULL,                   /* global_mech_list */
   2676         NULL,                   /* free_mutex */
   2677         {(sasl_malloc_t *)&malloc, (sasl_calloc_t *)&calloc,
   2678             (sasl_realloc_t *)&realloc, (sasl_free_t *)&free},
   2679                                 /* sasl_allocation_utils */
   2680         {&sasl_mutex_alloc, &sasl_mutex_lock, &sasl_mutex_unlock,
   2681             &sasl_mutex_free},  /* sasl_mutex_utils */
   2682         NULL			/* lib_list_head */
   2683   };
   2684 
   2685   return (&gbl_ctx);
   2686 }
   2687 
   2688 static int
   2689 _sasl_getconf(void *context __attribute__((unused)), const char **conf)
   2690 {
   2691     if (! conf)
   2692 	return SASL_BADPARAM;
   2693 
   2694     *conf = SASL_CONFDIR;
   2695 
   2696     return SASL_OK;
   2697 }
   2698 
   2699 /* EXPORT DELETE START */
   2700 /* CRYPT DELETE START */
   2701 #ifdef _INTEGRATED_SOLARIS_
   2702 #pragma fini(sasl_fini)
   2703 int
   2704 sasl_fini(void)
   2705 {
   2706     reg_list_t *next;
   2707 
   2708     while (reg_list_base != NULL) {
   2709 	next = reg_list_base->next;
   2710 	free(reg_list_base);
   2711 	reg_list_base = next;
   2712     }
   2713     return (0);
   2714 }
   2715 #endif /* _INTEGRATED_SOLARIS_ */
   2716 /* CRYPT DELETE END */
   2717 /* EXPORT DELETE END */
   2718 
   2719 #endif /* _SUN_SDK_ */
   2720 
   2721 #ifndef WIN32
   2722 static int
   2723 _sasl_getpath(void *context __attribute__((unused)),
   2724 	      const char **path)
   2725 {
   2726   if (! path)
   2727     return SASL_BADPARAM;
   2728 
   2729 #ifdef _SUN_SDK_
   2730 /* SASL_PATH is not allowed for SUN SDK */
   2731 #else
   2732   *path = getenv(SASL_PATH_ENV_VAR);
   2733   if (! *path)
   2734 #endif /* _SUN_SDK_ */
   2735     *path = PLUGINDIR;
   2736 
   2737   return SASL_OK;
   2738 }
   2739 
   2740 #else
   2741 /* Return NULL on failure */
   2742 static int
   2743 _sasl_getpath(void *context __attribute__((unused)), const char **path)
   2744 {
   2745     /* Open registry entry, and find all registered SASL libraries.
   2746      *
   2747      * Registry location:
   2748      *
   2749      *     SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
   2750      *
   2751      * Key - value:
   2752      *
   2753      *     "SearchPath" - value: PATH like (';' delimited) list
   2754      *                    of directories where to search for plugins
   2755      *                    The list may contain references to environment
   2756      *                    variables (e.g. %PATH%).
   2757      *
   2758      */
   2759     HKEY  hKey;
   2760     DWORD ret;
   2761     DWORD ValueType;		    /* value type */
   2762     DWORD cbData;		    /* value size */
   2763     BYTE * ValueData;		    /* value */
   2764     DWORD cbExpandedData;	    /* "expanded" value size */
   2765     BYTE * ExpandedValueData;	    /* "expanded" value */
   2766     char * return_value;	    /* function return value */
   2767     char * tmp;
   2768 
   2769     /* Initialization */
   2770     ExpandedValueData = NULL;
   2771     ValueData = NULL;
   2772     return_value = NULL;
   2773 
   2774     /* Open the registry */
   2775     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
   2776 		       SASL_ROOT_KEY,
   2777 		       0,
   2778 		       KEY_READ,
   2779 		       &hKey);
   2780 
   2781     if (ret != ERROR_SUCCESS) {
   2782 		/* no registry entry */
   2783 		*path = PLUGINDIR;
   2784 		return SASL_OK;
   2785 	}
   2786 
   2787     /* figure out value type and required buffer size */
   2788     /* the size will include space for terminating NUL if required */
   2789     RegQueryValueEx (hKey,
   2790 		     SASL_PATH_SUBKEY,
   2791 		     NULL,	    /* reserved */
   2792 		     &ValueType,
   2793 		     NULL,
   2794 		     &cbData);
   2795 
   2796     /* Only accept string related types */
   2797     if (ValueType != REG_EXPAND_SZ &&
   2798 	ValueType != REG_MULTI_SZ &&
   2799 	ValueType != REG_SZ) {
   2800 	return_value = NULL;
   2801 	goto CLEANUP;
   2802     }
   2803 
   2804     /* Any high water mark? */
   2805     ValueData = sasl_ALLOC(cbData);
   2806     if (ValueData == NULL) {
   2807 	return_value = NULL;
   2808 	goto CLEANUP;
   2809     };
   2810 
   2811     RegQueryValueEx (hKey,
   2812 		     SASL_PATH_SUBKEY,
   2813 		     NULL,	    /* reserved */
   2814 		     &ValueType,
   2815 		     ValueData,
   2816 		     &cbData);
   2817 
   2818     switch (ValueType) {
   2819     case REG_EXPAND_SZ:
   2820         /* : A random starting guess */
   2821         cbExpandedData = cbData + 1024;
   2822         ExpandedValueData = sasl_ALLOC(cbExpandedData);
   2823         if (ExpandedValueData == NULL) {
   2824             return_value = NULL;
   2825             goto CLEANUP;
   2826         };
   2827 
   2828         cbExpandedData = ExpandEnvironmentStrings(
   2829                                                   ValueData,
   2830                                                   ExpandedValueData,
   2831                                                   cbExpandedData);
   2832 
   2833         if (cbExpandedData == 0) {
   2834             /* : GetLastError() contains the reason for failure */
   2835             return_value = NULL;
   2836             goto CLEANUP;
   2837         }
   2838 
   2839         /* : Must retry expansion with the bigger buffer */
   2840         if (cbExpandedData > cbData + 1024) {
   2841             /* : Memory leak here if can't realloc */
   2842             ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
   2843             if (ExpandedValueData == NULL) {
   2844                 return_value = NULL;
   2845                 goto CLEANUP;
   2846             };
   2847 
   2848             cbExpandedData = ExpandEnvironmentStrings(
   2849                                                       ValueData,
   2850                                                       ExpandedValueData,
   2851                                                       cbExpandedData);
   2852 
   2853             /* : This should not happen */
   2854             if (cbExpandedData == 0) {
   2855                 /* : GetLastError() contains the reason for failure */
   2856                 return_value = NULL;
   2857                 goto CLEANUP;
   2858             }
   2859         }
   2860 
   2861         sasl_FREE(ValueData);
   2862         ValueData = ExpandedValueData;
   2863         /* : This is to prevent automatical freeing of this block on cleanup */
   2864         ExpandedValueData = NULL;
   2865 
   2866         break;
   2867 
   2868     case REG_MULTI_SZ:
   2869         tmp = ValueData;
   2870 
   2871         /* : We shouldn't overflow here, as the buffer is guarantied
   2872            : to contain at least two consequent NULs */
   2873         while (1) {
   2874             if (tmp[0] == '\0') {
   2875                 /* : Stop the process if we found the end of the string (two consequent NULs) */
   2876                 if (tmp[1] == '\0') {
   2877                     break;
   2878                 }
   2879 
   2880                 /* : Replace delimiting NUL with our delimiter characted */
   2881                 tmp[0] = PATHS_DELIMITER;
   2882             }
   2883             tmp += strlen(tmp);
   2884         }
   2885         break;
   2886 
   2887     case REG_SZ:
   2888         /* Do nothing, it is good as is */
   2889         break;
   2890 
   2891     default:
   2892         return_value = NULL;
   2893         goto CLEANUP;
   2894     }
   2895 
   2896     return_value = ValueData;
   2897 
   2898     CLEANUP:
   2899     RegCloseKey(hKey);
   2900     if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
   2901     if (return_value == NULL) {
   2902 	if (ValueData != NULL) sasl_FREE(ValueData);
   2903     }
   2904     *path = return_value;
   2905 
   2906 #ifdef _SUN_SDK_
   2907 /* SASL_PATH is not allowed for SUN SDK */
   2908   if (! *path)
   2909     *path = PLUGINDIR;
   2910 #endif /* _SUN_SDK_ */
   2911 	return SASL_OK;
   2912 }
   2913 
   2914 #endif
   2915