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