]> git.sur5r.net Git - openldap/blob - servers/slapd/bind.c
5c1e264636f7a442ea7448ef4d62e2194de5d10c
[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 extern Backend  *select_backend();
25 extern char     *suffixAlias();
26
27 extern char     *default_referral;
28
29 void
30 do_bind(
31     Connection  *conn,
32     Operation   *op
33 )
34 {
35         BerElement      *ber = op->o_ber;
36         int             version, method, len, rc;
37         char            *dn;
38         struct berval   cred;
39         Backend         *be;
40
41         Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
42
43         /*
44          * Parse the bind request.  It looks like this:
45          *
46          *      BindRequest ::= SEQUENCE {
47          *              version         INTEGER,                 -- version
48          *              name            DistinguishedName,       -- dn
49          *              authentication  CHOICE {
50          *                      simple          [0] OCTET STRING -- passwd
51          *                      krbv42ldap      [1] OCTET STRING
52          *                      krbv42dsa       [1] OCTET STRING
53          *              }
54          *      }
55          */
56
57 #ifdef LDAP_COMPAT30
58         /*
59          * in version 3.0 there is an extra SEQUENCE tag after the
60          * BindRequest SEQUENCE tag.
61          */
62
63         {
64         BerElement      tber;
65         unsigned long   tlen, ttag;
66
67         tber = *op->o_ber;
68         ttag = ber_skip_tag( &tber, &tlen );
69         if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) {
70                 Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n", 0, 0, 0 );
71                 conn->c_version = 30;
72                 rc = ber_scanf(ber, "{{iato}}", &version, &dn, &method, &cred);
73         } else {
74                 rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
75         }
76         }
77 #else
78         rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
79 #endif
80         if ( rc == LBER_ERROR ) {
81                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
82                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
83                     "decoding error" );
84                 return;
85         }
86 #ifdef LDAP_COMPAT30
87         if ( conn->c_version == 30 ) {
88                 switch ( method ) {
89                 case LDAP_AUTH_SIMPLE_30:
90                         method = LDAP_AUTH_SIMPLE;
91                         break;
92 #ifdef HAVE_KERBEROS
93                 case LDAP_AUTH_KRBV41_30:
94                         method = LDAP_AUTH_KRBV41;
95                         break;
96                 case LDAP_AUTH_KRBV42_30:
97                         method = LDAP_AUTH_KRBV42;
98                         break;
99 #endif
100                 }
101         }
102 #endif /* compat30 */
103         dn_normalize( dn );
104
105         Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
106             conn->c_connid, op->o_opid, dn, method, 0 );
107
108         if ( version != LDAP_VERSION2 ) {
109                 if ( dn != NULL ) {
110                         free( dn );
111                 }
112                 if ( cred.bv_val != NULL ) {
113                         free( cred.bv_val );
114                 }
115
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                 return;
120         }
121
122         Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
123             version, dn, method );
124
125         /* accept null binds */
126         if ( dn == NULL || *dn == '\0' ) {
127                 if ( dn != NULL ) {
128                         free( dn );
129                 }
130                 if ( cred.bv_val != NULL ) {
131                         free( cred.bv_val );
132                 }
133
134                 send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
135                 return;
136         }
137
138         /*
139          * We could be serving multiple database backends.  Select the
140          * appropriate one, or send a referral to our "referral server"
141          * if we don't hold it.
142          */
143
144         if ( (be = select_backend( dn )) == NULL ) {
145                 free( dn );
146                 if ( cred.bv_val != NULL ) {
147                         free( cred.bv_val );
148                 }
149                 if ( cred.bv_len == 0 ) {
150                         send_ldap_result( conn, op, LDAP_SUCCESS,
151                                 NULL, NULL );
152                 } else if ( default_referral && *default_referral ) {
153                         send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS,
154                                 NULL, default_referral );
155                 } else {
156                         send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
157                                 NULL, default_referral );
158                 }
159                 return;
160         }
161
162         /* alias suffix */
163         dn = suffixAlias ( dn, op, be );
164
165         if ( be->be_bind != NULL ) {
166                 if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) {
167                         pthread_mutex_lock( &conn->c_dnmutex );
168                         if ( conn->c_dn != NULL ) {
169                                 free( conn->c_dn );
170                         }
171                         conn->c_dn = strdup( dn );
172                         pthread_mutex_unlock( &conn->c_dnmutex );
173
174                         /* send this here to avoid a race condition */
175                         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
176                 }
177         } else {
178                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
179                     "Function not implemented" );
180         }
181
182         free( dn );
183         if ( cred.bv_val != NULL ) {
184                 free( cred.bv_val );
185         }
186 }