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