~ubuntu-branches/ubuntu/wily/389-ds-base/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2014-0132.patch/ldap/servers/slapd/saslbind.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2014-07-08 15:50:11 UTC
  • mfrom: (0.2.2)
  • Revision ID: package-import@ubuntu.com-20140708155011-r66lvtioamqwaype
Tags: 1.3.2.19-1
* New upstream release.
* admin_scripts.diff: Updated to fix more bashisms.
* watch: Update the url.
* Install failedbinds.py and logregex.py scripts.
* init: Use status from init-functions.
* control: Update my email.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** BEGIN COPYRIGHT BLOCK
2
 
 * This Program is free software; you can redistribute it and/or modify it under
3
 
 * the terms of the GNU General Public License as published by the Free Software
4
 
 * Foundation; version 2 of the License.
5
 
 * 
6
 
 * This Program is distributed in the hope that it will be useful, but WITHOUT
7
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8
 
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9
 
 * 
10
 
 * You should have received a copy of the GNU General Public License along with
11
 
 * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
12
 
 * Place, Suite 330, Boston, MA 02111-1307 USA.
13
 
 * 
14
 
 * In addition, as a special exception, Red Hat, Inc. gives You the additional
15
 
 * right to link the code of this Program with code not covered under the GNU
16
 
 * General Public License ("Non-GPL Code") and to distribute linked combinations
17
 
 * including the two, subject to the limitations in this paragraph. Non-GPL Code
18
 
 * permitted under this exception must only link to the code of this Program
19
 
 * through those well defined interfaces identified in the file named EXCEPTION
20
 
 * found in the source code files (the "Approved Interfaces"). The files of
21
 
 * Non-GPL Code may instantiate templates or use macros or inline functions from
22
 
 * the Approved Interfaces without causing the resulting work to be covered by
23
 
 * the GNU General Public License. Only Red Hat, Inc. may make changes or
24
 
 * additions to the list of Approved Interfaces. You must obey the GNU General
25
 
 * Public License in all respects for all of the Program code and other code used
26
 
 * in conjunction with the Program except the Non-GPL Code covered by this
27
 
 * exception. If you modify this file, you may extend this exception to your
28
 
 * version of the file, but you are not obligated to do so. If you do not wish to
29
 
 * provide this exception without modification, you must delete this exception
30
 
 * statement from your version and license this file solely under the GPL without
31
 
 * exception. 
32
 
 * 
33
 
 * 
34
 
 * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
35
 
 * Copyright (C) 2009 Red Hat, Inc.
36
 
 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
37
 
 * All rights reserved.
38
 
 *
39
 
 * Contributors:
40
 
 *   Hewlett-Packard Development Company, L.P.
41
 
 *     Bugfix for bug #193297
42
 
 *
43
 
 * END COPYRIGHT BLOCK **/
44
 
 
45
 
#ifdef HAVE_CONFIG_H
46
 
#  include <config.h>
47
 
#endif
48
 
 
49
 
 
50
 
#include <slap.h>
51
 
#include <fe.h>
52
 
#include <sasl.h>
53
 
#include <saslplug.h>
54
 
#ifndef _WIN32
55
 
#include <unistd.h>
56
 
#endif
57
 
 
58
 
static char *serverfqdn;
59
 
 
60
 
/*
61
 
 * utility functions needed by the sasl library
62
 
 */
63
 
void *nssasl_mutex_alloc(void)
64
 
{
65
 
    return PR_NewLock();
66
 
}
67
 
 
68
 
int nssasl_mutex_lock(void *mutex)
69
 
{
70
 
    PR_Lock(mutex);
71
 
    return SASL_OK;
72
 
}
73
 
 
74
 
int nssasl_mutex_unlock(void *mutex)
75
 
{
76
 
    if (PR_Unlock(mutex) == PR_SUCCESS) return SASL_OK;
77
 
    return SASL_FAIL;
78
 
}
79
 
 
80
 
void nssasl_mutex_free(void *mutex)
81
 
{
82
 
    PR_DestroyLock(mutex);
83
 
}
84
 
 
85
 
void nssasl_free(void *ptr)
86
 
{
87
 
    slapi_ch_free(&ptr);
88
 
}
89
 
 
90
 
static Slapi_ComponentId *sasl_component_id = NULL;
91
 
 
92
 
static void generate_component_id()
93
 
{
94
 
    if (NULL == sasl_component_id) {
95
 
        sasl_component_id = generate_componentid(NULL /* Not a plugin */,
96
 
                                                 COMPONENT_SASL);
97
 
    }
98
 
}
99
 
 
100
 
static Slapi_ComponentId *sasl_get_component_id()
101
 
{
102
 
    return sasl_component_id;
103
 
}
104
 
 
105
 
/* 
106
 
 * sasl library callbacks
107
 
 */
108
 
 
109
 
/*
110
 
 * We've added this auxprop stuff as a workaround for RHDS bug 166229
111
 
 * and FDS bug 166081.  The problem is that sasldb is configured and
112
 
 * enabled by default, but we don't want or need to use it.  What
113
 
 * happens after canon_user is that sasl looks up any auxiliary
114
 
 * properties of that user.  If you don't tell sasl which auxprop
115
 
 * plug-in to use, it tries all of them, including sasldb.  In order
116
 
 * to avoid this, we create a "dummy" auxprop plug-in with the name
117
 
 * "iDS" and tell sasl to use this plug-in for auxprop lookups.
118
 
 * The reason we don't need auxprops is because when we grab the user's
119
 
 * entry from the internal database, at the same time we get any other
120
 
 * properties we need - it's more efficient that way.
121
 
 */
122
 
#if SASL_AUXPROP_PLUG_VERSION > 4
123
 
