summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/acl/aclplugin.c
blob: 66ef7071d79a26b0227d05528c387fa416f7d8e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/** BEGIN COPYRIGHT BLOCK
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 2 of the License.
 * 
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA.
 * 
 * In addition, as a special exception, Red Hat, Inc. gives You the additional
 * right to link the code of this Program with code not covered under the GNU
 * General Public License ("Non-GPL Code") and to distribute linked combinations
 * including the two, subject to the limitations in this paragraph. Non-GPL Code
 * permitted under this exception must only link to the code of this Program
 * through those well defined interfaces identified in the file named EXCEPTION
 * found in the source code files (the "Approved Interfaces"). The files of
 * Non-GPL Code may instantiate templates or use macros or inline functions from
 * the Approved Interfaces without causing the resulting work to be covered by
 * the GNU General Public License. Only Red Hat, Inc. may make changes or
 * additions to the list of Approved Interfaces. You must obey the GNU General
 * Public License in all respects for all of the Program code and other code used
 * in conjunction with the Program except the Non-GPL Code covered by this
 * exception. If you modify this file, you may extend this exception to your
 * version of the file, but you are not obligated to do so. If you do not wish to
 * provide this exception without modification, you must delete this exception
 * statement from your version and license this file solely under the GPL without
 * exception. 
 * 
 * 
 * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*
 * There are 3 ACL PLUGIN points
 * PREOP, POSTOP and ACL plugin
 *
 */
#include "acl.h"

static Slapi_PluginDesc pdesc = { "acl", VENDOR, DS_PACKAGE_VERSION, "acl access check plugin" };
char *plugin_name = ACL_PLUGIN_NAME;

/* Prototypes */

static int aclplugin_preop_search ( Slapi_PBlock *pb );
static int aclplugin_preop_modify ( Slapi_PBlock *pb );
int aclplugin_preop_common ( Slapi_PBlock *pb );

/*******************************************************************************
 *  ACL PLUGIN Architecture
 *
 *	There are 3 registered plugins:
 *
 *	1) PREOP ACL Plugin
 *		The preop plugin does all the initialization. It allocate the ACL
 *		PBlock and copies stuff from the connection if it needs to.
 *	
 *	2) POSTOP ACL Plugin
 *		The Postop plugin cleans up the ACL PBlock. It copies Back to the
 *		connection struct. The Postop bind & Unbind  cleans up the 
 *		ACL CBlock ( struct hanging from conn struct ).
 *
 *	3) ACCESSCONTROL Plugin
 *		Main module which does the access check. There are 5 entry point
 *		from this plugin 
 *		a) Initilize the ACL system i.e read all the ACLs and generate the
 *		   the ACL List.
 *		b) Check for ACI syntax.
 *		c) Check for normal access.
 *		d) Check for access to a mod request.
 *		e) Update the in-memory ACL List.
 *
 *******************************************************************************/

/*******************************************************************************
 * PREOP
 *******************************************************************************/

/* Plugin identity is passed by the server in the plugin init function and must 
   be supplied by the plugin to all internal operations it initiates
 */
void* g_acl_preop_plugin_identity;

int
acl_preopInit (Slapi_PBlock *pb)
{
	int rc = 0;
	
	/* save plugin identity to later pass to internal operations */
	rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_preop_plugin_identity);

	/* Declare plugin version */
	rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);

    	/* Provide descriptive information */
	rc |=  slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&pdesc);

	/* Register functions */
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void*)aclplugin_preop_search);
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void*)aclplugin_preop_search);
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,    (void*)aclplugin_preop_modify);
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void*)aclplugin_preop_modify);
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void*)aclplugin_preop_modify);
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void*)aclplugin_preop_modify);

#if 0
	/*
	 * XXXmcs: In order to support access control checking from
	 * extended operations, we need a SLAPI_PLUGIN_PRE_EXTENDED_FN hook.
	 * But today no such entry point exists.
	 */
	rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTENDED_FN, (void*)aclplugin_preop_modify);
