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