]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/collect.c
f87fed856515ff9ee4829d5de75963b7cdf09f30
[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-2005 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
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_response( Operation *op, SlapReply *rs )
51 {
52         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
53         collect_info *ci = on->on_bi.bi_private;
54
55         /* If we've been configured and the current response is
56          * a search entry
57          */
58         if ( ci && rs->sr_type == REP_SEARCH ) {
59                 Entry *new = NULL;
60                 int rc;
61
62                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
63
64                 for (; ci; ci=ci->ci_next ) {
65                         BerVarray vals = NULL;
66
67                         /* Is our configured entry an ancestor of this one? */
68                         rc = rs->sr_entry->e_nname.bv_len - ci->ci_dn.bv_len;
69                         if ( rc < 1 || strcmp( rs->sr_entry->e_nname.bv_val + rc,
70                                 ci->ci_dn.bv_val )) continue;
71
72                         /* Extract the values of the desired attribute from
73                          * the ancestor entry
74                          */
75                         rc = backend_attribute( op, NULL, &ci->ci_dn, ci->ci_ad, &vals, ACL_READ );
76
77                         /* If there are any values, merge them into the
78                          * current entry
79                          */
80                         if ( vals ) {
81                                 /* The current entry may live in a cache, so
82                                  * don't modify it directly. Make a copy and
83                                  * work with that instead.
84                                  */
85                                 if ( !new ) {
86                                         new = entry_dup( rs->sr_entry );
87                                 }
88                                 attr_merge( new, ci->ci_ad, vals, NULL );
89                                 ber_bvarray_free_x( vals, op->o_tmpmemctx );
90                         }
91                 }
92
93                 if ( new ) {
94                         rs->sr_entry = new;
95                         rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
96                 }
97         }
98         /* Default is to just fall through to the normal processing */
99         return SLAP_CB_CONTINUE;
100 }
101
102 static int collect_config(
103     BackendDB   *be,
104     const char  *fname,
105     int         lineno,
106     int         argc,
107     char        **argv
108 )
109 {
110         slap_overinst *on = (slap_overinst *) be->bd_info;
111         AttributeDescription *ad = NULL;
112
113         /* The config syntax is "collectinfo <dn> <attribute-description>"
114          * and only one directive may be specified per overlay instance.
115          */
116
117         if ( strcasecmp( argv[0], "collectinfo" ) == 0 ) {
118                 collect_info *ci;
119                 struct berval bv, dn;
120                 const char *text;
121                 if ( argc != 3 ) {
122                         Debug( LDAP_DEBUG_ANY,
123                 "%s: line %d: argument missing in \"collectinfo <dn> <attribute-description>\" line.\n",
124                         fname, lineno, 0 );
125                         return( 1 );
126                 }
127                 ber_str2bv( argv[1], 0, 0, &bv );
128                 if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) {
129                         Debug( LDAP_DEBUG_ANY,
130                 "%s: line %d: invalid DN in \"collectinfo\" line: %s.\n",
131                         fname, lineno, text );
132                         return( 1 );
133                 }
134                 if ( slap_str2ad( argv[2], &ad, &text ) ) {
135                         Debug( LDAP_DEBUG_ANY,
136                 "%s: line %d: attribute description unknown in \"collectinfo\" line: %s.\n",
137                         fname, lineno, text );
138                         return( 1 );
139                 }
140
141                 /* The on->on_bi.bi_private pointer can be used for
142                  * anything this instance of the overlay needs.
143                  */
144                 ci = ch_malloc( sizeof( collect_info ));
145                 ci->ci_ad = ad;
146                 ci->ci_dn = dn;
147                 ci->ci_next = on->on_bi.bi_private;
148                 on->on_bi.bi_private = ci;
149                 return 0;
150         }
151         return SLAP_CONF_UNKNOWN;
152 }
153
154 static slap_overinst collect;
155
156 int collect_initialize() {
157         collect.on_bi.bi_type = "collect";
158         collect.on_bi.bi_db_config = collect_config;
159         collect.on_response = collect_response;
160
161         return overlay_register( &collect );
162 }
163
164 #if SLAPD_OVER_COLLECT == SLAPD_MOD_DYNAMIC
165 int init_module(int argc, char *argv[]) {
166         return collect_initialize();
167 }
168 #endif
169
170 #endif /* SLAPD_OVER_COLLECT */