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