static int ids_auxprop_lookup(
124
 
#else
125
 
static void ids_auxprop_lookup(
126
 
#endif
127
 
                                  void *glob_context,
128
 
                                  sasl_server_params_t *sparams,
129
 
                                  unsigned flags,
130
 
                                  const char *user,
131
 
                                  unsigned ulen) 
132
 
{
133
 
    /* do nothing - we don't need auxprops - we just do this to avoid
134
 
       sasldb_auxprop_lookup */
135
 
#if SASL_AUXPROP_PLUG_VERSION > 4
136
 
    return 0;
137
 
#endif
138
 
}
139
 
 
140
 
static sasl_auxprop_plug_t ids_auxprop_plugin = {
141
 
    0,                          /* Features */
142
 
    0,                          /* spare */
143
 
    NULL,                       /* glob_context */
144
 
    NULL,                       /* auxprop_free */
145
 
    ids_auxprop_lookup, /* auxprop_lookup */
146
 
    "iDS",                      /* name */
147
 
    NULL        /* auxprop_store */
148
 
};
149
 
 
150
 
int ids_auxprop_plug_init(const sasl_utils_t *utils,
151
 
                          int max_version,
152
 
                          int *out_version,
153
 
                          sasl_auxprop_plug_t **plug,
154
 
                          const char *plugname) 
155
 
{
156
 
    if(!out_version || !plug) return SASL_BADPARAM;
157
 
 
158
 
    if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
159
 
    
160
 
    *out_version = SASL_AUXPROP_PLUG_VERSION;
161
 
 
162
 
    *plug = &ids_auxprop_plugin;
163
 
 
164
 
    return SASL_OK;
165
 
}
166
 
 
167
 
static int ids_sasl_getopt(
168
 
    void *context, 
169
 
    const char *plugin_name,
170
 
    const char *option,
171
 
    const char **result, 
172
 
    unsigned *len
173
 
)
174
 
{
175
 
    unsigned tmplen;
176
 
 
177
 
    LDAPDebug(LDAP_DEBUG_TRACE, "ids_sasl_getopt: plugin=%s option=%s\n",
178
 
              plugin_name ? plugin_name : "", option, 0);
179
 
 
180
 
    if (len == NULL) len = &tmplen;
181
 
 
182
 
    *result = NULL;
183
 
    *len = 0;
184
 
 
185
 
    if (strcasecmp(option, "enable") == 0) {
186
 
        *result = "USERDB/DIGEST-MD5,GSSAPI/GSSAPI";
187
 
    } else if (strcasecmp(option, "has_plain_passwords") == 0) {
188
 
        *result = "yes";
189
 
    } else if (strcasecmp(option, "LOG_LEVEL") == 0) {
190
 
        if (LDAPDebugLevelIsSet(LDAP_DEBUG_TRACE)) {
191
 
            *result = "6"; /* SASL_LOG_TRACE */
192
 
        }
193
 
    } else if (strcasecmp(option, "auxprop_plugin") == 0) {
194
 
        *result = "iDS";
195
 
    } else if (strcasecmp(option, "mech_list") == 0){
196
 
        *result = config_get_allowed_sasl_mechs();
197
 
    }
198
 
 
199
 
    if (*result) *len = strlen(*result);
200
 
 
201
 
    return SASL_OK;
202
 
}
203
 
 
204
 
static int ids_sasl_log(
205
 
    void       *context,
206
 
    int        level,
207
 
    const char *message
208
 
)
209
 
{
210
 
    switch (level) {
211
 
    case SASL_LOG_ERR:          /* log unusual errors (default) */
212
 
        slapi_log_error(SLAPI_LOG_FATAL, "sasl", "%s\n", message);
213
 
        break;
214
 
 
215
 
    case SASL_LOG_FAIL:         /* log all authentication failures */
216
 
    case SASL_LOG_WARN:         /* log non-fatal warnings */
217
 
    case SASL_LOG_NOTE:         /* more verbose than LOG_WARN */
218
 
    case SASL_LOG_DEBUG:        /* more verbose than LOG_NOTE */
219
 
    case SASL_LOG_TRACE:        /* traces of internal protocols */
220
 
    case SASL_LOG_PASS:         /* traces of internal protocols, including
221
 
                                 * passwords */
222
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl(%d): %s\n", level, message, 0);
223
 
        break;
224
 
 
225
 
    case SASL_LOG_NONE:         /* don't log anything */
226
 
    default:
227
 
        break;
228
 
    }
229
 
    return SASL_OK;
230
 
}
231
 
 
232
 
static int ids_sasl_proxy_policy(
233
 
    sasl_conn_t *conn,
234
 
    void *context,
235
 
    const char *requested_user, int rlen,
236
 
    const char *auth_identity, int alen,
237
 
    const char *def_realm, int urlen,
238
 
    struct propctx *propctx
239
 
)
240
 
{
241
 
    int retVal = SASL_OK;
242
 
    /* do not permit sasl proxy authorization */
243
 
    /* if the auth_identity is null or empty string, allow the sasl request to go thru */    
244
 
    if ( (auth_identity != NULL ) && ( strlen(auth_identity) > 0 ) ) {
245
 
        Slapi_DN authId , reqUser;
246
 
        slapi_sdn_init_dn_byref(&authId,auth_identity);
247
 
        slapi_sdn_init_dn_byref(&reqUser,requested_user);
248
 
        if (slapi_sdn_compare((const Slapi_DN *)&reqUser,(const Slapi_DN *) &authId) != 0) {
249
 
            LDAPDebug(LDAP_DEBUG_TRACE, 
250
 
                  "sasl proxy auth not permitted authid=%s user=%s\n",
251
 
                  auth_identity, requested_user, 0);
252
 
            retVal =  SASL_NOAUTHZ;
253
 
        }
254
 
        slapi_sdn_done(&authId);
255
 
        slapi_sdn_done(&reqUser); 
256
 
    }
257
 
    return retVal;
258
 
}
259
 
 
260
 
static void ids_sasl_user_search(
261
 
    char *basedn,
262
 
    int scope,
263
 
    char *filter,
264
 
    LDAPControl **ctrls,
265
 
    char **attrs,
266
 
    int attrsonly,
267
 
    Slapi_Entry **ep,
268
 
    int *foundp
269
 
)
270
 
{
271
 
    Slapi_Entry **entries = NULL;
272
 
    Slapi_PBlock *pb = NULL;
273
 
    int i, ret;
274
 
 
275
 
    LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search basedn=\"%s\" filter=\"%s\"\n", basedn, filter, 0);
276
 
 
277
 
    /* TODO: set size and time limits */
278
 
    pb = slapi_pblock_new();
279
 
    if (!pb) {
280
 
        LDAPDebug(LDAP_DEBUG_TRACE, "null pblock for search_internal_pb\n", 0, 0, 0);
281
 
        goto out;
282
 
    }
283
 
 
284
 
    slapi_search_internal_set_pb(pb, basedn, scope, filter, attrs, attrsonly, ctrls, 
285
 
                                 NULL, sasl_get_component_id(), 0); 
286
 
 
287
 
    slapi_search_internal_pb(pb);
288
 
 
289
 
    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
290
 
    if (ret != LDAP_SUCCESS) {
291
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search failed basedn=\"%s\" "
292
 
                  "filter=\"%s\": %s\n", 
293
 
                  basedn, filter, ldap_err2string(ret));
294
 
        goto out;
295
 
    }
