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_BINDINGS: {
1212 struct sasl_channel_bindings *cb = (struct sasl_channel_bindings *)value;
1214 if (conn->type == SASL_CONN_SERVER) {
1217 ((sasl_server_conn_t *)conn)->sparams->chanbindingstype = cb->type;
1218 ((sasl_server_conn_t *)conn)->sparams->chanbindingscrit = cb->critical;
1219 ((sasl_server_conn_t *)conn)->sparams->chanbindingsdata = cb->data;
1220 ((sasl_server_conn_t *)conn)->sparams->chanbindingslen = cb->len;
1222 ((sasl_client_conn_t *)conn)->cparams->chanbindingstype = cb->type;
1223 ((sasl_client_conn_t *)conn)->cparams->chanbindingsdata = cb->data;
1224 ((sasl_client_conn_t *)conn)->cparams->chanbindingslen = cb->len;
1229 sasl_seterror(conn, 0, "Unknown parameter type");
1230 result = SASL_BADPARAM;
1233 RETURN(conn, result);
1236 /* this is apparently no longer a user function */
1237 static int sasl_usererr(int saslerr)
1239 /* Hide the difference in a username failure and a password failure */
1240 if (saslerr == SASL_NOUSER)
1241 return SASL_BADAUTH;
1243 /* otherwise return the error given; no transform necessary */
1247 const char *sasl_errstring(int saslerr,
1248 const char *langlist __attribute__((unused)),
1249 const char **outlang)
1251 if (outlang) *outlang="en-us";
1255 case SASL_CONTINUE: return "another step is needed in authentication";
1256 case SASL_OK: return "successful result";
1257 case SASL_FAIL: return "generic failure";
1258 case SASL_NOMEM: return "no memory available";
1259 case SASL_BUFOVER: return "overflowed buffer";
1260 case SASL_NOMECH: return "no mechanism available";
1261 case SASL_BADPROT: return "bad protocol / cancel";
1262 case SASL_NOTDONE: return "can't request info until later in exchange";
1263 case SASL_BADPARAM: return "invalid parameter supplied";
1264 case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
1265 case SASL_BADMAC: return "integrity check failed";
1266 case SASL_NOTINIT: return "SASL library not initialized";
1267 /* -- client only codes -- */
1268 case SASL_INTERACT: return "needs user interaction";
1269 case SASL_BADSERV: return "server failed mutual authentication step";
1270 case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
1271 /* -- server only codes -- */
1272 case SASL_BADAUTH: return "authentication failure";
1273 case SASL_NOAUTHZ: return "authorization failure";
1274 case SASL_TOOWEAK: return "mechanism too weak for this user";
1275 case SASL_ENCRYPT: return "encryption needed to use mechanism";
1276 case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
1277 case SASL_EXPIRED: return "passphrase expired, has to be reset";
1278 case SASL_DISABLED: return "account disabled";
1279 case SASL_NOUSER: return "user not found";
1280 case SASL_BADVERS: return "version mismatch with plug-in";
1281 case SASL_UNAVAIL: return "remote authentication server unavailable";
1282 case SASL_NOVERIFY: return "user exists, but no verifier for user";
1283 case SASL_PWLOCK: return "passphrase locked";
1284 case SASL_NOCHANGE: return "requested change was not needed";
1285 case SASL_WEAKPASS: return "passphrase is too weak for security policy";
1286 case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
1288 default: return "undefined error!";
1293 /* Return the sanitized error detail about the last error that occured for
1295 const char *sasl_errdetail(sasl_conn_t *conn)
1301 if(!conn) return NULL;
1303 errstr = sasl_errstring(conn->error_code, NULL, NULL);
1304 snprintf(leader,128,"SASL(%d): %s: ",
1305 sasl_usererr(conn->error_code), errstr);
1307 need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
1308 _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1310 snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
1312 return conn->errdetail_buf;
1316 /* Note that this needs the global callbacks, so if you don't give getcallbacks
1317 * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
1318 * have client and server at the same time */
1319 static int _sasl_global_getopt(void *context,
1320 const char *plugin_name,
1322 const char ** result,
1325 const sasl_global_callbacks_t * global_callbacks;
1326 const sasl_callback_t *callback;
1328 global_callbacks = (const sasl_global_callbacks_t *) context;
1330 if (global_callbacks && global_callbacks->callbacks) {
1331 for (callback = global_callbacks->callbacks;
1332 callback->id != SASL_CB_LIST_END;
1334 if (callback->id == SASL_CB_GETOPT) {
1335 if (!callback->proc) return SASL_FAIL;
1336 if (((sasl_getopt_t *)(callback->proc))(callback->context,
1347 /* look it up in our configuration file */
1348 *result = sasl_config_getstring(option, NULL);
1349 if (*result != NULL) {
1350 if (len) { *len = (unsigned) strlen(*result); }
1358 _sasl_conn_getopt(void *context,
1359 const char *plugin_name,
1361 const char ** result,
1365 const sasl_callback_t *callback;
1368 return SASL_BADPARAM;
1370 conn = (sasl_conn_t *) context;
1372 if (conn->callbacks)
1373 for (callback = conn->callbacks;
1374 callback->id != SASL_CB_LIST_END;
1376 if (callback->id == SASL_CB_GETOPT
1377 && (((sasl_getopt_t *)(callback->proc))(callback->context,
1385 /* If we made it here, we didn't find an appropriate callback
1386 * in the connection's callback list, or the callback we did
1387 * find didn't return SASL_OK. So we attempt to use the
1388 * global callback for this connection... */
1389 return _sasl_global_getopt((void *)conn->global_callbacks,
1397 /* this is the default logging */
1398 static int _sasl_syslog(void *context,
1400 const char *message)
1402 int syslog_priority;
1403 sasl_server_conn_t *sconn;
1406 if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
1407 sconn = (sasl_server_conn_t *)context;
1408 if (sconn->sparams->log_level < priority)
1413 /* set syslog priority */
1419 syslog_priority = LOG_ERR;
1422 syslog_priority = LOG_WARNING;
1426 syslog_priority = LOG_NOTICE;
1429 case SASL_LOG_TRACE:
1430 case SASL_LOG_DEBUG:
1432 syslog_priority = LOG_DEBUG;
1436 /* do the syslog call. Do not need to call openlog? */
1437 syslog(syslog_priority | LOG_AUTH, "%s", message);
1441 #endif /* HAVE_SYSLOG */
1444 _sasl_getsimple(void *context,
1446 const char ** result,
1452 if (! context || ! result) return SASL_BADPARAM;
1454 conn = (sasl_conn_t *)context;
1457 case SASL_CB_AUTHNAME:
1458 userid = getenv("USER");
1459 if (userid != NULL) {
1461 if (len) *len = strlen(userid);
1464 userid = getenv("USERNAME");
1465 if (userid != NULL) {
1467 if (len) *len = strlen(userid);
1471 /* for win32, try using the GetUserName standard call */
1475 static char sender[128];
1478 rval = GetUserName(sender, &i);
1479 if ( rval) { /* got a userid */
1481 if (len) *len = strlen(sender);
1488 return SASL_BADPARAM;
1493 _sasl_getpath(void *context __attribute__((unused)),
1494 const char ** path_dest)
1502 return SASL_BADPARAM;
1505 /* Only calculate the path once. */
1506 if (default_plugin_path == NULL) {
1509 /* NB: On Windows platforms this value is always allocated */
1510 default_plugin_path = _sasl_get_default_win_path(context,
1511 SASL_PLUGIN_PATH_ATTR,
1514 /* NB: On Unix platforms this value is never allocated */
1515 path = _sasl_get_default_unix_path(context,
1519 res = _sasl_strdup(path, &default_plugin_path, NULL);
1523 if (res == SASL_OK) {
1524 *path_dest = default_plugin_path;
1531 _sasl_getpath_simple(void *context __attribute__((unused)),
1535 return SASL_BADPARAM;
1538 if (default_plugin_path == NULL) {
1542 *path = default_plugin_path;
1548 _sasl_getconfpath(void *context __attribute__((unused)),
1557 return SASL_BADPARAM;
1560 /* Only calculate the path once. */
1561 if (default_conf_path == NULL) {
1564 /* NB: On Windows platforms this value is always allocated */
1565 default_conf_path = _sasl_get_default_win_path(context,
1566 SASL_CONF_PATH_ATTR,
1569 /* NB: On Unix platforms this value is never allocated */
1570 path = _sasl_get_default_unix_path(context,
1571 SASL_CONF_PATH_ENV_VAR,
1574 res = _sasl_strdup(path, &default_conf_path, NULL);
1578 if (res == SASL_OK) {
1579 *path_dest = default_conf_path;
1586 _sasl_getconfpath_simple(void *context __attribute__((unused)),
1590 return SASL_BADPARAM;
1593 if (default_conf_path == NULL) {
1597 *path = default_conf_path;
1603 _sasl_verifyfile(void *context __attribute__((unused)),
1604 char *file __attribute__((unused)),
1605 int type __attribute__((unused)))
1613 _sasl_proxy_policy(sasl_conn_t *conn,
1614 void *context __attribute__((unused)),
1615 const char *requested_user, unsigned rlen,
1616 const char *auth_identity, unsigned alen,
1617 const char *def_realm __attribute__((unused)),
1618 unsigned urlen __attribute__((unused)),
1619 struct propctx *propctx __attribute__((unused)))
1622 return SASL_BADPARAM;
1624 if (!requested_user || *requested_user == '\0')
1627 if (!auth_identity || !requested_user || rlen != alen ||
1628 (memcmp(auth_identity, requested_user, rlen) != 0)) {
1629 sasl_seterror(conn, 0,
1630 "Requested identity not authenticated identity");
1631 RETURN(conn, SASL_BADAUTH);
1637 int _sasl_getcallback(sasl_conn_t * conn,
1638 unsigned long callbackid,
1642 const sasl_callback_t *callback;
1644 if (!pproc || !pcontext)
1647 /* Some callbacks are always provided by the library */
1648 switch (callbackid) {
1649 case SASL_CB_LIST_END:
1650 /* Nothing ever gets to provide this */
1651 INTERROR(conn, SASL_FAIL);
1652 case SASL_CB_GETOPT:
1654 *pproc = &_sasl_conn_getopt;
1657 *pproc = &_sasl_global_getopt;
1663 /* If it's not always provided by the library, see if there's
1664 * a version provided by the application for this connection... */
1665 if (conn && conn->callbacks) {
1666 for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
1668 if (callback->id == callbackid) {
1669 *pproc = callback->proc;
1670 *pcontext = callback->context;
1671 if (callback->proc) {
1674 return SASL_INTERACT;
1680 /* And, if not for this connection, see if there's one
1681 * for all {server,client} connections... */
1682 if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
1683 for (callback = conn->global_callbacks->callbacks;
1684 callback->id != SASL_CB_LIST_END;
1686 if (callback->id == callbackid) {
1687 *pproc = callback->proc;
1688 *pcontext = callback->context;
1689 if (callback->proc) {
1692 return SASL_INTERACT;
1698 /* Otherwise, see if the library provides a default callback. */
1699 switch (callbackid) {
1702 *pproc = (int (*)()) &_sasl_syslog;
1705 #endif /* HAVE_SYSLOG */
1706 case SASL_CB_GETPATH:
1707 *pproc = default_getpath_cb.proc;
1708 *pcontext = default_getpath_cb.context;
1710 case SASL_CB_GETCONFPATH:
1711 *pproc = default_getconfpath_cb.proc;
1712 *pcontext = default_getconfpath_cb.context;
1714 case SASL_CB_AUTHNAME:
1715 *pproc = (int (*)()) &_sasl_getsimple;
1718 case SASL_CB_VERIFYFILE:
1719 *pproc = & _sasl_verifyfile;
1722 case SASL_CB_PROXY_POLICY:
1723 *pproc = (int (*)()) &_sasl_proxy_policy;
1728 /* Unable to find a callback... */
1731 sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
1732 RETURN(conn,SASL_FAIL);
1737 * This function is typically called from a plugin.
1738 * It creates a string from the formatting and varargs given
1739 * and calls the logging callback (syslog by default)
1741 * %m will parse the value in the next argument as an errno string
1742 * %z will parse the next argument as a SASL error code.
1746 _sasl_log (sasl_conn_t *conn,
1751 char *out=(char *) sasl_ALLOC(250);
1752 size_t alloclen=100; /* current allocated length */
1753 size_t outlen=0; /* current length of output buffer */
1755 size_t pos=0; /* current position in format string */
1763 va_list ap; /* varargs thing */
1768 formatlen = strlen(fmt);
1770 /* See if we have a logging callback... */
1771 result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1772 if (result == SASL_OK && ! log_cb)
1774 if (result != SASL_OK) goto done;
1776 va_start(ap, fmt); /* start varargs */
1778 while(pos<formatlen)
1780 if (fmt[pos]!='%') /* regular character */
1782 result = _buf_alloc(&out, &alloclen, outlen+1);
1783 if (result != SASL_OK) goto done;
1784 out[outlen]=fmt[pos];
1788 } else { /* formating thing */
1800 case 's': /* need to handle this */
1801 cval = va_arg(ap, char *); /* get the next arg */
1802 result = _sasl_add_string(&out, &alloclen,
1805 if (result != SASL_OK) /* add the string */
1811 case '%': /* double % output the '%' character */
1812 result = _buf_alloc(&out,&alloclen,outlen+1);
1813 if (result != SASL_OK)
1821 case 'm': /* insert the errno string */
1822 result = _sasl_add_string(&out, &alloclen, &outlen,
1823 strerror(va_arg(ap, int)));
1824 if (result != SASL_OK)
1830 case 'z': /* insert the sasl error string */
1831 result = _sasl_add_string(&out, &alloclen, &outlen,
1832 (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
1833 if (result != SASL_OK)
1840 frmt[frmtpos++]=fmt[pos];
1842 tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
1845 /* now add the character */
1846 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1847 if (result != SASL_OK)
1855 frmt[frmtpos++]=fmt[pos];
1857 ival = va_arg(ap, int); /* get the next arg */
1859 snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
1860 /* now add the string */
1861 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1862 if (result != SASL_OK)
1872 frmt[frmtpos++]=fmt[pos];
1874 uval = va_arg(ap, unsigned int); /* get the next arg */
1876 snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
1877 /* now add the string */
1878 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1879 if (result != SASL_OK)
1886 frmt[frmtpos++]=fmt[pos]; /* add to the formating */
1900 result = _buf_alloc(&out, &alloclen, outlen+1);
1901 if (result != SASL_OK) goto done;
1906 /* send log message */
1907 result = log_cb(log_ctx, level, out);
1910 if(out) sasl_FREE(out);
1915 /* Allocate and Init a sasl_utils_t structure */
1917 _sasl_alloc_utils(sasl_conn_t *conn,
1918 sasl_global_callbacks_t *global_callbacks)
1920 sasl_utils_t *utils;
1921 /* set util functions - need to do rest*/
1922 utils=sasl_ALLOC(sizeof(sasl_utils_t));
1928 sasl_randcreate(&utils->rpool);
1931 utils->getopt = &_sasl_conn_getopt;
1932 utils->getopt_context = conn;
1934 utils->getopt = &_sasl_global_getopt;
1935 utils->getopt_context = global_callbacks;
1938 utils->malloc=_sasl_allocation_utils.malloc;
1939 utils->calloc=_sasl_allocation_utils.calloc;
1940 utils->realloc=_sasl_allocation_utils.realloc;
1941 utils->free=_sasl_allocation_utils.free;
1943 utils->mutex_alloc = _sasl_mutex_utils.alloc;
1944 utils->mutex_lock = _sasl_mutex_utils.lock;
1945 utils->mutex_unlock = _sasl_mutex_utils.unlock;
1946 utils->mutex_free = _sasl_mutex_utils.free;
1948 utils->MD5Init = &_sasl_MD5Init;
1949 utils->MD5Update= &_sasl_MD5Update;
1950 utils->MD5Final = &_sasl_MD5Final;
1951 utils->hmac_md5 = &_sasl_hmac_md5;
1952 utils->hmac_md5_init = &_sasl_hmac_md5_init;
1953 utils->hmac_md5_final = &_sasl_hmac_md5_final;
1954 utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
1955 utils->hmac_md5_import = &_sasl_hmac_md5_import;
1956 utils->mkchal = &sasl_mkchal;
1957 utils->utf8verify = &sasl_utf8verify;
1958 utils->rand=&sasl_rand;
1959 utils->churn=&sasl_churn;
1960 utils->checkpass=NULL;
1962 utils->encode64=&sasl_encode64;
1963 utils->decode64=&sasl_decode64;
1965 utils->erasebuffer=&sasl_erasebuffer;
1967 utils->getprop=&sasl_getprop;
1968 utils->setprop=&sasl_setprop;
1970 utils->getcallback=&_sasl_getcallback;
1972 utils->log=&_sasl_log;
1974 utils->seterror=&sasl_seterror;
1977 /* Aux Property Utilities */
1978 utils->prop_new=&prop_new;
1979 utils->prop_dup=&prop_dup;
1980 utils->prop_request=&prop_request;
1981 utils->prop_get=&prop_get;
1982 utils->prop_getnames=&prop_getnames;
1983 utils->prop_clear=&prop_clear;
1984 utils->prop_dispose=&prop_dispose;
1985 utils->prop_format=&prop_format;
1986 utils->prop_set=&prop_set;
1987 utils->prop_setvals=&prop_setvals;
1988 utils->prop_erase=&prop_erase;
1989 utils->auxprop_store=&sasl_auxprop_store;
1993 utils->spare_fptr = NULL;
1994 utils->spare_fptr1 = utils->spare_fptr2 = NULL;
2000 _sasl_free_utils(const sasl_utils_t ** utils)
2002 sasl_utils_t *nonconst;
2004 if(!utils) return SASL_BADPARAM;
2005 if(!*utils) return SASL_OK;
2007 /* I wish we could avoid this cast, it's pretty gratuitous but it
2008 * does make life easier to have it const everywhere else. */
2009 nonconst = (sasl_utils_t *)(*utils);
2011 sasl_randfree(&(nonconst->rpool));
2012 sasl_FREE(nonconst);
2018 int sasl_idle(sasl_conn_t *conn)
2021 if (_sasl_server_idle_hook
2022 && _sasl_server_idle_hook(NULL))
2024 if (_sasl_client_idle_hook
2025 && _sasl_client_idle_hook(NULL))
2030 if (conn->idle_hook)
2031 return conn->idle_hook(conn);
2036 static const sasl_callback_t *
2037 _sasl_find_callback_by_type (const sasl_callback_t *callbacks,
2041 while (callbacks->id != SASL_CB_LIST_END) {
2042 if (callbacks->id == id) {
2052 const sasl_callback_t *
2053 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
2055 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
2056 if (callbacks != NULL) {
2059 return &default_getpath_cb;
2063 const sasl_callback_t *
2064 _sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
2066 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
2067 if (callbacks != NULL) {
2070 return &default_getconfpath_cb;
2074 const sasl_callback_t *
2075 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
2077 static const sasl_callback_t default_verifyfile_cb = {
2083 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
2084 if (callbacks != NULL) {
2087 return &default_verifyfile_cb;
2091 /* Basically a conditional call to realloc(), if we need more */
2092 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
2095 *rwbuf = sasl_ALLOC((unsigned)newlen);
2096 if (*rwbuf == NULL) {
2101 } else if(*rwbuf && *curlen < newlen) {
2102 size_t needed = 2*(*curlen);
2104 while(needed < newlen)
2107 /* WARN - We will leak the old buffer on failure */
2108 *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
2110 if (*rwbuf == NULL) {
2120 /* for the mac os x cfm glue: this lets the calling function
2121 get pointers to the error buffer without having to touch the sasl_conn_t struct */
2122 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
2124 *bufhdl = &conn->error_buf;
2125 *lenhdl = &conn->error_buf_len;
2128 /* convert an iovec to a single buffer */
2129 int _iovec_to_buf(const struct iovec *vec,
2130 unsigned numiov, buffer_info_t **output)
2137 if (!vec || !output) return SASL_BADPARAM;
2140 *output = sasl_ALLOC(sizeof(buffer_info_t));
2141 if (!*output) return SASL_NOMEM;
2142 memset(*output,0,sizeof(buffer_info_t));
2148 for (i = 0; i < numiov; i++) {
2149 out->curlen += vec[i].iov_len;
2152 ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
2154 if (ret != SASL_OK) return SASL_NOMEM;
2156 memset(out->data, 0, out->reallen);
2159 for (i = 0; i < numiov; i++) {
2160 memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2161 pos += vec[i].iov_len;
2167 /* This code might be useful in the future, but it isn't now, so.... */
2169 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
2170 char *out, unsigned outlen) {
2171 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
2174 if(!addr || !out) return SASL_BADPARAM;
2176 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
2177 #ifdef NI_WITHSCOPEID
2178 if (addr->sa_family == AF_INET6)
2179 niflags |= NI_WITHSCOPEID;
2181 if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
2183 return SASL_BADPARAM;
2185 if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
2186 return SASL_BUFOVER;
2188 snprintf(out, outlen, "%s;%s", hbuf, pbuf);
2194 int _sasl_ipfromstring(const char *addr,
2195 struct sockaddr *out, socklen_t outlen)
2198 struct addrinfo hints, *ai = NULL;
2199 char hbuf[NI_MAXHOST];
2201 /* A NULL out pointer just implies we don't do a copy, just verify it */
2203 if(!addr) return SASL_BADPARAM;
2205 /* Parse the address */
2206 for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2207 if (i >= NI_MAXHOST)
2208 return SASL_BADPARAM;
2215 /* XXX: Do we need this check? */
2216 for (j = i; addr[j] != '\0'; j++)
2217 if (!isdigit((int)(addr[j])))
2218 return SASL_BADPARAM;
2220 memset(&hints, 0, sizeof(hints));
2221 hints.ai_family = PF_UNSPEC;
2222 hints.ai_socktype = SOCK_STREAM;
2223 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2224 if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
2225 return SASL_BADPARAM;
2228 if (outlen < (socklen_t)ai->ai_addrlen) {
2230 return SASL_BUFOVER;
2232 memcpy(out, ai->ai_addr, ai->ai_addrlen);
2240 int _sasl_build_mechlist(void)
2243 sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
2244 sasl_string_list_t *p, *q, **last, *p_next;
2246 clist = _sasl_client_mechs();
2247 slist = _sasl_server_mechs();
2254 /* append slist to clist, and set olist to clist */
2255 for(p = slist; p; p = p_next) {
2260 for(q = clist; q; q = q->next) {
2261 if(!strcmp(q->d, p->d)) {
2262 /* They match, set the flag */
2281 printf ("no olist");
2285 for (p = olist; p; p = p->next) count++;
2287 if(global_mech_list) {
2288 sasl_FREE(global_mech_list);
2289 global_mech_list = NULL;
2292 global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
2293 if(!global_mech_list) return SASL_NOMEM;
2295 memset(global_mech_list, 0, (count + 1) * sizeof(char *));
2298 for (p = olist; p; p = p_next) {
2301 global_mech_list[count++] = (char *) p->d;
2309 const char ** sasl_global_listmech(void)
2311 return (const char **)global_mech_list;
2314 int sasl_listmech(sasl_conn_t *conn,
2319 const char **result,
2324 return SASL_BADPARAM;
2325 } else if(conn->type == SASL_CONN_SERVER) {
2326 RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
2327 result, plen, pcount));
2328 } else if (conn->type == SASL_CONN_CLIENT) {
2329 RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
2330 result, plen, pcount));
2339 _sasl_get_default_unix_path(void *context __attribute__((unused)),
2340 char * env_var_name,
2341 char * default_value)
2345 /* Honor external variable only in a safe environment */
2346 if (getuid() == geteuid() && getgid() == getegid()) {
2347 path = getenv(env_var_name);
2350 path = default_value;
2357 /* Return NULL on failure */
2359 _sasl_get_default_win_path(void *context __attribute__((unused)),
2360 char * reg_attr_name,
2361 char * default_value)
2363 /* Open registry entry, and find all registered SASL libraries.
2365 * Registry location:
2367 * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
2371 * "SearchPath" - value: PATH like (';' delimited) list
2372 * of directories where to search for plugins
2373 * The list may contain references to environment
2374 * variables (e.g. %PATH%).
2379 DWORD ValueType; /* value type */
2380 DWORD cbData; /* value size */
2381 BYTE * ValueData; /* value */
2382 DWORD cbExpandedData; /* "expanded" value size */
2383 BYTE * ExpandedValueData; /* "expanded" value */
2384 char * return_value; /* function return value */
2387 /* Initialization */
2388 ExpandedValueData = NULL;
2390 return_value = NULL;
2392 /* Open the registry */
2393 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2399 if (ret != ERROR_SUCCESS) {
2400 /* no registry entry */
2401 (void) _sasl_strdup (default_value, &return_value, NULL);
2402 return return_value;
2405 /* figure out value type and required buffer size */
2406 /* the size will include space for terminating NUL if required */
2407 RegQueryValueEx (hKey,
2409 NULL, /* reserved */
2414 /* Only accept string related types */
2415 if (ValueType != REG_EXPAND_SZ &&
2416 ValueType != REG_MULTI_SZ &&
2417 ValueType != REG_SZ) {
2418 return_value = NULL;
2422 /* Any high water mark? */
2423 ValueData = sasl_ALLOC(cbData);
2424 if (ValueData == NULL) {
2425 return_value = NULL;
2429 RegQueryValueEx (hKey,
2431 NULL, /* reserved */
2436 switch (ValueType) {
2438 /* : A random starting guess */
2439 cbExpandedData = cbData + 1024;
2440 ExpandedValueData = sasl_ALLOC(cbExpandedData);
2441 if (ExpandedValueData == NULL) {
2442 return_value = NULL;
2446 cbExpandedData = ExpandEnvironmentStrings(
2451 if (cbExpandedData == 0) {
2452 /* : GetLastError() contains the reason for failure */
2453 return_value = NULL;
2457 /* : Must retry expansion with the bigger buffer */
2458 if (cbExpandedData > cbData + 1024) {
2459 /* : Memory leak here if can't realloc */
2460 ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
2461 if (ExpandedValueData == NULL) {
2462 return_value = NULL;
2466 cbExpandedData = ExpandEnvironmentStrings(
2471 /* : This should not happen */
2472 if (cbExpandedData == 0) {
2473 /* : GetLastError() contains the reason for failure */
2474 return_value = NULL;
2479 sasl_FREE(ValueData);
2480 ValueData = ExpandedValueData;
2481 /* : This is to prevent automatical freeing of this block on cleanup */
2482 ExpandedValueData = NULL;
2489 /* : We shouldn't overflow here, as the buffer is guarantied
2490 : to contain at least two consequent NULs */
2492 if (tmp[0] == '\0') {
2493 /* : Stop the process if we found the end of the string (two consequent NULs) */
2494 if (tmp[1] == '\0') {
2498 /* : Replace delimiting NUL with our delimiter characted */
2499 tmp[0] = PATHS_DELIMITER;
2506 /* Do nothing, it is good as is */
2510 return_value = NULL;
2514 return_value = ValueData;
2518 if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
2519 if (return_value == NULL) {
2520 if (ValueData != NULL) sasl_FREE(ValueData);
2523 return (return_value);