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";
1279 case SASL_BADBINDING: return "channel binding failure";
1281 default: return "undefined error!";
1286 /* Return the sanitized error detail about the last error that occured for
1288 const char *sasl_errdetail(sasl_conn_t *conn)
1294 if(!conn) return NULL;
1296 errstr = sasl_errstring(conn->error_code, NULL, NULL);
1297 snprintf(leader,128,"SASL(%d): %s: ",
1298 sasl_usererr(conn->error_code), errstr);
1300 need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
1301 _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
1303 snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
1305 return conn->errdetail_buf;
1309 /* Note that this needs the global callbacks, so if you don't give getcallbacks
1310 * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
1311 * have client and server at the same time */
1312 static int _sasl_global_getopt(void *context,
1313 const char *plugin_name,
1315 const char ** result,
1318 const sasl_global_callbacks_t * global_callbacks;
1319 const sasl_callback_t *callback;
1321 global_callbacks = (const sasl_global_callbacks_t *) context;
1323 if (global_callbacks && global_callbacks->callbacks) {
1324 for (callback = global_callbacks->callbacks;
1325 callback->id != SASL_CB_LIST_END;
1327 if (callback->id == SASL_CB_GETOPT) {
1328 if (!callback->proc) return SASL_FAIL;
1329 if (((sasl_getopt_t *)(callback->proc))(callback->context,
1340 /* look it up in our configuration file */
1341 *result = sasl_config_getstring(option, NULL);
1342 if (*result != NULL) {
1343 if (len) { *len = (unsigned) strlen(*result); }
1351 _sasl_conn_getopt(void *context,
1352 const char *plugin_name,
1354 const char ** result,
1358 const sasl_callback_t *callback;
1361 return SASL_BADPARAM;
1363 conn = (sasl_conn_t *) context;
1365 if (conn->callbacks)
1366 for (callback = conn->callbacks;
1367 callback->id != SASL_CB_LIST_END;
1369 if (callback->id == SASL_CB_GETOPT
1370 && (((sasl_getopt_t *)(callback->proc))(callback->context,
1378 /* If we made it here, we didn't find an appropriate callback
1379 * in the connection's callback list, or the callback we did
1380 * find didn't return SASL_OK. So we attempt to use the
1381 * global callback for this connection... */
1382 return _sasl_global_getopt((void *)conn->global_callbacks,
1390 /* this is the default logging */
1391 static int _sasl_syslog(void *context,
1393 const char *message)
1395 int syslog_priority;
1396 sasl_server_conn_t *sconn;
1399 if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
1400 sconn = (sasl_server_conn_t *)context;
1401 if (sconn->sparams->log_level < priority)
1406 /* set syslog priority */
1412 syslog_priority = LOG_ERR;
1415 syslog_priority = LOG_WARNING;
1419 syslog_priority = LOG_NOTICE;
1422 case SASL_LOG_TRACE:
1423 case SASL_LOG_DEBUG:
1425 syslog_priority = LOG_DEBUG;
1429 /* do the syslog call. Do not need to call openlog? */
1430 syslog(syslog_priority | LOG_AUTH, "%s", message);
1434 #endif /* HAVE_SYSLOG */
1437 _sasl_getsimple(void *context,
1439 const char ** result,
1445 if (! context || ! result) return SASL_BADPARAM;
1447 conn = (sasl_conn_t *)context;
1450 case SASL_CB_AUTHNAME:
1451 userid = getenv("USER");
1452 if (userid != NULL) {
1454 if (len) *len = strlen(userid);
1457 userid = getenv("USERNAME");
1458 if (userid != NULL) {
1460 if (len) *len = strlen(userid);
1464 /* for win32, try using the GetUserName standard call */
1468 static char sender[128];
1471 rval = GetUserName(sender, &i);
1472 if ( rval) { /* got a userid */
1474 if (len) *len = strlen(sender);
1481 return SASL_BADPARAM;
1486 _sasl_getpath(void *context __attribute__((unused)),
1487 const char ** path_dest)
1495 return SASL_BADPARAM;
1498 /* Only calculate the path once. */
1499 if (default_plugin_path == NULL) {
1502 /* NB: On Windows platforms this value is always allocated */
1503 default_plugin_path = _sasl_get_default_win_path(context,
1504 SASL_PLUGIN_PATH_ATTR,
1507 /* NB: On Unix platforms this value is never allocated */
1508 path = _sasl_get_default_unix_path(context,
1512 res = _sasl_strdup(path, &default_plugin_path, NULL);
1516 if (res == SASL_OK) {
1517 *path_dest = default_plugin_path;
1524 _sasl_getpath_simple(void *context __attribute__((unused)),
1528 return SASL_BADPARAM;
1531 if (default_plugin_path == NULL) {
1535 *path = default_plugin_path;
1541 _sasl_getconfpath(void *context __attribute__((unused)),
1550 return SASL_BADPARAM;
1553 /* Only calculate the path once. */
1554 if (default_conf_path == NULL) {
1557 /* NB: On Windows platforms this value is always allocated */
1558 default_conf_path = _sasl_get_default_win_path(context,
1559 SASL_CONF_PATH_ATTR,
1562 /* NB: On Unix platforms this value is never allocated */
1563 path = _sasl_get_default_unix_path(context,
1564 SASL_CONF_PATH_ENV_VAR,
1567 res = _sasl_strdup(path, &default_conf_path, NULL);
1571 if (res == SASL_OK) {
1572 *path_dest = default_conf_path;
1579 _sasl_getconfpath_simple(void *context __attribute__((unused)),
1583 return SASL_BADPARAM;
1586 if (default_conf_path == NULL) {
1590 *path = default_conf_path;
1596 _sasl_verifyfile(void *context __attribute__((unused)),
1597 char *file __attribute__((unused)),
1598 int type __attribute__((unused)))
1606 _sasl_proxy_policy(sasl_conn_t *conn,
1607 void *context __attribute__((unused)),
1608 const char *requested_user, unsigned rlen,
1609 const char *auth_identity, unsigned alen,
1610 const char *def_realm __attribute__((unused)),
1611 unsigned urlen __attribute__((unused)),
1612 struct propctx *propctx __attribute__((unused)))
1615 return SASL_BADPARAM;
1617 if (!requested_user || *requested_user == '\0')
1620 if (!auth_identity || !requested_user || rlen != alen ||
1621 (memcmp(auth_identity, requested_user, rlen) != 0)) {
1622 sasl_seterror(conn, 0,
1623 "Requested identity not authenticated identity");
1624 RETURN(conn, SASL_BADAUTH);
1630 int _sasl_getcallback(sasl_conn_t * conn,
1631 unsigned long callbackid,
1635 const sasl_callback_t *callback;
1637 if (!pproc || !pcontext)
1640 /* Some callbacks are always provided by the library */
1641 switch (callbackid) {
1642 case SASL_CB_LIST_END:
1643 /* Nothing ever gets to provide this */
1644 INTERROR(conn, SASL_FAIL);
1645 case SASL_CB_GETOPT:
1647 *pproc = &_sasl_conn_getopt;
1650 *pproc = &_sasl_global_getopt;
1656 /* If it's not always provided by the library, see if there's
1657 * a version provided by the application for this connection... */
1658 if (conn && conn->callbacks) {
1659 for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
1661 if (callback->id == callbackid) {
1662 *pproc = callback->proc;
1663 *pcontext = callback->context;
1664 if (callback->proc) {
1667 return SASL_INTERACT;
1673 /* And, if not for this connection, see if there's one
1674 * for all {server,client} connections... */
1675 if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
1676 for (callback = conn->global_callbacks->callbacks;
1677 callback->id != SASL_CB_LIST_END;
1679 if (callback->id == callbackid) {
1680 *pproc = callback->proc;
1681 *pcontext = callback->context;
1682 if (callback->proc) {
1685 return SASL_INTERACT;
1691 /* Otherwise, see if the library provides a default callback. */
1692 switch (callbackid) {
1695 *pproc = (int (*)()) &_sasl_syslog;
1698 #endif /* HAVE_SYSLOG */
1699 case SASL_CB_GETPATH:
1700 *pproc = default_getpath_cb.proc;
1701 *pcontext = default_getpath_cb.context;
1703 case SASL_CB_GETCONFPATH:
1704 *pproc = default_getconfpath_cb.proc;
1705 *pcontext = default_getconfpath_cb.context;
1707 case SASL_CB_AUTHNAME:
1708 *pproc = (int (*)()) &_sasl_getsimple;
1711 case SASL_CB_VERIFYFILE:
1712 *pproc = & _sasl_verifyfile;
1715 case SASL_CB_PROXY_POLICY:
1716 *pproc = (int (*)()) &_sasl_proxy_policy;
1721 /* Unable to find a callback... */
1724 sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
1725 RETURN(conn,SASL_FAIL);
1730 * This function is typically called from a plugin.
1731 * It creates a string from the formatting and varargs given
1732 * and calls the logging callback (syslog by default)
1734 * %m will parse the value in the next argument as an errno string
1735 * %z will parse the next argument as a SASL error code.
1739 _sasl_log (sasl_conn_t *conn,
1744 char *out=(char *) sasl_ALLOC(250);
1745 size_t alloclen=100; /* current allocated length */
1746 size_t outlen=0; /* current length of output buffer */
1748 size_t pos=0; /* current position in format string */
1756 va_list ap; /* varargs thing */
1761 formatlen = strlen(fmt);
1763 /* See if we have a logging callback... */
1764 result = _sasl_getcallback(conn, SASL_CB_LOG, &log_cb, &log_ctx);
1765 if (result == SASL_OK && ! log_cb)
1767 if (result != SASL_OK) goto done;
1769 va_start(ap, fmt); /* start varargs */
1771 while(pos<formatlen)
1773 if (fmt[pos]!='%') /* regular character */
1775 result = _buf_alloc(&out, &alloclen, outlen+1);
1776 if (result != SASL_OK) goto done;
1777 out[outlen]=fmt[pos];
1781 } else { /* formating thing */
1793 case 's': /* need to handle this */
1794 cval = va_arg(ap, char *); /* get the next arg */
1795 result = _sasl_add_string(&out, &alloclen,
1798 if (result != SASL_OK) /* add the string */
1804 case '%': /* double % output the '%' character */
1805 result = _buf_alloc(&out,&alloclen,outlen+1);
1806 if (result != SASL_OK)
1814 case 'm': /* insert the errno string */
1815 result = _sasl_add_string(&out, &alloclen, &outlen,
1816 strerror(va_arg(ap, int)));
1817 if (result != SASL_OK)
1823 case 'z': /* insert the sasl error string */
1824 result = _sasl_add_string(&out, &alloclen, &outlen,
1825 (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
1826 if (result != SASL_OK)
1833 frmt[frmtpos++]=fmt[pos];
1835 tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
1838 /* now add the character */
1839 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1840 if (result != SASL_OK)
1848 frmt[frmtpos++]=fmt[pos];
1850 ival = va_arg(ap, int); /* get the next arg */
1852 snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
1853 /* now add the string */
1854 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1855 if (result != SASL_OK)
1865 frmt[frmtpos++]=fmt[pos];
1867 uval = va_arg(ap, unsigned int); /* get the next arg */
1869 snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
1870 /* now add the string */
1871 result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
1872 if (result != SASL_OK)
1879 frmt[frmtpos++]=fmt[pos]; /* add to the formating */
1893 result = _buf_alloc(&out, &alloclen, outlen+1);
1894 if (result != SASL_OK) goto done;
1899 /* send log message */
1900 result = log_cb(log_ctx, level, out);
1903 if(out) sasl_FREE(out);
1908 /* Allocate and Init a sasl_utils_t structure */
1910 _sasl_alloc_utils(sasl_conn_t *conn,
1911 sasl_global_callbacks_t *global_callbacks)
1913 sasl_utils_t *utils;
1914 /* set util functions - need to do rest*/
1915 utils=sasl_ALLOC(sizeof(sasl_utils_t));
1921 sasl_randcreate(&utils->rpool);
1924 utils->getopt = &_sasl_conn_getopt;
1925 utils->getopt_context = conn;
1927 utils->getopt = &_sasl_global_getopt;
1928 utils->getopt_context = global_callbacks;
1931 utils->malloc=_sasl_allocation_utils.malloc;
1932 utils->calloc=_sasl_allocation_utils.calloc;
1933 utils->realloc=_sasl_allocation_utils.realloc;
1934 utils->free=_sasl_allocation_utils.free;
1936 utils->mutex_alloc = _sasl_mutex_utils.alloc;
1937 utils->mutex_lock = _sasl_mutex_utils.lock;
1938 utils->mutex_unlock = _sasl_mutex_utils.unlock;
1939 utils->mutex_free = _sasl_mutex_utils.free;
1941 utils->MD5Init = &_sasl_MD5Init;
1942 utils->MD5Update= &_sasl_MD5Update;
1943 utils->MD5Final = &_sasl_MD5Final;
1944 utils->hmac_md5 = &_sasl_hmac_md5;
1945 utils->hmac_md5_init = &_sasl_hmac_md5_init;
1946 utils->hmac_md5_final = &_sasl_hmac_md5_final;
1947 utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
1948 utils->hmac_md5_import = &_sasl_hmac_md5_import;
1949 utils->mkchal = &sasl_mkchal;
1950 utils->utf8verify = &sasl_utf8verify;
1951 utils->rand=&sasl_rand;
1952 utils->churn=&sasl_churn;
1953 utils->checkpass=NULL;
1955 utils->encode64=&sasl_encode64;
1956 utils->decode64=&sasl_decode64;
1958 utils->erasebuffer=&sasl_erasebuffer;
1960 utils->getprop=&sasl_getprop;
1961 utils->setprop=&sasl_setprop;
1963 utils->getcallback=&_sasl_getcallback;
1965 utils->log=&_sasl_log;
1967 utils->seterror=&sasl_seterror;
1970 /* Aux Property Utilities */
1971 utils->prop_new=&prop_new;
1972 utils->prop_dup=&prop_dup;
1973 utils->prop_request=&prop_request;
1974 utils->prop_get=&prop_get;
1975 utils->prop_getnames=&prop_getnames;
1976 utils->prop_clear=&prop_clear;
1977 utils->prop_dispose=&prop_dispose;
1978 utils->prop_format=&prop_format;
1979 utils->prop_set=&prop_set;
1980 utils->prop_setvals=&prop_setvals;
1981 utils->prop_erase=&prop_erase;
1982 utils->auxprop_store=&sasl_auxprop_store;
1986 utils->spare_fptr = NULL;
1987 utils->spare_fptr1 = utils->spare_fptr2 = NULL;
1993 _sasl_free_utils(const sasl_utils_t ** utils)
1995 sasl_utils_t *nonconst;
1997 if(!utils) return SASL_BADPARAM;
1998 if(!*utils) return SASL_OK;
2000 /* I wish we could avoid this cast, it's pretty gratuitous but it
2001 * does make life easier to have it const everywhere else. */
2002 nonconst = (sasl_utils_t *)(*utils);
2004 sasl_randfree(&(nonconst->rpool));
2005 sasl_FREE(nonconst);
2011 int sasl_idle(sasl_conn_t *conn)
2014 if (_sasl_server_idle_hook
2015 && _sasl_server_idle_hook(NULL))
2017 if (_sasl_client_idle_hook
2018 && _sasl_client_idle_hook(NULL))
2023 if (conn->idle_hook)
2024 return conn->idle_hook(conn);
2029 static const sasl_callback_t *
2030 _sasl_find_callback_by_type (const sasl_callback_t *callbacks,
2034 while (callbacks->id != SASL_CB_LIST_END) {
2035 if (callbacks->id == id) {
2045 const sasl_callback_t *
2046 _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
2048 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
2049 if (callbacks != NULL) {
2052 return &default_getpath_cb;
2056 const sasl_callback_t *
2057 _sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
2059 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
2060 if (callbacks != NULL) {
2063 return &default_getconfpath_cb;
2067 const sasl_callback_t *
2068 _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
2070 static const sasl_callback_t default_verifyfile_cb = {
2076 callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
2077 if (callbacks != NULL) {
2080 return &default_verifyfile_cb;
2084 /* Basically a conditional call to realloc(), if we need more */
2085 int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
2088 *rwbuf = sasl_ALLOC((unsigned)newlen);
2089 if (*rwbuf == NULL) {
2094 } else if(*rwbuf && *curlen < newlen) {
2095 size_t needed = 2*(*curlen);
2097 while(needed < newlen)
2100 /* WARN - We will leak the old buffer on failure */
2101 *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
2103 if (*rwbuf == NULL) {
2113 /* for the mac os x cfm glue: this lets the calling function
2114 get pointers to the error buffer without having to touch the sasl_conn_t struct */
2115 void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
2117 *bufhdl = &conn->error_buf;
2118 *lenhdl = &conn->error_buf_len;
2121 /* convert an iovec to a single buffer */
2122 int _iovec_to_buf(const struct iovec *vec,
2123 unsigned numiov, buffer_info_t **output)
2130 if (!vec || !output) return SASL_BADPARAM;
2133 *output = sasl_ALLOC(sizeof(buffer_info_t));
2134 if (!*output) return SASL_NOMEM;
2135 memset(*output,0,sizeof(buffer_info_t));
2141 for (i = 0; i < numiov; i++) {
2142 out->curlen += vec[i].iov_len;
2145 ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
2147 if (ret != SASL_OK) return SASL_NOMEM;
2149 memset(out->data, 0, out->reallen);
2152 for (i = 0; i < numiov; i++) {
2153 memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2154 pos += vec[i].iov_len;
2160 /* This code might be useful in the future, but it isn't now, so.... */
2162 int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
2163 char *out, unsigned outlen) {
2164 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
2167 if(!addr || !out) return SASL_BADPARAM;
2169 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
2170 #ifdef NI_WITHSCOPEID
2171 if (addr->sa_family == AF_INET6)
2172 niflags |= NI_WITHSCOPEID;
2174 if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
2176 return SASL_BADPARAM;
2178 if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
2179 return SASL_BUFOVER;
2181 snprintf(out, outlen, "%s;%s", hbuf, pbuf);
2187 int _sasl_ipfromstring(const char *addr,
2188 struct sockaddr *out, socklen_t outlen)
2191 struct addrinfo hints, *ai = NULL;
2192 char hbuf[NI_MAXHOST];
2194 /* A NULL out pointer just implies we don't do a copy, just verify it */
2196 if(!addr) return SASL_BADPARAM;
2198 /* Parse the address */
2199 for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2200 if (i >= NI_MAXHOST)
2201 return SASL_BADPARAM;
2208 /* XXX: Do we need this check? */
2209 for (j = i; addr[j] != '\0'; j++)
2210 if (!isdigit((int)(addr[j])))
2211 return SASL_BADPARAM;
2213 memset(&hints, 0, sizeof(hints));
2214 hints.ai_family = PF_UNSPEC;
2215 hints.ai_socktype = SOCK_STREAM;
2216 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2217 if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
2218 return SASL_BADPARAM;
2221 if (outlen < (socklen_t)ai->ai_addrlen) {
2223 return SASL_BUFOVER;
2225 memcpy(out, ai->ai_addr, ai->ai_addrlen);
2233 int _sasl_build_mechlist(void)
2236 sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
2237 sasl_string_list_t *p, *q, **last, *p_next;
2239 clist = _sasl_client_mechs();
2240 slist = _sasl_server_mechs();
2247 /* append slist to clist, and set olist to clist */
2248 for(p = slist; p; p = p_next) {
2253 for(q = clist; q; q = q->next) {
2254 if(!strcmp(q->d, p->d)) {
2255 /* They match, set the flag */
2274 printf ("no olist");
2278 for (p = olist; p; p = p->next) count++;
2280 if(global_mech_list) {
2281 sasl_FREE(global_mech_list);
2282 global_mech_list = NULL;
2285 global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
2286 if(!global_mech_list) return SASL_NOMEM;
2288 memset(global_mech_list, 0, (count + 1) * sizeof(char *));
2291 for (p = olist; p; p = p_next) {
2294 global_mech_list[count++] = (char *) p->d;
2302 const char ** sasl_global_listmech(void)
2304 return (const char **)global_mech_list;
2307 int sasl_listmech(sasl_conn_t *conn,
2312 const char **result,
2317 return SASL_BADPARAM;
2318 } else if(conn->type == SASL_CONN_SERVER) {
2319 RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
2320 result, plen, pcount));
2321 } else if (conn->type == SASL_CONN_CLIENT) {
2322 RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
2323 result, plen, pcount));
2329 int _sasl_is_equal_mech(const char *req_mech,
2330 const char *plug_mech,
2331 size_t req_mech_len,
2336 if (req_mech_len > 5 &&
2337 strcasecmp(&req_mech[req_mech_len - 5], "-PLUS") == 0) {
2338 n = req_mech_len - 5;
2345 return (strncasecmp(req_mech, plug_mech, n) == 0);
2350 _sasl_get_default_unix_path(void *context __attribute__((unused)),
2351 char * env_var_name,
2352 char * default_value)
2356 /* Honor external variable only in a safe environment */
2357 if (getuid() == geteuid() && getgid() == getegid()) {
2358 path = getenv(env_var_name);
2361 path = default_value;
2368 /* Return NULL on failure */
2370 _sasl_get_default_win_path(void *context __attribute__((unused)),
2371 char * reg_attr_name,
2372 char * default_value)
2374 /* Open registry entry, and find all registered SASL libraries.
2376 * Registry location:
2378 * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
2382 * "SearchPath" - value: PATH like (';' delimited) list
2383 * of directories where to search for plugins
2384 * The list may contain references to environment
2385 * variables (e.g. %PATH%).
2390 DWORD ValueType; /* value type */
2391 DWORD cbData; /* value size */
2392 BYTE * ValueData; /* value */
2393 DWORD cbExpandedData; /* "expanded" value size */
2394 BYTE * ExpandedValueData; /* "expanded" value */
2395 char * return_value; /* function return value */
2398 /* Initialization */
2399 ExpandedValueData = NULL;
2401 return_value = NULL;
2403 /* Open the registry */
2404 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2410 if (ret != ERROR_SUCCESS) {
2411 /* no registry entry */
2412 (void) _sasl_strdup (default_value, &return_value, NULL);
2413 return return_value;
2416 /* figure out value type and required buffer size */
2417 /* the size will include space for terminating NUL if required */
2418 RegQueryValueEx (hKey,
2420 NULL, /* reserved */
2425 /* Only accept string related types */
2426 if (ValueType != REG_EXPAND_SZ &&
2427 ValueType != REG_MULTI_SZ &&
2428 ValueType != REG_SZ) {
2429 return_value = NULL;
2433 /* Any high water mark? */
2434 ValueData = sasl_ALLOC(cbData);
2435 if (ValueData == NULL) {
2436 return_value = NULL;
2440 RegQueryValueEx (hKey,
2442 NULL, /* reserved */
2447 switch (ValueType) {
2449 /* : A random starting guess */
2450 cbExpandedData = cbData + 1024;
2451 ExpandedValueData = sasl_ALLOC(cbExpandedData);
2452 if (ExpandedValueData == NULL) {
2453 return_value = NULL;
2457 cbExpandedData = ExpandEnvironmentStrings(
2462 if (cbExpandedData == 0) {
2463 /* : GetLastError() contains the reason for failure */
2464 return_value = NULL;
2468 /* : Must retry expansion with the bigger buffer */
2469 if (cbExpandedData > cbData + 1024) {
2470 /* : Memory leak here if can't realloc */
2471 ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
2472 if (ExpandedValueData == NULL) {
2473 return_value = NULL;
2477 cbExpandedData = ExpandEnvironmentStrings(
2482 /* : This should not happen */
2483 if (cbExpandedData == 0) {
2484 /* : GetLastError() contains the reason for failure */
2485 return_value = NULL;
2490 sasl_FREE(ValueData);
2491 ValueData = ExpandedValueData;
2492 /* : This is to prevent automatical freeing of this block on cleanup */
2493 ExpandedValueData = NULL;
2500 /* : We shouldn't overflow here, as the buffer is guarantied
2501 : to contain at least two consequent NULs */
2503 if (tmp[0] == '\0') {
2504 /* : Stop the process if we found the end of the string (two consequent NULs) */
2505 if (tmp[1] == '\0') {
2509 /* : Replace delimiting NUL with our delimiter characted */
2510 tmp[0] = PATHS_DELIMITER;
2517 /* Do nothing, it is good as is */
2521 return_value = NULL;
2525 return_value = ValueData;
2529 if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
2530 if (return_value == NULL) {
2531 if (ValueData != NULL) sasl_FREE(ValueData);
2534 return (return_value);