1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* SASL server API implementation 7 * Rob Siemborski 8 * Tim Martin 9 * $Id: server.c,v 1.123 2003/04/16 19:36:01 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 /* local functions/structs don't start with sasl 52 */ 53 #include <config.h> 54 #include <errno.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <limits.h> 58 #ifndef macintosh 59 #include <sys/types.h> 60 #include <sys/stat.h> 61 #endif 62 #include <fcntl.h> 63 #include <string.h> 64 #include <ctype.h> 65 66 #include "sasl.h" 67 #include "saslint.h" 68 #include "saslplug.h" 69 #include "saslutil.h" 70 71 #ifndef _SUN_SDK_ 72 #ifdef sun 73 /* gotta define gethostname ourselves on suns */ 74 extern int gethostname(char *, int); 75 #endif 76 #endif /* !_SUN_SDK_ */ 77 78 #define DEFAULT_CHECKPASS_MECH "auxprop" 79 80 /* Contains functions: 81 * 82 * sasl_server_init 83 * sasl_server_new 84 * sasl_listmech 85 * sasl_server_start 86 * sasl_server_step 87 * sasl_checkpass 88 * sasl_checkapop 89 * sasl_user_exists 90 * sasl_setpass 91 */ 92 93 #ifdef _SUN_SDK_ 94 int _is_sasl_server_active(_sasl_global_context_t *gctx) 95 { 96 return gctx->sasl_server_active; 97 } 98 99 DEFINE_STATIC_MUTEX(init_server_mutex); 100 DEFINE_STATIC_MUTEX(server_active_mutex); 101 /* 102 * server_plug_mutex ensures only one server plugin is init'ed at a time 103 * If a plugin is loaded more than once, the glob_context may be overwritten 104 * which may lead to a memory leak. We keep glob_context with each mech 105 * to avoid this problem. 106 */ 107 DEFINE_STATIC_MUTEX(server_plug_mutex); 108 #else 109 /* if we've initialized the server sucessfully */ 110 static int _sasl_server_active = 0; 111 112 /* For access by other modules */ 113 int _is_sasl_server_active(void) { return _sasl_server_active; } 114 #endif /* _SUN_SDK_ */ 115 116 static int _sasl_checkpass(sasl_conn_t *conn, 117 const char *user, unsigned userlen, 118 const char *pass, unsigned passlen); 119 120 #ifndef _SUN_SDK_ 121 static mech_list_t *mechlist = NULL; /* global var which holds the list */ 122 123 static sasl_global_callbacks_t global_callbacks; 124 #endif /* !_SUN_SDK_ */ 125 126 /* set the password for a user 127 * conn -- SASL connection 128 * user -- user name 129 * pass -- plaintext password, may be NULL to remove user 130 * passlen -- length of password, 0 = strlen(pass) 131 * oldpass -- NULL will sometimes work 132 * oldpasslen -- length of password, 0 = strlen(oldpass) 133 * flags -- see flags below 134 * 135 * returns: 136 * SASL_NOCHANGE -- proper entry already exists 137 * SASL_NOMECH -- no authdb supports password setting as configured 138 * SASL_NOVERIFY -- user exists, but no settable password present 139 * SASL_DISABLED -- account disabled 140 * SASL_PWLOCK -- password locked 141 * SASL_WEAKPASS -- password too weak for security policy 142 * SASL_NOUSERPASS -- user-supplied passwords not permitted 143 * SASL_FAIL -- OS error 144 * SASL_BADPARAM -- password too long 145 * SASL_OK -- successful 146 */ 147 148 int sasl_setpass(sasl_conn_t *conn, 149 const char *user, 150 const char *pass, unsigned passlen, 151 const char *oldpass, 152 unsigned oldpasslen, 153 unsigned flags) 154 { 155 int result=SASL_OK, tmpresult; 156 sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; 157 sasl_server_userdb_setpass_t *setpass_cb = NULL; 158 void *context = NULL; 159 mechanism_t *m; 160 161 #ifdef _SUN_SDK_ 162 _sasl_global_context_t *gctx = 163 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 164 mech_list_t *mechlist = gctx == NULL ? NULL : gctx->mechlist; 165 166 if (!gctx->sasl_server_active || !mechlist) return SASL_NOTINIT; 167 #else 168 if (!_sasl_server_active || !mechlist) return SASL_NOTINIT; 169 #endif /* _SUN_SDK_ */ 170 171 /* check params */ 172 if (!conn) return SASL_BADPARAM; 173 if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn); 174 175 if ((!(flags & SASL_SET_DISABLE) && passlen == 0) 176 || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE))) 177 PARAMERROR(conn); 178 179 /* call userdb callback function */ 180 result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS, 181 &setpass_cb, &context); 182 if(result == SASL_OK && setpass_cb) { 183 tmpresult = setpass_cb(conn, context, user, pass, passlen, 184 s_conn->sparams->propctx, flags); 185 if(tmpresult != SASL_OK) { 186 _sasl_log(conn, SASL_LOG_ERR, 187 "setpass callback failed for %s: %z", 188 user, tmpresult); 189 } else { 190 _sasl_log(conn, SASL_LOG_NOTE, 191 "setpass callback succeeded for %s", user); 192 } 193 } else { 194 result = SASL_OK; 195 } 196 197 /* now we let the mechanisms set their secrets */ 198 for (m = mechlist->mech_list; m; m = m->next) { 199 if (!m->plug->setpass) { 200 /* can't set pass for this mech */ 201 continue; 202 } 203 #ifdef _SUN_SDK_ 204 tmpresult = m->plug->setpass(m->glob_context, 205 #else 206 tmpresult = m->plug->setpass(m->plug->glob_context, 207 #endif /* _SUN_SDK_ */ 208 ((sasl_server_conn_t *)conn)->sparams, 209 user, 210 pass, 211 passlen, 212 oldpass, oldpasslen, 213 flags); 214 if (tmpresult == SASL_OK) { 215 _sasl_log(conn, SASL_LOG_NOTE, 216 "%s: set secret for %s", m->plug->mech_name, user); 217 218 m->condition = SASL_OK; /* if we previously thought the 219 mechanism didn't have any user secrets 220 we now think it does */ 221 222 } else if (tmpresult == SASL_NOCHANGE) { 223 _sasl_log(conn, SASL_LOG_NOTE, 224 "%s: secret not changed for %s", m->plug->mech_name, user); 225 } else { 226 result = tmpresult; 227 _sasl_log(conn, SASL_LOG_ERR, 228 "%s: failed to set secret for %s: %z (%m)", 229 m->plug->mech_name, user, tmpresult, 230 #ifndef WIN32 231 errno 232 #else 233 GetLastError() 234 #endif 235 ); 236 } 237 } 238 239 RETURN(conn, result); 240 } 241 242 #ifdef _SUN_SDK_ 243 static void 244 server_dispose_mech_contexts(sasl_conn_t *pconn) 245 { 246 sasl_server_conn_t *s_conn= (sasl_server_conn_t *) pconn; 247 context_list_t *cur, *cur_next; 248 _sasl_global_context_t *gctx = pconn->gctx; 249 250 for(cur = s_conn->mech_contexts; cur; cur=cur_next) { 251 cur_next = cur->next; 252 if(cur->context) 253 cur->mech->plug->mech_dispose(cur->context, s_conn->sparams->utils); 254 sasl_FREE(cur); 255 } 256 s_conn->mech_contexts = NULL; 257 } 258 #endif /* _SUN_SDK_ */ 259 260 /* local mechanism which disposes of server */ 261 static void server_dispose(sasl_conn_t *pconn) 262 { 263 sasl_server_conn_t *s_conn= (sasl_server_conn_t *) pconn; 264 #ifdef _SUN_SDK_ 265 _sasl_global_context_t *gctx = pconn->gctx; 266 #else 267 context_list_t *cur, *cur_next; 268 #endif /* _SUN_SDK_ */ 269 270 if (s_conn->mech 271 && s_conn->mech->plug->mech_dispose) { 272 s_conn->mech->plug->mech_dispose(pconn->context, 273 s_conn->sparams->utils); 274 } 275 pconn->context = NULL; 276 277 #ifdef _SUN_SDK_ 278 server_dispose_mech_contexts(pconn); 279 #else 280 for(cur = s_conn->mech_contexts; cur; cur=cur_next) { 281 cur_next = cur->next; 282 if(cur->context) 283 cur->mech->plug->mech_dispose(cur->context, s_conn->sparams->utils); 284 sasl_FREE(cur); 285 } 286 s_conn->mech_contexts = NULL; 287 #endif /* _SUN_SDK_ */ 288 289 _sasl_free_utils(&s_conn->sparams->utils); 290 291 if (s_conn->sparams->propctx) 292 prop_dispose(&s_conn->sparams->propctx); 293 294 if (s_conn->user_realm) 295 sasl_FREE(s_conn->user_realm); 296 297 if (s_conn->sparams) 298 sasl_FREE(s_conn->sparams); 299 300 _sasl_conn_dispose(pconn); 301 } 302 303 #ifdef _SUN_SDK_ 304 static int init_mechlist(_sasl_global_context_t *gctx) 305 { 306 mech_list_t *mechlist = gctx->mechlist; 307 #else 308 static int init_mechlist(void) 309 { 310 #endif /* _SUN_SDK_ */ 311 sasl_utils_t *newutils = NULL; 312 313 mechlist->mutex = sasl_MUTEX_ALLOC(); 314 if(!mechlist->mutex) return SASL_FAIL; 315 316 /* set util functions - need to do rest */ 317 #ifdef _SUN_SDK_ 318 newutils = _sasl_alloc_utils(gctx, NULL, &gctx->server_global_callbacks); 319 #else 320 newutils = _sasl_alloc_utils(NULL, &global_callbacks); 321 #endif /* _SUN_SDK_ */ 322 if (newutils == NULL) 323 return SASL_NOMEM; 324 325 newutils->checkpass = &_sasl_checkpass; 326 327 mechlist->utils = newutils; 328 mechlist->mech_list=NULL; 329 mechlist->mech_length=0; 330 331 return SASL_OK; 332 } 333 334 #ifdef _SUN_SDK_ 335 static int load_mech(_sasl_global_context_t *gctx, const char *mechname) 336 { 337 sasl_getopt_t *getopt; 338 void *context; 339 const char *mlist = NULL; 340 const char *cp; 341 size_t len; 342 343 /* No sasl_conn_t was given to getcallback, so we provide the 344 * global callbacks structure */ 345 if (_sasl_getcallback(NULL, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) 346 (void)getopt(&gctx->server_global_callbacks, NULL, 347 "server_load_mech_list", &mlist, NULL); 348 349 if (mlist == NULL) 350 return (1); 351 352 len = strlen(mechname); 353 while (*mlist && isspace((int) *mlist)) mlist++; 354 355 while (*mlist) { 356 for (cp = mlist; *cp && !isspace((int) *cp); cp++); 357 if (((size_t) (cp - mlist) == len) && 358 !strncasecmp(mlist, mechname, len)) 359 break; 360 mlist = cp; 361 while (*mlist && isspace((int) *mlist)) mlist++; 362 } 363 return (*mlist != '\0'); 364 } 365 #endif /* _SUN_SDK_ */ 366 367 /* 368 * parameters: 369 * p - entry point 370 */ 371 int sasl_server_add_plugin(const char *plugname, 372 sasl_server_plug_init_t *p) 373 #ifdef _SUN_SDK_ 374 { 375 return (_sasl_server_add_plugin(_sasl_gbl_ctx(), plugname, p)); 376 } 377 378 int _sasl_server_add_plugin(void *ctx, 379 const char *plugname, 380 sasl_server_plug_init_t *p) 381 { 382 int nplug = 0; 383 int i; 384 mechanism_t *m; 385 _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx; 386 mech_list_t *mechlist = gctx->mechlist; 387 388 #ifdef _INTEGRATED_SOLARIS_ 389 int sun_reg; 390 #endif /* _INTEGRATED_SOLARIS_ */ 391 #else 392 { 393 #endif /* _SUN_SDK_ */ 394 int plugcount; 395 sasl_server_plug_t *pluglist; 396 mechanism_t *mech; 397 sasl_server_plug_init_t *entry_point; 398 int result; 399 int version; 400 int lupe; 401 402 if(!plugname || !p) return SASL_BADPARAM; 403 404 #ifdef _SUN_SDK_ 405 if (mechlist == NULL) return SASL_BADPARAM; 406 407 /* Check to see if this plugin has already been registered */ 408 m = mechlist->mech_list; 409 for (i = 0; i < mechlist->mech_length; i++) { 410 if (strcmp(plugname, m->plugname) == 0) 411 return SASL_OK; 412 m = m->next; 413 } 414 415 result = LOCK_MUTEX(&server_plug_mutex); 416 if (result != SASL_OK) 417 return result; 418 419 #endif /* _SUN_SDK_ */ 420 entry_point = (sasl_server_plug_init_t *)p; 421 422 /* call into the shared library asking for information about it */ 423 /* version is filled in with the version of the plugin */ 424 result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version, 425 &pluglist, &plugcount); 426 427 #ifdef _INTEGRATED_SOLARIS_ 428 sun_reg = _is_sun_reg(pluglist); 429 #endif /* _INTEGRATED_SOLARIS_ */ 430 431 #ifdef _SUN_SDK_ 432 if (result != SASL_OK) { 433 UNLOCK_MUTEX(&server_plug_mutex); 434 __sasl_log(gctx, gctx->server_global_callbacks.callbacks, 435 SASL_LOG_DEBUG, 436 "server add_plugin entry_point error %z", result); 437 #else 438 if ((result != SASL_OK) && (result != SASL_NOUSER)) { 439 _sasl_log(NULL, SASL_LOG_DEBUG, 440 "server add_plugin entry_point error %z\n", result); 441 #endif /* _SUN_SDK_ */ 442 return result; 443 } 444 445 /* Make sure plugin is using the same SASL version as us */ 446 if (version != SASL_SERVER_PLUG_VERSION) 447 { 448 #ifdef _SUN_SDK_ 449 UNLOCK_MUTEX(&server_plug_mutex); 450 __sasl_log(gctx, gctx->server_global_callbacks.callbacks, 451 SASL_LOG_ERR, "version mismatch on plugin"); 452 #else 453 _sasl_log(NULL, SASL_LOG_ERR, 454 "version mismatch on plugin"); 455 #endif /* _SUN_SDK_ */ 456 return SASL_BADVERS; 457 } 458 #ifdef _SUN_SDK_ 459 /* Check plugins to make sure mech_name is non-NULL */ 460 for (lupe=0;lupe < plugcount ;lupe++) { 461 if (pluglist[lupe].mech_name == NULL) 462 break; 463 } 464 if (lupe < plugcount) { 465 #ifdef _SUN_SDK_ 466 UNLOCK_MUTEX(&server_plug_mutex); 467 __sasl_log(gctx, gctx->server_global_callbacks.callbacks, 468 SASL_LOG_ERR, "invalid server plugin %s", plugname); 469 #else 470 _sasl_log(NULL, SASL_LOG_ERR, "invalid server plugin %s", plugname); 471 #endif /* _SUN_SDK_ */ 472 return SASL_BADPROT; 473 } 474 #endif /* _SUN_SDK_ */ 475 476 for (lupe=0;lupe < plugcount ;lupe++) 477 { 478 #ifdef _SUN_SDK_ 479 if (!load_mech(gctx, pluglist->mech_name)) { 480 pluglist++; 481 continue; 482 } 483 nplug++; 484 #endif /* _SUN_SDK_ */ 485 mech = sasl_ALLOC(sizeof(mechanism_t)); 486 #ifdef _SUN_SDK_ 487 if (! mech) { 488 UNLOCK_MUTEX(&server_plug_mutex); 489 return SASL_NOMEM; 490 } 491 492 mech->glob_context = pluglist->glob_context; 493 #else 494 if (! mech) return SASL_NOMEM; 495 #endif /* _SUN_SDK_ */ 496 497 mech->plug=pluglist++; 498 if(_sasl_strdup(plugname, &mech->plugname, NULL) != SASL_OK) { 499 #ifdef _SUN_SDK_ 500 UNLOCK_MUTEX(&server_plug_mutex); 501 #endif /* _SUN_SDK_ */ 502 sasl_FREE(mech); 503 return SASL_NOMEM; 504 } 505 mech->version = version; 506 #ifdef _SUN_SDK_ 507 #ifdef _INTEGRATED_SOLARIS_ 508 mech->sun_reg = sun_reg; 509 #endif /* _INTEGRATED_SOLARIS_ */ 510 511 /* whether this mech actually has any users in it's db */ 512 mech->condition = SASL_OK; 513 #else 514 /* whether this mech actually has any users in it's db */ 515 mech->condition = result; /* SASL_OK or SASL_NOUSER */ 516 #endif /* _SUN_SDK_ */ 517 518 mech->next = mechlist->mech_list; 519 mechlist->mech_list = mech; 520 mechlist->mech_length++; 521 } 522 523 #ifdef _SUN_SDK_ 524 UNLOCK_MUTEX(&server_plug_mutex); 525 return (nplug == 0) ? SASL_NOMECH : SASL_OK; 526 #else 527 return SASL_OK; 528 #endif /* _SUN_SDK_ */ 529 } 530 531 #ifdef _SUN_SDK_ 532 static int server_done(_sasl_global_context_t *gctx) { 533 mech_list_t *mechlist = gctx->mechlist; 534 _sasl_path_info_t *path_info, *p; 535 #else 536 static int server_done(void) { 537 #endif /* _SUN_SDK_ */ 538 mechanism_t *m; 539 mechanism_t *prevm; 540 541 #ifdef _SUN_SDK_ 542 if(!gctx->sasl_server_active) 543 return SASL_NOTINIT; 544 545 if (LOCK_MUTEX(&server_active_mutex) < 0) { 546 return (SASL_FAIL); 547 } 548 gctx->sasl_server_active--; 549 550 if(gctx->sasl_server_active) { 551 /* Don't de-init yet! Our refcount is nonzero. */ 552 UNLOCK_MUTEX(&server_active_mutex); 553 return SASL_CONTINUE; 554 } 555 #else 556 if(!_sasl_server_active) 557 return SASL_NOTINIT; 558 else 559 _sasl_server_active--; 560 561 if(_sasl_server_active) { 562 /* Don't de-init yet! Our refcount is nonzero. */ 563 return SASL_CONTINUE; 564 } 565 #endif /* _SUN_SDK_ */ 566 567 if (mechlist != NULL) 568 { 569 m=mechlist->mech_list; /* m point to beginning of the list */ 570 571 while (m!=NULL) 572 { 573 prevm=m; 574 m=m->next; 575 576 if (prevm->plug->mech_free) { 577 #ifdef _SUN_SDK_ 578 prevm->plug->mech_free(prevm->glob_context, 579 #else 580 prevm->plug->mech_free(prevm->plug->glob_context, 581 #endif /* _SUN_SDK_ */ 582 mechlist->utils); 583 } 584 585 sasl_FREE(prevm->plugname); 586 sasl_FREE(prevm); 587 } 588 _sasl_free_utils(&mechlist->utils); 589 sasl_MUTEX_FREE(mechlist->mutex); 590 sasl_FREE(mechlist); 591 #ifdef _SUN_SDK_ 592 gctx->mechlist = NULL; 593 #else 594 mechlist = NULL; 595 #endif /* _SUN_SDK_ */ 596 } 597 598 /* Free the auxprop plugins */ 599 #ifdef _SUN_SDK_ 600 _sasl_auxprop_free(gctx); 601 602 gctx->server_global_callbacks.callbacks = NULL; 603 gctx->server_global_callbacks.appname = NULL; 604 605 p = gctx->splug_path_info; 606 while((path_info = p) != NULL) { 607 sasl_FREE(path_info->path); 608 p = path_info->next; 609 sasl_FREE(path_info); 610 } 611 gctx->splug_path_info = NULL; 612 UNLOCK_MUTEX(&server_active_mutex); 613 #else 614 _sasl_auxprop_free(); 615 616 global_callbacks.callbacks = NULL; 617 global_callbacks.appname = NULL; 618 #endif /* _SUN_SDK_ */ 619 620 return SASL_OK; 621 } 622 623 static int server_idle(sasl_conn_t *conn) 624 { 625 mechanism_t *m; 626 #ifdef _SUN_SDK_ 627 _sasl_global_context_t *gctx; 628 mech_list_t *mechlist; 629 630 if (conn == NULL) 631 gctx = _sasl_gbl_ctx(); 632 else 633 gctx = conn->gctx; 634 mechlist = gctx->mechlist; 635 #endif /* _SUN_SDK_ */ 636 if (! mechlist) 637 return 0; 638 639 for (m = mechlist->mech_list; 640 m!=NULL; 641 m = m->next) 642 if (m->plug->idle 643 #ifdef _SUN_SDK_ 644 && m->plug->idle(m->glob_context, 645 #else 646 && m->plug->idle(m->plug->glob_context, 647 #endif /* _SUN_SDK_ */ 648 conn, 649 conn ? ((sasl_server_conn_t *)conn)->sparams : NULL)) 650 return 1; 651 652 return 0; 653 } 654 655 #ifdef _SUN_SDK_ 656 static int load_config(_sasl_global_context_t *gctx, 657 const sasl_callback_t *verifyfile_cb) 658 { 659 int result; 660 const char *conf_to_config = NULL; 661 const char *conf_file = NULL; 662 int conf_len; 663 sasl_global_callbacks_t global_callbacks = gctx->server_global_callbacks; 664 char *alloc_file_name=NULL; 665 int len; 666 const sasl_callback_t *getconf_cb=NULL; 667 struct stat buf; 668 int full_file = 0; 669 int file_exists = 0; 670 671 /* get the path to the plugins; for now the config file will reside there */ 672 getconf_cb = _sasl_find_getconf_callback(global_callbacks.callbacks); 673 if (getconf_cb==NULL) return SASL_BADPARAM; 674 675 result = ((sasl_getpath_t *)(getconf_cb->proc))(getconf_cb->context, 676 &conf_to_config); 677 if (result!=SASL_OK) goto done; 678 if (conf_to_config == NULL) conf_to_config = ""; 679 else { 680 if (stat(conf_to_config, &buf)) 681 goto process_file; 682 full_file = !S_ISDIR(buf.st_mode); 683 } 684 685 if (!full_file) { 686 conf_len = strlen(conf_to_config); 687 len = strlen(conf_to_config)+2+ strlen(global_callbacks.appname)+5+1; 688 689 if (len > PATH_MAX ) { 690 result = SASL_FAIL; 691 goto done; 692 } 693 694 /* construct the filename for the config file */ 695 alloc_file_name = sasl_ALLOC(len); 696 if (! alloc_file_name) { 697 result = SASL_NOMEM; 698 goto done; 699 } 700 701 snprintf(alloc_file_name, len, "%.*s/%s.conf", conf_len, conf_to_config, 702 global_callbacks.appname); 703 704 } 705 conf_file = full_file ? conf_to_config : alloc_file_name; 706 707 if (full_file || stat(conf_file, &buf) == 0) 708 file_exists = S_ISREG(buf.st_mode); 709 710 process_file: 711 /* Check to see if anything has changed */ 712 if (file_exists && gctx->config_path != NULL && 713 strcmp(conf_file, gctx->config_path) == 0 && 714 gctx->config_last_read == buf.st_mtime) { 715 /* File has not changed */ 716 goto done; 717 } else if (gctx->config_path == NULL) { 718 /* No new file, nothing has changed */ 719 if (!file_exists) 720 goto done; 721 } else { 722 sasl_config_free(gctx); 723 if (!file_exists) { 724 gctx->config_path = NULL; 725 goto done; 726 } 727 } 728 gctx->config_last_read = buf.st_mtime; 729 730 /* Ask the application if it's safe to use this file */ 731 result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context, 732 conf_file, SASL_VRFY_CONF); 733 734 /* returns continue if this file is to be skipped */ 735 736 /* returns SASL_CONTINUE if doesn't exist 737 * if doesn't exist we can continue using default behavior 738 */ 739 if (result==SASL_OK) 740 result=sasl_config_init(gctx, conf_file); 741 742 done: 743 if (alloc_file_name) sasl_FREE(alloc_file_name); 744 745 return result; 746 } 747 #else 748 static int load_config(const sasl_callback_t *verifyfile_cb) 749 { 750 int result; 751 const char *path_to_config=NULL; 752 const char *c; 753 unsigned path_len; 754 755 char *config_filename=NULL; 756 int len; 757 const sasl_callback_t *getpath_cb=NULL; 758 759 /* get the path to the plugins; for now the config file will reside there */ 760 getpath_cb=_sasl_find_getpath_callback( global_callbacks.callbacks ); 761 if (getpath_cb==NULL) return SASL_BADPARAM; 762 763 /* getpath_cb->proc MUST be a sasl_getpath_t; if only c had a type 764 system */ 765 result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context, 766 &path_to_config); 767 if (result!=SASL_OK) goto done; 768 if (path_to_config == NULL) path_to_config = ""; 769 770 c = strchr(path_to_config, PATHS_DELIMITER); 771 772 /* length = length of path + '/' + length of appname + ".conf" + 1 773 for '\0' */ 774 775 if(c != NULL) 776 path_len = c - path_to_config; 777 else 778 path_len = strlen(path_to_config); 779 780 len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1; 781 782 if (len > PATH_MAX ) { 783 result = SASL_FAIL; 784 goto done; 785 } 786 787 /* construct the filename for the config file */ 788 config_filename = sasl_ALLOC(len); 789 if (! config_filename) { 790 result = SASL_NOMEM; 791 goto done; 792 } 793 794 snprintf(config_filename, len, "%.*s/%s.conf", path_len, path_to_config, 795 global_callbacks.appname); 796 797 /* Ask the application if it's safe to use this file */ 798 result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context, 799 config_filename, SASL_VRFY_CONF); 800 801 /* returns continue if this file is to be skipped */ 802 803 /* returns SASL_CONTINUE if doesn't exist 804 * if doesn't exist we can continue using default behavior 805 */ 806 if (result==SASL_OK) 807 result=sasl_config_init(config_filename); 808 809 done: 810 if (config_filename) sasl_FREE(config_filename); 811 812 return result; 813 } 814 #endif /* _SUN_SDK_ */ 815 816 /* 817 * Verify that all the callbacks are valid 818 */ 819 static int verify_server_callbacks(const sasl_callback_t *callbacks) 820 { 821 if (callbacks == NULL) return SASL_OK; 822 823 while (callbacks->id != SASL_CB_LIST_END) { 824 if (callbacks->proc==NULL) return SASL_FAIL; 825 826 callbacks++; 827 } 828 829 return SASL_OK; 830 } 831 832 #ifndef _SUN_SDK_ 833 static char *grab_field(char *line, char **eofield) 834 { 835 int d = 0; 836 char *field; 837 838 while (isspace((int) *line)) line++; 839 840 /* find end of field */ 841 while (line[d] && !isspace(((int) line[d]))) d++; 842 field = sasl_ALLOC(d + 1); 843 if (!field) { return NULL; } 844 memcpy(field, line, d); 845 field[d] = '\0'; 846 *eofield = line + d; 847 848 return field; 849 } 850 851 struct secflag_map_s { 852 char *name; 853 int value; 854 }; 855 856 struct secflag_map_s secflag_map[] = { 857 { "noplaintext", SASL_SEC_NOPLAINTEXT }, 858 { "noactive", SASL_SEC_NOACTIVE }, 859 { "nodictionary", SASL_SEC_NODICTIONARY }, 860 { "forward_secrecy", SASL_SEC_FORWARD_SECRECY }, 861 { "noanonymous", SASL_SEC_NOANONYMOUS }, 862 { "pass_credentials", SASL_SEC_PASS_CREDENTIALS }, 863 { "mutual_auth", SASL_SEC_MUTUAL_AUTH }, 864 { NULL, 0x0 } 865 }; 866 867 static int parse_mechlist_file(const char *mechlistfile) 868 { 869 FILE *f; 870 char buf[1024]; 871 char *t, *ptr; 872 int r = 0; 873 874 f = fopen(mechlistfile, "rF"); 875 if (!f) return SASL_FAIL; 876 877 r = SASL_OK; 878 while (fgets(buf, sizeof(buf), f) != NULL) { 879 mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t)); 880 sasl_server_plug_t *nplug; 881 882 if (n == NULL) { r = SASL_NOMEM; break; } 883 n->version = SASL_SERVER_PLUG_VERSION; 884 n->condition = SASL_CONTINUE; 885 nplug = sasl_ALLOC(sizeof(sasl_server_plug_t)); 886 if (nplug == NULL) { r = SASL_NOMEM; break; } 887 memset(nplug, 0, sizeof(sasl_server_plug_t)); 888 889 /* each line is: 890 plugin-file WS mech_name WS max_ssf *(WS security_flag) RET 891 */ 892 893 /* grab file */ 894 n->f = grab_field(buf, &ptr); 895 896 /* grab mech_name */ 897 nplug->mech_name = grab_field(ptr, &ptr); 898 899 /* grab max_ssf */ 900 nplug->max_ssf = strtol(ptr, &ptr, 10); 901 902 /* grab security flags */ 903 while (*ptr != '\n') { 904 struct secflag_map_s *map; 905 906 /* read security flag */ 907 t = grab_field(ptr, &ptr); 908 map = secflag_map; 909 while (map->name) { 910 if (!strcasecmp(t, map->name)) { 911 nplug->security_flags |= map->value; 912 break; 913 } 914 map++; 915 } 916 if (!map->name) { 917 _sasl_log(NULL, SASL_LOG_ERR, 918 "%s: couldn't identify flag '%s'", 919 nplug->mech_name, t); 920 } 921 free(t); 922 } 923 924 /* insert mechanism into mechlist */ 925 n->plug = nplug; 926 n->next = mechlist->mech_list; 927 mechlist->mech_list = n; 928 mechlist->mech_length++; 929 } 930 931 fclose(f); 932 return r; 933 } 934 #endif /* !_SUN_SDK_ */ 935 936 #ifdef _SUN_SDK_ 937 static int _load_server_plugins(_sasl_global_context_t *gctx) 938 { 939 int ret; 940 const add_plugin_list_t _ep_list[] = { 941 { "sasl_server_plug_init", (add_plugin_t *)_sasl_server_add_plugin }, 942 { "sasl_auxprop_plug_init", (add_plugin_t *)_sasl_auxprop_add_plugin }, 943 { "sasl_canonuser_init", (add_plugin_t *)_sasl_canonuser_add_plugin }, 944 { NULL, NULL } 945 }; 946 const sasl_callback_t *callbacks = gctx->server_global_callbacks.callbacks; 947 948 ret = _sasl_load_plugins(gctx, 1, _ep_list, 949 _sasl_find_getpath_callback(callbacks), 950 _sasl_find_verifyfile_callback(callbacks)); 951 return (ret); 952 } 953 #endif /* _SUN_SDK_ */ 954 955 /* initialize server drivers, done once per process 956 #ifdef _SUN_SDK_ 957 * callbacks -- callbacks for all server connections 958 * appname -- name of calling application (for config) 959 #else 960 * callbacks -- callbacks for all server connections; must include 961 * getopt callback 962 * appname -- name of calling application (for lower level logging) 963 * results: 964 * state -- server state 965 #endif 966 * returns: 967 * SASL_OK -- success 968 * SASL_BADPARAM -- error in config file 969 * SASL_NOMEM -- memory failure 970 #ifndef _SUN_SDK_ 971 * SASL_BADVERS -- Mechanism version mismatch 972 #endif 973 */ 974 975 int sasl_server_init(const sasl_callback_t *callbacks, 976 const char *appname) 977 #ifdef _SUN_SDK_ 978 { 979 return _sasl_server_init(NULL, callbacks, appname); 980 } 981 982 int _sasl_server_init(void *ctx, const sasl_callback_t *callbacks, 983 const char *appname) 984 #endif /* _SUN_SDK_ */ 985 { 986 int ret; 987 const sasl_callback_t *vf; 988 #ifdef _SUN_SDK_ 989 _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx; 990 #else 991 const char *pluginfile = NULL; 992 #ifdef PIC 993 sasl_getopt_t *getopt; 994 void *context; 995 #endif 996 997 const add_plugin_list_t ep_list[] = { 998 { "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin }, 999 { "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin }, 1000 { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin }, 1001 { NULL, NULL } 1002 }; 1003 #endif /* _SUN_SDK_ */ 1004 1005 /* we require the appname to be non-null and short enough to be a path */ 1006 if (!appname || strlen(appname) >= PATH_MAX) 1007 return SASL_BADPARAM; 1008 1009 #ifdef _SUN_SDK_ 1010 /* Process only one _sasl_server_init() at a time */ 1011 if (LOCK_MUTEX(&init_server_mutex) < 0) 1012 return (SASL_FAIL); 1013 if (LOCK_MUTEX(&server_active_mutex) < 0) 1014 return (SASL_FAIL); 1015 1016 if (gctx->sasl_server_active) { 1017 /* We're already active, just increase our refcount */ 1018 /* xxx do something with the callback structure? */ 1019 gctx->sasl_server_active++; 1020 UNLOCK_MUTEX(&server_active_mutex); 1021 UNLOCK_MUTEX(&init_server_mutex); 1022 return SASL_OK; 1023 } 1024 1025 ret = _sasl_common_init(gctx, &gctx->server_global_callbacks, 1); 1026 if (ret != SASL_OK) { 1027 UNLOCK_MUTEX(&server_active_mutex); 1028 UNLOCK_MUTEX(&init_server_mutex); 1029 return ret; 1030 } 1031 #else 1032 if (_sasl_server_active) { 1033 /* We're already active, just increase our refcount */ 1034 /* xxx do something with the callback structure? */ 1035 _sasl_server_active++; 1036 return SASL_OK; 1037 } 1038 1039 ret = _sasl_common_init(&global_callbacks); 1040 if (ret != SASL_OK) 1041 return ret; 1042 #endif /* _SUN_SDK_ */ 1043 1044 /* verify that the callbacks look ok */ 1045 ret = verify_server_callbacks(callbacks); 1046 #ifdef _SUN_SDK_ 1047 if (ret != SASL_OK) { 1048 UNLOCK_MUTEX(&server_active_mutex); 1049 UNLOCK_MUTEX(&init_server_mutex); 1050 return ret; 1051 } 1052 1053 gctx->server_global_callbacks.callbacks = callbacks; 1054 gctx->server_global_callbacks.appname = appname; 1055 1056 /* If we fail now, we have to call server_done */ 1057 gctx->sasl_server_active = 1; 1058 UNLOCK_MUTEX(&server_active_mutex); 1059 1060 /* allocate mechlist and set it to empty */ 1061 gctx->mechlist = sasl_ALLOC(sizeof(mech_list_t)); 1062 if (gctx->mechlist == NULL) { 1063 server_done(gctx); 1064 UNLOCK_MUTEX(&init_server_mutex); 1065 return SASL_NOMEM; 1066 } 1067 1068 ret = init_mechlist(gctx); 1069 1070 if (ret != SASL_OK) { 1071 server_done(gctx); 1072 UNLOCK_MUTEX(&init_server_mutex); 1073 return ret; 1074 } 1075 #else 1076 if (ret != SASL_OK) 1077 return ret; 1078 1079 global_callbacks.callbacks = callbacks; 1080 global_callbacks.appname = appname; 1081 1082 /* If we fail now, we have to call server_done */ 1083 _sasl_server_active = 1; 1084 1085 /* allocate mechlist and set it to empty */ 1086 mechlist = sasl_ALLOC(sizeof(mech_list_t)); 1087 if (mechlist == NULL) { 1088 server_done(); 1089 return SASL_NOMEM; 1090 } 1091 1092 ret = init_mechlist(); 1093 if (ret != SASL_OK) { 1094 server_done(); 1095 return ret; 1096 } 1097 #endif /* _SUN_SDK_ */ 1098 1099 vf = _sasl_find_verifyfile_callback(callbacks); 1100 1101 /* load config file if applicable */ 1102 #ifdef _SUN_SDK_ 1103 ret = load_config(gctx, vf); 1104 if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) { 1105 server_done(gctx); 1106 UNLOCK_MUTEX(&init_server_mutex); 1107 #else 1108 ret = load_config(vf); 1109 if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) { 1110 server_done(); 1111 #endif /* _SUN_SDK_ */ 1112 return ret; 1113 } 1114 1115 /* load internal plugins */ 1116 #ifdef _SUN_SDK_ 1117 _sasl_server_add_plugin(gctx, "EXTERNAL", &external_server_plug_init); 1118 1119 /* NOTE: plugin_list option not supported in SUN SDK */ 1120 { 1121 #else 1122 sasl_server_add_plugin("EXTERNAL", &external_server_plug_init); 1123 1124 #ifdef PIC 1125 /* delayed loading of plugins? (DSO only, as it doesn't 1126 * make much [any] sense to delay in the static library case) */ 1127 if (_sasl_getcallback(NULL, SASL_CB_GETOPT, &getopt, &context) 1128 == SASL_OK) { 1129 /* No sasl_conn_t was given to getcallback, so we provide the 1130 * global callbacks structure */ 1131 ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL); 1132 } 1133 #endif 1134 1135 if (pluginfile != NULL) { 1136 /* this file should contain a list of plugins available. 1137 we'll load on demand. */ 1138 1139 /* Ask the application if it's safe to use this file */ 1140 ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context, 1141 pluginfile, 1142 SASL_VRFY_CONF); 1143 if (ret != SASL_OK) { 1144 _sasl_log(NULL, SASL_LOG_ERR, 1145 "unable to load plugin list %s: %z", pluginfile, ret); 1146 } 1147 1148 if (ret == SASL_OK) { 1149 ret = parse_mechlist_file(pluginfile); 1150 } 1151 } else { 1152 #endif /* _SUN_SDK_ */ 1153 /* load all plugins now */ 1154 #ifdef _SUN_SDK_ 1155 ret = _load_server_plugins(gctx); 1156 #else 1157 ret = _sasl_load_plugins(ep_list, 1158 _sasl_find_getpath_callback(callbacks), 1159 _sasl_find_verifyfile_callback(callbacks)); 1160 #endif /* _SUN_SDK_ */ 1161 } 1162 1163 #ifdef _SUN_SDK_ 1164 if (ret == SASL_OK) 1165 ret = _sasl_build_mechlist(gctx); 1166 if (ret == SASL_OK) { 1167 gctx->sasl_server_cleanup_hook = &server_done; 1168 gctx->sasl_server_idle_hook = &server_idle; 1169 } else { 1170 server_done(gctx); 1171 } 1172 UNLOCK_MUTEX(&init_server_mutex); 1173 #else 1174 if (ret == SASL_OK) { 1175 _sasl_server_cleanup_hook = &server_done; 1176 _sasl_server_idle_hook = &server_idle; 1177 1178 ret = _sasl_build_mechlist(); 1179 } else { 1180 server_done(); 1181 } 1182 #endif /* _SUN_SDK_ */ 1183 1184 return ret; 1185 } 1186 1187 /* 1188 * Once we have the users plaintext password we 1189 * may want to transition them. That is put entries 1190 * for them in the passwd database for other 1191 * stronger mechanism 1192 * 1193 * for example PLAIN -> CRAM-MD5 1194 */ 1195 static int 1196 _sasl_transition(sasl_conn_t * conn, 1197 const char * pass, 1198 unsigned passlen) 1199 { 1200 const char *dotrans = "n"; 1201 sasl_getopt_t *getopt; 1202 int result = SASL_OK; 1203 void *context; 1204 1205 if (! conn) 1206 return SASL_BADPARAM; 1207 1208 if (! conn->oparams.authid) 1209 PARAMERROR(conn); 1210 1211 /* check if this is enabled: default to false */ 1212 if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) 1213 { 1214 getopt(context, NULL, "auto_transition", &dotrans, NULL); 1215 if (dotrans == NULL) dotrans = "n"; 1216 } 1217 1218 if (*dotrans == '1' || *dotrans == 'y' || 1219 (*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') { 1220 /* ok, it's on! */ 1221 result = sasl_setpass(conn, 1222 conn->oparams.authid, 1223 pass, 1224 passlen, 1225 NULL, 0, 0); 1226 } 1227 1228 RETURN(conn,result); 1229 } 1230 1231 1232 /* create context for a single SASL connection 1233 * service -- registered name of the service using SASL (e.g. "imap") 1234 * serverFQDN -- Fully qualified domain name of server. NULL means use 1235 * gethostname() or equivalent. 1236 * Useful for multi-homed servers. 1237 * user_realm -- permits multiple user realms on server, NULL = default 1238 * iplocalport -- server IPv4/IPv6 domain literal string with port 1239 * (if NULL, then mechanisms requiring IPaddr are disabled) 1240 * ipremoteport -- client IPv4/IPv6 domain literal string with port 1241 * (if NULL, then mechanisms requiring IPaddr are disabled) 1242 * callbacks -- callbacks (e.g., authorization, lang, new getopt context) 1243 * flags -- usage flags (see above) 1244 * returns: 1245 * pconn -- new connection context 1246 * 1247 * returns: 1248 * SASL_OK -- success 1249 * SASL_NOMEM -- not enough memory 1250 */ 1251 1252 int sasl_server_new(const char *service, 1253 const char *serverFQDN, 1254 const char *user_realm, 1255 const char *iplocalport, 1256 const char *ipremoteport, 1257 const sasl_callback_t *callbacks, 1258 unsigned flags, 1259 sasl_conn_t **pconn) 1260 #ifdef _SUN_SDK_ 1261 { 1262 return _sasl_server_new(NULL, service, serverFQDN, user_realm, iplocalport, 1263 ipremoteport, callbacks, flags, pconn); 1264 } 1265 1266 int _sasl_server_new(void *ctx, 1267 const char *service, 1268 const char *serverFQDN, 1269 const char *user_realm, 1270 const char *iplocalport, 1271 const char *ipremoteport, 1272 const sasl_callback_t *callbacks, 1273 unsigned flags, 1274 sasl_conn_t **pconn) 1275 #endif /* _SUN_SDK_ */ 1276 { 1277 int result; 1278 sasl_server_conn_t *serverconn; 1279 sasl_utils_t *utils; 1280 sasl_getopt_t *getopt; 1281 void *context; 1282 const char *log_level; 1283 1284 #ifdef _SUN_SDK_ 1285 _sasl_global_context_t *gctx = (ctx == NULL) ? _sasl_gbl_ctx() : ctx; 1286 1287 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 1288 #else 1289 if (_sasl_server_active==0) return SASL_NOTINIT; 1290 #endif /* _SUN_SDK_ */ 1291 if (! pconn) return SASL_FAIL; 1292 if (! service) return SASL_FAIL; 1293 1294 *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t)); 1295 if (*pconn==NULL) return SASL_NOMEM; 1296 1297 memset(*pconn, 0, sizeof(sasl_server_conn_t)); 1298 1299 #ifdef _SUN_SDK_ 1300 (*pconn)->gctx = gctx; 1301 #endif /* _SUN_SDK_ */ 1302 1303 serverconn = (sasl_server_conn_t *)*pconn; 1304 1305 /* make sparams */ 1306 serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t)); 1307 if (serverconn->sparams==NULL) 1308 MEMERROR(*pconn); 1309 1310 memset(serverconn->sparams, 0, sizeof(sasl_server_params_t)); 1311 1312 (*pconn)->destroy_conn = &server_dispose; 1313 result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER, 1314 &server_idle, serverFQDN, 1315 iplocalport, ipremoteport, 1316 #ifdef _SUN_SDK_ 1317 callbacks, &gctx->server_global_callbacks); 1318 #else 1319 callbacks, &global_callbacks); 1320 #endif /* _SUN_SDK_ */ 1321 if (result != SASL_OK) 1322 goto done_error; 1323 1324 1325 /* set util functions - need to do rest */ 1326 #ifdef _SUN_SDK_ 1327 utils=_sasl_alloc_utils(gctx, *pconn, &gctx->server_global_callbacks); 1328 #else 1329 utils=_sasl_alloc_utils(*pconn, &global_callbacks); 1330 #endif /* _SUN_SDK_ */ 1331 if (!utils) { 1332 result = SASL_NOMEM; 1333 goto done_error; 1334 } 1335 1336 #ifdef _SUN_SDK_ 1337 utils->checkpass = &_sasl_checkpass; 1338 #else /* _SUN_SDK_ */ 1339 utils->checkpass = &sasl_checkpass; 1340 #endif /* _SUN_SDK_ */ 1341 1342 /* Setup the propctx -> We'll assume the default size */ 1343 serverconn->sparams->propctx=prop_new(0); 1344 if(!serverconn->sparams->propctx) { 1345 result = SASL_NOMEM; 1346 goto done_error; 1347 } 1348 1349 serverconn->sparams->service = (*pconn)->service; 1350 serverconn->sparams->servicelen = strlen((*pconn)->service); 1351 1352 #ifdef _SUN_SDK_ 1353 serverconn->sparams->appname = gctx->server_global_callbacks.appname; 1354 serverconn->sparams->applen = strlen(gctx->server_global_callbacks.appname); 1355 #else 1356 serverconn->sparams->appname = global_callbacks.appname; 1357 serverconn->sparams->applen = strlen(global_callbacks.appname); 1358 #endif /* _SUN_SDK_ */ 1359 1360 serverconn->sparams->serverFQDN = (*pconn)->serverFQDN; 1361 serverconn->sparams->slen = strlen((*pconn)->serverFQDN); 1362 1363 if (user_realm) { 1364 result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL); 1365 serverconn->sparams->urlen = strlen(user_realm); 1366 serverconn->sparams->user_realm = serverconn->user_realm; 1367 } else { 1368 serverconn->user_realm = NULL; 1369 /* the sparams is already zeroed */ 1370 } 1371 1372 #ifdef _SUN_SDK_ 1373 serverconn->sparams->iplocalport = (*pconn)->iplocalport; 1374 serverconn->sparams->iploclen = strlen((*pconn)->iplocalport); 1375 serverconn->sparams->ipremoteport = (*pconn)->ipremoteport; 1376 serverconn->sparams->ipremlen = strlen((*pconn)->ipremoteport); 1377 1378 serverconn->sparams->callbacks = callbacks; 1379 #endif /* _SUN_SDK_ */ 1380 1381 log_level = NULL; 1382 if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) { 1383 getopt(context, NULL, "log_level", &log_level, NULL); 1384 } 1385 serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR; 1386 1387 serverconn->sparams->utils = utils; 1388 serverconn->sparams->transition = &_sasl_transition; 1389 serverconn->sparams->canon_user = &_sasl_canon_user; 1390 serverconn->sparams->props = serverconn->base.props; 1391 serverconn->sparams->flags = flags; 1392 1393 if(result == SASL_OK) return SASL_OK; 1394 1395 done_error: 1396 _sasl_conn_dispose(*pconn); 1397 sasl_FREE(*pconn); 1398 *pconn = NULL; 1399 return result; 1400 } 1401 1402 /* 1403 * The rule is: 1404 * IF mech strength + external strength < min ssf THEN FAIL 1405 * We also have to look at the security properties and make sure 1406 * that this mechanism has everything we want 1407 */ 1408 static int mech_permitted(sasl_conn_t *conn, 1409 mechanism_t *mech) 1410 { 1411 sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn; 1412 const sasl_server_plug_t *plug; 1413 int myflags; 1414 context_list_t *cur; 1415 sasl_getopt_t *getopt; 1416 void *context; 1417 sasl_ssf_t minssf = 0; 1418 #ifdef _SUN_SDK_ 1419 _sasl_global_context_t *gctx; 1420 #endif /* _SUN_SDK_ */ 1421 1422 if(!conn) return 0; 1423 1424 #ifdef _SUN_SDK_ 1425 gctx = conn->gctx; 1426 #endif /* _SUN_SDK_ */ 1427 1428 if(! mech || ! mech->plug) { 1429 #ifdef _SUN_SDK_ 1430 if(conn) _sasl_log(conn, SASL_LOG_WARN, "Parameter error"); 1431 #else 1432 PARAMERROR(conn); 1433 #endif /* _SUN_SDK_ */ 1434 return 0; 1435 } 1436 1437 plug = mech->plug; 1438 1439 /* get the list of allowed mechanisms (default = all) */ 1440 if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) 1441 == SASL_OK) { 1442 const char *mlist = NULL; 1443 1444 getopt(context, NULL, "mech_list", &mlist, NULL); 1445 1446 /* if we have a list, check the plugin against it */ 1447 if (mlist) { 1448 const char *cp; 1449 1450 while (*mlist) { 1451 for (cp = mlist; *cp && !isspace((int) *cp); cp++); 1452 if (((size_t) (cp - mlist) == strlen(plug->mech_name)) && 1453 !strncasecmp(mlist, plug->mech_name, 1454 strlen(plug->mech_name))) { 1455 break; 1456 } 1457 mlist = cp; 1458 while (*mlist && isspace((int) *mlist)) mlist++; 1459 } 1460 1461 if (!*mlist) return 0; /* reached EOS -> not in our list */ 1462 } 1463 } 1464 1465 /* setup parameters for the call to mech_avail */ 1466 s_conn->sparams->serverFQDN=conn->serverFQDN; 1467 s_conn->sparams->service=conn->service; 1468 s_conn->sparams->user_realm=s_conn->user_realm; 1469 s_conn->sparams->props=conn->props; 1470 s_conn->sparams->external_ssf=conn->external.ssf; 1471 1472 /* Check if we have banished this one already */ 1473 for(cur = s_conn->mech_contexts; cur; cur=cur->next) { 1474 if(cur->mech == mech) { 1475 /* If it's not mech_avail'd, then stop now */ 1476 if(!cur->context) return 0; 1477 break; 1478 } 1479 } 1480 1481 #ifdef _INTEGRATED_SOLARIS_ 1482 if (!mech->sun_reg) { 1483 s_conn->sparams->props.min_ssf = 0; 1484 s_conn->sparams->props.max_ssf = 0; 1485 } 1486 s_conn->base.sun_reg = mech->sun_reg; 1487 #endif /* _INTEGRATED_SOLARIS_ */ 1488 if (conn->props.min_ssf < conn->external.ssf) { 1489 minssf = 0; 1490 } else { 1491 minssf = conn->props.min_ssf - conn->external.ssf; 1492 } 1493 1494 /* Generic mechanism */ 1495 #ifdef _INTEGRATED_SOLARIS_ 1496 /* If not SUN supplied mech, it has no strength */ 1497 if (plug->max_ssf < minssf || (minssf > 0 && !mech->sun_reg)) { 1498 #else 1499 if (plug->max_ssf < minssf) { 1500 #endif /* _INTEGRATED_SOLARIS_ */ 1501 #ifdef _INTEGRATED_SOLARIS_ 1502 sasl_seterror(conn, SASL_NOLOG, 1503 gettext("mech %s is too weak"), plug->mech_name); 1504 #else 1505 sasl_seterror(conn, SASL_NOLOG, 1506 "mech %s is too weak", plug->mech_name); 1507 #endif /* _INTEGRATED_SOLARIS_ */ 1508 return 0; /* too weak */ 1509 } 1510 1511 context = NULL; 1512 if(plug->mech_avail 1513 #ifdef _SUN_SDK_ 1514 && plug->mech_avail(mech->glob_context, 1515 #else 1516 && plug->mech_avail(plug->glob_context, 1517 #endif /* _SUN_SDK_ */ 1518 s_conn->sparams, (void **)&context) != SASL_OK ) { 1519 /* Mark this mech as no good for this connection */ 1520 cur = sasl_ALLOC(sizeof(context_list_t)); 1521 if(!cur) { 1522 #ifdef _SUN_SDK_ 1523 if(conn) _sasl_log(conn, SASL_LOG_WARN, "Out of Memory"); 1524 #else 1525 MEMERROR(conn); 1526 #endif /* _SUN_SDK_ */ 1527 return 0; 1528 } 1529 cur->context = NULL; 1530 cur->mech = mech; 1531 cur->next = s_conn->mech_contexts; 1532 s_conn->mech_contexts = cur; 1533 1534 /* Error should be set by mech_avail call */ 1535 return 0; 1536 } else if(context) { 1537 /* Save this context */ 1538 cur = sasl_ALLOC(sizeof(context_list_t)); 1539 if(!cur) { 1540 #ifdef _SUN_SDK_ 1541 if(conn) _sasl_log(conn, SASL_LOG_WARN, "Out of Memory"); 1542 #else 1543 MEMERROR(conn); 1544 #endif /* _SUN_SDK_ */ 1545 return 0; 1546 } 1547 cur->context = context; 1548 cur->mech = mech; 1549 cur->next = s_conn->mech_contexts; 1550 s_conn->mech_contexts = cur; 1551 } 1552 1553 /* Generic mechanism */ 1554 #ifdef _INTEGRATED_SOLARIS_ 1555 /* If not SUN supplied mech, it has no strength */ 1556 if (plug->max_ssf < minssf || (minssf > 0 && !mech->sun_reg)) { 1557 #else 1558 if (plug->max_ssf < minssf) { 1559 #endif /* _INTEGRATED_SOLARIS_ */ 1560 #ifdef _INTEGRATED_SOLARIS_ 1561 sasl_seterror(conn, SASL_NOLOG, gettext("too weak")); 1562 #else 1563 sasl_seterror(conn, SASL_NOLOG, "too weak"); 1564 #endif /* _INTEGRATED_SOLARIS_ */ 1565 return 0; /* too weak */ 1566 } 1567 1568 #ifndef _SUN_SDK_ 1569 /* if there are no users in the secrets database we can't use this 1570 mechanism */ 1571 if (mech->condition == SASL_NOUSER) { 1572 sasl_seterror(conn, 0, "no users in secrets db"); 1573 return 0; 1574 } 1575 #endif /* !_SUN_SDK_ */ 1576 1577 /* Can it meet our features? */ 1578 if ((conn->flags & SASL_NEED_PROXY) && 1579 !(plug->features & SASL_FEAT_ALLOWS_PROXY)) { 1580 return 0; 1581 } 1582 1583 /* security properties---if there are any flags that differ and are 1584 in what the connection are requesting, then fail */ 1585 1586 /* special case plaintext */ 1587 myflags = conn->props.security_flags; 1588 1589 /* if there's an external layer this is no longer plaintext */ 1590 if ((conn->props.min_ssf <= conn->external.ssf) && 1591 (conn->external.ssf > 1)) { 1592 myflags &= ~SASL_SEC_NOPLAINTEXT; 1593 } 1594 1595 /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */ 1596 if (((myflags ^ plug->security_flags) & myflags) != 0) { 1597 #ifdef _INTEGRATED_SOLARIS_ 1598 sasl_seterror(conn, SASL_NOLOG, 1599 gettext("security flags do not match required")); 1600 #else 1601 sasl_seterror(conn, SASL_NOLOG, 1602 "security flags do not match required"); 1603 #endif /* _INTEGRATED_SOLARIS_ */ 1604 return 0; 1605 } 1606 1607 /* Check Features */ 1608 if(plug->features & SASL_FEAT_GETSECRET) { 1609 /* We no longer support sasl_server_{get,put}secret */ 1610 #ifdef _SUN_SDK_ 1611 _sasl_log(conn, SASL_LOG_ERR, 1612 "mech %s requires unprovided secret facility", 1613 plug->mech_name); 1614 #else 1615 sasl_seterror(conn, 0, 1616 "mech %s requires unprovided secret facility", 1617 plug->mech_name); 1618 #endif /* _SUN_SDK_ */ 1619 return 0; 1620 } 1621 1622 return 1; 1623 } 1624 1625 /* 1626 * make the authorization 1627 * 1628 */ 1629 1630 static int do_authorization(sasl_server_conn_t *s_conn) 1631 { 1632 int ret; 1633 sasl_authorize_t *authproc; 1634 void *auth_context; 1635 1636 /* now let's see if authname is allowed to proxy for username! */ 1637 1638 /* check the proxy callback */ 1639 if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY, 1640 &authproc, &auth_context) != SASL_OK) { 1641 INTERROR(&s_conn->base, SASL_NOAUTHZ); 1642 } 1643 1644 ret = authproc(&(s_conn->base), auth_context, 1645 s_conn->base.oparams.user, s_conn->base.oparams.ulen, 1646 s_conn->base.oparams.authid, s_conn->base.oparams.alen, 1647 s_conn->user_realm, 1648 (s_conn->user_realm ? strlen(s_conn->user_realm) : 0), 1649 s_conn->sparams->propctx); 1650 1651 RETURN(&s_conn->base, ret); 1652 } 1653 1654 1655 /* start a mechanism exchange within a connection context 1656 * mech -- the mechanism name client requested 1657 * clientin -- client initial response (NUL terminated), NULL if empty 1658 * clientinlen -- length of initial response 1659 * serverout -- initial server challenge, NULL if done 1660 * (library handles freeing this string) 1661 * serveroutlen -- length of initial server challenge 1662 #ifdef _SUN_SDK_ 1663 * conn -- the sasl connection 1664 #else 1665 * output: 1666 * pconn -- the connection negotiation state on success 1667 #endif 1668 * 1669 * Same returns as sasl_server_step() or 1670 * SASL_NOMECH if mechanism not available. 1671 */ 1672 int sasl_server_start(sasl_conn_t *conn, 1673 const char *mech, 1674 const char *clientin, 1675 unsigned clientinlen, 1676 const char **serverout, 1677 unsigned *serveroutlen) 1678 { 1679 sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn; 1680 int result; 1681 context_list_t *cur, **prev; 1682 mechanism_t *m; 1683 1684 #ifdef _SUN_SDK_ 1685 _sasl_global_context_t *gctx = 1686 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 1687 mech_list_t *mechlist; 1688 1689 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 1690 if (! conn) 1691 return SASL_BADPARAM; 1692 1693 (void)_load_server_plugins(gctx); 1694 mechlist = gctx->mechlist; 1695 m=mechlist->mech_list; 1696 result = load_config(gctx, _sasl_find_verifyfile_callback( 1697 gctx->server_global_callbacks.callbacks)); 1698 if (result != SASL_OK) 1699 return (result); 1700 #else 1701 if (_sasl_server_active==0) return SASL_NOTINIT; 1702 1703 /* make sure mech is valid mechanism 1704 if not return appropriate error */ 1705 m=mechlist->mech_list; 1706 1707 /* check parameters */ 1708 if(!conn) return SASL_BADPARAM; 1709 #endif /* _SUN_SDK_ */ 1710 1711 if (!mech || ((clientin==NULL) && (clientinlen>0))) 1712 PARAMERROR(conn); 1713 1714 if(serverout) *serverout = NULL; 1715 if(serveroutlen) *serveroutlen = 0; 1716 1717 while (m!=NULL) 1718 { 1719 if ( strcasecmp(mech,m->plug->mech_name)==0) 1720 { 1721 break; 1722 } 1723 m=m->next; 1724 } 1725 1726 if (m==NULL) { 1727 #ifdef _INTEGRATED_SOLARIS_ 1728 sasl_seterror(conn, 0, gettext("Couldn't find mech %s"), mech); 1729 #else 1730 sasl_seterror(conn, 0, "Couldn't find mech %s", mech); 1731 #endif /* _INTEGRATED_SOLARIS_ */ 1732 result = SASL_NOMECH; 1733 goto done; 1734 } 1735 1736 #ifdef _SUN_SDK_ 1737 server_dispose_mech_contexts(conn); 1738 #endif /*_SUN_SDK_ */ 1739 1740 /* Make sure that we're willing to use this mech */ 1741 if (! mech_permitted(conn, m)) { 1742 result = SASL_NOMECH; 1743 goto done; 1744 } 1745 1746 #ifdef _SUN_SDK_ 1747 if(conn->context) { 1748 s_conn->mech->plug->mech_dispose(conn->context, s_conn->sparams->utils); 1749 conn->context = NULL; 1750 } 1751 memset(&conn->oparams, 0, sizeof(sasl_out_params_t)); 1752 #else 1753 if (m->condition == SASL_CONTINUE) { 1754 sasl_server_plug_init_t *entry_point; 1755 void *library = NULL; 1756 sasl_server_plug_t *pluglist; 1757 int version, plugcount; 1758 int l = 0; 1759 1760 /* need to load this plugin */ 1761 result = _sasl_get_plugin(m->f, 1762 _sasl_find_verifyfile_callback(global_callbacks.callbacks), 1763 &library); 1764 1765 if (result == SASL_OK) { 1766 result = _sasl_locate_entry(library, "sasl_server_plug_init", 1767 (void **)&entry_point); 1768 } 1769 1770 if (result == SASL_OK) { 1771 result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, 1772 &version, &pluglist, &plugcount); 1773 } 1774 1775 if (result == SASL_OK) { 1776 /* find the correct mechanism in this plugin */ 1777 for (l = 0; l < plugcount; l++) { 1778 if (!strcasecmp(pluglist[l].mech_name, 1779 m->plug->mech_name)) break; 1780 } 1781 if (l == plugcount) { 1782 result = SASL_NOMECH; 1783 } 1784 } 1785 if (result == SASL_OK) { 1786 /* check that the parameters are the same */ 1787 if ((pluglist[l].max_ssf != m->plug->max_ssf) || 1788 (pluglist[l].security_flags != m->plug->security_flags)) { 1789 _sasl_log(conn, SASL_LOG_ERR, 1790 "%s: security parameters don't match mechlist file", 1791 pluglist[l].mech_name); 1792 result = SASL_NOMECH; 1793 } 1794 } 1795 if (result == SASL_OK) { 1796 /* copy mechlist over */ 1797 sasl_FREE((sasl_server_plug_t *) m->plug); 1798 m->plug = &pluglist[l]; 1799 m->condition = SASL_OK; 1800 } 1801 1802 if (result != SASL_OK) { 1803 /* The library will eventually be freed, don't sweat it */ 1804 RETURN(conn, result); 1805 } 1806 } 1807 #endif /* !_SUN_SDK_ */ 1808 1809 /* We used to setup sparams HERE, but now it's done 1810 inside of mech_permitted (which is called above) */ 1811 prev = &s_conn->mech_contexts; 1812 for(cur = *prev; cur; prev=&cur->next,cur=cur->next) { 1813 if(cur->mech == m) { 1814 if(!cur->context) { 1815 #ifdef _SUN_SDK_ 1816 _sasl_log(conn, SASL_LOG_ERR, 1817 "Got past mech_permitted with a disallowed mech!"); 1818 #else 1819 sasl_seterror(conn, 0, 1820 "Got past mech_permitted with a disallowed mech!"); 1821 #endif /* _SUN_SDK_ */ 1822 return SASL_NOMECH; 1823 } 1824 /* If we find it, we need to pull cur out of the 1825 list so it won't be freed later! */ 1826 (*prev)->next = cur->next; 1827 conn->context = cur->context; 1828 sasl_FREE(cur); 1829 } 1830 } 1831 1832 s_conn->mech = m; 1833 1834 if(!conn->context) { 1835 /* Note that we don't hand over a new challenge */ 1836 #ifdef _SUN_SDK_ 1837 result = s_conn->mech->plug->mech_new(s_conn->mech->glob_context, 1838 #else 1839 result = s_conn->mech->plug->mech_new(s_conn->mech->plug->glob_context, 1840 #endif /* _SUN_SDK_ */ 1841 s_conn->sparams, 1842 NULL, 1843 0, 1844 &(conn->context)); 1845 } else { 1846 /* the work was already done by mech_avail! */ 1847 result = SASL_OK; 1848 } 1849 1850 if (result == SASL_OK) { 1851 if(clientin) { 1852 if(s_conn->mech->plug->features & SASL_FEAT_SERVER_FIRST) { 1853 /* Remote sent first, but mechanism does not support it. 1854 * RFC 2222 says we fail at this point. */ 1855 #ifdef _SUN_SDK_ 1856 _sasl_log(conn, SASL_LOG_ERR, 1857 "Remote sent first but mech does not allow it."); 1858 #else 1859 sasl_seterror(conn, 0, 1860 "Remote sent first but mech does not allow it."); 1861 #endif /* _SUN_SDK_ */ 1862 result = SASL_BADPROT; 1863 } else { 1864 /* Mech wants client-first, so let them have it */ 1865 result = sasl_server_step(conn, 1866 clientin, clientinlen, 1867 serverout, serveroutlen); 1868 } 1869 } else { 1870 if(s_conn->mech->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) { 1871 /* Mech wants client first anyway, so we should do that */ 1872 *serverout = ""; 1873 *serveroutlen = 0; 1874 result = SASL_CONTINUE; 1875 } else { 1876 /* Mech wants server-first, so let them have it */ 1877 result = sasl_server_step(conn, 1878 clientin, clientinlen, 1879 serverout, serveroutlen); 1880 } 1881 } 1882 } 1883 1884 done: 1885 if( result != SASL_OK 1886 && result != SASL_CONTINUE 1887 && result != SASL_INTERACT) { 1888 if(conn->context) { 1889 s_conn->mech->plug->mech_dispose(conn->context, 1890 s_conn->sparams->utils); 1891 conn->context = NULL; 1892 } 1893 } 1894 1895 RETURN(conn,result); 1896 } 1897 1898 1899 /* perform one step of the SASL exchange 1900 * inputlen & input -- client data 1901 * NULL on first step if no optional client step 1902 * outputlen & output -- set to the server data to transmit 1903 * to the client in the next step 1904 * (library handles freeing this) 1905 * 1906 * returns: 1907 * SASL_OK -- exchange is complete. 1908 * SASL_CONTINUE -- indicates another step is necessary. 1909 * SASL_TRANS -- entry for user exists, but not for mechanism 1910 * and transition is possible 1911 * SASL_BADPARAM -- service name needed 1912 * SASL_BADPROT -- invalid input from client 1913 * ... 1914 */ 1915 1916 int sasl_server_step(sasl_conn_t *conn, 1917 const char *clientin, 1918 unsigned clientinlen, 1919 const char **serverout, 1920 unsigned *serveroutlen) 1921 { 1922 int ret; 1923 sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */ 1924 1925 #ifdef _SUN_SDK_ 1926 _sasl_global_context_t *gctx = 1927 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 1928 1929 /* check parameters */ 1930 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 1931 #else 1932 /* check parameters */ 1933 if (_sasl_server_active==0) return SASL_NOTINIT; 1934 #endif /* _SUN_SDK_ */ 1935 if (!conn) return SASL_BADPARAM; 1936 if ((clientin==NULL) && (clientinlen>0)) 1937 PARAMERROR(conn); 1938 1939 /* If we've already done the last send, return! */ 1940 if(s_conn->sent_last == 1) { 1941 return SASL_OK; 1942 } 1943 1944 /* Don't do another step if the plugin told us that we're done */ 1945 if (conn->oparams.doneflag) { 1946 _sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag"); 1947 return SASL_FAIL; 1948 } 1949 1950 if(serverout) *serverout = NULL; 1951 if(serveroutlen) *serveroutlen = 0; 1952 1953 ret = s_conn->mech->plug->mech_step(conn->context, 1954 s_conn->sparams, 1955 clientin, 1956 clientinlen, 1957 serverout, 1958 serveroutlen, 1959 &conn->oparams); 1960 1961 if (ret == SASL_OK) { 1962 ret = do_authorization(s_conn); 1963 } 1964 1965 if (ret == SASL_OK) { 1966 /* if we're done, we need to watch out for the following: 1967 * 1. the mech does server-send-last 1968 * 2. the protocol does not 1969 * 1970 * in this case, return SASL_CONTINUE and remember we are done. 1971 */ 1972 if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) { 1973 s_conn->sent_last = 1; 1974 ret = SASL_CONTINUE; 1975 } 1976 if(!conn->oparams.maxoutbuf) { 1977 conn->oparams.maxoutbuf = conn->props.maxbufsize; 1978 } 1979 1980 if(conn->oparams.user == NULL || conn->oparams.authid == NULL) { 1981 #ifdef _SUN_SDK_ 1982 _sasl_log(conn, SASL_LOG_ERR, 1983 "mech did not call canon_user for both authzid " 1984 "and authid"); 1985 #else 1986 sasl_seterror(conn, 0, 1987 "mech did not call canon_user for both authzid " \ 1988 "and authid"); 1989 #endif /* _SUN_SDK_ */ 1990 ret = SASL_BADPROT; 1991 } 1992 } 1993 1994 if( ret != SASL_OK 1995 && ret != SASL_CONTINUE 1996 && ret != SASL_INTERACT) { 1997 if(conn->context) { 1998 s_conn->mech->plug->mech_dispose(conn->context, 1999 s_conn->sparams->utils); 2000 conn->context = NULL; 2001 } 2002 } 2003 2004 RETURN(conn, ret); 2005 } 2006 2007 /* returns the length of all the mechanisms 2008 * added up 2009 */ 2010 2011 #ifdef _SUN_SDK_ 2012 static unsigned mech_names_len(_sasl_global_context_t *gctx) 2013 { 2014 mech_list_t *mechlist = gctx->mechlist; 2015 #else 2016 static unsigned mech_names_len() 2017 { 2018 #endif /* _SUN_SDK_ */ 2019 mechanism_t *listptr; 2020 unsigned result = 0; 2021 2022 for (listptr = mechlist->mech_list; 2023 listptr; 2024 listptr = listptr->next) 2025 result += strlen(listptr->plug->mech_name); 2026 2027 return result; 2028 } 2029 2030 /* This returns a list of mechanisms in a NUL-terminated string 2031 * 2032 * The default behavior is to seperate with spaces if sep==NULL 2033 */ 2034 int _sasl_server_listmech(sasl_conn_t *conn, 2035 const char *user __attribute__((unused)), 2036 const char *prefix, 2037 const char *sep, 2038 const char *suffix, 2039 const char **result, 2040 unsigned *plen, 2041 int *pcount) 2042 { 2043 int lup; 2044 mechanism_t *listptr; 2045 int ret; 2046 int resultlen; 2047 int flag; 2048 const char *mysep; 2049 2050 #ifdef _SUN_SDK_ 2051 _sasl_global_context_t *gctx; 2052 mech_list_t *mechlist; 2053 2054 if (!conn) return SASL_BADPARAM; 2055 /* if there hasn't been a sasl_sever_init() fail */ 2056 gctx = conn->gctx; 2057 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 2058 2059 (void)_load_server_plugins(gctx); 2060 mechlist = gctx->mechlist; 2061 #else 2062 /* if there hasn't been a sasl_sever_init() fail */ 2063 if (_sasl_server_active==0) return SASL_NOTINIT; 2064 if (!conn) return SASL_BADPARAM; 2065 #endif /* _SUN_SDK_ */ 2066 if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn); 2067 2068 if (! result) 2069 PARAMERROR(conn); 2070 2071 if (plen != NULL) 2072 *plen = 0; 2073 if (pcount != NULL) 2074 *pcount = 0; 2075 2076 if (sep) { 2077 mysep = sep; 2078 } else { 2079 mysep = " "; 2080 } 2081 2082 if (! mechlist || mechlist->mech_length <= 0) 2083 INTERROR(conn, SASL_NOMECH); 2084 2085 resultlen = (prefix ? strlen(prefix) : 0) 2086 + (strlen(mysep) * (mechlist->mech_length - 1)) 2087 #ifdef _SUN_SDK_ 2088 + mech_names_len(gctx) 2089 #else 2090 + mech_names_len() 2091 #endif /* _SUN_SDK_ */ 2092 + (suffix ? strlen(suffix) : 0) 2093 + 1; 2094 ret = _buf_alloc(&conn->mechlist_buf, 2095 &conn->mechlist_buf_len, resultlen); 2096 if(ret != SASL_OK) MEMERROR(conn); 2097 2098 if (prefix) 2099 strcpy (conn->mechlist_buf,prefix); 2100 else 2101 *(conn->mechlist_buf) = '\0'; 2102 2103 listptr = mechlist->mech_list; 2104 2105 flag = 0; 2106 /* make list */ 2107 for (lup = 0; lup < mechlist->mech_length; lup++) { 2108 /* currently, we don't use the "user" parameter for anything */ 2109 if (mech_permitted(conn, listptr)) { 2110 if (pcount != NULL) 2111 (*pcount)++; 2112 2113 /* print seperator */ 2114 if (flag) { 2115 strcat(conn->mechlist_buf, mysep); 2116 } else { 2117 flag = 1; 2118 } 2119 2120 /* now print the mechanism name */ 2121 strcat(conn->mechlist_buf, listptr->plug->mech_name); 2122 } 2123 2124 listptr = listptr->next; 2125 } 2126 2127 if (suffix) 2128 strcat(conn->mechlist_buf,suffix); 2129 2130 if (plen!=NULL) 2131 *plen=strlen(conn->mechlist_buf); 2132 2133 *result = conn->mechlist_buf; 2134 2135 return SASL_OK; 2136 } 2137 2138 #ifdef _SUN_SDK_ 2139 sasl_string_list_t *_sasl_server_mechs(_sasl_global_context_t *gctx) 2140 #else 2141 sasl_string_list_t *_sasl_server_mechs(void) 2142 #endif /* _SUN_SDK_ */ 2143 { 2144 mechanism_t *listptr; 2145 sasl_string_list_t *retval = NULL, *next=NULL; 2146 #ifdef _SUN_SDK_ 2147 mech_list_t *mechlist = gctx->mechlist; 2148 2149 if(!gctx->sasl_server_active) return NULL; 2150 #else 2151 if(!_sasl_server_active) return NULL; 2152 #endif /* _SUN_SDK_ */ 2153 2154 /* make list */ 2155 for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) { 2156 next = sasl_ALLOC(sizeof(sasl_string_list_t)); 2157 2158 if(!next && !retval) return NULL; 2159 else if(!next) { 2160 next = retval->next; 2161 do { 2162 sasl_FREE(retval); 2163 retval = next; 2164 next = retval->next; 2165 } while(next); 2166 return NULL; 2167 } 2168 2169 next->d = listptr->plug->mech_name; 2170 2171 if(!retval) { 2172 next->next = NULL; 2173 retval = next; 2174 } else { 2175 next->next = retval; 2176 retval = next; 2177 } 2178 } 2179 2180 return retval; 2181 } 2182 2183 #define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t')) 2184 static int is_mech(const char *t, const char *m) 2185 { 2186 int sl = strlen(m); 2187 return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl)); 2188 } 2189 2190 /* returns OK if it's valid */ 2191 static int _sasl_checkpass(sasl_conn_t *conn, 2192 const char *user, 2193 unsigned userlen __attribute__((unused)), 2194 const char *pass, 2195 unsigned passlen __attribute__((unused))) 2196 { 2197 sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; 2198 int result; 2199 sasl_getopt_t *getopt; 2200 sasl_server_userdb_checkpass_t *checkpass_cb; 2201 void *context; 2202 const char *mlist = NULL, *mech = NULL; 2203 struct sasl_verify_password_s *v; 2204 const char *service = conn->service; 2205 2206 /* call userdb callback function, if available */ 2207 result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS, 2208 &checkpass_cb, &context); 2209 if(result == SASL_OK && checkpass_cb) { 2210 result = checkpass_cb(conn, context, user, pass, strlen(pass), 2211 s_conn->sparams->propctx); 2212 if(result == SASL_OK) 2213 return SASL_OK; 2214 } 2215 2216 /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */ 2217 if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) 2218 == SASL_OK) { 2219 getopt(context, NULL, "pwcheck_method", &mlist, NULL); 2220 } 2221 2222 if(!mlist) mlist = DEFAULT_CHECKPASS_MECH; 2223 2224 result = SASL_NOMECH; 2225 2226 mech = mlist; 2227 while (*mech && result != SASL_OK) { 2228 for (v = _sasl_verify_password; v->name; v++) { 2229 if(is_mech(mech, v->name)) { 2230 result = v->verify(conn, user, pass, service, 2231 s_conn->user_realm); 2232 break; 2233 } 2234 } 2235 if (result != SASL_OK) { 2236 /* skip to next mech in list */ 2237 while (*mech && !isspace((int) *mech)) mech++; 2238 while (*mech && isspace((int) *mech)) mech++; 2239 } 2240 } 2241 2242 if (result == SASL_NOMECH) { 2243 /* no mechanism available ?!? */ 2244 _sasl_log(conn, SASL_LOG_ERR, "unknown password verifier %s", mech); 2245 } 2246 2247 if (result != SASL_OK) 2248 #ifdef _INTEGRATED_SOLARIS_ 2249 sasl_seterror(conn, SASL_NOLOG, gettext("checkpass failed")); 2250 #else 2251 sasl_seterror(conn, SASL_NOLOG, "checkpass failed"); 2252 #endif /* _INTEGRATED_SOLARIS_ */ 2253 2254 RETURN(conn, result); 2255 } 2256 2257 /* check if a plaintext password is valid 2258 * if user is NULL, check if plaintext passwords are enabled 2259 * inputs: 2260 * user -- user to query in current user_domain 2261 * userlen -- length of username, 0 = strlen(user) 2262 * pass -- plaintext password to check 2263 * passlen -- length of password, 0 = strlen(pass) 2264 * returns 2265 * SASL_OK -- success 2266 * SASL_NOMECH -- mechanism not supported 2267 * SASL_NOVERIFY -- user found, but no verifier 2268 * SASL_NOUSER -- user not found 2269 */ 2270 int sasl_checkpass(sasl_conn_t *conn, 2271 const char *user, 2272 #ifdef _SUN_SDK_ 2273 unsigned userlen, 2274 #else /* _SUN_SDK_ */ 2275 unsigned userlen __attribute__((unused)), 2276 #endif /* _SUN_SDK_ */ 2277 const char *pass, 2278 unsigned passlen) 2279 { 2280 int result; 2281 2282 #ifdef _SUN_SDK_ 2283 _sasl_global_context_t *gctx = 2284 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 2285 2286 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 2287 2288 /* A NULL user means the caller is checking if plaintext authentication 2289 * is enabled. But if no connection context is supplied, we have no 2290 * appropriate policy to check against. So for consistant global 2291 * behavior we always say plaintext is enabled in this case. 2292 */ 2293 if (!user && !conn) return SASL_OK; 2294 2295 if (!conn) return SASL_BADPARAM; 2296 2297 /* Check connection security policy to see if plaintext password 2298 * authentication is permitted. 2299 * 2300 * XXX TODO FIXME: 2301 * This should call mech_permitted with the PLAIN mechanism, 2302 * since all plaintext mechanisms should fall under the same 2303 * security policy guidelines. But to keep code changes and 2304 * risk to a minimum at this juncture, we do the minimal 2305 * security strength and plaintext policy checks which are 2306 * most likely to be deployed and useful in the field. 2307 */ 2308 if (conn->props.min_ssf > conn->external.ssf) 2309 RETURN(conn, SASL_TOOWEAK); 2310 if ((conn->props.security_flags & SASL_SEC_NOPLAINTEXT) != 0 2311 && conn->external.ssf == 0) 2312 RETURN(conn, SASL_ENCRYPT); 2313 2314 if (!user) 2315 return SASL_OK; 2316 #else 2317 if (_sasl_server_active==0) return SASL_NOTINIT; 2318 2319 /* check if it's just a query if we are enabled */ 2320 if (!user) 2321 return SASL_OK; 2322 2323 if (!conn) return SASL_BADPARAM; 2324 #endif /* _SUN_SDK_ */ 2325 2326 /* check params */ 2327 if (pass == NULL) 2328 PARAMERROR(conn); 2329 2330 /* canonicalize the username */ 2331 result = _sasl_canon_user(conn, user, 0, 2332 SASL_CU_AUTHID | SASL_CU_AUTHZID, 2333 &(conn->oparams)); 2334 if(result != SASL_OK) RETURN(conn, result); 2335 user = conn->oparams.user; 2336 2337 /* Check the password */ 2338 result = _sasl_checkpass(conn, user, strlen(user), pass, strlen(pass)); 2339 2340 #ifdef _SUN_SDK_ 2341 if (result == SASL_OK) { 2342 result = do_authorization((sasl_server_conn_t *) conn); 2343 } 2344 #endif /* _SUN_SDK_ */ 2345 2346 if (result == SASL_OK) 2347 result = _sasl_transition(conn, pass, passlen); 2348 2349 RETURN(conn,result); 2350 } 2351 2352 /* check if a user exists on server 2353 * conn -- connection context (may be NULL, used to hold last error) 2354 * service -- registered name of the service using SASL (e.g. "imap") 2355 * user_realm -- permits multiple user realms on server, NULL = default 2356 * user -- NUL terminated user name 2357 * 2358 * returns: 2359 * SASL_OK -- success 2360 * SASL_DISABLED -- account disabled [FIXME: currently not detected] 2361 * SASL_NOUSER -- user not found 2362 * SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported] 2363 * SASL_NOMECH -- no mechanisms enabled 2364 */ 2365 int sasl_user_exists(sasl_conn_t *conn, 2366 const char *service, 2367 const char *user_realm, 2368 const char *user) 2369 { 2370 int result=SASL_NOMECH; 2371 const char *mlist = NULL, *mech = NULL; 2372 void *context; 2373 sasl_getopt_t *getopt; 2374 struct sasl_verify_password_s *v; 2375 2376 #ifdef _SUN_SDK_ 2377 _sasl_global_context_t *gctx = 2378 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 2379 2380 /* check params */ 2381 if (gctx->sasl_server_active==0) return SASL_NOTINIT; 2382 #else 2383 /* check params */ 2384 if (_sasl_server_active==0) return SASL_NOTINIT; 2385 #endif /* _SUN_SDK_ */ 2386 if (!conn) return SASL_BADPARAM; 2387 if (!user || conn->type != SASL_CONN_SERVER) 2388 PARAMERROR(conn); 2389 2390 if(!service) service = conn->service; 2391 2392 /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */ 2393 if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) 2394 == SASL_OK) { 2395 getopt(context, NULL, "pwcheck_method", &mlist, NULL); 2396 } 2397 2398 if(!mlist) mlist = DEFAULT_CHECKPASS_MECH; 2399 2400 result = SASL_NOMECH; 2401 2402 mech = mlist; 2403 while (*mech && result != SASL_OK) { 2404 for (v = _sasl_verify_password; v->name; v++) { 2405 if(is_mech(mech, v->name)) { 2406 result = v->verify(conn, user, NULL, service, user_realm); 2407 break; 2408 } 2409 } 2410 if (result != SASL_OK) { 2411 /* skip to next mech in list */ 2412 while (*mech && !isspace((int) *mech)) mech++; 2413 while (*mech && isspace((int) *mech)) mech++; 2414 } 2415 } 2416 2417 /* Screen out the SASL_BADPARAM response 2418 * we'll get from not giving a password */ 2419 if(result == SASL_BADPARAM) { 2420 result = SASL_OK; 2421 } 2422 2423 if (result == SASL_NOMECH) { 2424 /* no mechanism available ?!? */ 2425 _sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?"); 2426 #ifndef _SUN_SDK_ 2427 sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?"); 2428 #endif /* !_SUN_SDK_ */ 2429 } 2430 2431 RETURN(conn, result); 2432 } 2433 2434 /* check if an apop exchange is valid 2435 * (note this is an optional part of the SASL API) 2436 * if challenge is NULL, just check if APOP is enabled 2437 * inputs: 2438 * challenge -- challenge which was sent to client 2439 * challen -- length of challenge, 0 = strlen(challenge) 2440 * response -- client response, "<user> <digest>" (RFC 1939) 2441 * resplen -- length of response, 0 = strlen(response) 2442 * returns 2443 * SASL_OK -- success 2444 * SASL_BADAUTH -- authentication failed 2445 * SASL_BADPARAM -- missing challenge 2446 * SASL_BADPROT -- protocol error (e.g., response in wrong format) 2447 * SASL_NOVERIFY -- user found, but no verifier 2448 * SASL_NOMECH -- mechanism not supported 2449 * SASL_NOUSER -- user not found 2450 */ 2451 int sasl_checkapop(sasl_conn_t *conn, 2452 #ifdef DO_SASL_CHECKAPOP 2453 const char *challenge, 2454 unsigned challen __attribute__((unused)), 2455 const char *response, 2456 unsigned resplen __attribute__((unused))) 2457 #else 2458 const char *challenge __attribute__((unused)), 2459 unsigned challen __attribute__((unused)), 2460 const char *response __attribute__((unused)), 2461 unsigned resplen __attribute__((unused))) 2462 #endif 2463 { 2464 #ifdef DO_SASL_CHECKAPOP 2465 sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; 2466 char *user, *user_end; 2467 const char *password_request[] = { SASL_AUX_PASSWORD, NULL }; 2468 size_t user_len; 2469 int result; 2470 #ifdef _SUN_SDK_ 2471 _sasl_global_context_t *gctx = 2472 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx; 2473 2474 if (gctx->sasl_server_active==0) 2475 return SASL_NOTINIT; 2476 #else 2477 if (_sasl_server_active==0) 2478 return SASL_NOTINIT; 2479 #endif /* _SUN_SDK_ */ 2480 2481 /* check if it's just a query if we are enabled */ 2482 if(!challenge) 2483 return SASL_OK; 2484 2485 /* check params */ 2486 if (!conn) return SASL_BADPARAM; 2487 if (!response) 2488 PARAMERROR(conn); 2489 2490 /* Parse out username and digest. 2491 * 2492 * Per RFC 1939, response must be "<user> <digest>", where 2493 * <digest> is a 16-octet value which is sent in hexadecimal 2494 * format, using lower-case ASCII characters. 2495 */ 2496 user_end = strrchr(response, ' '); 2497 if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32) 2498 { 2499 #ifdef _INTEGRATED_SOLARIS_ 2500 sasl_seterror(conn, 0, gettext("Bad Digest")); 2501 #else 2502 sasl_seterror(conn, 0, "Bad Digest"); 2503 #endif /* _INTEGRATED_SOLARIS_ */ 2504 RETURN(conn,SASL_BADPROT); 2505 } 2506 2507 user_len = (size_t)(user_end - response); 2508 user = sasl_ALLOC(user_len + 1); 2509 memcpy(user, response, user_len); 2510 user[user_len] = '\0'; 2511 2512 result = prop_request(s_conn->sparams->propctx, password_request); 2513 if(result != SASL_OK) 2514 { 2515 sasl_FREE(user); 2516 RETURN(conn, result); 2517 } 2518 2519 /* Cannonify it */ 2520 result = _sasl_canon_user(conn, user, user_len, 2521 SASL_CU_AUTHID | SASL_CU_AUTHZID, 2522 &(conn->oparams)); 2523 sasl_FREE(user); 2524 2525 if(result != SASL_OK) RETURN(conn, result); 2526 2527 /* Do APOP verification */ 2528 result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid, 2529 challenge, user_end + 1, s_conn->user_realm); 2530 2531 /* If verification failed, we don't want to encourage getprop to work */ 2532 if(result != SASL_OK) { 2533 conn->oparams.user = NULL; 2534 conn->oparams.authid = NULL; 2535 } 2536 2537 RETURN(conn, result); 2538 #else /* sasl_checkapop was disabled at compile time */ 2539 sasl_seterror(conn, SASL_NOLOG, 2540 "sasl_checkapop called, but was disabled at compile time"); 2541 RETURN(conn, SASL_NOMECH); 2542 #endif /* DO_SASL_CHECKAPOP */ 2543 } 2544 2545