~ubuntu-branches/ubuntu/gutsy/cyrus-sasl2/gutsy-201105300151

« back to all changes in this revision

Viewing changes to lib/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2006-11-27 12:59:40 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20061127125940-na3q3g3tkydvyvgl
Tags: 2.1.22.dfsg1-4ubuntu1
* Merge from debian unstable, remaining changes:
  - remove stop links from rc0 and rc6
  - build against db4.3 instead of 4.2
  - build against heimdal-dev instead of libkrb5-dev
  - depend on, don't recommend, modules

Show diffs side-by-side

added added

removed removed

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