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