296
 
 
297
 
    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
298
 
    if ((entries == NULL) || (entries[0] == NULL)) {
299
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found no entries\n",
300
 
                  0, 0, 0);
301
 
        goto out;
302
 
    }
303
 
 
304
 
    for (i = 0; entries[i]; i++) {
305
 
        (*foundp)++;
306
 
        if (*ep != NULL) {
307
 
            slapi_entry_free(*ep);
308
 
        }
309
 
        *ep = slapi_entry_dup(entries[i]);
310
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found dn=%s\n",
311
 
                  slapi_entry_get_dn(*ep), 0, 0);
312
 
    }
313
 
 
314
 
 out:
315
 
 
316
 
    if (pb) {
317
 
        slapi_free_search_results_internal(pb);
318
 
        slapi_pblock_destroy(pb);
319
 
        pb = NULL;
320
 
    }
321
 
    return;
322
 
}
323
 
 
324
 
/*
325
 
 * Search for an entry representing the sasl user.
326
 
 */
327
 
static Slapi_Entry *ids_sasl_user_to_entry(
328
 
    sasl_conn_t *conn,
329
 
    void *context,
330
 
    const char *user,
331
 
    const char *user_realm
332
 
)
333
 
{
334
 
    LDAPControl **ctrls = NULL;
335
 
    sasl_map_data *map = NULL;
336
 
    Slapi_Entry *entry = NULL;
337
 
    char **attrs = NULL;
338
 
    char *base = NULL;
339
 
    char *filter = NULL;
340
 
    int attrsonly = 0, scope = LDAP_SCOPE_SUBTREE;
341
 
    int regexmatch = 0;
342
 
    int found = 0;
343
 
 
344
 
    /* Check for wildcards in the authid and realm. If we encounter one,
345
 
     * just fail the mapping without performing a costly internal search. */
346
 
    if (user && strchr(user, '*')) {
347
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search encountered a wildcard in "
348
 
            "the authid.  Not attempting to map to entry. (authid=%s)\n", user, 0, 0);
349
 
        return NULL;
350
 
    } else if (user_realm && strchr(user_realm, '*')) {
351
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search encountered a wildcard in "
352
 
            "the realm.  Not attempting to map to entry. (realm=%s)\n", user_realm, 0, 0);
353
 
        return NULL;
354
 
    }
355
 
 
356
 
    /* New regex-based identity mapping */
357
 
    sasl_map_read_lock();
358
 
    while(1){
359
 
        regexmatch = sasl_map_domap(&map, (char*)user, (char*)user_realm, &base, &filter);
360
 
        if (regexmatch) {
361
 
            ids_sasl_user_search(base, scope, filter,
362
 
                                 ctrls, attrs, attrsonly,
363
 
                                 &entry, &found);
364
 
            if (found == 1) {
365
 
                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found this entry: dn:%s, "
366
 
                    "matching filter=%s\n", entry->e_sdn.dn, filter, 0);
367
 
            } else if (found == 0) {
368
 
                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found no entries matching "
369
 
                    "filter=%s\n", filter, 0, 0);
370
 
            } else {
371
 
                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found more than one entry "
372
 
                    "matching filter=%s\n", filter, 0, 0);
373
 
                if (entry) {
374
 
                    slapi_entry_free(entry);
375
 
                    entry = NULL;
376
 
                }
377
 
            }
378
 
 
379
 
            /* Free the filter etc */
380
 
            slapi_ch_free_string(&base);
381
 
            slapi_ch_free_string(&filter);
382
 
 
383
 
            /* If we didn't find an entry, look at the other maps */
384
 
            if(found){
385
 
                break;
386
 
            }
387
 
        }
388
 
        /* break if the next map is NULL, or we are not checking all the mappings */
389
 
        if(map == NULL || !config_get_sasl_mapping_fallback()){
390
 
            break;
391
 
        }
392
 
    }
393
 
    sasl_map_read_unlock();
394
 
 
395
 
    return entry;
396
 
}
397
 
 
398
 
static char *buf2str(const char *buf, unsigned buflen)
399
 
{
400
 
    char *ret;
401
 
 
402
 
    ret = (char*)slapi_ch_malloc(buflen+1);
403
 
    memcpy(ret, buf, buflen);
404
 
    ret[buflen] = '\0';
405
 
 
406
 
    return ret;
407
 
}
408
 
 
409
 
/* Note that in this sasl1 API, when it says 'authid' it really means 'authzid'. */
410
 
static int ids_sasl_canon_user(
411
 
    sasl_conn_t *conn,
412
 
    void *context,
413
 
    const char *userbuf, unsigned ulen,
414
 
    unsigned flags, const char *user_realm,
415
 
    char *out_user, unsigned out_umax, unsigned *out_ulen
416
 
)
417
 
