]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
41e94d310693ee2f34234720034fce021fac26fd
[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 void
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            *cdn, *ndn;
35         ber_tag_t       rc;
36         struct berval   cred;
37         Backend         *be;
38
39         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
40
41         cdn = NULL;
42         ndn = NULL;
43         mech = NULL;
44         cred.bv_val = NULL;
45
46         /*
47          * Parse the bind request.  It looks like this:
48          *
49          *      BindRequest ::= SEQUENCE {
50          *              version         INTEGER,                 -- version
51          *              name            DistinguishedName,       -- dn
52          *              authentication  CHOICE {
53          *                      simple          [0] OCTET STRING -- passwd
54          *                      krbv42ldap      [1] OCTET STRING
55          *                      krbv42dsa       [1] OCTET STRING
56          *              }
57          *      }
58          */
59
60         rc = ber_scanf( ber, "{iat" /*}*/, &version, &cdn, &method );
61
62         if ( rc == LBER_ERROR ) {
63                 Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
64                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
65                     "decoding error" );
66                 goto cleanup;
67         }
68
69         if( method != LDAP_AUTH_SASL ) {
70                 rc = ber_scanf( ber, /*{*/ "o}", &cred );
71
72         } else {
73                 rc = ber_scanf( ber, "{a" /*}*/, &mech );
74
75                 if ( rc != LBER_ERROR ) {
76                         ber_len_t len;
77                         rc = ber_peek_tag( ber, &len );
78
79                         if ( rc == LDAP_TAG_LDAPCRED ) { 
80                                 rc = ber_scanf( ber, "o", &cred );
81                         }
82
83                         if ( rc != LBER_ERROR ) {
84                                 rc = ber_scanf( ber, /*{{*/ "}}" );
85                         }
86                 }
87         }
88
89         if ( rc == LBER_ERROR ) {
90                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
91                 "decoding error" );
92                 goto cleanup;
93         }
94
95 #ifdef GET_CTRLS
96         if( get_ctrls( conn, op, 1 ) == -1 ) {
97                 Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
98                 goto cleanup;
99         } 
100 #endif
101
102         if( method == LDAP_AUTH_SASL ) {
103                 Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
104                         cdn, mech, NULL );
105         } else {
106                 Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
107                         version, cdn, method );
108         }
109
110         ndn = dn_normalize_case( ch_strdup( cdn ) );
111
112         Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
113             conn->c_connid, op->o_opid, ndn, method, 0 );
114
115         if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
116                 Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
117                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
118                     "version not supported" );
119                 goto cleanup;
120         }
121
122         if ( method == LDAP_AUTH_SASL ) {
123                 if ( version < LDAP_VERSION3 ) {
124                         Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%d\n",
125                                 version, 0, 0 );
126                         send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
127                                 "sasl bind requires LDAPv3" );
128                         goto cleanup;
129                 }
130
131                 if( mech == NULL || *mech == '\0' ) {
132                         Debug( LDAP_DEBUG_ANY,
133                                 "do_bind: no sasl mechanism provided\n",
134                                 version, 0, 0 );
135                         /* XXYYZ need to check this return code */
136                         send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
137                                 NULL, "no sasl mechanism provided." );
138                         goto cleanup;
139                 }
140
141                 if( 1 ) {
142                         Debug( LDAP_DEBUG_ANY,
143                                 "do_bind: sasl mechanism \"%s\" not supported.\n",
144                                 mech, 0, 0 );
145                         /* XXYYZ need to check this return code */
146                         send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
147                                 NULL, "no sasl mechanism provided." );
148                         goto cleanup;
149                 }
150         }
151
152         /* accept null binds */
153         if ( ndn == NULL || *ndn == '\0' ) {
154                 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
155
156                 conn->c_protocol = version;
157
158                 if ( conn->c_cdn != NULL ) {
159                         free( conn->c_cdn );
160                         conn->c_cdn = NULL;
161                 }
162
163                 if ( conn->c_dn != NULL ) {
164                         free( conn->c_dn );
165                         conn->c_dn = NULL;
166                 }
167
168                 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
169
170                 send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
171                 goto cleanup;
172         }
173
174         /*
175          * We could be serving multiple database backends.  Select the
176          * appropriate one, or send a referral to our "referral server"
177          * if we don't hold it.
178          */
179
180         if ( (be = select_backend( ndn )) == NULL ) {
181                 if ( cred.bv_len == 0 ) {
182                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
183
184                         conn->c_protocol = version;
185
186                         if ( conn->c_cdn != NULL ) {
187                                 free( conn->c_cdn );
188                                 conn->c_cdn = NULL;
189                         }
190
191                         if ( conn->c_dn != NULL ) {
192                                 free( conn->c_dn );
193                                 conn->c_dn = NULL;
194                         }
195
196                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
197
198                         send_ldap_result( conn, op, LDAP_SUCCESS,
199                                 NULL, NULL );
200                 } else if ( default_referral && *default_referral ) {
201                         send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS,
202                                 NULL, default_referral );
203                 } else {
204                         send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
205                                 NULL, default_referral );
206                 }
207                 goto cleanup;
208         }
209
210         if ( be->be_bind ) {
211                 /* alias suffix */
212                 char *edn;
213
214                 ndn = suffixAlias( ndn, op, be );
215
216                 if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) {
217                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
218
219                         conn->c_protocol = version;
220
221                         if ( conn->c_cdn != NULL ) {
222                                 free( conn->c_cdn );
223                         }
224
225                         conn->c_cdn = cdn;
226                         cdn = NULL;
227
228                         if ( conn->c_dn != NULL ) {
229                                 free( conn->c_dn );
230                         }
231
232                         if(edn != NULL) {
233                                 conn->c_dn = edn;
234                         } else {
235                                 conn->c_dn = ndn;
236                                 ndn = NULL;
237                         }
238
239                         Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
240                         conn->c_cdn, conn->c_dn, method );
241
242                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
243
244                         /* send this here to avoid a race condition */
245                         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
246
247                 } else if (edn != NULL) {
248                         free( edn );
249                 }
250
251         } else {
252                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
253                     "Function not implemented" );
254         }
255
256 cleanup:
257         if( cdn != NULL ) {
258                 free( cdn );
259         }
260         if( ndn != NULL ) {
261                 free( ndn );
262         }
263         if ( mech != NULL ) {
264                 free( mech );
265         }
266         if ( cred.bv_val != NULL ) {
267                 free( cred.bv_val );
268         }
269 }