]> git.sur5r.net Git - openldap/blob - servers/slapd/extended.c
dfff66d4d79b9cdb63eb8ad717aab55dd62b209d
[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, ENTRY, "do_extended: conn %d\n", conn->c_connid, 0, 0 );
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, ERR, 
114                         "do_extended: protocol version (%d) too low.\n", op->o_protocol, 0, 0 );
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, ERR, "do_extended: conn %d  ber_scanf failed\n", 
129                         conn->c_connid, 0, 0 );
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, ERR, 
142                         "do_extended: conn %d  unsupported operation \"%s\"\n",
143                         conn->c_connid, reqoid.bv_val, 0 );
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         op->o_extendedop = reqoid.bv_val;
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, ERR, 
161                                 "do_extended: conn %d  ber_scanf failed\n", 
162                                 conn->c_connid, 0, 0 );
163 #else
164                         Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
165 #endif
166                         send_ldap_disconnect( conn, op,
167                                 LDAP_PROTOCOL_ERROR, "decoding error" );
168                         rc = -1;
169                         goto done;
170                 }
171         }
172
173         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
174 #ifdef NEW_LOGGING
175                 LDAP_LOG( OPERATION, ERR, 
176                         "do_extended: conn %d  get_ctrls failed\n", conn->c_connid, 0, 0 );
177 #else
178                 Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
179 #endif
180                 return rc;
181         } 
182
183         /* check for controls inappropriate for all extended operations */
184         if( get_manageDSAit( op ) == SLAP_CRITICAL_CONTROL ) {
185                 send_ldap_result( conn, op,
186                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
187                         NULL, "manageDSAit control inappropriate",
188                         NULL, NULL );
189                 goto done;
190         }
191
192 #ifdef NEW_LOGGING
193         LDAP_LOG( OPERATION, DETAIL1, 
194                 "do_extended: conn %d  oid=%d\n.", conn->c_connid, reqoid.bv_val, 0 );
195 #else
196         Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", reqoid.bv_val, 0 ,0 );
197 #endif
198
199         rspoid = NULL;
200         rspdata = NULL;
201         rspctrls = NULL;
202         text = NULL;
203         refs = NULL;
204
205         rc = (ext->ext_main)( conn, op,
206                 reqoid.bv_val, reqdata.bv_val ? &reqdata : NULL,
207                 &rspoid, &rspdata, &rspctrls, &text, &refs );
208
209         if( rc != SLAPD_ABANDON ) {
210                 if ( rc == LDAP_REFERRAL && refs == NULL ) {
211                         refs = referral_rewrite( default_referral,
212                                 NULL, NULL, LDAP_SCOPE_DEFAULT );
213                 }
214
215                 send_ldap_extended( conn, op, rc, NULL, text, refs,
216                         rspoid, rspdata, rspctrls );
217
218                 ber_bvarray_free( refs );
219         }
220
221         if ( rspoid != NULL ) {
222                 free( rspoid );
223         }
224
225         if ( rspdata != NULL ) {
226                 ber_bvfree( rspdata );
227         }
228
229 done:
230         return rc;
231 }
232
233 int
234 load_extop(
235         const char *ext_oid,
236         SLAP_EXTOP_MAIN_FN *ext_main )
237 {
238         struct extop_list *ext;
239
240         if( ext_oid == NULL || *ext_oid == '\0' ) return -1; 
241         if(!ext_main) return -1; 
242
243         ext = ch_calloc(1, sizeof(struct extop_list));
244         if (ext == NULL)
245                 return(-1);
246
247         ber_str2bv( ext_oid, 0, 1, &ext->oid );
248         if (ext->oid.bv_val == NULL) {
249                 free(ext);
250                 return(-1);
251         }
252
253         ext->ext_main = ext_main;
254         ext->next = supp_ext_list;
255
256         supp_ext_list = ext;
257
258         return(0);
259 }
260
261 int
262 extops_init (void)
263 {
264         int i;
265
266         for (i = 0; builtin_extops[i].oid.bv_val != NULL; i++) {
267                 load_extop(builtin_extops[i].oid.bv_val, builtin_extops[i].ext_main);
268         }
269         return(0);
270 }
271
272 int
273 extops_kill (void)
274 {
275         struct extop_list *ext;
276
277         /* we allocated the memory, so we have to free it, too. */
278         while ((ext = supp_ext_list) != NULL) {
279                 supp_ext_list = ext->next;
280                 if (ext->oid.bv_val != NULL)
281                         ch_free(ext->oid.bv_val);
282                 ch_free(ext);
283         }
284         return(0);
285 }
286
287 static struct extop_list *
288 find_extop( struct extop_list *list, struct berval *oid )
289 {
290         struct extop_list *ext;
291
292         for (ext = list; ext; ext = ext->next) {
293                 if (bvmatch(&ext->oid, oid))
294                         return(ext);
295         }
296         return(NULL);
297 }
298
299
300 static int
301 whoami_extop (
302         Connection *conn,
303         Operation *op,
304         const char * reqoid,
305         struct berval * reqdata,
306         char ** rspoid,
307         struct berval ** rspdata,
308         LDAPControl ***rspctrls,
309         const char ** text,
310         BerVarray * refs )
311 {
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 }