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 const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
1214 if (conn->type == SASL_CONN_SERVER)
1215 ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
1217 ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
1221 sasl_seterror(conn, 0, "Unknown parameter type");
1222 result = SASL_BADPARAM;
1225 RETURN(conn, result);
1228 /* this is apparently no longer a user function */
1229 static int sasl_usererr(int saslerr)
1231 /* Hide the difference in a username failure and a password failure */
1232 if (saslerr == SASL_NOUSER)
1233 return SASL_BADAUTH;
1235 /* otherwise return the error given; no transform necessary */
1239 const char *sasl_errstring(int saslerr,
1240 const char *langlist __attribute__((unused)),
1241 const char **outlang)
1243 if (outlang) *outlang="en-us";
1247 case SASL_CONTINUE: return "another step is needed in authentication";
1248 case SASL_OK: return "successful result";
1249 case SASL_FAIL: return "generic failure";
1250 case SASL_NOMEM: return "no memory available";
1251 case SASL_BUFOVER: return "overflowed buffer";
1252 case SASL_NOMECH: return "no mechanism available";
1253 case SASL_BADPROT: return "bad protocol / cancel";
1254 case SASL_NOTDONE: return "can't request info until later in exchange";
1255 case SASL_BADPARAM: return "invalid parameter supplied";
1256 case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
1257 case SASL_BADMAC: return "integrity check failed";
1258 case SASL_NOTINIT: return "SASL library not initialized";
1259 /* -- client only codes -- */
1260 case SASL_INTERACT: return "needs user interaction";
1261 case SASL_BADSERV: return "server failed mutual authentication step";
1262 case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
1263 /* -- server only codes -- */
1264 case SASL_BADAUTH: return "authentication failure";
1265 case SASL_NOAUTHZ: return "authorization failure";
1266 case SASL_TOOWEAK: return "mechanism too weak for this user";
1267 case SASL_ENCRYPT: return "encryption needed to use mechanism";
1268 case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
1269 case SASL_EXPIRED: return "passphrase expired, has to be reset";
1270 case SASL_DISABLED: return "account disabled";
1271 case SASL_NOUSER: return "user not found";
1272 case SASL_BADVERS: return "version mismatch with plug-in";
1273 case SASL_UNAVAIL: return "remote authentication server unavailable";
1274 case SASL_NOVERIFY: return "user exists, but no verifier for user";
1275 case SASL_PWLOCK: return "passphrase locked";
1276 case SASL_NOCHANGE: return "requested change was not needed";
1277 case SASL_WEAKPASS: return "passphrase is too weak for security policy";
1278 case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
1280 default: return "undefined error!";
1285 /* Return the sanitized error detail about the last error that occured for
1287 const char *sasl_errdetail(sasl_conn_t *conn)
1293 if(!conn) return NULL;
1295 errstr = sasl_errstring(conn->error_code, NULL, NULL);
1296 snprintf(leader,128,"SASL(%d): %s: ",
1297 sasl_usererr(conn->error_code), errstr);
1299 need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
1300 _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1302 snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
1304 return conn->errdetail_buf;
1308 /* Note that this needs the global callbacks, so if you don't give getcallbacks
1309 * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
1310 * have client and server at the same time */
1311 static int _sasl_global_getopt(void *context,
1312 const char *plugin_name,
1314 const char ** result,
1317 const sasl_global_callbacks_t * global_callbacks;
1318 const sasl_callback_t *callback;
1320 global_callbacks = (const sasl_global_callbacks_t *) context;
1322 if (global_callbacks && global_callbacks->callbacks) {
1323 for (callback = global_callbacks->callbacks;
1324 callback->id != SASL_CB_LIST_END;
1326 if (callback->id == SASL_CB_GETOPT) {
1327 if (!callback->proc) return SASL_FAIL;
1328 if (((sasl_getopt_t *)(callback->proc))(callback->context,
1339 /* look it up in our configuration file */
1340 *result = sasl_config_getstring(option, NULL);
1341 if (*result != NULL) {
1342 if (len) { *len = (unsigned) strlen(*result); }
1350 _sasl_conn_getopt(void *context,
1351 const char *plugin_name,
1353 const char ** result,
1357 const sasl_callback_t *callback;
1360 return SASL_BADPARAM;
1362 conn = (sasl_conn_t *) context;
1364 if (conn->callbacks)
1365 for (callback = conn->callbacks;
1366 callback->id != SASL_CB_LIST_END;
1368 if (callback->id == SASL_CB_GETOPT
1369 && (((sasl_getopt_t *)(callback->proc))(callback->context,
1377 /* If we made it here, we didn't find an appropriate callback
1378 * in the connection's callback list, or the callback we did
1379 * find didn't return SASL_OK. So we attempt to use the
1380 * global callback for this connection... */
1381 return _sasl_global_getopt((void *)conn->global_callbacks,
1389 /* this is the default logging */
1390 static int _sasl_syslog(void *context,
1392 const char *message)
1394 int syslog_priority;
1395 sasl_server_conn_t *sconn;
1398 if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
1399 sconn = (sasl_server_conn_t *)context;
1400 if (sconn->sparams->log_level < priority)
1405 /* set syslog priority */
1411 syslog_priority = LOG_ERR;
1414 syslog_priority = LOG_WARNING;
1418 syslog_priority = LOG_NOTICE;
1421 case SASL_LOG_TRACE:
1422 case SASL_LOG_DEBUG:
1424 syslog_priority = LOG_DEBUG;
1428 /* do the syslog call. Do not need to call openlog? */
1429 syslog(syslog_priority | LOG_AUTH, "%s", message);
1433 #endif /* HAVE_SYSLOG */
1436 _sasl_getsimple(void *context,
1438 const char ** result,
1444 if (! context || ! result) return SASL_BADPARAM;
1446 conn = (sasl_conn_t *)context;
1449 case SASL_CB_AUTHNAME:
1450 userid = getenv("USER");
1451 if (userid != NULL) {
1453 if (len) *len = strlen(userid);
1456 userid = getenv("USERNAME");
1457 if (userid != NULL) {
1459 if (len) *len = strlen(userid);
1463 /* for win32, try using the GetUserName standard call */
1467 static char sender[128];
1470 rval = GetUserName(sender, &i);
1471 if ( rval) { /* got a userid */
1473 if (len) *len = strlen(sender);
1480 return SASL_BADPARAM;
1485 _sasl_getpath(void *context __attribute__((unused)),
1486 const char ** path_dest)
1494 return SASL_BADPARAM;
1497 /* Only calculate the path once. */
1498 if (default_plugin_path == NULL) {
1501 /* NB: On Windows platforms this value is always allocated */
1502 default_plugin_path = _sasl_get_default_win_path(context,
1503 SASL_PLUGIN_PATH_ATTR,
1506 /* NB: On Unix platforms this value is never allocated */
1507 path = _sasl_get_default_unix_path(context,
1511 res = _sasl_strdup(path, &default_plugin_path, NULL);
1515 if (res == SASL_OK) {
1516 *path_dest = default_plugin_path;
1523 _sasl_getpath_simple(void *context __attribute__((unused)),
1527 return SASL_BADPARAM;
1530 if (default_plugin_path == NULL) {
1534 *path = default_plugin_path;
1540 _sasl_getconfpath(void *context __attribute__((unused)),
1549 return SASL_BADPARAM;
1552 /* Only calculate the path once. */
1553 if (default_conf_path == NULL) {
1556 /* NB: On Windows platforms this value is always allocated */
1557 default_conf_path = _sasl_get_default_win_path(context,
1558 SASL_CONF_PATH_ATTR,
1561 /* NB: On Unix platforms this value is never allocated */
1562 path = _sasl_get_default_unix_path(context,
1563 SASL_CONF_PATH_ENV_VAR,
1566 res = _sasl_strdup(path, &default_conf_path, NULL);
1570 if (res == SASL_OK) {
1571 *path_dest = default_conf_path;
1578 _sasl_getconfpath_simple(void *context __attribute__((unused)),
1582 return SASL_BADPARAM;
1585 if (default_conf_path == NULL) {
1589 *path = default_conf_path;
1595 _sasl_verifyfile(void *context __attribute__((unused)),
1596 char *file __attribute__((unused)),
1597 int type __attribute__((unused)))
1605 _sasl_proxy_policy(sasl_conn_t *conn,
1606 void *context __attribute__((unused)),
1607 const char *requested_user, unsigned rlen,
1608 const char *auth_identity, unsigned alen,
1609 const char *def_realm __attribute__((unused)),
1610 unsigned urlen __attribute__((unused)),
1611 struct propctx *propctx __attribute__((unused)))
1614 return SASL_BADPARAM;
1616 if (!requested_user || *requested_user == '\0')
1619 if (!auth_identity || !requested_user || rlen != alen ||
1620 (memcmp(auth_identity, requested_user, rlen) != 0)) {
1621 sasl_seterror(conn, 0,
1622 "Requested identity not authenticated identity");
1623 RETURN(conn, SASL_BADAUTH);
1629 int _sasl_getcallback(sasl_conn_t * conn,
1630 unsigned long callbackid,
1634 const sasl_callback_t *callback;
1636 if (!pproc || !pcontext)
1639 /* Some callbacks are always provided by the library */
1640 switch (callbackid) {
1641 case SASL_CB_LIST_END:
1642 /* Nothing ever gets to provide this */
1643 INTERROR(conn, SASL_FAIL);
1644 case SASL_CB_GETOPT:
1646 *pproc = &_sasl_conn_getopt;
1649 *pproc = &_sasl_global_getopt;
1655 /* If it's not always provided by the library, see if there's
1656 * a version provided by the application for this connection... */
1657 if (conn && conn->callbacks) {
1658 for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
1660 if (callback->id == callbackid) {
1661 *pproc = callback->proc;
1662 *pcontext = callback->context;
1663 if (callback->proc) {
1666 return SASL_INTERACT;
1672 /* And, if not for this connection, see if there's one
1673 * for all {server,client} connections... */
1674 if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
1675 for (callback = conn->global_callbacks->callbacks;
1676 callback->id != SASL_CB_LIST_END;
1678 if (callback->id == callbackid) {
1679 *pproc = callback->proc;
1680 *pcontext = callback->context;
1681 if (callback->proc) {
1684 return SASL_INTERACT;
1690 /* Otherwise, see if the library provides a default callback. */
1691 switch (callbackid) {
1694 *pproc = (int (*)()) &_sasl_syslog;
1697 #endif /* HAVE_SYSLOG */
1698 case SASL_CB_GETPATH:
1699 *pproc = default_getpath_cb.proc;
1700 *pcontext = default_getpath_cb.context;
1702 case SASL_CB_GETCONFPATH:
1703 *pproc = default_getconfpath_cb.proc;
1704 *pcontext = default_getconfpath_cb.context;
1706 case SASL_CB_AUTHNAME:
1707 *pproc = (int (*)()) &_sasl_getsimple;
1710 case SASL_CB_VERIFYFILE:
1711 *pproc = & _sasl_verifyfile;
1714 case SASL_CB_PROXY_POLICY:
1715 *pproc = (int (*)()) &_sasl_proxy_policy;
1720 /* Unable to find a callback... */
1723 sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
1724 RETURN(conn,SASL_FAIL);
1729 * This function is typically called from a plugin.
1730 * It creates a string from the formatting and varargs given
1731 * and calls the logging callback (syslog by default)
1733 * %m will parse the value in the next argument as an errno string
1734 * %z will parse the next argument as a SASL error code.
1738 _sasl_log (sasl_conn_t *conn,
1743 char *out=(char *) sasl_ALLOC(250);
1744 size_t alloclen=100; /* current allocated length */
1745 size_t outlen=0; /* current length of output buffer */
1747 size_t pos=0; /* current position in format string */
1755 va_list ap; /* varargs thing */
1760 formatlen = strlen(fmt);
1762 /* See if we have a logging callback... */
1763 result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1764 if (result == SASL_OK && ! log_cb)
1766 if (result != SASL_OK) goto done;
1768 va_start(ap, fmt); /* start varargs */
1770 while(pos<formatlen)
1772 if (fmt[pos]!='%') /* regular character */
1774 result = _buf_alloc(&out, &alloclen, outlen+1);
1775 if (result != SASL_OK) goto done;
1776 out[outlen]=fmt[pos];
1780 } else { /* formating thing */
1792 case 's': /* need to handle this */
1793 cval = va_arg(ap, char *); /* get the next arg */
1794 result = _sasl_add_string(&out, &alloclen,
1797 if (result != SASL_OK) /* add the string */
1803 case '%': /* double % output the '%' character */
1804 result = _buf_alloc(&out,&alloclen,outlen+1);
1805 if (result != SASL_OK)
1813 case 'm': /* insert the errno string */
1814 result = _sasl_add_string(&out, &alloclen, &outlen,
1815 strerror(va_arg(ap, int)));
1816 if (result != SASL_OK)
1822 case 'z': /* insert the sasl error string */
1823 result = _sasl_add_string(&out, &alloclen, &outlen,
1824 (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
1825 if (result != SASL_OK)
1832 frmt[frmtpos++]=fmt[pos];
1834 tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
1837 /* now add the character */
1838 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1839 if (result != SASL_OK)
1847 frmt[frmtpos++]=fmt[pos];
1849 ival = va_arg(ap, int); /* get the next arg */
1851 snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
1852 /* now add the string */
1853 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1854 if (result != SASL_OK)
1864 frmt[frmtpos++]=fmt[pos];
1866 uval = va_arg(ap, unsigned int); /* get the next arg */
1868 snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
1869 /* now add the string */
1870 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1871 if (result != SASL_OK)
1878 frmt[frmtpos++]=fmt[pos]; /* add to the formating */
1892 result = _buf_alloc(&out, &alloclen, outlen+1);
1893 if (result != SASL_OK) goto done;
1898 /* send log message */
1899 result = log_cb(log_ctx, level, out);
1902 if(out) sasl_FREE(out);
1907 /* Allocate and Init a sasl_utils_t structure */
1909 _sasl_alloc_utils(sasl_conn_t *conn,
1910 sasl_global_callbacks_t *global_callbacks)
1912 sasl_utils_t *utils;
1913 /* set util functions - need to do rest*/
1914 utils=sasl_ALLOC(sizeof(sasl_utils_t));
1920 sasl_randcreate(&utils->rpool);
1923 utils->getopt = &_sasl_conn_getopt;
1924 utils->getopt_context = conn;
1926 utils->getopt = &_sasl_global_getopt;
1927 utils->getopt_context = global_callbacks;
1930 utils->malloc=_sasl_allocation_utils.malloc;
1931 utils->calloc=_sasl_allocation_utils.calloc;
1932 utils->realloc=_sasl_allocation_utils.realloc;
1933 utils->free=_sasl_allocation_utils.free;
1935 utils->mutex_alloc = _sasl_mutex_utils.alloc;
1936 utils->mutex_lock = _sasl_mutex_utils.lock;
1937 utils->mutex_unlock = _sasl_mutex_utils.unlock;
1938 utils->mutex_free = _sasl_mutex_utils.free;
1940 utils->MD5Init = &_sasl_MD5Init;
1941 utils->MD5Update= &_sasl_MD5Update;
1942 utils->MD5Final = &_sasl_MD5Final;
1943 utils->hmac_md5 = &_sasl_hmac_md5;
1944 utils->hmac_md5_init = &_sasl_hmac_md5_init;
1945 utils->hmac_md5_final = &_sasl_hmac_md5_final;
1946 utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
1947 utils->hmac_md5_import = &_sasl_hmac_md5_import;
1948 utils->mkchal = &sasl_mkchal;
1949 utils->utf8verify = &sasl_utf8verify;
1950 utils->rand=&sasl_rand;
1951 utils->churn=&sasl_churn;
1952 utils->checkpass=NULL;
1954 utils->encode64=&sasl_encode64;
1955 utils->decode64=&sasl_decode64;
1957 utils->erasebuffer=&sasl_erasebuffer;
1959 utils->getprop=&sasl_getprop;
1960 utils->setprop=&sasl_setprop;
1962 utils->getcallback=&_sasl_getcallback;
1964 utils->log=&_sasl_log;
1966 utils->seterror=&sasl_seterror;
1969 /* Aux Property Utilities */
1970 utils->prop_new=&prop_new;
1971 utils->prop_dup=&prop_dup;
1972 utils->prop_request=&prop_request;
1973 utils->prop_get=&prop_get;
1974 utils->prop_getnames=&prop_getnames;
1975 utils->prop_clear=&prop_clear;
1976 utils->prop_dispose=&prop_dispose;
1977 utils->prop_format=&prop_format;
1978 utils->prop_set=&prop_set;
1979 utils->prop_setvals=&prop_setvals;
1980 utils->prop_erase=&prop_erase;
1981 utils->auxprop_store=&sasl_auxprop_store;
1985 utils->spare_fptr = NULL;
1986 utils->spare_fptr1 = utils->spare_fptr2 = NULL;
1992 _sasl_free_utils(const sasl_utils_t ** utils)
1994 sasl_utils_t *nonconst;
1996 if(!utils) return SASL_BADPARAM;
1997 if(!*utils) return SASL_OK;
1999 /* I wish we could avoid this cast, it's pretty gratuitous but it
2000 * does make life easier to have it const everywhere else. */
2001 nonconst = (sasl_utils_t *)(*utils);
2003 sasl_randfree(&(nonconst->rpool));
2004 sasl_FREE(nonconst);
2010 int sasl_idle(sasl_conn_t *conn)
2013 if (_sasl_server_idle_hook
2014 && _sasl_server_idle_hook(NULL))
2016 if (_sasl_client_idle_hook
2017 && _sasl_client_idle_hook(NULL))
2022 if (conn->idle_hook)
2023 return conn->idle_hook(conn);
2028 static const sasl_callback_t *
2029 _sasl_find_callback_by_type (const sasl_callback_t *callbacks,
2033 while (callbacks->id != SASL_CB_LIST_END) {
2034 if (callbacks->id == id) {
2044 const sasl_callback_t *
2045 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
2047 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
2048 if (callbacks != NULL) {
2051 return &default_getpath_cb;
2055 const sasl_callback_t *
2056 _sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
2058 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
2059 if (callbacks != NULL) {
2062 return &default_getconfpath_cb;
2066 const sasl_callback_t *
2067 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
2069 static const sasl_callback_t default_verifyfile_cb = {
2075 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
2076 if (callbacks != NULL) {
2079 return &default_verifyfile_cb;
2083 /* Basically a conditional call to realloc(), if we need more */
2084 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
2087 *rwbuf = sasl_ALLOC((unsigned)newlen);
2088 if (*rwbuf == NULL) {
2093 } else if(*rwbuf && *curlen < newlen) {
2094 size_t needed = 2*(*curlen);
2096 while(needed < newlen)
2099 /* WARN - We will leak the old buffer on failure */
2100 *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
2102 if (*rwbuf == NULL) {
2112 /* for the mac os x cfm glue: this lets the calling function
2113 get pointers to the error buffer without having to touch the sasl_conn_t struct */
2114 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
2116 *bufhdl = &conn->error_buf;
2117 *lenhdl = &conn->error_buf_len;
2120 /* convert an iovec to a single buffer */
2121 int _iovec_to_buf(const struct iovec *vec,
2122 unsigned numiov, buffer_info_t **output)
2129 if (!vec || !output) return SASL_BADPARAM;
2132 *output = sasl_ALLOC(sizeof(buffer_info_t));
2133 if (!*output) return SASL_NOMEM;
2134 memset(*output,0,sizeof(buffer_info_t));
2140 for (i = 0; i < numiov; i++) {
2141 out->curlen += vec[i].iov_len;
2144 ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
2146 if (ret != SASL_OK) return SASL_NOMEM;
2148 memset(out->data, 0, out->reallen);
2151 for (i = 0; i < numiov; i++) {
2152 memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2153 pos += vec[i].iov_len;
2159 /* This code might be useful in the future, but it isn't now, so.... */
2161 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
2162 char *out, unsigned outlen) {
2163 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
2166 if(!addr || !out) return SASL_BADPARAM;
2168 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
2169 #ifdef NI_WITHSCOPEID
2170 if (addr->sa_family == AF_INET6)
2171 niflags |= NI_WITHSCOPEID;
2173 if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
2175 return SASL_BADPARAM;
2177 if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
2178 return SASL_BUFOVER;
2180 snprintf(out, outlen, "%s;%s", hbuf, pbuf);
2186 int _sasl_ipfromstring(const char *addr,
2187 struct sockaddr *out, socklen_t outlen)
2190 struct addrinfo hints, *ai = NULL;
2191 char hbuf[NI_MAXHOST];
2193 /* A NULL out pointer just implies we don't do a copy, just verify it */
2195 if(!addr) return SASL_BADPARAM;
2197 /* Parse the address */
2198 for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2199 if (i >= NI_MAXHOST)
2200 return SASL_BADPARAM;
2207 /* XXX: Do we need this check? */
2208 for (j = i; addr[j] != '\0'; j++)
2209 if (!isdigit((int)(addr[j])))
2210 return SASL_BADPARAM;
2212 memset(&hints, 0, sizeof(hints));
2213 hints.ai_family = PF_UNSPEC;
2214 hints.ai_socktype = SOCK_STREAM;
2215 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2216 if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
2217 return SASL_BADPARAM;
2220 if (outlen < (socklen_t)ai->ai_addrlen) {
2222 return SASL_BUFOVER;
2224 memcpy(out, ai->ai_addr, ai->ai_addrlen);
2232 int _sasl_build_mechlist(void)
2235 sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
2236 sasl_string_list_t *p, *q, **last, *p_next;
2238 clist = _sasl_client_mechs();
2239 slist = _sasl_server_mechs();
2246 /* append slist to clist, and set olist to clist */
2247 for(p = slist; p; p = p_next) {
2252 for(q = clist; q; q = q->next) {
2253 if(!strcmp(q->d, p->d)) {
2254 /* They match, set the flag */
2273 printf ("no olist");
2277 for (p = olist; p; p = p->next) count++;
2279 if(global_mech_list) {
2280 sasl_FREE(global_mech_list);
2281 global_mech_list = NULL;
2284 global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
2285 if(!global_mech_list) return SASL_NOMEM;
2287 memset(global_mech_list, 0, (count + 1) * sizeof(char *));
2290 for (p = olist; p; p = p_next) {
2293 global_mech_list[count++] = (char *) p->d;
2301 const char ** sasl_global_listmech(void)
2303 return (const char **)global_mech_list;
2306 int sasl_listmech(sasl_conn_t *conn,
2311 const char **result,
2316 return SASL_BADPARAM;
2317 } else if(conn->type == SASL_CONN_SERVER) {
2318 RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
2319 result, plen, pcount));
2320 } else if (conn->type == SASL_CONN_CLIENT) {
2321 RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
2322 result, plen, pcount));
2328 int _sasl_is_equal_mech(const char *req_mech,
2329 const char *plug_mech,
2332 size_t len = strlen(req_mech);
2336 strcasecmp(&req_mech[len - 5], "-PLUS") == 0) {
2344 return (strncasecmp(req_mech, plug_mech, n) == 0);
2349 _sasl_get_default_unix_path(void *context __attribute__((unused)),
2350 char * env_var_name,
2351 char * default_value)
2355 /* Honor external variable only in a safe environment */
2356 if (getuid() == geteuid() && getgid() == getegid()) {
2357 path = getenv(env_var_name);
2360 path = default_value;
2367 /* Return NULL on failure */
2369 _sasl_get_default_win_path(void *context __attribute__((unused)),
2370 char * reg_attr_name,
2371 char * default_value)
2373 /* Open registry entry, and find all registered SASL libraries.
2375 * Registry location:
2377 * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
2381 * "SearchPath" - value: PATH like (';' delimited) list
2382 * of directories where to search for plugins
2383 * The list may contain references to environment
2384 * variables (e.g. %PATH%).
2389 DWORD ValueType; /* value type */
2390 DWORD cbData; /* value size */
2391 BYTE * ValueData; /* value */
2392 DWORD cbExpandedData; /* "expanded" value size */
2393 BYTE * ExpandedValueData; /* "expanded" value */
2394 char * return_value; /* function return value */
2397 /* Initialization */
2398 ExpandedValueData = NULL;
2400 return_value = NULL;
2402 /* Open the registry */
2403 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2409 if (ret != ERROR_SUCCESS) {
2410 /* no registry entry */
2411 (void) _sasl_strdup (default_value, &return_value, NULL);
2412 return return_value;
2415 /* figure out value type and required buffer size */
2416 /* the size will include space for terminating NUL if required */
2417 RegQueryValueEx (hKey,
2419 NULL, /* reserved */
2424 /* Only accept string related types */
2425 if (ValueType != REG_EXPAND_SZ &&
2426 ValueType != REG_MULTI_SZ &&
2427 ValueType != REG_SZ) {
2428 return_value = NULL;
2432 /* Any high water mark? */
2433 ValueData = sasl_ALLOC(cbData);
2434 if (ValueData == NULL) {
2435 return_value = NULL;
2439 RegQueryValueEx (hKey,
2441 NULL, /* reserved */
2446 switch (ValueType) {
2448 /* : A random starting guess */
2449 cbExpandedData = cbData + 1024;
2450 ExpandedValueData = sasl_ALLOC(cbExpandedData);
2451 if (ExpandedValueData == NULL) {
2452 return_value = NULL;
2456 cbExpandedData = ExpandEnvironmentStrings(
2461 if (cbExpandedData == 0) {
2462 /* : GetLastError() contains the reason for failure */
2463 return_value = NULL;
2467 /* : Must retry expansion with the bigger buffer */
2468 if (cbExpandedData > cbData + 1024) {
2469 /* : Memory leak here if can't realloc */
2470 ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
2471 if (ExpandedValueData == NULL) {
2472 return_value = NULL;
2476 cbExpandedData = ExpandEnvironmentStrings(
2481 /* : This should not happen */
2482 if (cbExpandedData == 0) {
2483 /* : GetLastError() contains the reason for failure */
2484 return_value = NULL;
2489 sasl_FREE(ValueData);
2490 ValueData = ExpandedValueData;
2491 /* : This is to prevent automatical freeing of this block on cleanup */
2492 ExpandedValueData = NULL;
2499 /* : We shouldn't overflow here, as the buffer is guarantied
2500 : to contain at least two consequent NULs */
2502 if (tmp[0] == '\0') {
2503 /* : Stop the process if we found the end of the string (two consequent NULs) */
2504 if (tmp[1] == '\0') {
2508 /* : Replace delimiting NUL with our delimiter characted */
2509 tmp[0] = PATHS_DELIMITER;
2516 /* Do nothing, it is good as is */
2520 return_value = NULL;
2524 return_value = ValueData;
2528 if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
2529 if (return_value == NULL) {
2530 if (ValueData != NULL) sasl_FREE(ValueData);
2533 return (return_value);