]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
6a78b4a51afde281424ec12c55cd4a688b5b6cc6
[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 = NULL;
40         struct berval dn = { 0, NULL };
41         struct berval *pdn = NULL;
42         struct berval *ndn = NULL;
43         ber_tag_t tag;
44         int     rc = LDAP_SUCCESS;
45         const char *text;
46         struct berval cred = { 0, NULL };
47         Backend *be;
48
49 #ifdef NEW_LOGGING
50         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
51                 "do_bind: conn %d\n", conn->c_connid ));
52 #else
53         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
54 #endif
55
56         /*
57          * Force to connection to "anonymous" until bind succeeds.
58          */
59         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
60         connection2anonymous( conn );
61         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
62
63         if ( op->o_dn != NULL ) {
64                 free( op->o_dn );
65                 op->o_dn = ch_strdup( "" );
66         }
67
68         if ( op->o_ndn != NULL ) {
69                 free( op->o_ndn );
70                 op->o_ndn = ch_strdup( "" );
71         }
72
73         /*
74          * Parse the bind request.  It looks like this:
75          *
76          *      BindRequest ::= SEQUENCE {
77          *              version         INTEGER,                 -- version
78          *              name            DistinguishedName,       -- dn
79          *              authentication  CHOICE {
80          *                      simple          [0] OCTET STRING -- passwd
81          *                      krbv42ldap      [1] OCTET STRING
82          *                      krbv42dsa       [2] OCTET STRING
83          *                      SASL            [3] SaslCredentials
84          *              }
85          *      }
86          *
87          *      SaslCredentials ::= SEQUENCE {
88      *          mechanism           LDAPString,
89      *          credentials         OCTET STRING OPTIONAL
90          *      }
91          */
92
93         tag = ber_scanf( ber, "{iot" /*}*/, &version, &dn, &method );
94
95         if ( tag == LBER_ERROR ) {
96 #ifdef NEW_LOGGING
97                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
98                         "do_bind: conn %d  ber_scanf failed\n", conn->c_connid ));
99 #else
100                 Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
101 #endif
102                 send_ldap_disconnect( conn, op,
103                         LDAP_PROTOCOL_ERROR, "decoding error" );
104                 rc = -1;
105                 goto cleanup;
106         }
107
108         op->o_protocol = version;
109
110         if( method != LDAP_AUTH_SASL ) {
111                 tag = ber_scanf( ber, /*{*/ "o}", &cred );
112
113         } else {
114                 tag = ber_scanf( ber, "{a" /*}*/, &mech );
115
116                 if ( tag != LBER_ERROR ) {
117                         ber_len_t len;
118                         tag = ber_peek_tag( ber, &len );
119
120                         if ( tag == LDAP_TAG_LDAPCRED ) { 
121                                 tag = ber_scanf( ber, "o", &cred );
122                         } else {
123                                 tag = LDAP_TAG_LDAPCRED;
124                                 cred.bv_val = NULL;
125                                 cred.bv_len = 0;
126                         }
127
128                         if ( tag != LBER_ERROR ) {
129                                 tag = ber_scanf( ber, /*{{*/ "}}" );
130                         }
131                 }
132         }
133
134         if ( tag == LBER_ERROR ) {
135                 send_ldap_disconnect( conn, op,
136                         LDAP_PROTOCOL_ERROR,
137                 "decoding error" );
138                 rc = SLAPD_DISCONNECT;
139                 goto cleanup;
140         }
141
142         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
143 #ifdef NEW_LOGGING
144                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
145                         "do_bind: conn %d  get_ctrls failed\n", conn->c_connid ));
146 #else
147                 Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
148 #endif
149                 goto cleanup;
150         } 
151
152         rc = dnPretty( NULL, &dn, &pdn );
153         if ( rc != LDAP_SUCCESS ) {
154 #ifdef NEW_LOGGING
155                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
156                         "do_bind: conn %d  invalid dn (%s)\n",
157                         conn->c_connid, dn.bv_val ));
158 #else
159                 Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n",
160                         dn.bv_val, 0, 0 );
161 #endif
162                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
163                     "invalid DN", NULL, NULL );
164                 goto cleanup;
165         }
166
167         rc = dnNormalize( NULL, &dn, &ndn );
168         if ( rc != LDAP_SUCCESS ) {
169 #ifdef NEW_LOGGING
170                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
171                         "do_bind: conn %d  invalid dn (%s)\n",
172                         conn->c_connid, dn.bv_val ));
173 #else
174                 Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n",
175                         dn.bv_val, 0, 0 );
176 #endif
177                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
178                     "invalid DN", NULL, NULL );
179                 goto cleanup;
180         }
181
182         if( method == LDAP_AUTH_SASL ) {
183 #ifdef NEW_LOGGING
184                 LDAP_LOG(( "operation",  LDAP_LEVEL_DETAIL1,
185                         "do_sasl_bind: conn %d  dn (%s) mech %s\n", conn->c_connid,
186                         pdn->bv_val, mech ));
187 #else
188                 Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
189                         pdn->bv_val, mech, NULL );
190 #endif
191
192         } else {
193 #ifdef NEW_LOGGING
194                 LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
195                         "do_bind: conn %d  version=%ld dn=\"%s\" method=%ld\n",
196                         conn->c_connid, (unsigned long) version,
197                         pdn->bv_val, (unsigned long)method ));
198 #else
199                 Debug( LDAP_DEBUG_TRACE,
200                         "do_bind: version=%ld dn=\"%s\" method=%ld\n",
201                         (unsigned long) version,
202                         pdn->bv_val, (unsigned long) method );
203 #endif
204         }
205
206         Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d BIND dn=\"%s\" method=%ld\n",
207             op->o_connid, op->o_opid, pdn->bv_val, (unsigned long) method, 0 );
208
209         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
210 #ifdef NEW_LOGGING
211                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
212                         "do_bind: conn %d  unknown version = %ld\n",
213                         conn->c_connid, (unsigned long)version ));
214 #else
215                 Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n",
216                         (unsigned long) version, 0, 0 );
217 #endif
218                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
219                         NULL, "requested protocol version not supported", NULL, NULL );
220                 goto cleanup;
221
222         } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) &&
223                 version < LDAP_VERSION3 )
224         {
225                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
226                         NULL, "requested protocol version not allowed", NULL, NULL );
227                 goto cleanup;
228         }
229
230         /* we set connection version regardless of whether bind succeeds
231          * or not.
232          */
233         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
234         conn->c_protocol = version;
235         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
236
237         if ( method == LDAP_AUTH_SASL ) {
238                 char *edn;
239                 slap_ssf_t ssf = 0;
240
241                 if ( version < LDAP_VERSION3 ) {
242 #ifdef NEW_LOGGING
243                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
244                                 "do_bind: conn %d  sasl with LDAPv%ld\n",
245                                 conn->c_connid, (unsigned long)version ));
246 #else
247                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
248                                 (unsigned long) version, 0, 0 );
249 #endif
250                         send_ldap_disconnect( conn, op,
251                                 LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" );
252                         rc = SLAPD_DISCONNECT;
253                         goto cleanup;
254                 }
255
256                 if( mech == NULL || *mech == '\0' ) {
257 #ifdef NEW_LOGGING
258                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
259                                    "do_bind: conn %d  no SASL mechanism provided\n",
260                                    conn->c_connid ));
261 #else
262                         Debug( LDAP_DEBUG_ANY,
263                                 "do_bind: no sasl mechanism provided\n",
264                                 0, 0, 0 );
265 #endif
266                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
267                                 NULL, "no SASL mechanism provided", NULL, NULL );
268                         goto cleanup;
269                 }
270
271                 /* check restrictions */
272                 rc = backend_check_restrictions( NULL, conn, op, mech, &text );
273                 if( rc != LDAP_SUCCESS ) {
274                         send_ldap_result( conn, op, rc,
275                                 NULL, text, NULL, NULL );
276                         goto cleanup;
277                 }
278
279                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
280                 if ( conn->c_sasl_bind_in_progress ) {
281                         if((strcmp(conn->c_sasl_bind_mech, mech) != 0)) {
282                                 /* mechanism changed between bind steps */
283                                 slap_sasl_reset(conn);
284                         }
285                 } else {
286                         conn->c_sasl_bind_mech = mech;
287                         mech = NULL;
288                 }
289                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
290
291                 edn = NULL;
292                 rc = slap_sasl_bind( conn, op,
293                         pdn->bv_val, ndn->bv_val,
294                         &cred, &edn, &ssf );
295
296                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
297                 if( rc == LDAP_SUCCESS ) {
298                         conn->c_dn = edn;
299                         if( edn != NULL ) {
300                                 conn->c_ndn = ch_strdup( edn );
301                                 dn_normalize( conn->c_ndn );
302                         }
303                         conn->c_authmech = conn->c_sasl_bind_mech;
304                         conn->c_sasl_bind_mech = NULL;
305                         conn->c_sasl_bind_in_progress = 0;
306
307                         conn->c_sasl_ssf = ssf;
308                         if( ssf > conn->c_ssf ) {
309                                 conn->c_ssf = ssf;
310                         }
311
312                         if( conn->c_dn != NULL ) {
313                                 ber_len_t max = sockbuf_max_incoming;
314                                 ber_sockbuf_ctrl( conn->c_sb,
315                                         LBER_SB_OPT_SET_MAX_INCOMING, &max );
316                         }
317
318                 } else if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) {
319                         conn->c_sasl_bind_in_progress = 1;
320
321                 } else {
322                         if ( conn->c_sasl_bind_mech ) {
323                                 free( conn->c_sasl_bind_mech );
324                                 conn->c_sasl_bind_mech = NULL;
325                         }
326                         conn->c_sasl_bind_in_progress = 0;
327                 }
328                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
329
330                 goto cleanup;
331
332         } else {
333                 /* Not SASL, cancel any in-progress bind */
334                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
335
336                 if ( conn->c_sasl_bind_mech != NULL ) {
337                         free(conn->c_sasl_bind_mech);
338                         conn->c_sasl_bind_mech = NULL;
339                 }
340                 conn->c_sasl_bind_in_progress = 0;
341
342                 slap_sasl_reset( conn );
343                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
344         }
345
346         if ( method == LDAP_AUTH_SIMPLE ) {
347                 /* accept "anonymous" binds */
348                 if ( cred.bv_len == 0 || ndn->bv_len == 0 ) {
349                         rc = LDAP_SUCCESS;
350                         text = NULL;
351
352                         if( cred.bv_len &&
353                                 !( global_allows & SLAP_ALLOW_BIND_ANON_CRED ))
354                         {
355                                 /* cred is not empty, disallow */
356                                 rc = LDAP_INVALID_CREDENTIALS;
357
358                         } else if ( ndn->bv_len &&
359                                 !( global_allows & SLAP_ALLOW_BIND_ANON_DN ))
360                         {
361                                 /* DN is not empty, disallow */
362                                 rc = LDAP_UNWILLING_TO_PERFORM;
363                                 text = "unwilling to allow anonymous bind with non-empty DN";
364
365                         } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) {
366                                 /* disallow */
367                                 rc = LDAP_INAPPROPRIATE_AUTH;
368                                 text = "anonymous bind disallowed";
369
370                         } else {
371                                 rc = backend_check_restrictions( NULL, conn, op, mech, &text );
372                         }
373
374                         /*
375                          * we already forced connection to "anonymous",
376                          * just need to send success
377                          */
378                         send_ldap_result( conn, op, rc,
379                                 NULL, text, NULL, NULL );
380 #ifdef NEW_LOGGING
381                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
382                                    "do_bind: conn %d  v%d anonymous bind\n",
383                                    conn->c_connid, version ));
384 #else
385                         Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n",
386                                 version, 0, 0 );
387 #endif
388                         goto cleanup;
389
390                 } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) {
391                         /* disallow simple authentication */
392                         rc = LDAP_UNWILLING_TO_PERFORM;
393                         text = "unwilling to perform simple authentication";
394
395                         send_ldap_result( conn, op, rc,
396                                 NULL, text, NULL, NULL );
397 #ifdef NEW_LOGGING
398                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
399                                    "do_bind: conn %d  v%d simple bind(%s) disallowed\n",
400                                    conn->c_connid, version, ndn ));
401 #else
402                         Debug( LDAP_DEBUG_TRACE,
403                                 "do_bind: v%d simple bind(%s) disallowed\n",
404                                 version, ndn, 0 );
405 #endif
406                         goto cleanup;
407                 }
408
409 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
410         } else if ( method == LDAP_AUTH_KRBV41 || method == LDAP_AUTH_KRBV42 ) {
411                 if ( global_disallows & SLAP_DISALLOW_BIND_KRBV4 ) {
412                         /* disallow simple authentication */
413                         rc = LDAP_UNWILLING_TO_PERFORM;
414                         text = "unwilling to perform Kerberos V4 bind";
415
416                         send_ldap_result( conn, op, rc,
417                                 NULL, text, NULL, NULL );
418 #ifdef NEW_LOGGING
419                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
420                                    "do_bind: conn %d  v%d Kerberos V4 bind\n",
421                                    conn->c_connid, version ));
422 #else
423                         Debug( LDAP_DEBUG_TRACE, "do_bind: v%d Kerberos V4 bind\n",
424                                 version, 0, 0 );
425 #endif
426                         goto cleanup;
427                 }
428 #endif
429
430         } else {
431                 rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
432                 text = "unknown authentication method";
433
434                 send_ldap_result( conn, op, rc,
435                         NULL, text, NULL, NULL );
436 #ifdef NEW_LOGGING
437                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
438                            "do_bind: conn %ld  v%d unknown authentication method (%ld)\n",
439                            conn->c_connid, version, method ));
440 #else
441                 Debug( LDAP_DEBUG_TRACE,
442                         "do_bind: v%d unknown authentication method (%ld)\n",
443                         version, method, 0 );
444 #endif
445                 goto cleanup;
446         }
447
448         /*
449          * We could be serving multiple database backends.  Select the
450          * appropriate one, or send a referral to our "referral server"
451          * if we don't hold it.
452          */
453
454         if ( (be = select_backend( ndn->bv_val, 0, 0 )) == NULL ) {
455                 if ( default_referral ) {
456                         struct berval **ref = referral_rewrite( default_referral,
457                                 NULL, pdn->bv_val, LDAP_SCOPE_DEFAULT );
458
459                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
460                                 NULL, NULL, ref ? ref : default_referral, NULL );
461
462                         ber_bvecfree( ref );
463
464                 } else {
465                         /* noSuchObject is not allowed to be returned by bind */
466                         send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
467                                 NULL, NULL, NULL, NULL );
468                 }
469
470                 goto cleanup;
471         }
472
473         /* check restrictions */
474         rc = backend_check_restrictions( be, conn, op, NULL, &text );
475         if( rc != LDAP_SUCCESS ) {
476                 send_ldap_result( conn, op, rc,
477                         NULL, text, NULL, NULL );
478                 goto cleanup;
479         }
480
481         conn->c_authz_backend = be;
482
483         if ( be->be_bind ) {
484                 int ret;
485                 /* alias suffix */
486                 char *edn = NULL;
487
488                 /* deref suffix alias if appropriate */
489                 ndn->bv_val = suffix_alias( be, ndn->bv_val );
490                 ndn->bv_len = strlen( ndn->bv_val );
491
492                 ret = (*be->be_bind)( be, conn, op,
493                         pdn->bv_val, ndn->bv_val,
494                         method, &cred, &edn );
495
496                 if ( ret == 0 ) {
497                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
498
499                         conn->c_cdn = pdn->bv_val;
500                         pdn->bv_val = NULL;
501                         pdn->bv_len = 0;
502
503                         if(edn != NULL) {
504                                 conn->c_dn = edn;
505                         } else {
506                                 conn->c_dn = ch_strdup( conn->c_cdn );
507                         }
508                         conn->c_ndn = ndn->bv_val;
509                         ndn->bv_val = NULL;
510                         ndn->bv_len = 0;
511
512                         if( conn->c_dn != NULL ) {
513                                 ber_len_t max = sockbuf_max_incoming;
514                                 ber_sockbuf_ctrl( conn->c_sb,
515                                         LBER_SB_OPT_SET_MAX_INCOMING, &max );
516                         }
517
518 #ifdef NEW_LOGGING
519                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
520                                 "do_bind: conn %d  v%d bind: \"%s\" to \"%s\" \n",
521                                 conn->c_connid, version, conn->c_cdn, conn->c_dn ));
522 #else
523                         Debug( LDAP_DEBUG_TRACE,
524                                 "do_bind: v%d bind: \"%s\" to \"%s\"\n",
525                                 version, conn->c_cdn, conn->c_dn );
526 #endif
527
528                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
529
530                         /* send this here to avoid a race condition */
531                         send_ldap_result( conn, op, LDAP_SUCCESS,
532                                 NULL, NULL, NULL, NULL );
533
534                 } else if (edn != NULL) {
535                         free( edn );
536                 }
537
538         } else {
539                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
540                         NULL, "operation not supported within namingContext",
541                         NULL, NULL );
542         }
543
544 cleanup:
545         free( dn.bv_val );
546         if( pdn != NULL ) {
547                 ber_bvfree( pdn );
548         }
549         if( ndn != NULL ) {
550                 ber_bvfree( ndn );
551         }
552         if ( mech != NULL ) {
553                 free( mech );
554         }
555         if ( cred.bv_val != NULL ) {
556                 free( cred.bv_val );
557         }
558
559         return rc;
560 }