]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
Use calloc properly... could result in too few bytes being allocated.
[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 = *op->o_ber;
64         ttag = ber_skip_tag( &tber, &tlen );
65         if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) {
66                 Debug( LDAP_DEBUG_ANY, "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 #else
74         rc = ber_scanf( ber, "{iato}", &version, &cdn, &method, &cred );
75 #endif
76
77         if ( rc == LBER_ERROR ) {
78                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
79                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
80                     "decoding error" );
81                 return;
82         }
83 #ifdef LDAP_COMPAT30
84         if ( conn->c_version == 30 ) {
85                 switch ( method ) {
86                 case LDAP_AUTH_SIMPLE_30:
87                         method = LDAP_AUTH_SIMPLE;
88                         break;
89 #ifdef HAVE_KERBEROS
90                 case LDAP_AUTH_KRBV41_30:
91                         method = LDAP_AUTH_KRBV41;
92                         break;
93                 case LDAP_AUTH_KRBV42_30:
94                         method = LDAP_AUTH_KRBV42;
95                         break;
96 #endif
97                 }
98         }
99 #endif /* compat30 */
100
101         Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
102             version, cdn, method );
103
104         ndn = dn_normalize_case( ch_strdup( cdn ) );
105
106         Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
107             conn->c_connid, op->o_opid, ndn, method, 0 );
108
109         if ( version != LDAP_VERSION2 ) {
110                 if ( cdn != NULL ) {
111                         free( cdn );
112                 }
113                 if ( ndn != NULL ) {
114                         free( ndn );
115                 }
116                 if ( cred.bv_val != NULL ) {
117                         free( cred.bv_val );
118                 }
119
120                 Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
121                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
122                     "version not supported" );
123                 return;
124         }
125
126         /* accept null binds */
127         if ( ndn == NULL || *ndn == '\0' ) {
128                 if ( cdn != NULL ) {
129                         free( cdn );
130                 }
131                 if ( ndn != NULL ) {
132                         free( ndn );
133                 }
134                 if ( cred.bv_val != NULL ) {
135                         free( cred.bv_val );
136                 }
137
138                 ldap_pvt_thread_mutex_lock( &conn->c_dnmutex );
139
140                 conn->c_protocol = version;
141
142                 if ( conn->c_cdn != NULL ) {
143                         free( conn->c_cdn );
144                         conn->c_cdn = NULL;
145                 }
146
147                 if ( conn->c_dn != NULL ) {
148                         free( conn->c_dn );
149                         conn->c_dn = NULL;
150                 }
151
152                 ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex );
153
154                 send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
155                 return;
156         }
157
158         /*
159          * We could be serving multiple database backends.  Select the
160          * appropriate one, or send a referral to our "referral server"
161          * if we don't hold it.
162          */
163
164         if ( (be = select_backend( ndn )) == NULL ) {
165                 free( cdn );
166                 free( ndn );
167                 if ( cred.bv_val != NULL ) {
168                         free( cred.bv_val );
169                 }
170                 if ( cred.bv_len == 0 ) {
171                         ldap_pvt_thread_mutex_lock( &conn->c_dnmutex );
172
173                         conn->c_protocol = version;
174
175                         if ( conn->c_cdn != NULL ) {
176                                 free( conn->c_cdn );
177                                 conn->c_cdn = NULL;
178                         }
179
180                         if ( conn->c_dn != NULL ) {
181                                 free( conn->c_dn );
182                                 conn->c_dn = NULL;
183                         }
184
185                         ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex );
186
187                         send_ldap_result( conn, op, LDAP_SUCCESS,
188                                 NULL, NULL );
189                 } else if ( default_referral && *default_referral ) {
190                         send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS,
191                                 NULL, default_referral );
192                 } else {
193                         send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
194                                 NULL, default_referral );
195                 }
196                 return;
197         }
198
199         if ( be->be_bind ) {
200                 /* alias suffix */
201                 char *edn;
202
203                 ndn = suffixAlias( ndn, op, be );
204
205                 if ( (*be->be_bind)( be, conn, op, ndn, method, &cred, &edn ) == 0 ) {
206                         ldap_pvt_thread_mutex_lock( &conn->c_dnmutex );
207
208                         conn->c_protocol = version;
209
210                         if ( conn->c_cdn != NULL ) {
211                                 free( conn->c_cdn );
212                         }
213
214                         conn->c_cdn = cdn;
215                         cdn = NULL;
216
217                         if ( conn->c_dn != NULL ) {
218                                 free( conn->c_dn );
219                         }
220
221                         if(edn != NULL) {
222                                 conn->c_dn = edn;
223                         } else {
224                                 conn->c_dn = ndn;
225                                 ndn = NULL;
226                         }
227
228                         Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
229                         conn->c_cdn, conn->c_dn, method );
230
231                         ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex );
232
233                         /* send this here to avoid a race condition */
234                         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
235
236                 } else if (edn != NULL) {
237                         free( edn );
238                 }
239
240         } else {
241                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
242                     "Function not implemented" );
243         }
244
245         if( cdn != NULL ) {
246                 free( cdn );
247         }
248         if( ndn != NULL ) {
249                 free( ndn );
250         }
251         if ( cred.bv_val != NULL ) {
252                 free( cred.bv_val );
253         }
254 }