{
418
 
    struct propctx *propctx = sasl_auxprop_getctx(conn);
419
 
    Slapi_Entry *entry = NULL;
420
 
    Slapi_DN *sdn = NULL;
421
 
    char *pw = NULL;
422
 
    char *user = NULL;
423
 
    char *mech = NULL;
424
 
    const char *dn;
425
 
    int isroot = 0;
426
 
    char *clear = NULL;
427
 
    int returnvalue = SASL_FAIL;
428
 
 
429
 
    user = buf2str(userbuf, ulen);
430
 
    if (user == NULL) {
431
 
        goto fail;
432
 
    } 
433
 
    LDAPDebug(LDAP_DEBUG_TRACE, 
434
 
              "ids_sasl_canon_user(user=%s, realm=%s)\n", 
435
 
              user, user_realm ? user_realm : "", 0);
436
 
 
437
 
    sasl_getprop(conn, SASL_MECHNAME, (const void**)&mech);
438
 
    if (mech == NULL) {
439
 
        LDAPDebug0Args(LDAP_DEBUG_TRACE, "Unable to read SASL mechanism while "
440
 
              "canonifying user.\n")
441
 
        goto fail;
442
 
    }
443
 
 
444
 
    if (strncasecmp(user, "dn:", 3) == 0) {
445
 
        sdn = slapi_sdn_new();
446
 
        slapi_sdn_set_dn_byval(sdn, user+3);
447
 
        isroot = slapi_dn_isroot(slapi_sdn_get_ndn(sdn));
448
 
    }
449
 
 
450
 
    if (isroot) {
451
 
        /* special case directory manager */
452
 
        dn = slapi_sdn_get_ndn(sdn);
453
 
        pw = config_get_rootpw();
454
 
        *out_ulen = PR_snprintf(out_user, out_umax, "dn: %s", dn);
455
 
    } else if (strcasecmp(mech, "ANONYMOUS") == 0) {
456
 
        /* SASL doesn't allow us to set the username to an empty string,
457
 
         * so we just set it to anonymous. */
458
 
        dn = "anonymous";
459
 
        PL_strncpyz(out_user, dn, out_umax);
460
 
        /* the length of out_user needs to be set for Cyrus SASL */
461
 
        *out_ulen = strlen(out_user);
462
 
    } else {
463
 
        /* map the sasl username into an entry */
464
 
        entry = ids_sasl_user_to_entry(conn, context, user, user_realm);
465
 
        if (entry == NULL) {
466
 
            /* Specific return value is supposed to be set instead of 
467
 
               an generic error (SASL_FAIL) for Cyrus SASL */
468
 
            returnvalue = SASL_NOAUTHZ;
469
 
            goto fail;
470
 
        }
471
 
        dn = slapi_entry_get_ndn(entry);
472
 
        pw = slapi_entry_attr_get_charptr(entry, "userpassword");
473
 
        *out_ulen = PR_snprintf(out_user, out_umax, "dn: %s", dn);
474
 
    }
475
 
 
476
 
    /* Need to set dn property to an empty string for the ANONYMOUS mechanism.  This
477
 
     * property determines what the bind identity will be if authentication succeeds. */
478
 
    if (strcasecmp(mech, "ANONYMOUS") == 0) {
479
 
        if (prop_set(propctx, "dn", "", -1) != 0) {
480
 
            LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(dn) failed\n", 0, 0, 0);
481
 
            goto fail;
482
 
        }
483
 
    } else if (prop_set(propctx, "dn", dn, -1) != 0) {
484
 
        LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(dn) failed\n", 0, 0, 0);
485
 
        goto fail;
486
 
    }
487
 
 
488
 
    /* We need to check if the first character of pw is an opening
489
 
     * brace since strstr will simply return it's first argument if
490
 
     * it is an empty string. */
491
 
    if (pw && (*pw == '{')) {
492
 
        if (strchr( pw, '}' )) {
493
 
            /* This password is stored in a non-cleartext format.
494
 
             * Any SASL mechanism that actually needs the
495
 
             * password is going to fail.  We should print a warning
496
 
             * to aid in troubleshooting. */
497
 
            LDAPDebug(LDAP_DEBUG_TRACE, "Warning: Detected a sasl bind attempt by an "
498
 
                      "entry whose password is stored in a non-cleartext format.  This "
499
 
                      "will not work for mechanisms which require a cleartext password "
500
 
                      "such as DIGEST-MD5 and CRAM-MD5.\n", 0, 0, 0);
501
 
        } else {
502
 
            /* This password doesn't have a storage prefix but
503
 
             * just happens to start with the '{' character.  We'll
504
 
             * assume that it's just a cleartext password without
505
 
             * the proper storage prefix. */
506
 
            clear = pw;
507
 
        }
508
 
    } else {
509
 
        /* This password has no storage prefix, or the password is empty */
510
 
        clear = pw;
511
 
    }
512
 
 
513
 
    if (clear) {
514
 
/* older versions of sasl do not have SASL_AUX_PASSWORD_PROP, so omit it */
515
 
#ifdef SASL_AUX_PASSWORD_PROP
516
 
        if (prop_set(propctx, SASL_AUX_PASSWORD_PROP, clear, -1) != 0) {
517
 
            /* Failure is benign here because some mechanisms don't support this property */
518
 
            /*LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(userpassword) failed\n", 0, 0, 0);
519
 
            goto fail */ ;
520
 
        }
521
 
#endif /* SASL_AUX_PASSWORD_PROP */
522
 
        if (prop_set(propctx, SASL_AUX_PASSWORD, clear, -1) != 0) {
523
 
            /* Failure is benign here because some mechanisms don't support this property */
524
 
            /*LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(userpassword) failed\n", 0, 0, 0);
525
 
            goto fail */ ;
526
 
        }
527
 
    }
528
 
 
529
 
    slapi_entry_free(entry);
530
 
    slapi_ch_free((void**)&user);
531
 
    slapi_ch_free((void**)&pw);
532
 
    slapi_sdn_free(&sdn);
533
 
 
534
 
    return SASL_OK;
535
 
 
536
 
fail:
537
 
    slapi_entry_free(entry);
538
 
    slapi_ch_free((void**)&user);
539
 
    slapi_ch_free((void**)&pw);
540
 
    slapi_sdn_free(&sdn);
541
 
 
542
 
    return returnvalue;
543
 
}
544
 
 
545
 
static int ids_sasl_getpluginpath(sasl_conn_t *conn, const char **path)
546
 
