]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
List supportedSASLmechanisms based upon what sasl_listmech() returns.
[openldap] / servers / slapd / bind.c
1 /* bind.c - decode an ldap bind operation and pass it to a backend db */
2
3 /*
4  * Copyright (c) 1995 Regents of the University of Michigan.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that this notice is preserved and that due credit is given
9  * to the University of Michigan at Ann Arbor. The name of the University
10  * may not be used to endorse or promote products derived from this
11  * software without specific prior written permission. This software
12  * is provided ``as is'' without express or implied warranty.
13  */
14
15 #include "portable.h"
16
17 #include <stdio.h>
18
19 #include <ac/string.h>
20 #include <ac/socket.h>
21
22 #include "slap.h"
23
24 int
25 do_bind(
26     Connection  *conn,
27     Operation   *op
28 )
29 {
30         BerElement      *ber = op->o_ber;
31         ber_int_t               version;
32         ber_tag_t method;
33         char            *mech;
34         char            *dn, *ndn;
35         ber_tag_t       tag;
36         int                     rc = LDAP_SUCCESS;
37         struct berval   cred;
38         Backend         *be;
39
40         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
41
42         dn = NULL;
43         ndn = NULL;
44         mech = NULL;
45         cred.bv_val = NULL;
46
47         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
48
49         /* Force to connection to "anonymous" until bind succeeds.
50          * This may need to be relocated or done on a case by case basis
51          * to handle certain SASL mechanisms.
52          */
53
54         if ( conn->c_cdn != NULL ) {
55                 free( conn->c_cdn );
56                 conn->c_cdn = NULL;
57         }
58
59         if ( conn->c_dn != NULL ) {
60                 free( conn->c_dn );
61                 conn->c_dn = NULL;
62         }
63
64         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
65
66         if ( op->o_dn != NULL ) {
67                 free( op->o_dn );
68                 op->o_dn = ch_strdup( "" );
69         }
70
71         if ( op->o_ndn != NULL ) {
72                 free( op->o_ndn );
73                 op->o_ndn = ch_strdup( "" );
74         }
75
76         /*
77          * Parse the bind request.  It looks like this:
78          *
79          *      BindRequest ::= SEQUENCE {
80          *              version         INTEGER,                 -- version
81          *              name            DistinguishedName,       -- dn
82          *              authentication  CHOICE {
83          *                      simple          [0] OCTET STRING -- passwd
84          *                      krbv42ldap      [1] OCTET STRING
85          *                      krbv42dsa       [2] OCTET STRING
86          *                      SASL            [3] SaslCredentials
87          *              }
88          *      }
89          *
90          *      SaslCredentials ::= SEQUENCE {
91      *          mechanism           LDAPString,
92      *          credentials         OCTET STRING OPTIONAL
93          *      }
94          */
95
96         tag = ber_scanf( ber, "{iat" /*}*/, &version, &dn, &method );
97
98         if ( tag == LBER_ERROR ) {
99                 Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
100                 send_ldap_disconnect( conn, op,
101                         LDAP_PROTOCOL_ERROR, "decoding error" );
102                 rc = -1;
103                 goto cleanup;
104         }
105
106         ndn = ch_strdup( dn );
107
108         if ( dn_normalize_case( ndn ) == NULL ) {
109                 Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n", dn, 0, 0 );
110                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
111                     "invalid DN", NULL, NULL );
112                 goto cleanup;
113         }
114
115         op->o_protocol = version;
116
117         if( method != LDAP_AUTH_SASL ) {
118                 tag = ber_scanf( ber, /*{*/ "o}", &cred );
119
120         } else {
121                 tag = ber_scanf( ber, "{a" /*}*/, &mech );
122
123                 if ( tag != LBER_ERROR ) {
124                         ber_len_t len;
125                         tag = ber_peek_tag( ber, &len );
126
127                         if ( tag == LDAP_TAG_LDAPCRED ) { 
128                                 tag = ber_scanf( ber, "o", &cred );
129                         }
130
131                         if ( tag != LBER_ERROR ) {
132                                 tag = ber_scanf( ber, /*{{*/ "}}" );
133                         }
134                 }
135         }
136
137         if ( tag == LBER_ERROR ) {
138                 send_ldap_disconnect( conn, op,
139                         LDAP_PROTOCOL_ERROR,
140                 "decoding error" );
141                 rc = -1;
142                 goto cleanup;
143         }
144
145         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
146                 Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
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 %d dn (%s) method %d\n",
155                         version, dn, method );
156         }
157
158         Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
159             op->o_connid, op->o_opid, ndn, method, 0 );
160
161         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
162                 Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
163                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
164                         NULL, "version not supported", NULL, NULL );
165                 goto cleanup;
166         }
167
168         if ( method == LDAP_AUTH_SASL ) {
169                 if ( version < LDAP_VERSION3 ) {
170                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%d\n",
171                                 version, 0, 0 );
172                         send_ldap_disconnect( conn, op,
173                                 LDAP_PROTOCOL_ERROR, "sasl bind requires LDAPv3" );
174                         rc = -1;
175                         goto cleanup;
176                 }
177
178                 if( mech == NULL || *mech == '\0' ) {
179                         Debug( LDAP_DEBUG_ANY,
180                                 "do_bind: no sasl mechanism provided\n",
181                                 version, 0, 0 );
182                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
183                                 NULL, "no sasl mechanism provided", NULL, NULL );
184                         goto cleanup;
185                 }
186
187                 if( !charray_inlist( supportedSASLMechanisms, mech ) ) {
188                         Debug( LDAP_DEBUG_ANY,
189                                 "do_bind: sasl mechanism \"%s\" not supported.\n",
190                                 mech, 0, 0 );
191                         send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
192                                 NULL, "sasl mechanism not supported", NULL, NULL );
193                         goto cleanup;
194                 }
195
196                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
197
198                 if ( conn->c_authmech != NULL ) {
199                         assert( conn->c_bind_in_progress );
200
201                         if((strcmp(conn->c_authmech, mech) != 0)) {
202                                 /* mechanism changed, cancel in progress bind */
203                                 conn->c_bind_in_progress = 0;
204                                 if( conn->c_authstate != NULL ) {
205                                         free(conn->c_authstate);
206                                         conn->c_authstate = NULL;
207                                 }
208                                 free(conn->c_authmech);
209                                 conn->c_authmech = NULL;
210                         }
211
212 #ifdef LDAP_DEBUG
213                 } else {
214                         assert( !conn->c_bind_in_progress );
215                         assert( conn->c_authmech == NULL );
216                         assert( conn->c_authstate == NULL );
217 #endif
218                 }
219
220         } else {
221                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
222
223                 if ( conn->c_authmech != NULL ) {
224                         assert( conn->c_bind_in_progress );
225
226                         /* cancel in progress bind */
227                         conn->c_bind_in_progress = 0;
228
229                         if( conn->c_authstate != NULL ) {
230                                 free(conn->c_authstate);
231                                 conn->c_authstate = NULL;
232                         }
233                         free(conn->c_authmech);
234                         conn->c_authmech = NULL;
235                 }
236         }
237
238         conn->c_protocol = version;
239         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
240
241         /* accept null binds */
242         if ( ndn == NULL || *ndn == '\0' ) {
243                 /*
244                  * we already forced connection to "anonymous", we just
245                  * need to send success
246                  */
247                 send_ldap_result( conn, op, LDAP_SUCCESS,
248                         NULL, NULL, NULL, NULL );
249                 goto cleanup;
250         }
251
252         /*
253          * We could be serving multiple database backends.  Select the
254          * appropriate one, or send a referral to our "referral server"
255          * if we don't hold it.
256          */
257
258         if ( (be = select_backend( ndn )) == NULL ) {
259                 if ( cred.bv_len == 0 ) {
260                         send_ldap_result( conn, op, LDAP_SUCCESS,
261                                 NULL, NULL, NULL, NULL );
262
263                 } else if ( default_referral ) {
264                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
265                                 NULL, NULL, default_referral, NULL );
266
267                 } else {
268                         send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
269                                 NULL, NULL, NULL, NULL );
270                 }
271
272                 goto cleanup;
273         }
274
275         if ( be->be_bind ) {
276                 /* alias suffix */
277                 char *edn;
278
279                 /* deref suffix alias if appropriate */
280                 ndn = suffix_alias( be, ndn );
281
282                 if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) {
283                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
284
285                         conn->c_cdn = dn;
286                         dn = NULL;
287
288                         if(edn != NULL) {
289                                 conn->c_dn = edn;
290                         } else {
291                                 conn->c_dn = ndn;
292                                 ndn = NULL;
293                         }
294
295                         Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
296                         conn->c_cdn, conn->c_dn, method );
297
298                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
299
300                         /* send this here to avoid a race condition */
301                         send_ldap_result( conn, op, LDAP_SUCCESS,
302                                 NULL, NULL, NULL, NULL );
303
304                 } else if (edn != NULL) {
305                         free( edn );
306                 }
307
308         } else {
309                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
310                         NULL, "Function not implemented", NULL, NULL );
311         }
312
313 cleanup:
314         if( dn != NULL ) {
315                 free( dn );
316         }
317         if( ndn != NULL ) {
318                 free( ndn );
319         }
320         if ( mech != NULL ) {
321                 free( mech );
322         }
323         if ( cred.bv_val != NULL ) {
324                 free( cred.bv_val );
325         }
326
327         return rc;
328 }