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