{
547
 
    /* Try to get path from config, otherwise check for SASL_PATH environment
548
 
     * variable.  If neither of these are set, default to /usr/lib64/sasl2 on
549
 
     * 64-bit Linux machines, and /usr/lib/sasl2 on all other platforms.
550
 
     */
551
 
    char *pluginpath = config_get_saslpath();
552
 
    if ((!pluginpath) || (*pluginpath == '\0')) {
553
 
        if (!(pluginpath = getenv("SASL_PATH"))) {
554
 
#if defined(LINUX) && defined(__LP64__)
555
 
            pluginpath = "/usr/lib64/sasl2";
556
 
            if (PR_SUCCESS != PR_Access(pluginpath, PR_ACCESS_EXISTS)) {
557
 
                /* Since the path does not exist, try gnu triplet. */
558
 
                pluginpath = "/usr/lib/x86_64-linux-gnu/sasl2";
559
 
            }
560
 
#else
561
 
            pluginpath = "/usr/lib/sasl2";
562
 
            if (PR_SUCCESS != PR_Access(pluginpath, PR_ACCESS_EXISTS)) {
563
 
                /* Since the path does not exist, try gnu triplet. */
564
 
                pluginpath = "/usr/lib/i386-linux-gnu/sasl2";
565
 
            }
566
 
#endif
567
 
        }
568
 
    }
569
 
    *path = pluginpath;
570
 
    return SASL_OK;
571
 
}
572
 
 
573
 
static sasl_callback_t ids_sasl_callbacks[] =
574
 
{
575
 
    {
576
 
      SASL_CB_GETOPT,
577
 
      (IFP) ids_sasl_getopt,
578
 
      NULL
579
 
    },
580
 
    {
581
 
      SASL_CB_LOG,
582
 
      (IFP) ids_sasl_log,
583
 
      NULL
584
 
    },
585
 
    {
586
 
      SASL_CB_PROXY_POLICY,
587
 
      (IFP) ids_sasl_proxy_policy,
588
 
      NULL
589
 
    },
590
 
    {
591
 
      SASL_CB_CANON_USER,
592
 
      (IFP) ids_sasl_canon_user,
593
 
      NULL
594
 
    },
595
 
    {
596
 
      SASL_CB_GETPATH,
597
 
      (IFP) ids_sasl_getpluginpath,
598
 
      NULL
599
 
    },
600
 
    {
601
 
      SASL_CB_LIST_END,
602
 
      (IFP) NULL,
603
 
      NULL
604
 
    }
605
 
};
606
 
 
607
 
static const char *dn_propnames[] = { "dn", 0 };
608
 
 
609
 
/*
610
 
 * initialize the sasl library
611
 
 */
612
 
int ids_sasl_init(void)
613
 
{
614
 
    static int inited = 0;
615
 
    int result;
616
 
 
617
 
    LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_init\n", 0, 0, 0 );
618
 
 
619
 
    PR_ASSERT(inited == 0);
620
 
    inited = 1;
621
 
 
622
 
    serverfqdn = get_localhost_DNS();
623
 
 
624
 
    LDAPDebug(LDAP_DEBUG_TRACE, "sasl service fqdn is: %s\n", 
625
 
                  serverfqdn, 0, 0);
626
 
 
627
 
    /* get component ID for internal operations */
628
 
    generate_component_id();
629
 
 
630
 
    /* Set SASL memory allocation callbacks */
631
 
    sasl_set_alloc(
632
 
        (sasl_malloc_t *)slapi_ch_malloc,
633
 
        (sasl_calloc_t *)slapi_ch_calloc,
634
 
        (sasl_realloc_t *)slapi_ch_realloc,
635
 
        (sasl_free_t *)nssasl_free );
636
 
 
637
 
    /* Set SASL mutex callbacks */
638
 
    sasl_set_mutex(
639
 
        (sasl_mutex_alloc_t *)nssasl_mutex_alloc,
640
 
        (sasl_mutex_lock_t *)nssasl_mutex_lock,
641
 
        (sasl_mutex_unlock_t *)nssasl_mutex_unlock,
642
 
        (sasl_mutex_free_t *)nssasl_mutex_free);
643
 
 
644
 
    result = sasl_server_init(ids_sasl_callbacks, "iDS");
645
 
 
646
 
    if (result != SASL_OK) {
647
 
        LDAPDebug(LDAP_DEBUG_TRACE, "failed to initialize sasl library\n", 
648
 
                  0, 0, 0);
649
 
        return result;
650
 
    }
651
 
 
652
 
    result = sasl_auxprop_add_plugin("iDS", ids_auxprop_plug_init);
653
 
 
654
 
    LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_init\n", 0, 0, 0 );
655
 
 
656
 
    return result;
657
 
}
658
 
 
659
 
/*
660
 
 * create a sasl server connection
661
 
 */
662
 
void ids_sasl_server_new(Connection *conn)
663
 
{
664
 
    int rc;
665
 
    sasl_conn_t *sasl_conn = NULL;
666
 
    struct propctx *propctx;
667
 
    sasl_security_properties_t secprops = {0};
668
 
 
669
 
    LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_server_new (%s)\n", serverfqdn, 0, 0 );
670
 
 
671
 
    rc = sasl_server_new("ldap", 
672
 
                         serverfqdn,
673
 
                         NULL,  /* user_realm */
674
 
                         NULL,  /* iplocalport */
675
 
                         NULL,  /* ipremoteport */
676
 
                         ids_sasl_callbacks,
677
 
                         SASL_SUCCESS_DATA, 
678
 
                         &sasl_conn);
679
 
 
680
 
    if (rc != SASL_OK) {
681
 
        LDAPDebug(LDAP_DEBUG_ANY, "sasl_server_new: %s\n", 
682
 
                  sasl_errstring(rc, NULL, NULL), 0, 0);
683
 
    }
684
 
 
685
 
    if (rc == SASL_OK) {
686
 
        propctx = sasl_auxprop_getctx(sasl_conn);
687
 
        if (propctx != NULL) {
688
 
            prop_request(propctx, dn_propnames);
689
 
        }
690
 
    }
691
 
 
692
 
    /* Enable security for this connection */
693
 
    secprops.maxbufsize = config_get_sasl_maxbufsize();
694
 
    secprops.max_ssf = 0xffffffff;
695
 
    secprops.min_ssf = config_get_minssf();
696
 
    /* If anonymous access is disabled, set the appropriate flag */
697
 
    if (config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) {
698
 
        secprops.security_flags = SASL_SEC_NOANONYMOUS;
699
 
    }
700
 
 
701
 
    rc = sasl_setprop(sasl_conn, SASL_SEC_PROPS, &secprops);
702
 
 
703
 
    if (rc != SASL_OK) {
704
 
        LDAPDebug(LDAP_DEBUG_ANY, "sasl_setprop: %s\n",
705
 
                  sasl_errstring(rc, NULL, NULL), 0, 0);
706
 
    }
707
 
    
708
 
    conn->c_sasl_conn = sasl_conn;
709
 
    conn->c_sasl_ssf = 0;
710
 
 
711
 
    LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_server_new\n", 0, 0, 0 );
712
 
 
713
 
    return;
714
 
}
715
 
 
716
 
