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