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