#endif


        slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_preop_Init %d\n", rc );
        return( rc );
}

/* For preop search we do two things:
 * 1) based on the search base, we preselect the acls.
 * 2) also get hold of a acl_pblock for use 
 */
static int
aclplugin_preop_search ( Slapi_PBlock *pb )
{
	int 		scope;
	char		*base = NULL;
	int			optype;
	int			isRoot;
	int			rc = 0;
			
	TNF_PROBE_0_DEBUG(aclplugin_preop_search_start ,"ACL","");

	slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
	slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );

	if ( isRoot ) {
		TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
							tnf_string,isroot,"");
		return rc;
	}

	slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
	/* For anonymous client  doing search nothing needs to be set up */
	if ( optype == SLAPI_OPERATION_SEARCH && aclanom_is_client_anonymous ( pb )  &&
			! slapi_dn_issuffix( base, "cn=monitor") ) {
				TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
									tnf_string,anon,"");
		return rc;
	}

	if ( 0 == ( rc = aclplugin_preop_common( pb ))) {
		slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
		acllist_init_scan ( pb, scope, base );
	}

	TNF_PROBE_0_DEBUG(aclplugin_preop_search_end ,"ACL","");

	return rc;
}

/* 
 * For rest of the opertion type, we get a hold of the acl
 * private Block.
 */
static int
aclplugin_preop_modify ( Slapi_PBlock *pb )
{
	/*
	 * Note: since we don't keep the anom profile for modifies, we have to go
	 * through the regular process to check the access.
	*/
	return aclplugin_preop_common( pb );
}

/*
 * Common function that is called by aclplugin_preop_search() and
 * aclplugin_preop_modify().
 *
 * Return values:
 *	0 - all is well; proceed.
 *  1 - fatal error; result has been sent to client.
 */ 
int
aclplugin_preop_common( Slapi_PBlock *pb )
{
	char		*proxy_dn;	/* id being assumed */
	char		*dn;		/* proxy master */
	char		*errtext = NULL;
	int			lderr;
	Acl_PBlock	*aclpb;

	TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL","");

	aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );

	if (aclpb == NULL) {
		slapi_log_error( SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common: Error: aclpb is NULL\n" );
		slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
		return 1;
	}

        /* See if we have initialized already */
        if ( aclpb->aclpb_state & ACLPB_INITIALIZED ) goto done;

	/*
	 * The following mallocs memory for proxy_dn, but not the dn.
	 * The proxy_dn is the id being assumed, while dn
	 * is the "proxy master".
	*/
	proxy_dn = NULL;
	if ( LDAP_SUCCESS != ( lderr = proxyauth_get_dn( pb, &proxy_dn,
			&errtext ))) {
		/*
		 * Fatal error -- send a result to the client and arrange to skip
		 * any further processing.
		 */
		slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL );
		TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","",
						tnf_string,proxid_error,"");

		return 1;	/* skip any further processing */
	}
	slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn );


	/*
	 * The dn is copied into the aclpb during initialization.
	*/
	if ( proxy_dn) {
		TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL","");

		slapi_log_error( SLAPI_LOG_ACL, plugin_name,
				"proxied authorization dn is (%s)\n", proxy_dn );
		acl_init_aclpb ( pb, aclpb, proxy_dn, 1 );
		aclpb = acl_new_proxy_aclpb (pb );
		acl_init_aclpb ( pb, aclpb, dn, 0 );
		slapi_ch_free ( (void **) &proxy_dn );
		
		TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL","");
 
	} else {
		TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL","");
		acl_init_aclpb ( pb, aclpb, dn, 1 );
		TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL","");

	}

done:
	TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL","");

	return 0;
}

/*******************************************************************************
 * POSTOP
 *******************************************************************************/

/*******************************************************************************
 * ACCESSCONTROL PLUGIN
 *******************************************************************************/

void* g_acl_plugin_identity;

