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