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