xref: /illumos-gate/usr/src/lib/libsasl/lib/common.c (revision 7c478bd9)
1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
6 
7 /* common.c - Functions that are common to server and clinet
8  * Rob Siemborski
9  * Tim Martin
10  * $Id: common.c,v 1.92 2003/04/16 19:36:00 rjs3 Exp $
11  */
12 /*
13  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  *
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  *
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in
24  *    the documentation and/or other materials provided with the
25  *    distribution.
26  *
27  * 3. The name "Carnegie Mellon University" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For permission or any other legal
30  *    details, please contact
31  *      Office of Technology Transfer
32  *      Carnegie Mellon University
33  *      5000 Forbes Avenue
34  *      Pittsburgh, PA  15213-3890
35  *      (412) 268-4387, fax: (412) 268-7395
36  *      tech-transfer@andrew.cmu.edu
37  *
38  * 4. Redistributions of any form whatsoever must retain the following
39  *    acknowledgment:
40  *    "This product includes software developed by Computing Services
41  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
42  *
43  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
44  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
45  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
46  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
47  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
48  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
49  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
50  */
51 
52 #include <config.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <limits.h>
57 #ifdef HAVE_SYSLOG
58 #include <syslog.h>
59 #endif
60 #include <stdarg.h>
61 #include <ctype.h>
62 
63 #include <sasl.h>
64 #include <saslutil.h>
65 #include <saslplug.h>
66 #include "saslint.h"
67 
68 #ifdef _SUN_SDK_
69 #include "md5_private.h"
70 #include "hmac-md5.h"
71 #include "plugin_common.h"
72 #endif
73 
74 
75 #ifdef WIN32
76 /* need to handle the fact that errno has been defined as a function
77    in a dll, not an extern int */
78 # ifdef errno
79 #  undef errno
80 # endif /* errno */
81 #endif /* WIN32 */
82 #ifdef HAVE_UNISTD_H
83 #include <unistd.h>
84 #endif
85 
86 static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
87 
88 #ifdef _SUN_SDK_
89 DEFINE_STATIC_MUTEX(global_mutex);
90 DEFINE_STATIC_MUTEX(malloc_global_mutex);
91 static void _sasl_dispose_context(_sasl_global_context_t *ctx);
92 static int _sasl_getconf(void *context, const char **conf);
93 
94 #ifdef _INTEGRATED_SOLARIS_
95 static int init_thread_set_specific = 0;
96 static pthread_key_t errstring_key;
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     pthread_setspecific(errstring_key, NULL);
1115 }
1116 #endif /* _INTEGRATED_SOLARIS_ */
1117 
1118 const char *sasl_errstring(int saslerr,
1119 #ifdef _SUN_SDK_
1120 			   const char *langlist,
1121 #else
1122 			   const char *langlist __attribute__((unused)),
1123 #endif /* _SUN_SDK_ */
1124 			   const char **outlang)
1125 {
1126 #ifdef _INTEGRATED_SOLARIS_
1127   const char *s;
1128   const char *s_locale;
1129   char *s_utf8;
1130   void *tsd;
1131 
1132   if (outlang) *outlang="i-default";
1133 #else
1134   if (outlang) *outlang="en-us";
1135 #endif /* _INTEGRATED_SOLARIS_ */
1136 
1137 #ifdef _INTEGRATED_SOLARIS_
1138   switch(saslerr)
1139     {
1140     case SASL_CONTINUE: s = gettext("another step is needed in authentication");
1141 	break;
1142     case SASL_OK:       s = gettext("successful result");
1143 	break;
1144     case SASL_FAIL:     s = gettext("generic failure");
1145 	break;
1146     case SASL_NOMEM:    s = gettext("no memory available");
1147 	break;
1148     case SASL_BUFOVER:  s = gettext("overflowed buffer");
1149 	break;
1150     case SASL_NOMECH:   s = gettext("no mechanism available");
1151 	break;
1152     case SASL_BADPROT:  s = gettext("bad protocol / cancel");
1153 	break;
1154     case SASL_NOTDONE:  s = gettext("can't request info until later in exchange");
1155 	break;
1156     case SASL_BADPARAM: s = gettext("invalid parameter supplied");
1157 	break;
1158     case SASL_TRYAGAIN: s = gettext("transient failure (e.g., weak key)");
1159 	break;
1160     case SASL_BADMAC:   s = gettext("integrity check failed");
1161 	break;
1162     case SASL_NOTINIT:  s = gettext("SASL library not initialized");
1163 	break;
1164                              /* -- client only codes -- */
1165     case SASL_INTERACT:   s = gettext("needs user interaction");
1166 	break;
1167     case SASL_BADSERV:    s = gettext("server failed mutual authentication step");
1168 	break;
1169     case SASL_WRONGMECH:  s = gettext("mechanism doesn't support requested feature");
1170 	break;
1171                              /* -- server only codes -- */
1172     case SASL_BADAUTH:    s = gettext("authentication failure");
1173 	break;
1174     case SASL_NOAUTHZ:    s = gettext("authorization failure");
1175 	break;
1176     case SASL_TOOWEAK:    s = gettext("mechanism too weak for this user");
1177 	break;
1178     case SASL_ENCRYPT:    s = gettext("encryption needed to use mechanism");
1179 	break;
1180     case SASL_TRANS:      s = gettext("One time use of a plaintext password will enable requested mechanism for user");
1181 	break;
1182     case SASL_EXPIRED:    s = gettext("passphrase expired, has to be reset");
1183 	break;
1184     case SASL_DISABLED:   s = gettext("account disabled");
1185 	break;
1186     case SASL_NOUSER:     s = gettext("user not found");
1187 	break;
1188     case SASL_BADVERS:    s = gettext("version mismatch with plug-in");
1189 	break;
1190     case SASL_UNAVAIL:    s = gettext("remote authentication server unavailable");
1191 	break;
1192     case SASL_NOVERIFY:   s = gettext("user exists, but no verifier for user");
1193 	break;
1194     case SASL_PWLOCK:     s = gettext("passphrase locked");
1195 	break;
1196     case SASL_NOCHANGE:   s = gettext("requested change was not needed");
1197 	break;
1198     case SASL_WEAKPASS:   s = gettext("passphrase is too weak for security policy");
1199 	break;
1200     case SASL_NOUSERPASS: s = gettext("user supplied passwords are not permitted");
1201 
1202 	break;
1203     default:   s = gettext("undefined error!");
1204 	break;
1205   }
1206 
1207   if (use_locale(langlist, 0))
1208     s_locale = dgettext(TEXT_DOMAIN, s);
1209   else
1210     s_locale = s;
1211 
1212   if (s == s_locale)
1213     return s;
1214 
1215   s_utf8 = local_to_utf(NULL, s_locale);
1216   if (s_utf8 == NULL)
1217     return s;
1218 
1219   if (!init_thread_set_specific) {
1220     LOCK_MUTEX(&global_mutex);
1221     if (!init_thread_set_specific) {
1222       if (pthread_key_create(&errstring_key, free_err_tsd) == 0)
1223 	init_thread_set_specific = 1;
1224     }
1225     UNLOCK_MUTEX(&global_mutex);
1226   }
1227   if (!init_thread_set_specific) {
1228     free(s_utf8);
1229     return s;
1230   }
1231 
1232   tsd = pthread_getspecific(errstring_key);
1233   if (tsd == NULL)
1234     free(tsd);
1235   pthread_setspecific(errstring_key, s_utf8);
1236 
1237   if (outlang) *outlang="*";
1238   return s_utf8;
1239 #else
1240   switch(saslerr)
1241     {
1242     case SASL_CONTINUE: return "another step is needed in authentication";
1243     case SASL_OK:       return "successful result";
1244     case SASL_FAIL:     return "generic failure";
1245     case SASL_NOMEM:    return "no memory available";
1246     case SASL_BUFOVER:  return "overflowed buffer";
1247     case SASL_NOMECH:   return "no mechanism available";
1248     case SASL_BADPROT:  return "bad protocol / cancel";
1249     case SASL_NOTDONE:  return "can't request info until later in exchange";
1250     case SASL_BADPARAM: return "invalid parameter supplied";
1251     case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
1252     case SASL_BADMAC:   return "integrity check failed";
1253     case SASL_NOTINIT:  return "SASL library not initialized";
1254                              /* -- client only codes -- */
1255     case SASL_INTERACT:   return "needs user interaction";
1256     case SASL_BADSERV:    return "server failed mutual authentication step";
1257     case SASL_WRONGMECH:  return "mechanism doesn't support requested feature";
1258                              /* -- server only codes -- */
1259     case SASL_BADAUTH:    return "authentication failure";
1260     case SASL_NOAUTHZ:    return "authorization failure";
1261     case SASL_TOOWEAK:    return "mechanism too weak for this user";
1262     case SASL_ENCRYPT:    return "encryption needed to use mechanism";
1263     case SASL_TRANS:      return "One time use of a plaintext password will enable requested mechanism for user";
1264     case SASL_EXPIRED:    return "passphrase expired, has to be reset";
1265     case SASL_DISABLED:   return "account disabled";
1266     case SASL_NOUSER:     return "user not found";
1267     case SASL_BADVERS:    return "version mismatch with plug-in";
1268     case SASL_UNAVAIL:    return "remote authentication server unavailable";
1269     case SASL_NOVERIFY:   return "user exists, but no verifier for user";
1270     case SASL_PWLOCK:     return "passphrase locked";
1271     case SASL_NOCHANGE:   return "requested change was not needed";
1272     case SASL_WEAKPASS:   return "passphrase is too weak for security policy";
1273     case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
1274 
1275     default:   return "undefined error!";
1276     }
1277 #endif /* _INTEGRATED_SOLARIS_ */
1278 
1279 }
1280 
1281 /* Return the sanitized error detail about the last error that occured for
1282  * a connection */
1283 const char *sasl_errdetail(sasl_conn_t *conn)
1284 {
1285     unsigned need_len;
1286     const char *errstr;
1287     char leader[128];
1288 #ifdef _SUN_SDK_
1289     int ret;
1290     const _sasl_global_context_t *gctx;
1291 
1292     if(!conn) return "invalid parameter supplied";
1293 
1294     gctx = conn->gctx;
1295 #else
1296     if(!conn) return NULL;
1297 #endif /* _SUN_SDK_ */
1298 
1299     errstr = sasl_errstring(conn->error_code, NULL, NULL);
1300     snprintf(leader,128,"SASL(%d): %s: ",
1301 	     sasl_usererr(conn->error_code), errstr);
1302 
1303     need_len = strlen(leader) + strlen(conn->error_buf) + 12;
1304 #ifdef _SUN_SDK_
1305     ret = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1306     if (ret != SASL_OK)
1307 	return "no memory available";
1308 #else
1309     _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1310 #endif /* _SUN_SDK_ */
1311 
1312     snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
1313 
1314     return conn->errdetail_buf;
1315 }
1316 
1317 /* EXPORT DELETE START */
1318 /* CRYPT DELETE START */
1319 #ifdef _INTEGRATED_SOLARIS_
1320 DEFINE_STATIC_MUTEX(reg_mutex);
1321 typedef struct reg_list {
1322 	struct reg_list *next;
1323 	void *mech;
1324 } reg_list_t;
1325 
1326 static reg_list_t *reg_list_base = NULL;
1327 
1328 int _is_sun_reg(void *mech)
1329 {
1330 	reg_list_t *r, *prev;
1331 	int is_reg = 0;
1332 
1333 	LOCK_MUTEX(&reg_mutex);
1334 	for (r = reg_list_base; r != NULL; r = r->next) {
1335 		if (r->mech != mech) {
1336 			prev = r;
1337 			continue;
1338 		}
1339 		is_reg = 1;
1340 		if (r == reg_list_base) {
1341 			reg_list_base = reg_list_base->next;
1342 		} else {
1343 			prev->next = r->next;
1344 		}
1345 		free(r);
1346 		break;
1347 	}
1348 	UNLOCK_MUTEX(&reg_mutex);
1349 	return (is_reg);
1350 }
1351 
1352 static void
1353 _register_plugin(void *arg)
1354 {
1355 	reg_list_t *r = (reg_list_t *)calloc(1, sizeof (reg_list_t));
1356 
1357 	if (r != NULL) {
1358 		r->mech = arg;
1359 		LOCK_MUTEX(&reg_mutex);
1360 		r->next = reg_list_base;
1361 		reg_list_base = r;
1362 		UNLOCK_MUTEX(&reg_mutex);
1363 	}
1364 }
1365 #endif /* _INTEGRATED_SOLARIS_ */
1366 /* CRYPT DELETE END */
1367 /* EXPORT DELETE END */
1368 
1369 /* Note that this needs the global callbacks, so if you don't give getcallbacks
1370  * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
1371  * have client and server at the same time */
1372 static int _sasl_global_getopt(void *context,
1373 			       const char *plugin_name,
1374 			       const char *option,
1375 			       const char ** result,
1376 			       unsigned *len)
1377 {
1378   const sasl_global_callbacks_t * global_callbacks;
1379   const sasl_callback_t *callback;
1380 #ifdef _SUN_SDK_
1381   _sasl_global_context_t *gctx;
1382 #endif /* _SUN_SDK_ */
1383 
1384   global_callbacks = (const sasl_global_callbacks_t *) context;
1385 
1386 #ifdef _SUN_SDK_
1387   /* EXPORT DELETE START */
1388   /* CRYPT DELETE START */
1389 #ifdef _INTEGRATED_SOLARIS_
1390   if (strcmp("reg_sun_plug", option) == 0) {
1391         *result = (const char *)_register_plugin;
1392         *len = 0;
1393         return (SASL_OK);
1394   }
1395 #endif /* _INTEGRATED_SOLARIS_ */
1396   /* CRYPT DELETE END */
1397   /* EXPORT DELETE END */
1398 
1399   if (global_callbacks)
1400     gctx = global_callbacks->gctx;
1401   else
1402     gctx = _sasl_gbl_ctx();
1403 #endif /* _SUN_SDK_ */
1404 
1405   if (global_callbacks && global_callbacks->callbacks) {
1406       for (callback = global_callbacks->callbacks;
1407 	   callback->id != SASL_CB_LIST_END;
1408 	   callback++) {
1409 	if (callback->id == SASL_CB_GETOPT) {
1410 	  if (!callback->proc) return SASL_FAIL;
1411 	  if (((sasl_getopt_t *)(callback->proc))(callback->context,
1412 						  plugin_name,
1413 						  option,
1414 						  result,
1415 						  len)
1416 	      == SASL_OK)
1417 	    return SASL_OK;
1418 	}
1419       }
1420   }
1421 
1422   /* look it up in our configuration file */
1423 #ifdef _SUN_SDK_
1424   *result = sasl_config_getstring(gctx, option, NULL);
1425 #else
1426   *result = sasl_config_getstring(option, NULL);
1427 #endif /* _SUN_SDK_ */
1428   if (*result != NULL) {
1429       if (len) { *len = strlen(*result); }
1430       return SASL_OK;
1431   }
1432 
1433   return SASL_FAIL;
1434 }
1435 
1436 static int
1437 _sasl_conn_getopt(void *context,
1438 		  const char *plugin_name,
1439 		  const char *option,
1440 		  const char ** result,
1441 		  unsigned *len)
1442 {
1443   sasl_conn_t * conn;
1444   const sasl_callback_t *callback;
1445 
1446   if (! context)
1447     return SASL_BADPARAM;
1448 
1449   conn = (sasl_conn_t *) context;
1450 
1451   if (conn->callbacks)
1452     for (callback = conn->callbacks;
1453 	 callback->id != SASL_CB_LIST_END;
1454 	 callback++)
1455       if (callback->id == SASL_CB_GETOPT
1456 	  && (((sasl_getopt_t *)(callback->proc))(callback->context,
1457 						  plugin_name,
1458 						  option,
1459 						  result,
1460 						  len)
1461 	      == SASL_OK))
1462 	return SASL_OK;
1463 
1464   /* If we made it here, we didn't find an appropriate callback
1465    * in the connection's callback list, or the callback we did
1466    * find didn't return SASL_OK.  So we attempt to use the
1467    * global callback for this connection... */
1468   return _sasl_global_getopt((void *)conn->global_callbacks,
1469 			     plugin_name,
1470 			     option,
1471 			     result,
1472 			     len);
1473 }
1474 
1475 #ifdef HAVE_SYSLOG
1476 /* this is the default logging */
1477 static int _sasl_syslog(void *context __attribute__((unused)),
1478 			int priority,
1479 			const char *message)
1480 {
1481     int syslog_priority;
1482 
1483     /* set syslog priority */
1484     switch(priority) {
1485     case SASL_LOG_NONE:
1486 	return SASL_OK;
1487 	break;
1488     case SASL_LOG_ERR:
1489 	syslog_priority = LOG_ERR;
1490 	break;
1491     case SASL_LOG_WARN:
1492 	syslog_priority = LOG_WARNING;
1493 	break;
1494     case SASL_LOG_NOTE:
1495     case SASL_LOG_FAIL:
1496 	syslog_priority = LOG_NOTICE;
1497 	break;
1498     case SASL_LOG_PASS:
1499     case SASL_LOG_TRACE:
1500     case SASL_LOG_DEBUG:
1501     default:
1502 	syslog_priority = LOG_DEBUG;
1503 	break;
1504     }
1505 
1506     /* do the syslog call. do not need to call openlog */
1507     syslog(syslog_priority | LOG_AUTH, "%s", message);
1508 
1509     return SASL_OK;
1510 }
1511 #endif				/* HAVE_SYSLOG */
1512 
1513 static int
1514 _sasl_getsimple(void *context,
1515 		int id,
1516 		const char ** result,
1517 		size_t *len)
1518 {
1519   const char *userid;
1520 #ifndef _SUN_SDK_
1521   sasl_conn_t *conn;
1522 #endif /* _SUN_SDK_ */
1523 
1524   if (! context || ! result) return SASL_BADPARAM;
1525 
1526 #ifndef _SUN_SDK_
1527   conn = (sasl_conn_t *)context;
1528 #endif /* _SUN_SDK_ */
1529 
1530   switch(id) {
1531   case SASL_CB_AUTHNAME:
1532 #ifdef _INTEGRATED_SOLARIS_
1533     userid = getenv("LOGNAME");
1534     if (userid != NULL) {
1535 	*result = userid;
1536 	if (len) *len = strlen(userid);
1537 	return SASL_OK;
1538     }
1539 #else
1540     userid = getenv("USER");
1541     if (userid != NULL) {
1542 	*result = userid;
1543 	if (len) *len = strlen(userid);
1544 	return SASL_OK;
1545     }
1546     userid = getenv("USERNAME");
1547     if (userid != NULL) {
1548 	*result = userid;
1549 	if (len) *len = strlen(userid);
1550 	return SASL_OK;
1551     }
1552 #endif /* _INTEGRATED_SOLARIS_ */
1553 #ifdef WIN32
1554     /* for win32, try using the GetUserName standard call */
1555     {
1556 	DWORD i;
1557 	BOOL rval;
1558 	static char sender[128];
1559 
1560 	i = sizeof(sender);
1561 	rval = GetUserName(sender, &i);
1562 	if ( rval) { /* got a userid */
1563 		*result = sender;
1564 		if (len) *len = strlen(sender);
1565 		return SASL_OK;
1566 	}
1567     }
1568 #endif /* WIN32 */
1569     return SASL_FAIL;
1570   default:
1571     return SASL_BADPARAM;
1572   }
1573 }
1574 
1575 static int
1576 _sasl_verifyfile(void *context __attribute__((unused)),
1577 		 char *file  __attribute__((unused)),
1578 		 int type  __attribute__((unused)))
1579 {
1580   /* always say ok */
1581   return SASL_OK;
1582 }
1583 
1584 
1585 static int
1586 _sasl_proxy_policy(sasl_conn_t *conn,
1587 		   void *context __attribute__((unused)),
1588 		   const char *requested_user, unsigned rlen,
1589 		   const char *auth_identity, unsigned alen,
1590 		   const char *def_realm __attribute__((unused)),
1591 		   unsigned urlen __attribute__((unused)),
1592 		   struct propctx *propctx __attribute__((unused)))
1593 {
1594     if (!conn)
1595 	return SASL_BADPARAM;
1596 
1597     if (!requested_user || *requested_user == '\0')
1598 	return SASL_OK;
1599 
1600     if (!auth_identity || !requested_user || rlen != alen ||
1601 	(memcmp(auth_identity, requested_user, rlen) != 0)) {
1602 #ifdef _INTEGRATED_SOLARIS_
1603 	sasl_seterror(conn, 0,
1604 		      gettext("Requested identity not authenticated identity"));
1605 #else
1606 	sasl_seterror(conn, 0,
1607 		      "Requested identity not authenticated identity");
1608 #endif /* _INTEGRATED_SOLARIS_ */
1609 	RETURN(conn, SASL_BADAUTH);
1610     }
1611 
1612     return SASL_OK;
1613 }
1614 
1615 int _sasl_getcallback(sasl_conn_t * conn,
1616 		      unsigned long callbackid,
1617 		      int (**pproc)(),
1618 		      void **pcontext)
1619 {
1620   const sasl_callback_t *callback;
1621 
1622   if (!pproc || !pcontext)
1623       PARAMERROR(conn);
1624 
1625   /* Some callbacks are always provided by the library */
1626   switch (callbackid) {
1627   case SASL_CB_LIST_END:
1628     /* Nothing ever gets to provide this */
1629       INTERROR(conn, SASL_FAIL);
1630 #ifdef _SUN_SDK_
1631       break;
1632 #endif /* _SUN_SDK_ */
1633   case SASL_CB_GETOPT:
1634       if (conn) {
1635 	  *pproc = &_sasl_conn_getopt;
1636 	  *pcontext = conn;
1637       } else {
1638 	  *pproc = &_sasl_global_getopt;
1639 	  *pcontext = NULL;
1640       }
1641       return SASL_OK;
1642   }
1643 
1644   /* If it's not always provided by the library, see if there's
1645    * a version provided by the application for this connection... */
1646   if (conn && conn->callbacks) {
1647     for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
1648 	 callback++) {
1649 	if (callback->id == callbackid) {
1650 	    *pproc = callback->proc;
1651 	    *pcontext = callback->context;
1652 	    if (callback->proc) {
1653 		return SASL_OK;
1654 	    } else {
1655 		return SASL_INTERACT;
1656 	    }
1657 	}
1658     }
1659   }
1660 
1661   /* And, if not for this connection, see if there's one
1662    * for all {server,client} connections... */
1663   if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
1664       for (callback = conn->global_callbacks->callbacks;
1665 	   callback->id != SASL_CB_LIST_END;
1666 	   callback++) {
1667 	  if (callback->id == callbackid) {
1668 	      *pproc = callback->proc;
1669 	      *pcontext = callback->context;
1670 	      if (callback->proc) {
1671 		  return SASL_OK;
1672 	      } else {
1673 		  return SASL_INTERACT;
1674 	      }
1675 	  }
1676       }
1677   }
1678 
1679   /* Otherwise, see if the library provides a default callback. */
1680   switch (callbackid) {
1681 #ifdef HAVE_SYSLOG
1682   case SASL_CB_LOG:
1683     *pproc = (int (*)()) &_sasl_syslog;
1684     *pcontext = NULL;
1685     return SASL_OK;
1686 #endif /* HAVE_SYSLOG */
1687   case SASL_CB_GETPATH:
1688     *pproc = (int (*)()) &_sasl_getpath;
1689     *pcontext = NULL;
1690     return SASL_OK;
1691   case SASL_CB_AUTHNAME:
1692     *pproc = (int (*)()) &_sasl_getsimple;
1693     *pcontext = conn;
1694     return SASL_OK;
1695   case SASL_CB_VERIFYFILE:
1696     *pproc = & _sasl_verifyfile;
1697     *pcontext = NULL;
1698     return SASL_OK;
1699   case SASL_CB_PROXY_POLICY:
1700     *pproc = (int (*)()) &_sasl_proxy_policy;
1701     *pcontext = NULL;
1702     return SASL_OK;
1703   }
1704 
1705   /* Unable to find a callback... */
1706   *pproc = NULL;
1707   *pcontext = NULL;
1708 #ifdef _SUN_SDK_
1709   if (callbackid != SASL_CB_LANGUAGE)
1710     _sasl_log(conn, SASL_LOG_NONE, "Unable to find a callback: %d", callbackid);
1711 #else
1712   sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
1713 #endif /* _SUN_SDK_ */
1714   RETURN(conn,SASL_FAIL);
1715 }
1716 
1717 
1718 #ifdef _SUN_SDK_
1719 static void ___sasl_log (const _sasl_global_context_t *gctx,
1720 			sasl_log_t *log_cb, void *log_ctx,
1721 			int level, const char *fmt, va_list ap);
1722 #endif /* _SUN_SDK_ */
1723 /*
1724  * This function is typically called from a plugin.
1725  * It creates a string from the formatting and varargs given
1726  * and calls the logging callback (syslog by default)
1727  *
1728  * %m will parse the value in the next argument as an errno string
1729  * %z will parse the next argument as a SASL error code.
1730  */
1731 
1732 void
1733 _sasl_log (sasl_conn_t *conn,
1734 	   int level,
1735 	   const char *fmt,
1736 	   ...)
1737 #ifdef _SUN_SDK_
1738 {
1739   _sasl_global_context_t *gctx = conn==NULL ? _sasl_gbl_ctx() : conn->gctx;
1740   sasl_log_t *log_cb;
1741   void *log_ctx;
1742   int result;
1743   va_list ap;
1744 
1745   /* See if we have a logging callback... */
1746   result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1747   if (result == SASL_OK && ! log_cb)
1748     return;
1749 
1750   va_start(ap, fmt); /* start varargs */
1751   ___sasl_log(gctx, log_cb, log_ctx, level, fmt, ap);
1752   va_end(ap);
1753 }
1754 
1755 void
1756 __sasl_log(const _sasl_global_context_t *gctx,
1757 	   const sasl_callback_t *callbacks,
1758 	   int level,
1759 	   const char *fmt,
1760 	   ...)
1761 {
1762   sasl_log_t *log_cb = NULL;
1763   void *log_ctx = NULL;
1764   int result;
1765   va_list ap;
1766 
1767   if (callbacks)
1768     while (callbacks->id != SASL_CB_LIST_END) {
1769       if (callbacks->id == SASL_CB_LOG) {
1770 	log_cb = callbacks->proc;
1771 	log_ctx = callbacks->context;
1772 	break;
1773       }
1774       ++callbacks;
1775     }
1776 
1777   if (log_cb == NULL) {
1778     result = _sasl_getcallback(NULL, SASL_CB_LOG, &log_cb, &log_ctx);
1779     if (result != SASL_OK || ! log_cb)
1780 	return;
1781   }
1782 
1783   if (gctx == NULL)
1784     gctx = _sasl_gbl_ctx();
1785 
1786   va_start(ap, fmt); /* start varargs */
1787   ___sasl_log(gctx, log_cb, log_ctx, level, fmt, ap);
1788   va_end(ap);
1789 }
1790 
1791 static void
1792 ___sasl_log(const _sasl_global_context_t *gctx,
1793 	    sasl_log_t *log_cb,
1794 	    void *log_ctx,
1795 	    int level,
1796 	    const char *fmt,
1797 	    va_list ap)
1798 #endif /* _SUN_SDK_ */
1799 {
1800   char *out=(char *) sasl_ALLOC(250);
1801   size_t alloclen=100; /* current allocated length */
1802   size_t outlen=0; /* current length of output buffer */
1803   size_t formatlen;
1804   size_t pos=0; /* current position in format string */
1805   int result;
1806 #ifndef _SUN_SDK_
1807   sasl_log_t *log_cb;
1808   void *log_ctx;
1809 #endif /* !_SUN_SDK_ */
1810 
1811   int ival;
1812   char *cval;
1813 #ifndef _SUN_SDK_
1814   va_list ap; /* varargs thing */
1815 #endif /* !_SUN_SDK_ */
1816 
1817   if(!fmt) goto done;
1818   if(!out) return;
1819 
1820   formatlen = strlen(fmt);
1821 
1822 #ifndef _SUN_SDK_
1823   /* See if we have a logging callback... */
1824   result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1825   if (result == SASL_OK && ! log_cb)
1826     result = SASL_FAIL;
1827   if (result != SASL_OK) goto done;
1828 
1829   va_start(ap, fmt); /* start varargs */
1830 #endif /* !_SUN_SDK_ */
1831 
1832   while(pos<formatlen)
1833   {
1834     if (fmt[pos]!='%') /* regular character */
1835     {
1836       result = _buf_alloc(&out, &alloclen, outlen+1);
1837       if (result != SASL_OK) goto done;
1838       out[outlen]=fmt[pos];
1839       outlen++;
1840       pos++;
1841 
1842     } else { /* formating thing */
1843       int done=0;
1844       char frmt[10];
1845       int frmtpos=1;
1846       char tempbuf[21];
1847       frmt[0]='%';
1848       pos++;
1849 
1850       while (done==0)
1851       {
1852 	switch(fmt[pos])
1853 	  {
1854 	  case 's': /* need to handle this */
1855 	    cval = va_arg(ap, char *); /* get the next arg */
1856 	    result = _sasl_add_string(&out, &alloclen,
1857 				&outlen, cval);
1858 
1859 	    if (result != SASL_OK) /* add the string */
1860 		goto done;
1861 
1862 	    done=1;
1863 	    break;
1864 
1865 	  case '%': /* double % output the '%' character */
1866 	    result = _buf_alloc(&out,&alloclen,outlen+1);
1867 	    if (result != SASL_OK)
1868 		goto done;
1869 
1870 	    out[outlen]='%';
1871 	    outlen++;
1872 	    done=1;
1873 	    break;
1874 
1875 	  case 'm': /* insert the errno string */
1876 	    result = _sasl_add_string(&out, &alloclen, &outlen,
1877 				strerror(va_arg(ap, int)));
1878 	    if (result != SASL_OK)
1879 		goto done;
1880 
1881 	    done=1;
1882 	    break;
1883 
1884 	  case 'z': /* insert the sasl error string */
1885 	    result = _sasl_add_string(&out, &alloclen, &outlen,
1886 				(char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
1887 	    if (result != SASL_OK)
1888 		goto done;
1889 
1890 	    done=1;
1891 	    break;
1892 
1893 	  case 'c':
1894 #ifndef _SUN_SDK_
1895 	    frmt[frmtpos++]=fmt[pos];
1896 	    frmt[frmtpos]=0;
1897 #endif /* !_SUN_SDK_ */
1898 	    tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
1899 	    tempbuf[1]='\0';
1900 
1901 	    /* now add the character */
1902 	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1903 	    if (result != SASL_OK)
1904 		goto done;
1905 
1906 	    done=1;
1907 	    break;
1908 
1909 	  case 'd':
1910 	  case 'i':
1911 	    frmt[frmtpos++]=fmt[pos];
1912 	    frmt[frmtpos]=0;
1913 	    ival = va_arg(ap, int); /* get the next arg */
1914 
1915 	    snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
1916 	    /* now add the string */
1917 	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1918 	    if (result != SASL_OK)
1919 		goto done;
1920 
1921 	    done=1;
1922 
1923 	    break;
1924 	  default:
1925 	    frmt[frmtpos++]=fmt[pos]; /* add to the formating */
1926 	    frmt[frmtpos]=0;
1927 #ifdef _SUN_SDK_
1928 	    if (frmtpos > sizeof (frmt) - 2)
1929 #else
1930 	    if (frmtpos>9)
1931 #endif /* _SUN_SDK_ */
1932 	      done=1;
1933 	  }
1934 	pos++;
1935 	if (pos>formatlen)
1936 	  done=1;
1937       }
1938 
1939     }
1940   }
1941 
1942   /* put 0 at end */
1943   result = _buf_alloc(&out, &alloclen, outlen+1);
1944   if (result != SASL_OK) goto done;
1945   out[outlen]=0;
1946 
1947   va_end(ap);
1948 
1949   /* send log message */
1950   result = log_cb(log_ctx, level, out);
1951 
1952  done:
1953   if(out) sasl_FREE(out);
1954 }
1955 
1956 
1957 
1958 /* Allocate and Init a sasl_utils_t structure */
1959 #ifdef _SUN_SDK_
1960 sasl_utils_t *
1961 _sasl_alloc_utils(_sasl_global_context_t *gctx, sasl_conn_t *conn,
1962 		  sasl_global_callbacks_t *global_callbacks)
1963 #else
1964 sasl_utils_t *
1965 _sasl_alloc_utils(sasl_conn_t *conn,
1966 		  sasl_global_callbacks_t *global_callbacks)
1967 #endif /* _SUN_SDK_ */
1968 {
1969   sasl_utils_t *utils;
1970 #ifdef _SUN_SDK_
1971   sasl_allocation_utils_t alloc;
1972   sasl_mutex_utils_t mutex;
1973 
1974   LOCK_MUTEX(&malloc_global_mutex);
1975   alloc = gctx->sasl_allocation_utils;
1976   mutex = gctx->sasl_mutex_utils;
1977   UNLOCK_MUTEX(&malloc_global_mutex);
1978 #endif /* _SUN_SDK_ */
1979 
1980   /* set util functions - need to do rest*/
1981 #ifdef _SUN_SDK_
1982   utils=alloc.malloc(sizeof(sasl_utils_t));
1983 #else
1984   utils=sasl_ALLOC(sizeof(sasl_utils_t));
1985 #endif /* _SUN_SDK_ */
1986   if (utils==NULL)
1987     return NULL;
1988 
1989   utils->conn = conn;
1990 
1991   sasl_randcreate(&utils->rpool);
1992 
1993   if (conn) {
1994     utils->getopt = &_sasl_conn_getopt;
1995     utils->getopt_context = conn;
1996   } else {
1997     utils->getopt = &_sasl_global_getopt;
1998     utils->getopt_context = global_callbacks;
1999   }
2000 
2001 #ifdef _SUN_SDK_
2002   utils->malloc=alloc.malloc;
2003   utils->calloc=alloc.calloc;
2004   utils->realloc=alloc.realloc;
2005   utils->free=alloc.free;
2006 
2007   utils->mutex_alloc = mutex.alloc;
2008   utils->mutex_lock = mutex.lock;
2009   utils->mutex_unlock = mutex.unlock;
2010   utils->mutex_free = mutex.free;
2011 #else
2012   utils->malloc=_sasl_allocation_utils.malloc;
2013   utils->calloc=_sasl_allocation_utils.calloc;
2014   utils->realloc=_sasl_allocation_utils.realloc;
2015   utils->free=_sasl_allocation_utils.free;
2016 
2017   utils->mutex_alloc = _sasl_mutex_utils.alloc;
2018   utils->mutex_lock = _sasl_mutex_utils.lock;
2019   utils->mutex_unlock = _sasl_mutex_utils.unlock;
2020   utils->mutex_free = _sasl_mutex_utils.free;
2021 #endif /* _SUN_SDK_ */
2022 
2023 #ifdef _SUN_SDK_
2024   utils->MD5Init  = (void (*)(MD5_CTX *))&MD5Init;
2025   utils->MD5Update= (void (*)
2026 	(MD5_CTX *, const unsigned char *, unsigned int ))&MD5Update;
2027   utils->MD5Final = (void (*)(unsigned char [16], MD5_CTX *))&MD5Final;
2028 #else
2029   utils->MD5Init  = &_sasl_MD5Init;
2030   utils->MD5Update= &_sasl_MD5Update;
2031   utils->MD5Final = &_sasl_MD5Final;
2032 #endif /* _SUN_SDK_ */
2033   utils->hmac_md5 = &_sasl_hmac_md5;
2034   utils->hmac_md5_init = &_sasl_hmac_md5_init;
2035   utils->hmac_md5_final = &_sasl_hmac_md5_final;
2036   utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
2037   utils->hmac_md5_import = &_sasl_hmac_md5_import;
2038   utils->mkchal = &sasl_mkchal;
2039   utils->utf8verify = &sasl_utf8verify;
2040   utils->rand=&sasl_rand;
2041   utils->churn=&sasl_churn;
2042   utils->checkpass=NULL;
2043 
2044   utils->encode64=&sasl_encode64;
2045   utils->decode64=&sasl_decode64;
2046 
2047   utils->erasebuffer=&sasl_erasebuffer;
2048 
2049   utils->getprop=&sasl_getprop;
2050   utils->setprop=&sasl_setprop;
2051 
2052   utils->getcallback=&_sasl_getcallback;
2053 
2054   utils->log=&_sasl_log;
2055 
2056   utils->seterror=&sasl_seterror;
2057 
2058 #ifndef macintosh
2059   /* Aux Property Utilities */
2060   utils->prop_new=&prop_new;
2061   utils->prop_dup=&prop_dup;
2062   utils->prop_request=&prop_request;
2063   utils->prop_get=&prop_get;
2064   utils->prop_getnames=&prop_getnames;
2065   utils->prop_clear=&prop_clear;
2066   utils->prop_dispose=&prop_dispose;
2067   utils->prop_format=&prop_format;
2068   utils->prop_set=&prop_set;
2069   utils->prop_setvals=&prop_setvals;
2070   utils->prop_erase=&prop_erase;
2071 #endif
2072 
2073   /* Spares */
2074   utils->spare_fptr = NULL;
2075   utils->spare_fptr1 = utils->spare_fptr2 =
2076       utils->spare_fptr3 = NULL;
2077 
2078   return utils;
2079 }
2080 
2081 int
2082 _sasl_free_utils(const sasl_utils_t ** utils)
2083 {
2084     sasl_utils_t *nonconst;
2085 #ifdef _SUN_SDK_
2086     sasl_free_t *free_func;
2087 #endif /* _SUN_SDK_ */
2088 
2089     if(!utils) return SASL_BADPARAM;
2090     if(!*utils) return SASL_OK;
2091 
2092     /* I wish we could avoid this cast, it's pretty gratuitous but it
2093      * does make life easier to have it const everywhere else. */
2094     nonconst = (sasl_utils_t *)(*utils);
2095 
2096     sasl_randfree(&(nonconst->rpool));
2097 #ifdef _SUN_SDK_
2098     free_func = (*utils)->free;
2099     free_func(nonconst);
2100 #else
2101     sasl_FREE(nonconst);
2102 #endif /* _SUN_SDK_ */
2103 
2104     *utils = NULL;
2105     return SASL_OK;
2106 }
2107 
2108 int sasl_idle(sasl_conn_t *conn)
2109 {
2110   if (! conn) {
2111 #ifdef _SUN_SDK_
2112     _sasl_global_context_t *gctx = _sasl_gbl_ctx();
2113 
2114     if (gctx->sasl_server_idle_hook
2115         && gctx->sasl_server_idle_hook(NULL))
2116       return 1;
2117     if (gctx->sasl_client_idle_hook
2118         && gctx->sasl_client_idle_hook(NULL))
2119       return 1;
2120 #else
2121     if (_sasl_server_idle_hook
2122 	&& _sasl_server_idle_hook(NULL))
2123       return 1;
2124     if (_sasl_client_idle_hook
2125 	&& _sasl_client_idle_hook(NULL))
2126       return 1;
2127 #endif /* _SUN_SDK_ */
2128     return 0;
2129   }
2130 
2131   if (conn->idle_hook)
2132     return conn->idle_hook(conn);
2133 
2134   return 0;
2135 }
2136 
2137 const sasl_callback_t *
2138 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
2139 {
2140   static const sasl_callback_t default_getpath_cb = {
2141     SASL_CB_GETPATH,
2142     &_sasl_getpath,
2143     NULL
2144   };
2145 
2146   if (callbacks)
2147     while (callbacks->id != SASL_CB_LIST_END)
2148     {
2149       if (callbacks->id == SASL_CB_GETPATH)
2150       {
2151 	return callbacks;
2152       } else {
2153 	++callbacks;
2154       }
2155     }
2156 
2157   return &default_getpath_cb;
2158 }
2159 
2160 #ifdef _SUN_SDK_
2161 extern const sasl_callback_t *
2162 _sasl_find_getconf_callback(const sasl_callback_t *callbacks)
2163 {
2164   static const sasl_callback_t default_getconf_cb = {
2165     SASL_CB_GETCONF,
2166     &_sasl_getconf,
2167     NULL
2168   };
2169 
2170   if (callbacks)
2171     while (callbacks->id != SASL_CB_LIST_END)
2172     {
2173       if (callbacks->id == SASL_CB_GETCONF)
2174       {
2175 	return callbacks;
2176       } else {
2177 	++callbacks;
2178       }
2179     }
2180 
2181   return &default_getconf_cb;
2182 }
2183 #endif /* _SUN_SDK_ */
2184 
2185 const sasl_callback_t *
2186 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
2187 {
2188   static const sasl_callback_t default_verifyfile_cb = {
2189     SASL_CB_VERIFYFILE,
2190     &_sasl_verifyfile,
2191     NULL
2192   };
2193 
2194   if (callbacks)
2195     while (callbacks->id != SASL_CB_LIST_END)
2196     {
2197       if (callbacks->id == SASL_CB_VERIFYFILE)
2198       {
2199 	return callbacks;
2200       } else {
2201 	++callbacks;
2202       }
2203     }
2204 
2205   return &default_verifyfile_cb;
2206 }
2207 
2208 /* Basically a conditional call to realloc(), if we need more */
2209 #ifdef _SUN_SDK_
2210 int __buf_alloc(const _sasl_global_context_t *gctx, char **rwbuf,
2211 		size_t *curlen, size_t newlen)
2212 #else
2213 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
2214 #endif /* _SUN_SDK_ */
2215 {
2216     if(!(*rwbuf)) {
2217 	*rwbuf = sasl_ALLOC(newlen);
2218 	if (*rwbuf == NULL) {
2219 	    *curlen = 0;
2220 	    return SASL_NOMEM;
2221 	}
2222 	*curlen = newlen;
2223     } else if(*rwbuf && *curlen < newlen) {
2224 	size_t needed = 2*(*curlen);
2225 
2226 	while(needed < newlen)
2227 	    needed *= 2;
2228 
2229 	*rwbuf = sasl_REALLOC(*rwbuf, needed);
2230 
2231 	if (*rwbuf == NULL) {
2232 	    *curlen = 0;
2233 	    return SASL_NOMEM;
2234 	}
2235 	*curlen = needed;
2236     }
2237 
2238     return SASL_OK;
2239 }
2240 
2241 /* for the mac os x cfm glue: this lets the calling function
2242    get pointers to the error buffer without having to touch the sasl_conn_t struct */
2243 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
2244 {
2245 	*bufhdl = &conn->error_buf;
2246 	*lenhdl = &conn->error_buf_len;
2247 }
2248 
2249 /* convert an iovec to a single buffer */
2250 #ifdef _SUN_SDK_
2251 int _iovec_to_buf(const _sasl_global_context_t *gctx, const struct iovec *vec,
2252 		  unsigned numiov, buffer_info_t **output)
2253 #else
2254 int _iovec_to_buf(const struct iovec *vec,
2255 		  unsigned numiov, buffer_info_t **output)
2256 #endif /* _SUN_SDK_ */
2257 {
2258     unsigned i;
2259     int ret;
2260     buffer_info_t *out;
2261     char *pos;
2262 
2263     if(!vec || !output) return SASL_BADPARAM;
2264 
2265     if(!(*output)) {
2266 	*output = sasl_ALLOC(sizeof(buffer_info_t));
2267 	if(!*output) return SASL_NOMEM;
2268 	memset(*output,0,sizeof(buffer_info_t));
2269     }
2270 
2271     out = *output;
2272 
2273     out->curlen = 0;
2274     for(i=0; i<numiov; i++)
2275 	out->curlen += vec[i].iov_len;
2276 
2277     ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
2278 
2279     if(ret != SASL_OK) return SASL_NOMEM;
2280 
2281     memset(out->data, 0, out->reallen);
2282     pos = out->data;
2283 
2284     for(i=0; i<numiov; i++) {
2285 	memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2286 	pos += vec[i].iov_len;
2287     }
2288 
2289     return SASL_OK;
2290 }
2291 
2292 /* This code might be useful in the future, but it isn't now, so.... */
2293 #if 0
2294 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
2295 		     char *out, unsigned outlen) {
2296     char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
2297 
2298     if(!addr || !out) return SASL_BADPARAM;
2299 
2300     getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
2301 		NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
2302 
2303     if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
2304 	return SASL_BUFOVER;
2305 
2306     snprintf(out, outlen, "%s;%s", hbuf, pbuf);
2307 
2308     return SASL_OK;
2309 }
2310 #endif
2311 
2312 #ifdef _SUN_SDK_
2313 /* An ipv6 address will contain at least two colons */
2314 static int can_be_ipv6(const char *addr)
2315 {
2316    const char *p;
2317 
2318    if ((p = strchr(addr, ':')) == NULL)
2319 	return (0);
2320 
2321    p = strchr(p + 1, ':');
2322 
2323    return (p != NULL);
2324 }
2325 #endif /* _SUN_SDK_ */
2326 
2327 int _sasl_ipfromstring(const char *addr,
2328 		       struct sockaddr *out, socklen_t outlen)
2329 {
2330     int i, j;
2331     struct addrinfo hints, *ai = NULL;
2332     char hbuf[NI_MAXHOST];
2333 #ifdef _SUN_SDK_
2334     const char *start, *end, *p;
2335     int addr_only = 1;
2336 #endif /* _SUN_SDK_ */
2337 
2338     /* A NULL out pointer just implies we don't do a copy, just verify it */
2339 
2340     if(!addr) return SASL_BADPARAM;
2341 
2342 #ifdef _SUN_SDK_
2343     end = strchr(addr, ']');
2344     if (end != NULL) {
2345 	/* This an rfc 2732 ipv6 address */
2346 	start = strchr(addr, '[');
2347 	if (start >= end || start == NULL)
2348 	    return SASL_BADPARAM;
2349 	for (i = 0, p = start + 1; p < end; p++) {
2350 	    hbuf[i++] = *p;
2351 	    if (i >= NI_MAXHOST)
2352 		return SASL_BADPARAM;
2353 	}
2354 	p = strchr(end, ':');
2355 	if (p == NULL)
2356 		p = end + 1;
2357 	else
2358 		p = p + 1;
2359     } else if (can_be_ipv6(addr) != 0) {
2360 	/* Parse the address */
2361 	for (i = 0; addr[i] != '\0' && addr[i] != ';'; ) {
2362 	    hbuf[i] = addr[i];
2363 	    if (++i >= NI_MAXHOST)
2364 		return SASL_BADPARAM;
2365 	}
2366 	if (addr[i] == ';')
2367 	     p = &addr[i+1];
2368 	else
2369 	     p = &addr[i];
2370     } else {
2371 	for (i = 0; addr[i] != '\0' && addr[i] != ';' && addr[i] != ':'; ) {
2372 	    hbuf[i] = addr[i];
2373 	    if (isalpha(addr[i]))
2374 		addr_only = 0;
2375 	    if (++i >= NI_MAXHOST)
2376 		return SASL_BADPARAM;
2377 	}
2378 	if (addr[i] == ';' || addr[i] == ':')
2379 	     p = &addr[i+1];
2380 	else
2381 	     p = &addr[i];
2382     }
2383     hbuf[i] = '\0';
2384     for (j = 0; p[j] != '\0'; j++)
2385 	if (!isdigit((int)(p[j])))
2386 	    return SASL_BADPARAM;
2387     if (atoi(p) == 0)
2388 	p = NULL;
2389 #else
2390     /* Parse the address */
2391     for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2392 	if (i >= NI_MAXHOST)
2393 	    return SASL_BADPARAM;
2394 	hbuf[i] = addr[i];
2395     }
2396     hbuf[i] = '\0';
2397 
2398     if (addr[i] == ';')
2399 	i++;
2400     /* XXX: Do we need this check? */
2401     for (j = i; addr[j] != '\0'; j++)
2402 	if (!isdigit((int)(addr[j])))
2403 	    return SASL_BADPARAM;
2404 #endif /* _SUN_SDK_ */
2405 
2406     memset(&hints, 0, sizeof(hints));
2407     hints.ai_family = PF_UNSPEC;
2408     hints.ai_socktype = SOCK_STREAM;
2409 #ifdef _SUN_SDK_
2410     hints.ai_flags = addr_only ? AI_PASSIVE | AI_NUMERICHOST : AI_PASSIVE;
2411     if (getaddrinfo(hbuf, p, &hints, &ai) != 0)
2412 #else
2413     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2414     if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
2415 #endif /* _SUN_SDK_ */
2416 	return SASL_BADPARAM;
2417 
2418     if (out) {
2419 	if (outlen < (socklen_t)ai->ai_addrlen) {
2420 	    freeaddrinfo(ai);
2421 	    return SASL_BUFOVER;
2422 	}
2423 	memcpy(out, ai->ai_addr, ai->ai_addrlen);
2424     }
2425 
2426     freeaddrinfo(ai);
2427 
2428     return SASL_OK;
2429 }
2430 
2431 #ifdef _SUN_SDK_
2432 int _sasl_build_mechlist(_sasl_global_context_t *gctx)
2433 #else
2434 int _sasl_build_mechlist(void)
2435 #endif /* _SUN_SDK_ */
2436 {
2437     int count = 0;
2438     sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
2439     sasl_string_list_t *p, *q, **last, *p_next;
2440 
2441 #ifdef _SUN_SDK_
2442     char **global_mech_list;
2443 
2444     LOCK_MUTEX(&global_mutex);
2445 
2446     clist = _sasl_client_mechs(gctx);
2447     slist = _sasl_server_mechs(gctx);
2448 
2449     global_mech_list = gctx->global_mech_list;
2450 #else
2451     clist = _sasl_client_mechs();
2452     slist = _sasl_server_mechs();
2453 #endif /* _SUN_SDK_ */
2454 
2455     if(!clist) {
2456 	olist = slist;
2457     } else {
2458 	int flag;
2459 
2460 	/* append slist to clist, and set olist to clist */
2461 	for(p = slist; p; p = p_next) {
2462 	    flag = 0;
2463 	    p_next = p->next;
2464 
2465 	    last = &clist;
2466 	    for(q = clist; q; q = q->next) {
2467 		if(!strcmp(q->d, p->d)) {
2468 		    /* They match, set the flag */
2469 		    flag = 1;
2470 		    break;
2471 		}
2472 		last = &(q->next);
2473 	    }
2474 
2475 	    if(!flag) {
2476 		*last = p;
2477 		p->next = NULL;
2478 	    } else {
2479 		sasl_FREE(p);
2480 	    }
2481 	}
2482 
2483 	olist = clist;
2484     }
2485 
2486     if(!olist) {
2487 #ifdef _SUN_SDK_
2488 	UNLOCK_MUTEX(&global_mutex);
2489 #else
2490 	printf ("no olist");
2491 #endif /* _SUN_SDK_ */
2492 	return SASL_FAIL;
2493     }
2494 
2495     for (p = olist; p; p = p->next) count++;
2496 
2497     if(global_mech_list) {
2498 	sasl_FREE(global_mech_list);
2499 #ifdef _SUN_SDK_
2500 	gctx->global_mech_list = NULL;
2501 #else
2502 	global_mech_list = NULL;
2503 #endif /* _SUN_SDK_ */
2504     }
2505 
2506     global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
2507     if(!global_mech_list) return SASL_NOMEM;
2508 
2509     memset(global_mech_list, 0, (count + 1) * sizeof(char *));
2510 #ifdef _SUN_SDK_
2511     gctx->global_mech_list = global_mech_list;
2512 #endif /* _SUN_SDK_ */
2513 
2514     count = 0;
2515     for (p = olist; p; p = p_next) {
2516 	p_next = p->next;
2517 
2518 	global_mech_list[count++] = (char *) p->d;
2519 
2520     	sasl_FREE(p);
2521     }
2522 
2523 #ifdef _SUN_SDK_
2524     UNLOCK_MUTEX(&global_mutex);
2525 #endif /* _SUN_SDK_ */
2526 
2527     return SASL_OK;
2528 }
2529 
2530 const char ** sasl_global_listmech(void)
2531 {
2532 #ifdef _SUN_SDK_
2533     _sasl_global_context_t *gctx = _sasl_gbl_ctx();
2534 
2535     return (const char **)gctx->global_mech_list;
2536 #else
2537     return (const char **)global_mech_list;
2538 #endif /* _SUN_SDK_ */
2539 }
2540 
2541 int sasl_listmech(sasl_conn_t *conn,
2542 		  const char *user,
2543 		  const char *prefix,
2544 		  const char *sep,
2545 		  const char *suffix,
2546 		  const char **result,
2547 		  unsigned *plen,
2548 		  int *pcount)
2549 {
2550     if(!conn) {
2551 	return SASL_BADPARAM;
2552     } else if(conn->type == SASL_CONN_SERVER) {
2553 	RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
2554 					   result, plen, pcount));
2555     } else if (conn->type == SASL_CONN_CLIENT) {
2556 	RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
2557 					   result, plen, pcount));
2558     }
2559 
2560     PARAMERROR(conn);
2561 }
2562 
2563 #ifdef _SUN_SDK_
2564 /*
2565  * Creates a context so that libraries may use libsasl independently
2566  * of applications using libsasl.
2567  * Returns NULL on failure.
2568  *
2569  * sasl_free_context frees the context
2570  * To use libsasl independently of the default context, use
2571  * _sasl_server_init()		instead of	sasl_server_init()
2572  * _sasl_server_new()		instead of	sasl_server_new()
2573  * _sasl_client_init()		instead of	sasl_client_init()
2574  * _sasl_client_new()		instead of	sasl_client_new()
2575  * _sasl_client_add_plugin()	instead of	sasl_client_add_plugin()
2576  * _sasl_server_add_plugin()	instead of	sasl_server_add_plugin()
2577  * _sasl_canonuser_add_plugin()	instead of	sasl_canonuser_add_plugin()
2578  * _sasl_auxprop_add_plugin()	instead of	sasl_auxprop_add_plugin()
2579  */
2580 
2581 void *sasl_create_context(void)
2582 {
2583   _sasl_global_context_t *gctx;
2584 
2585   gctx = (_sasl_global_context_t *)
2586 	sasl_sun_ALLOC(sizeof(_sasl_global_context_t));
2587 
2588   if (gctx != NULL) {
2589     memset(gctx, 0, sizeof(_sasl_global_context_t));
2590 
2591     gctx->server_global_callbacks.gctx = gctx;
2592     gctx->client_global_callbacks.gctx = gctx;
2593     LOCK_MUTEX(&malloc_global_mutex);
2594     gctx->sasl_allocation_utils.malloc = (sasl_malloc_t *)&malloc;
2595     gctx->sasl_allocation_utils.calloc = (sasl_calloc_t *)&calloc;
2596     gctx->sasl_allocation_utils.realloc = (sasl_realloc_t *)&realloc;
2597     gctx->sasl_allocation_utils.free = (sasl_free_t *)&free;
2598     gctx->sasl_mutex_utils.alloc = sasl_mutex_alloc;
2599     gctx->sasl_mutex_utils.lock = sasl_mutex_lock;
2600     gctx->sasl_mutex_utils.unlock = sasl_mutex_unlock;
2601     gctx->sasl_mutex_utils.free = sasl_mutex_free;
2602     UNLOCK_MUTEX(&malloc_global_mutex);
2603   }
2604   return gctx;
2605 }
2606 
2607 /* Frees the context created by sasl_create_context() */
2608 void sasl_free_context(void *context)
2609 {
2610   _sasl_dispose_context(context);
2611   if (context != NULL) {
2612     sasl_sun_FREE(context);
2613   }
2614 }
2615 
2616 /* Used by both sasl_done() and sasl_free_context() to free context */
2617 static void _sasl_dispose_context(_sasl_global_context_t *gctx)
2618 {
2619   if (gctx == NULL)
2620         return;
2621 
2622   if (gctx->sasl_server_cleanup_hook &&
2623 		gctx->sasl_server_cleanup_hook(gctx) == SASL_OK) {
2624 	gctx->sasl_server_idle_hook = NULL;
2625 	gctx->sasl_server_cleanup_hook = NULL;
2626   }
2627 
2628   if (gctx->sasl_client_cleanup_hook &&
2629 		gctx->sasl_client_cleanup_hook(gctx) == SASL_OK) {
2630 	gctx->sasl_client_idle_hook = NULL;
2631 	gctx->sasl_client_cleanup_hook = NULL;
2632   }
2633 
2634   if(gctx->sasl_server_cleanup_hook || gctx->sasl_client_cleanup_hook)
2635 	return;
2636 
2637   _sasl_canonuser_free(gctx);
2638   _sasl_done_with_plugins(gctx);
2639 
2640   sasl_config_free(gctx);
2641 
2642   if (gctx->free_mutex != NULL)
2643     sasl_MUTEX_FREE(gctx->free_mutex);
2644   gctx->free_mutex = NULL;
2645 
2646   _sasl_free_utils(&(gctx->sasl_server_global_utils));
2647   _sasl_free_utils(&(gctx->sasl_canonusr_global_utils));
2648 
2649   LOCK_MUTEX(&global_mutex);
2650   sasl_FREE((void *)gctx->global_mech_list);
2651   gctx->global_mech_list = NULL;
2652   UNLOCK_MUTEX(&global_mutex);
2653 
2654   /* in case of another init/done */
2655   gctx->sasl_server_cleanup_hook = NULL;
2656   gctx->sasl_client_cleanup_hook = NULL;
2657 
2658   gctx->sasl_client_idle_hook = NULL;
2659   gctx->sasl_server_idle_hook = NULL;
2660 }
2661 
2662 _sasl_global_context_t *_sasl_gbl_ctx(void)
2663 {
2664   static _sasl_global_context_t gbl_ctx = {
2665         0,                      /* sasl_server_active */
2666         NULL,                   /* mechlist */
2667 	NULL,			/* splug_path_info */
2668         {NULL, NULL, &gbl_ctx}, /* server_global_callbacks */
2669         NULL,                   /* sasl_server_cleanup_hook */
2670         NULL,                   /* sasl_server_idle_hook */
2671         NULL,                   /* cmechlist */
2672 	NULL,			/* cplug_path_info */
2673         {NULL, NULL, &gbl_ctx}, /* client_global_callbacks */
2674         0,                      /* sasl_client_active */
2675         NULL,                   /* sasl_client_cleanup_hook */
2676         NULL,                   /* sasl_client_idle_hook */
2677         NULL,                   /* sasl_server_global_utils */
2678         NULL,                   /* sasl_client_global_utils */
2679         NULL,                   /* configlist */
2680         0,                      /* nconfiglist */
2681 	NULL,			/* config_path */
2682 	0,			/* config_last_read */
2683         NULL,                   /* auxprop_head */
2684         NULL,                   /* canonuser_head */
2685         NULL,                   /* global_mech_list */
2686         NULL,                   /* free_mutex */
2687         {(sasl_malloc_t *)&malloc, (sasl_calloc_t *)&calloc,
2688             (sasl_realloc_t *)&realloc, (sasl_free_t *)&free},
2689                                 /* sasl_allocation_utils */
2690         {&sasl_mutex_alloc, &sasl_mutex_lock, &sasl_mutex_unlock,
2691             &sasl_mutex_free},  /* sasl_mutex_utils */
2692         NULL			/* lib_list_head */
2693   };
2694 
2695   return (&gbl_ctx);
2696 }
2697 
2698 static int
2699 _sasl_getconf(void *context __attribute__((unused)), const char **conf)
2700 {
2701     if (! conf)
2702 	return SASL_BADPARAM;
2703 
2704     *conf = SASL_CONFDIR;
2705 
2706     return SASL_OK;
2707 }
2708 
2709 /* EXPORT DELETE START */
2710 /* CRYPT DELETE START */
2711 #ifdef _INTEGRATED_SOLARIS_
2712 #pragma fini(sasl_fini)
2713 int
2714 sasl_fini(void)
2715 {
2716     reg_list_t *next;
2717 
2718     while (reg_list_base != NULL) {
2719 	next = reg_list_base->next;
2720 	free(reg_list_base);
2721 	reg_list_base = next;
2722     }
2723     return (0);
2724 }
2725 #endif /* _INTEGRATED_SOLARIS_ */
2726 /* CRYPT DELETE END */
2727 /* EXPORT DELETE END */
2728 
2729 #endif /* _SUN_SDK_ */
2730 
2731 #ifndef WIN32
2732 static int
2733 _sasl_getpath(void *context __attribute__((unused)),
2734 	      const char **path)
2735 {
2736   if (! path)
2737     return SASL_BADPARAM;
2738 
2739 #ifdef _SUN_SDK_
2740 /* SASL_PATH is not allowed for SUN SDK */
2741 #else
2742   *path = getenv(SASL_PATH_ENV_VAR);
2743   if (! *path)
2744 #endif /* _SUN_SDK_ */
2745     *path = PLUGINDIR;
2746 
2747   return SASL_OK;
2748 }
2749 
2750 #else
2751 /* Return NULL on failure */
2752 static int
2753 _sasl_getpath(void *context __attribute__((unused)), const char **path)
2754 {
2755     /* Open registry entry, and find all registered SASL libraries.
2756      *
2757      * Registry location:
2758      *
2759      *     SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
2760      *
2761      * Key - value:
2762      *
2763      *     "SearchPath" - value: PATH like (';' delimited) list
2764      *                    of directories where to search for plugins
2765      *                    The list may contain references to environment
2766      *                    variables (e.g. %PATH%).
2767      *
2768      */
2769     HKEY  hKey;
2770     DWORD ret;
2771     DWORD ValueType;		    /* value type */
2772     DWORD cbData;		    /* value size */
2773     BYTE * ValueData;		    /* value */
2774     DWORD cbExpandedData;	    /* "expanded" value size */
2775     BYTE * ExpandedValueData;	    /* "expanded" value */
2776     char * return_value;	    /* function return value */
2777     char * tmp;
2778 
2779     /* Initialization */
2780     ExpandedValueData = NULL;
2781     ValueData = NULL;
2782     return_value = NULL;
2783 
2784     /* Open the registry */
2785     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2786 		       SASL_ROOT_KEY,
2787 		       0,
2788 		       KEY_READ,
2789 		       &hKey);
2790 
2791     if (ret != ERROR_SUCCESS) {
2792 		/* no registry entry */
2793 		*path = PLUGINDIR;
2794 		return SASL_OK;
2795 	}
2796 
2797     /* figure out value type and required buffer size */
2798     /* the size will include space for terminating NUL if required */
2799     RegQueryValueEx (hKey,
2800 		     SASL_PATH_SUBKEY,
2801 		     NULL,	    /* reserved */
2802 		     &ValueType,
2803 		     NULL,
2804 		     &cbData);
2805 
2806     /* Only accept string related types */
2807     if (ValueType != REG_EXPAND_SZ &&
2808 	ValueType != REG_MULTI_SZ &&
2809 	ValueType != REG_SZ) {
2810 	return_value = NULL;
2811 	goto CLEANUP;
2812     }
2813 
2814     /* Any high water mark? */
2815     ValueData = sasl_ALLOC(cbData);
2816     if (ValueData == NULL) {
2817 	return_value = NULL;
2818 	goto CLEANUP;
2819     };
2820 
2821     RegQueryValueEx (hKey,
2822 		     SASL_PATH_SUBKEY,
2823 		     NULL,	    /* reserved */
2824 		     &ValueType,
2825 		     ValueData,
2826 		     &cbData);
2827 
2828     switch (ValueType) {
2829     case REG_EXPAND_SZ:
2830         /* : A random starting guess */
2831         cbExpandedData = cbData + 1024;
2832         ExpandedValueData = sasl_ALLOC(cbExpandedData);
2833         if (ExpandedValueData == NULL) {
2834             return_value = NULL;
2835             goto CLEANUP;
2836         };
2837 
2838         cbExpandedData = ExpandEnvironmentStrings(
2839                                                   ValueData,
2840                                                   ExpandedValueData,
2841                                                   cbExpandedData);
2842 
2843         if (cbExpandedData == 0) {
2844             /* : GetLastError() contains the reason for failure */
2845             return_value = NULL;
2846             goto CLEANUP;
2847         }
2848 
2849         /* : Must retry expansion with the bigger buffer */
2850         if (cbExpandedData > cbData + 1024) {
2851             /* : Memory leak here if can't realloc */
2852             ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
2853             if (ExpandedValueData == NULL) {
2854                 return_value = NULL;
2855                 goto CLEANUP;
2856             };
2857 
2858             cbExpandedData = ExpandEnvironmentStrings(
2859                                                       ValueData,
2860                                                       ExpandedValueData,
2861                                                       cbExpandedData);
2862 
2863             /* : This should not happen */
2864             if (cbExpandedData == 0) {
2865                 /* : GetLastError() contains the reason for failure */
2866                 return_value = NULL;
2867                 goto CLEANUP;
2868             }
2869         }
2870 
2871         sasl_FREE(ValueData);
2872         ValueData = ExpandedValueData;
2873         /* : This is to prevent automatical freeing of this block on cleanup */
2874         ExpandedValueData = NULL;
2875 
2876         break;
2877 
2878     case REG_MULTI_SZ:
2879         tmp = ValueData;
2880 
2881         /* : We shouldn't overflow here, as the buffer is guarantied
2882            : to contain at least two consequent NULs */
2883         while (1) {
2884             if (tmp[0] == '\0') {
2885                 /* : Stop the process if we found the end of the string (two consequent NULs) */
2886                 if (tmp[1] == '\0') {
2887                     break;
2888                 }
2889 
2890                 /* : Replace delimiting NUL with our delimiter characted */
2891                 tmp[0] = PATHS_DELIMITER;
2892             }
2893             tmp += strlen(tmp);
2894         }
2895         break;
2896 
2897     case REG_SZ:
2898         /* Do nothing, it is good as is */
2899         break;
2900 
2901     default:
2902         return_value = NULL;
2903         goto CLEANUP;
2904     }
2905 
2906     return_value = ValueData;
2907 
2908     CLEANUP:
2909     RegCloseKey(hKey);
2910     if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
2911     if (return_value == NULL) {
2912 	if (ValueData != NULL) sasl_FREE(ValueData);
2913     }
2914     *path = return_value;
2915 
2916 #ifdef _SUN_SDK_
2917 /* SASL_PATH is not allowed for SUN SDK */
2918   if (! *path)
2919     *path = PLUGINDIR;
2920 #endif /* _SUN_SDK_ */
2921 	return SASL_OK;
2922 }
2923 
2924 #endif
2925