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 43static int 44print_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 68int 69slapacl( 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 389destroy:; 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