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