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