1/*	$NetBSD: slapacl.c,v 1.1.1.3 2010/12/12 15:22:47 adam Exp $	*/
2
3/* OpenLDAP: pkg/ldap/servers/slapd/slapacl.c,v 1.24.2.11 2010/04/13 20:23:20 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2004-2010 The OpenLDAP Foundation.
7 * Portions Copyright 2004 Pierangelo Masarati.
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 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
20 * in OpenLDAP Software.
21 */
22
23#include "portable.h"
24
25#include <stdio.h>
26
27#include <ac/stdlib.h>
28
29#include <ac/ctype.h>
30#include <ac/string.h>
31#include <ac/socket.h>
32#include <ac/unistd.h>
33
34#include <lber.h>
35#include <ldif.h>
36#include <lutil.h>
37
38#include "slapcommon.h"
39
40static int
41print_access(
42	Operation		*op,
43	Entry			*e,
44	AttributeDescription	*desc,
45	struct berval		*val,
46	struct berval		*nval )
47{
48	int			rc;
49	slap_mask_t		mask;
50	char			accessmaskbuf[ACCESSMASK_MAXLEN];
51
52	rc = access_allowed_mask( op, e, desc, nval, ACL_AUTH, NULL, &mask );
53
54	fprintf( stderr, "%s%s%s: %s\n",
55			desc->ad_cname.bv_val,
56			( val && !BER_BVISNULL( val ) ) ? "=" : "",
57			( val && !BER_BVISNULL( val ) ) ?
58				( desc == slap_schema.si_ad_userPassword ?
59					"****" : val->bv_val ) : "",
60			accessmask2str( mask, accessmaskbuf, 1 ) );
61
62	return rc;
63}
64
65int
66slapacl( int argc, char **argv )
67{
68	int			rc = EXIT_SUCCESS;
69	const char		*progname = "slapacl";
70	Connection		conn = { 0 };
71	Listener		listener;
72	OperationBuffer	opbuf;
73	Operation		*op = NULL;
74	Entry			e = { 0 }, *ep = &e;
75	char			*attr = NULL;
76	int			doclose = 0;
77	BackendDB		*bd;
78	void			*thrctx;
79
80	slap_tool_init( progname, SLAPACL, argc, argv );
81
82	if ( !dryrun ) {
83		int	i = 0;
84
85		LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
86			if ( bd != be && backend_startup( bd ) ) {
87				fprintf( stderr, "backend_startup(#%d%s%s) failed\n",
88						i,
89						bd->be_suffix ? ": " : "",
90						bd->be_suffix ? bd->be_suffix[0].bv_val : "" );
91				rc = 1;
92				goto destroy;
93			}
94
95			i++;
96		}
97	}
98
99	argv = &argv[ optind ];
100	argc -= optind;
101
102	thrctx = ldap_pvt_thread_pool_context();
103	connection_fake_init( &conn, &opbuf, thrctx );
104	op = &opbuf.ob_op;
105	op->o_tmpmemctx = NULL;
106
107	conn.c_listener = &listener;
108	conn.c_listener_url = listener_url;
109	conn.c_peer_domain = peer_domain;
110	conn.c_peer_name = peer_name;
111	conn.c_sock_name = sock_name;
112	op->o_ssf = ssf;
113	op->o_transport_ssf = transport_ssf;
114	op->o_tls_ssf = tls_ssf;
115	op->o_sasl_ssf = sasl_ssf;
116
117	if ( !BER_BVISNULL( &authcID ) ) {
118		if ( !BER_BVISNULL( &authcDN ) ) {
119			fprintf( stderr, "both authcID=\"%s\" "
120					"and authcDN=\"%s\" provided\n",
121					authcID.bv_val, authcDN.bv_val );
122			rc = 1;
123			goto destroy;
124		}
125
126		rc = slap_sasl_getdn( &conn, op, &authcID, NULL,
127				&authcDN, SLAP_GETDN_AUTHCID );
128		if ( rc != LDAP_SUCCESS ) {
129			fprintf( stderr, "authcID: <%s> check failed %d (%s)\n",
130					authcID.bv_val, rc,
131					ldap_err2string( rc ) );
132			rc = 1;
133			goto destroy;
134		}
135
136	} else if ( !BER_BVISNULL( &authcDN ) ) {
137		struct berval	ndn;
138
139		rc = dnNormalize( 0, NULL, NULL, &authcDN, &ndn, NULL );
140		if ( rc != LDAP_SUCCESS ) {
141			fprintf( stderr, "autchDN=\"%s\" normalization failed %d (%s)\n",
142					authcDN.bv_val, rc,
143					ldap_err2string( rc ) );
144			rc = 1;
145			goto destroy;
146		}
147		ch_free( authcDN.bv_val );
148		authcDN = ndn;
149	}
150
151	if ( !BER_BVISNULL( &authzID ) ) {
152		if ( !BER_BVISNULL( &authzDN ) ) {
153			fprintf( stderr, "both authzID=\"%s\" "
154					"and authzDN=\"%s\" provided\n",
155					authzID.bv_val, authzDN.bv_val );
156			rc = 1;
157			goto destroy;
158		}
159
160		rc = slap_sasl_getdn( &conn, op, &authzID, NULL,
161				&authzDN, SLAP_GETDN_AUTHZID );
162		if ( rc != LDAP_SUCCESS ) {
163			fprintf( stderr, "authzID: <%s> check failed %d (%s)\n",
164					authzID.bv_val, rc,
165					ldap_err2string( rc ) );
166			rc = 1;
167			goto destroy;
168		}
169
170	} else if ( !BER_BVISNULL( &authzDN ) ) {
171		struct berval	ndn;
172
173		rc = dnNormalize( 0, NULL, NULL, &authzDN, &ndn, NULL );
174		if ( rc != LDAP_SUCCESS ) {
175			fprintf( stderr, "autchDN=\"%s\" normalization failed %d (%s)\n",
176					authzDN.bv_val, rc,
177					ldap_err2string( rc ) );
178			rc = 1;
179			goto destroy;
180		}
181		ch_free( authzDN.bv_val );
182		authzDN = ndn;
183	}
184
185
186	if ( !BER_BVISNULL( &authcDN ) ) {
187		fprintf( stderr, "authcDN: \"%s\"\n", authcDN.bv_val );
188	}
189
190	if ( !BER_BVISNULL( &authzDN ) ) {
191		fprintf( stderr, "authzDN: \"%s\"\n", authzDN.bv_val );
192	}
193
194	if ( !BER_BVISNULL( &authzDN ) ) {
195		op->o_dn = authzDN;
196		op->o_ndn = authzDN;
197
198		if ( !BER_BVISNULL( &authcDN ) ) {
199			op->o_conn->c_dn = authcDN;
200			op->o_conn->c_ndn = authcDN;
201
202		} else {
203			op->o_conn->c_dn = authzDN;
204			op->o_conn->c_ndn = authzDN;
205		}
206
207	} else if ( !BER_BVISNULL( &authcDN ) ) {
208		op->o_conn->c_dn = authcDN;
209		op->o_conn->c_ndn = authcDN;
210		op->o_dn = authcDN;
211		op->o_ndn = authcDN;
212	}
213
214	assert( !BER_BVISNULL( &baseDN ) );
215	rc = dnPrettyNormal( NULL, &baseDN, &e.e_name, &e.e_nname, NULL );
216	if ( rc != LDAP_SUCCESS ) {
217		fprintf( stderr, "base=\"%s\" normalization failed %d (%s)\n",
218				baseDN.bv_val, rc,
219				ldap_err2string( rc ) );
220		rc = 1;
221		goto destroy;
222	}
223
224	op->o_bd = be;
225	if ( op->o_bd == NULL ) {
226		/* NOTE: if no database could be found (e.g. because
227		 * accessing the rootDSE or so), use the frontendDB
228		 * rules; might need work */
229		op->o_bd = frontendDB;
230	}
231
232	if ( !dryrun ) {
233		ID	id;
234
235		if ( be == NULL ) {
236			fprintf( stderr, "%s: no target database "
237				"has been found for baseDN=\"%s\"; "
238				"you may try with \"-u\" (dry run).\n",
239				baseDN.bv_val, progname );
240			rc = 1;
241			goto destroy;
242		}
243
244		if ( !be->be_entry_open ||
245			!be->be_entry_close ||
246			!be->be_dn2id_get ||
247			!be->be_entry_get )
248		{
249			fprintf( stderr, "%s: target database "
250				"doesn't support necessary operations; "
251				"you may try with \"-u\" (dry run).\n",
252				progname );
253			rc = 1;
254			goto destroy;
255		}
256
257		if ( be->be_entry_open( be, 0 ) != 0 ) {
258			fprintf( stderr, "%s: could not open database.\n",
259				progname );
260			rc = 1;
261			goto destroy;
262		}
263
264		doclose = 1;
265
266		id = be->be_dn2id_get( be, &e.e_nname );
267		if ( id == NOID ) {
268			fprintf( stderr, "%s: unable to fetch ID of DN \"%s\"\n",
269				progname, e.e_nname.bv_val );
270			rc = 1;
271			goto destroy;
272		}
273		ep = be->be_entry_get( be, id );
274		if ( ep == NULL ) {
275			fprintf( stderr, "%s: unable to fetch entry \"%s\" (%lu)\n",
276				progname, e.e_nname.bv_val, id );
277			rc = 1;
278			goto destroy;
279
280		}
281
282		if ( argc == 0 ) {
283			Attribute	*a;
284
285			(void)print_access( op, ep, slap_schema.si_ad_entry, NULL, NULL );
286			(void)print_access( op, ep, slap_schema.si_ad_children, NULL, NULL );
287
288			for ( a = ep->e_attrs; a; a = a->a_next ) {
289				int	i;
290
291				for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
292					(void)print_access( op, ep, a->a_desc,
293							&a->a_vals[ i ],
294							&a->a_nvals[ i ] );
295				}
296			}
297		}
298	}
299
300	for ( ; argc--; argv++ ) {
301		slap_mask_t		mask;
302		AttributeDescription	*desc = NULL;
303		struct berval		val = BER_BVNULL,
304					*valp = NULL;
305		const char		*text;
306		char			accessmaskbuf[ACCESSMASK_MAXLEN];
307		char			*accessstr;
308		slap_access_t		access = ACL_AUTH;
309
310		if ( attr == NULL ) {
311			attr = argv[ 0 ];
312		}
313
314		val.bv_val = strchr( attr, ':' );
315		if ( val.bv_val != NULL ) {
316			val.bv_val[0] = '\0';
317			val.bv_val++;
318			val.bv_len = strlen( val.bv_val );
319			valp = &val;
320		}
321
322		accessstr = strchr( attr, '/' );
323		if ( accessstr != NULL ) {
324			int	invalid = 0;
325
326			accessstr[0] = '\0';
327			accessstr++;
328			access = str2access( accessstr );
329			switch ( access ) {
330			case ACL_INVALID_ACCESS:
331				fprintf( stderr, "unknown access \"%s\" for attribute \"%s\"\n",
332						accessstr, attr );
333				invalid = 1;
334				break;
335
336			case ACL_NONE:
337				fprintf( stderr, "\"none\" not allowed for attribute \"%s\"\n",
338						attr );
339				invalid = 1;
340				break;
341
342			default:
343				break;
344			}
345
346			if ( invalid ) {
347				if ( continuemode ) {
348					continue;
349				}
350				break;
351			}
352		}
353
354		rc = slap_str2ad( attr, &desc, &text );
355		if ( rc != LDAP_SUCCESS ) {
356			fprintf( stderr, "slap_str2ad(%s) failed %d (%s)\n",
357					attr, rc, ldap_err2string( rc ) );
358			if ( continuemode ) {
359				continue;
360			}
361			break;
362		}
363
364		rc = access_allowed_mask( op, ep, desc, valp, access,
365				NULL, &mask );
366
367		if ( accessstr ) {
368			fprintf( stderr, "%s access to %s%s%s: %s\n",
369					accessstr,
370					desc->ad_cname.bv_val,
371					val.bv_val ? "=" : "",
372					val.bv_val ? val.bv_val : "",
373					rc ? "ALLOWED" : "DENIED" );
374
375		} else {
376			fprintf( stderr, "%s%s%s: %s\n",
377					desc->ad_cname.bv_val,
378					val.bv_val ? "=" : "",
379					val.bv_val ? val.bv_val : "",
380					accessmask2str( mask, accessmaskbuf, 1 ) );
381		}
382		rc = 0;
383		attr = NULL;
384	}
385
386destroy:;
387	if ( !BER_BVISNULL( &e.e_name ) ) {
388		ber_memfree( e.e_name.bv_val );
389	}
390	if ( !BER_BVISNULL( &e.e_nname ) ) {
391		ber_memfree( e.e_nname.bv_val );
392	}
393	if ( !dryrun && be ) {
394		if ( ep && ep != &e ) {
395			be_entry_release_r( op, ep );
396		}
397		if ( doclose ) {
398			be->be_entry_close( be );
399		}
400
401		LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
402			if ( bd != be ) {
403				backend_shutdown( bd );
404			}
405		}
406	}
407
408	if ( slap_tool_destroy())
409		rc = EXIT_FAILURE;
410
411	return rc;
412}
413
414