]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/bind.c
6fa83775b13a87549c583edea8770afd01314862
[openldap] / servers / slapd / back-ldap / bind.c
1 /* bind.c - ldap backend bind function */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7 /* This is an altered version */
8 /*
9  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
10  * 
11  * Permission is granted to anyone to use this software for any purpose
12  * on any computer system, and to alter it and redistribute it, subject
13  * to the following restrictions:
14  * 
15  * 1. The author is not responsible for the consequences of use of this
16  *    software, no matter how awful, even if they arise from flaws in it.
17  * 
18  * 2. The origin of this software must not be misrepresented, either by
19  *    explicit claim or by omission.  Since few users ever read sources,
20  *    credits should appear in the documentation.
21  * 
22  * 3. Altered versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.  Since few users
24  *    ever read sources, credits should appear in the documentation.
25  * 
26  * 4. This notice may not be removed or altered.
27  *
28  *
29  *
30  * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
31  * 
32  * This software is being modified by Pierangelo Masarati.
33  * The previously reported conditions apply to the modified code as well.
34  * Changes in the original code are highlighted where required.
35  * Credits for the original code go to the author, Howard Chu.
36  */
37
38 #include "portable.h"
39
40 #include <stdio.h>
41
42 #include <ac/socket.h>
43 #include <ac/string.h>
44
45
46 #define AVL_INTERNAL
47 #include "slap.h"
48 #include "back-ldap.h"
49
50 int
51 ldap_back_bind(
52     Backend             *be,
53     Connection          *conn,
54     Operation           *op,
55     const char          *dn,
56     const char          *ndn,
57     int                 method,
58     struct berval       *cred,
59         char            **edn
60 )
61 {
62         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
63         struct ldapconn *lc;
64
65         char *mdn = NULL;
66         int rc = 0;
67
68         *edn = NULL;
69
70         lc = ldap_back_getconn(li, conn, op);
71         if ( !lc ) {
72                 return( -1 );
73         }
74
75         mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 );
76         if ( mdn == NULL ) {
77                 return -1;
78         }
79
80         if (ldap_bind_s(lc->ld, mdn, cred->bv_val, method) != LDAP_SUCCESS) {
81                 rc = ldap_back_op_result( lc, op );
82         } else {
83                 lc->bound = 1;
84         }
85         
86         free( mdn );
87         
88         return( rc );
89 }
90
91 /*
92  * conn_cmp
93  *
94  * compares two struct ldapconn based on the value of the conn pointer;
95  * used by avl stuff
96  */
97 int
98 conn_cmp(
99         const void *c1,
100         const void *c2
101         )
102 {
103         struct ldapconn *lc1 = (struct ldapconn *)c1;
104         struct ldapconn *lc2 = (struct ldapconn *)c2;
105         
106         return ( ( lc1->conn < lc2->conn ) ? -1 : ( ( lc1->conn > lc2-> conn ) ? 1 : 0 ) );
107 }
108
109 /*
110  * conn_dup
111  *
112  * returns -1 in case a duplicate struct ldapconn has been inserted;
113  * used by avl stuff
114  */
115 int
116 conn_dup(
117         void *c1,
118         void *c2
119         )
120 {
121         struct ldapconn *lc1 = (struct ldapconn *)c1;
122         struct ldapconn *lc2 = (struct ldapconn *)c2;
123
124         return( ( lc1->conn == lc2->conn ) ? -1 : 0 );
125 }
126
127 static void ravl_print( Avlnode *root, int depth )
128 {
129         int     i;
130         
131         if ( root == 0 )
132                 return;
133         
134         ravl_print( root->avl_right, depth+1 );
135         
136         for ( i = 0; i < depth; i++ )
137                 printf( "   " );
138
139         printf( "c(%d) %d\n", ((struct ldapconn *) root->avl_data)->conn->c_connid, root->avl_bf );
140         
141         ravl_print( root->avl_left, depth+1 );
142 }
143
144 static void myprint( Avlnode *root )
145 {
146         printf( "********\n" );
147         
148         if ( root == 0 )
149                 printf( "\tNULL\n" );
150
151         else
152                 ravl_print( root, 0 );
153         
154         printf( "********\n" );
155 }
156
157 struct ldapconn *
158 ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
159 {
160         struct ldapconn *lc, lc_curr;
161         LDAP *ld;
162
163         /* Searches for a ldapconn in the avl tree */
164         lc_curr.conn = conn;
165         ldap_pvt_thread_mutex_lock( &li->conn_mutex );
166         lc = (struct ldapconn *)avl_find( li->conntree, 
167                 (caddr_t)&lc_curr, conn_cmp );
168         ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
169
170         /* Looks like we didn't get a bind. Open a new session... */
171         if (!lc) {
172                 int vers = conn->c_protocol;
173                 int err = ldap_initialize(&ld, li->url);
174                 
175                 if (err != LDAP_SUCCESS) {
176                         err = ldap_back_map_result(err);
177                         send_ldap_result( conn, op, err,
178                                 NULL, "ldap_init failed", NULL, NULL );
179                         return( NULL );
180                 }
181                 /* Set LDAP version. This will always succeed: If the client
182                  * bound with a particular version, then so can we.
183                  */
184                 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &vers);
185
186                 lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn));
187                 lc->conn = conn;
188                 lc->ld = ld;
189                 if ( lc->conn->c_cdn != NULL && lc->conn->c_cdn[0] != '\0' ) {
190                         lc->bound_dn = ldap_back_dn_massage( li,
191                                 ch_strdup( lc->conn->c_cdn ), 0 );
192                 } else {
193                         lc->bound_dn = NULL;
194                 }
195                 lc->bound = 0;
196
197                 /* Inserts the newly created ldapconn in the avl tree */
198                 ldap_pvt_thread_mutex_lock( &li->conn_mutex );
199                 err = avl_insert( &li->conntree, (caddr_t)lc,
200                         conn_cmp, conn_dup );
201
202 #if 1
203                 myprint( li->conntree );
204 #endif
205                 
206                 ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
207
208                 Debug( LDAP_DEBUG_TRACE,
209                         "=>ldap_back_getconn: conn %d inserted\n",
210                         lc->conn->c_connid, 0, 0 );
211                 
212                 /* Err could be -1 in case a duplicate ldapconn is inserted */
213                 if ( err != 0 ) {
214                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
215                         NULL, "internal server error", NULL, NULL );
216                         /* better destroy the ldapconn struct? */
217                         return( NULL );
218                 }
219         } else {
220                 Debug( LDAP_DEBUG_TRACE,
221                         "=>ldap_back_getconn: conn %d fetched\n",
222                         lc->conn->c_connid, 0, 0 );
223         }
224         
225         return( lc );
226 }
227
228 /*
229  * ldap_back_dobind
230  *
231  * Note: as the check for the value of lc->bound was already here, I removed
232  * it from all the callers, and I made the function return the flag, so
233  * it can be used to simplify the check.
234  */
235 int
236 ldap_back_dobind(struct ldapconn *lc, Operation *op)
237 {
238         if (lc->bound) {
239                 return( lc->bound );
240         }
241
242         if (ldap_bind_s(lc->ld, lc->bound_dn, NULL, LDAP_AUTH_SIMPLE) !=
243                 LDAP_SUCCESS) {
244                 ldap_back_op_result(lc, op);
245                 return( 0 );
246         } /* else */
247         return( lc->bound = 1 );
248 }
249
250 /* Map API errors to protocol errors... */
251
252 int
253 ldap_back_map_result(int err)
254 {
255         switch(err)
256         {
257         case LDAP_SERVER_DOWN:
258                 return LDAP_UNAVAILABLE;
259         case LDAP_LOCAL_ERROR:
260                 return LDAP_OPERATIONS_ERROR;
261         case LDAP_ENCODING_ERROR:
262         case LDAP_DECODING_ERROR:
263                 return LDAP_PROTOCOL_ERROR;
264         case LDAP_TIMEOUT:
265                 return LDAP_UNAVAILABLE;
266         case LDAP_AUTH_UNKNOWN:
267                 return LDAP_AUTH_METHOD_NOT_SUPPORTED;
268         case LDAP_FILTER_ERROR:
269                 return LDAP_OPERATIONS_ERROR;
270         case LDAP_USER_CANCELLED:
271                 return LDAP_OPERATIONS_ERROR;
272         case LDAP_PARAM_ERROR:
273                 return LDAP_PROTOCOL_ERROR;
274         case LDAP_NO_MEMORY:
275                 return LDAP_OPERATIONS_ERROR;
276         case LDAP_CONNECT_ERROR:
277                 return LDAP_UNAVAILABLE;
278         case LDAP_NOT_SUPPORTED:
279                 return LDAP_UNWILLING_TO_PERFORM;
280         case LDAP_CONTROL_NOT_FOUND:
281                 return LDAP_PROTOCOL_ERROR;
282         case LDAP_NO_RESULTS_RETURNED:
283                 return LDAP_NO_SUCH_OBJECT;
284         case LDAP_MORE_RESULTS_TO_RETURN:
285                 return LDAP_OTHER;
286         case LDAP_CLIENT_LOOP:
287         case LDAP_REFERRAL_LIMIT_EXCEEDED:
288                 return LDAP_LOOP_DETECT;
289         default:
290                 if LDAP_API_ERROR(err)
291                         return LDAP_OTHER;
292                 else
293                         return err;
294         }
295 }
296
297 int
298 ldap_back_op_result(struct ldapconn *lc, Operation *op)
299 {
300         int err = LDAP_SUCCESS;
301         char *msg = NULL;
302         char *match = NULL;
303
304         ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &err);
305         ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &msg);
306         ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match);
307         err = ldap_back_map_result(err);
308         send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL );
309         /* better test the pointers before freeing? */
310         if ( match ) free( match );
311         if ( msg ) free( msg );
312         return( (err==LDAP_SUCCESS) ? 0 : -1 );
313 }