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