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