/* For now, the acl component is implemented as 2 different plugins */
/* Return the right plugin identity 				    */
void * aclplugin_get_identity(int plug) {
        if (plug == ACL_PLUGIN_IDENTITY)
                return g_acl_plugin_identity;
        if (plug == ACL_PREOP_PLUGIN_IDENTITY)
                return g_acl_preop_plugin_identity;
        return NULL;
}

int
aclplugin_init (Slapi_PBlock *pb )
{

	int rc = 0; /* OK */
	rc = aclinit_main ( pb );

	return  rc;

}
int
aclplugin_stop ( Slapi_PBlock *pb )
{
	int rc = 0; /* OK */

	/* nothing to be done now */
	return  rc;
}

int
acl_init( Slapi_PBlock *pb )
{
        int     rc =0;

        slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> acl_init\n" );

        if  ( 0 != acl_init_ext() ) {
		    slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
			    "Unable to initialize the extensions\n");
		    return 1;
	    }

		/* save plugin identity to later pass to internal operations */
		rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_plugin_identity);

        rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
            (void *) SLAPI_PLUGIN_VERSION_01 );
        rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
            (void *)&pdesc );

		rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) aclplugin_init );
		rc = slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) aclplugin_stop );
        rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_SYNTAX_CHECK, 
            (void *) acl_verify_aci_syntax );
        rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_ALLOW_ACCESS,
            (void *) acl_access_allowed_main );
        rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_ALLOWED,
            (void *) acl_check_mods );
        rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_UPDATE,
            (void *) acl_modified );

        slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_init %d\n", rc);
        return( rc );
}

/*
 *
 * acl_access_allowed_main
 *	Main interface to the plugin. Calls different access check functions
 *	based on the flag.
 *
 *	
 *  Returns:
 *	LDAP_SUCCESS			-- access is granted
 *	LDAP_INSUFFICIENT_ACCESS	-- access denied
 *	<other ldap error>		-- ex: opererations error
 *
 */
int
acl_access_allowed_main ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs, 
			  struct berval *val, int access , int flags, char **errbuf)
{
	int	rc =0;
	char	*attr = NULL;

	TNF_PROBE_0_DEBUG(acl_access_allowed_main_start,"ACL","");

	if (attrs && *attrs) attr = attrs[0];

	if (ACLPLUGIN_ACCESS_READ_ON_ENTRY == flags)
		rc = acl_read_access_allowed_on_entry ( pb, e, attrs, access);
	else if ( ACLPLUGIN_ACCESS_READ_ON_ATTR == flags) {
		if (attr == NULL) {
        		slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "Missing attribute\n" );
			rc = LDAP_OPERATIONS_ERROR;
		} else {
			rc = acl_read_access_allowed_on_attr ( pb, e, attr, val, access);
		}
	} else if ( ACLPLUGIN_ACCESS_READ_ON_VLV == flags)
		rc =  acl_access_allowed_disjoint_resource ( pb, e, attr, val, access);
	else if ( ACLPLUGIN_ACCESS_MODRDN == flags)
		rc =  acl_access_allowed_modrdn ( pb, e, attr, val, access);
	else if ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS == flags)
		rc =  acl_get_effective_rights ( pb, e, attrs, val, access, errbuf );
	else
		rc = acl_access_allowed ( pb, e, attr, val, access);

	/* generate the appropriate error message */
	if ( ( rc != LDAP_SUCCESS ) && errbuf && 
		 ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS != flags ) &&
		 ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE ))) {

		char	*edn  = slapi_entry_get_dn ( e );

		acl_gen_err_msg(access, edn, attr, errbuf);
	}
	
	TNF_PROBE_0_DEBUG(acl_access_allowed_main_end,"ACL","");

	return rc;
}
#ifdef _WIN32

int *module_ldap_debug = 0;
void plugin_init_debug_level ( int *level_ptr )
{
	module_ldap_debug = level_ptr;
}
#endif