]> git.sur5r.net Git - openldap/blob - servers/slapd/extended.c
Changed reqoid to struct berval
[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         if( op->o_protocol < LDAP_VERSION3 ) {
111 #ifdef NEW_LOGGING
112                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
113                         "do_extended: protocol version (%d) too low.\n",
114                         op->o_protocol ));
115 #else
116                 Debug( LDAP_DEBUG_ANY,
117                         "do_extended: protocol version (%d) too low\n",
118                         op->o_protocol, 0 ,0 );
119 #endif
120                 send_ldap_disconnect( conn, op,
121                         LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
122                 rc = -1;
123                 goto done;
124         }
125
126         if ( ber_scanf( op->o_ber, "{m" /*}*/, &reqoid ) == LBER_ERROR ) {
127 #ifdef NEW_LOGGING
128                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
129                         "do_extended: conn %d  ber_scanf failed\n", conn->c_connid ));
130 #else
131                 Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
132 #endif
133                 send_ldap_disconnect( conn, op,
134                         LDAP_PROTOCOL_ERROR, "decoding error" );
135                 rc = -1;
136                 goto done;
137         }
138
139         if( !(ext = find_extop(supp_ext_list, &reqoid)) ) {
140 #ifdef NEW_LOGGING
141                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
142                         "do_extended: conn %d  unsupported operation \"%s\"\n",
143                         conn->c_connid, reqoid.bv_val ));
144 #else
145                 Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
146                         reqoid.bv_val, 0 ,0 );
147 #endif
148                 send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
149                         NULL, "unsupported extended operation", NULL, NULL );
150                 goto done;
151         }
152
153         tag = ber_peek_tag( op->o_ber, &len );
154         
155         if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
156                 if( ber_scanf( op->o_ber, "m", &reqdata ) == LBER_ERROR ) {
157 #ifdef NEW_LOGGING
158                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
159                                 "do_extended: conn %d  ber_scanf failed\n", conn->c_connid ));
160 #else
161                         Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
162 #endif
163                         send_ldap_disconnect( conn, op,
164                                 LDAP_PROTOCOL_ERROR, "decoding error" );
165                         rc = -1;
166                         goto done;
167                 }
168         }
169
170         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
171 #ifdef NEW_LOGGING
172                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
173                         "do_extended: conn %d  get_ctrls failed\n", conn->c_connid ));
174 #else
175                 Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
176 #endif
177                 return rc;
178         } 
179
180         /* check for controls inappropriate for all extended operations */
181         if( get_manageDSAit( op ) == SLAP_CRITICAL_CONTROL ) {
182                 send_ldap_result( conn, op,
183                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
184                         NULL, "manageDSAit control inappropriate",
185                         NULL, NULL );
186                 goto done;
187         }
188
189 #ifdef NEW_LOGGING
190         LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1,
191                 "do_extended: conn %d  oid=%d\n.", conn->c_connid, reqoid.bv_val ));
192 #else
193         Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", reqoid.bv_val, 0 ,0 );
194 #endif
195
196         rspoid = NULL;
197         rspdata = NULL;
198         rspctrls = NULL;
199         text = NULL;
200         refs = NULL;
201
202         rc = (ext->ext_main)( conn, op,
203                 reqoid.bv_val, &reqdata,
204                 &rspoid, &rspdata, &rspctrls, &text, &refs );
205
206         if( rc != SLAPD_ABANDON ) {
207                 if ( rc == LDAP_REFERRAL && refs == NULL ) {
208                         refs = referral_rewrite( default_referral,
209                                 NULL, NULL, LDAP_SCOPE_DEFAULT );
210                 }
211
212                 send_ldap_extended( conn, op, rc, NULL, text, refs,
213                         rspoid, rspdata, rspctrls );
214
215                 ber_bvarray_free( refs );
216         }
217
218         if ( rspoid != NULL ) {
219                 free( rspoid );
220         }
221
222         if ( rspdata != NULL ) {
223                 ber_bvfree( rspdata );
224         }
225
226 done:
227         return rc;
228 }
229
230 int
231 load_extop(
232         const char *ext_oid,
233         SLAP_EXTOP_MAIN_FN *ext_main )
234 {
235         struct extop_list *ext;
236
237         if( ext_oid == NULL || *ext_oid == '\0' ) return -1; 
238         if(!ext_main) return -1; 
239
240         ext = ch_calloc(1, sizeof(struct extop_list));
241         if (ext == NULL)
242                 return(-1);
243
244         ber_str2bv( ext_oid, 0, 1, &ext->oid );
245         if (ext->oid.bv_val == NULL) {
246                 free(ext);
247                 return(-1);
248         }
249
250         ext->ext_main = ext_main;
251         ext->next = supp_ext_list;
252
253         supp_ext_list = ext;
254
255         return(0);
256 }
257
258 int
259 extops_init (void)
260 {
261         int i;
262
263         for (i = 0; builtin_extops[i].oid.bv_val != NULL; i++) {
264                 load_extop(builtin_extops[i].oid.bv_val, builtin_extops[i].ext_main);
265         }
266         return(0);
267 }
268
269 int
270 extops_kill (void)
271 {
272         struct extop_list *ext;
273
274         /* we allocated the memory, so we have to free it, too. */
275         while ((ext = supp_ext_list) != NULL) {
276                 supp_ext_list = ext->next;
277                 if (ext->oid.bv_val != NULL)
278                         ch_free(ext->oid.bv_val);
279                 ch_free(ext);
280         }
281         return(0);
282 }
283
284 static struct extop_list *
285 find_extop( struct extop_list *list, struct berval *oid )
286 {
287         struct extop_list *ext;
288
289         for (ext = list; ext; ext = ext->next) {
290                 if (ber_bvcmp(&ext->oid, oid) == 0)
291                         return(ext);
292         }
293         return(NULL);
294 }
295
296
297 int
298 whoami_extop (
299         Connection *conn,
300         Operation *op,
301         const char * reqoid,
302         struct berval * reqdata,
303         char ** rspoid,
304         struct berval ** rspdata,
305         LDAPControl ***rspctrls,
306         const char ** text,
307         BerVarray * refs )
308 {
309         struct berval *bv;
310
311         if ( reqdata != NULL ) {
312                 /* no request data should be provided */
313                 *text = "no request data expected";
314                 return LDAP_PROTOCOL_ERROR;
315         }
316
317         bv = (struct berval *) ch_malloc( sizeof(struct berval) );
318         if( op->o_dn.bv_len ) {
319                 bv->bv_len = op->o_dn.bv_len + sizeof("dn:")-1;
320                 bv->bv_val = ch_malloc( bv->bv_len + 1 );
321                 AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:")-1 );
322                 AC_MEMCPY( &bv->bv_val[sizeof("dn:")-1], op->o_dn.bv_val,
323                         op->o_dn.bv_len );
324                 bv->bv_val[bv->bv_len] = '\0';
325
326         } else {
327                 bv->bv_len = 0;
328                 bv->bv_val = NULL;
329         }
330
331         *rspdata = bv;
332         return LDAP_SUCCESS;
333 }