xref: /illumos-gate/usr/src/lib/libsasl/lib/server.c (revision 694c35fa)
17c478bd9Sstevel@tonic-gate /*
2*004388ebScasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* SASL server API implementation
77c478bd9Sstevel@tonic-gate  * Rob Siemborski
87c478bd9Sstevel@tonic-gate  * Tim Martin
97c478bd9Sstevel@tonic-gate  * $Id: server.c,v 1.123 2003/04/16 19:36:01 rjs3 Exp $
107c478bd9Sstevel@tonic-gate  */
117c478bd9Sstevel@tonic-gate /*
127c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
157c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
167c478bd9Sstevel@tonic-gate  * are met:
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
197c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
207c478bd9Sstevel@tonic-gate  *
217c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
227c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
237c478bd9Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
247c478bd9Sstevel@tonic-gate  *    distribution.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * 3. The name "Carnegie Mellon University" must not be used to
277c478bd9Sstevel@tonic-gate  *    endorse or promote products derived from this software without
287c478bd9Sstevel@tonic-gate  *    prior written permission. For permission or any other legal
297c478bd9Sstevel@tonic-gate  *    details, please contact
307c478bd9Sstevel@tonic-gate  *      Office of Technology Transfer
317c478bd9Sstevel@tonic-gate  *      Carnegie Mellon University
327c478bd9Sstevel@tonic-gate  *      5000 Forbes Avenue
337c478bd9Sstevel@tonic-gate  *      Pittsburgh, PA  15213-3890
347c478bd9Sstevel@tonic-gate  *      (412) 268-4387, fax: (412) 268-7395
357c478bd9Sstevel@tonic-gate  *      tech-transfer@andrew.cmu.edu
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * 4. Redistributions of any form whatsoever must retain the following
387c478bd9Sstevel@tonic-gate  *    acknowledgment:
397c478bd9Sstevel@tonic-gate  *    "This product includes software developed by Computing Services
407c478bd9Sstevel@tonic-gate  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
437c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
447c478bd9Sstevel@tonic-gate  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
457c478bd9Sstevel@tonic-gate  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
467c478bd9Sstevel@tonic-gate  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
477c478bd9Sstevel@tonic-gate  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
487c478bd9Sstevel@tonic-gate  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* local functions/structs don't start with sasl
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate #include <config.h>
547c478bd9Sstevel@tonic-gate #include <errno.h>
557c478bd9Sstevel@tonic-gate #include <stdio.h>
567c478bd9Sstevel@tonic-gate #include <stdlib.h>
577c478bd9Sstevel@tonic-gate #include <limits.h>
587c478bd9Sstevel@tonic-gate #ifndef macintosh
597c478bd9Sstevel@tonic-gate #include <sys/types.h>
607c478bd9Sstevel@tonic-gate #include <sys/stat.h>
617c478bd9Sstevel@tonic-gate #endif
627c478bd9Sstevel@tonic-gate #include <fcntl.h>
637c478bd9Sstevel@tonic-gate #include <string.h>
647c478bd9Sstevel@tonic-gate #include <ctype.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include "sasl.h"
677c478bd9Sstevel@tonic-gate #include "saslint.h"
687c478bd9Sstevel@tonic-gate #include "saslplug.h"
697c478bd9Sstevel@tonic-gate #include "saslutil.h"
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
727c478bd9Sstevel@tonic-gate #ifdef sun
737c478bd9Sstevel@tonic-gate /* gotta define gethostname ourselves on suns */
747c478bd9Sstevel@tonic-gate extern int gethostname(char *, int);
757c478bd9Sstevel@tonic-gate #endif
767c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define DEFAULT_CHECKPASS_MECH "auxprop"
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /* Contains functions:
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  * sasl_server_init
837c478bd9Sstevel@tonic-gate  * sasl_server_new
847c478bd9Sstevel@tonic-gate  * sasl_listmech
857c478bd9Sstevel@tonic-gate  * sasl_server_start
867c478bd9Sstevel@tonic-gate  * sasl_server_step
877c478bd9Sstevel@tonic-gate  * sasl_checkpass
887c478bd9Sstevel@tonic-gate  * sasl_checkapop
897c478bd9Sstevel@tonic-gate  * sasl_user_exists
907c478bd9Sstevel@tonic-gate  * sasl_setpass
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
947c478bd9Sstevel@tonic-gate int _is_sasl_server_active(_sasl_global_context_t *gctx)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate     return gctx->sasl_server_active;
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(init_server_mutex);
1007c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(server_active_mutex);
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * server_plug_mutex ensures only one server plugin is init'ed at a time
1037c478bd9Sstevel@tonic-gate  * If a plugin is loaded more than once, the glob_context may be overwritten
1047c478bd9Sstevel@tonic-gate  * which may lead to a memory leak. We keep glob_context with each mech
1057c478bd9Sstevel@tonic-gate  * to avoid this problem.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(server_plug_mutex);
1087c478bd9Sstevel@tonic-gate #else
1097c478bd9Sstevel@tonic-gate /* if we've initialized the server sucessfully */
1107c478bd9Sstevel@tonic-gate static int _sasl_server_active = 0;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /* For access by other modules */
1137c478bd9Sstevel@tonic-gate int _is_sasl_server_active(void) { return _sasl_server_active; }
1147c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static int _sasl_checkpass(sasl_conn_t *conn,
1177c478bd9Sstevel@tonic-gate 			   const char *user, unsigned userlen,
1187c478bd9Sstevel@tonic-gate 			   const char *pass, unsigned passlen);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
1217c478bd9Sstevel@tonic-gate static mech_list_t *mechlist = NULL; /* global var which holds the list */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static sasl_global_callbacks_t global_callbacks;
1247c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /* set the password for a user
1277c478bd9Sstevel@tonic-gate  *  conn        -- SASL connection
1287c478bd9Sstevel@tonic-gate  *  user        -- user name
1297c478bd9Sstevel@tonic-gate  *  pass        -- plaintext password, may be NULL to remove user
1307c478bd9Sstevel@tonic-gate  *  passlen     -- length of password, 0 = strlen(pass)
1317c478bd9Sstevel@tonic-gate  *  oldpass     -- NULL will sometimes work
1327c478bd9Sstevel@tonic-gate  *  oldpasslen  -- length of password, 0 = strlen(oldpass)
1337c478bd9Sstevel@tonic-gate  *  flags       -- see flags below
1347c478bd9Sstevel@tonic-gate  *
1357c478bd9Sstevel@tonic-gate  * returns:
1367c478bd9Sstevel@tonic-gate  *  SASL_NOCHANGE  -- proper entry already exists
1377c478bd9Sstevel@tonic-gate  *  SASL_NOMECH    -- no authdb supports password setting as configured
1387c478bd9Sstevel@tonic-gate  *  SASL_NOVERIFY  -- user exists, but no settable password present
1397c478bd9Sstevel@tonic-gate  *  SASL_DISABLED  -- account disabled
1407c478bd9Sstevel@tonic-gate  *  SASL_PWLOCK    -- password locked
1417c478bd9Sstevel@tonic-gate  *  SASL_WEAKPASS  -- password too weak for security policy
1427c478bd9Sstevel@tonic-gate  *  SASL_NOUSERPASS -- user-supplied passwords not permitted
1437c478bd9Sstevel@tonic-gate  *  SASL_FAIL      -- OS error
1447c478bd9Sstevel@tonic-gate  *  SASL_BADPARAM  -- password too long
1457c478bd9Sstevel@tonic-gate  *  SASL_OK        -- successful
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate int sasl_setpass(sasl_conn_t *conn,
1497c478bd9Sstevel@tonic-gate 		 const char *user,
1507c478bd9Sstevel@tonic-gate 		 const char *pass, unsigned passlen,
1517c478bd9Sstevel@tonic-gate 		 const char *oldpass,
1527c478bd9Sstevel@tonic-gate 		 unsigned oldpasslen,
1537c478bd9Sstevel@tonic-gate 		 unsigned flags)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate     int result=SASL_OK, tmpresult;
1567c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
1577c478bd9Sstevel@tonic-gate     sasl_server_userdb_setpass_t *setpass_cb = NULL;
1587c478bd9Sstevel@tonic-gate     void *context = NULL;
1597c478bd9Sstevel@tonic-gate     mechanism_t *m;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1627c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
1637c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
1647c478bd9Sstevel@tonic-gate     mech_list_t *mechlist = gctx == NULL ? NULL : gctx->mechlist;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate     if (!gctx->sasl_server_active || !mechlist) return SASL_NOTINIT;
1677c478bd9Sstevel@tonic-gate #else
1687c478bd9Sstevel@tonic-gate     if (!_sasl_server_active || !mechlist) return SASL_NOTINIT;
1697c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate     /* check params */
1727c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
1737c478bd9Sstevel@tonic-gate     if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate     if ((!(flags & SASL_SET_DISABLE) && passlen == 0)
1767c478bd9Sstevel@tonic-gate         || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE)))
1777c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate     /* call userdb callback function */
1807c478bd9Sstevel@tonic-gate     result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS,
1817c478bd9Sstevel@tonic-gate 			       &setpass_cb, &context);
1827c478bd9Sstevel@tonic-gate     if(result == SASL_OK && setpass_cb) {
1837c478bd9Sstevel@tonic-gate 	tmpresult = setpass_cb(conn, context, user, pass, passlen,
1847c478bd9Sstevel@tonic-gate 			    s_conn->sparams->propctx, flags);
1857c478bd9Sstevel@tonic-gate 	if(tmpresult != SASL_OK) {
1867c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_ERR,
1877c478bd9Sstevel@tonic-gate 		      "setpass callback failed for %s: %z",
1887c478bd9Sstevel@tonic-gate 		      user, tmpresult);
1897c478bd9Sstevel@tonic-gate 	} else {
1907c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_NOTE,
1917c478bd9Sstevel@tonic-gate 		      "setpass callback succeeded for %s", user);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate     } else {
1947c478bd9Sstevel@tonic-gate 	result = SASL_OK;
1957c478bd9Sstevel@tonic-gate     }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate     /* now we let the mechanisms set their secrets */
1987c478bd9Sstevel@tonic-gate     for (m = mechlist->mech_list; m; m = m->next) {
1997c478bd9Sstevel@tonic-gate 	if (!m->plug->setpass) {
2007c478bd9Sstevel@tonic-gate 	    /* can't set pass for this mech */
2017c478bd9Sstevel@tonic-gate 	    continue;
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2047c478bd9Sstevel@tonic-gate 	tmpresult = m->plug->setpass(m->glob_context,
2057c478bd9Sstevel@tonic-gate #else
2067c478bd9Sstevel@tonic-gate 	tmpresult = m->plug->setpass(m->plug->glob_context,
2077c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2087c478bd9Sstevel@tonic-gate 				     ((sasl_server_conn_t *)conn)->sparams,
2097c478bd9Sstevel@tonic-gate 				     user,
2107c478bd9Sstevel@tonic-gate 				     pass,
2117c478bd9Sstevel@tonic-gate 				     passlen,
2127c478bd9Sstevel@tonic-gate 				     oldpass, oldpasslen,
2137c478bd9Sstevel@tonic-gate 				     flags);
2147c478bd9Sstevel@tonic-gate 	if (tmpresult == SASL_OK) {
2157c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_NOTE,
2167c478bd9Sstevel@tonic-gate 		      "%s: set secret for %s", m->plug->mech_name, user);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	    m->condition = SASL_OK; /* if we previously thought the
2197c478bd9Sstevel@tonic-gate 				       mechanism didn't have any user secrets
2207c478bd9Sstevel@tonic-gate 				       we now think it does */
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	} else if (tmpresult == SASL_NOCHANGE) {
2237c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_NOTE,
2247c478bd9Sstevel@tonic-gate 		      "%s: secret not changed for %s", m->plug->mech_name, user);
2257c478bd9Sstevel@tonic-gate 	} else {
2267c478bd9Sstevel@tonic-gate 	    result = tmpresult;
2277c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_ERR,
2287c478bd9Sstevel@tonic-gate 		      "%s: failed to set secret for %s: %z (%m)",
2297c478bd9Sstevel@tonic-gate 		      m->plug->mech_name, user, tmpresult,
2307c478bd9Sstevel@tonic-gate #ifndef WIN32
2317c478bd9Sstevel@tonic-gate 		      errno
2327c478bd9Sstevel@tonic-gate #else
2337c478bd9Sstevel@tonic-gate 		      GetLastError()
2347c478bd9Sstevel@tonic-gate #endif
2357c478bd9Sstevel@tonic-gate 		      );
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate     }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     RETURN(conn, result);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2437c478bd9Sstevel@tonic-gate static void
2447c478bd9Sstevel@tonic-gate server_dispose_mech_contexts(sasl_conn_t *pconn)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate   sasl_server_conn_t *s_conn=  (sasl_server_conn_t *) pconn;
2477c478bd9Sstevel@tonic-gate   context_list_t *cur, *cur_next;
2487c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = pconn->gctx;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate   for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
2517c478bd9Sstevel@tonic-gate       cur_next = cur->next;
2527c478bd9Sstevel@tonic-gate       if(cur->context)
2537c478bd9Sstevel@tonic-gate 	  cur->mech->plug->mech_dispose(cur->context, s_conn->sparams->utils);
2547c478bd9Sstevel@tonic-gate       sasl_FREE(cur);
2557c478bd9Sstevel@tonic-gate   }
2567c478bd9Sstevel@tonic-gate   s_conn->mech_contexts = NULL;
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /* local mechanism which disposes of server */
2617c478bd9Sstevel@tonic-gate static void server_dispose(sasl_conn_t *pconn)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate   sasl_server_conn_t *s_conn=  (sasl_server_conn_t *) pconn;
2647c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2657c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = pconn->gctx;
2667c478bd9Sstevel@tonic-gate #else
2677c478bd9Sstevel@tonic-gate   context_list_t *cur, *cur_next;
2687c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate   if (s_conn->mech
2717c478bd9Sstevel@tonic-gate       && s_conn->mech->plug->mech_dispose) {
2727c478bd9Sstevel@tonic-gate     s_conn->mech->plug->mech_dispose(pconn->context,
2737c478bd9Sstevel@tonic-gate 				     s_conn->sparams->utils);
2747c478bd9Sstevel@tonic-gate   }
2757c478bd9Sstevel@tonic-gate   pconn->context = NULL;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2787c478bd9Sstevel@tonic-gate   server_dispose_mech_contexts(pconn);
2797c478bd9Sstevel@tonic-gate #else
2807c478bd9Sstevel@tonic-gate   for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
2817c478bd9Sstevel@tonic-gate       cur_next = cur->next;
2827c478bd9Sstevel@tonic-gate       if(cur->context)
2837c478bd9Sstevel@tonic-gate 	  cur->mech->plug->mech_dispose(cur->context, s_conn->sparams->utils);
2847c478bd9Sstevel@tonic-gate       sasl_FREE(cur);
2857c478bd9Sstevel@tonic-gate   }
2867c478bd9Sstevel@tonic-gate   s_conn->mech_contexts = NULL;
2877c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate   _sasl_free_utils(&s_conn->sparams->utils);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate   if (s_conn->sparams->propctx)
2927c478bd9Sstevel@tonic-gate       prop_dispose(&s_conn->sparams->propctx);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate   if (s_conn->user_realm)
2957c478bd9Sstevel@tonic-gate       sasl_FREE(s_conn->user_realm);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate   if (s_conn->sparams)
2987c478bd9Sstevel@tonic-gate       sasl_FREE(s_conn->sparams);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate   _sasl_conn_dispose(pconn);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3047c478bd9Sstevel@tonic-gate static int init_mechlist(_sasl_global_context_t *gctx)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate     mech_list_t *mechlist = gctx->mechlist;
3077c478bd9Sstevel@tonic-gate #else
3087c478bd9Sstevel@tonic-gate static int init_mechlist(void)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3117c478bd9Sstevel@tonic-gate     sasl_utils_t *newutils = NULL;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate     mechlist->mutex = sasl_MUTEX_ALLOC();
3147c478bd9Sstevel@tonic-gate     if(!mechlist->mutex) return SASL_FAIL;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate     /* set util functions - need to do rest */
3177c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3187c478bd9Sstevel@tonic-gate     newutils = _sasl_alloc_utils(gctx, NULL, &gctx->server_global_callbacks);
3197c478bd9Sstevel@tonic-gate #else
3207c478bd9Sstevel@tonic-gate     newutils = _sasl_alloc_utils(NULL, &global_callbacks);
3217c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3227c478bd9Sstevel@tonic-gate     if (newutils == NULL)
3237c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate     newutils->checkpass = &_sasl_checkpass;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate     mechlist->utils = newutils;
3287c478bd9Sstevel@tonic-gate     mechlist->mech_list=NULL;
3297c478bd9Sstevel@tonic-gate     mechlist->mech_length=0;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate     return SASL_OK;
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3357c478bd9Sstevel@tonic-gate static int load_mech(_sasl_global_context_t *gctx, const char *mechname)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
3387c478bd9Sstevel@tonic-gate     void *context;
3397c478bd9Sstevel@tonic-gate     const char *mlist = NULL;
3407c478bd9Sstevel@tonic-gate     const char *cp;
3417c478bd9Sstevel@tonic-gate     size_t len;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate     /* No sasl_conn_t was given to getcallback, so we provide the
3447c478bd9Sstevel@tonic-gate      * global callbacks structure */
3457c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(NULL, SASL_CB_GETOPT, &getopt, &context) == SASL_OK)
3467c478bd9Sstevel@tonic-gate 	(void)getopt(&gctx->server_global_callbacks, NULL,
3477c478bd9Sstevel@tonic-gate 		"server_load_mech_list", &mlist, NULL);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate     if (mlist == NULL)
3507c478bd9Sstevel@tonic-gate 	return (1);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate     len = strlen(mechname);
3537c478bd9Sstevel@tonic-gate     while (*mlist && isspace((int) *mlist)) mlist++;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate     while (*mlist) {
3567c478bd9Sstevel@tonic-gate 	for (cp = mlist; *cp && !isspace((int) *cp); cp++);
3577c478bd9Sstevel@tonic-gate 	if (((size_t) (cp - mlist) == len) &&
3587c478bd9Sstevel@tonic-gate 		!strncasecmp(mlist, mechname, len))
3597c478bd9Sstevel@tonic-gate 	    break;
3607c478bd9Sstevel@tonic-gate 	mlist = cp;
3617c478bd9Sstevel@tonic-gate 	while (*mlist && isspace((int) *mlist)) mlist++;
3627c478bd9Sstevel@tonic-gate     }
3637c478bd9Sstevel@tonic-gate     return (*mlist != '\0');
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate  * parameters:
3697c478bd9Sstevel@tonic-gate  *  p - entry point
3707c478bd9Sstevel@tonic-gate  */
3717c478bd9Sstevel@tonic-gate int sasl_server_add_plugin(const char *plugname,
3727c478bd9Sstevel@tonic-gate 			   sasl_server_plug_init_t *p)
3737c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate     return (_sasl_server_add_plugin(_sasl_gbl_ctx(), plugname, p));
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate int _sasl_server_add_plugin(void *ctx,
3797c478bd9Sstevel@tonic-gate 			    const char *plugname,
3807c478bd9Sstevel@tonic-gate 			    sasl_server_plug_init_t *p)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate     int nplug = 0;
3837c478bd9Sstevel@tonic-gate     int i;
3847c478bd9Sstevel@tonic-gate     mechanism_t *m;
3857c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
3867c478bd9Sstevel@tonic-gate     mech_list_t *mechlist = gctx->mechlist;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
3897c478bd9Sstevel@tonic-gate     int sun_reg;
3907c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
3917c478bd9Sstevel@tonic-gate #else
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3947c478bd9Sstevel@tonic-gate     int plugcount;
3957c478bd9Sstevel@tonic-gate     sasl_server_plug_t *pluglist;
3967c478bd9Sstevel@tonic-gate     mechanism_t *mech;
3977c478bd9Sstevel@tonic-gate     sasl_server_plug_init_t *entry_point;
3987c478bd9Sstevel@tonic-gate     int result;
3997c478bd9Sstevel@tonic-gate     int version;
4007c478bd9Sstevel@tonic-gate     int lupe;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     if(!plugname || !p) return SASL_BADPARAM;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4057c478bd9Sstevel@tonic-gate     if (mechlist == NULL) return SASL_BADPARAM;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate     /* Check to see if this plugin has already been registered */
4087c478bd9Sstevel@tonic-gate     m = mechlist->mech_list;
4097c478bd9Sstevel@tonic-gate     for (i = 0; i < mechlist->mech_length; i++) {
4107c478bd9Sstevel@tonic-gate 	if (strcmp(plugname, m->plugname) == 0)
4117c478bd9Sstevel@tonic-gate 		return SASL_OK;
4127c478bd9Sstevel@tonic-gate 	m = m->next;
4137c478bd9Sstevel@tonic-gate     }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate     result = LOCK_MUTEX(&server_plug_mutex);
4167c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
4177c478bd9Sstevel@tonic-gate 	return result;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4207c478bd9Sstevel@tonic-gate     entry_point = (sasl_server_plug_init_t *)p;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate     /* call into the shared library asking for information about it */
4237c478bd9Sstevel@tonic-gate     /* version is filled in with the version of the plugin */
4247c478bd9Sstevel@tonic-gate     result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version,
4257c478bd9Sstevel@tonic-gate 			 &pluglist, &plugcount);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
4287c478bd9Sstevel@tonic-gate     sun_reg = _is_sun_reg(pluglist);
4297c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4327c478bd9Sstevel@tonic-gate     if (result != SASL_OK) {
4337c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_plug_mutex);
4347c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks,
4357c478bd9Sstevel@tonic-gate 		   SASL_LOG_DEBUG,
4367c478bd9Sstevel@tonic-gate 		   "server add_plugin entry_point error %z", result);
4377c478bd9Sstevel@tonic-gate #else
4387c478bd9Sstevel@tonic-gate     if ((result != SASL_OK) && (result != SASL_NOUSER)) {
4397c478bd9Sstevel@tonic-gate 	_sasl_log(NULL, SASL_LOG_DEBUG,
4407c478bd9Sstevel@tonic-gate 		  "server add_plugin entry_point error %z\n", result);
4417c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4427c478bd9Sstevel@tonic-gate 	return result;
4437c478bd9Sstevel@tonic-gate     }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate     /* Make sure plugin is using the same SASL version as us */
4467c478bd9Sstevel@tonic-gate     if (version != SASL_SERVER_PLUG_VERSION)
4477c478bd9Sstevel@tonic-gate     {
4487c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4497c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_plug_mutex);
4507c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks,
4517c478bd9Sstevel@tonic-gate 		   SASL_LOG_ERR, "version mismatch on plugin");
4527c478bd9Sstevel@tonic-gate #else
4537c478bd9Sstevel@tonic-gate 	_sasl_log(NULL, SASL_LOG_ERR,
4547c478bd9Sstevel@tonic-gate 		  "version mismatch on plugin");
4557c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4567c478bd9Sstevel@tonic-gate 	return SASL_BADVERS;
4577c478bd9Sstevel@tonic-gate     }
4587c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4597c478bd9Sstevel@tonic-gate     /* Check plugins to make sure mech_name is non-NULL */
4607c478bd9Sstevel@tonic-gate     for (lupe=0;lupe < plugcount ;lupe++) {
4617c478bd9Sstevel@tonic-gate 	if (pluglist[lupe].mech_name == NULL)
4627c478bd9Sstevel@tonic-gate 	     break;
4637c478bd9Sstevel@tonic-gate     }
4647c478bd9Sstevel@tonic-gate     if (lupe < plugcount) {
4657c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4667c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_plug_mutex);
4677c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks,
4687c478bd9Sstevel@tonic-gate 		   SASL_LOG_ERR, "invalid server plugin %s", plugname);
4697c478bd9Sstevel@tonic-gate #else
4707c478bd9Sstevel@tonic-gate 	_sasl_log(NULL, SASL_LOG_ERR, "invalid server plugin %s", plugname);
4717c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4727c478bd9Sstevel@tonic-gate 	return SASL_BADPROT;
4737c478bd9Sstevel@tonic-gate     }
4747c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate     for (lupe=0;lupe < plugcount ;lupe++)
4777c478bd9Sstevel@tonic-gate     {
4787c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4797c478bd9Sstevel@tonic-gate 	if (!load_mech(gctx, pluglist->mech_name)) {
4807c478bd9Sstevel@tonic-gate 	     pluglist++;
4817c478bd9Sstevel@tonic-gate 	     continue;
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	nplug++;
4847c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4857c478bd9Sstevel@tonic-gate 	mech = sasl_ALLOC(sizeof(mechanism_t));
4867c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4877c478bd9Sstevel@tonic-gate 	if (! mech) {
4887c478bd9Sstevel@tonic-gate 	    UNLOCK_MUTEX(&server_plug_mutex);
4897c478bd9Sstevel@tonic-gate 	    return SASL_NOMEM;
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	mech->glob_context = pluglist->glob_context;
4937c478bd9Sstevel@tonic-gate #else
4947c478bd9Sstevel@tonic-gate 	if (! mech) return SASL_NOMEM;
4957c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	mech->plug=pluglist++;
4987c478bd9Sstevel@tonic-gate 	if(_sasl_strdup(plugname, &mech->plugname, NULL) != SASL_OK) {
4997c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5007c478bd9Sstevel@tonic-gate 	    UNLOCK_MUTEX(&server_plug_mutex);
5017c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5027c478bd9Sstevel@tonic-gate 	    sasl_FREE(mech);
5037c478bd9Sstevel@tonic-gate 	    return SASL_NOMEM;
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 	mech->version = version;
5067c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5077c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
5087c478bd9Sstevel@tonic-gate 	mech->sun_reg = sun_reg;
5097c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/* whether this mech actually has any users in it's db */
5127c478bd9Sstevel@tonic-gate 	mech->condition = SASL_OK;
5137c478bd9Sstevel@tonic-gate #else
5147c478bd9Sstevel@tonic-gate 	/* whether this mech actually has any users in it's db */
5157c478bd9Sstevel@tonic-gate 	mech->condition = result; /* SASL_OK or SASL_NOUSER */
5167c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	mech->next = mechlist->mech_list;
5197c478bd9Sstevel@tonic-gate 	mechlist->mech_list = mech;
5207c478bd9Sstevel@tonic-gate 	mechlist->mech_length++;
5217c478bd9Sstevel@tonic-gate     }
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5247c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&server_plug_mutex);
5257c478bd9Sstevel@tonic-gate     return (nplug == 0) ? SASL_NOMECH : SASL_OK;
5267c478bd9Sstevel@tonic-gate #else
5277c478bd9Sstevel@tonic-gate     return SASL_OK;
5287c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5327c478bd9Sstevel@tonic-gate static int server_done(_sasl_global_context_t *gctx) {
5337c478bd9Sstevel@tonic-gate   mech_list_t *mechlist = gctx->mechlist;
5347c478bd9Sstevel@tonic-gate   _sasl_path_info_t *path_info, *p;
5357c478bd9Sstevel@tonic-gate #else
5367c478bd9Sstevel@tonic-gate static int server_done(void) {
5377c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5387c478bd9Sstevel@tonic-gate   mechanism_t *m;
5397c478bd9Sstevel@tonic-gate   mechanism_t *prevm;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5427c478bd9Sstevel@tonic-gate   if(!gctx->sasl_server_active)
5437c478bd9Sstevel@tonic-gate       return SASL_NOTINIT;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate   if (LOCK_MUTEX(&server_active_mutex) < 0) {
5467c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
5477c478bd9Sstevel@tonic-gate   }
5487c478bd9Sstevel@tonic-gate   gctx->sasl_server_active--;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate   if(gctx->sasl_server_active) {
5517c478bd9Sstevel@tonic-gate       /* Don't de-init yet! Our refcount is nonzero. */
5527c478bd9Sstevel@tonic-gate       UNLOCK_MUTEX(&server_active_mutex);
5537c478bd9Sstevel@tonic-gate       return SASL_CONTINUE;
5547c478bd9Sstevel@tonic-gate   }
5557c478bd9Sstevel@tonic-gate #else
5567c478bd9Sstevel@tonic-gate   if(!_sasl_server_active)
5577c478bd9Sstevel@tonic-gate       return SASL_NOTINIT;
5587c478bd9Sstevel@tonic-gate   else
5597c478bd9Sstevel@tonic-gate       _sasl_server_active--;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate   if(_sasl_server_active) {
5627c478bd9Sstevel@tonic-gate       /* Don't de-init yet! Our refcount is nonzero. */
5637c478bd9Sstevel@tonic-gate       return SASL_CONTINUE;
5647c478bd9Sstevel@tonic-gate   }
5657c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate   if (mechlist != NULL)
5687c478bd9Sstevel@tonic-gate   {
5697c478bd9Sstevel@tonic-gate       m=mechlist->mech_list; /* m point to beginning of the list */
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate       while (m!=NULL)
5727c478bd9Sstevel@tonic-gate       {
5737c478bd9Sstevel@tonic-gate 	  prevm=m;
5747c478bd9Sstevel@tonic-gate 	  m=m->next;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	  if (prevm->plug->mech_free) {
5777c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5787c478bd9Sstevel@tonic-gate 	      prevm->plug->mech_free(prevm->glob_context,
5797c478bd9Sstevel@tonic-gate #else
5807c478bd9Sstevel@tonic-gate 	      prevm->plug->mech_free(prevm->plug->glob_context,
5817c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5827c478bd9Sstevel@tonic-gate 				     mechlist->utils);
5837c478bd9Sstevel@tonic-gate 	  }
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	  sasl_FREE(prevm->plugname);
5867c478bd9Sstevel@tonic-gate 	  sasl_FREE(prevm);
5877c478bd9Sstevel@tonic-gate       }
5887c478bd9Sstevel@tonic-gate       _sasl_free_utils(&mechlist->utils);
5897c478bd9Sstevel@tonic-gate       sasl_MUTEX_FREE(mechlist->mutex);
5907c478bd9Sstevel@tonic-gate       sasl_FREE(mechlist);
5917c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5927c478bd9Sstevel@tonic-gate       gctx->mechlist = NULL;
5937c478bd9Sstevel@tonic-gate #else
5947c478bd9Sstevel@tonic-gate       mechlist = NULL;
5957c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5967c478bd9Sstevel@tonic-gate   }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate   /* Free the auxprop plugins */
5997c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
6007c478bd9Sstevel@tonic-gate   _sasl_auxprop_free(gctx);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate   gctx->server_global_callbacks.callbacks = NULL;
6037c478bd9Sstevel@tonic-gate   gctx->server_global_callbacks.appname = NULL;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate   p = gctx->splug_path_info;
6067c478bd9Sstevel@tonic-gate   while((path_info = p) != NULL) {
6077c478bd9Sstevel@tonic-gate     sasl_FREE(path_info->path);
6087c478bd9Sstevel@tonic-gate     p = path_info->next;
6097c478bd9Sstevel@tonic-gate     sasl_FREE(path_info);
6107c478bd9Sstevel@tonic-gate   }
6117c478bd9Sstevel@tonic-gate   gctx->splug_path_info = NULL;
6127c478bd9Sstevel@tonic-gate   UNLOCK_MUTEX(&server_active_mutex);
6137c478bd9Sstevel@tonic-gate #else
6147c478bd9Sstevel@tonic-gate   _sasl_auxprop_free();
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate   global_callbacks.callbacks = NULL;
6177c478bd9Sstevel@tonic-gate   global_callbacks.appname = NULL;
6187c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate   return SASL_OK;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate static int server_idle(sasl_conn_t *conn)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate     mechanism_t *m;
6267c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
6277c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx;
6287c478bd9Sstevel@tonic-gate     mech_list_t *mechlist;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate     if (conn == NULL)
6317c478bd9Sstevel@tonic-gate         gctx = _sasl_gbl_ctx();
6327c478bd9Sstevel@tonic-gate     else
6337c478bd9Sstevel@tonic-gate         gctx = conn->gctx;
6347c478bd9Sstevel@tonic-gate   mechlist = gctx->mechlist;
6357c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
6367c478bd9Sstevel@tonic-gate     if (! mechlist)
6377c478bd9Sstevel@tonic-gate 	return 0;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate     for (m = mechlist->mech_list;
6407c478bd9Sstevel@tonic-gate 	 m!=NULL;
6417c478bd9Sstevel@tonic-gate 	 m = m->next)
6427c478bd9Sstevel@tonic-gate 	if (m->plug->idle
6437c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
6447c478bd9Sstevel@tonic-gate 	    &&  m->plug->idle(m->glob_context,
6457c478bd9Sstevel@tonic-gate #else
6467c478bd9Sstevel@tonic-gate 	    &&  m->plug->idle(m->plug->glob_context,
6477c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
6487c478bd9Sstevel@tonic-gate 			      conn,
6497c478bd9Sstevel@tonic-gate 			      conn ? ((sasl_server_conn_t *)conn)->sparams : NULL))
6507c478bd9Sstevel@tonic-gate 	    return 1;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate     return 0;
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
6567c478bd9Sstevel@tonic-gate static int load_config(_sasl_global_context_t *gctx,
6577c478bd9Sstevel@tonic-gate 		       const sasl_callback_t *verifyfile_cb)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate   int result;
6607c478bd9Sstevel@tonic-gate   const char *conf_to_config = NULL;
6617c478bd9Sstevel@tonic-gate   const char *conf_file = NULL;
6627c478bd9Sstevel@tonic-gate   int conf_len;
6637c478bd9Sstevel@tonic-gate   sasl_global_callbacks_t global_callbacks = gctx->server_global_callbacks;
6647c478bd9Sstevel@tonic-gate   char *alloc_file_name=NULL;
6657c478bd9Sstevel@tonic-gate   int len;
6667c478bd9Sstevel@tonic-gate   const sasl_callback_t *getconf_cb=NULL;
6677c478bd9Sstevel@tonic-gate   struct stat buf;
6687c478bd9Sstevel@tonic-gate   int full_file = 0;
6697c478bd9Sstevel@tonic-gate   int file_exists = 0;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate   /* get the path to the plugins; for now the config file will reside there */
6727c478bd9Sstevel@tonic-gate   getconf_cb = _sasl_find_getconf_callback(global_callbacks.callbacks);
6737c478bd9Sstevel@tonic-gate   if (getconf_cb==NULL) return SASL_BADPARAM;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate   result = ((sasl_getpath_t *)(getconf_cb->proc))(getconf_cb->context,
6767c478bd9Sstevel@tonic-gate 						  &conf_to_config);
6777c478bd9Sstevel@tonic-gate   if (result!=SASL_OK) goto done;
6787c478bd9Sstevel@tonic-gate   if (conf_to_config == NULL) conf_to_config = "";
6797c478bd9Sstevel@tonic-gate   else {
6807c478bd9Sstevel@tonic-gate 	if (stat(conf_to_config, &buf))
6817c478bd9Sstevel@tonic-gate 		goto process_file;
6827c478bd9Sstevel@tonic-gate 	full_file = !S_ISDIR(buf.st_mode);
6837c478bd9Sstevel@tonic-gate   }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate   if (!full_file) {
6867c478bd9Sstevel@tonic-gate     conf_len = strlen(conf_to_config);
6877c478bd9Sstevel@tonic-gate     len = strlen(conf_to_config)+2+ strlen(global_callbacks.appname)+5+1;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate     if (len > PATH_MAX ) {
6907c478bd9Sstevel@tonic-gate       result = SASL_FAIL;
6917c478bd9Sstevel@tonic-gate       goto done;
6927c478bd9Sstevel@tonic-gate     }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate     /* construct the filename for the config file */
6957c478bd9Sstevel@tonic-gate     alloc_file_name = sasl_ALLOC(len);
6967c478bd9Sstevel@tonic-gate     if (! alloc_file_name) {
6977c478bd9Sstevel@tonic-gate         result = SASL_NOMEM;
6987c478bd9Sstevel@tonic-gate         goto done;
6997c478bd9Sstevel@tonic-gate     }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate     snprintf(alloc_file_name, len, "%.*s/%s.conf", conf_len, conf_to_config,
7027c478bd9Sstevel@tonic-gate 	   global_callbacks.appname);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate   }
7057c478bd9Sstevel@tonic-gate   conf_file = full_file ? conf_to_config : alloc_file_name;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate   if (full_file || stat(conf_file, &buf) == 0)
7087c478bd9Sstevel@tonic-gate 	file_exists = S_ISREG(buf.st_mode);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate process_file:
7117c478bd9Sstevel@tonic-gate   /* Check to see if anything has changed */
7127c478bd9Sstevel@tonic-gate   if (file_exists && gctx->config_path != NULL &&
7137c478bd9Sstevel@tonic-gate 	strcmp(conf_file, gctx->config_path) == 0 &&
7147c478bd9Sstevel@tonic-gate 	gctx->config_last_read == buf.st_mtime) {
7157c478bd9Sstevel@tonic-gate     /* File has not changed */
7167c478bd9Sstevel@tonic-gate     goto done;
7177c478bd9Sstevel@tonic-gate   } else if (gctx->config_path == NULL) {
7187c478bd9Sstevel@tonic-gate     /* No new file, nothing has changed  */
7197c478bd9Sstevel@tonic-gate     if (!file_exists)
7207c478bd9Sstevel@tonic-gate 	goto done;
7217c478bd9Sstevel@tonic-gate   } else {
7227c478bd9Sstevel@tonic-gate     sasl_config_free(gctx);
7237c478bd9Sstevel@tonic-gate     if (!file_exists) {
7247c478bd9Sstevel@tonic-gate 	gctx->config_path = NULL;
7257c478bd9Sstevel@tonic-gate 	goto done;
7267c478bd9Sstevel@tonic-gate     }
7277c478bd9Sstevel@tonic-gate   }
7287c478bd9Sstevel@tonic-gate   gctx->config_last_read = buf.st_mtime;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate   /* Ask the application if it's safe to use this file */
7317c478bd9Sstevel@tonic-gate   result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
7327c478bd9Sstevel@tonic-gate 		conf_file, SASL_VRFY_CONF);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate   /* returns continue if this file is to be skipped */
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate   /* returns SASL_CONTINUE if doesn't exist
7377c478bd9Sstevel@tonic-gate    * if doesn't exist we can continue using default behavior
7387c478bd9Sstevel@tonic-gate    */
7397c478bd9Sstevel@tonic-gate   if (result==SASL_OK)
7407c478bd9Sstevel@tonic-gate     result=sasl_config_init(gctx, conf_file);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate  done:
7437c478bd9Sstevel@tonic-gate   if (alloc_file_name) sasl_FREE(alloc_file_name);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate   return result;
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate #else
7487c478bd9Sstevel@tonic-gate static int load_config(const sasl_callback_t *verifyfile_cb)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate   int result;
7517c478bd9Sstevel@tonic-gate   const char *path_to_config=NULL;
7527c478bd9Sstevel@tonic-gate   const char *c;
7537c478bd9Sstevel@tonic-gate   unsigned path_len;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate   char *config_filename=NULL;
7567c478bd9Sstevel@tonic-gate   int len;
7577c478bd9Sstevel@tonic-gate   const sasl_callback_t *getpath_cb=NULL;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate   /* get the path to the plugins; for now the config file will reside there */
7607c478bd9Sstevel@tonic-gate   getpath_cb=_sasl_find_getpath_callback( global_callbacks.callbacks );
7617c478bd9Sstevel@tonic-gate   if (getpath_cb==NULL) return SASL_BADPARAM;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate   /* getpath_cb->proc MUST be a sasl_getpath_t; if only c had a type
7647c478bd9Sstevel@tonic-gate      system */
7657c478bd9Sstevel@tonic-gate   result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
7667c478bd9Sstevel@tonic-gate 						  &path_to_config);
7677c478bd9Sstevel@tonic-gate   if (result!=SASL_OK) goto done;
7687c478bd9Sstevel@tonic-gate   if (path_to_config == NULL) path_to_config = "";
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate   c = strchr(path_to_config, PATHS_DELIMITER);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate   /* length = length of path + '/' + length of appname + ".conf" + 1
7737c478bd9Sstevel@tonic-gate      for '\0' */
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate   if(c != NULL)
7767c478bd9Sstevel@tonic-gate     path_len = c - path_to_config;
7777c478bd9Sstevel@tonic-gate   else
7787c478bd9Sstevel@tonic-gate     path_len = strlen(path_to_config);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate   len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate   if (len > PATH_MAX ) {
7837c478bd9Sstevel@tonic-gate       result = SASL_FAIL;
7847c478bd9Sstevel@tonic-gate       goto done;
7857c478bd9Sstevel@tonic-gate   }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate   /* construct the filename for the config file */
7887c478bd9Sstevel@tonic-gate   config_filename = sasl_ALLOC(len);
7897c478bd9Sstevel@tonic-gate   if (! config_filename) {
7907c478bd9Sstevel@tonic-gate       result = SASL_NOMEM;
7917c478bd9Sstevel@tonic-gate       goto done;
7927c478bd9Sstevel@tonic-gate   }
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate   snprintf(config_filename, len, "%.*s/%s.conf", path_len, path_to_config,
7957c478bd9Sstevel@tonic-gate 	   global_callbacks.appname);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate   /* Ask the application if it's safe to use this file */
7987c478bd9Sstevel@tonic-gate   result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
7997c478bd9Sstevel@tonic-gate 					config_filename, SASL_VRFY_CONF);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate   /* returns continue if this file is to be skipped */
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate   /* returns SASL_CONTINUE if doesn't exist
8047c478bd9Sstevel@tonic-gate    * if doesn't exist we can continue using default behavior
8057c478bd9Sstevel@tonic-gate    */
8067c478bd9Sstevel@tonic-gate   if (result==SASL_OK)
8077c478bd9Sstevel@tonic-gate     result=sasl_config_init(config_filename);
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate  done:
8107c478bd9Sstevel@tonic-gate   if (config_filename) sasl_FREE(config_filename);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate   return result;
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate /*
8177c478bd9Sstevel@tonic-gate  * Verify that all the callbacks are valid
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate static int verify_server_callbacks(const sasl_callback_t *callbacks)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate     if (callbacks == NULL) return SASL_OK;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate     while (callbacks->id != SASL_CB_LIST_END) {
8247c478bd9Sstevel@tonic-gate 	if (callbacks->proc==NULL) return SASL_FAIL;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	callbacks++;
8277c478bd9Sstevel@tonic-gate     }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate     return SASL_OK;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
8337c478bd9Sstevel@tonic-gate static char *grab_field(char *line, char **eofield)
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate     int d = 0;
8367c478bd9Sstevel@tonic-gate     char *field;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate     while (isspace((int) *line)) line++;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate     /* find end of field */
8417c478bd9Sstevel@tonic-gate     while (line[d] && !isspace(((int) line[d]))) d++;
8427c478bd9Sstevel@tonic-gate     field = sasl_ALLOC(d + 1);
8437c478bd9Sstevel@tonic-gate     if (!field) { return NULL; }
8447c478bd9Sstevel@tonic-gate     memcpy(field, line, d);
8457c478bd9Sstevel@tonic-gate     field[d] = '\0';
8467c478bd9Sstevel@tonic-gate     *eofield = line + d;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate     return field;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate struct secflag_map_s {
8527c478bd9Sstevel@tonic-gate     char *name;
8537c478bd9Sstevel@tonic-gate     int value;
8547c478bd9Sstevel@tonic-gate };
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate struct secflag_map_s secflag_map[] = {
8577c478bd9Sstevel@tonic-gate     { "noplaintext", SASL_SEC_NOPLAINTEXT },
8587c478bd9Sstevel@tonic-gate     { "noactive", SASL_SEC_NOACTIVE },
8597c478bd9Sstevel@tonic-gate     { "nodictionary", SASL_SEC_NODICTIONARY },
8607c478bd9Sstevel@tonic-gate     { "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
8617c478bd9Sstevel@tonic-gate     { "noanonymous", SASL_SEC_NOANONYMOUS },
8627c478bd9Sstevel@tonic-gate     { "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
8637c478bd9Sstevel@tonic-gate     { "mutual_auth", SASL_SEC_MUTUAL_AUTH },
8647c478bd9Sstevel@tonic-gate     { NULL, 0x0 }
8657c478bd9Sstevel@tonic-gate };
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate static int parse_mechlist_file(const char *mechlistfile)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate     FILE *f;
8707c478bd9Sstevel@tonic-gate     char buf[1024];
8717c478bd9Sstevel@tonic-gate     char *t, *ptr;
8727c478bd9Sstevel@tonic-gate     int r = 0;
8737c478bd9Sstevel@tonic-gate 
874*004388ebScasper     f = fopen(mechlistfile, "rF");
8757c478bd9Sstevel@tonic-gate     if (!f) return SASL_FAIL;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate     r = SASL_OK;
8787c478bd9Sstevel@tonic-gate     while (fgets(buf, sizeof(buf), f) != NULL) {
8797c478bd9Sstevel@tonic-gate 	mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t));
8807c478bd9Sstevel@tonic-gate 	sasl_server_plug_t *nplug;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (n == NULL) { r = SASL_NOMEM; break; }
8837c478bd9Sstevel@tonic-gate 	n->version = SASL_SERVER_PLUG_VERSION;
8847c478bd9Sstevel@tonic-gate 	n->condition = SASL_CONTINUE;
8857c478bd9Sstevel@tonic-gate 	nplug = sasl_ALLOC(sizeof(sasl_server_plug_t));
8867c478bd9Sstevel@tonic-gate 	if (nplug == NULL) { r = SASL_NOMEM; break; }
8877c478bd9Sstevel@tonic-gate 	memset(nplug, 0, sizeof(sasl_server_plug_t));
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* each line is:
8907c478bd9Sstevel@tonic-gate 	   plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
8917c478bd9Sstevel@tonic-gate 	*/
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* grab file */
8947c478bd9Sstevel@tonic-gate 	n->f = grab_field(buf, &ptr);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	/* grab mech_name */
8977c478bd9Sstevel@tonic-gate 	nplug->mech_name = grab_field(ptr, &ptr);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	/* grab max_ssf */
9007c478bd9Sstevel@tonic-gate 	nplug->max_ssf = strtol(ptr, &ptr, 10);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	/* grab security flags */
9037c478bd9Sstevel@tonic-gate 	while (*ptr != '\n') {
9047c478bd9Sstevel@tonic-gate 	    struct secflag_map_s *map;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	    /* read security flag */
9077c478bd9Sstevel@tonic-gate 	    t = grab_field(ptr, &ptr);
9087c478bd9Sstevel@tonic-gate 	    map = secflag_map;
9097c478bd9Sstevel@tonic-gate 	    while (map->name) {
9107c478bd9Sstevel@tonic-gate 		if (!strcasecmp(t, map->name)) {
9117c478bd9Sstevel@tonic-gate 		    nplug->security_flags |= map->value;
9127c478bd9Sstevel@tonic-gate 		    break;
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 		map++;
9157c478bd9Sstevel@tonic-gate 	    }
9167c478bd9Sstevel@tonic-gate 	    if (!map->name) {
9177c478bd9Sstevel@tonic-gate 		_sasl_log(NULL, SASL_LOG_ERR,
9187c478bd9Sstevel@tonic-gate 			  "%s: couldn't identify flag '%s'",
9197c478bd9Sstevel@tonic-gate 			  nplug->mech_name, t);
9207c478bd9Sstevel@tonic-gate 	    }
9217c478bd9Sstevel@tonic-gate 	    free(t);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	/* insert mechanism into mechlist */
9257c478bd9Sstevel@tonic-gate 	n->plug = nplug;
9267c478bd9Sstevel@tonic-gate 	n->next = mechlist->mech_list;
9277c478bd9Sstevel@tonic-gate 	mechlist->mech_list = n;
9287c478bd9Sstevel@tonic-gate 	mechlist->mech_length++;
9297c478bd9Sstevel@tonic-gate     }
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate     fclose(f);
9327c478bd9Sstevel@tonic-gate     return r;
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
9377c478bd9Sstevel@tonic-gate static int _load_server_plugins(_sasl_global_context_t *gctx)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate     int ret;
9407c478bd9Sstevel@tonic-gate     const add_plugin_list_t _ep_list[] = {
9417c478bd9Sstevel@tonic-gate 	{ "sasl_server_plug_init", (add_plugin_t *)_sasl_server_add_plugin },
9427c478bd9Sstevel@tonic-gate 	{ "sasl_auxprop_plug_init", (add_plugin_t *)_sasl_auxprop_add_plugin },
9437c478bd9Sstevel@tonic-gate 	{ "sasl_canonuser_init", (add_plugin_t *)_sasl_canonuser_add_plugin },
9447c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
9457c478bd9Sstevel@tonic-gate     };
9467c478bd9Sstevel@tonic-gate     const sasl_callback_t *callbacks = gctx->server_global_callbacks.callbacks;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate     ret = _sasl_load_plugins(gctx, 1, _ep_list,
9497c478bd9Sstevel@tonic-gate 			     _sasl_find_getpath_callback(callbacks),
9507c478bd9Sstevel@tonic-gate 			     _sasl_find_verifyfile_callback(callbacks));
9517c478bd9Sstevel@tonic-gate     return (ret);
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate /* initialize server drivers, done once per process
9567c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
9577c478bd9Sstevel@tonic-gate  *  callbacks      -- callbacks for all server connections
9587c478bd9Sstevel@tonic-gate  *  appname        -- name of calling application (for config)
9597c478bd9Sstevel@tonic-gate #else
9607c478bd9Sstevel@tonic-gate  *  callbacks      -- callbacks for all server connections; must include
9617c478bd9Sstevel@tonic-gate  *                    getopt callback
9627c478bd9Sstevel@tonic-gate  *  appname        -- name of calling application (for lower level logging)
9637c478bd9Sstevel@tonic-gate  * results:
9647c478bd9Sstevel@tonic-gate  *  state          -- server state
9657c478bd9Sstevel@tonic-gate #endif
9667c478bd9Sstevel@tonic-gate  * returns:
9677c478bd9Sstevel@tonic-gate  *  SASL_OK        -- success
9687c478bd9Sstevel@tonic-gate  *  SASL_BADPARAM  -- error in config file
9697c478bd9Sstevel@tonic-gate  *  SASL_NOMEM     -- memory failure
9707c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
9717c478bd9Sstevel@tonic-gate  *  SASL_BADVERS   -- Mechanism version mismatch
9727c478bd9Sstevel@tonic-gate #endif
9737c478bd9Sstevel@tonic-gate  */
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate int sasl_server_init(const sasl_callback_t *callbacks,
9767c478bd9Sstevel@tonic-gate 		     const char *appname)
9777c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	return _sasl_server_init(NULL, callbacks, appname);
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate int _sasl_server_init(void *ctx, const sasl_callback_t *callbacks,
9837c478bd9Sstevel@tonic-gate 		     const char *appname)
9847c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate     int ret;
9877c478bd9Sstevel@tonic-gate     const sasl_callback_t *vf;
9887c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
9897c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
9907c478bd9Sstevel@tonic-gate #else
9917c478bd9Sstevel@tonic-gate     const char *pluginfile = NULL;
9927c478bd9Sstevel@tonic-gate #ifdef PIC
9937c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
9947c478bd9Sstevel@tonic-gate     void *context;
9957c478bd9Sstevel@tonic-gate #endif
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate     const add_plugin_list_t ep_list[] = {
9987c478bd9Sstevel@tonic-gate 	{ "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin },
9997c478bd9Sstevel@tonic-gate 	{ "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin },
10007c478bd9Sstevel@tonic-gate 	{ "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
10017c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
10027c478bd9Sstevel@tonic-gate     };
10037c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate     /* we require the appname to be non-null and short enough to be a path */
10067c478bd9Sstevel@tonic-gate     if (!appname || strlen(appname) >= PATH_MAX)
10077c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
10107c478bd9Sstevel@tonic-gate     /* Process only one _sasl_server_init() at a time */
10117c478bd9Sstevel@tonic-gate     if (LOCK_MUTEX(&init_server_mutex) < 0)
10127c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
10137c478bd9Sstevel@tonic-gate     if (LOCK_MUTEX(&server_active_mutex) < 0)
10147c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active) {
10177c478bd9Sstevel@tonic-gate 	/* We're already active, just increase our refcount */
10187c478bd9Sstevel@tonic-gate 	/* xxx do something with the callback structure? */
10197c478bd9Sstevel@tonic-gate 	gctx->sasl_server_active++;
10207c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_active_mutex);
10217c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
10227c478bd9Sstevel@tonic-gate 	return SASL_OK;
10237c478bd9Sstevel@tonic-gate     }
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate     ret = _sasl_common_init(gctx, &gctx->server_global_callbacks, 1);
10267c478bd9Sstevel@tonic-gate     if (ret != SASL_OK) {
10277c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_active_mutex);
10287c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
10297c478bd9Sstevel@tonic-gate 	return ret;
10307c478bd9Sstevel@tonic-gate     }
10317c478bd9Sstevel@tonic-gate #else
10327c478bd9Sstevel@tonic-gate     if (_sasl_server_active) {
10337c478bd9Sstevel@tonic-gate 	/* We're already active, just increase our refcount */
10347c478bd9Sstevel@tonic-gate 	/* xxx do something with the callback structure? */
10357c478bd9Sstevel@tonic-gate 	_sasl_server_active++;
10367c478bd9Sstevel@tonic-gate 	return SASL_OK;
10377c478bd9Sstevel@tonic-gate     }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate     ret = _sasl_common_init(&global_callbacks);
10407c478bd9Sstevel@tonic-gate     if (ret != SASL_OK)
10417c478bd9Sstevel@tonic-gate 	return ret;
10427c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate     /* verify that the callbacks look ok */
10457c478bd9Sstevel@tonic-gate     ret = verify_server_callbacks(callbacks);
10467c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
10477c478bd9Sstevel@tonic-gate     if (ret != SASL_OK) {
10487c478bd9Sstevel@tonic-gate 	UNLOCK_MUTEX(&server_active_mutex);
10497c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
10507c478bd9Sstevel@tonic-gate 	return ret;
10517c478bd9Sstevel@tonic-gate     }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate     gctx->server_global_callbacks.callbacks = callbacks;
10547c478bd9Sstevel@tonic-gate     gctx->server_global_callbacks.appname = appname;
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate     /* If we fail now, we have to call server_done */
10577c478bd9Sstevel@tonic-gate     gctx->sasl_server_active = 1;
10587c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&server_active_mutex);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate     /* allocate mechlist and set it to empty */
10617c478bd9Sstevel@tonic-gate     gctx->mechlist = sasl_ALLOC(sizeof(mech_list_t));
10627c478bd9Sstevel@tonic-gate     if (gctx->mechlist == NULL) {
10637c478bd9Sstevel@tonic-gate 	server_done(gctx);
10647c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
10657c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
10667c478bd9Sstevel@tonic-gate     }
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate     ret = init_mechlist(gctx);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate     if (ret != SASL_OK) {
10717c478bd9Sstevel@tonic-gate 	server_done(gctx);
10727c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
10737c478bd9Sstevel@tonic-gate 	return ret;
10747c478bd9Sstevel@tonic-gate     }
10757c478bd9Sstevel@tonic-gate #else
10767c478bd9Sstevel@tonic-gate     if (ret != SASL_OK)
10777c478bd9Sstevel@tonic-gate 	return ret;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate     global_callbacks.callbacks = callbacks;
10807c478bd9Sstevel@tonic-gate     global_callbacks.appname = appname;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate     /* If we fail now, we have to call server_done */
10837c478bd9Sstevel@tonic-gate     _sasl_server_active = 1;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate     /* allocate mechlist and set it to empty */
10867c478bd9Sstevel@tonic-gate     mechlist = sasl_ALLOC(sizeof(mech_list_t));
10877c478bd9Sstevel@tonic-gate     if (mechlist == NULL) {
10887c478bd9Sstevel@tonic-gate 	server_done();
10897c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
10907c478bd9Sstevel@tonic-gate     }
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate     ret = init_mechlist();
10937c478bd9Sstevel@tonic-gate     if (ret != SASL_OK) {
10947c478bd9Sstevel@tonic-gate 	server_done();
10957c478bd9Sstevel@tonic-gate 	return ret;
10967c478bd9Sstevel@tonic-gate     }
10977c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate     vf = _sasl_find_verifyfile_callback(callbacks);
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate     /* load config file if applicable */
11027c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11037c478bd9Sstevel@tonic-gate     ret = load_config(gctx, vf);
11047c478bd9Sstevel@tonic-gate     if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
11057c478bd9Sstevel@tonic-gate 	server_done(gctx);
11067c478bd9Sstevel@tonic-gate   	UNLOCK_MUTEX(&init_server_mutex);
11077c478bd9Sstevel@tonic-gate #else
11087c478bd9Sstevel@tonic-gate     ret = load_config(vf);
11097c478bd9Sstevel@tonic-gate     if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
11107c478bd9Sstevel@tonic-gate 	server_done();
11117c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11127c478bd9Sstevel@tonic-gate 	return ret;
11137c478bd9Sstevel@tonic-gate     }
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate     /* load internal plugins */
11167c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11177c478bd9Sstevel@tonic-gate     _sasl_server_add_plugin(gctx, "EXTERNAL", &external_server_plug_init);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate /* NOTE: plugin_list option not supported in SUN SDK */
11207c478bd9Sstevel@tonic-gate     {
11217c478bd9Sstevel@tonic-gate #else
11227c478bd9Sstevel@tonic-gate     sasl_server_add_plugin("EXTERNAL", &external_server_plug_init);
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate #ifdef PIC
11257c478bd9Sstevel@tonic-gate     /* delayed loading of plugins? (DSO only, as it doesn't
11267c478bd9Sstevel@tonic-gate      * make much [any] sense to delay in the static library case) */
11277c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(NULL, SASL_CB_GETOPT, &getopt, &context)
11287c478bd9Sstevel@tonic-gate 	   == SASL_OK) {
11297c478bd9Sstevel@tonic-gate 	/* No sasl_conn_t was given to getcallback, so we provide the
11307c478bd9Sstevel@tonic-gate 	 * global callbacks structure */
11317c478bd9Sstevel@tonic-gate 	ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL);
11327c478bd9Sstevel@tonic-gate     }
11337c478bd9Sstevel@tonic-gate #endif
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate     if (pluginfile != NULL) {
11367c478bd9Sstevel@tonic-gate 	/* this file should contain a list of plugins available.
11377c478bd9Sstevel@tonic-gate 	   we'll load on demand. */
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/* Ask the application if it's safe to use this file */
11407c478bd9Sstevel@tonic-gate 	ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context,
11417c478bd9Sstevel@tonic-gate 						pluginfile,
11427c478bd9Sstevel@tonic-gate 						SASL_VRFY_CONF);
11437c478bd9Sstevel@tonic-gate 	if (ret != SASL_OK) {
11447c478bd9Sstevel@tonic-gate 	    _sasl_log(NULL, SASL_LOG_ERR,
11457c478bd9Sstevel@tonic-gate 		      "unable to load plugin list %s: %z", pluginfile, ret);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	if (ret == SASL_OK) {
11497c478bd9Sstevel@tonic-gate 	    ret = parse_mechlist_file(pluginfile);
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate     } else {
11527c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11537c478bd9Sstevel@tonic-gate 	/* load all plugins now */
11547c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11557c478bd9Sstevel@tonic-gate 	ret = _load_server_plugins(gctx);
11567c478bd9Sstevel@tonic-gate #else
11577c478bd9Sstevel@tonic-gate 	ret = _sasl_load_plugins(ep_list,
11587c478bd9Sstevel@tonic-gate 				 _sasl_find_getpath_callback(callbacks),
11597c478bd9Sstevel@tonic-gate 				 _sasl_find_verifyfile_callback(callbacks));
11607c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11617c478bd9Sstevel@tonic-gate     }
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11647c478bd9Sstevel@tonic-gate     if (ret == SASL_OK)
11657c478bd9Sstevel@tonic-gate 	ret = _sasl_build_mechlist(gctx);
11667c478bd9Sstevel@tonic-gate     if (ret == SASL_OK) {
11677c478bd9Sstevel@tonic-gate 	gctx->sasl_server_cleanup_hook = &server_done;
11687c478bd9Sstevel@tonic-gate 	gctx->sasl_server_idle_hook = &server_idle;
11697c478bd9Sstevel@tonic-gate     } else {
11707c478bd9Sstevel@tonic-gate 	server_done(gctx);
11717c478bd9Sstevel@tonic-gate     }
11727c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&init_server_mutex);
11737c478bd9Sstevel@tonic-gate #else
11747c478bd9Sstevel@tonic-gate     if (ret == SASL_OK) {
11757c478bd9Sstevel@tonic-gate 	_sasl_server_cleanup_hook = &server_done;
11767c478bd9Sstevel@tonic-gate 	_sasl_server_idle_hook = &server_idle;
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	ret = _sasl_build_mechlist();
11797c478bd9Sstevel@tonic-gate     } else {
11807c478bd9Sstevel@tonic-gate 	server_done();
11817c478bd9Sstevel@tonic-gate     }
11827c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate     return ret;
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate /*
11887c478bd9Sstevel@tonic-gate  * Once we have the users plaintext password we
11897c478bd9Sstevel@tonic-gate  * may want to transition them. That is put entries
11907c478bd9Sstevel@tonic-gate  * for them in the passwd database for other
11917c478bd9Sstevel@tonic-gate  * stronger mechanism
11927c478bd9Sstevel@tonic-gate  *
11937c478bd9Sstevel@tonic-gate  * for example PLAIN -> CRAM-MD5
11947c478bd9Sstevel@tonic-gate  */
11957c478bd9Sstevel@tonic-gate static int
11967c478bd9Sstevel@tonic-gate _sasl_transition(sasl_conn_t * conn,
11977c478bd9Sstevel@tonic-gate 		 const char * pass,
11987c478bd9Sstevel@tonic-gate 		 unsigned passlen)
11997c478bd9Sstevel@tonic-gate {
12007c478bd9Sstevel@tonic-gate     const char *dotrans = "n";
12017c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
12027c478bd9Sstevel@tonic-gate     int result = SASL_OK;
12037c478bd9Sstevel@tonic-gate     void *context;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate     if (! conn)
12067c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate     if (! conn->oparams.authid)
12097c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate     /* check if this is enabled: default to false */
12127c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK)
12137c478bd9Sstevel@tonic-gate     {
12147c478bd9Sstevel@tonic-gate 	getopt(context, NULL, "auto_transition", &dotrans, NULL);
12157c478bd9Sstevel@tonic-gate 	if (dotrans == NULL) dotrans = "n";
12167c478bd9Sstevel@tonic-gate     }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate     if (*dotrans == '1' || *dotrans == 'y' ||
12197c478bd9Sstevel@tonic-gate 	(*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') {
12207c478bd9Sstevel@tonic-gate 	/* ok, it's on! */
12217c478bd9Sstevel@tonic-gate 	result = sasl_setpass(conn,
12227c478bd9Sstevel@tonic-gate 			      conn->oparams.authid,
12237c478bd9Sstevel@tonic-gate 			      pass,
12247c478bd9Sstevel@tonic-gate 			      passlen,
12257c478bd9Sstevel@tonic-gate 			      NULL, 0, 0);
12267c478bd9Sstevel@tonic-gate     }
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate     RETURN(conn,result);
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate /* create context for a single SASL connection
12337c478bd9Sstevel@tonic-gate  *  service        -- registered name of the service using SASL (e.g. "imap")
12347c478bd9Sstevel@tonic-gate  *  serverFQDN     -- Fully qualified domain name of server.  NULL means use
12357c478bd9Sstevel@tonic-gate  *                    gethostname() or equivalent.
12367c478bd9Sstevel@tonic-gate  *                    Useful for multi-homed servers.
12377c478bd9Sstevel@tonic-gate  *  user_realm     -- permits multiple user realms on server, NULL = default
12387c478bd9Sstevel@tonic-gate  *  iplocalport    -- server IPv4/IPv6 domain literal string with port
12397c478bd9Sstevel@tonic-gate  *                    (if NULL, then mechanisms requiring IPaddr are disabled)
12407c478bd9Sstevel@tonic-gate  *  ipremoteport   -- client IPv4/IPv6 domain literal string with port
12417c478bd9Sstevel@tonic-gate  *                    (if NULL, then mechanisms requiring IPaddr are disabled)
12427c478bd9Sstevel@tonic-gate  *  callbacks      -- callbacks (e.g., authorization, lang, new getopt context)
12437c478bd9Sstevel@tonic-gate  *  flags          -- usage flags (see above)
12447c478bd9Sstevel@tonic-gate  * returns:
12457c478bd9Sstevel@tonic-gate  *  pconn          -- new connection context
12467c478bd9Sstevel@tonic-gate  *
12477c478bd9Sstevel@tonic-gate  * returns:
12487c478bd9Sstevel@tonic-gate  *  SASL_OK        -- success
12497c478bd9Sstevel@tonic-gate  *  SASL_NOMEM     -- not enough memory
12507c478bd9Sstevel@tonic-gate  */
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate int sasl_server_new(const char *service,
12537c478bd9Sstevel@tonic-gate 		    const char *serverFQDN,
12547c478bd9Sstevel@tonic-gate 		    const char *user_realm,
12557c478bd9Sstevel@tonic-gate 		    const char *iplocalport,
12567c478bd9Sstevel@tonic-gate 		    const char *ipremoteport,
12577c478bd9Sstevel@tonic-gate 		    const sasl_callback_t *callbacks,
12587c478bd9Sstevel@tonic-gate 		    unsigned flags,
12597c478bd9Sstevel@tonic-gate 		    sasl_conn_t **pconn)
12607c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate     return _sasl_server_new(NULL, service, serverFQDN, user_realm, iplocalport,
12637c478bd9Sstevel@tonic-gate 			   ipremoteport, callbacks, flags, pconn);
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate int _sasl_server_new(void *ctx,
12677c478bd9Sstevel@tonic-gate 		    const char *service,
12687c478bd9Sstevel@tonic-gate 		    const char *serverFQDN,
12697c478bd9Sstevel@tonic-gate 		    const char *user_realm,
12707c478bd9Sstevel@tonic-gate 		    const char *iplocalport,
12717c478bd9Sstevel@tonic-gate 		    const char *ipremoteport,
12727c478bd9Sstevel@tonic-gate 		    const sasl_callback_t *callbacks,
12737c478bd9Sstevel@tonic-gate 		    unsigned flags,
12747c478bd9Sstevel@tonic-gate 		    sasl_conn_t **pconn)
12757c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
12767c478bd9Sstevel@tonic-gate {
12777c478bd9Sstevel@tonic-gate   int result;
12787c478bd9Sstevel@tonic-gate   sasl_server_conn_t *serverconn;
12797c478bd9Sstevel@tonic-gate   sasl_utils_t *utils;
12807c478bd9Sstevel@tonic-gate   sasl_getopt_t *getopt;
12817c478bd9Sstevel@tonic-gate   void *context;
12827c478bd9Sstevel@tonic-gate   const char *log_level;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
12857c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx = (ctx == NULL) ? _sasl_gbl_ctx() : ctx;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate   if (gctx->sasl_server_active==0) return SASL_NOTINIT;
12887c478bd9Sstevel@tonic-gate #else
12897c478bd9Sstevel@tonic-gate   if (_sasl_server_active==0) return SASL_NOTINIT;
12907c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
12917c478bd9Sstevel@tonic-gate   if (! pconn) return SASL_FAIL;
12927c478bd9Sstevel@tonic-gate   if (! service) return SASL_FAIL;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate   *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t));
12957c478bd9Sstevel@tonic-gate   if (*pconn==NULL) return SASL_NOMEM;
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate   memset(*pconn, 0, sizeof(sasl_server_conn_t));
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13007c478bd9Sstevel@tonic-gate   (*pconn)->gctx = gctx;
13017c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate   serverconn = (sasl_server_conn_t *)*pconn;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate   /* make sparams */
13067c478bd9Sstevel@tonic-gate   serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t));
13077c478bd9Sstevel@tonic-gate   if (serverconn->sparams==NULL)
13087c478bd9Sstevel@tonic-gate       MEMERROR(*pconn);
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate   memset(serverconn->sparams, 0, sizeof(sasl_server_params_t));
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate   (*pconn)->destroy_conn = &server_dispose;
13137c478bd9Sstevel@tonic-gate   result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER,
13147c478bd9Sstevel@tonic-gate 			   &server_idle, serverFQDN,
13157c478bd9Sstevel@tonic-gate 			   iplocalport, ipremoteport,
13167c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13177c478bd9Sstevel@tonic-gate 			   callbacks, &gctx->server_global_callbacks);
13187c478bd9Sstevel@tonic-gate #else
13197c478bd9Sstevel@tonic-gate 			   callbacks, &global_callbacks);
13207c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13217c478bd9Sstevel@tonic-gate   if (result != SASL_OK)
13227c478bd9Sstevel@tonic-gate       goto done_error;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate   /* set util functions - need to do rest */
13267c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13277c478bd9Sstevel@tonic-gate   utils=_sasl_alloc_utils(gctx, *pconn, &gctx->server_global_callbacks);
13287c478bd9Sstevel@tonic-gate #else
13297c478bd9Sstevel@tonic-gate   utils=_sasl_alloc_utils(*pconn, &global_callbacks);
13307c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13317c478bd9Sstevel@tonic-gate   if (!utils) {
13327c478bd9Sstevel@tonic-gate       result = SASL_NOMEM;
13337c478bd9Sstevel@tonic-gate       goto done_error;
13347c478bd9Sstevel@tonic-gate   }
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13377c478bd9Sstevel@tonic-gate   utils->checkpass = &_sasl_checkpass;
13387c478bd9Sstevel@tonic-gate #else /* _SUN_SDK_ */
13397c478bd9Sstevel@tonic-gate   utils->checkpass = &sasl_checkpass;
13407c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate   /* Setup the propctx -> We'll assume the default size */
13437c478bd9Sstevel@tonic-gate   serverconn->sparams->propctx=prop_new(0);
13447c478bd9Sstevel@tonic-gate   if(!serverconn->sparams->propctx) {
13457c478bd9Sstevel@tonic-gate       result = SASL_NOMEM;
13467c478bd9Sstevel@tonic-gate       goto done_error;
13477c478bd9Sstevel@tonic-gate   }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate   serverconn->sparams->service = (*pconn)->service;
13507c478bd9Sstevel@tonic-gate   serverconn->sparams->servicelen = strlen((*pconn)->service);
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13537c478bd9Sstevel@tonic-gate   serverconn->sparams->appname = gctx->server_global_callbacks.appname;
13547c478bd9Sstevel@tonic-gate   serverconn->sparams->applen = strlen(gctx->server_global_callbacks.appname);
13557c478bd9Sstevel@tonic-gate #else
13567c478bd9Sstevel@tonic-gate   serverconn->sparams->appname = global_callbacks.appname;
13577c478bd9Sstevel@tonic-gate   serverconn->sparams->applen = strlen(global_callbacks.appname);
13587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate   serverconn->sparams->serverFQDN = (*pconn)->serverFQDN;
13617c478bd9Sstevel@tonic-gate   serverconn->sparams->slen = strlen((*pconn)->serverFQDN);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate   if (user_realm) {
13647c478bd9Sstevel@tonic-gate       result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL);
13657c478bd9Sstevel@tonic-gate       serverconn->sparams->urlen = strlen(user_realm);
13667c478bd9Sstevel@tonic-gate       serverconn->sparams->user_realm = serverconn->user_realm;
13677c478bd9Sstevel@tonic-gate   } else {
13687c478bd9Sstevel@tonic-gate       serverconn->user_realm = NULL;
13697c478bd9Sstevel@tonic-gate       /* the sparams is already zeroed */
13707c478bd9Sstevel@tonic-gate   }
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
13737c478bd9Sstevel@tonic-gate   serverconn->sparams->iplocalport = (*pconn)->iplocalport;
13747c478bd9Sstevel@tonic-gate   serverconn->sparams->iploclen = strlen((*pconn)->iplocalport);
13757c478bd9Sstevel@tonic-gate   serverconn->sparams->ipremoteport = (*pconn)->ipremoteport;
13767c478bd9Sstevel@tonic-gate   serverconn->sparams->ipremlen = strlen((*pconn)->ipremoteport);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate   serverconn->sparams->callbacks = callbacks;
13797c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate   log_level = NULL;
13827c478bd9Sstevel@tonic-gate   if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
13837c478bd9Sstevel@tonic-gate     getopt(context, NULL, "log_level", &log_level, NULL);
13847c478bd9Sstevel@tonic-gate   }
13857c478bd9Sstevel@tonic-gate   serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate   serverconn->sparams->utils = utils;
13887c478bd9Sstevel@tonic-gate   serverconn->sparams->transition = &_sasl_transition;
13897c478bd9Sstevel@tonic-gate   serverconn->sparams->canon_user = &_sasl_canon_user;
13907c478bd9Sstevel@tonic-gate   serverconn->sparams->props = serverconn->base.props;
13917c478bd9Sstevel@tonic-gate   serverconn->sparams->flags = flags;
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate   if(result == SASL_OK) return SASL_OK;
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate  done_error:
13967c478bd9Sstevel@tonic-gate   _sasl_conn_dispose(*pconn);
13977c478bd9Sstevel@tonic-gate   sasl_FREE(*pconn);
13987c478bd9Sstevel@tonic-gate   *pconn = NULL;
13997c478bd9Sstevel@tonic-gate   return result;
14007c478bd9Sstevel@tonic-gate }
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate /*
14037c478bd9Sstevel@tonic-gate  * The rule is:
14047c478bd9Sstevel@tonic-gate  * IF mech strength + external strength < min ssf THEN FAIL
14057c478bd9Sstevel@tonic-gate  * We also have to look at the security properties and make sure
14067c478bd9Sstevel@tonic-gate  * that this mechanism has everything we want
14077c478bd9Sstevel@tonic-gate  */
14087c478bd9Sstevel@tonic-gate static int mech_permitted(sasl_conn_t *conn,
14097c478bd9Sstevel@tonic-gate 			  mechanism_t *mech)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn;
14127c478bd9Sstevel@tonic-gate     const sasl_server_plug_t *plug;
14137c478bd9Sstevel@tonic-gate     int myflags;
14147c478bd9Sstevel@tonic-gate     context_list_t *cur;
14157c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
14167c478bd9Sstevel@tonic-gate     void *context;
14177c478bd9Sstevel@tonic-gate     sasl_ssf_t minssf = 0;
14187c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
14197c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx;
14207c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate     if(!conn) return 0;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
14257c478bd9Sstevel@tonic-gate     gctx = conn->gctx;
14267c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate     if(! mech || ! mech->plug) {
14297c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
14307c478bd9Sstevel@tonic-gate 	if(conn) _sasl_log(conn, SASL_LOG_WARN, "Parameter error");
14317c478bd9Sstevel@tonic-gate #else
14327c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
14337c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
14347c478bd9Sstevel@tonic-gate 	return 0;
14357c478bd9Sstevel@tonic-gate     }
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate     plug = mech->plug;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate     /* get the list of allowed mechanisms (default = all) */
14407c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
14417c478bd9Sstevel@tonic-gate             == SASL_OK) {
14427c478bd9Sstevel@tonic-gate 	const char *mlist = NULL;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	getopt(context, NULL, "mech_list", &mlist, NULL);
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	/* if we have a list, check the plugin against it */
14477c478bd9Sstevel@tonic-gate 	if (mlist) {
14487c478bd9Sstevel@tonic-gate 	    const char *cp;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	    while (*mlist) {
14517c478bd9Sstevel@tonic-gate 		for (cp = mlist; *cp && !isspace((int) *cp); cp++);
14527c478bd9Sstevel@tonic-gate 		if (((size_t) (cp - mlist) == strlen(plug->mech_name)) &&
14537c478bd9Sstevel@tonic-gate 		    !strncasecmp(mlist, plug->mech_name,
14547c478bd9Sstevel@tonic-gate 				 strlen(plug->mech_name))) {
14557c478bd9Sstevel@tonic-gate 		    break;
14567c478bd9Sstevel@tonic-gate 		}
14577c478bd9Sstevel@tonic-gate 		mlist = cp;
14587c478bd9Sstevel@tonic-gate 		while (*mlist && isspace((int) *mlist)) mlist++;
14597c478bd9Sstevel@tonic-gate 	    }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	    if (!*mlist) return 0;  /* reached EOS -> not in our list */
14627c478bd9Sstevel@tonic-gate 	}
14637c478bd9Sstevel@tonic-gate     }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate     /* setup parameters for the call to mech_avail */
14667c478bd9Sstevel@tonic-gate     s_conn->sparams->serverFQDN=conn->serverFQDN;
14677c478bd9Sstevel@tonic-gate     s_conn->sparams->service=conn->service;
14687c478bd9Sstevel@tonic-gate     s_conn->sparams->user_realm=s_conn->user_realm;
14697c478bd9Sstevel@tonic-gate     s_conn->sparams->props=conn->props;
14707c478bd9Sstevel@tonic-gate     s_conn->sparams->external_ssf=conn->external.ssf;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate     /* Check if we have banished this one already */
14737c478bd9Sstevel@tonic-gate     for(cur = s_conn->mech_contexts; cur; cur=cur->next) {
14747c478bd9Sstevel@tonic-gate 	if(cur->mech == mech) {
14757c478bd9Sstevel@tonic-gate 	    /* If it's not mech_avail'd, then stop now */
14767c478bd9Sstevel@tonic-gate 	    if(!cur->context) return 0;
14777c478bd9Sstevel@tonic-gate 	    break;
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate     }
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
14827c478bd9Sstevel@tonic-gate     if (!mech->sun_reg) {
14837c478bd9Sstevel@tonic-gate 	s_conn->sparams->props.min_ssf = 0;
14847c478bd9Sstevel@tonic-gate 	s_conn->sparams->props.max_ssf = 0;
14857c478bd9Sstevel@tonic-gate     }
14867c478bd9Sstevel@tonic-gate     s_conn->base.sun_reg = mech->sun_reg;
14877c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
14887c478bd9Sstevel@tonic-gate     if (conn->props.min_ssf < conn->external.ssf) {
14897c478bd9Sstevel@tonic-gate 	minssf = 0;
14907c478bd9Sstevel@tonic-gate     } else {
14917c478bd9Sstevel@tonic-gate 	minssf = conn->props.min_ssf - conn->external.ssf;
14927c478bd9Sstevel@tonic-gate     }
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate     /* Generic mechanism */
14957c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
14967c478bd9Sstevel@tonic-gate     /* If not SUN supplied mech, it has no strength */
14977c478bd9Sstevel@tonic-gate     if (plug->max_ssf < minssf || (minssf > 0 && !mech->sun_reg)) {
14987c478bd9Sstevel@tonic-gate #else
14997c478bd9Sstevel@tonic-gate     if (plug->max_ssf < minssf) {
15007c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
15017c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
15027c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG,
15037c478bd9Sstevel@tonic-gate 		      gettext("mech %s is too weak"), plug->mech_name);
15047c478bd9Sstevel@tonic-gate #else
15057c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG,
15067c478bd9Sstevel@tonic-gate 		      "mech %s is too weak", plug->mech_name);
15077c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
15087c478bd9Sstevel@tonic-gate 	return 0; /* too weak */
15097c478bd9Sstevel@tonic-gate     }
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate     context = NULL;
15127c478bd9Sstevel@tonic-gate     if(plug->mech_avail
15137c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
15147c478bd9Sstevel@tonic-gate        && plug->mech_avail(mech->glob_context,
15157c478bd9Sstevel@tonic-gate #else
15167c478bd9Sstevel@tonic-gate        && plug->mech_avail(plug->glob_context,
15177c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
15187c478bd9Sstevel@tonic-gate 			   s_conn->sparams, (void **)&context) != SASL_OK ) {
15197c478bd9Sstevel@tonic-gate 	/* Mark this mech as no good for this connection */
15207c478bd9Sstevel@tonic-gate 	cur = sasl_ALLOC(sizeof(context_list_t));
15217c478bd9Sstevel@tonic-gate 	if(!cur) {
15227c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
15237c478bd9Sstevel@tonic-gate 	    if(conn) _sasl_log(conn, SASL_LOG_WARN, "Out of Memory");
15247c478bd9Sstevel@tonic-gate #else
15257c478bd9Sstevel@tonic-gate 	    MEMERROR(conn);
15267c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
15277c478bd9Sstevel@tonic-gate 	    return 0;
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 	cur->context = NULL;
15307c478bd9Sstevel@tonic-gate 	cur->mech = mech;
15317c478bd9Sstevel@tonic-gate 	cur->next = s_conn->mech_contexts;
15327c478bd9Sstevel@tonic-gate 	s_conn->mech_contexts = cur;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	/* Error should be set by mech_avail call */
15357c478bd9Sstevel@tonic-gate 	return 0;
15367c478bd9Sstevel@tonic-gate     } else if(context) {
15377c478bd9Sstevel@tonic-gate 	/* Save this context */
15387c478bd9Sstevel@tonic-gate 	cur = sasl_ALLOC(sizeof(context_list_t));
15397c478bd9Sstevel@tonic-gate 	if(!cur) {
15407c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
15417c478bd9Sstevel@tonic-gate 	    if(conn) _sasl_log(conn, SASL_LOG_WARN, "Out of Memory");
15427c478bd9Sstevel@tonic-gate #else
15437c478bd9Sstevel@tonic-gate 	    MEMERROR(conn);
15447c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
15457c478bd9Sstevel@tonic-gate 	    return 0;
15467c478bd9Sstevel@tonic-gate 	}
15477c478bd9Sstevel@tonic-gate 	cur->context = context;
15487c478bd9Sstevel@tonic-gate 	cur->mech = mech;
15497c478bd9Sstevel@tonic-gate 	cur->next = s_conn->mech_contexts;
15507c478bd9Sstevel@tonic-gate 	s_conn->mech_contexts = cur;
15517c478bd9Sstevel@tonic-gate     }
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate     /* Generic mechanism */
15547c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
15557c478bd9Sstevel@tonic-gate     /* If not SUN supplied mech, it has no strength */
15567c478bd9Sstevel@tonic-gate     if (plug->max_ssf < minssf || (minssf > 0 && !mech->sun_reg)) {
15577c478bd9Sstevel@tonic-gate #else
15587c478bd9Sstevel@tonic-gate     if (plug->max_ssf < minssf) {
15597c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
15607c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
15617c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG, gettext("too weak"));
15627c478bd9Sstevel@tonic-gate #else
15637c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG, "too weak");
15647c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
15657c478bd9Sstevel@tonic-gate 	return 0; /* too weak */
15667c478bd9Sstevel@tonic-gate     }
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
15697c478bd9Sstevel@tonic-gate     /* if there are no users in the secrets database we can't use this
15707c478bd9Sstevel@tonic-gate        mechanism */
15717c478bd9Sstevel@tonic-gate     if (mech->condition == SASL_NOUSER) {
15727c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "no users in secrets db");
15737c478bd9Sstevel@tonic-gate 	return 0;
15747c478bd9Sstevel@tonic-gate     }
15757c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate     /* Can it meet our features? */
15787c478bd9Sstevel@tonic-gate     if ((conn->flags & SASL_NEED_PROXY) &&
15797c478bd9Sstevel@tonic-gate 	!(plug->features & SASL_FEAT_ALLOWS_PROXY)) {
15807c478bd9Sstevel@tonic-gate 	return 0;
15817c478bd9Sstevel@tonic-gate     }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate     /* security properties---if there are any flags that differ and are
15847c478bd9Sstevel@tonic-gate        in what the connection are requesting, then fail */
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate     /* special case plaintext */
15877c478bd9Sstevel@tonic-gate     myflags = conn->props.security_flags;
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate     /* if there's an external layer this is no longer plaintext */
15907c478bd9Sstevel@tonic-gate     if ((conn->props.min_ssf <= conn->external.ssf) &&
15917c478bd9Sstevel@tonic-gate 	(conn->external.ssf > 1)) {
15927c478bd9Sstevel@tonic-gate 	myflags &= ~SASL_SEC_NOPLAINTEXT;
15937c478bd9Sstevel@tonic-gate     }
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate     /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
15967c478bd9Sstevel@tonic-gate     if (((myflags ^ plug->security_flags) & myflags) != 0) {
15977c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
15987c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG,
15997c478bd9Sstevel@tonic-gate 		      gettext("security flags do not match required"));
16007c478bd9Sstevel@tonic-gate #else
16017c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG,
16027c478bd9Sstevel@tonic-gate 		      "security flags do not match required");
16037c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
16047c478bd9Sstevel@tonic-gate 	return 0;
16057c478bd9Sstevel@tonic-gate     }
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate     /* Check Features */
16087c478bd9Sstevel@tonic-gate     if(plug->features & SASL_FEAT_GETSECRET) {
16097c478bd9Sstevel@tonic-gate 	/* We no longer support sasl_server_{get,put}secret */
16107c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
16117c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR,
16127c478bd9Sstevel@tonic-gate 		  "mech %s requires unprovided secret facility",
16137c478bd9Sstevel@tonic-gate 		  plug->mech_name);
16147c478bd9Sstevel@tonic-gate #else
16157c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0,
16167c478bd9Sstevel@tonic-gate 		      "mech %s requires unprovided secret facility",
16177c478bd9Sstevel@tonic-gate 		      plug->mech_name);
16187c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
16197c478bd9Sstevel@tonic-gate 	return 0;
16207c478bd9Sstevel@tonic-gate     }
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate     return 1;
16237c478bd9Sstevel@tonic-gate }
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate /*
16267c478bd9Sstevel@tonic-gate  * make the authorization
16277c478bd9Sstevel@tonic-gate  *
16287c478bd9Sstevel@tonic-gate  */
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate static int do_authorization(sasl_server_conn_t *s_conn)
16317c478bd9Sstevel@tonic-gate {
16327c478bd9Sstevel@tonic-gate     int ret;
16337c478bd9Sstevel@tonic-gate     sasl_authorize_t *authproc;
16347c478bd9Sstevel@tonic-gate     void *auth_context;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate     /* now let's see if authname is allowed to proxy for username! */
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate     /* check the proxy callback */
16397c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY,
16407c478bd9Sstevel@tonic-gate 			  &authproc, &auth_context) != SASL_OK) {
16417c478bd9Sstevel@tonic-gate 	INTERROR(&s_conn->base, SASL_NOAUTHZ);
16427c478bd9Sstevel@tonic-gate     }
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate     ret = authproc(&(s_conn->base), auth_context,
16457c478bd9Sstevel@tonic-gate 		   s_conn->base.oparams.user, s_conn->base.oparams.ulen,
16467c478bd9Sstevel@tonic-gate 		   s_conn->base.oparams.authid, s_conn->base.oparams.alen,
16477c478bd9Sstevel@tonic-gate 		   s_conn->user_realm,
16487c478bd9Sstevel@tonic-gate 		   (s_conn->user_realm ? strlen(s_conn->user_realm) : 0),
16497c478bd9Sstevel@tonic-gate 		   s_conn->sparams->propctx);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate     RETURN(&s_conn->base, ret);
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate /* start a mechanism exchange within a connection context
16567c478bd9Sstevel@tonic-gate  *  mech           -- the mechanism name client requested
16577c478bd9Sstevel@tonic-gate  *  clientin       -- client initial response (NUL terminated), NULL if empty
16587c478bd9Sstevel@tonic-gate  *  clientinlen    -- length of initial response
16597c478bd9Sstevel@tonic-gate  *  serverout      -- initial server challenge, NULL if done
16607c478bd9Sstevel@tonic-gate  *                    (library handles freeing this string)
16617c478bd9Sstevel@tonic-gate  *  serveroutlen   -- length of initial server challenge
16627c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
16637c478bd9Sstevel@tonic-gate  * conn            -- the sasl connection
16647c478bd9Sstevel@tonic-gate #else
16657c478bd9Sstevel@tonic-gate  * output:
16667c478bd9Sstevel@tonic-gate  *  pconn          -- the connection negotiation state on success
16677c478bd9Sstevel@tonic-gate #endif
16687c478bd9Sstevel@tonic-gate  *
16697c478bd9Sstevel@tonic-gate  * Same returns as sasl_server_step() or
16707c478bd9Sstevel@tonic-gate  * SASL_NOMECH if mechanism not available.
16717c478bd9Sstevel@tonic-gate  */
16727c478bd9Sstevel@tonic-gate int sasl_server_start(sasl_conn_t *conn,
16737c478bd9Sstevel@tonic-gate 		      const char *mech,
16747c478bd9Sstevel@tonic-gate 		      const char *clientin,
16757c478bd9Sstevel@tonic-gate 		      unsigned clientinlen,
16767c478bd9Sstevel@tonic-gate 		      const char **serverout,
16777c478bd9Sstevel@tonic-gate 		      unsigned *serveroutlen)
16787c478bd9Sstevel@tonic-gate {
16797c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn;
16807c478bd9Sstevel@tonic-gate     int result;
16817c478bd9Sstevel@tonic-gate     context_list_t *cur, **prev;
16827c478bd9Sstevel@tonic-gate     mechanism_t *m;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
16857c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
16867c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
16877c478bd9Sstevel@tonic-gate     mech_list_t *mechlist;
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active==0) return SASL_NOTINIT;
16907c478bd9Sstevel@tonic-gate     if (! conn)
16917c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate     (void)_load_server_plugins(gctx);
16947c478bd9Sstevel@tonic-gate     mechlist = gctx->mechlist;
16957c478bd9Sstevel@tonic-gate     m=mechlist->mech_list;
16967c478bd9Sstevel@tonic-gate     result = load_config(gctx, _sasl_find_verifyfile_callback(
16977c478bd9Sstevel@tonic-gate 	gctx->server_global_callbacks.callbacks));
16987c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
16997c478bd9Sstevel@tonic-gate 	return (result);
17007c478bd9Sstevel@tonic-gate #else
17017c478bd9Sstevel@tonic-gate     if (_sasl_server_active==0) return SASL_NOTINIT;
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate     /* make sure mech is valid mechanism
17047c478bd9Sstevel@tonic-gate        if not return appropriate error */
17057c478bd9Sstevel@tonic-gate     m=mechlist->mech_list;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate     /* check parameters */
17087c478bd9Sstevel@tonic-gate     if(!conn) return SASL_BADPARAM;
17097c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate     if (!mech || ((clientin==NULL) && (clientinlen>0)))
17127c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate     if(serverout) *serverout = NULL;
17157c478bd9Sstevel@tonic-gate     if(serveroutlen) *serveroutlen = 0;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate     while (m!=NULL)
17187c478bd9Sstevel@tonic-gate     {
17197c478bd9Sstevel@tonic-gate 	if ( strcasecmp(mech,m->plug->mech_name)==0)
17207c478bd9Sstevel@tonic-gate 	{
17217c478bd9Sstevel@tonic-gate 	    break;
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 	m=m->next;
17247c478bd9Sstevel@tonic-gate     }
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate     if (m==NULL) {
17277c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
17287c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, gettext("Couldn't find mech %s"), mech);
17297c478bd9Sstevel@tonic-gate #else
17307c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "Couldn't find mech %s", mech);
17317c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
17327c478bd9Sstevel@tonic-gate 	result = SASL_NOMECH;
17337c478bd9Sstevel@tonic-gate 	goto done;
17347c478bd9Sstevel@tonic-gate     }
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
17377c478bd9Sstevel@tonic-gate     server_dispose_mech_contexts(conn);
17387c478bd9Sstevel@tonic-gate #endif /*_SUN_SDK_ */
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate     /* Make sure that we're willing to use this mech */
17417c478bd9Sstevel@tonic-gate     if (! mech_permitted(conn, m)) {
17427c478bd9Sstevel@tonic-gate 	result = SASL_NOMECH;
17437c478bd9Sstevel@tonic-gate 	goto done;
17447c478bd9Sstevel@tonic-gate     }
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
17477c478bd9Sstevel@tonic-gate     if(conn->context) {
17487c478bd9Sstevel@tonic-gate 	s_conn->mech->plug->mech_dispose(conn->context, s_conn->sparams->utils);
17497c478bd9Sstevel@tonic-gate 	conn->context = NULL;
17507c478bd9Sstevel@tonic-gate     }
17517c478bd9Sstevel@tonic-gate     memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
17527c478bd9Sstevel@tonic-gate #else
17537c478bd9Sstevel@tonic-gate     if (m->condition == SASL_CONTINUE) {
17547c478bd9Sstevel@tonic-gate 	sasl_server_plug_init_t *entry_point;
17557c478bd9Sstevel@tonic-gate 	void *library = NULL;
17567c478bd9Sstevel@tonic-gate 	sasl_server_plug_t *pluglist;
17577c478bd9Sstevel@tonic-gate 	int version, plugcount;
17587c478bd9Sstevel@tonic-gate 	int l = 0;
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	/* need to load this plugin */
17617c478bd9Sstevel@tonic-gate 	result = _sasl_get_plugin(m->f,
17627c478bd9Sstevel@tonic-gate 		    _sasl_find_verifyfile_callback(global_callbacks.callbacks),
17637c478bd9Sstevel@tonic-gate 				  &library);
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) {
17667c478bd9Sstevel@tonic-gate 	    result = _sasl_locate_entry(library, "sasl_server_plug_init",
17677c478bd9Sstevel@tonic-gate 					(void **)&entry_point);
17687c478bd9Sstevel@tonic-gate 	}
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) {
17717c478bd9Sstevel@tonic-gate 	    result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION,
17727c478bd9Sstevel@tonic-gate 				 &version, &pluglist, &plugcount);
17737c478bd9Sstevel@tonic-gate 	}
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) {
17767c478bd9Sstevel@tonic-gate 	    /* find the correct mechanism in this plugin */
17777c478bd9Sstevel@tonic-gate 	    for (l = 0; l < plugcount; l++) {
17787c478bd9Sstevel@tonic-gate 		if (!strcasecmp(pluglist[l].mech_name,
17797c478bd9Sstevel@tonic-gate 				m->plug->mech_name)) break;
17807c478bd9Sstevel@tonic-gate 	    }
17817c478bd9Sstevel@tonic-gate 	    if (l == plugcount) {
17827c478bd9Sstevel@tonic-gate 		result = SASL_NOMECH;
17837c478bd9Sstevel@tonic-gate 	    }
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) {
17867c478bd9Sstevel@tonic-gate 	    /* check that the parameters are the same */
17877c478bd9Sstevel@tonic-gate 	    if ((pluglist[l].max_ssf != m->plug->max_ssf) ||
17887c478bd9Sstevel@tonic-gate 		(pluglist[l].security_flags != m->plug->security_flags)) {
17897c478bd9Sstevel@tonic-gate 		_sasl_log(conn, SASL_LOG_ERR,
17907c478bd9Sstevel@tonic-gate 			  "%s: security parameters don't match mechlist file",
17917c478bd9Sstevel@tonic-gate 			  pluglist[l].mech_name);
17927c478bd9Sstevel@tonic-gate 		result = SASL_NOMECH;
17937c478bd9Sstevel@tonic-gate 	    }
17947c478bd9Sstevel@tonic-gate 	}
17957c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) {
17967c478bd9Sstevel@tonic-gate 	    /* copy mechlist over */
17977c478bd9Sstevel@tonic-gate 	    sasl_FREE((sasl_server_plug_t *) m->plug);
17987c478bd9Sstevel@tonic-gate 	    m->plug = &pluglist[l];
17997c478bd9Sstevel@tonic-gate 	    m->condition = SASL_OK;
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) {
18037c478bd9Sstevel@tonic-gate 	    /* The library will eventually be freed, don't sweat it */
18047c478bd9Sstevel@tonic-gate 	    RETURN(conn, result);
18057c478bd9Sstevel@tonic-gate 	}
18067c478bd9Sstevel@tonic-gate     }
18077c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate     /* We used to setup sparams HERE, but now it's done
18107c478bd9Sstevel@tonic-gate        inside of mech_permitted (which is called above) */
18117c478bd9Sstevel@tonic-gate     prev = &s_conn->mech_contexts;
18127c478bd9Sstevel@tonic-gate     for(cur = *prev; cur; prev=&cur->next,cur=cur->next) {
18137c478bd9Sstevel@tonic-gate 	if(cur->mech == m) {
18147c478bd9Sstevel@tonic-gate 	    if(!cur->context) {
18157c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
18167c478bd9Sstevel@tonic-gate 		_sasl_log(conn, SASL_LOG_ERR,
18177c478bd9Sstevel@tonic-gate 			  "Got past mech_permitted with a disallowed mech!");
18187c478bd9Sstevel@tonic-gate #else
18197c478bd9Sstevel@tonic-gate 		sasl_seterror(conn, 0,
18207c478bd9Sstevel@tonic-gate 			      "Got past mech_permitted with a disallowed mech!");
18217c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
18227c478bd9Sstevel@tonic-gate 		return SASL_NOMECH;
18237c478bd9Sstevel@tonic-gate 	    }
18247c478bd9Sstevel@tonic-gate 	    /* If we find it, we need to pull cur out of the
18257c478bd9Sstevel@tonic-gate 	       list so it won't be freed later! */
18267c478bd9Sstevel@tonic-gate 	    (*prev)->next = cur->next;
18277c478bd9Sstevel@tonic-gate 	    conn->context = cur->context;
18287c478bd9Sstevel@tonic-gate 	    sasl_FREE(cur);
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate     }
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate     s_conn->mech = m;
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate     if(!conn->context) {
18357c478bd9Sstevel@tonic-gate 	/* Note that we don't hand over a new challenge */
18367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
18377c478bd9Sstevel@tonic-gate 	result = s_conn->mech->plug->mech_new(s_conn->mech->glob_context,
18387c478bd9Sstevel@tonic-gate #else
18397c478bd9Sstevel@tonic-gate 	result = s_conn->mech->plug->mech_new(s_conn->mech->plug->glob_context,
18407c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
18417c478bd9Sstevel@tonic-gate 					      s_conn->sparams,
18427c478bd9Sstevel@tonic-gate 					      NULL,
18437c478bd9Sstevel@tonic-gate 					      0,
18447c478bd9Sstevel@tonic-gate 					      &(conn->context));
18457c478bd9Sstevel@tonic-gate     } else {
18467c478bd9Sstevel@tonic-gate 	/* the work was already done by mech_avail! */
18477c478bd9Sstevel@tonic-gate 	result = SASL_OK;
18487c478bd9Sstevel@tonic-gate     }
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate     if (result == SASL_OK) {
18517c478bd9Sstevel@tonic-gate          if(clientin) {
18527c478bd9Sstevel@tonic-gate             if(s_conn->mech->plug->features & SASL_FEAT_SERVER_FIRST) {
18537c478bd9Sstevel@tonic-gate                 /* Remote sent first, but mechanism does not support it.
18547c478bd9Sstevel@tonic-gate                  * RFC 2222 says we fail at this point. */
18557c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
18567c478bd9Sstevel@tonic-gate 		_sasl_log(conn, SASL_LOG_ERR,
18577c478bd9Sstevel@tonic-gate                           "Remote sent first but mech does not allow it.");
18587c478bd9Sstevel@tonic-gate #else
18597c478bd9Sstevel@tonic-gate                 sasl_seterror(conn, 0,
18607c478bd9Sstevel@tonic-gate                               "Remote sent first but mech does not allow it.");
18617c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
18627c478bd9Sstevel@tonic-gate                 result = SASL_BADPROT;
18637c478bd9Sstevel@tonic-gate             } else {
18647c478bd9Sstevel@tonic-gate                 /* Mech wants client-first, so let them have it */
18657c478bd9Sstevel@tonic-gate                 result = sasl_server_step(conn,
18667c478bd9Sstevel@tonic-gate                                           clientin, clientinlen,
18677c478bd9Sstevel@tonic-gate                                           serverout, serveroutlen);
18687c478bd9Sstevel@tonic-gate             }
18697c478bd9Sstevel@tonic-gate         } else {
18707c478bd9Sstevel@tonic-gate             if(s_conn->mech->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
18717c478bd9Sstevel@tonic-gate                 /* Mech wants client first anyway, so we should do that */
18727c478bd9Sstevel@tonic-gate                 *serverout = "";
18737c478bd9Sstevel@tonic-gate                 *serveroutlen = 0;
18747c478bd9Sstevel@tonic-gate                 result = SASL_CONTINUE;
18757c478bd9Sstevel@tonic-gate             } else {
18767c478bd9Sstevel@tonic-gate                 /* Mech wants server-first, so let them have it */
18777c478bd9Sstevel@tonic-gate                 result = sasl_server_step(conn,
18787c478bd9Sstevel@tonic-gate                                           clientin, clientinlen,
18797c478bd9Sstevel@tonic-gate                                           serverout, serveroutlen);
18807c478bd9Sstevel@tonic-gate             }
18817c478bd9Sstevel@tonic-gate 	}
18827c478bd9Sstevel@tonic-gate     }
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate  done:
18857c478bd9Sstevel@tonic-gate     if(   result != SASL_OK
18867c478bd9Sstevel@tonic-gate        && result != SASL_CONTINUE
18877c478bd9Sstevel@tonic-gate        && result != SASL_INTERACT) {
18887c478bd9Sstevel@tonic-gate 	if(conn->context) {
18897c478bd9Sstevel@tonic-gate 	    s_conn->mech->plug->mech_dispose(conn->context,
18907c478bd9Sstevel@tonic-gate 					     s_conn->sparams->utils);
18917c478bd9Sstevel@tonic-gate 	    conn->context = NULL;
18927c478bd9Sstevel@tonic-gate 	}
18937c478bd9Sstevel@tonic-gate     }
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate     RETURN(conn,result);
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate /* perform one step of the SASL exchange
19007c478bd9Sstevel@tonic-gate  *  inputlen & input -- client data
19017c478bd9Sstevel@tonic-gate  *                      NULL on first step if no optional client step
19027c478bd9Sstevel@tonic-gate  *  outputlen & output -- set to the server data to transmit
19037c478bd9Sstevel@tonic-gate  *                        to the client in the next step
19047c478bd9Sstevel@tonic-gate  *                        (library handles freeing this)
19057c478bd9Sstevel@tonic-gate  *
19067c478bd9Sstevel@tonic-gate  * returns:
19077c478bd9Sstevel@tonic-gate  *  SASL_OK        -- exchange is complete.
19087c478bd9Sstevel@tonic-gate  *  SASL_CONTINUE  -- indicates another step is necessary.
19097c478bd9Sstevel@tonic-gate  *  SASL_TRANS     -- entry for user exists, but not for mechanism
19107c478bd9Sstevel@tonic-gate  *                    and transition is possible
19117c478bd9Sstevel@tonic-gate  *  SASL_BADPARAM  -- service name needed
19127c478bd9Sstevel@tonic-gate  *  SASL_BADPROT   -- invalid input from client
19137c478bd9Sstevel@tonic-gate  *  ...
19147c478bd9Sstevel@tonic-gate  */
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate int sasl_server_step(sasl_conn_t *conn,
19177c478bd9Sstevel@tonic-gate 		     const char *clientin,
19187c478bd9Sstevel@tonic-gate 		     unsigned clientinlen,
19197c478bd9Sstevel@tonic-gate 		     const char **serverout,
19207c478bd9Sstevel@tonic-gate 		     unsigned *serveroutlen)
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate     int ret;
19237c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;  /* cast */
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
19267c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
19277c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate     /* check parameters */
19307c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active==0) return SASL_NOTINIT;
19317c478bd9Sstevel@tonic-gate #else
19327c478bd9Sstevel@tonic-gate     /* check parameters */
19337c478bd9Sstevel@tonic-gate     if (_sasl_server_active==0) return SASL_NOTINIT;
19347c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
19357c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
19367c478bd9Sstevel@tonic-gate     if ((clientin==NULL) && (clientinlen>0))
19377c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate     /* If we've already done the last send, return! */
19407c478bd9Sstevel@tonic-gate     if(s_conn->sent_last == 1) {
19417c478bd9Sstevel@tonic-gate 	return SASL_OK;
19427c478bd9Sstevel@tonic-gate     }
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate     /* Don't do another step if the plugin told us that we're done */
19457c478bd9Sstevel@tonic-gate     if (conn->oparams.doneflag) {
19467c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag");
19477c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
19487c478bd9Sstevel@tonic-gate     }
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate     if(serverout) *serverout = NULL;
19517c478bd9Sstevel@tonic-gate     if(serveroutlen) *serveroutlen = 0;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate     ret = s_conn->mech->plug->mech_step(conn->context,
19547c478bd9Sstevel@tonic-gate 					s_conn->sparams,
19557c478bd9Sstevel@tonic-gate 					clientin,
19567c478bd9Sstevel@tonic-gate 					clientinlen,
19577c478bd9Sstevel@tonic-gate 					serverout,
19587c478bd9Sstevel@tonic-gate 					serveroutlen,
19597c478bd9Sstevel@tonic-gate 					&conn->oparams);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate     if (ret == SASL_OK) {
19627c478bd9Sstevel@tonic-gate 	ret = do_authorization(s_conn);
19637c478bd9Sstevel@tonic-gate     }
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate     if (ret == SASL_OK) {
19667c478bd9Sstevel@tonic-gate 	/* if we're done, we need to watch out for the following:
19677c478bd9Sstevel@tonic-gate 	 * 1. the mech does server-send-last
19687c478bd9Sstevel@tonic-gate 	 * 2. the protocol does not
19697c478bd9Sstevel@tonic-gate 	 *
19707c478bd9Sstevel@tonic-gate 	 * in this case, return SASL_CONTINUE and remember we are done.
19717c478bd9Sstevel@tonic-gate 	 */
19727c478bd9Sstevel@tonic-gate 	if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) {
19737c478bd9Sstevel@tonic-gate 	    s_conn->sent_last = 1;
19747c478bd9Sstevel@tonic-gate 	    ret = SASL_CONTINUE;
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 	if(!conn->oparams.maxoutbuf) {
19777c478bd9Sstevel@tonic-gate 	    conn->oparams.maxoutbuf = conn->props.maxbufsize;
19787c478bd9Sstevel@tonic-gate 	}
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
19817c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
19827c478bd9Sstevel@tonic-gate 	    _sasl_log(conn, SASL_LOG_ERR,
19837c478bd9Sstevel@tonic-gate 		      "mech did not call canon_user for both authzid "
19847c478bd9Sstevel@tonic-gate 		      "and authid");
19857c478bd9Sstevel@tonic-gate #else
19867c478bd9Sstevel@tonic-gate 	    sasl_seterror(conn, 0,
19877c478bd9Sstevel@tonic-gate 			  "mech did not call canon_user for both authzid " \
19887c478bd9Sstevel@tonic-gate 			  "and authid");
19897c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
19907c478bd9Sstevel@tonic-gate 	    ret = SASL_BADPROT;
19917c478bd9Sstevel@tonic-gate 	}
19927c478bd9Sstevel@tonic-gate     }
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate     if(   ret != SASL_OK
19957c478bd9Sstevel@tonic-gate        && ret != SASL_CONTINUE
19967c478bd9Sstevel@tonic-gate        && ret != SASL_INTERACT) {
19977c478bd9Sstevel@tonic-gate 	if(conn->context) {
19987c478bd9Sstevel@tonic-gate 	    s_conn->mech->plug->mech_dispose(conn->context,
19997c478bd9Sstevel@tonic-gate 					     s_conn->sparams->utils);
20007c478bd9Sstevel@tonic-gate 	    conn->context = NULL;
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate     }
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate     RETURN(conn, ret);
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate /* returns the length of all the mechanisms
20087c478bd9Sstevel@tonic-gate  * added up
20097c478bd9Sstevel@tonic-gate  */
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
20127c478bd9Sstevel@tonic-gate static unsigned mech_names_len(_sasl_global_context_t *gctx)
20137c478bd9Sstevel@tonic-gate {
20147c478bd9Sstevel@tonic-gate   mech_list_t *mechlist = gctx->mechlist;
20157c478bd9Sstevel@tonic-gate #else
20167c478bd9Sstevel@tonic-gate static unsigned mech_names_len()
20177c478bd9Sstevel@tonic-gate {
20187c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
20197c478bd9Sstevel@tonic-gate   mechanism_t *listptr;
20207c478bd9Sstevel@tonic-gate   unsigned result = 0;
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate   for (listptr = mechlist->mech_list;
20237c478bd9Sstevel@tonic-gate        listptr;
20247c478bd9Sstevel@tonic-gate        listptr = listptr->next)
20257c478bd9Sstevel@tonic-gate     result += strlen(listptr->plug->mech_name);
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate   return result;
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate /* This returns a list of mechanisms in a NUL-terminated string
20317c478bd9Sstevel@tonic-gate  *
20327c478bd9Sstevel@tonic-gate  * The default behavior is to seperate with spaces if sep==NULL
20337c478bd9Sstevel@tonic-gate  */
20347c478bd9Sstevel@tonic-gate int _sasl_server_listmech(sasl_conn_t *conn,
20357c478bd9Sstevel@tonic-gate 			  const char *user __attribute__((unused)),
20367c478bd9Sstevel@tonic-gate 			  const char *prefix,
20377c478bd9Sstevel@tonic-gate 			  const char *sep,
20387c478bd9Sstevel@tonic-gate 			  const char *suffix,
20397c478bd9Sstevel@tonic-gate 			  const char **result,
20407c478bd9Sstevel@tonic-gate 			  unsigned *plen,
20417c478bd9Sstevel@tonic-gate 			  int *pcount)
20427c478bd9Sstevel@tonic-gate {
20437c478bd9Sstevel@tonic-gate   int lup;
20447c478bd9Sstevel@tonic-gate   mechanism_t *listptr;
20457c478bd9Sstevel@tonic-gate   int ret;
20467c478bd9Sstevel@tonic-gate   int resultlen;
20477c478bd9Sstevel@tonic-gate   int flag;
20487c478bd9Sstevel@tonic-gate   const char *mysep;
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
20517c478bd9Sstevel@tonic-gate   _sasl_global_context_t *gctx;
20527c478bd9Sstevel@tonic-gate    mech_list_t *mechlist;
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate   if (!conn) return SASL_BADPARAM;
20557c478bd9Sstevel@tonic-gate    /* if there hasn't been a sasl_sever_init() fail */
20567c478bd9Sstevel@tonic-gate   gctx = conn->gctx;
20577c478bd9Sstevel@tonic-gate   if (gctx->sasl_server_active==0) return SASL_NOTINIT;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate   (void)_load_server_plugins(gctx);
20607c478bd9Sstevel@tonic-gate   mechlist = gctx->mechlist;
20617c478bd9Sstevel@tonic-gate #else
20627c478bd9Sstevel@tonic-gate   /* if there hasn't been a sasl_sever_init() fail */
20637c478bd9Sstevel@tonic-gate   if (_sasl_server_active==0) return SASL_NOTINIT;
20647c478bd9Sstevel@tonic-gate   if (!conn) return SASL_BADPARAM;
20657c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
20667c478bd9Sstevel@tonic-gate   if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate   if (! result)
20697c478bd9Sstevel@tonic-gate       PARAMERROR(conn);
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate   if (plen != NULL)
20727c478bd9Sstevel@tonic-gate       *plen = 0;
20737c478bd9Sstevel@tonic-gate   if (pcount != NULL)
20747c478bd9Sstevel@tonic-gate       *pcount = 0;
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate   if (sep) {
20777c478bd9Sstevel@tonic-gate       mysep = sep;
20787c478bd9Sstevel@tonic-gate   } else {
20797c478bd9Sstevel@tonic-gate       mysep = " ";
20807c478bd9Sstevel@tonic-gate   }
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate   if (! mechlist || mechlist->mech_length <= 0)
20837c478bd9Sstevel@tonic-gate       INTERROR(conn, SASL_NOMECH);
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate   resultlen = (prefix ? strlen(prefix) : 0)
20867c478bd9Sstevel@tonic-gate             + (strlen(mysep) * (mechlist->mech_length - 1))
20877c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
20887c478bd9Sstevel@tonic-gate 	    + mech_names_len(gctx)
20897c478bd9Sstevel@tonic-gate #else
20907c478bd9Sstevel@tonic-gate 	    + mech_names_len()
20917c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
20927c478bd9Sstevel@tonic-gate             + (suffix ? strlen(suffix) : 0)
20937c478bd9Sstevel@tonic-gate 	    + 1;
20947c478bd9Sstevel@tonic-gate   ret = _buf_alloc(&conn->mechlist_buf,
20957c478bd9Sstevel@tonic-gate 		   &conn->mechlist_buf_len, resultlen);
20967c478bd9Sstevel@tonic-gate   if(ret != SASL_OK) MEMERROR(conn);
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate   if (prefix)
20997c478bd9Sstevel@tonic-gate     strcpy (conn->mechlist_buf,prefix);
21007c478bd9Sstevel@tonic-gate   else
21017c478bd9Sstevel@tonic-gate     *(conn->mechlist_buf) = '\0';
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate   listptr = mechlist->mech_list;
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate   flag = 0;
21067c478bd9Sstevel@tonic-gate   /* make list */
21077c478bd9Sstevel@tonic-gate   for (lup = 0; lup < mechlist->mech_length; lup++) {
21087c478bd9Sstevel@tonic-gate       /* currently, we don't use the "user" parameter for anything */
21097c478bd9Sstevel@tonic-gate       if (mech_permitted(conn, listptr)) {
21107c478bd9Sstevel@tonic-gate 	  if (pcount != NULL)
21117c478bd9Sstevel@tonic-gate 	      (*pcount)++;
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	  /* print seperator */
21147c478bd9Sstevel@tonic-gate 	  if (flag) {
21157c478bd9Sstevel@tonic-gate 	      strcat(conn->mechlist_buf, mysep);
21167c478bd9Sstevel@tonic-gate 	  } else {
21177c478bd9Sstevel@tonic-gate 	      flag = 1;
21187c478bd9Sstevel@tonic-gate 	  }
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	  /* now print the mechanism name */
21217c478bd9Sstevel@tonic-gate 	  strcat(conn->mechlist_buf, listptr->plug->mech_name);
21227c478bd9Sstevel@tonic-gate       }
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate       listptr = listptr->next;
21257c478bd9Sstevel@tonic-gate   }
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate   if (suffix)
21287c478bd9Sstevel@tonic-gate       strcat(conn->mechlist_buf,suffix);
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate   if (plen!=NULL)
21317c478bd9Sstevel@tonic-gate       *plen=strlen(conn->mechlist_buf);
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate   *result = conn->mechlist_buf;
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate   return SASL_OK;
21367c478bd9Sstevel@tonic-gate }
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
21397c478bd9Sstevel@tonic-gate sasl_string_list_t *_sasl_server_mechs(_sasl_global_context_t *gctx)
21407c478bd9Sstevel@tonic-gate #else
21417c478bd9Sstevel@tonic-gate sasl_string_list_t *_sasl_server_mechs(void)
21427c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate   mechanism_t *listptr;
21457c478bd9Sstevel@tonic-gate   sasl_string_list_t *retval = NULL, *next=NULL;
21467c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
21477c478bd9Sstevel@tonic-gate   mech_list_t *mechlist = gctx->mechlist;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate   if(!gctx->sasl_server_active) return NULL;
21507c478bd9Sstevel@tonic-gate #else
21517c478bd9Sstevel@tonic-gate   if(!_sasl_server_active) return NULL;
21527c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate   /* make list */
21557c478bd9Sstevel@tonic-gate   for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) {
21567c478bd9Sstevel@tonic-gate       next = sasl_ALLOC(sizeof(sasl_string_list_t));
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate       if(!next && !retval) return NULL;
21597c478bd9Sstevel@tonic-gate       else if(!next) {
21607c478bd9Sstevel@tonic-gate 	  next = retval->next;
21617c478bd9Sstevel@tonic-gate 	  do {
21627c478bd9Sstevel@tonic-gate 	      sasl_FREE(retval);
21637c478bd9Sstevel@tonic-gate 	      retval = next;
21647c478bd9Sstevel@tonic-gate 	      next = retval->next;
21657c478bd9Sstevel@tonic-gate 	  } while(next);
21667c478bd9Sstevel@tonic-gate 	  return NULL;
21677c478bd9Sstevel@tonic-gate       }
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate       next->d = listptr->plug->mech_name;
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate       if(!retval) {
21727c478bd9Sstevel@tonic-gate 	  next->next = NULL;
21737c478bd9Sstevel@tonic-gate 	  retval = next;
21747c478bd9Sstevel@tonic-gate       } else {
21757c478bd9Sstevel@tonic-gate 	  next->next = retval;
21767c478bd9Sstevel@tonic-gate 	  retval = next;
21777c478bd9Sstevel@tonic-gate       }
21787c478bd9Sstevel@tonic-gate   }
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate   return retval;
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate #define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t'))
21847c478bd9Sstevel@tonic-gate static int is_mech(const char *t, const char *m)
21857c478bd9Sstevel@tonic-gate {
21867c478bd9Sstevel@tonic-gate     int sl = strlen(m);
21877c478bd9Sstevel@tonic-gate     return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl));
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate /* returns OK if it's valid */
21917c478bd9Sstevel@tonic-gate static int _sasl_checkpass(sasl_conn_t *conn,
21927c478bd9Sstevel@tonic-gate 			   const char *user,
21937c478bd9Sstevel@tonic-gate 			   unsigned userlen __attribute__((unused)),
21947c478bd9Sstevel@tonic-gate 			   const char *pass,
21957c478bd9Sstevel@tonic-gate 			   unsigned passlen __attribute__((unused)))
21967c478bd9Sstevel@tonic-gate {
21977c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
21987c478bd9Sstevel@tonic-gate     int result;
21997c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
22007c478bd9Sstevel@tonic-gate     sasl_server_userdb_checkpass_t *checkpass_cb;
22017c478bd9Sstevel@tonic-gate     void *context;
22027c478bd9Sstevel@tonic-gate     const char *mlist = NULL, *mech = NULL;
22037c478bd9Sstevel@tonic-gate     struct sasl_verify_password_s *v;
22047c478bd9Sstevel@tonic-gate     const char *service = conn->service;
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate     /* call userdb callback function, if available */
22077c478bd9Sstevel@tonic-gate     result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS,
22087c478bd9Sstevel@tonic-gate 			       &checkpass_cb, &context);
22097c478bd9Sstevel@tonic-gate     if(result == SASL_OK && checkpass_cb) {
22107c478bd9Sstevel@tonic-gate 	result = checkpass_cb(conn, context, user, pass, strlen(pass),
22117c478bd9Sstevel@tonic-gate 			      s_conn->sparams->propctx);
22127c478bd9Sstevel@tonic-gate 	if(result == SASL_OK)
22137c478bd9Sstevel@tonic-gate 	    return SASL_OK;
22147c478bd9Sstevel@tonic-gate     }
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate     /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
22177c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
22187c478bd9Sstevel@tonic-gate             == SASL_OK) {
22197c478bd9Sstevel@tonic-gate         getopt(context, NULL, "pwcheck_method", &mlist, NULL);
22207c478bd9Sstevel@tonic-gate     }
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate     if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate     result = SASL_NOMECH;
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate     mech = mlist;
22277c478bd9Sstevel@tonic-gate     while (*mech && result != SASL_OK) {
22287c478bd9Sstevel@tonic-gate 	for (v = _sasl_verify_password; v->name; v++) {
22297c478bd9Sstevel@tonic-gate 	    if(is_mech(mech, v->name)) {
22307c478bd9Sstevel@tonic-gate 		result = v->verify(conn, user, pass, service,
22317c478bd9Sstevel@tonic-gate 				   s_conn->user_realm);
22327c478bd9Sstevel@tonic-gate 		break;
22337c478bd9Sstevel@tonic-gate 	    }
22347c478bd9Sstevel@tonic-gate 	}
22357c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) {
22367c478bd9Sstevel@tonic-gate 	    /* skip to next mech in list */
22377c478bd9Sstevel@tonic-gate 	    while (*mech && !isspace((int) *mech)) mech++;
22387c478bd9Sstevel@tonic-gate 	    while (*mech && isspace((int) *mech)) mech++;
22397c478bd9Sstevel@tonic-gate 	}
22407c478bd9Sstevel@tonic-gate     }
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate     if (result == SASL_NOMECH) {
22437c478bd9Sstevel@tonic-gate 	/* no mechanism available ?!? */
22447c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR, "unknown password verifier %s", mech);
22457c478bd9Sstevel@tonic-gate     }
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
22487c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
22497c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG, gettext("checkpass failed"));
22507c478bd9Sstevel@tonic-gate #else
22517c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG, "checkpass failed");
22527c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate     RETURN(conn, result);
22557c478bd9Sstevel@tonic-gate }
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate /* check if a plaintext password is valid
22587c478bd9Sstevel@tonic-gate  *   if user is NULL, check if plaintext passwords are enabled
22597c478bd9Sstevel@tonic-gate  * inputs:
22607c478bd9Sstevel@tonic-gate  *  user          -- user to query in current user_domain
22617c478bd9Sstevel@tonic-gate  *  userlen       -- length of username, 0 = strlen(user)
22627c478bd9Sstevel@tonic-gate  *  pass          -- plaintext password to check
22637c478bd9Sstevel@tonic-gate  *  passlen       -- length of password, 0 = strlen(pass)
22647c478bd9Sstevel@tonic-gate  * returns
22657c478bd9Sstevel@tonic-gate  *  SASL_OK       -- success
22667c478bd9Sstevel@tonic-gate  *  SASL_NOMECH   -- mechanism not supported
22677c478bd9Sstevel@tonic-gate  *  SASL_NOVERIFY -- user found, but no verifier
22687c478bd9Sstevel@tonic-gate  *  SASL_NOUSER   -- user not found
22697c478bd9Sstevel@tonic-gate  */
22707c478bd9Sstevel@tonic-gate int sasl_checkpass(sasl_conn_t *conn,
22717c478bd9Sstevel@tonic-gate 		   const char *user,
22727c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
22737c478bd9Sstevel@tonic-gate 		   unsigned userlen,
22747c478bd9Sstevel@tonic-gate #else /* _SUN_SDK_ */
22757c478bd9Sstevel@tonic-gate 		   unsigned userlen __attribute__((unused)),
22767c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
22777c478bd9Sstevel@tonic-gate 		   const char *pass,
22787c478bd9Sstevel@tonic-gate 		   unsigned passlen)
22797c478bd9Sstevel@tonic-gate {
22807c478bd9Sstevel@tonic-gate     int result;
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
22837c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
22847c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active==0) return SASL_NOTINIT;
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate     /* A NULL user means the caller is checking if plaintext authentication
22897c478bd9Sstevel@tonic-gate      * is enabled.  But if no connection context is supplied, we have no
22907c478bd9Sstevel@tonic-gate      * appropriate policy to check against.  So for consistant global
22917c478bd9Sstevel@tonic-gate      * behavior we always say plaintext is enabled in this case.
22927c478bd9Sstevel@tonic-gate      */
22937c478bd9Sstevel@tonic-gate     if (!user && !conn) return SASL_OK;
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate     /* Check connection security policy to see if plaintext password
22987c478bd9Sstevel@tonic-gate      * authentication is permitted.
22997c478bd9Sstevel@tonic-gate      *
23007c478bd9Sstevel@tonic-gate      * XXX TODO FIXME:
23017c478bd9Sstevel@tonic-gate      * This should call mech_permitted with the PLAIN mechanism,
23027c478bd9Sstevel@tonic-gate      * since all plaintext mechanisms should fall under the same
23037c478bd9Sstevel@tonic-gate      * security policy guidelines.  But to keep code changes and
23047c478bd9Sstevel@tonic-gate      * risk to a minimum at this juncture, we do the minimal
23057c478bd9Sstevel@tonic-gate      * security strength and plaintext policy checks which are
23067c478bd9Sstevel@tonic-gate      * most likely to be deployed and useful in the field.
23077c478bd9Sstevel@tonic-gate      */
23087c478bd9Sstevel@tonic-gate     if (conn->props.min_ssf > conn->external.ssf)
23097c478bd9Sstevel@tonic-gate       RETURN(conn, SASL_TOOWEAK);
23107c478bd9Sstevel@tonic-gate     if ((conn->props.security_flags & SASL_SEC_NOPLAINTEXT) != 0
23117c478bd9Sstevel@tonic-gate       && conn->external.ssf == 0)
23127c478bd9Sstevel@tonic-gate       RETURN(conn, SASL_ENCRYPT);
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate     if (!user)
23157c478bd9Sstevel@tonic-gate       return SASL_OK;
23167c478bd9Sstevel@tonic-gate #else
23177c478bd9Sstevel@tonic-gate     if (_sasl_server_active==0) return SASL_NOTINIT;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate     /* check if it's just a query if we are enabled */
23207c478bd9Sstevel@tonic-gate     if (!user)
23217c478bd9Sstevel@tonic-gate 	return SASL_OK;
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
23247c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate     /* check params */
23277c478bd9Sstevel@tonic-gate     if (pass == NULL)
23287c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate     /* canonicalize the username */
23317c478bd9Sstevel@tonic-gate     result = _sasl_canon_user(conn, user, 0,
23327c478bd9Sstevel@tonic-gate 			      SASL_CU_AUTHID | SASL_CU_AUTHZID,
23337c478bd9Sstevel@tonic-gate 			      &(conn->oparams));
23347c478bd9Sstevel@tonic-gate     if(result != SASL_OK) RETURN(conn, result);
23357c478bd9Sstevel@tonic-gate     user = conn->oparams.user;
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate     /* Check the password */
23387c478bd9Sstevel@tonic-gate     result = _sasl_checkpass(conn, user, strlen(user), pass, strlen(pass));
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
23417c478bd9Sstevel@tonic-gate     if (result == SASL_OK) {
23427c478bd9Sstevel@tonic-gate       result = do_authorization((sasl_server_conn_t *) conn);
23437c478bd9Sstevel@tonic-gate     }
23447c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate     if (result == SASL_OK)
23477c478bd9Sstevel@tonic-gate 	result = _sasl_transition(conn, pass, passlen);
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate     RETURN(conn,result);
23507c478bd9Sstevel@tonic-gate }
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate /* check if a user exists on server
23537c478bd9Sstevel@tonic-gate  *  conn          -- connection context (may be NULL, used to hold last error)
23547c478bd9Sstevel@tonic-gate  *  service       -- registered name of the service using SASL (e.g. "imap")
23557c478bd9Sstevel@tonic-gate  *  user_realm    -- permits multiple user realms on server, NULL = default
23567c478bd9Sstevel@tonic-gate  *  user          -- NUL terminated user name
23577c478bd9Sstevel@tonic-gate  *
23587c478bd9Sstevel@tonic-gate  * returns:
23597c478bd9Sstevel@tonic-gate  *  SASL_OK       -- success
23607c478bd9Sstevel@tonic-gate  *  SASL_DISABLED -- account disabled [FIXME: currently not detected]
23617c478bd9Sstevel@tonic-gate  *  SASL_NOUSER   -- user not found
23627c478bd9Sstevel@tonic-gate  *  SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
23637c478bd9Sstevel@tonic-gate  *  SASL_NOMECH   -- no mechanisms enabled
23647c478bd9Sstevel@tonic-gate  */
23657c478bd9Sstevel@tonic-gate int sasl_user_exists(sasl_conn_t *conn,
23667c478bd9Sstevel@tonic-gate 		     const char *service,
23677c478bd9Sstevel@tonic-gate 		     const char *user_realm,
23687c478bd9Sstevel@tonic-gate 		     const char *user)
23697c478bd9Sstevel@tonic-gate {
23707c478bd9Sstevel@tonic-gate     int result=SASL_NOMECH;
23717c478bd9Sstevel@tonic-gate     const char *mlist = NULL, *mech = NULL;
23727c478bd9Sstevel@tonic-gate     void *context;
23737c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
23747c478bd9Sstevel@tonic-gate     struct sasl_verify_password_s *v;
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
23777c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
23787c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate     /* check params */
23817c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active==0) return SASL_NOTINIT;
23827c478bd9Sstevel@tonic-gate #else
23837c478bd9Sstevel@tonic-gate     /* check params */
23847c478bd9Sstevel@tonic-gate     if (_sasl_server_active==0) return SASL_NOTINIT;
23857c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
23867c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
23877c478bd9Sstevel@tonic-gate     if (!user || conn->type != SASL_CONN_SERVER)
23887c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate     if(!service) service = conn->service;
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate     /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
23937c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context)
23947c478bd9Sstevel@tonic-gate             == SASL_OK) {
23957c478bd9Sstevel@tonic-gate         getopt(context, NULL, "pwcheck_method", &mlist, NULL);
23967c478bd9Sstevel@tonic-gate     }
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate     if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate     result = SASL_NOMECH;
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate     mech = mlist;
24037c478bd9Sstevel@tonic-gate     while (*mech && result != SASL_OK) {
24047c478bd9Sstevel@tonic-gate 	for (v = _sasl_verify_password; v->name; v++) {
24057c478bd9Sstevel@tonic-gate 	    if(is_mech(mech, v->name)) {
24067c478bd9Sstevel@tonic-gate 		result = v->verify(conn, user, NULL, service, user_realm);
24077c478bd9Sstevel@tonic-gate 		break;
24087c478bd9Sstevel@tonic-gate 	    }
24097c478bd9Sstevel@tonic-gate 	}
24107c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) {
24117c478bd9Sstevel@tonic-gate 	    /* skip to next mech in list */
24127c478bd9Sstevel@tonic-gate 	    while (*mech && !isspace((int) *mech)) mech++;
24137c478bd9Sstevel@tonic-gate 	    while (*mech && isspace((int) *mech)) mech++;
24147c478bd9Sstevel@tonic-gate 	}
24157c478bd9Sstevel@tonic-gate     }
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate     /* Screen out the SASL_BADPARAM response
24187c478bd9Sstevel@tonic-gate      * we'll get from not giving a password */
24197c478bd9Sstevel@tonic-gate     if(result == SASL_BADPARAM) {
24207c478bd9Sstevel@tonic-gate 	result = SASL_OK;
24217c478bd9Sstevel@tonic-gate     }
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate     if (result == SASL_NOMECH) {
24247c478bd9Sstevel@tonic-gate 	/* no mechanism available ?!? */
24257c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?");
24267c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
24277c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?");
24287c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
24297c478bd9Sstevel@tonic-gate     }
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate     RETURN(conn, result);
24327c478bd9Sstevel@tonic-gate }
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate /* check if an apop exchange is valid
24357c478bd9Sstevel@tonic-gate  *  (note this is an optional part of the SASL API)
24367c478bd9Sstevel@tonic-gate  *  if challenge is NULL, just check if APOP is enabled
24377c478bd9Sstevel@tonic-gate  * inputs:
24387c478bd9Sstevel@tonic-gate  *  challenge     -- challenge which was sent to client
24397c478bd9Sstevel@tonic-gate  *  challen       -- length of challenge, 0 = strlen(challenge)
24407c478bd9Sstevel@tonic-gate  *  response      -- client response, "<user> <digest>" (RFC 1939)
24417c478bd9Sstevel@tonic-gate  *  resplen       -- length of response, 0 = strlen(response)
24427c478bd9Sstevel@tonic-gate  * returns
24437c478bd9Sstevel@tonic-gate  *  SASL_OK       -- success
24447c478bd9Sstevel@tonic-gate  *  SASL_BADAUTH  -- authentication failed
24457c478bd9Sstevel@tonic-gate  *  SASL_BADPARAM -- missing challenge
24467c478bd9Sstevel@tonic-gate  *  SASL_BADPROT  -- protocol error (e.g., response in wrong format)
24477c478bd9Sstevel@tonic-gate  *  SASL_NOVERIFY -- user found, but no verifier
24487c478bd9Sstevel@tonic-gate  *  SASL_NOMECH   -- mechanism not supported
24497c478bd9Sstevel@tonic-gate  *  SASL_NOUSER   -- user not found
24507c478bd9Sstevel@tonic-gate  */
24517c478bd9Sstevel@tonic-gate int sasl_checkapop(sasl_conn_t *conn,
24527c478bd9Sstevel@tonic-gate #ifdef DO_SASL_CHECKAPOP
24537c478bd9Sstevel@tonic-gate  		   const char *challenge,
24547c478bd9Sstevel@tonic-gate  		   unsigned challen __attribute__((unused)),
24557c478bd9Sstevel@tonic-gate  		   const char *response,
24567c478bd9Sstevel@tonic-gate  		   unsigned resplen __attribute__((unused)))
24577c478bd9Sstevel@tonic-gate #else
24587c478bd9Sstevel@tonic-gate  		   const char *challenge __attribute__((unused)),
24597c478bd9Sstevel@tonic-gate  		   unsigned challen __attribute__((unused)),
24607c478bd9Sstevel@tonic-gate  		   const char *response __attribute__((unused)),
24617c478bd9Sstevel@tonic-gate  		   unsigned resplen __attribute__((unused)))
24627c478bd9Sstevel@tonic-gate #endif
24637c478bd9Sstevel@tonic-gate {
24647c478bd9Sstevel@tonic-gate #ifdef DO_SASL_CHECKAPOP
24657c478bd9Sstevel@tonic-gate     sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
24667c478bd9Sstevel@tonic-gate     char *user, *user_end;
24677c478bd9Sstevel@tonic-gate     const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
24687c478bd9Sstevel@tonic-gate     size_t user_len;
24697c478bd9Sstevel@tonic-gate     int result;
24707c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
24717c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx =
24727c478bd9Sstevel@tonic-gate 		 (conn == NULL) ? _sasl_gbl_ctx() : conn->gctx;
24737c478bd9Sstevel@tonic-gate 
24747c478bd9Sstevel@tonic-gate     if (gctx->sasl_server_active==0)
24757c478bd9Sstevel@tonic-gate         return SASL_NOTINIT;
24767c478bd9Sstevel@tonic-gate #else
24777c478bd9Sstevel@tonic-gate     if (_sasl_server_active==0)
24787c478bd9Sstevel@tonic-gate 	return SASL_NOTINIT;
24797c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate     /* check if it's just a query if we are enabled */
24827c478bd9Sstevel@tonic-gate     if(!challenge)
24837c478bd9Sstevel@tonic-gate 	return SASL_OK;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate     /* check params */
24867c478bd9Sstevel@tonic-gate     if (!conn) return SASL_BADPARAM;
24877c478bd9Sstevel@tonic-gate     if (!response)
24887c478bd9Sstevel@tonic-gate 	PARAMERROR(conn);
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate     /* Parse out username and digest.
24917c478bd9Sstevel@tonic-gate      *
24927c478bd9Sstevel@tonic-gate      * Per RFC 1939, response must be "<user> <digest>", where
24937c478bd9Sstevel@tonic-gate      * <digest> is a 16-octet value which is sent in hexadecimal
24947c478bd9Sstevel@tonic-gate      * format, using lower-case ASCII characters.
24957c478bd9Sstevel@tonic-gate      */
24967c478bd9Sstevel@tonic-gate     user_end = strrchr(response, ' ');
24977c478bd9Sstevel@tonic-gate     if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32)
24987c478bd9Sstevel@tonic-gate     {
24997c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
25007c478bd9Sstevel@tonic-gate         sasl_seterror(conn, 0, gettext("Bad Digest"));
25017c478bd9Sstevel@tonic-gate #else
25027c478bd9Sstevel@tonic-gate         sasl_seterror(conn, 0, "Bad Digest");
25037c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
25047c478bd9Sstevel@tonic-gate         RETURN(conn,SASL_BADPROT);
25057c478bd9Sstevel@tonic-gate     }
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate     user_len = (size_t)(user_end - response);
25087c478bd9Sstevel@tonic-gate     user = sasl_ALLOC(user_len + 1);
25097c478bd9Sstevel@tonic-gate     memcpy(user, response, user_len);
25107c478bd9Sstevel@tonic-gate     user[user_len] = '\0';
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate     result = prop_request(s_conn->sparams->propctx, password_request);
25137c478bd9Sstevel@tonic-gate     if(result != SASL_OK)
25147c478bd9Sstevel@tonic-gate     {
25157c478bd9Sstevel@tonic-gate         sasl_FREE(user);
25167c478bd9Sstevel@tonic-gate         RETURN(conn, result);
25177c478bd9Sstevel@tonic-gate     }
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate     /* Cannonify it */
25207c478bd9Sstevel@tonic-gate     result = _sasl_canon_user(conn, user, user_len,
25217c478bd9Sstevel@tonic-gate 	                      SASL_CU_AUTHID | SASL_CU_AUTHZID,
25227c478bd9Sstevel@tonic-gate 	                      &(conn->oparams));
25237c478bd9Sstevel@tonic-gate     sasl_FREE(user);
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate     if(result != SASL_OK) RETURN(conn, result);
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate     /* Do APOP verification */
25287c478bd9Sstevel@tonic-gate     result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid,
25297c478bd9Sstevel@tonic-gate 	challenge, user_end + 1, s_conn->user_realm);
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate     /* If verification failed, we don't want to encourage getprop to work */
25327c478bd9Sstevel@tonic-gate     if(result != SASL_OK) {
25337c478bd9Sstevel@tonic-gate 	conn->oparams.user = NULL;
25347c478bd9Sstevel@tonic-gate 	conn->oparams.authid = NULL;
25357c478bd9Sstevel@tonic-gate     }
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate     RETURN(conn, result);
25387c478bd9Sstevel@tonic-gate #else /* sasl_checkapop was disabled at compile time */
25397c478bd9Sstevel@tonic-gate     sasl_seterror(conn, SASL_NOLOG,
25407c478bd9Sstevel@tonic-gate 	"sasl_checkapop called, but was disabled at compile time");
25417c478bd9Sstevel@tonic-gate     RETURN(conn, SASL_NOMECH);
25427c478bd9Sstevel@tonic-gate #endif /* DO_SASL_CHECKAPOP */
25437c478bd9Sstevel@tonic-gate }
25447c478bd9Sstevel@tonic-gate 
2545