X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Facl.c;h=e4a2b8f1696006df0521ed4caf9c9fa9c3a025d0;hb=93d0ef91e65c6d11991b1c36faba67f212f43a34;hp=d6bc21d3118c8f69c9902ac5317b946499accf58;hpb=b2284183f9ebcb655b286e5b6cbc8e583939289d;p=openldap diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index d6bc21d311..e4a2b8f169 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -39,46 +39,10 @@ #define ACL_BUF_SIZE 1024 /* use most appropriate size */ -/* - * speed up compares - */ -const struct berval aci_bv[] = { - BER_BVC("entry"), - BER_BVC("children"), - BER_BVC("onelevel"), - BER_BVC("subtree"), - BER_BVC("[entry]"), - BER_BVC("[all]"), - BER_BVC("access-id"), -#if 0 - BER_BVC("anonymous"), -#endif - BER_BVC("public"), - BER_BVC("users"), - BER_BVC("self"), - BER_BVC("dnattr"), - BER_BVC("group"), - BER_BVC("role"), - BER_BVC("set"), - BER_BVC("set-ref"), - BER_BVC("grant"), - BER_BVC("deny"), - - BER_BVC("IP="), +static const struct berval acl_bv_ip_eq = BER_BVC( "IP=" ); #ifdef LDAP_PF_LOCAL - BER_BVC("PATH="), -#if 0 - BER_BVC(LDAP_DIRSEP), -#endif +static const struct berval acl_bv_path_eq = BER_BVC("PATH="); #endif /* LDAP_PF_LOCAL */ - - BER_BVC(SLAPD_GROUP_CLASS), - BER_BVC(SLAPD_GROUP_ATTR), - BER_BVC(SLAPD_ROLE_CLASS), - BER_BVC(SLAPD_ROLE_ATTR), - - BER_BVC(SLAPD_ACI_SET_ATTR) -}; static AccessControl * slap_acl_get( AccessControl *ac, int *count, @@ -103,8 +67,9 @@ static int regex_matches( int nmatch, regmatch_t *matches); typedef struct AclSetCookie { - Operation *op; - Entry *e; + SetCookie asc_cookie; +#define asc_op asc_cookie.set_op + Entry *asc_e; } AclSetCookie; SLAP_SET_GATHER acl_set_gather; @@ -142,7 +107,8 @@ slap_access_always_allowed( { assert( maskp != NULL ); - ACL_PRIV_SET( *maskp, ACL_ACCESS2PRIV( access ) ); + /* assign all */ + ACL_LVL_ASSIGN_MANAGE( *maskp ); return 1; } @@ -181,6 +147,8 @@ slap_access_allowed( assert( attr != NULL ); + ACL_INIT( mask ); + /* grant database root access */ if ( be_isroot( op ) ) { Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 ); @@ -192,8 +160,13 @@ slap_access_allowed( * no-user-modification operational attributes are ignored * by ACL_WRITE checking as any found here are not provided * by the user + * + * NOTE: but they are not ignored for ACL_MANAGE, because + * if we get here it means a non-root user is trying to + * manage data, so we need to check its privileges. */ - if ( access_level >= ACL_WRITE && is_at_no_user_mod( desc->ad_type ) + if ( access_level == ACL_WRITE + && is_at_no_user_mod( desc->ad_type ) && desc != slap_schema.si_ad_entry && desc != slap_schema.si_ad_children ) { @@ -337,9 +310,10 @@ fe_access_allowed( */ be_orig = op->o_bd; - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); if ( op->o_bd == NULL ) { - op->o_bd = frontendDB; + op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); + if ( op->o_bd == NULL ) + op->o_bd = frontendDB; } rc = slap_access_allowed( op, e, desc, val, access, state, maskp ); op->o_bd = be_orig; @@ -384,10 +358,17 @@ access_allowed_mask( assert( attr != NULL ); - if ( op && op->o_is_auth_check && - ( access_level == ACL_SEARCH || access_level == ACL_READ ) ) - { - access = ACL_AUTH; + if ( op ) { + if ( op->o_is_auth_check && + ( access_level == ACL_SEARCH || access_level == ACL_READ ) ) + { + access = ACL_AUTH; + + } else if ( get_manageDIT( op ) && access_level == ACL_WRITE && + desc == slap_schema.si_ad_entry ) + { + access = ACL_MANAGE; + } } if ( state ) { @@ -443,14 +424,10 @@ access_allowed_mask( desc, val, access, state, &mask ); } else { - BackendDB *be_orig = op->o_bd; - /* use default (but pass through frontend * for global ACL overlays) */ - op->o_bd = frontendDB; ret = frontendDB->bd_info->bi_access_allowed( op, e, desc, val, access, state, &mask ); - op->o_bd = be_orig; } if ( !ret ) { @@ -528,10 +505,17 @@ access_allowed_mask( assert( attr != NULL ); - if ( op && op->o_is_auth_check && - ( access_level == ACL_SEARCH || access_level == ACL_READ ) ) - { - access = ACL_AUTH; + if ( op ) { + if ( op->o_is_auth_check && + ( access_level == ACL_SEARCH || access_level == ACL_READ ) ) + { + access = ACL_AUTH; + + } else if ( get_manageDIT( op ) && access_level == ACL_WRITE && + desc == slap_schema.si_ad_entry ) + { + access = ACL_MANAGE; + } } if ( state ) { @@ -595,8 +579,12 @@ access_allowed_mask( * no-user-modification operational attributes are ignored * by ACL_WRITE checking as any found here are not provided * by the user + * + * NOTE: but they are not ignored for ACL_MANAGE, because + * if we get here it means a non-root user is trying to + * manage data, so we need to check its privileges. */ - if ( access_level >= ACL_WRITE && is_at_no_user_mod( desc->ad_type ) + if ( access_level == ACL_WRITE && is_at_no_user_mod( desc->ad_type ) && desc != slap_schema.si_ad_entry && desc != slap_schema.si_ad_children ) { @@ -824,7 +812,8 @@ slap_acl_get( continue; } else if ( a->acl_dn_style == ACL_STYLE_ONE ) { - int rdnlen = -1, sep = 0; + ber_len_t rdnlen = 0; + int sep = 0; if ( dnlen <= patlen ) continue; @@ -896,7 +885,7 @@ slap_acl_get( if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) { if (value_match( &match, desc, - /* desc->ad_type->sat_equality */ a->acl_attrval_mr, 0, + a->acl_attrval_mr, 0, val, &a->acl_attrval, &text ) != LDAP_SUCCESS || match ) continue; @@ -915,7 +904,7 @@ slap_acl_get( continue; } else if ( a->acl_attrval_style == ACL_STYLE_ONE ) { - int rdnlen = -1; + ber_len_t rdnlen = 0; if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) ) continue; @@ -936,7 +925,7 @@ slap_acl_get( continue; } - if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen )) + if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ) ) continue; } } @@ -1159,7 +1148,7 @@ acl_mask_dn( } } else if ( b->a_style == ACL_STYLE_ONE ) { - int rdnlen = -1; + ber_len_t rdnlen = 0; if ( odnlen <= patlen ) { goto dn_match_cleanup; @@ -1170,7 +1159,7 @@ acl_mask_dn( } rdnlen = dn_rdnlen( NULL, opndn ); - if ( rdnlen != odnlen - patlen - 1 ) { + if ( rdnlen - ( odnlen - patlen - 1 ) != 0 ) { goto dn_match_cleanup; } @@ -1189,8 +1178,8 @@ acl_mask_dn( } } else if ( b->a_style == ACL_STYLE_LEVEL ) { - int level; - struct berval ndn; + int level = b->a_level; + struct berval ndn; if ( odnlen <= patlen ) { goto dn_match_cleanup; @@ -1201,7 +1190,6 @@ acl_mask_dn( goto dn_match_cleanup; } - level = b->a_level; ndn = *opndn; for ( ; level > 0; level-- ) { if ( BER_BVISEMPTY( &ndn ) ) { @@ -1368,9 +1356,6 @@ slap_acl_mask( Access *b; #ifdef LDAP_DEBUG char accessmaskbuf[ACCESSMASK_MAXLEN]; -#if !defined( SLAP_DYNACL ) && defined( SLAPD_ACI_ENABLED ) - char accessmaskbuf1[ACCESSMASK_MAXLEN]; -#endif /* !SLAP_DYNACL && SLAPD_ACI_ENABLED */ #endif /* DEBUG */ const char *attr; slap_mask_t a2pmask = ACL_ACCESS2PRIV( *mask ); @@ -1606,21 +1591,18 @@ slap_acl_mask( int port_number = -1; if ( strncasecmp( op->o_conn->c_peer_name.bv_val, - aci_bv[ ACI_BV_IP_EQ ].bv_val, - aci_bv[ ACI_BV_IP_EQ ].bv_len ) != 0 ) + acl_bv_ip_eq.bv_val, + acl_bv_ip_eq.bv_len ) != 0 ) continue; - ip.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv[ ACI_BV_IP_EQ ].bv_len; - ip.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv[ ACI_BV_IP_EQ ].bv_len; + ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len; + ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len; port = strrchr( ip.bv_val, ':' ); if ( port ) { - char *next; - ip.bv_len = port - ip.bv_val; ++port; - port_number = strtol( port, &next, 10 ); - if ( next[0] != '\0' ) + if ( lutil_atoi( &port_number, port ) != 0 ) continue; } @@ -1650,14 +1632,14 @@ slap_acl_mask( struct berval path; if ( strncmp( op->o_conn->c_peer_name.bv_val, - aci_bv[ ACI_BV_PATH_EQ ].bv_val, - aci_bv[ ACI_BV_PATH_EQ ].bv_len ) != 0 ) + acl_bv_path_eq.bv_val, + acl_bv_path_eq.bv_len ) != 0 ) continue; path.bv_val = op->o_conn->c_peer_name.bv_val - + aci_bv[ ACI_BV_PATH_EQ ].bv_len; + + acl_bv_path_eq.bv_len; path.bv_len = op->o_conn->c_peer_name.bv_len - - aci_bv[ ACI_BV_PATH_EQ ].bv_len; + - acl_bv_path_eq.bv_len; if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 ) continue; @@ -1896,7 +1878,7 @@ slap_acl_mask( bv = b->a_set_pat; } - if ( acl_match_set( &bv, op, e, 0 ) == 0 ) { + if ( acl_match_set( &bv, op, e, NULL ) == 0 ) { continue; } } @@ -1945,14 +1927,9 @@ slap_acl_mask( 0, 0, 0 ); /* this case works different from the others above. - * since aci's themselves give permissions, we need + * since dynamic ACL's themselves give permissions, we need * to first check b->a_access_mask, the ACL's access level. */ - if ( BER_BVISEMPTY( &e->e_nname ) ) { - /* no ACIs in the root DSE */ - continue; - } - /* first check if the right being requested * is allowed by the ACL clause. */ @@ -2010,6 +1987,8 @@ slap_acl_mask( } else #else /* !SLAP_DYNACL */ + /* NOTE: this entire block can be eliminated when SLAP_DYNACL + * moves outside of LDAP_DEVEL */ #ifdef SLAPD_ACI_ENABLED if ( b->a_aci_at != NULL ) { Attribute *at; @@ -2017,6 +1996,9 @@ slap_acl_mask( struct berval parent_ndn; BerVarray bvals = NULL; int ret, stop; +#ifdef LDAP_DEBUG + char accessmaskbuf1[ACCESSMASK_MAXLEN]; +#endif /* DEBUG */ Debug( LDAP_DEBUG_ACL, " <= check a_aci_at: %s\n", b->a_aci_at->ad_cname.bv_val, 0, 0 ); @@ -2237,8 +2219,7 @@ int acl_check_modlist( Operation *op, Entry *e, - Modifications *mlist -) + Modifications *mlist ) { struct berval *bv; AccessControlState state = ACL_STATE_INIT; @@ -2291,7 +2272,7 @@ acl_check_modlist( * by the user */ if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) - && !mlist->sml_managing ) + && ! ( mlist->sml_flags & SLAP_MOD_MANAGING ) ) { Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:" " modify access granted\n", @@ -2307,7 +2288,9 @@ acl_check_modlist( * This prevents abuse from selfwriters. */ if ( ! access_allowed( op, e, - mlist->sml_desc, NULL, ACL_WDEL, &state ) ) + mlist->sml_desc, NULL, + ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, + &state ) ) { ret = 0; goto done; @@ -2325,7 +2308,9 @@ acl_check_modlist( bv->bv_val != NULL; bv++ ) { if ( ! access_allowed( op, e, - mlist->sml_desc, bv, ACL_WADD, &state ) ) + mlist->sml_desc, bv, + ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WADD, + &state ) ) { ret = 0; goto done; @@ -2336,7 +2321,9 @@ acl_check_modlist( case LDAP_MOD_DELETE: if ( mlist->sml_values == NULL ) { if ( ! access_allowed( op, e, - mlist->sml_desc, NULL, ACL_WDEL, NULL ) ) + mlist->sml_desc, NULL, + ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, + NULL ) ) { ret = 0; goto done; @@ -2348,7 +2335,9 @@ acl_check_modlist( bv->bv_val != NULL; bv++ ) { if ( ! access_allowed( op, e, - mlist->sml_desc, bv, ACL_WDEL, &state ) ) + mlist->sml_desc, bv, + ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, + &state ) ) { ret = 0; goto done; @@ -2506,7 +2495,7 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de /* Grab the searchbase and see if an appropriate database can be found */ ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn ); rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn, - &op2.o_req_ndn, cp->op->o_tmpmemctx ); + &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); BER_BVZERO( &op2.o_req_dn ); if ( rc != LDAP_SUCCESS ) { goto url_done; @@ -2521,13 +2510,13 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de /* Grab the filter */ if ( ludp->lud_filter ) { ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr, - cp->op->o_tmpmemctx ); + cp->asc_op->o_tmpmemctx ); } else { op2.ors_filterstr = defaultFilter_bv; } - op2.ors_filter = str2filter_x( cp->op, op2.ors_filterstr.bv_val ); + op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val ); if ( op2.ors_filter == NULL ) { rc = LDAP_PROTOCOL_ERROR; goto url_done; @@ -2542,7 +2531,7 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de ; anlistp = slap_sl_malloc( sizeof( AttributeName ) * ( nattrs + 2 ), - cp->op->o_tmpmemctx ); + cp->asc_op->o_tmpmemctx ); for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) { ber_str2bv( ludp->lud_attrs[ nattrs ], 0, 0, &anlistp[ nattrs ].an_name ); @@ -2565,19 +2554,19 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de p.cookie = cookie; - op2.o_hdr = cp->op->o_hdr; + op2.o_hdr = cp->asc_op->o_hdr; op2.o_tag = LDAP_REQ_SEARCH; op2.o_ndn = op2.o_bd->be_rootndn; op2.o_callback = &cb; - op2.o_time = slap_get_time(); + slap_op_time( &op2.o_time, &op2.o_tincr ); op2.o_do_not_cache = 1; op2.o_is_auth_check = 0; - ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->op->o_tmpmemctx ); + ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); op2.ors_slimit = SLAP_NO_LIMIT; op2.ors_tlimit = SLAP_NO_LIMIT; op2.ors_attrs = anlistp; op2.ors_attrsonly = 0; - op2.o_private = cp->op->o_private; + op2.o_private = cp->asc_op->o_private; cb.sc_private = &p; @@ -2588,19 +2577,19 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de url_done:; if ( op2.ors_filter ) { - filter_free_x( cp->op, op2.ors_filter ); + filter_free_x( cp->asc_op, op2.ors_filter ); } if ( !BER_BVISNULL( &op2.o_req_ndn ) ) { - slap_sl_free( op2.o_req_ndn.bv_val, cp->op->o_tmpmemctx ); + slap_sl_free( op2.o_req_ndn.bv_val, cp->asc_op->o_tmpmemctx ); } if ( !BER_BVISNULL( &op2.o_req_dn ) ) { - slap_sl_free( op2.o_req_dn.bv_val, cp->op->o_tmpmemctx ); + slap_sl_free( op2.o_req_dn.bv_val, cp->asc_op->o_tmpmemctx ); } if ( ludp ) { ldap_free_urldesc( ludp ); } if ( anlistp && anlistp != anlist ) { - slap_sl_free( anlistp, cp->op->o_tmpmemctx ); + slap_sl_free( anlistp, cp->asc_op->o_tmpmemctx ); } return p.bvals; @@ -2618,22 +2607,22 @@ acl_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *d * plain strings, since syntax is not known. It should * also return the syntax or some "comparison cookie". */ - rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->op->o_tmpmemctx ); + rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->asc_op->o_tmpmemctx ); if ( rc == LDAP_SUCCESS ) { if ( desc == slap_schema.si_ad_entryDN ) { bvals = (BerVarray)slap_sl_malloc( sizeof( BerValue ) * 2, - cp->op->o_tmpmemctx ); + cp->asc_op->o_tmpmemctx ); bvals[ 0 ] = ndn; BER_BVZERO( &bvals[ 1 ] ); BER_BVZERO( &ndn ); } else { - backend_attribute( cp->op, - cp->e, &ndn, desc, &bvals, ACL_NONE ); + backend_attribute( cp->asc_op, + cp->asc_e, &ndn, desc, &bvals, ACL_NONE ); } if ( !BER_BVISNULL( &ndn ) ) { - slap_sl_free( ndn.bv_val, cp->op->o_tmpmemctx ); + slap_sl_free( ndn.bv_val, cp->asc_op->o_tmpmemctx ); } } @@ -2645,13 +2634,13 @@ acl_match_set ( struct berval *subj, Operation *op, Entry *e, - int setref ) + struct berval *default_set_attribute ) { struct berval set = BER_BVNULL; int rc = 0; AclSetCookie cookie; - if ( setref == 0 ) { + if ( default_set_attribute == NULL ) { ber_dupbv_x( &set, subj, op->o_tmpmemctx ); } else { @@ -2667,7 +2656,7 @@ acl_match_set ( } if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) { - setat = aci_bv[ ACI_BV_SET_ATTR ]; + setat = *default_set_attribute; } /* @@ -2695,9 +2684,11 @@ acl_match_set ( } if ( !BER_BVISNULL( &set ) ) { - cookie.op = op; - cookie.e = e; - rc = ( slap_set_filter( acl_set_gather, (SetCookie *)&cookie, &set, + cookie.asc_op = op; + cookie.asc_e = e; + rc = ( slap_set_filter( + acl_set_gather, + (SetCookie *)&cookie, &set, &op->o_ndn, &e->e_nname, NULL ) > 0 ); slap_sl_free( set.bv_val, op->o_tmpmemctx ); } @@ -2762,20 +2753,32 @@ slap_dynacl_get( const char *name ) } #endif /* SLAP_DYNACL */ +/* + * statically built-in dynamic ACL initialization + */ +static int (*acl_init_func[])( void ) = { +#ifdef SLAPD_ACI_ENABLED +#ifdef SLAP_DYNACL + dynacl_aci_init, +#else /* !SLAP_DYNACL */ + aci_init, +#endif /* !SLAP_DYNACL */ +#endif /* SLAPD_ACI_ENABLED */ + + NULL +}; + int acl_init( void ) { -#ifdef SLAP_DYNACL - int rc; + int i, rc; -#ifdef SLAPD_ACI_ENABLED - rc = dynacl_aci_init(); - if ( rc != 0 ) { - return rc; + for ( i = 0; acl_init_func[ i ] != NULL; i++ ) { + rc = (*(acl_init_func[ i ]))(); + if ( rc != 0 ) { + return rc; + } } -#endif /* SLAPD_ACI_ENABLED */ - -#endif /* SLAP_DYNACL */ return 0; }