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