]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
Changed dnExtractRdn to use a provided berval instead of allocating one.
[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 = { 0, NULL };
42         struct berval ndn = { 0, 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.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, "{iot" /*}*/, &version, &dn, &method );
96
97         if ( tag == LBER_ERROR ) {
98 #ifdef NEW_LOGGING
99                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
100                         "do_bind: conn %d  ber_scanf failed\n", conn->c_connid ));
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, /*{*/ "o}", &cred );
114
115         } else {
116                 tag = ber_scanf( ber, "{a" /*}*/, &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, "o", &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", LDAP_LEVEL_INFO,
147                         "do_bind: conn %d  get_ctrls failed\n", conn->c_connid ));
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", LDAP_LEVEL_INFO,
158                         "do_bind: conn %d  invalid dn (%s)\n",
159                         conn->c_connid, dn.bv_val ));
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",  LDAP_LEVEL_DETAIL1,
172                         "do_sasl_bind: conn %d  dn (%s) mech %s\n", conn->c_connid,
173                         pdn.bv_val, mech ));
174 #else
175                 Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
176                         pdn.bv_val, mech, NULL );
177 #endif
178
179         } else {
180 #ifdef NEW_LOGGING
181                 LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
182                         "do_bind: conn %d  version=%ld dn=\"%s\" method=%ld\n",
183                         conn->c_connid, (unsigned long) version,
184                         pdn.bv_val, (unsigned long)method ));
185 #else
186                 Debug( LDAP_DEBUG_TRACE,
187                         "do_bind: version=%ld dn=\"%s\" method=%ld\n",
188                         (unsigned long) version,
189                         pdn.bv_val, (unsigned long) method );
190 #endif
191         }
192
193         Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d BIND dn=\"%s\" method=%ld\n",
194             op->o_connid, op->o_opid, pdn.bv_val, (unsigned long) method, 0 );
195
196         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
197 #ifdef NEW_LOGGING
198                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
199                         "do_bind: conn %d  unknown version = %ld\n",
200                         conn->c_connid, (unsigned long)version ));
201 #else
202                 Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n",
203                         (unsigned long) version, 0, 0 );
204 #endif
205                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
206                         NULL, "requested protocol version not supported", NULL, NULL );
207                 goto cleanup;
208
209         } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) &&
210                 version < LDAP_VERSION3 )
211         {
212                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
213                         NULL, "requested protocol version not allowed", NULL, NULL );
214                 goto cleanup;
215         }
216
217         /* we set connection version regardless of whether bind succeeds
218          * or not.
219          */
220         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
221         conn->c_protocol = version;
222         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
223
224         if ( method == LDAP_AUTH_SASL ) {
225                 char *edn;
226                 slap_ssf_t ssf = 0;
227
228                 if ( version < LDAP_VERSION3 ) {
229 #ifdef NEW_LOGGING
230                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
231                                 "do_bind: conn %d  sasl with LDAPv%ld\n",
232                                 conn->c_connid, (unsigned long)version ));
233 #else
234                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
235                                 (unsigned long) version, 0, 0 );
236 #endif
237                         send_ldap_disconnect( conn, op,
238                                 LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" );
239                         rc = SLAPD_DISCONNECT;
240                         goto cleanup;
241                 }
242
243                 if( mech == NULL || *mech == '\0' ) {
244 #ifdef NEW_LOGGING
245                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
246                                    "do_bind: conn %d  no SASL mechanism provided\n",
247                                    conn->c_connid ));
248 #else
249                         Debug( LDAP_DEBUG_ANY,
250                                 "do_bind: no sasl mechanism provided\n",
251                                 0, 0, 0 );
252 #endif
253                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
254                                 NULL, "no SASL mechanism provided", NULL, NULL );
255                         goto cleanup;
256                 }
257
258                 /* check restrictions */
259                 rc = backend_check_restrictions( NULL, conn, op, mech, &text );
260                 if( rc != LDAP_SUCCESS ) {
261                         send_ldap_result( conn, op, rc,
262                                 NULL, text, NULL, NULL );
263                         goto cleanup;
264                 }
265
266                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
267                 if ( conn->c_sasl_bind_in_progress ) {
268                         if((strcmp(conn->c_sasl_bind_mech, mech) != 0)) {
269                                 /* mechanism changed between bind steps */
270                                 slap_sasl_reset(conn);
271                         }
272                 } else {
273                         conn->c_sasl_bind_mech = mech;
274                         mech = NULL;
275                 }
276                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
277
278                 edn = NULL;
279                 rc = slap_sasl_bind( conn, op,
280                         &pdn, &ndn,
281                         &cred, &edn, &ssf );
282
283                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
284                 if( rc == LDAP_SUCCESS ) {
285                         conn->c_dn.bv_val = edn;
286                         if( edn != NULL ) {
287                                 struct berval *cndn;
288                                 conn->c_dn.bv_len = strlen( edn );
289                                 dnNormalize( NULL, &conn->c_dn, &cndn );
290                                 conn->c_ndn = *cndn;
291                                 free( cndn );
292                         }
293                         conn->c_authmech = conn->c_sasl_bind_mech;
294                         conn->c_sasl_bind_mech = NULL;
295                         conn->c_sasl_bind_in_progress = 0;
296
297                         conn->c_sasl_ssf = ssf;
298                         if( ssf > conn->c_ssf ) {
299                                 conn->c_ssf = ssf;
300                         }
301
302                         if( conn->c_dn.bv_len != 0 ) {
303                                 ber_len_t max = sockbuf_max_incoming;
304                                 ber_sockbuf_ctrl( conn->c_sb,
305                                         LBER_SB_OPT_SET_MAX_INCOMING, &max );
306                         }
307
308                 } else if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) {
309                         conn->c_sasl_bind_in_progress = 1;
310
311                 } else {
312                         if ( conn->c_sasl_bind_mech ) {
313                                 free( conn->c_sasl_bind_mech );
314                                 conn->c_sasl_bind_mech = NULL;
315                         }
316                         conn->c_sasl_bind_in_progress = 0;
317                 }
318                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
319
320                 goto cleanup;
321
322         } else {
323                 /* Not SASL, cancel any in-progress bind */
324                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
325
326                 if ( conn->c_sasl_bind_mech != NULL ) {
327                         free(conn->c_sasl_bind_mech);
328                         conn->c_sasl_bind_mech = NULL;
329                 }
330                 conn->c_sasl_bind_in_progress = 0;
331
332                 slap_sasl_reset( conn );
333                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
334         }
335
336         if ( method == LDAP_AUTH_SIMPLE ) {
337                 /* accept "anonymous" binds */
338                 if ( cred.bv_len == 0 || ndn.bv_len == 0 ) {
339                         rc = LDAP_SUCCESS;
340                         text = NULL;
341
342                         if( cred.bv_len &&
343                                 !( global_allows & SLAP_ALLOW_BIND_ANON_CRED ))
344                         {
345                                 /* cred is not empty, disallow */
346                                 rc = LDAP_INVALID_CREDENTIALS;
347
348                         } else if ( ndn.bv_len &&
349                                 !( global_allows & SLAP_ALLOW_BIND_ANON_DN ))
350                         {
351                                 /* DN is not empty, disallow */
352                                 rc = LDAP_UNWILLING_TO_PERFORM;
353                                 text = "unwilling to allow anonymous bind with non-empty DN";
354
355                         } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) {
356                                 /* disallow */
357                                 rc = LDAP_INAPPROPRIATE_AUTH;
358                                 text = "anonymous bind disallowed";
359
360                         } else {
361                                 rc = backend_check_restrictions( NULL, conn, op, mech, &text );
362                         }
363
364                         /*
365                          * we already forced connection to "anonymous",
366                          * just need to send success
367                          */
368                         send_ldap_result( conn, op, rc,
369                                 NULL, text, NULL, NULL );
370 #ifdef NEW_LOGGING
371                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
372                                    "do_bind: conn %d  v%d anonymous bind\n",
373                                    conn->c_connid, version ));
374 #else
375                         Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n",
376                                 version, 0, 0 );
377 #endif
378                         goto cleanup;
379
380                 } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) {
381                         /* disallow simple authentication */
382                         rc = LDAP_UNWILLING_TO_PERFORM;
383                         text = "unwilling to perform simple authentication";
384
385                         send_ldap_result( conn, op, rc,
386                                 NULL, text, NULL, NULL );
387 #ifdef NEW_LOGGING
388                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
389                                    "do_bind: conn %d  v%d simple bind(%s) disallowed\n",
390                                    conn->c_connid, version, ndn.bv_val ));
391 #else
392                         Debug( LDAP_DEBUG_TRACE,
393                                 "do_bind: v%d simple bind(%s) disallowed\n",
394                                 version, ndn.bv_val, 0 );
395 #endif
396                         goto cleanup;
397                 }
398
399 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
400         } else if ( method == LDAP_AUTH_KRBV41 || method == LDAP_AUTH_KRBV42 ) {
401                 if ( global_disallows & SLAP_DISALLOW_BIND_KRBV4 ) {
402                         /* disallow simple authentication */
403                         rc = LDAP_UNWILLING_TO_PERFORM;
404                         text = "unwilling to perform Kerberos V4 bind";
405
406                         send_ldap_result( conn, op, rc,
407                                 NULL, text, NULL, NULL );
408 #ifdef NEW_LOGGING
409                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
410                                    "do_bind: conn %d  v%d Kerberos V4 bind\n",
411                                    conn->c_connid, version ));
412 #else
413                         Debug( LDAP_DEBUG_TRACE, "do_bind: v%d Kerberos V4 bind\n",
414                                 version, 0, 0 );
415 #endif
416                         goto cleanup;
417                 }
418 #endif
419
420         } else {
421                 rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
422                 text = "unknown authentication method";
423
424                 send_ldap_result( conn, op, rc,
425                         NULL, text, NULL, NULL );
426 #ifdef NEW_LOGGING
427                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
428                            "do_bind: conn %ld  v%d unknown authentication method (%ld)\n",
429                            conn->c_connid, version, method ));
430 #else
431                 Debug( LDAP_DEBUG_TRACE,
432                         "do_bind: v%d unknown authentication method (%ld)\n",
433                         version, method, 0 );
434 #endif
435                 goto cleanup;
436         }
437
438         /*
439          * We could be serving multiple database backends.  Select the
440          * appropriate one, or send a referral to our "referral server"
441          * if we don't hold it.
442          */
443
444         if ( (be = select_backend( &ndn, 0, 0 )) == NULL ) {
445                 if ( default_referral ) {
446                         struct berval **ref = referral_rewrite( default_referral,
447                                 NULL, &pdn, LDAP_SCOPE_DEFAULT );
448
449                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
450                                 NULL, NULL, ref ? ref : default_referral, NULL );
451
452                         ber_bvecfree( ref );
453
454                 } else {
455                         /* noSuchObject is not allowed to be returned by bind */
456                         send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
457                                 NULL, NULL, NULL, NULL );
458                 }
459
460                 goto cleanup;
461         }
462
463         /* check restrictions */
464         rc = backend_check_restrictions( be, conn, op, NULL, &text );
465         if( rc != LDAP_SUCCESS ) {
466                 send_ldap_result( conn, op, rc,
467                         NULL, text, NULL, NULL );
468                 goto cleanup;
469         }
470
471         conn->c_authz_backend = be;
472
473         if ( be->be_bind ) {
474                 int ret;
475                 /* alias suffix */
476                 struct berval edn = { 0, NULL };
477
478                 /* deref suffix alias if appropriate */
479                 suffix_alias( be, &ndn );
480
481                 ret = (*be->be_bind)( be, conn, op,
482                         &pdn, &ndn, method, &cred, &edn );
483
484                 if ( ret == 0 ) {
485                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
486
487                         if(edn.bv_len) {
488                                 conn->c_dn = edn;
489                         } else {
490                                 ber_dupbv( &conn->c_dn, &pdn );
491                         }
492                         conn->c_cdn = pdn.bv_val;
493                         pdn.bv_val = NULL;
494                         pdn.bv_len = 0;
495
496                         conn->c_ndn = ndn;
497                         ndn.bv_val = NULL;
498                         ndn.bv_len = 0;
499
500                         if( conn->c_dn.bv_len != 0 ) {
501                                 ber_len_t max = sockbuf_max_incoming;
502                                 ber_sockbuf_ctrl( conn->c_sb,
503                                         LBER_SB_OPT_SET_MAX_INCOMING, &max );
504                         }
505
506 #ifdef NEW_LOGGING
507                         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
508                                 "do_bind: conn %d  v%d bind: \"%s\" to \"%s\" \n",
509                                 conn->c_connid, version, conn->c_cdn, conn->c_dn.bv_val ));
510 #else
511                         Debug( LDAP_DEBUG_TRACE,
512                                 "do_bind: v%d bind: \"%s\" to \"%s\"\n",
513                                 version, conn->c_cdn, conn->c_dn.bv_val );
514 #endif
515
516                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
517
518                         /* send this here to avoid a race condition */
519                         send_ldap_result( conn, op, LDAP_SUCCESS,
520                                 NULL, NULL, NULL, NULL );
521
522                 } else if (edn.bv_val != NULL) {
523                         free( edn.bv_val );
524                 }
525
526         } else {
527                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
528                         NULL, "operation not supported within namingContext",
529                         NULL, NULL );
530         }
531
532 cleanup:
533         free( dn.bv_val );
534         if( pdn.bv_val != NULL ) {
535                 free( pdn.bv_val );
536         }
537         if( ndn.bv_val != NULL ) {
538                 free( ndn.bv_val );
539         }
540         if ( mech != NULL ) {
541                 free( mech );
542         }
543         if ( cred.bv_val != NULL ) {
544                 free( cred.bv_val );
545         }
546
547         return rc;
548 }