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