/*
717
 
 * return sasl mechanisms available on this connection.
718
 
 * caller must free returned charray.
719
 
 */
720
 
char **ids_sasl_listmech(Slapi_PBlock *pb)
721
 
{
722
 
    char **ret, **others;
723
 
    const char *str;
724
 
    char *dupstr;
725
 
    sasl_conn_t *sasl_conn;
726
 
 
727
 
    LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_listmech\n", 0, 0, 0 );
728
 
 
729
 
    PR_ASSERT(pb);
730
 
 
731
 
    /* hard-wired mechanisms and slapi plugin registered mechanisms */
732
 
    ret = slapi_get_supported_saslmechanisms_copy();
733
 
 
734
 
    if (pb->pb_conn == NULL) return ret;
735
 
 
736
 
    sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
737
 
    if (sasl_conn == NULL) return ret;
738
 
 
739
 
    /* sasl library mechanisms are connection dependent */
740
 
    PR_Lock(pb->pb_conn->c_mutex);
741
 
    if (sasl_listmech(sasl_conn, 
742
 
                      NULL,     /* username */
743
 
                      "", ",", "",
744
 
                      &str, NULL, NULL) == SASL_OK) {
745
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl library mechs: %s\n", str, 0, 0);
746
 
        /* merge into result set */
747
 
        dupstr = slapi_ch_strdup(str);
748
 
        others = slapi_str2charray_ext(dupstr, ",", 0 /* don't list duplicate mechanisms */);
749
 
        charray_merge(&ret, others, 1);
750
 
        charray_free(others);
751
 
        slapi_ch_free((void**)&dupstr);
752
 
    }
753
 
    PR_Unlock(pb->pb_conn->c_mutex);
754
 
 
755
 
    LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_listmech\n", 0, 0, 0 );
756
 
 
757
 
    return ret;
758
 
}
759
 
 
760
 
/*
761
 
 * Determine whether a given sasl mechanism is supported by
762
 
 * this sasl connection. Returns true/false.
763
 
 * NOTE: caller must lock pb->pb_conn->c_mutex
764
 
 */
765
 
static int
766
 
ids_sasl_mech_supported(Slapi_PBlock *pb, const char *mech)
767
 
{
768
 
  int i, ret = 0;
769
 
  char **mechs;
770
 
  char *dupstr;
771
 
  const char *str;
772
 
  int sasl_result = 0;
773
 
  sasl_conn_t *sasl_conn = (sasl_conn_t *)pb->pb_conn->c_sasl_conn;
774
 
 
775
 
  LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_mech_supported\n", 0, 0, 0 );
776
 
 
777
 
 
778
 
  /* sasl_listmech is not thread-safe - caller must lock pb_conn */
779
 
  sasl_result = sasl_listmech(sasl_conn, 
780
 
                    NULL,     /* username */
781
 
                    "", ",", "",
782
 
                    &str, NULL, NULL);
783
 
  if (sasl_result != SASL_OK) {
784
 
    return 0;
785
 
  }
786
 
 
787
 
  dupstr = slapi_ch_strdup(str);
788
 
  mechs = slapi_str2charray(dupstr, ",");
789
 
 
790
 
  for (i = 0; mechs[i] != NULL; i++) {
791
 
    if (strcasecmp(mech, mechs[i]) == 0) {
792
 
      ret = 1;
793
 
      break;
794
 
    }
795
 
  }
796
 
 
797
 
  charray_free(mechs);
798
 
  slapi_ch_free((void**)&dupstr);
799
 
 
800
 
  LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_mech_supported\n", 0, 0, 0 );
801
 
 
802
 
  return ret;
803
 
}
804
 
 
805
 
/*
806
 
 * do a sasl bind and return a result
807
 
 */
808
 
void ids_sasl_check_bind(Slapi_PBlock *pb)
809
 
{
810
 
    int rc, isroot;
811
 
    long t;
812
 
    sasl_conn_t *sasl_conn;
813
 
    struct propctx *propctx;
814
 
    sasl_ssf_t *ssfp;
815
 
    char *activemech = NULL, *mech = NULL;
816
 
    char *username, *dn = NULL;
817
 
    const char *normdn = NULL;
818
 
    Slapi_DN *sdn = NULL;
819
 
    const char *sdata, *errstr;
820
 
    unsigned slen;
821
 
    int continuing = 0;
822
 
    int pwresponse_requested = 0;
823
 
    LDAPControl **ctrls;
824
 
    struct berval bvr, *cred;
825
 
    struct propval dnval[2];
826
 
    char authtype[256]; /* >26 (strlen(SLAPD_AUTH_SASL)+SASL_MECHNAMEMAX+1) */
827
 
    Slapi_Entry *bind_target_entry = NULL, *referral = NULL;
828
 
    Slapi_Backend *be = NULL;
829
 
    char errorbuf[BUFSIZ];
830
 
 
831
 
    LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_check_bind\n", 0, 0, 0 );
832
 
 
833
 
    PR_ASSERT(pb);
834
 
    PR_ASSERT(pb->pb_conn);
835
 
 
836
 
    PR_Lock(pb->pb_conn->c_mutex); /* BIG LOCK */
837
 
    continuing = pb->pb_conn->c_flags & CONN_FLAG_SASL_CONTINUE;
838
 
    pb->pb_conn->c_flags &= ~CONN_FLAG_SASL_CONTINUE; /* reset flag */
839
 
 
840
 
    sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
841
 
    if (sasl_conn == NULL) {
842
 
        PR_Unlock(pb->pb_conn->c_mutex);
843
 
        send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
844
 
                          "sasl library unavailable", 0, NULL );
845
 
        return;
846
 
    }
847
 
 
848
 
    slapi_pblock_get(pb, SLAPI_BIND_SASLMECHANISM, &mech);
