Home | History | Annotate | Download | only in lib
      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 (at) 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 
   2578