]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/dyngroup.c
ITS#5705
[openldap] / servers / slapd / overlays / dyngroup.c
1 /* dyngroup.c - Demonstration of overlay code */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2008 The OpenLDAP Foundation.
6  * Copyright 2003 by 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 Howard Chu for inclusion in
19  * OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_DYNGROUP
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/socket.h>
30
31 #include "lutil.h"
32 #include "slap.h"
33 #include "config.h"
34
35 /* This overlay extends the Compare operation to detect members of a
36  * dynamic group. It has no effect on any other operations. It must
37  * be configured with a pair of attributes to trigger on, e.g.
38  *      attrpair member memberURL
39  * will cause compares on "member" to trigger a compare on "memberURL".
40  */
41
42 typedef struct adpair {
43         struct adpair *ap_next;
44         AttributeDescription *ap_mem;
45         AttributeDescription *ap_uri;
46 } adpair;
47
48 static int dgroup_cf( ConfigArgs *c )
49 {
50         slap_overinst *on = (slap_overinst *)c->bi;
51         int rc = 1;
52
53         switch( c->op ) {
54         case SLAP_CONFIG_EMIT:
55                 {
56                 adpair *ap;
57                 for ( ap = on->on_bi.bi_private; ap; ap = ap->ap_next ) {
58                         struct berval bv;
59                         char *ptr;
60                         bv.bv_len = ap->ap_mem->ad_cname.bv_len + 1 +
61                                 ap->ap_uri->ad_cname.bv_len;
62                         bv.bv_val = ch_malloc( bv.bv_len + 1 );
63                         ptr = lutil_strcopy( bv.bv_val, ap->ap_mem->ad_cname.bv_val );
64                         *ptr++ = ' ';
65                         strcpy( ptr, ap->ap_uri->ad_cname.bv_val );
66                         ber_bvarray_add( &c->rvalue_vals, &bv );
67                         rc = 0;
68                 }
69                 }
70                 break;
71         case LDAP_MOD_DELETE:
72                 if ( c->valx == -1 ) {
73                         adpair *ap;
74                         while (( ap = on->on_bi.bi_private )) {
75                                 on->on_bi.bi_private = ap->ap_next;
76                                 ch_free( ap );
77                         }
78                 } else {
79                         adpair **app, *ap;
80                         int i;
81                         app = (adpair **)&on->on_bi.bi_private;
82                         for (i=0; i<=c->valx; i++, app = &ap->ap_next) {
83                                 ap = *app;
84                         }
85                         *app = ap->ap_next;
86                         ch_free( ap );
87                 }
88                 rc = 0;
89                 break;
90         case SLAP_CONFIG_ADD:
91         case LDAP_MOD_ADD:
92                 {
93                 adpair ap = { NULL, NULL, NULL }, *a2;
94                 const char *text;
95                 if ( slap_str2ad( c->argv[1], &ap.ap_mem, &text ) ) {
96                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"",
97                                 c->argv[0], c->argv[1] );
98                         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
99                                 "%s: %s\n", c->log, c->cr_msg, 0 );
100                         return ARG_BAD_CONF;
101                 }
102                 if ( slap_str2ad( c->argv[2], &ap.ap_uri, &text ) ) {
103                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"",
104                                 c->argv[0], c->argv[2] );
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                 /* The on->on_bi.bi_private pointer can be used for
110                  * anything this instance of the overlay needs.
111                  */
112                 a2 = ch_malloc( sizeof(adpair) );
113                 a2->ap_next = on->on_bi.bi_private;
114                 a2->ap_mem = ap.ap_mem;
115                 a2->ap_uri = ap.ap_uri;
116                 on->on_bi.bi_private = a2;
117                 rc = 0;
118                 }
119         }
120         return rc;
121 }
122
123 static ConfigTable dgroupcfg[] = {
124         { "attrpair", "member-attribute> <URL-attribute", 3, 3, 0,
125           ARG_MAGIC, dgroup_cf,
126           "( OLcfgOvAt:17.1 NAME 'olcDGAttrPair' "
127           "DESC 'Member and MemberURL attribute pair' "
128           "SYNTAX OMsDirectoryString )", NULL, NULL },
129         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
130 };
131
132 static ConfigOCs dgroupocs[] = {
133         { "( OLcfgOvOc:17.1 "
134           "NAME 'olcDGConfig' "
135           "DESC 'Dynamic Group configuration' "
136           "SUP olcOverlayConfig "
137           "MAY olcDGAttrPair )",
138           Cft_Overlay, dgroupcfg },
139         { NULL, 0, NULL }
140 };
141
142 static int
143 dyngroup_response( Operation *op, SlapReply *rs )
144 {
145         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
146         adpair *ap = on->on_bi.bi_private;
147
148         /* If we've been configured and the current response is
149          * what we're looking for...
150          */
151         if ( ap && op->o_tag == LDAP_REQ_COMPARE &&
152                 rs->sr_err == LDAP_NO_SUCH_ATTRIBUTE ) {
153
154                 for (;ap;ap=ap->ap_next) {
155                         if ( op->oq_compare.rs_ava->aa_desc == ap->ap_mem ) {
156                                 /* This compare is for one of the attributes we're
157                                  * interested in. We'll use slapd's existing dyngroup
158                                  * evaluator to get the answer we want.
159                                  */
160                                 int cache = op->o_do_not_cache;
161                                 
162                                 op->o_do_not_cache = 1;
163                                 rs->sr_err = backend_group( op, NULL, &op->o_req_ndn,
164                                         &op->oq_compare.rs_ava->aa_value, NULL, ap->ap_uri );
165                                 op->o_do_not_cache = cache;
166                                 switch ( rs->sr_err ) {
167                                 case LDAP_SUCCESS:
168                                         rs->sr_err = LDAP_COMPARE_TRUE;
169                                         break;
170
171                                 case LDAP_NO_SUCH_OBJECT:
172                                         rs->sr_err = LDAP_COMPARE_FALSE;
173                                         break;
174                                 }
175                                 break;
176                         }
177                 }
178         }
179         /* Default is to just fall through to the normal processing */
180         return SLAP_CB_CONTINUE;
181 }
182
183 static int
184 dyngroup_close(
185         BackendDB *be,
186         ConfigReply *cr
187 )
188 {
189         slap_overinst *on = (slap_overinst *) be->bd_info;
190         adpair *ap, *a2;
191
192         for ( ap = on->on_bi.bi_private; ap; ap = a2 ) {
193                 a2 = ap->ap_next;
194                 ch_free( ap );
195         }
196         return 0;
197 }
198
199 static slap_overinst dyngroup;
200
201 /* This overlay is set up for dynamic loading via moduleload. For static
202  * configuration, you'll need to arrange for the slap_overinst to be
203  * initialized and registered by some other function inside slapd.
204  */
205
206 int dyngroup_initialize() {
207         int code;
208
209         dyngroup.on_bi.bi_type = "dyngroup";
210         dyngroup.on_bi.bi_db_close = dyngroup_close;
211         dyngroup.on_response = dyngroup_response;
212
213         dyngroup.on_bi.bi_cf_ocs = dgroupocs;
214         code = config_register_schema( dgroupcfg, dgroupocs );
215         if ( code ) return code;
216
217         return overlay_register( &dyngroup );
218 }
219
220 #if SLAPD_OVER_DYNGROUP == SLAPD_MOD_DYNAMIC
221 int
222 init_module( int argc, char *argv[] )
223 {
224         return dyngroup_initialize();
225 }
226 #endif
227
228 #endif /* defined(SLAPD_OVER_DYNGROUP) */