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-2021 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 "slap-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 
dgroup_cf(ConfigArgs * c)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 );
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 );
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 ( 'olcDynGroupAttrPair' 'olcDGAttrPair' ) "
127 	  "EQUALITY caseIgnoreMatch "
128 	  "DESC 'Member and MemberURL attribute pair' "
129 	  "SYNTAX OMsDirectoryString )", NULL, NULL },
130 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
131 };
132 
133 static ConfigOCs dgroupocs[] = {
134 	{ "( OLcfgOvOc:17.1 "
135 	  "NAME ( 'olcDynGroupConfig' 'olcDGConfig' ) "
136 	  "DESC 'Dynamic Group configuration' "
137 	  "SUP olcOverlayConfig "
138 	  "MAY olcDynGroupAttrPair)",
139 	  Cft_Overlay, dgroupcfg },
140 	{ NULL, 0, NULL }
141 };
142 
143 static int
dyngroup_response(Operation * op,SlapReply * rs)144 dyngroup_response( Operation *op, SlapReply *rs )
145 {
146 	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
147 	adpair *ap = on->on_bi.bi_private;
148 
149 	/* If we've been configured and the current response is
150 	 * what we're looking for...
151 	 */
152 	if ( ap && op->o_tag == LDAP_REQ_COMPARE &&
153 		rs->sr_err == LDAP_NO_SUCH_ATTRIBUTE ) {
154 
155 		for (;ap;ap=ap->ap_next) {
156 			if ( op->oq_compare.rs_ava->aa_desc == ap->ap_mem ) {
157 				/* This compare is for one of the attributes we're
158 				 * interested in. We'll use slapd's existing dyngroup
159 				 * evaluator to get the answer we want.
160 				 */
161 				int cache = op->o_do_not_cache;
162 
163 				op->o_do_not_cache = 1;
164 				rs->sr_err = backend_group( op, NULL, &op->o_req_ndn,
165 					&op->oq_compare.rs_ava->aa_value, NULL, ap->ap_uri );
166 				op->o_do_not_cache = cache;
167 				switch ( rs->sr_err ) {
168 				case LDAP_SUCCESS:
169 					rs->sr_err = LDAP_COMPARE_TRUE;
170 					break;
171 
172 				case LDAP_NO_SUCH_OBJECT:
173 					rs->sr_err = LDAP_COMPARE_FALSE;
174 					break;
175 				}
176 				break;
177 			}
178 		}
179 	}
180 	/* Default is to just fall through to the normal processing */
181 	return SLAP_CB_CONTINUE;
182 }
183 
184 static int
dyngroup_destroy(BackendDB * be,ConfigReply * cr)185 dyngroup_destroy(
186 	BackendDB *be,
187 	ConfigReply *cr
188 )
189 {
190 	slap_overinst *on = (slap_overinst *) be->bd_info;
191 	adpair *ap, *a2;
192 
193 	for ( ap = on->on_bi.bi_private; ap; ap = a2 ) {
194 		a2 = ap->ap_next;
195 		ch_free( ap );
196 	}
197 	return 0;
198 }
199 
200 static slap_overinst dyngroup;
201 
202 /* This overlay is set up for dynamic loading via moduleload. For static
203  * configuration, you'll need to arrange for the slap_overinst to be
204  * initialized and registered by some other function inside slapd.
205  */
206 
dyngroup_initialize()207 int dyngroup_initialize() {
208 	int code;
209 
210 	dyngroup.on_bi.bi_type = "dyngroup";
211 	dyngroup.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
212 	dyngroup.on_bi.bi_db_destroy = dyngroup_destroy;
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
init_module(int argc,char * argv[])224 init_module( int argc, char *argv[] )
225 {
226 	return dyngroup_initialize();
227 }
228 #endif
229 
230 #endif /* defined(SLAPD_OVER_DYNGROUP) */
231