849
 
    slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &cred);
850
 
    slapi_pblock_get(pb, SLAPI_PWPOLICY, &pwresponse_requested);
851
 
    PR_ASSERT(mech);
852
 
    PR_ASSERT(cred);
853
 
 
854
 
    /* Work around a bug in the sasl library. We've told the
855
 
     * library that CRAM-MD5 is disabled, but it gives us a
856
 
     * different error code to SASL_NOMECH.  Must be called
857
 
     * while holding the pb_conn lock
858
 
     */
859
 
    if (!ids_sasl_mech_supported(pb, mech)) {
860
 
      rc = SASL_NOMECH;
861
 
      goto sasl_check_result;
862
 
    }
863
 
 
864
 
    /* can't do any harm */
865
 
    if (cred->bv_len == 0) cred->bv_val = NULL;
866
 
 
867
 
    if (continuing) {
868
 
        /* 
869
 
         * RFC 2251: a client may abort a sasl bind negotiation by
870
 
         * sending a bindrequest with a different value in the
871
 
         * mechanism field.
872
 
         */
873
 
        sasl_getprop(sasl_conn, SASL_MECHNAME, (const void**)&activemech);
874
 
        if (activemech == NULL) {
875
 
            LDAPDebug(LDAP_DEBUG_TRACE, "could not get active sasl mechanism\n", 0, 0, 0);
876
 
            goto sasl_start;
877
 
        }
878
 
        if (strcasecmp(activemech, mech) != 0) {
879
 
            LDAPDebug(LDAP_DEBUG_TRACE, "sasl mechanisms differ: active=%s current=%s\n", 0, 0, 0);
880
 
            goto sasl_start;
881
 
        }
882
 
 
883
 
        rc = sasl_server_step(sasl_conn, 
884
 
                              cred->bv_val, cred->bv_len, 
885
 
                              &sdata, &slen);
886
 
        goto sasl_check_result;
887
 
    }
888
 
 
889
 
 sasl_start:
890
 
 
891
 
    /* Check if we are already authenticated via sasl.  If so,
892
 
     * dispose of the current sasl_conn and create a new one
893
 
     * using the new mechanism.  We also need to do this if the
894
 
     * mechanism changed in the middle of the SASL authentication
895
 
     * process. */
896
 
    if ((pb->pb_conn->c_flags & CONN_FLAG_SASL_COMPLETE) || continuing) {
897
 
        Slapi_Operation *operation;
898
 
        slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
899
 
        slapi_log_error(SLAPI_LOG_CONNS, "ids_sasl_check_bind",
900
 
                        "cleaning up sasl IO conn=%" NSPRIu64 " op=%d complete=%d continuing=%d\n",
901
 
                        (long long unsigned int)pb->pb_conn->c_connid, operation->o_opid,
902
 
                        (pb->pb_conn->c_flags & CONN_FLAG_SASL_COMPLETE), continuing);
903
 
        /* reset flag */
904
 
        pb->pb_conn->c_flags &= ~CONN_FLAG_SASL_COMPLETE;
905
 
 
906
 
        /* remove any SASL I/O from the connection */
907
 
        connection_set_io_layer_cb(pb->pb_conn, NULL, sasl_io_cleanup, NULL);
908
 
 
909
 
        /* dispose of sasl_conn and create a new sasl_conn */
910
 
        sasl_dispose(&sasl_conn);
911
 
        ids_sasl_server_new(pb->pb_conn);
912
 
        sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
913
 
 
914
 
        if (sasl_conn == NULL) {
915
 
            send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
916
 
                          "sasl library unavailable", 0, NULL );
917
 
            PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
918
 
            return;
919
 
        }
920
 
    }
921
 
 
922
 
    rc = sasl_server_start(sasl_conn, mech, 
923
 
                           cred->bv_val, cred->bv_len, 
924
 
                           &sdata, &slen);
925
 
 
926
 
 sasl_check_result:
927
 
 
928
 
    switch (rc) {
929
 
    case SASL_OK:               /* complete */
930
 
        /* retrieve the authenticated username */
931
 
        if (sasl_getprop(sasl_conn, SASL_USERNAME,
932
 
                         (const void**)&username) != SASL_OK) {
933
 
            PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
934
 
            send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
935
 
                             "could not obtain sasl username", 0, NULL);
936
 
            break;
937
 
        }
938
 
 
939
 
        LDAPDebug(LDAP_DEBUG_TRACE, "sasl authenticated mech=%s user=%s\n",
940
 
                  mech, username, 0);
941
 
 
942
 
        /* 
943
 
         * Retrieve the DN corresponding to the authenticated user.
944
 
         * This should have been set by the user canon callback
945
 
         * in an auxiliary property called "dn".
946
 
         */
947
 
        propctx = sasl_auxprop_getctx(sasl_conn);
948
 
        if (prop_getnames(propctx, dn_propnames, dnval) == 1) {
949
 
            if (dnval[0].values && dnval[0].values[0]) {
950
 
                dn = slapi_ch_smprintf("%s", dnval[0].values[0]);
951
 
            }
952
 
        }
953
 
        if (dn == NULL) {
954
 
            PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
955
 
            send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
956
 
                             "could not get auth dn from sasl", 0, NULL);
957
 
            break;
958
 
        }
959
 
 
960
 
        /* clean up already set TARGET */
961
 
        slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &sdn);
962
 
        slapi_sdn_free(&sdn);
963
 
 
964
 
        sdn = slapi_sdn_new_dn_passin(dn);
965
 
        normdn = slapi_sdn_get_dn(sdn);
966
 
 
967
 
        slapi_pblock_set( pb, SLAPI_BIND_TARGET_SDN, sdn );
968
 
 
969
 
        if ((sasl_getprop(sasl_conn, SASL_SSF, 
970
 
                          (const void**)&ssfp) == SASL_OK) && (*ssfp > 0)) {
971
 
            LDAPDebug(LDAP_DEBUG_TRACE, "sasl ssf=%u\n", (unsigned)*ssfp, 0, 0);
972
 
        } else {
973
 
            *ssfp = 0;
974
 
        }
975
 
 
976
 
        /* Set a flag to signify that sasl bind is complete */
977
 
        pb->pb_conn->c_flags |= CONN_FLAG_SASL_COMPLETE;
