1 /* common.c - Functions that are common to server and clinet
4 * $Id: common.c,v 1.114 2006/04/19 18:39:59 mel Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
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.
67 static const char *implementation_string = "Cyrus SASL";
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, \
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);
80 static char * _sasl_get_default_unix_path(void *context __attribute__((unused)),
81 char * env_var_name, char * default_value);
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);
89 static const char build_ident[] = "$Build: libsasl " PACKAGE "-" VERSION " $";
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;
94 /* Should be a null-terminated array that lists the available mechanisms */
95 static char **global_mech_list = NULL;
97 void *free_mutex = NULL;
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;
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
111 #define SASL_ENCODEV_EXTRA 4096
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
117 static sasl_callback_t default_getconfpath_cb = {
118 SASL_CB_GETCONFPATH, &_sasl_getconfpath, NULL
121 static char * default_plugin_path = NULL;
122 static char * default_conf_path = NULL;
124 /* Intenal mutex functions do as little as possible (no thread protection) */
125 static void *sasl_mutex_alloc(void)
130 static int sasl_mutex_lock(void *mutex __attribute__((unused)))
135 static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
140 static void sasl_mutex_free(void *mutex __attribute__((unused)))
145 sasl_mutex_utils_t _sasl_mutex_utils={
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)
155 _sasl_mutex_utils.alloc=n;
156 _sasl_mutex_utils.lock=l;
157 _sasl_mutex_utils.unlock=u;
158 _sasl_mutex_utils.free=d;
161 /* copy a string to malloced memory */
162 int _sasl_strdup(const char *in, char **out, size_t *outlen)
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);
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)
178 if (add==NULL) add = "(null)";
180 addlen=strlen(add); /* only compute once */
181 if (_buf_alloc(out, alloclen, (*outlen)+addlen)!=SASL_OK)
184 strncpy(*out + *outlen, add, addlen);
190 /* a simpler way to set plugin path or configuration file path
191 * without the need to set sasl_getpath_t callback.
193 * This function can be called before sasl_server_init/sasl_client_init.
195 * Don't call this function without locking in a multithreaded application.
197 int sasl_set_path (int path_type, char * path)
206 case SASL_PATH_TYPE_PLUGIN:
207 if (default_plugin_path != NULL) {
208 sasl_FREE (default_plugin_path);
209 default_plugin_path = NULL;
211 result = _sasl_strdup (path, &default_plugin_path, NULL);
212 if (result != SASL_OK) {
216 /* Update the default getpath_t callback */
217 default_getpath_cb.proc = (int (*)()) &_sasl_getpath_simple;
220 case SASL_PATH_TYPE_CONFIG:
221 if (default_conf_path != NULL) {
222 sasl_FREE (default_conf_path);
223 default_conf_path = NULL;
225 result = _sasl_strdup (path, &default_conf_path, NULL);
226 if (result != SASL_OK) {
230 /* Update the default getpath_t callback */
231 default_getconfpath_cb.proc = (int (*)()) &_sasl_getconfpath_simple;
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)
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) |
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,
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;
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,
271 const char **output, unsigned *outputlen)
276 if(!conn) return SASL_BADPARAM;
277 if(!input || !inputlen || !output || !outputlen)
280 /* maxoutbuf checking is done in sasl_encodev */
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;
288 result = sasl_encodev(conn, &tmp, 1, output, outputlen);
290 RETURN(conn, result);
293 /* Internal function that doesn't do any verification */
295 _sasl_encodev (sasl_conn_t *conn,
296 const struct iovec *invec,
298 int * p_num_packets, /* number of packets generated so far */
299 const char **output, /* previous output, if *p_num_packets > 0 */
305 assert (conn->oparams.encode != NULL);
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);
318 if (conn->multipacket_encoded_data.data == NULL) {
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;
329 new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
330 conn->multipacket_encoded_data.reallen + 1);
331 if (new_buf == NULL) {
334 conn->multipacket_encoded_data.data = new_buf;
338 memcpy (conn->multipacket_encoded_data.data,
343 result = conn->oparams.encode(conn->context,
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) {
360 conn->multipacket_encoded_data.data = new_buf;
363 /* Append new data to the end of the buffer */
364 memcpy (conn->multipacket_encoded_data.data +
365 conn->multipacket_encoded_data.curlen,
368 conn->multipacket_encoded_data.curlen += *outputlen;
370 *output = conn->multipacket_encoded_data.data;
371 *outputlen = conn->multipacket_encoded_data.curlen;
376 RETURN(conn, result);
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,
390 size_t total_size = 0;
391 struct iovec *cur_invec = NULL;
392 struct iovec last_invec;
394 char * next_buf = NULL;
395 unsigned remainder_len;
396 unsigned index_offset;
397 unsigned allocated = 0;
398 /* Number of generated SASL packets */
401 if (!conn) return SASL_BADPARAM;
402 if (! invec || ! output || ! outputlen || numiov < 1) {
406 if (!conn->props.maxbufsize) {
407 sasl_seterror(conn, 0,
408 "called sasl_encode[v] with application that does not support security layers");
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);
418 *output = conn->encode_buf->data;
419 *outputlen = (unsigned) conn->encode_buf->curlen;
421 RETURN(conn, result);
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 */
428 last_invec.iov_base = NULL;
433 if ((total_size + invec[i].iov_len) > conn->oparams.maxoutbuf) {
435 /* CLAIM: total_size < conn->oparams.maxoutbuf */
437 /* Fit as many bytes in last_invec, so that we have conn->oparams.maxoutbuf
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;
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. */
447 /* +1 --- for the tail record */
450 /* +1 --- just in case we need the head record */
451 if ((cur_numiov + 1) > allocated) {
452 struct iovec *new_invec;
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);
462 cur_invec = new_invec;
465 if (next_buf != NULL) {
466 cur_invec[0].iov_base = next_buf;
467 cur_invec[0].iov_len = remainder_len;
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];
482 /* Initialize the last record */
483 cur_invec[i + index_offset] = last_invec;
485 result = _sasl_encodev (conn,
492 if (result != SASL_OK) {
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;
505 /* Skip all consumed IOV records */
507 numiov = numiov - (i + 1);
510 while (remainder_len > conn->oparams.maxoutbuf) {
511 last_invec.iov_base = next_buf;
512 last_invec.iov_len = conn->oparams.maxoutbuf;
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;
519 result = _sasl_encodev (conn,
525 if (result != SASL_OK) {
530 total_size = remainder_len;
532 if (remainder_len == 0) {
533 /* Just clear next_buf */
537 total_size += invec[i].iov_len;
542 /* CLAIM - The remaining data is shorter then conn->oparams.maxoutbuf. */
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;
549 result = _sasl_encodev (conn,
556 if (result != SASL_OK) {
562 result = _sasl_encodev (conn,
571 if (cur_invec != NULL) {
572 sasl_FREE(cur_invec);
575 RETURN(conn, result);
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)
585 if(!conn) return SASL_BADPARAM;
586 if(!input || !output || !outputlen)
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);
595 if(conn->oparams.decode == NULL)
597 /* Since we know how long the output is maximally, we can
598 * just allocate it to begin with, and never need another
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);
609 if(!conn->decode_buf)
610 conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
611 if(!conn->decode_buf)
614 memcpy(conn->decode_buf, input, inputlen);
615 conn->decode_buf[inputlen] = '\0';
616 *output = conn->decode_buf;
617 *outputlen = inputlen;
621 result = conn->oparams.decode(conn->context, input, inputlen,
624 /* NULL an empty buffer (for misbehaved applications) */
625 if (*outputlen == 0) *output = NULL;
627 RETURN(conn, result);
630 INTERROR(conn, SASL_FAIL);
635 sasl_set_alloc(sasl_malloc_t *m,
640 _sasl_allocation_utils.malloc=m;
641 _sasl_allocation_utils.calloc=c;
642 _sasl_allocation_utils.realloc=r;
643 _sasl_allocation_utils.free=f;
648 if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
649 _sasl_server_idle_hook = NULL;
650 _sasl_server_cleanup_hook = NULL;
653 if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
654 _sasl_client_idle_hook = NULL;
655 _sasl_client_cleanup_hook = NULL;
658 if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
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;
668 if (default_conf_path != NULL) {
669 sasl_FREE (default_conf_path);
670 default_conf_path = NULL;
673 _sasl_canonuser_free();
674 _sasl_done_with_plugins();
676 sasl_MUTEX_FREE(free_mutex);
679 _sasl_free_utils(&sasl_global_utils);
681 if(global_mech_list) sasl_FREE(global_mech_list);
682 global_mech_list = NULL;
685 /* fills in the base sasl_conn_t info */
686 int _sasl_conn_init(sasl_conn_t *conn,
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;
700 result = _sasl_strdup(service, &conn->service, NULL);
701 if (result != SASL_OK)
704 memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
705 memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
709 result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
710 if(result != SASL_OK)
711 RETURN(conn, result);
713 result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
714 if(result != SASL_OK)
715 RETURN(conn, result);
717 conn->encode_buf = NULL;
718 conn->context = NULL;
720 conn->idle_hook = idle_hook;
721 conn->callbacks = callbacks;
722 conn->global_callbacks = global_callbacks;
724 memset(&conn->props, 0, sizeof(conn->props));
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;
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);
736 conn->error_buf[0] = '\0';
737 conn->errdetail_buf[0] = '\0';
739 conn->decode_buf = NULL;
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);
749 result = _sasl_strdup(name, &conn->serverFQDN, NULL);
751 conn->serverFQDN = NULL;
755 if(result != SASL_OK) MEMERROR( conn );
757 RETURN(conn, SASL_OK);
760 int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
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;
770 /* Init the canon_user plugin */
771 result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
772 if(result != SASL_OK) return result;
775 free_mutex = sasl_MUTEX_ALLOC();
776 if (!free_mutex) return SASL_FAIL;
781 /* dispose connection state, sets it to NULL
782 * checks for pointer to NULL
784 void sasl_dispose(sasl_conn_t **pconn)
789 if (! *pconn) return;
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;
796 /* *pconn might have become NULL by now */
797 if (! (*pconn)) return;
799 (*pconn)->destroy_conn(*pconn);
803 sasl_MUTEX_UNLOCK(free_mutex);
806 void _sasl_conn_dispose(sasl_conn_t *conn) {
807 if (conn->serverFQDN)
808 sasl_FREE(conn->serverFQDN);
810 if (conn->external.auth_id)
811 sasl_FREE(conn->external.auth_id);
813 if(conn->encode_buf) {
814 if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
815 sasl_FREE(conn->encode_buf);
819 sasl_FREE(conn->error_buf);
821 if(conn->errdetail_buf)
822 sasl_FREE(conn->errdetail_buf);
825 sasl_FREE(conn->decode_buf);
827 if(conn->mechlist_buf)
828 sasl_FREE(conn->mechlist_buf);
831 sasl_FREE(conn->service);
833 if (conn->multipacket_encoded_data.data) {
834 sasl_FREE(conn->multipacket_encoded_data.data);
837 /* oparams sub-members should be freed by the plugin, in so much
838 * as they were allocated by the plugin */
842 /* get property from SASL connection state
843 * propnum -- property number
844 * pvalue -- pointer to value
846 * SASL_OK -- no error
847 * SASL_NOTDONE -- property not available yet
848 * SASL_BADPARAM -- bad property number
850 int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
852 int result = SASL_OK;
853 sasl_getopt_t *getopt;
856 if (! conn) return SASL_BADPARAM;
857 if (! pvalue) PARAMERROR(conn);
862 *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
865 *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
868 result = _sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context);
869 if(result != SASL_OK) break;
871 *(void **)pvalue = context;
874 *(const sasl_callback_t **)pvalue = conn->callbacks;
876 case SASL_IPLOCALPORT:
877 if(conn->got_ip_local)
878 *(const char **)pvalue = conn->iplocalport;
880 *(const char **)pvalue = NULL;
881 result = SASL_NOTDONE;
884 case SASL_IPREMOTEPORT:
885 if(conn->got_ip_remote)
886 *(const char **)pvalue = conn->ipremoteport;
888 *(const char **)pvalue = NULL;
889 result = SASL_NOTDONE;
893 if(! conn->oparams.user)
894 result = SASL_NOTDONE;
896 *((const char **)pvalue) = conn->oparams.user;
899 if(! conn->oparams.authid)
900 result = SASL_NOTDONE;
902 *((const char **)pvalue) = conn->oparams.authid;
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;
909 *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->sparams->appname;
911 case SASL_SERVERFQDN:
912 *((const char **)pvalue) = conn->serverFQDN;
914 case SASL_DEFUSERREALM:
915 if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
917 *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
920 *((const char **)pvalue) = conn->service;
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;
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;
935 *((const char **)pvalue) =
936 ((sasl_server_conn_t *)conn)->mech->m.plugname;
938 result = SASL_BADPARAM;
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;
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;
954 *((const char **)pvalue) =
955 ((sasl_server_conn_t *)conn)->mech->m.plug->mech_name;
957 result = SASL_BADPARAM;
960 if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
963 *((const char **)pvalue) = conn->error_buf;
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;
971 *((const char **)pvalue) = conn->oparams.client_creds;
973 case SASL_GSS_PEER_NAME:
974 if(! conn->oparams.gss_peer_name)
975 result = SASL_NOTDONE;
977 *((const char **)pvalue) = conn->oparams.gss_peer_name;
979 case SASL_GSS_LOCAL_NAME:
980 if(! conn->oparams.gss_peer_name)
981 result = SASL_NOTDONE;
983 *((const char **)pvalue) = conn->oparams.gss_local_name;
985 case SASL_SSF_EXTERNAL:
986 *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
988 case SASL_AUTH_EXTERNAL:
989 *((const char **)pvalue) = conn->external.auth_id;
992 *((const sasl_security_properties_t **)pvalue) = &conn->props;
995 result = SASL_BADPARAM;
998 if(result == SASL_BADPARAM) {
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);
1007 RETURN(conn, result);
1010 /* set property in SASL connection state
1012 * SASL_OK -- value set
1013 * SASL_BADPARAM -- invalid property or value
1015 int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
1017 int result = SASL_OK;
1020 /* make sure the sasl context is valid */
1022 return SASL_BADPARAM;
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 =
1032 ((sasl_client_conn_t*)conn)->cparams->external_ssf =
1037 case SASL_AUTH_EXTERNAL:
1038 if(value && strlen(value)) {
1039 result = _sasl_strdup(value, &str, NULL);
1040 if(result != SASL_OK) MEMERROR(conn);
1045 if(conn->external.auth_id)
1046 sasl_FREE(conn->external.auth_id);
1048 conn->external.auth_id = str;
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;
1059 if(value && strlen(value)) {
1060 result = _sasl_strdup(value, &str, NULL);
1061 if(result != SASL_OK) MEMERROR(conn);
1066 if(((sasl_server_conn_t *)conn)->user_realm)
1067 sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
1069 ((sasl_server_conn_t *)conn)->user_realm = str;
1070 ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
1074 case SASL_SEC_PROPS:
1076 sasl_security_properties_t *props = (sasl_security_properties_t *)value;
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);
1084 conn->props = *props;
1086 if(conn->type == SASL_CONN_SERVER) {
1087 ((sasl_server_conn_t*)conn)->sparams->props = *props;
1089 ((sasl_client_conn_t*)conn)->cparams->props = *props;
1095 case SASL_IPREMOTEPORT:
1097 const char *ipremoteport = (const char *)value;
1099 conn->got_ip_remote = 0;
1100 } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
1102 sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
1103 RETURN(conn, SASL_BADPARAM);
1105 strcpy(conn->ipremoteport, ipremoteport);
1106 conn->got_ip_remote = 1;
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);
1122 if(conn->type == SASL_CONN_CLIENT) {
1123 ((sasl_client_conn_t *)conn)->cparams->ipremoteport
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
1129 ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
1136 case SASL_IPLOCALPORT:
1138 const char *iplocalport = (const char *)value;
1140 conn->got_ip_local = 0;
1141 } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
1143 sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
1144 RETURN(conn, SASL_BADPARAM);
1146 strcpy(conn->iplocalport, iplocalport);
1147 conn->got_ip_local = 1;
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);
1163 if(conn->type == SASL_CONN_CLIENT) {
1164 ((sasl_client_conn_t *)conn)->cparams->iplocalport
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
1170 ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
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;
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;
1190 if(value && strlen(value)) {
1191 result = _sasl_strdup(value,
1192 &(((sasl_server_conn_t *)conn)->appname),
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);
1200 ((sasl_server_conn_t *)conn)->sparams->appname = NULL;
1201 ((sasl_server_conn_t *)conn)->sparams->applen = 0;
1205 case SASL_GSS_CREDS:
1206 if (conn->type == SASL_CONN_SERVER)
1207 ((sasl_server_conn_t *)conn)->sparams->gss_creds = (void *)value;
1209 ((sasl_client_conn_t *)conn)->cparams->gss_creds = (void *)value;
1211 case SASL_CHANNEL_BINDING: {
1212 struct sasl_channel_binding *cb = (struct sasl_channel_binding *)value;
1214 if (conn->type == SASL_CONN_SERVER) {
1215 ((sasl_server_conn_t *)conn)->sparams->chanbindingtype = cb->type;
1216 ((sasl_server_conn_t *)conn)->sparams->chanbindingdata = cb->data;
1217 ((sasl_server_conn_t *)conn)->sparams->chanbindinglen = cb->len;
1218 ((sasl_server_conn_t *)conn)->sparams->chanbindingcrit = cb->critical;
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 if (cb->critical != 0)
1224 ((sasl_client_conn_t *)conn)->cparams->chanbindingflags |= SASL_CB_FLAG_CRIT;
1226 ((sasl_client_conn_t *)conn)->cparams->chanbindingflags &= ~(SASL_CB_FLAG_CRIT);
1231 sasl_seterror(conn, 0, "Unknown parameter type");
1232 result = SASL_BADPARAM;
1235 RETURN(conn, result);
1238 /* this is apparently no longer a user function */
1239 static int sasl_usererr(int saslerr)
1241 /* Hide the difference in a username failure and a password failure */
1242 if (saslerr == SASL_NOUSER)
1243 return SASL_BADAUTH;
1245 /* otherwise return the error given; no transform necessary */
1249 const char *sasl_errstring(int saslerr,
1250 const char *langlist __attribute__((unused)),
1251 const char **outlang)
1253 if (outlang) *outlang="en-us";
1257 case SASL_CONTINUE: return "another step is needed in authentication";
1258 case SASL_OK: return "successful result";
1259 case SASL_FAIL: return "generic failure";
1260 case SASL_NOMEM: return "no memory available";
1261 case SASL_BUFOVER: return "overflowed buffer";
1262 case SASL_NOMECH: return "no mechanism available";
1263 case SASL_BADPROT: return "bad protocol / cancel";
1264 case SASL_NOTDONE: return "can't request info until later in exchange";
1265 case SASL_BADPARAM: return "invalid parameter supplied";
1266 case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
1267 case SASL_BADMAC: return "integrity check failed";
1268 case SASL_NOTINIT: return "SASL library not initialized";
1269 /* -- client only codes -- */
1270 case SASL_INTERACT: return "needs user interaction";
1271 case SASL_BADSERV: return "server failed mutual authentication step";
1272 case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
1273 /* -- server only codes -- */
1274 case SASL_BADAUTH: return "authentication failure";
1275 case SASL_NOAUTHZ: return "authorization failure";
1276 case SASL_TOOWEAK: return "mechanism too weak for this user";
1277 case SASL_ENCRYPT: return "encryption needed to use mechanism";
1278 case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
1279 case SASL_EXPIRED: return "passphrase expired, has to be reset";
1280 case SASL_DISABLED: return "account disabled";
1281 case SASL_NOUSER: return "user not found";
1282 case SASL_BADVERS: return "version mismatch with plug-in";
1283 case SASL_UNAVAIL: return "remote authentication server unavailable";
1284 case SASL_NOVERIFY: return "user exists, but no verifier for user";
1285 case SASL_PWLOCK: return "passphrase locked";
1286 case SASL_NOCHANGE: return "requested change was not needed";
1287 case SASL_WEAKPASS: return "passphrase is too weak for security policy";
1288 case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
1290 default: return "undefined error!";
1295 /* Return the sanitized error detail about the last error that occured for
1297 const char *sasl_errdetail(sasl_conn_t *conn)
1303 if(!conn) return NULL;
1305 errstr = sasl_errstring(conn->error_code, NULL, NULL);
1306 snprintf(leader,128,"SASL(%d): %s: ",
1307 sasl_usererr(conn->error_code), errstr);
1309 need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
1310 _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1312 snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
1314 return conn->errdetail_buf;
1318 /* Note that this needs the global callbacks, so if you don't give getcallbacks
1319 * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
1320 * have client and server at the same time */
1321 static int _sasl_global_getopt(void *context,
1322 const char *plugin_name,
1324 const char ** result,
1327 const sasl_global_callbacks_t * global_callbacks;
1328 const sasl_callback_t *callback;
1330 global_callbacks = (const sasl_global_callbacks_t *) context;
1332 if (global_callbacks && global_callbacks->callbacks) {
1333 for (callback = global_callbacks->callbacks;
1334 callback->id != SASL_CB_LIST_END;
1336 if (callback->id == SASL_CB_GETOPT) {
1337 if (!callback->proc) return SASL_FAIL;
1338 if (((sasl_getopt_t *)(callback->proc))(callback->context,
1349 /* look it up in our configuration file */
1350 *result = sasl_config_getstring(option, NULL);
1351 if (*result != NULL) {
1352 if (len) { *len = (unsigned) strlen(*result); }
1360 _sasl_conn_getopt(void *context,
1361 const char *plugin_name,
1363 const char ** result,
1367 const sasl_callback_t *callback;
1370 return SASL_BADPARAM;
1372 conn = (sasl_conn_t *) context;
1374 if (conn->callbacks)
1375 for (callback = conn->callbacks;
1376 callback->id != SASL_CB_LIST_END;
1378 if (callback->id == SASL_CB_GETOPT
1379 && (((sasl_getopt_t *)(callback->proc))(callback->context,
1387 /* If we made it here, we didn't find an appropriate callback
1388 * in the connection's callback list, or the callback we did
1389 * find didn't return SASL_OK. So we attempt to use the
1390 * global callback for this connection... */
1391 return _sasl_global_getopt((void *)conn->global_callbacks,
1399 /* this is the default logging */
1400 static int _sasl_syslog(void *context,
1402 const char *message)
1404 int syslog_priority;
1405 sasl_server_conn_t *sconn;
1408 if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
1409 sconn = (sasl_server_conn_t *)context;
1410 if (sconn->sparams->log_level < priority)
1415 /* set syslog priority */
1421 syslog_priority = LOG_ERR;
1424 syslog_priority = LOG_WARNING;
1428 syslog_priority = LOG_NOTICE;
1431 case SASL_LOG_TRACE:
1432 case SASL_LOG_DEBUG:
1434 syslog_priority = LOG_DEBUG;
1438 /* do the syslog call. Do not need to call openlog? */
1439 syslog(syslog_priority | LOG_AUTH, "%s", message);
1443 #endif /* HAVE_SYSLOG */
1446 _sasl_getsimple(void *context,
1448 const char ** result,
1454 if (! context || ! result) return SASL_BADPARAM;
1456 conn = (sasl_conn_t *)context;
1459 case SASL_CB_AUTHNAME:
1460 userid = getenv("USER");
1461 if (userid != NULL) {
1463 if (len) *len = strlen(userid);
1466 userid = getenv("USERNAME");
1467 if (userid != NULL) {
1469 if (len) *len = strlen(userid);
1473 /* for win32, try using the GetUserName standard call */
1477 static char sender[128];
1480 rval = GetUserName(sender, &i);
1481 if ( rval) { /* got a userid */
1483 if (len) *len = strlen(sender);
1490 return SASL_BADPARAM;
1495 _sasl_getpath(void *context __attribute__((unused)),
1496 const char ** path_dest)
1504 return SASL_BADPARAM;
1507 /* Only calculate the path once. */
1508 if (default_plugin_path == NULL) {
1511 /* NB: On Windows platforms this value is always allocated */
1512 default_plugin_path = _sasl_get_default_win_path(context,
1513 SASL_PLUGIN_PATH_ATTR,
1516 /* NB: On Unix platforms this value is never allocated */
1517 path = _sasl_get_default_unix_path(context,
1521 res = _sasl_strdup(path, &default_plugin_path, NULL);
1525 if (res == SASL_OK) {
1526 *path_dest = default_plugin_path;
1533 _sasl_getpath_simple(void *context __attribute__((unused)),
1537 return SASL_BADPARAM;
1540 if (default_plugin_path == NULL) {
1544 *path = default_plugin_path;
1550 _sasl_getconfpath(void *context __attribute__((unused)),
1559 return SASL_BADPARAM;
1562 /* Only calculate the path once. */
1563 if (default_conf_path == NULL) {
1566 /* NB: On Windows platforms this value is always allocated */
1567 default_conf_path = _sasl_get_default_win_path(context,
1568 SASL_CONF_PATH_ATTR,
1571 /* NB: On Unix platforms this value is never allocated */
1572 path = _sasl_get_default_unix_path(context,
1573 SASL_CONF_PATH_ENV_VAR,
1576 res = _sasl_strdup(path, &default_conf_path, NULL);
1580 if (res == SASL_OK) {
1581 *path_dest = default_conf_path;
1588 _sasl_getconfpath_simple(void *context __attribute__((unused)),
1592 return SASL_BADPARAM;
1595 if (default_conf_path == NULL) {
1599 *path = default_conf_path;
1605 _sasl_verifyfile(void *context __attribute__((unused)),
1606 char *file __attribute__((unused)),
1607 int type __attribute__((unused)))
1615 _sasl_proxy_policy(sasl_conn_t *conn,
1616 void *context __attribute__((unused)),
1617 const char *requested_user, unsigned rlen,
1618 const char *auth_identity, unsigned alen,
1619 const char *def_realm __attribute__((unused)),
1620 unsigned urlen __attribute__((unused)),
1621 struct propctx *propctx __attribute__((unused)))
1624 return SASL_BADPARAM;
1626 if (!requested_user || *requested_user == '\0')
1629 if (!auth_identity || !requested_user || rlen != alen ||
1630 (memcmp(auth_identity, requested_user, rlen) != 0)) {
1631 sasl_seterror(conn, 0,
1632 "Requested identity not authenticated identity");
1633 RETURN(conn, SASL_BADAUTH);
1639 int _sasl_getcallback(sasl_conn_t * conn,
1640 unsigned long callbackid,
1644 const sasl_callback_t *callback;
1646 if (!pproc || !pcontext)
1649 /* Some callbacks are always provided by the library */
1650 switch (callbackid) {
1651 case SASL_CB_LIST_END:
1652 /* Nothing ever gets to provide this */
1653 INTERROR(conn, SASL_FAIL);
1654 case SASL_CB_GETOPT:
1656 *pproc = &_sasl_conn_getopt;
1659 *pproc = &_sasl_global_getopt;
1665 /* If it's not always provided by the library, see if there's
1666 * a version provided by the application for this connection... */
1667 if (conn && conn->callbacks) {
1668 for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
1670 if (callback->id == callbackid) {
1671 *pproc = callback->proc;
1672 *pcontext = callback->context;
1673 if (callback->proc) {
1676 return SASL_INTERACT;
1682 /* And, if not for this connection, see if there's one
1683 * for all {server,client} connections... */
1684 if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
1685 for (callback = conn->global_callbacks->callbacks;
1686 callback->id != SASL_CB_LIST_END;
1688 if (callback->id == callbackid) {
1689 *pproc = callback->proc;
1690 *pcontext = callback->context;
1691 if (callback->proc) {
1694 return SASL_INTERACT;
1700 /* Otherwise, see if the library provides a default callback. */
1701 switch (callbackid) {
1704 *pproc = (int (*)()) &_sasl_syslog;
1707 #endif /* HAVE_SYSLOG */
1708 case SASL_CB_GETPATH:
1709 *pproc = default_getpath_cb.proc;
1710 *pcontext = default_getpath_cb.context;
1712 case SASL_CB_GETCONFPATH:
1713 *pproc = default_getconfpath_cb.proc;
1714 *pcontext = default_getconfpath_cb.context;
1716 case SASL_CB_AUTHNAME:
1717 *pproc = (int (*)()) &_sasl_getsimple;
1720 case SASL_CB_VERIFYFILE:
1721 *pproc = & _sasl_verifyfile;
1724 case SASL_CB_PROXY_POLICY:
1725 *pproc = (int (*)()) &_sasl_proxy_policy;
1730 /* Unable to find a callback... */
1733 sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
1734 RETURN(conn,SASL_FAIL);
1739 * This function is typically called from a plugin.
1740 * It creates a string from the formatting and varargs given
1741 * and calls the logging callback (syslog by default)
1743 * %m will parse the value in the next argument as an errno string
1744 * %z will parse the next argument as a SASL error code.
1748 _sasl_log (sasl_conn_t *conn,
1753 char *out=(char *) sasl_ALLOC(250);
1754 size_t alloclen=100; /* current allocated length */
1755 size_t outlen=0; /* current length of output buffer */
1757 size_t pos=0; /* current position in format string */
1765 va_list ap; /* varargs thing */
1770 formatlen = strlen(fmt);
1772 /* See if we have a logging callback... */
1773 result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1774 if (result == SASL_OK && ! log_cb)
1776 if (result != SASL_OK) goto done;
1778 va_start(ap, fmt); /* start varargs */
1780 while(pos<formatlen)
1782 if (fmt[pos]!='%') /* regular character */
1784 result = _buf_alloc(&out, &alloclen, outlen+1);
1785 if (result != SASL_OK) goto done;
1786 out[outlen]=fmt[pos];
1790 } else { /* formating thing */
1802 case 's': /* need to handle this */
1803 cval = va_arg(ap, char *); /* get the next arg */
1804 result = _sasl_add_string(&out, &alloclen,
1807 if (result != SASL_OK) /* add the string */
1813 case '%': /* double % output the '%' character */
1814 result = _buf_alloc(&out,&alloclen,outlen+1);
1815 if (result != SASL_OK)
1823 case 'm': /* insert the errno string */
1824 result = _sasl_add_string(&out, &alloclen, &outlen,
1825 strerror(va_arg(ap, int)));
1826 if (result != SASL_OK)
1832 case 'z': /* insert the sasl error string */
1833 result = _sasl_add_string(&out, &alloclen, &outlen,
1834 (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
1835 if (result != SASL_OK)
1842 frmt[frmtpos++]=fmt[pos];
1844 tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
1847 /* now add the character */
1848 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1849 if (result != SASL_OK)
1857 frmt[frmtpos++]=fmt[pos];
1859 ival = va_arg(ap, int); /* get the next arg */
1861 snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
1862 /* now add the string */
1863 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1864 if (result != SASL_OK)
1874 frmt[frmtpos++]=fmt[pos];
1876 uval = va_arg(ap, unsigned int); /* get the next arg */
1878 snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
1879 /* now add the string */
1880 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1881 if (result != SASL_OK)
1888 frmt[frmtpos++]=fmt[pos]; /* add to the formating */
1902 result = _buf_alloc(&out, &alloclen, outlen+1);
1903 if (result != SASL_OK) goto done;
1908 /* send log message */
1909 result = log_cb(log_ctx, level, out);
1912 if(out) sasl_FREE(out);
1917 /* Allocate and Init a sasl_utils_t structure */
1919 _sasl_alloc_utils(sasl_conn_t *conn,
1920 sasl_global_callbacks_t *global_callbacks)
1922 sasl_utils_t *utils;
1923 /* set util functions - need to do rest*/
1924 utils=sasl_ALLOC(sizeof(sasl_utils_t));
1930 sasl_randcreate(&utils->rpool);
1933 utils->getopt = &_sasl_conn_getopt;
1934 utils->getopt_context = conn;
1936 utils->getopt = &_sasl_global_getopt;
1937 utils->getopt_context = global_callbacks;
1940 utils->malloc=_sasl_allocation_utils.malloc;
1941 utils->calloc=_sasl_allocation_utils.calloc;
1942 utils->realloc=_sasl_allocation_utils.realloc;
1943 utils->free=_sasl_allocation_utils.free;
1945 utils->mutex_alloc = _sasl_mutex_utils.alloc;
1946 utils->mutex_lock = _sasl_mutex_utils.lock;
1947 utils->mutex_unlock = _sasl_mutex_utils.unlock;
1948 utils->mutex_free = _sasl_mutex_utils.free;
1950 utils->MD5Init = &_sasl_MD5Init;
1951 utils->MD5Update= &_sasl_MD5Update;
1952 utils->MD5Final = &_sasl_MD5Final;
1953 utils->hmac_md5 = &_sasl_hmac_md5;
1954 utils->hmac_md5_init = &_sasl_hmac_md5_init;
1955 utils->hmac_md5_final = &_sasl_hmac_md5_final;
1956 utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
1957 utils->hmac_md5_import = &_sasl_hmac_md5_import;
1958 utils->mkchal = &sasl_mkchal;
1959 utils->utf8verify = &sasl_utf8verify;
1960 utils->rand=&sasl_rand;
1961 utils->churn=&sasl_churn;
1962 utils->checkpass=NULL;
1964 utils->encode64=&sasl_encode64;
1965 utils->decode64=&sasl_decode64;
1967 utils->erasebuffer=&sasl_erasebuffer;
1969 utils->getprop=&sasl_getprop;
1970 utils->setprop=&sasl_setprop;
1972 utils->getcallback=&_sasl_getcallback;
1974 utils->log=&_sasl_log;
1976 utils->seterror=&sasl_seterror;
1979 /* Aux Property Utilities */
1980 utils->prop_new=&prop_new;
1981 utils->prop_dup=&prop_dup;
1982 utils->prop_request=&prop_request;
1983 utils->prop_get=&prop_get;
1984 utils->prop_getnames=&prop_getnames;
1985 utils->prop_clear=&prop_clear;
1986 utils->prop_dispose=&prop_dispose;
1987 utils->prop_format=&prop_format;
1988 utils->prop_set=&prop_set;
1989 utils->prop_setvals=&prop_setvals;
1990 utils->prop_erase=&prop_erase;
1991 utils->auxprop_store=&sasl_auxprop_store;
1995 utils->spare_fptr = NULL;
1996 utils->spare_fptr1 = utils->spare_fptr2 = NULL;
2002 _sasl_free_utils(const sasl_utils_t ** utils)
2004 sasl_utils_t *nonconst;
2006 if(!utils) return SASL_BADPARAM;
2007 if(!*utils) return SASL_OK;
2009 /* I wish we could avoid this cast, it's pretty gratuitous but it
2010 * does make life easier to have it const everywhere else. */
2011 nonconst = (sasl_utils_t *)(*utils);
2013 sasl_randfree(&(nonconst->rpool));
2014 sasl_FREE(nonconst);
2020 int sasl_idle(sasl_conn_t *conn)
2023 if (_sasl_server_idle_hook
2024 && _sasl_server_idle_hook(NULL))
2026 if (_sasl_client_idle_hook
2027 && _sasl_client_idle_hook(NULL))
2032 if (conn->idle_hook)
2033 return conn->idle_hook(conn);
2038 static const sasl_callback_t *
2039 _sasl_find_callback_by_type (const sasl_callback_t *callbacks,
2043 while (callbacks->id != SASL_CB_LIST_END) {
2044 if (callbacks->id == id) {
2054 const sasl_callback_t *
2055 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
2057 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
2058 if (callbacks != NULL) {
2061 return &default_getpath_cb;
2065 const sasl_callback_t *
2066 _sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
2068 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
2069 if (callbacks != NULL) {
2072 return &default_getconfpath_cb;
2076 const sasl_callback_t *
2077 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
2079 static const sasl_callback_t default_verifyfile_cb = {
2085 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
2086 if (callbacks != NULL) {
2089 return &default_verifyfile_cb;
2093 /* Basically a conditional call to realloc(), if we need more */
2094 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
2097 *rwbuf = sasl_ALLOC((unsigned)newlen);
2098 if (*rwbuf == NULL) {
2103 } else if(*rwbuf && *curlen < newlen) {
2104 size_t needed = 2*(*curlen);
2106 while(needed < newlen)
2109 /* WARN - We will leak the old buffer on failure */
2110 *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
2112 if (*rwbuf == NULL) {
2122 /* for the mac os x cfm glue: this lets the calling function
2123 get pointers to the error buffer without having to touch the sasl_conn_t struct */
2124 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
2126 *bufhdl = &conn->error_buf;
2127 *lenhdl = &conn->error_buf_len;
2130 /* convert an iovec to a single buffer */
2131 int _iovec_to_buf(const struct iovec *vec,
2132 unsigned numiov, buffer_info_t **output)
2139 if (!vec || !output) return SASL_BADPARAM;
2142 *output = sasl_ALLOC(sizeof(buffer_info_t));
2143 if (!*output) return SASL_NOMEM;
2144 memset(*output,0,sizeof(buffer_info_t));
2150 for (i = 0; i < numiov; i++) {
2151 out->curlen += vec[i].iov_len;
2154 ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
2156 if (ret != SASL_OK) return SASL_NOMEM;
2158 memset(out->data, 0, out->reallen);
2161 for (i = 0; i < numiov; i++) {
2162 memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2163 pos += vec[i].iov_len;
2169 /* This code might be useful in the future, but it isn't now, so.... */
2171 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
2172 char *out, unsigned outlen) {
2173 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
2176 if(!addr || !out) return SASL_BADPARAM;
2178 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
2179 #ifdef NI_WITHSCOPEID
2180 if (addr->sa_family == AF_INET6)
2181 niflags |= NI_WITHSCOPEID;
2183 if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
2185 return SASL_BADPARAM;
2187 if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
2188 return SASL_BUFOVER;
2190 snprintf(out, outlen, "%s;%s", hbuf, pbuf);
2196 int _sasl_ipfromstring(const char *addr,
2197 struct sockaddr *out, socklen_t outlen)
2200 struct addrinfo hints, *ai = NULL;
2201 char hbuf[NI_MAXHOST];
2203 /* A NULL out pointer just implies we don't do a copy, just verify it */
2205 if(!addr) return SASL_BADPARAM;
2207 /* Parse the address */
2208 for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2209 if (i >= NI_MAXHOST)
2210 return SASL_BADPARAM;
2217 /* XXX: Do we need this check? */
2218 for (j = i; addr[j] != '\0'; j++)
2219 if (!isdigit((int)(addr[j])))
2220 return SASL_BADPARAM;
2222 memset(&hints, 0, sizeof(hints));
2223 hints.ai_family = PF_UNSPEC;
2224 hints.ai_socktype = SOCK_STREAM;
2225 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2226 if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
2227 return SASL_BADPARAM;
2230 if (outlen < (socklen_t)ai->ai_addrlen) {
2232 return SASL_BUFOVER;
2234 memcpy(out, ai->ai_addr, ai->ai_addrlen);
2242 int _sasl_build_mechlist(void)
2245 sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
2246 sasl_string_list_t *p, *q, **last, *p_next;
2248 clist = _sasl_client_mechs();
2249 slist = _sasl_server_mechs();
2256 /* append slist to clist, and set olist to clist */
2257 for(p = slist; p; p = p_next) {
2262 for(q = clist; q; q = q->next) {
2263 if(!strcmp(q->d, p->d)) {
2264 /* They match, set the flag */
2283 printf ("no olist");
2287 for (p = olist; p; p = p->next) count++;
2289 if(global_mech_list) {
2290 sasl_FREE(global_mech_list);
2291 global_mech_list = NULL;
2294 global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
2295 if(!global_mech_list) return SASL_NOMEM;
2297 memset(global_mech_list, 0, (count + 1) * sizeof(char *));
2300 for (p = olist; p; p = p_next) {
2303 global_mech_list[count++] = (char *) p->d;
2311 const char ** sasl_global_listmech(void)
2313 return (const char **)global_mech_list;
2316 int sasl_listmech(sasl_conn_t *conn,
2321 const char **result,
2326 return SASL_BADPARAM;
2327 } else if(conn->type == SASL_CONN_SERVER) {
2328 RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
2329 result, plen, pcount));
2330 } else if (conn->type == SASL_CONN_CLIENT) {
2331 RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
2332 result, plen, pcount));
2338 int _sasl_is_equal_mech(const char *req_mech,
2339 const char *plug_mech,
2342 size_t len = strlen(req_mech);
2346 strcasecmp(&req_mech[len - 5], "-PLUS") == 0) {
2354 return (strncasecmp(req_mech, plug_mech, n) == 0);
2359 _sasl_get_default_unix_path(void *context __attribute__((unused)),
2360 char * env_var_name,
2361 char * default_value)
2365 /* Honor external variable only in a safe environment */
2366 if (getuid() == geteuid() && getgid() == getegid()) {
2367 path = getenv(env_var_name);
2370 path = default_value;
2377 /* Return NULL on failure */
2379 _sasl_get_default_win_path(void *context __attribute__((unused)),
2380 char * reg_attr_name,
2381 char * default_value)
2383 /* Open registry entry, and find all registered SASL libraries.
2385 * Registry location:
2387 * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
2391 * "SearchPath" - value: PATH like (';' delimited) list
2392 * of directories where to search for plugins
2393 * The list may contain references to environment
2394 * variables (e.g. %PATH%).
2399 DWORD ValueType; /* value type */
2400 DWORD cbData; /* value size */
2401 BYTE * ValueData; /* value */
2402 DWORD cbExpandedData; /* "expanded" value size */
2403 BYTE * ExpandedValueData; /* "expanded" value */
2404 char * return_value; /* function return value */
2407 /* Initialization */
2408 ExpandedValueData = NULL;
2410 return_value = NULL;
2412 /* Open the registry */
2413 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2419 if (ret != ERROR_SUCCESS) {
2420 /* no registry entry */
2421 (void) _sasl_strdup (default_value, &return_value, NULL);
2422 return return_value;
2425 /* figure out value type and required buffer size */
2426 /* the size will include space for terminating NUL if required */
2427 RegQueryValueEx (hKey,
2429 NULL, /* reserved */
2434 /* Only accept string related types */
2435 if (ValueType != REG_EXPAND_SZ &&
2436 ValueType != REG_MULTI_SZ &&
2437 ValueType != REG_SZ) {
2438 return_value = NULL;
2442 /* Any high water mark? */
2443 ValueData = sasl_ALLOC(cbData);
2444 if (ValueData == NULL) {
2445 return_value = NULL;
2449 RegQueryValueEx (hKey,
2451 NULL, /* reserved */
2456 switch (ValueType) {
2458 /* : A random starting guess */
2459 cbExpandedData = cbData + 1024;
2460 ExpandedValueData = sasl_ALLOC(cbExpandedData);
2461 if (ExpandedValueData == NULL) {
2462 return_value = NULL;
2466 cbExpandedData = ExpandEnvironmentStrings(
2471 if (cbExpandedData == 0) {
2472 /* : GetLastError() contains the reason for failure */
2473 return_value = NULL;
2477 /* : Must retry expansion with the bigger buffer */
2478 if (cbExpandedData > cbData + 1024) {
2479 /* : Memory leak here if can't realloc */
2480 ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
2481 if (ExpandedValueData == NULL) {
2482 return_value = NULL;
2486 cbExpandedData = ExpandEnvironmentStrings(
2491 /* : This should not happen */
2492 if (cbExpandedData == 0) {
2493 /* : GetLastError() contains the reason for failure */
2494 return_value = NULL;
2499 sasl_FREE(ValueData);
2500 ValueData = ExpandedValueData;
2501 /* : This is to prevent automatical freeing of this block on cleanup */
2502 ExpandedValueData = NULL;
2509 /* : We shouldn't overflow here, as the buffer is guarantied
2510 : to contain at least two consequent NULs */
2512 if (tmp[0] == '\0') {
2513 /* : Stop the process if we found the end of the string (two consequent NULs) */
2514 if (tmp[1] == '\0') {
2518 /* : Replace delimiting NUL with our delimiter characted */
2519 tmp[0] = PATHS_DELIMITER;
2526 /* Do nothing, it is good as is */
2530 return_value = NULL;
2534 return_value = ValueData;
2538 if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
2539 if (return_value == NULL) {
2540 if (ValueData != NULL) sasl_FREE(ValueData);
2543 return (return_value);