]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
Per ITS#419, don't require SLAPD_RLOOKUPS when HAVE_TCPD
[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-1999 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         struct berval   cred;
45         Backend         *be;
46
47         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
48
49         dn = NULL;
50         ndn = NULL;
51         mech = NULL;
52         cred.bv_val = NULL;
53
54         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
55
56         /* Force to connection to "anonymous" until bind succeeds.
57          * This may need to be relocated or done on a case by case basis
58          * to handle certain SASL mechanisms.
59          */
60
61         if ( conn->c_cdn != NULL ) {
62                 free( conn->c_cdn );
63                 conn->c_cdn = NULL;
64         }
65
66         if ( conn->c_dn != NULL ) {
67                 free( conn->c_dn );
68                 conn->c_dn = NULL;
69         }
70
71         conn->c_authz_backend = NULL;
72
73         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
74
75         if ( op->o_dn != NULL ) {
76                 free( op->o_dn );
77                 op->o_dn = ch_strdup( "" );
78         }
79
80         if ( op->o_ndn != NULL ) {
81                 free( op->o_ndn );
82                 op->o_ndn = ch_strdup( "" );
83         }
84
85         /*
86          * Parse the bind request.  It looks like this:
87          *
88          *      BindRequest ::= SEQUENCE {
89          *              version         INTEGER,                 -- version
90          *              name            DistinguishedName,       -- dn
91          *              authentication  CHOICE {
92          *                      simple          [0] OCTET STRING -- passwd
93          *                      krbv42ldap      [1] OCTET STRING
94          *                      krbv42dsa       [2] OCTET STRING
95          *                      SASL            [3] SaslCredentials
96          *              }
97          *      }
98          *
99          *      SaslCredentials ::= SEQUENCE {
100      *          mechanism           LDAPString,
101      *          credentials         OCTET STRING OPTIONAL
102          *      }
103          */
104
105         tag = ber_scanf( ber, "{iat" /*}*/, &version, &dn, &method );
106
107         if ( tag == LBER_ERROR ) {
108                 Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
109                 send_ldap_disconnect( conn, op,
110                         LDAP_PROTOCOL_ERROR, "decoding error" );
111                 rc = -1;
112                 goto cleanup;
113         }
114
115         ndn = ch_strdup( dn );
116
117         if ( dn_normalize( ndn ) == NULL ) {
118                 Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n", dn, 0, 0 );
119                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
120                     "invalid DN", NULL, NULL );
121                 goto cleanup;
122         }
123
124         op->o_protocol = version;
125
126         if( method != LDAP_AUTH_SASL ) {
127                 tag = ber_scanf( ber, /*{*/ "o}", &cred );
128
129         } else {
130                 tag = ber_scanf( ber, "{a" /*}*/, &mech );
131
132                 if ( tag != LBER_ERROR ) {
133                         ber_len_t len;
134                         tag = ber_peek_tag( ber, &len );
135
136                         if ( tag == LDAP_TAG_LDAPCRED ) { 
137                                 tag = ber_scanf( ber, "o", &cred );
138                         }
139
140                         if ( tag != LBER_ERROR ) {
141                                 tag = ber_scanf( ber, /*{{*/ "}}" );
142                         }
143                 }
144         }
145
146         if ( tag == LBER_ERROR ) {
147                 send_ldap_disconnect( conn, op,
148                         LDAP_PROTOCOL_ERROR,
149                 "decoding error" );
150                 rc = -1;
151                 goto cleanup;
152         }
153
154         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
155                 Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
156                 goto cleanup;
157         } 
158
159         if( method == LDAP_AUTH_SASL ) {
160                 Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
161                         dn, mech, NULL );
162         } else {
163                 Debug( LDAP_DEBUG_TRACE, "do_bind: version=%ld dn=\"%s\" method=%ld\n",
164                         (unsigned long) version, dn, (unsigned long) method );
165         }
166
167         Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d BIND dn=\"%s\" method=%ld\n",
168             op->o_connid, op->o_opid, ndn, (unsigned long) method, 0 );
169
170         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
171                 Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n",
172                         (unsigned long) version, 0, 0 );
173                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
174                         NULL, "version not supported", NULL, NULL );
175                 goto cleanup;
176         }
177
178         if ( method == LDAP_AUTH_SASL ) {
179                 if ( version < LDAP_VERSION3 ) {
180                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
181                                 (unsigned long) version, 0, 0 );
182                         send_ldap_disconnect( conn, op,
183                                 LDAP_PROTOCOL_ERROR, "sasl bind requires LDAPv3" );
184                         rc = -1;
185                         goto cleanup;
186                 }
187
188                 if( mech == NULL || *mech == '\0' ) {
189                         Debug( LDAP_DEBUG_ANY,
190                                 "do_bind: no sasl mechanism provided\n",
191                                 0, 0, 0 );
192                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
193                                 NULL, "no sasl mechanism provided", NULL, NULL );
194                         goto cleanup;
195                 }
196
197                 if( !charray_inlist( supportedSASLMechanisms, mech ) ) {
198                         Debug( LDAP_DEBUG_ANY,
199                                 "do_bind: sasl mechanism=\"%s\" not supported.\n",
200                                 mech, 0, 0 );
201                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
202                                 NULL, "sasl mechanism not supported", NULL, NULL );
203                         goto cleanup;
204                 }
205
206                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
207
208                 if ( conn->c_authmech != NULL ) {
209                         assert( conn->c_bind_in_progress );
210
211                         if((strcmp(conn->c_authmech, mech) != 0)) {
212                                 /* mechanism changed, cancel in progress bind */
213                                 conn->c_bind_in_progress = 0;
214                                 if( conn->c_authstate != NULL ) {
215                                         free(conn->c_authstate);
216                                         conn->c_authstate = NULL;
217                                 }
218                                 free(conn->c_authmech);
219                                 conn->c_authmech = NULL;
220                         }
221
222 #ifdef LDAP_DEBUG
223                 } else {
224                         assert( !conn->c_bind_in_progress );
225                         assert( conn->c_authmech == NULL );
226                         assert( conn->c_authstate == NULL );
227 #endif
228                 }
229         } else {
230                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
231
232                 if ( conn->c_authmech != NULL ) {
233                         assert( conn->c_bind_in_progress );
234
235                         /* cancel in progress bind */
236                         conn->c_bind_in_progress = 0;
237
238                         if( conn->c_authstate != NULL ) {
239                                 free(conn->c_authstate);
240                                 conn->c_authstate = NULL;
241                         }
242                         free(conn->c_authmech);
243                         conn->c_authmech = NULL;
244                 }
245         }
246
247         conn->c_protocol = version;
248         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
249
250         /* accept null binds */
251         if ( ndn == NULL || *ndn == '\0' ) {
252                 /*
253                  * we already forced connection to "anonymous", we just
254                  * need to send success
255                  */
256                 send_ldap_result( conn, op, LDAP_SUCCESS,
257                         NULL, NULL, NULL, NULL );
258                 goto cleanup;
259         }
260
261         /*
262          * We could be serving multiple database backends.  Select the
263          * appropriate one, or send a referral to our "referral server"
264          * if we don't hold it.
265          */
266
267         if ( (be = select_backend( ndn )) == NULL ) {
268                 if ( cred.bv_len == 0 ) {
269                         send_ldap_result( conn, op, LDAP_SUCCESS,
270                                 NULL, NULL, NULL, NULL );
271
272                 } else if ( default_referral ) {
273                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
274                                 NULL, NULL, default_referral, NULL );
275
276                 } else {
277                         /* noSuchObject is not allowed to be returned by bind */
278                         send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
279                                 NULL, NULL, NULL, NULL );
280                 }
281
282                 goto cleanup;
283         }
284
285         conn->c_authz_backend = be;
286
287         /* make sure this backend recongizes critical controls */
288         rc = backend_check_controls( be, conn, op ) ;
289
290         if( rc != LDAP_SUCCESS ) {
291                 send_ldap_result( conn, op, rc,
292                         NULL, NULL, NULL, NULL );
293         }
294
295         if ( be->be_bind ) {
296                 int ret;
297                 /* alias suffix */
298                 char *edn = NULL;
299
300                 /* deref suffix alias if appropriate */
301                 ndn = suffix_alias( be, ndn );
302
303                 ret = (*be->be_bind)( be, conn, op, dn, ndn,
304                         method, mech, &cred, &edn );
305
306                 if ( ret == 0 ) {
307 #ifdef HAVE_CYRUS_SASL
308                         int ssf = 0;
309 #endif
310
311                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
312
313                         conn->c_cdn = dn;
314                         dn = NULL;
315
316                         if(edn != NULL) {
317                                 conn->c_dn = edn;
318                         } else {
319                                 conn->c_dn = ndn;
320                                 ndn = NULL;
321                         }
322
323                         Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
324                         conn->c_cdn, conn->c_dn, method );
325
326                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
327
328                         /* send this here to avoid a race condition */
329                         send_ldap_result( conn, op, LDAP_SUCCESS,
330                                 NULL, NULL, NULL, NULL );
331
332 #ifdef HAVE_CYRUS_SASL
333                         if ( conn->c_sasl_context != NULL && 
334                                 sasl_getprop( conn->c_sasl_context, SASL_SSF, (void **)&ssf )
335                                         == SASL_OK && ssf ) {
336                                 /* Enable encode/decode */
337                                 ldap_pvt_sasl_install( conn->c_sb, conn->c_sasl_context );
338                         }
339 #endif
340                 } else if (edn != NULL) {
341                         free( edn );
342                 }
343
344         } else {
345                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
346                         NULL, "Function not implemented", NULL, NULL );
347         }
348
349 cleanup:
350         if( dn != NULL ) {
351                 free( dn );
352         }
353         if( ndn != NULL ) {
354                 free( ndn );
355         }
356         if ( mech != NULL ) {
357                 free( mech );
358         }
359         if ( cred.bv_val != NULL ) {
360                 free( cred.bv_val );
361         }
362
363         return rc;
364 }