978
 
        /* note - we set this here in case there are pre-bind
979
 
           plugins that want to know what the negotiated
980
 
           ssf is - but this happens before we actually set
981
 
           up the socket for SASL encryption - so one
982
 
           consequence is that we attempt to do sasl
983
 
           encryption on the connection after the pre-bind
984
 
           plugin has been called, and sasl encryption fails
985
 
           and the operation returns an error */
986
 
        pb->pb_conn->c_sasl_ssf = (unsigned)*ssfp;
987
 
 
988
 
        /* set the connection bind credentials */
989
 
        PR_snprintf(authtype, sizeof(authtype), "%s%s", SLAPD_AUTH_SASL, mech);
990
 
        /* normdn is consumed by bind_credentials_set_nolock */
991
 
        bind_credentials_set_nolock(pb->pb_conn, authtype, 
992
 
                                    slapi_ch_strdup(normdn), 
993
 
                                    NULL, NULL, NULL, bind_target_entry);
994
 
 
995
 
        PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
996
 
 
997
 
        if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) != 0){
998
 
            break;
999
 
        }
1000
 
 
1001
 
        isroot = slapi_dn_isroot(normdn);
1002
 
 
1003
 
        if (!isroot )
1004
 
        {
1005
 
            /* check if the account is locked */
1006
 
            bind_target_entry = get_entry(pb,  normdn);
1007
 
            if ( bind_target_entry == NULL )
1008
 
            {
1009
 
                goto out;
1010
 
            } 
1011
 
            if ( slapi_check_account_lock(pb, bind_target_entry, pwresponse_requested, 1, 1) == 1) {
1012
 
                goto out;
1013
 
            }
1014
 
        }
1015
 
 
1016
 
        /* set the auth response control if requested */
1017
 
        slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrls);
1018
 
        if (slapi_control_present(ctrls, LDAP_CONTROL_AUTH_REQUEST, 
1019
 
                                  NULL, NULL)) {
1020
 
            slapi_add_auth_response_control(pb, normdn);
1021
 
        }
1022
 
 
1023
 
        if (slapi_mapping_tree_select(pb, &be, &referral, errorbuf) != LDAP_SUCCESS) {
1024
 
            send_nobackend_ldap_result( pb );
1025
 
            be = NULL;
1026
 
            LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_check_bind\n", 0, 0, 0 );
1027
 
            return; 
1028
 
        }
1029
 
 
1030
 
        if (referral) {
1031
 
            send_referrals_from_entry(pb,referral);
1032
 
            goto out;
1033
 
        }
1034
 
 
1035
 
        slapi_pblock_set( pb, SLAPI_BACKEND, be );
1036
 
 
1037
 
        slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
1038
 
        set_db_default_result_handlers(pb);
1039
 
 
1040
 
        /* check password expiry */
1041
 
        if (!isroot) {
1042
 
            int pwrc;
1043
 
 
1044
 
            pwrc = need_new_pw(pb, &t, bind_target_entry, pwresponse_requested);
1045
 
            
1046
 
            switch (pwrc) {
1047
 
            case 1:
1048
 
                slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
1049
 
                break;
1050
 
            case 2:
1051
 
                slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, t);
1052
 
                break;
1053
 
            case -1:
1054
 
                goto out;
1055
 
            default:
1056
 
                break;
1057
 
            }
1058
 
        }
1059
 
 
1060
 
        /* attach the sasl data */
1061
 
        if (slen != 0) {
1062
 
            bvr.bv_val = (char*)sdata;
1063
 
            bvr.bv_len = slen;
1064
 
            slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, &bvr);
1065
 
        }
1066
 
 
1067
 
        /* see if we negotiated a security layer */
1068
 
        if (*ssfp > 0) {
1069
 
            /* Enable SASL I/O on the connection */
1070
 
            PR_Lock(pb->pb_conn->c_mutex);
1071
 
            connection_set_io_layer_cb(pb->pb_conn, sasl_io_enable, NULL, NULL);
1072
 
            PR_Unlock(pb->pb_conn->c_mutex);
1073
 
        }
1074
 
 
1075
 
        /* send successful result */
1076
 
        send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
1077
 
 
1078
 
        /* remove the sasl data from the pblock */
1079
 
        slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, NULL);
1080
 
 
1081
 
        break;
1082
 
 
1083
 
    case SASL_CONTINUE:         /* another step needed */
1084
 
        pb->pb_conn->c_flags |= CONN_FLAG_SASL_CONTINUE;
1085
 
        PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
1086
 
 
1087
 
        if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) != 0){
1088
 
            break;
1089
 
        }
1090
 
 
1091
 
        /* attach the sasl data */
1092
 
        bvr.bv_val = (char*)sdata;
1093
 
        bvr.bv_len = slen;
1094
 
        slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, &bvr);
1095
 
 
1096
 
        /* send continuation result */
1097
 
        send_ldap_result( pb, LDAP_SASL_BIND_IN_PROGRESS, NULL, 
1098
 
                          NULL, 0, NULL );
1099
 
 
1100
 
        /* remove the sasl data from the pblock */
1101
 
        slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, NULL);
1102
 
 
1103
 
        break;
1104
 
 
1105
 
    case SASL_NOMECH:
1106
 
 
1107
 
        PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
1108
 
        send_ldap_result(pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
1109
 
                         "sasl mechanism not supported", 0, NULL);
1110
 
        break;
1111
 
 
1112
 
    default:                    /* other error */
1113
 
        errstr = sasl_errdetail(sasl_conn);
1114
 
 
1115
 
        PR_Unlock(pb->pb_conn->c_mutex); /* BIG LOCK */
1116
 
        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
1117
 
                         (char*)errstr, 0, NULL);
1118
 
        break;
1119
 
    }
1120
 
 
1121
 
    out:
1122
 
        if (referral)
1123
 
            slapi_entry_free(referral);
1124
 
        if (be)
1125
 
            slapi_be_Unlock(be);
1126
 
        if (bind_target_entry)
1127
 
            slapi_entry_free(bind_target_entry);
1128
 
 
1129
 
    LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_check_bind\n", 0, 0, 0 );
1130
 
 
1131
 
    return;
1132
 
}