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