xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/slapacl.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: slapacl.c,v 1.1.1.4 2014/05/28 09:58:48 tron Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2004-2014 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 
40 static int
41 print_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 
65 int
66 slapacl( 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 
386 destroy:;
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