]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/collect.c
check for ee == NULL
[openldap] / servers / slapd / overlays / collect.c
1 /* collect.c - Demonstration of overlay code */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2007 The OpenLDAP Foundation.
6  * Portions Copyright 2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_COLLECT
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/socket.h>
30
31 #include "slap.h"
32 #include "config.h"
33
34 /* This is a cheap hack to implement a collective attribute.
35  *
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.
41  */
42
43 typedef struct collect_info {
44         struct collect_info *ci_next;
45         struct berval ci_dn;
46         AttributeDescription *ci_ad;
47 } collect_info;
48
49 static int
50 collect_cf( ConfigArgs *c )
51 {
52         slap_overinst *on = (slap_overinst *)c->bi;
53         int rc = 1;
54
55         switch( c->op ) {
56         case SLAP_CONFIG_EMIT:
57                 {
58                 collect_info *ci;
59                 for ( ci = on->on_bi.bi_private; ci; ci = ci->ci_next ) {
60                         struct berval bv;
61
62                         bv.bv_len = ci->ci_dn.bv_len + 3 +
63                                 ci->ci_ad->ad_cname.bv_len;
64                         bv.bv_val = ch_malloc( bv.bv_len + 1 );
65                         sprintf( bv.bv_val, "\"%s\" %s", ci->ci_dn.bv_val,
66                                 ci->ci_ad->ad_cname.bv_val );
67                         ber_bvarray_add( &c->rvalue_vals, &bv );
68                         rc = 0;
69                 }
70                 }
71                 break;
72         case LDAP_MOD_DELETE:
73                 if ( c->valx == -1 ) {
74                 /* Delete entire attribute */
75                         collect_info *ci;
76                         while (( ci = on->on_bi.bi_private )) {
77                                 on->on_bi.bi_private = ci->ci_next;
78                                 ch_free( ci->ci_dn.bv_val );
79                                 ch_free( ci );
80                         }
81                 } else {
82                 /* Delete just one value */
83                         collect_info **cip, *ci;
84                         int i;
85                         cip = (collect_info **)&on->on_bi.bi_private;
86                         for ( i=0; i <= c->valx; i++, cip = &ci->ci_next ) ci = *cip;
87                         *cip = ci->ci_next;
88                         ch_free( ci->ci_dn.bv_val );
89                         ch_free( ci );
90                 }
91                 rc = 0;
92                 break;
93         case SLAP_CONFIG_ADD:
94         case LDAP_MOD_ADD:
95                 {
96                 collect_info *ci;
97                 struct berval bv, dn;
98                 const char *text;
99                 AttributeDescription *ad = NULL;
100
101                 ber_str2bv( c->argv[1], 0, 0, &bv );
102                 if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) {
103                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: \"%s\"",
104                                 c->argv[0], c->argv[1] );
105                         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
106                                 "%s: %s\n", c->log, c->cr_msg, 0 );
107                         return ARG_BAD_CONF;
108                 }
109                 if ( slap_str2ad( c->argv[2], &ad, &text ) ) {
110                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"",
111                                 c->argv[0], c->argv[2] );
112                         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
113                                 "%s: %s\n", c->log, c->cr_msg, 0 );
114                         return ARG_BAD_CONF;
115                 }
116
117                 /* The on->on_bi.bi_private pointer can be used for
118                  * anything this instance of the overlay needs.
119                  */
120                 ci = ch_malloc( sizeof( collect_info ));
121                 ci->ci_ad = ad;
122                 ci->ci_dn = dn;
123                 ci->ci_next = on->on_bi.bi_private;
124                 on->on_bi.bi_private = ci;
125                 rc = 0;
126                 }
127         }
128         return rc;
129 }
130
131 static ConfigTable collectcfg[] = {
132         { "collectinfo", "dn> <attribute", 3, 3, 0,
133           ARG_MAGIC, collect_cf,
134           "( OLcfgOvAt:19.1 NAME 'olcCollectInfo' "
135           "DESC 'DN of entry and attribute to distribute' "
136           "SYNTAX OMsDirectoryString )", NULL, NULL },
137         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
138 };
139
140 static ConfigOCs collectocs[] = {
141         { "( OLcfgOvOc:19.1 "
142           "NAME 'olcCollectConfig' "
143           "DESC 'Collective Attribute configuration' "
144           "SUP olcOverlayConfig "
145           "MAY olcCollectInfo )",
146           Cft_Overlay, collectcfg },
147         { NULL, 0, NULL }
148 };
149
150 static int
151 collect_destroy(
152         BackendDB *be,
153         ConfigReply *cr
154 )
155 {
156         slap_overinst *on = (slap_overinst *)be->bd_info;
157         collect_info *ci;
158
159         while (( ci = on->on_bi.bi_private )) {
160                 on->on_bi.bi_private = ci->ci_next;
161                 ch_free( ci->ci_dn.bv_val );
162                 ch_free( ci );
163         }
164         return 0;
165 }
166
167 static int
168 collect_response( Operation *op, SlapReply *rs )
169 {
170         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
171         collect_info *ci = on->on_bi.bi_private;
172
173         /* If we've been configured and the current response is
174          * a search entry
175          */
176         if ( ci && rs->sr_type == REP_SEARCH ) {
177                 int rc;
178
179                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
180
181                 for (; ci; ci=ci->ci_next ) {
182                         BerVarray vals = NULL;
183
184                         /* Is our configured entry an ancestor of this one? */
185                         if ( !dnIsSuffix( &rs->sr_entry->e_nname, &ci->ci_dn ))
186                                 continue;
187
188                         /* Extract the values of the desired attribute from
189                          * the ancestor entry
190                          */
191                         rc = backend_attribute( op, NULL, &ci->ci_dn, ci->ci_ad, &vals, ACL_READ );
192
193                         /* If there are any values, merge them into the
194                          * current entry
195                          */
196                         if ( vals ) {
197                                 /* The current entry may live in a cache, so
198                                  * don't modify it directly. Make a copy and
199                                  * work with that instead.
200                                  */
201                                 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) {
202                                         rs->sr_entry = entry_dup( rs->sr_entry );
203                                         rs->sr_flags |= REP_ENTRY_MODIFIABLE |
204                                                 REP_ENTRY_MUSTBEFREED;
205                                 }
206                                 attr_merge( rs->sr_entry, ci->ci_ad, vals, NULL );
207                                 ber_bvarray_free_x( vals, op->o_tmpmemctx );
208                         }
209                 }
210         }
211         /* Default is to just fall through to the normal processing */
212         return SLAP_CB_CONTINUE;
213 }
214
215 static slap_overinst collect;
216
217 int collect_initialize() {
218         int code;
219
220         collect.on_bi.bi_type = "collect";
221         collect.on_bi.bi_db_destroy = collect_destroy;
222         collect.on_response = collect_response;
223
224         collect.on_bi.bi_cf_ocs = collectocs;
225         code = config_register_schema( collectcfg, collectocs );
226         if ( code ) return code;
227
228         return overlay_register( &collect );
229 }
230
231 #if SLAPD_OVER_COLLECT == SLAPD_MOD_DYNAMIC
232 int init_module(int argc, char *argv[]) {
233         return collect_initialize();
234 }
235 #endif
236
237 #endif /* SLAPD_OVER_COLLECT */