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