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