1 /* collect.c - Demonstration of overlay code */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/collect.c,v 1.5.2.4 2008/02/11 23:26:48 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2003 Howard Chu.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by the Howard Chu for inclusion
19 * in OpenLDAP Software.
24 #ifdef SLAPD_OVER_COLLECT
28 #include <ac/string.h>
29 #include <ac/socket.h>
34 /* This is a cheap hack to implement a collective attribute.
36 * This demonstration overlay looks for a specified attribute in an
37 * ancestor of a given entry and adds that attribute to the given
38 * entry when it is returned in a search response. It takes no effect
39 * for any other operations. If the ancestor does not exist, there
40 * is no effect. If no attribute was configured, there is no effect.
43 typedef struct collect_info
{
44 struct collect_info
*ci_next
;
46 AttributeDescription
*ci_ad
;
50 collect_cf( ConfigArgs
*c
)
52 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
56 case SLAP_CONFIG_EMIT
:
59 for ( ci
= on
->on_bi
.bi_private
; ci
; ci
= ci
->ci_next
) {
63 bv
.bv_len
= ci
->ci_dn
.bv_len
+ STRLENOF("\"\" ") +
64 ci
->ci_ad
->ad_cname
.bv_len
;
65 bv
.bv_val
= ch_malloc( bv
.bv_len
+ 1 );
66 len
= snprintf( bv
.bv_val
, bv
.bv_len
+ 1, "\"%s\" %s",
67 ci
->ci_dn
.bv_val
, ci
->ci_ad
->ad_cname
.bv_val
);
68 assert( len
== bv
.bv_len
);
69 ber_bvarray_add( &c
->rvalue_vals
, &bv
);
75 if ( c
->valx
== -1 ) {
76 /* Delete entire attribute */
78 while (( ci
= on
->on_bi
.bi_private
)) {
79 on
->on_bi
.bi_private
= ci
->ci_next
;
80 ch_free( ci
->ci_dn
.bv_val
);
84 /* Delete just one value */
85 collect_info
**cip
, *ci
;
87 cip
= (collect_info
**)&on
->on_bi
.bi_private
;
88 for ( i
=0; i
<= c
->valx
; i
++, cip
= &ci
->ci_next
) ci
= *cip
;
90 ch_free( ci
->ci_dn
.bv_val
);
101 AttributeDescription
*ad
= NULL
;
103 ber_str2bv( c
->argv
[1], 0, 0, &bv
);
104 if ( dnNormalize( 0, NULL
, NULL
, &bv
, &dn
, NULL
) ) {
105 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
), "%s invalid DN: \"%s\"",
106 c
->argv
[0], c
->argv
[1] );
107 Debug( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
108 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
111 if ( slap_str2ad( c
->argv
[2], &ad
, &text
) ) {
112 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
), "%s attribute description unknown: \"%s\"",
113 c
->argv
[0], c
->argv
[2] );
114 Debug( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
115 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
119 /* The on->on_bi.bi_private pointer can be used for
120 * anything this instance of the overlay needs.
122 ci
= ch_malloc( sizeof( collect_info
));
125 ci
->ci_next
= on
->on_bi
.bi_private
;
126 on
->on_bi
.bi_private
= ci
;
133 static ConfigTable collectcfg
[] = {
134 { "collectinfo", "dn> <attribute", 3, 3, 0,
135 ARG_MAGIC
, collect_cf
,
136 "( OLcfgOvAt:19.1 NAME 'olcCollectInfo' "
137 "DESC 'DN of entry and attribute to distribute' "
138 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
139 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
142 static ConfigOCs collectocs
[] = {
143 { "( OLcfgOvOc:19.1 "
144 "NAME 'olcCollectConfig' "
145 "DESC 'Collective Attribute configuration' "
146 "SUP olcOverlayConfig "
147 "MAY olcCollectInfo )",
148 Cft_Overlay
, collectcfg
},
158 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
161 while (( ci
= on
->on_bi
.bi_private
)) {
162 on
->on_bi
.bi_private
= ci
->ci_next
;
163 ch_free( ci
->ci_dn
.bv_val
);
170 collect_response( Operation
*op
, SlapReply
*rs
)
172 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
173 collect_info
*ci
= on
->on_bi
.bi_private
;
175 /* If we've been configured and the current response is
178 if ( ci
&& rs
->sr_type
== REP_SEARCH
) {
181 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
183 for (; ci
; ci
=ci
->ci_next
) {
184 BerVarray vals
= NULL
;
186 /* Is our configured entry an ancestor of this one? */
187 if ( !dnIsSuffix( &rs
->sr_entry
->e_nname
, &ci
->ci_dn
))
190 /* Extract the values of the desired attribute from
193 rc
= backend_attribute( op
, NULL
, &ci
->ci_dn
, ci
->ci_ad
, &vals
, ACL_READ
);
195 /* If there are any values, merge them into the
199 /* The current entry may live in a cache, so
200 * don't modify it directly. Make a copy and
201 * work with that instead.
203 if ( !( rs
->sr_flags
& REP_ENTRY_MODIFIABLE
)) {
204 rs
->sr_entry
= entry_dup( rs
->sr_entry
);
205 rs
->sr_flags
|= REP_ENTRY_MODIFIABLE
|
206 REP_ENTRY_MUSTBEFREED
;
208 attr_merge( rs
->sr_entry
, ci
->ci_ad
, vals
, NULL
);
209 ber_bvarray_free_x( vals
, op
->o_tmpmemctx
);
213 /* Default is to just fall through to the normal processing */
214 return SLAP_CB_CONTINUE
;
217 static slap_overinst collect
;
219 int collect_initialize() {
222 collect
.on_bi
.bi_type
= "collect";
223 collect
.on_bi
.bi_db_destroy
= collect_destroy
;
224 collect
.on_response
= collect_response
;
226 collect
.on_bi
.bi_cf_ocs
= collectocs
;
227 code
= config_register_schema( collectcfg
, collectocs
);
228 if ( code
) return code
;
230 return overlay_register( &collect
);
233 #if SLAPD_OVER_COLLECT == SLAPD_MOD_DYNAMIC
234 int init_module(int argc
, char *argv
[]) {
235 return collect_initialize();
239 #endif /* SLAPD_OVER_COLLECT */