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