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
85static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
86
87#ifdef _SUN_SDK_
88DEFINE_STATIC_MUTEX(global_mutex);
89DEFINE_STATIC_MUTEX(malloc_global_mutex);
90static void _sasl_dispose_context(_sasl_global_context_t *ctx);
91static int _sasl_getconf(void *context, const char **conf);
92
93#ifdef _INTEGRATED_SOLARIS_
94static pthread_key_t errstring_key = PTHREAD_ONCE_KEY_NP;
95#endif /* _INTEGRATED_SOLARIS_ */
96#else
97static const char build_ident[] = "$Build: libsasl " PACKAGE "-" VERSION " $";
98
99/* It turns out to be conveinent to have a shared sasl_utils_t */
100LIBSASL_VAR const sasl_utils_t *sasl_global_utils = NULL;
101
102/* Should be a null-terminated array that lists the available mechanisms */
103static char **global_mech_list = NULL;
104
105void *free_mutex = NULL;
106
107int (*_sasl_client_cleanup_hook)(void) = NULL;
108int (*_sasl_server_cleanup_hook)(void) = NULL;
109int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
110int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
111
112sasl_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
121static 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
135static 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
145static 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
155static 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) */
164static void *sasl_mutex_alloc(void)
165{
166  return (void *)0x1;
167}
168
169static int sasl_mutex_lock(void *mutex __attribute__((unused)))
170{
171    return SASL_OK;
172}
173
174static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
175{
176    return SASL_OK;
177}
178
179static void sasl_mutex_free(void *mutex __attribute__((unused)))
180{
181    return;
182}
183#endif /* USE_PTHREADS */
184
185#ifndef _SUN_SDK_
186sasl_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
194void 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_
214int __sasl_strdup(const _sasl_global_context_t *gctx, const char *in,
215	char **out, size_t *outlen)
216#else
217int _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_
230int __sasl_add_string(const _sasl_global_context_t *gctx, char **out,
231		     size_t *alloclen, size_t *outlen,
232		     const char *add)
233#else
234int _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 # */
255void 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 */
270int 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 */
296int 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 */
361int 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
441void
442sasl_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
464void 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 */
501int _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_
585int _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
622int _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 */
647void 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
684void _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 */
728int 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 */
878int 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 */
1085static 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_
1096static void free_err_tsd(void *key)
1097{
1098    free(key);
1099}
1100#endif /* _INTEGRATED_SOLARIS_ */
1101
1102const 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 */
1259const 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_
1294DEFINE_STATIC_MUTEX(reg_mutex);
1295typedef struct reg_list {
1296	struct reg_list *next;
1297	void *mech;
1298} reg_list_t;
1299
1300static reg_list_t *reg_list_base = NULL;
1301
1302int _is_sun_reg(void *mech)
1303{
1304	reg_list_t *r, *prev = NULL;
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 (prev == NULL) {
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
1326static 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 */
1344static 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
1404static 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 */
1445static 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
1481static 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
1543static 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
1553static 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
1583int _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_
1687static 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
1700void
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
1723void
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
1759static 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_
1928sasl_utils_t *
1929_sasl_alloc_utils(_sasl_global_context_t *gctx, sasl_conn_t *conn,
1930		  sasl_global_callbacks_t *global_callbacks)
1931#else
1932sasl_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
2049int
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
2076int 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
2105const 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_
2129extern 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
2153const 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_
2178int __buf_alloc(const _sasl_global_context_t *gctx, char **rwbuf,
2179		size_t *curlen, size_t newlen)
2180#else
2181int _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 */
2211void _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_
2219int _iovec_to_buf(const _sasl_global_context_t *gctx, const struct iovec *vec,
2220		  unsigned numiov, buffer_info_t **output)
2221#else
2222int _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
2262int _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 */
2282static 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
2295int _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_
2400int _sasl_build_mechlist(_sasl_global_context_t *gctx)
2401#else
2402int _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
2498const 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
2509int 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
2549void *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() */
2576void 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 */
2585static 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
2666static 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)
2679int
2680sasl_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
2696static 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 */
2716static 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