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