]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
Update for Alpha3 from -devel as of OPENLDAP_DEVEL_981116.
[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, len;
32         unsigned long   rc;
33         char            *dn;
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, &dn, &method, &cred);
69         } else {
70                 rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
71         }
72         }
73 #else
74         rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
75 #endif
76         if ( rc == LBER_ERROR ) {
77                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
78                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
79                     "decoding error" );
80                 return;
81         }
82 #ifdef LDAP_COMPAT30
83         if ( conn->c_version == 30 ) {
84                 switch ( method ) {
85                 case LDAP_AUTH_SIMPLE_30:
86                         method = LDAP_AUTH_SIMPLE;
87                         break;
88 #ifdef HAVE_KERBEROS
89                 case LDAP_AUTH_KRBV41_30:
90                         method = LDAP_AUTH_KRBV41;
91                         break;
92                 case LDAP_AUTH_KRBV42_30:
93                         method = LDAP_AUTH_KRBV42;
94                         break;
95 #endif
96                 }
97         }
98 #endif /* compat30 */
99         dn_normalize( dn );
100
101         Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
102             conn->c_connid, op->o_opid, dn, method, 0 );
103
104         if ( version != LDAP_VERSION2 ) {
105                 if ( dn != NULL ) {
106                         free( dn );
107                 }
108                 if ( cred.bv_val != NULL ) {
109                         free( cred.bv_val );
110                 }
111
112                 Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
113                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
114                     "version not supported" );
115                 return;
116         }
117
118         Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
119             version, dn, method );
120
121         /* accept null binds */
122         if ( dn == NULL || *dn == '\0' ) {
123                 if ( dn != NULL ) {
124                         free( dn );
125                 }
126                 if ( cred.bv_val != NULL ) {
127                         free( cred.bv_val );
128                 }
129
130                 send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
131                 return;
132         }
133
134         /*
135          * We could be serving multiple database backends.  Select the
136          * appropriate one, or send a referral to our "referral server"
137          * if we don't hold it.
138          */
139
140         if ( (be = select_backend( dn )) == NULL ) {
141                 free( dn );
142                 if ( cred.bv_val != NULL ) {
143                         free( cred.bv_val );
144                 }
145                 if ( cred.bv_len == 0 ) {
146                         send_ldap_result( conn, op, LDAP_SUCCESS,
147                                 NULL, NULL );
148                 } else if ( default_referral && *default_referral ) {
149                         send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS,
150                                 NULL, default_referral );
151                 } else {
152                         send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
153                                 NULL, default_referral );
154                 }
155                 return;
156         }
157
158         /* alias suffix */
159         dn = suffixAlias ( dn, op, be );
160
161         if ( be->be_bind != NULL ) {
162                 if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) {
163                         pthread_mutex_lock( &conn->c_dnmutex );
164                         if ( conn->c_dn != NULL ) {
165                                 free( conn->c_dn );
166                         }
167                         conn->c_dn = strdup( dn );
168                         pthread_mutex_unlock( &conn->c_dnmutex );
169
170                         /* send this here to avoid a race condition */
171                         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
172                 }
173         } else {
174                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
175                     "Function not implemented" );
176         }
177
178         free( dn );
179         if ( cred.bv_val != NULL ) {
180                 free( cred.bv_val );
181         }
182 }