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