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