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