]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
e825eeb850d6352af19e2a05341d2d45e7c6ba0a
[openldap] / servers / slapd / bind.c
1 /* bind.c - decode an ldap bind operation and pass it to a backend db */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 /*
9  * Copyright (c) 1995 Regents of the University of Michigan.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms are permitted
13  * provided that this notice is preserved and that due credit is given
14  * to the University of Michigan at Ann Arbor. The name of the University
15  * may not be used to endorse or promote products derived from this
16  * software without specific prior written permission. This software
17  * is provided ``as is'' without express or implied warranty.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/string.h>
25 #include <ac/socket.h>
26
27 #include "ldap_pvt.h"
28 #include "slap.h"
29
30 int
31 do_bind(
32     Connection  *conn,
33     Operation   *op
34 )
35 {
36         BerElement      *ber = op->o_ber;
37         ber_int_t               version;
38         ber_tag_t method;
39         char            *mech;
40         char            *saslmech;
41         char            *dn;
42         char *ndn;
43         ber_tag_t       tag;
44         int                     rc = LDAP_SUCCESS;
45         const char      *text;
46         struct berval   cred;
47         Backend         *be;
48
49         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
50
51         dn = NULL;
52         ndn = NULL;
53         mech = NULL;
54         cred.bv_val = NULL;
55
56         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
57
58         /*
59          * Force to connection to "anonymous" until bind succeeds.
60          */
61
62         if ( conn->c_authmech != NULL ) {
63                 free( conn->c_authmech );
64                 conn->c_authmech = NULL;
65         }
66
67         if ( conn->c_cdn != NULL ) {
68                 free( conn->c_cdn );
69                 conn->c_cdn = NULL;
70         }
71
72         if ( conn->c_dn != NULL ) {
73                 free( conn->c_dn );
74                 conn->c_dn = NULL;
75         }
76
77         conn->c_authc_backend = NULL;
78         conn->c_authz_backend = NULL;
79
80         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
81
82         if ( op->o_dn != NULL ) {
83                 free( op->o_dn );
84                 op->o_dn = ch_strdup( "" );
85         }
86
87         if ( op->o_ndn != NULL ) {
88                 free( op->o_ndn );
89                 op->o_ndn = ch_strdup( "" );
90         }
91
92         /*
93          * Parse the bind request.  It looks like this:
94          *
95          *      BindRequest ::= SEQUENCE {
96          *              version         INTEGER,                 -- version
97          *              name            DistinguishedName,       -- dn
98          *              authentication  CHOICE {
99          *                      simple          [0] OCTET STRING -- passwd
100          *                      krbv42ldap      [1] OCTET STRING
101          *                      krbv42dsa       [2] OCTET STRING
102          *                      SASL            [3] SaslCredentials
103          *              }
104          *      }
105          *
106          *      SaslCredentials ::= SEQUENCE {
107      *          mechanism           LDAPString,
108      *          credentials         OCTET STRING OPTIONAL
109          *      }
110          */
111
112         tag = ber_scanf( ber, "{iat" /*}*/, &version, &dn, &method );
113
114         if ( tag == LBER_ERROR ) {
115                 Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
116                 send_ldap_disconnect( conn, op,
117                         LDAP_PROTOCOL_ERROR, "decoding error" );
118                 rc = -1;
119                 goto cleanup;
120         }
121
122         op->o_protocol = version;
123
124         if( method != LDAP_AUTH_SASL ) {
125                 tag = ber_scanf( ber, /*{*/ "o}", &cred );
126
127         } else {
128                 tag = ber_scanf( ber, "{a" /*}*/, &mech );
129
130                 if ( tag != LBER_ERROR ) {
131                         ber_len_t len;
132                         tag = ber_peek_tag( ber, &len );
133
134                         if ( tag == LDAP_TAG_LDAPCRED ) { 
135                                 tag = ber_scanf( ber, "o", &cred );
136                         }
137
138                         if ( tag != LBER_ERROR ) {
139                                 tag = ber_scanf( ber, /*{{*/ "}}" );
140                         }
141                 }
142         }
143
144         if ( tag == LBER_ERROR ) {
145                 send_ldap_disconnect( conn, op,
146                         LDAP_PROTOCOL_ERROR,
147                 "decoding error" );
148                 rc = SLAPD_DISCONNECT;
149                 goto cleanup;
150         }
151
152         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
153                 Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
154                 goto cleanup;
155         } 
156
157         ndn = ch_strdup( dn );
158
159         if ( dn_normalize( ndn ) == NULL ) {
160                 Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n", dn, 0, 0 );
161                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
162                     "invalid DN", NULL, NULL );
163                 goto cleanup;
164         }
165
166         if( method == LDAP_AUTH_SASL ) {
167                 Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
168                         dn, mech, NULL );
169         } else {
170                 Debug( LDAP_DEBUG_TRACE, "do_bind: version=%ld dn=\"%s\" method=%ld\n",
171                         (unsigned long) version, dn, (unsigned long) method );
172         }
173
174         Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d BIND dn=\"%s\" method=%ld\n",
175             op->o_connid, op->o_opid, ndn, (unsigned long) method, 0 );
176
177         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
178                 Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n",
179                         (unsigned long) version, 0, 0 );
180                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
181                         NULL, "requested protocol version not supported", NULL, NULL );
182                 goto cleanup;
183
184         } else if (( global_disallows & SLAP_DISALLOW_BIND_V2 ) &&
185                 version < LDAP_VERSION3 )
186         {
187                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
188                         NULL, "requested protocol version not allowed", NULL, NULL );
189                 goto cleanup;
190         }
191
192         /* we set connection version regardless of whether bind succeeds
193          * or not.
194          */
195         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
196         conn->c_protocol = version;
197         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
198
199         if ( method == LDAP_AUTH_SASL ) {
200                 char *edn;
201                 slap_ssf_t ssf = 0;
202
203                 if ( version < LDAP_VERSION3 ) {
204                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
205                                 (unsigned long) version, 0, 0 );
206                         send_ldap_disconnect( conn, op,
207                                 LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" );
208                         rc = SLAPD_DISCONNECT;
209                         goto cleanup;
210                 }
211
212                 if( mech == NULL || *mech == '\0' ) {
213                         Debug( LDAP_DEBUG_ANY,
214                                 "do_bind: no sasl mechanism provided\n",
215                                 0, 0, 0 );
216                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
217                                 NULL, "no SASL mechanism provided", NULL, NULL );
218                         goto cleanup;
219                 }
220
221                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
222
223                 if ( conn->c_sasl_bind_mech != NULL ) {
224                         /* SASL bind is in progress */
225                         saslmech = NULL;
226
227                         if((strcmp(conn->c_sasl_bind_mech, mech) != 0)) {
228                                 /* mechanism changed */
229                                 slap_sasl_reset(conn);
230                         }
231
232                         free( conn->c_sasl_bind_mech );
233                         conn->c_sasl_bind_mech = NULL;
234
235 #ifdef LDAP_DEBUG
236                 } else {
237                         /* SASL bind is NOT in progress */
238                         saslmech = mech;
239                         assert( conn->c_sasl_bind_mech == NULL );
240 #endif
241                 }
242
243                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
244
245                 edn = NULL;
246                 rc = slap_sasl_bind( conn, op, dn, ndn, saslmech, &cred,
247                         &edn, &ssf );
248
249                 if( rc == LDAP_SUCCESS ) {
250                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
251                         conn->c_dn = edn;
252                         conn->c_authmech = mech;
253                         if( ssf ) conn->c_sasl_layers++;
254                         conn->c_sasl_ssf = ssf;
255                         if( ssf > conn->c_ssf ) {
256                                 conn->c_ssf = ssf;
257                         }
258                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
259
260                 } else if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) {
261                         conn->c_sasl_bind_mech = mech;
262                 }
263
264                 mech = NULL;
265
266                 goto cleanup;
267
268         } else {
269                 /* Not SASL, cancel any in-progress bind */
270                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
271
272                 if ( conn->c_sasl_bind_mech != NULL ) {
273                         assert( conn->c_sasl_bind_in_progress );
274
275                         free(conn->c_sasl_bind_mech);
276                         conn->c_sasl_bind_mech = NULL;
277
278                 } else {
279                         assert( !conn->c_sasl_bind_in_progress );
280                 }
281
282                 slap_sasl_reset( conn );
283                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
284         }
285
286         /* accept "anonymous" binds */
287         if ( cred.bv_len == 0 || ndn == NULL || *ndn == '\0' ) {
288                 rc = LDAP_SUCCESS;
289                 text = NULL;
290
291                 if( cred.bv_len &&
292                         ( global_disallows & SLAP_DISALLOW_BIND_ANON_CRED ))
293                 {
294                         /* cred is not empty, disallow */
295                         rc = LDAP_INVALID_CREDENTIALS;
296
297                 } else if ( ndn != NULL && *ndn != '\0' &&
298                         ( global_disallows & SLAP_DISALLOW_BIND_ANON_DN ))
299                 {
300                         /* DN is not empty, disallow */
301                         rc = LDAP_UNWILLING_TO_PERFORM;
302                         text = "unwilling to allow anonymous bind with non-empty DN";
303
304                 } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) {
305                         /* disallow */
306                         rc = LDAP_UNWILLING_TO_PERFORM;
307                         text = "anonymous bind disallowed";
308                 }
309
310                 /*
311                  * we already forced connection to "anonymous",
312                  * just need to send success
313                  */
314                 send_ldap_result( conn, op, rc,
315                         NULL, text, NULL, NULL );
316                 Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n",
317                         version, 0, 0 );
318                 goto cleanup;
319         }
320
321         /*
322          * We could be serving multiple database backends.  Select the
323          * appropriate one, or send a referral to our "referral server"
324          * if we don't hold it.
325          */
326
327         if ( (be = select_backend( ndn )) == NULL ) {
328                 if ( default_referral ) {
329                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
330                                 NULL, NULL, default_referral, NULL );
331
332                 } else {
333                         /* noSuchObject is not allowed to be returned by bind */
334                         send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
335                                 NULL, NULL, NULL, NULL );
336                 }
337
338                 goto cleanup;
339         }
340
341         /* check restrictions */
342         rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
343         if( rc != LDAP_SUCCESS ) {
344                 send_ldap_result( conn, op, rc,
345                         NULL, text, NULL, NULL );
346                 goto cleanup;
347         }
348
349         conn->c_authz_backend = be;
350
351         if ( be->be_bind ) {
352                 int ret;
353                 /* alias suffix */
354                 char *edn = NULL;
355
356                 /* deref suffix alias if appropriate */
357                 ndn = suffix_alias( be, ndn );
358
359                 ret = (*be->be_bind)( be, conn, op, dn, ndn,
360                         method, &cred, &edn );
361
362                 if ( ret == 0 ) {
363                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
364
365                         conn->c_cdn = dn;
366                         dn = NULL;
367
368                         if(edn != NULL) {
369                                 conn->c_dn = edn;
370                         } else {
371                                 conn->c_dn = ndn;
372                                 ndn = NULL;
373                         }
374
375                         Debug( LDAP_DEBUG_TRACE, "do_bind: v%d bind: \"%s\" to \"%s\"\n",
376                         version, conn->c_cdn, conn->c_dn );
377
378                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
379
380                         /* send this here to avoid a race condition */
381                         send_ldap_result( conn, op, LDAP_SUCCESS,
382                                 NULL, NULL, NULL, NULL );
383
384                 } else if (edn != NULL) {
385                         free( edn );
386                 }
387
388         } else {
389                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
390                         NULL, "operation not supported within namingContext", NULL, NULL );
391         }
392
393 cleanup:
394         if( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
395                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
396
397                 /* dispose of mech */
398                 free( conn->c_sasl_bind_mech );
399                 conn->c_sasl_bind_mech = NULL;
400
401                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
402         }
403
404         if( dn != NULL ) {
405                 free( dn );
406         }
407         if( ndn != NULL ) {
408                 free( ndn );
409         }
410         if ( mech != NULL ) {
411                 free( mech );
412         }
413         if ( cred.bv_val != NULL ) {
414                 free( cred.bv_val );
415         }
416
417         return rc;
418 }