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