1 1.3 christos /* $NetBSD: denyop.c,v 1.4 2025/09/05 21:16:16 christos Exp $ */ 2 1.2 christos 3 1.1 lukem /* denyop.c - Denies operations */ 4 1.2 christos /* $OpenLDAP$ */ 5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 lukem * 7 1.4 christos * Copyright 2004-2024 The OpenLDAP Foundation. 8 1.1 lukem * All rights reserved. 9 1.1 lukem * 10 1.1 lukem * Redistribution and use in source and binary forms, with or without 11 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 12 1.1 lukem * Public License. 13 1.1 lukem * 14 1.1 lukem * A copy of this license is available in the file LICENSE in the 15 1.1 lukem * top-level directory of the distribution or, alternatively, at 16 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 17 1.1 lukem */ 18 1.1 lukem /* ACKNOWLEDGEMENTS: 19 1.1 lukem * This work was initially developed by Pierangelo Masarati for inclusion in 20 1.1 lukem * OpenLDAP Software. 21 1.1 lukem */ 22 1.1 lukem 23 1.2 christos #include <sys/cdefs.h> 24 1.3 christos __RCSID("$NetBSD: denyop.c,v 1.4 2025/09/05 21:16:16 christos Exp $"); 25 1.2 christos 26 1.1 lukem #include "portable.h" 27 1.1 lukem 28 1.1 lukem #ifdef SLAPD_OVER_DENYOP 29 1.1 lukem 30 1.1 lukem #include <stdio.h> 31 1.1 lukem 32 1.1 lukem #include <ac/string.h> 33 1.1 lukem #include <ac/socket.h> 34 1.1 lukem 35 1.1 lukem #include "slap.h" 36 1.1 lukem 37 1.1 lukem /* This overlay provides a quick'n'easy way to deny selected operations 38 1.1 lukem * for a database whose backend implements the operations. It is intended 39 1.1 lukem * to be less expensive than ACLs because its evaluation occurs before 40 1.1 lukem * any backend specific operation is actually even initiated. 41 1.1 lukem */ 42 1.1 lukem 43 1.1 lukem enum { 44 1.1 lukem denyop_add = 0, 45 1.1 lukem denyop_bind, 46 1.1 lukem denyop_compare, 47 1.1 lukem denyop_delete, 48 1.1 lukem denyop_extended, 49 1.1 lukem denyop_modify, 50 1.1 lukem denyop_modrdn, 51 1.1 lukem denyop_search, 52 1.1 lukem denyop_unbind 53 1.1 lukem } denyop_e; 54 1.1 lukem 55 1.1 lukem typedef struct denyop_info { 56 1.1 lukem int do_op[denyop_unbind + 1]; 57 1.1 lukem } denyop_info; 58 1.1 lukem 59 1.1 lukem static int 60 1.1 lukem denyop_func( Operation *op, SlapReply *rs ) 61 1.1 lukem { 62 1.1 lukem slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 63 1.1 lukem denyop_info *oi = (denyop_info *)on->on_bi.bi_private; 64 1.1 lukem int deny = 0; 65 1.1 lukem 66 1.1 lukem switch( op->o_tag ) { 67 1.1 lukem case LDAP_REQ_BIND: 68 1.1 lukem deny = oi->do_op[denyop_bind]; 69 1.1 lukem break; 70 1.1 lukem 71 1.1 lukem case LDAP_REQ_ADD: 72 1.1 lukem deny = oi->do_op[denyop_add]; 73 1.1 lukem break; 74 1.1 lukem 75 1.1 lukem case LDAP_REQ_DELETE: 76 1.1 lukem deny = oi->do_op[denyop_delete]; 77 1.1 lukem break; 78 1.1 lukem 79 1.1 lukem case LDAP_REQ_MODRDN: 80 1.1 lukem deny = oi->do_op[denyop_modrdn]; 81 1.1 lukem break; 82 1.1 lukem 83 1.1 lukem case LDAP_REQ_MODIFY: 84 1.1 lukem deny = oi->do_op[denyop_modify]; 85 1.1 lukem break; 86 1.1 lukem 87 1.1 lukem case LDAP_REQ_COMPARE: 88 1.1 lukem deny = oi->do_op[denyop_compare]; 89 1.1 lukem break; 90 1.1 lukem 91 1.1 lukem case LDAP_REQ_SEARCH: 92 1.1 lukem deny = oi->do_op[denyop_search]; 93 1.1 lukem break; 94 1.1 lukem 95 1.1 lukem case LDAP_REQ_EXTENDED: 96 1.1 lukem deny = oi->do_op[denyop_extended]; 97 1.1 lukem break; 98 1.1 lukem 99 1.1 lukem case LDAP_REQ_UNBIND: 100 1.1 lukem deny = oi->do_op[denyop_unbind]; 101 1.1 lukem break; 102 1.1 lukem } 103 1.1 lukem 104 1.1 lukem if ( !deny ) { 105 1.1 lukem return SLAP_CB_CONTINUE; 106 1.1 lukem } 107 1.1 lukem 108 1.1 lukem op->o_bd->bd_info = (BackendInfo *)on->on_info; 109 1.1 lukem send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 110 1.1 lukem "operation not allowed within namingContext" ); 111 1.1 lukem 112 1.1 lukem return 0; 113 1.1 lukem } 114 1.1 lukem 115 1.1 lukem static int 116 1.1 lukem denyop_over_init( 117 1.2 christos BackendDB *be, ConfigReply *cr 118 1.1 lukem ) 119 1.1 lukem { 120 1.1 lukem slap_overinst *on = (slap_overinst *) be->bd_info; 121 1.1 lukem denyop_info *oi; 122 1.1 lukem 123 1.1 lukem oi = (denyop_info *)ch_malloc(sizeof(denyop_info)); 124 1.1 lukem memset(oi, 0, sizeof(denyop_info)); 125 1.1 lukem on->on_bi.bi_private = oi; 126 1.1 lukem 127 1.1 lukem return 0; 128 1.1 lukem } 129 1.1 lukem 130 1.1 lukem static int 131 1.1 lukem denyop_config( 132 1.1 lukem BackendDB *be, 133 1.1 lukem const char *fname, 134 1.1 lukem int lineno, 135 1.1 lukem int argc, 136 1.1 lukem char **argv 137 1.1 lukem ) 138 1.1 lukem { 139 1.1 lukem slap_overinst *on = (slap_overinst *) be->bd_info; 140 1.1 lukem denyop_info *oi = (denyop_info *)on->on_bi.bi_private; 141 1.1 lukem 142 1.1 lukem if ( strcasecmp( argv[0], "denyop" ) == 0 ) { 143 1.1 lukem char *op; 144 1.1 lukem 145 1.1 lukem if ( argc != 2 ) { 146 1.1 lukem Debug( LDAP_DEBUG_ANY, "%s: line %d: " 147 1.1 lukem "operation list missing in " 148 1.1 lukem "\"denyop <op-list>\" line.\n", 149 1.3 christos fname, lineno ); 150 1.1 lukem return( 1 ); 151 1.1 lukem } 152 1.1 lukem 153 1.1 lukem /* The on->on_bi.bi_private pointer can be used for 154 1.1 lukem * anything this instance of the overlay needs. 155 1.1 lukem */ 156 1.1 lukem 157 1.1 lukem op = argv[1]; 158 1.1 lukem do { 159 1.1 lukem char *next = strchr( op, ',' ); 160 1.1 lukem 161 1.1 lukem if ( next ) { 162 1.1 lukem next[0] = '\0'; 163 1.1 lukem next++; 164 1.1 lukem } 165 1.1 lukem 166 1.1 lukem if ( strcmp( op, "add" ) == 0 ) { 167 1.1 lukem oi->do_op[denyop_add] = 1; 168 1.1 lukem 169 1.1 lukem } else if ( strcmp( op, "bind" ) == 0 ) { 170 1.1 lukem oi->do_op[denyop_bind] = 1; 171 1.1 lukem 172 1.1 lukem } else if ( strcmp( op, "compare" ) == 0 ) { 173 1.1 lukem oi->do_op[denyop_compare] = 1; 174 1.1 lukem 175 1.1 lukem } else if ( strcmp( op, "delete" ) == 0 ) { 176 1.1 lukem oi->do_op[denyop_delete] = 1; 177 1.1 lukem 178 1.1 lukem } else if ( strcmp( op, "extended" ) == 0 ) { 179 1.1 lukem oi->do_op[denyop_extended] = 1; 180 1.1 lukem 181 1.1 lukem } else if ( strcmp( op, "modify" ) == 0 ) { 182 1.1 lukem oi->do_op[denyop_modify] = 1; 183 1.1 lukem 184 1.1 lukem } else if ( strcmp( op, "modrdn" ) == 0 ) { 185 1.1 lukem oi->do_op[denyop_modrdn] = 1; 186 1.1 lukem 187 1.1 lukem } else if ( strcmp( op, "search" ) == 0 ) { 188 1.1 lukem oi->do_op[denyop_search] = 1; 189 1.1 lukem 190 1.1 lukem } else if ( strcmp( op, "unbind" ) == 0 ) { 191 1.1 lukem oi->do_op[denyop_unbind] = 1; 192 1.1 lukem 193 1.1 lukem } else { 194 1.1 lukem Debug( LDAP_DEBUG_ANY, "%s: line %d: " 195 1.1 lukem "unknown operation \"%s\" at " 196 1.1 lukem "\"denyop <op-list>\" line.\n", 197 1.1 lukem fname, lineno, op ); 198 1.1 lukem return( 1 ); 199 1.1 lukem } 200 1.1 lukem 201 1.1 lukem op = next; 202 1.1 lukem } while ( op ); 203 1.1 lukem 204 1.1 lukem } else { 205 1.1 lukem return SLAP_CONF_UNKNOWN; 206 1.1 lukem } 207 1.1 lukem return 0; 208 1.1 lukem } 209 1.1 lukem 210 1.1 lukem static int 211 1.1 lukem denyop_destroy( 212 1.2 christos BackendDB *be, ConfigReply *cr 213 1.1 lukem ) 214 1.1 lukem { 215 1.1 lukem slap_overinst *on = (slap_overinst *) be->bd_info; 216 1.1 lukem denyop_info *oi = (denyop_info *)on->on_bi.bi_private; 217 1.1 lukem 218 1.1 lukem if ( oi ) { 219 1.1 lukem ch_free( oi ); 220 1.1 lukem } 221 1.1 lukem 222 1.1 lukem return 0; 223 1.1 lukem } 224 1.1 lukem 225 1.1 lukem /* This overlay is set up for dynamic loading via moduleload. For static 226 1.1 lukem * configuration, you'll need to arrange for the slap_overinst to be 227 1.1 lukem * initialized and registered by some other function inside slapd. 228 1.1 lukem */ 229 1.1 lukem 230 1.1 lukem static slap_overinst denyop; 231 1.1 lukem 232 1.1 lukem int 233 1.1 lukem denyop_initialize( void ) 234 1.1 lukem { 235 1.1 lukem memset( &denyop, 0, sizeof( slap_overinst ) ); 236 1.1 lukem denyop.on_bi.bi_type = "denyop"; 237 1.3 christos denyop.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 238 1.1 lukem denyop.on_bi.bi_db_init = denyop_over_init; 239 1.1 lukem denyop.on_bi.bi_db_config = denyop_config; 240 1.1 lukem denyop.on_bi.bi_db_destroy = denyop_destroy; 241 1.1 lukem 242 1.1 lukem denyop.on_bi.bi_op_bind = denyop_func; 243 1.1 lukem denyop.on_bi.bi_op_search = denyop_func; 244 1.1 lukem denyop.on_bi.bi_op_compare = denyop_func; 245 1.1 lukem denyop.on_bi.bi_op_modify = denyop_func; 246 1.1 lukem denyop.on_bi.bi_op_modrdn = denyop_func; 247 1.1 lukem denyop.on_bi.bi_op_add = denyop_func; 248 1.1 lukem denyop.on_bi.bi_op_delete = denyop_func; 249 1.1 lukem denyop.on_bi.bi_extended = denyop_func; 250 1.1 lukem denyop.on_bi.bi_op_unbind = denyop_func; 251 1.1 lukem 252 1.1 lukem denyop.on_response = NULL /* denyop_response */ ; 253 1.1 lukem 254 1.1 lukem return overlay_register( &denyop ); 255 1.1 lukem } 256 1.1 lukem 257 1.1 lukem #if SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC 258 1.1 lukem int 259 1.1 lukem init_module( int argc, char *argv[] ) 260 1.1 lukem { 261 1.1 lukem return denyop_initialize(); 262 1.1 lukem } 263 1.1 lukem #endif /* SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC */ 264 1.1 lukem 265 1.1 lukem #endif /* defined(SLAPD_OVER_DENYOP) */ 266