1 /* $OpenLDAP: pkg/ldap/servers/slapd/extended.c,v 1.92.2.5 2008/02/11 23:26:44 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
17 * LDAPv3 Extended Operation Request
18 * ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
19 * requestName [0] LDAPOID,
20 * requestValue [1] OCTET STRING OPTIONAL
23 * LDAPv3 Extended Operation Response
24 * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
25 * COMPONENTS OF LDAPResult,
26 * responseName [10] LDAPOID OPTIONAL,
27 * response [11] OCTET STRING OPTIONAL
36 #include <ac/socket.h>
37 #include <ac/string.h>
42 static struct extop_list
{
43 struct extop_list
*next
;
46 SLAP_EXTOP_MAIN_FN
*ext_main
;
47 } *supp_ext_list
= NULL
;
49 static SLAP_EXTOP_MAIN_FN whoami_extop
;
51 /* This list of built-in extops is for extops that are not part
52 * of backends or in external modules. Essentially, this is
53 * just a way to get built-in extops onto the extop list without
54 * having a separate init routine for each built-in extop.
57 const struct berval
*oid
;
59 SLAP_EXTOP_MAIN_FN
*ext_main
;
60 } builtin_extops
[] = {
62 { &slap_EXOP_TXN_START
, 0, txn_start_extop
},
63 { &slap_EXOP_TXN_END
, 0, txn_end_extop
},
65 { &slap_EXOP_CANCEL
, 0, cancel_extop
},
66 { &slap_EXOP_WHOAMI
, 0, whoami_extop
},
67 { &slap_EXOP_MODIFY_PASSWD
, SLAP_EXOP_WRITES
, passwd_extop
},
72 static struct extop_list
*find_extop(
73 struct extop_list
*list
, struct berval
*oid
);
76 get_supported_extop (int index
)
78 struct extop_list
*ext
;
80 /* linear scan is slow, but this way doesn't force a
81 * big change on root_dse.c, where this routine is used.
83 for (ext
= supp_ext_list
; ext
!= NULL
&& --index
>= 0; ext
= ext
->next
) {
87 if (ext
== NULL
) return NULL
;
93 int exop_root_dse_info( Entry
*e
)
95 AttributeDescription
*ad_supportedExtension
96 = slap_schema
.si_ad_supportedExtension
;
97 struct berval vals
[2];
98 struct extop_list
*ext
;
100 vals
[1].bv_val
= NULL
;
103 for (ext
= supp_ext_list
; ext
!= NULL
; ext
= ext
->next
) {
104 if( ext
->flags
& SLAP_EXOP_HIDE
) continue;
108 if( attr_merge( e
, ad_supportedExtension
, vals
, NULL
) ) {
122 struct berval reqdata
= {0, NULL
};
126 Debug( LDAP_DEBUG_TRACE
, "%s do_extended\n",
127 op
->o_log_prefix
, 0, 0 );
129 if( op
->o_protocol
< LDAP_VERSION3
) {
130 Debug( LDAP_DEBUG_ANY
, "%s do_extended: protocol version (%d) too low\n",
131 op
->o_log_prefix
, op
->o_protocol
, 0 );
132 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "requires LDAPv3" );
133 rs
->sr_err
= SLAPD_DISCONNECT
;
137 if ( ber_scanf( op
->o_ber
, "{m" /*}*/, &op
->ore_reqoid
) == LBER_ERROR
) {
138 Debug( LDAP_DEBUG_ANY
, "%s do_extended: ber_scanf failed\n",
139 op
->o_log_prefix
, 0, 0 );
140 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
141 rs
->sr_err
= SLAPD_DISCONNECT
;
145 tag
= ber_peek_tag( op
->o_ber
, &len
);
147 if( ber_peek_tag( op
->o_ber
, &len
) == LDAP_TAG_EXOP_REQ_VALUE
) {
148 if( ber_scanf( op
->o_ber
, "m", &reqdata
) == LBER_ERROR
) {
149 Debug( LDAP_DEBUG_ANY
, "%s do_extended: ber_scanf failed\n",
150 op
->o_log_prefix
, 0, 0 );
151 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
152 rs
->sr_err
= SLAPD_DISCONNECT
;
157 if( get_ctrls( op
, rs
, 1 ) != LDAP_SUCCESS
) {
158 Debug( LDAP_DEBUG_ANY
, "%s do_extended: get_ctrls failed\n",
159 op
->o_log_prefix
, 0, 0 );
163 Statslog( LDAP_DEBUG_STATS
, "%s EXT oid=%s\n",
164 op
->o_log_prefix
, op
->ore_reqoid
.bv_val
, 0, 0, 0 );
166 /* check for controls inappropriate for all extended operations */
167 if( get_manageDSAit( op
) == SLAP_CONTROL_CRITICAL
) {
168 send_ldap_error( op
, rs
,
169 LDAP_UNAVAILABLE_CRITICAL_EXTENSION
,
170 "manageDSAit control inappropriate" );
174 /* FIXME: temporary? */
175 if ( reqdata
.bv_val
) {
176 op
->ore_reqdata
= &reqdata
;
179 op
->o_bd
= frontendDB
;
180 rs
->sr_err
= frontendDB
->be_extended( op
, rs
);
182 /* clean up in case some overlay set them? */
183 if ( !BER_BVISNULL( &op
->o_req_ndn
) ) {
184 if ( !BER_BVISNULL( &op
->o_req_dn
)
185 && op
->o_req_ndn
.bv_val
!= op
->o_req_dn
.bv_val
)
187 op
->o_tmpfree( op
->o_req_dn
.bv_val
, op
->o_tmpmemctx
);
189 op
->o_tmpfree( op
->o_req_ndn
.bv_val
, op
->o_tmpmemctx
);
190 BER_BVZERO( &op
->o_req_dn
);
191 BER_BVZERO( &op
->o_req_ndn
);
199 fe_extended( Operation
*op
, SlapReply
*rs
)
201 struct extop_list
*ext
= NULL
;
202 struct berval reqdata
= BER_BVNULL
;
204 if (op
->ore_reqdata
) {
205 reqdata
= *op
->ore_reqdata
;
208 ext
= find_extop(supp_ext_list
, &op
->ore_reqoid
);
210 Debug( LDAP_DEBUG_ANY
, "%s do_extended: unsupported operation \"%s\"\n",
211 op
->o_log_prefix
, op
->ore_reqoid
.bv_val
, 0 );
212 send_ldap_error( op
, rs
, LDAP_PROTOCOL_ERROR
,
213 "unsupported extended operation" );
217 op
->ore_flags
= ext
->flags
;
219 Debug( LDAP_DEBUG_ARGS
, "do_extended: oid=%s\n",
220 op
->ore_reqoid
.bv_val
, 0 ,0 );
222 { /* start of OpenLDAP extended operation */
223 BackendDB
*bd
= op
->o_bd
;
225 rs
->sr_err
= (ext
->ext_main
)( op
, rs
);
227 if( rs
->sr_err
!= SLAPD_ABANDON
) {
228 if ( rs
->sr_err
== LDAP_REFERRAL
&& rs
->sr_ref
== NULL
) {
229 rs
->sr_ref
= referral_rewrite( default_referral
,
230 NULL
, NULL
, LDAP_SCOPE_DEFAULT
);
231 if ( !rs
->sr_ref
) rs
->sr_ref
= default_referral
;
233 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
234 rs
->sr_text
= "referral missing";
238 if ( op
->o_bd
== NULL
)
240 send_ldap_extended( op
, rs
);
242 if ( rs
->sr_ref
!= default_referral
) {
243 ber_bvarray_free( rs
->sr_ref
);
248 if ( rs
->sr_rspoid
!= NULL
) {
249 free( (char *)rs
->sr_rspoid
);
252 if ( rs
->sr_rspdata
!= NULL
) {
253 ber_bvfree( rs
->sr_rspdata
);
255 } /* end of OpenLDAP extended operation */
263 const struct berval
*ext_oid
,
264 slap_mask_t ext_flags
,
265 SLAP_EXTOP_MAIN_FN
*ext_main
,
268 struct berval oidm
= BER_BVNULL
;
269 struct extop_list
*ext
;
276 if ( ext_oid
== NULL
|| BER_BVISNULL( ext_oid
) ||
277 BER_BVISEMPTY( ext_oid
) )
282 if ( numericoidValidate( NULL
, (struct berval
*)ext_oid
) !=
285 oidm
.bv_val
= oidm_find( ext_oid
->bv_val
);
286 if ( oidm
.bv_val
== NULL
) {
289 oidm
.bv_len
= strlen( oidm
.bv_val
);
293 for ( ext
= supp_ext_list
; ext
; ext
= ext
->next
) {
294 if ( bvmatch( ext_oid
, &ext
->oid
) ) {
302 if ( flags
== 0 || ext
== NULL
) {
303 ext
= ch_calloc( 1, sizeof(struct extop_list
) + ext_oid
->bv_len
+ 1 );
308 ext
->oid
.bv_val
= (char *)(ext
+ 1);
309 AC_MEMCPY( ext
->oid
.bv_val
, ext_oid
->bv_val
, ext_oid
->bv_len
);
310 ext
->oid
.bv_len
= ext_oid
->bv_len
;
311 ext
->oid
.bv_val
[ext
->oid
.bv_len
] = '\0';
316 ext
->flags
= ext_flags
;
317 ext
->ext_main
= ext_main
;
320 ext
->next
= supp_ext_list
;
332 for ( i
= 0; builtin_extops
[i
].oid
!= NULL
; i
++ ) {
333 load_extop( (struct berval
*)builtin_extops
[i
].oid
,
334 builtin_extops
[i
].flags
,
335 builtin_extops
[i
].ext_main
);
343 struct extop_list
*ext
;
345 /* we allocated the memory, so we have to free it, too. */
346 while ((ext
= supp_ext_list
) != NULL
) {
347 supp_ext_list
= ext
->next
;
353 static struct extop_list
*
354 find_extop( struct extop_list
*list
, struct berval
*oid
)
356 struct extop_list
*ext
;
358 for (ext
= list
; ext
; ext
= ext
->next
) {
359 if (bvmatch(&ext
->oid
, oid
))
366 const struct berval slap_EXOP_WHOAMI
= BER_BVC(LDAP_EXOP_WHO_AM_I
);
375 if ( op
->ore_reqdata
!= NULL
) {
376 /* no request data should be provided */
377 rs
->sr_text
= "no request data expected";
378 return LDAP_PROTOCOL_ERROR
;
381 Statslog( LDAP_DEBUG_STATS
, "%s WHOAMI\n",
382 op
->o_log_prefix
, 0, 0, 0, 0 );
384 op
->o_bd
= op
->o_conn
->c_authz_backend
;
385 if( backend_check_restrictions( op
, rs
,
386 (struct berval
*)&slap_EXOP_WHOAMI
) != LDAP_SUCCESS
)
391 bv
= (struct berval
*) ch_malloc( sizeof(struct berval
) );
392 if( op
->o_dn
.bv_len
) {
393 bv
->bv_len
= op
->o_dn
.bv_len
+ STRLENOF( "dn:" );
394 bv
->bv_val
= ch_malloc( bv
->bv_len
+ 1 );
395 AC_MEMCPY( bv
->bv_val
, "dn:", STRLENOF( "dn:" ) );
396 AC_MEMCPY( &bv
->bv_val
[STRLENOF( "dn:" )], op
->o_dn
.bv_val
,
398 bv
->bv_val
[bv
->bv_len
] = '\0';