]> git.sur5r.net Git - openldap/blob - servers/slapd/extended.c
Fix matched values bug
[openldap] / servers / slapd / extended.c
1 /* $OpenLDAP$ */
2 /* 
3  * Copyright 1999-2002 The OpenLDAP Foundation.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted only
7  * as authorized by the OpenLDAP Public License.  A copy of this
8  * license is available at http://www.OpenLDAP.org/license.html or
9  * in file LICENSE in the top-level directory of the distribution.
10  */
11
12 /*
13  * LDAPv3 Extended Operation Request
14  *      ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
15  *              requestName      [0] LDAPOID,
16  *              requestValue     [1] OCTET STRING OPTIONAL
17  *      }
18  *
19  * LDAPv3 Extended Operation Response
20  *      ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
21  *              COMPONENTS OF LDAPResult,
22  *              responseName     [10] LDAPOID OPTIONAL,
23  *              response         [11] OCTET STRING OPTIONAL
24  *      }
25  *
26  */
27
28 #include "portable.h"
29
30 #include <stdio.h>
31 #include <ac/socket.h>
32 #include <ac/string.h>
33
34 #include "slap.h"
35 #include "lber_pvt.h"
36
37 static struct extop_list {
38         struct extop_list *next;
39         struct berval oid;
40         SLAP_EXTOP_MAIN_FN *ext_main;
41 } *supp_ext_list = NULL;
42
43 static SLAP_EXTOP_MAIN_FN whoami_extop;
44
45 /* BerVal Constant initializer */
46
47 #define BVC(x)  {sizeof(x)-1, x}
48
49 /* this list of built-in extops is for extops that are not part
50  * of backends or in external modules.  essentially, this is
51  * just a way to get built-in extops onto the extop list without
52  * having a separate init routine for each built-in extop.
53  */
54 static struct {
55         struct berval oid;
56         SLAP_EXTOP_MAIN_FN *ext_main;
57 } builtin_extops[] = {
58 #ifdef HAVE_TLS
59         { BVC(LDAP_EXOP_START_TLS), starttls_extop },
60 #endif
61         { BVC(LDAP_EXOP_MODIFY_PASSWD), passwd_extop },
62         { BVC(LDAP_EXOP_X_WHO_AM_I), whoami_extop },
63         { {0,NULL}, NULL }
64 };
65
66
67 static struct extop_list *find_extop(
68         struct extop_list *list, struct berval *oid );
69
70 struct berval *
71 get_supported_extop (int index)
72 {
73         struct extop_list *ext;
74
75         /* linear scan is slow, but this way doesn't force a
76          * big change on root_dse.c, where this routine is used.
77          */
78         for (ext = supp_ext_list; ext != NULL && --index >= 0; ext = ext->next) {
79                 ; /* empty */
80         }
81
82         if (ext == NULL) return NULL;
83
84         return &ext->oid ;
85 }
86
87 int
88 do_extended(
89     Connection  *conn,
90     Operation   *op
91 )
92 {
93         int rc = LDAP_SUCCESS;
94         struct berval reqoid = {0, NULL};
95         struct berval reqdata = {0, NULL};
96         ber_tag_t tag;
97         ber_len_t len;
98         struct extop_list *ext;
99         const char *text;
100         BerVarray refs;
101         char *rspoid;
102         struct berval *rspdata;
103         LDAPControl **rspctrls;
104
105 #ifdef NEW_LOGGING
106         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
107                 "do_extended: conn %d\n", conn->c_connid ));
108 #else
109         Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
110 #endif
111
112         if( op->o_protocol < LDAP_VERSION3 ) {
113 #ifdef NEW_LOGGING
114                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
115                         "do_extended: protocol version (%d) too low.\n",
116                         op->o_protocol ));
117 #else
118                 Debug( LDAP_DEBUG_ANY,
119                         "do_extended: protocol version (%d) too low\n",
120                         op->o_protocol, 0 ,0 );
121 #endif
122                 send_ldap_disconnect( conn, op,
123                         LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
124                 rc = -1;
125                 goto done;
126         }
127
128         if ( ber_scanf( op->o_ber, "{m" /*}*/, &reqoid ) == LBER_ERROR ) {
129 #ifdef NEW_LOGGING
130                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
131                         "do_extended: conn %d  ber_scanf failed\n", conn->c_connid ));
132 #else
133                 Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
134 #endif
135                 send_ldap_disconnect( conn, op,
136                         LDAP_PROTOCOL_ERROR, "decoding error" );
137                 rc = -1;
138                 goto done;
139         }
140
141         if( !(ext = find_extop(supp_ext_list, &reqoid)) ) {
142 #ifdef NEW_LOGGING
143                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
144                         "do_extended: conn %d  unsupported operation \"%s\"\n",
145                         conn->c_connid, reqoid.bv_val ));
146 #else
147                 Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
148                         reqoid.bv_val, 0 ,0 );
149 #endif
150                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
151                         NULL, "unsupported extended operation", NULL, NULL );
152                 goto done;
153         }
154
155         tag = ber_peek_tag( op->o_ber, &len );
156         
157         if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
158                 if( ber_scanf( op->o_ber, "m", &reqdata ) == LBER_ERROR ) {
159 #ifdef NEW_LOGGING
160                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
161                                 "do_extended: conn %d  ber_scanf failed\n", conn->c_connid ));
162 #else
163                         Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
164 #endif
165                         send_ldap_disconnect( conn, op,
166                                 LDAP_PROTOCOL_ERROR, "decoding error" );
167                         rc = -1;
168                         goto done;
169                 }
170         }
171
172         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
173 #ifdef NEW_LOGGING
174                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
175                         "do_extended: conn %d  get_ctrls failed\n", conn->c_connid ));
176 #else
177                 Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
178 #endif
179                 return rc;
180         } 
181
182         /* check for controls inappropriate for all extended operations */
183         if( get_manageDSAit( op ) == SLAP_CRITICAL_CONTROL ) {
184                 send_ldap_result( conn, op,
185                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
186                         NULL, "manageDSAit control inappropriate",
187                         NULL, NULL );
188                 goto done;
189         }
190
191 #ifdef NEW_LOGGING
192         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
193                 "do_extended: conn %d  oid=%d\n.", conn->c_connid, reqoid.bv_val ));
194 #else
195         Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", reqoid.bv_val, 0 ,0 );
196 #endif
197
198         rspoid = NULL;
199         rspdata = NULL;
200         rspctrls = NULL;
201         text = NULL;
202         refs = NULL;
203
204         rc = (ext->ext_main)( conn, op,
205                 reqoid.bv_val, reqdata.bv_val ? &reqdata : NULL,
206                 &rspoid, &rspdata, &rspctrls, &text, &refs );
207
208         if( rc != SLAPD_ABANDON ) {
209                 if ( rc == LDAP_REFERRAL && refs == NULL ) {
210                         refs = referral_rewrite( default_referral,
211                                 NULL, NULL, LDAP_SCOPE_DEFAULT );
212                 }
213
214                 send_ldap_extended( conn, op, rc, NULL, text, refs,
215                         rspoid, rspdata, rspctrls );
216
217                 ber_bvarray_free( refs );
218         }
219
220         if ( rspoid != NULL ) {
221                 free( rspoid );
222         }
223
224         if ( rspdata != NULL ) {
225                 ber_bvfree( rspdata );
226         }
227
228 done:
229         return rc;
230 }
231
232 int
233 load_extop(
234         const char *ext_oid,
235         SLAP_EXTOP_MAIN_FN *ext_main )
236 {
237         struct extop_list *ext;
238
239         if( ext_oid == NULL || *ext_oid == '\0' ) return -1; 
240         if(!ext_main) return -1; 
241
242         ext = ch_calloc(1, sizeof(struct extop_list));
243         if (ext == NULL)
244                 return(-1);
245
246         ber_str2bv( ext_oid, 0, 1, &ext->oid );
247         if (ext->oid.bv_val == NULL) {
248                 free(ext);
249                 return(-1);
250         }
251
252         ext->ext_main = ext_main;
253         ext->next = supp_ext_list;
254
255         supp_ext_list = ext;
256
257         return(0);
258 }
259
260 int
261 extops_init (void)
262 {
263         int i;
264
265         for (i = 0; builtin_extops[i].oid.bv_val != NULL; i++) {
266                 load_extop(builtin_extops[i].oid.bv_val, builtin_extops[i].ext_main);
267         }
268         return(0);
269 }
270
271 int
272 extops_kill (void)
273 {
274         struct extop_list *ext;
275
276         /* we allocated the memory, so we have to free it, too. */
277         while ((ext = supp_ext_list) != NULL) {
278                 supp_ext_list = ext->next;
279                 if (ext->oid.bv_val != NULL)
280                         ch_free(ext->oid.bv_val);
281                 ch_free(ext);
282         }
283         return(0);
284 }
285
286 static struct extop_list *
287 find_extop( struct extop_list *list, struct berval *oid )
288 {
289         struct extop_list *ext;
290
291         for (ext = list; ext; ext = ext->next) {
292                 if (ber_bvcmp(&ext->oid, oid) == 0)
293                         return(ext);
294         }
295         return(NULL);
296 }
297
298
299 static int
300 whoami_extop (
301         Connection *conn,
302         Operation *op,
303         const char * reqoid,
304         struct berval * reqdata,
305         char ** rspoid,
306         struct berval ** rspdata,
307         LDAPControl ***rspctrls,
308         const char ** text,
309         BerVarray * refs )
310 {
311         int rc;
312         struct berval *bv;
313
314         if ( reqdata != NULL ) {
315                 /* no request data should be provided */
316                 *text = "no request data expected";
317                 return LDAP_PROTOCOL_ERROR;
318         }
319
320         {
321                 int rc;
322                 struct berval whoami = BER_BVC( LDAP_EXOP_X_WHO_AM_I );
323
324                 rc = backend_check_restrictions( conn->c_authz_backend,
325                         conn, op, &whoami, text );
326
327                 if( rc != LDAP_SUCCESS ) return rc;
328         }
329
330         bv = (struct berval *) ch_malloc( sizeof(struct berval) );
331         if( op->o_dn.bv_len ) {
332                 bv->bv_len = op->o_dn.bv_len + sizeof("dn:")-1;
333                 bv->bv_val = ch_malloc( bv->bv_len + 1 );
334                 AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:")-1 );
335                 AC_MEMCPY( &bv->bv_val[sizeof("dn:")-1], op->o_dn.bv_val,
336                         op->o_dn.bv_len );
337                 bv->bv_val[bv->bv_len] = '\0';
338
339         } else {
340                 bv->bv_len = 0;
341                 bv->bv_val = NULL;
342         }
343
344         *rspdata = bv;
345         return LDAP_SUCCESS;
346 }