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