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