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 47typedef struct adpair { 48 struct adpair *ap_next; 49 AttributeDescription *ap_mem; 50 AttributeDescription *ap_uri; 51} adpair; 52 53static 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 128static 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 138static 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 148static int 149dyngroup_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 189static int 190dyngroup_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 205static 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 212int 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 228int 229init_module( int argc, char *argv[] ) 230{ 231 return dyngroup_initialize(); 232} 233#endif 234 235#endif /* defined(SLAPD_OVER_DYNGROUP) */ 236