/* $NetBSD: posixgroup.c,v 1.3 2021/08/14 16:14:50 christos Exp $ */
/* posixgroup.c */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 1998-2021 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* .
*/
#include
#include
#include
#include
/* Need dynacl... */
#ifdef SLAP_DYNACL
typedef struct pg_t {
slap_style_t pg_style;
struct berval pg_pat;
} pg_t;
static ObjectClass *pg_posixGroup;
static AttributeDescription *pg_memberUid;
static ObjectClass *pg_posixAccount;
static AttributeDescription *pg_uidNumber;
static int pg_dynacl_destroy( void *priv );
static int
pg_dynacl_parse(
const char *fname,
int lineno,
const char *opts,
slap_style_t style,
const char *pattern,
void **privp )
{
pg_t *pg;
int rc;
const char *text = NULL;
struct berval pat;
ber_str2bv( pattern, 0, 0, &pat );
pg = ch_calloc( 1, sizeof( pg_t ) );
pg->pg_style = style;
switch ( pg->pg_style ) {
case ACL_STYLE_BASE:
rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unable to normalize DN \"%s\".\n",
fname, lineno, pattern );
goto cleanup;
}
break;
case ACL_STYLE_EXPAND:
ber_dupbv( &pg->pg_pat, &pat );
break;
default:
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unsupported style \"%s\".\n",
fname, lineno, style_strings[ pg->pg_style ] );
goto cleanup;
}
/* TODO: use opts to allow the use of different
* group objects and member attributes */
if ( pg_posixGroup == NULL ) {
pg_posixGroup = oc_find( "posixGroup" );
if ( pg_posixGroup == NULL ) {
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unable to lookup \"posixGroup\" "
"objectClass.\n",
fname, lineno );
goto cleanup;
}
pg_posixAccount = oc_find( "posixAccount" );
if ( pg_posixGroup == NULL ) {
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unable to lookup \"posixAccount\" "
"objectClass.\n",
fname, lineno );
goto cleanup;
}
rc = slap_str2ad( "memberUid", &pg_memberUid, &text );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unable to lookup \"memberUid\" "
"attributeDescription (%d: %s).\n",
fname, lineno, rc, text );
goto cleanup;
}
rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "%s line %d: posixGroup ACL: "
"unable to lookup \"uidNumber\" "
"attributeDescription (%d: %s).\n",
fname, lineno, rc, text );
goto cleanup;
}
}
*privp = (void *)pg;
return 0;
cleanup:
(void)pg_dynacl_destroy( (void *)pg );
return 1;
}
static int
pg_dynacl_unparse(
void *priv,
struct berval *bv )
{
pg_t *pg = (pg_t *)priv;
char *ptr;
bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len;
bv->bv_val = ch_malloc( bv->bv_len + 1 );
ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" );
switch ( pg->pg_style ) {
case ACL_STYLE_BASE:
ptr = lutil_strcopy( ptr, ".exact=" );
break;
case ACL_STYLE_EXPAND:
ptr = lutil_strcopy( ptr, ".expand=" );
break;
default:
assert( 0 );
}
ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len );
ptr[ 0 ] = '\0';
bv->bv_len = ptr - bv->bv_val;
return 0;
}
static int
pg_dynacl_mask(
void *priv,
Operation *op,
Entry *target,
AttributeDescription *desc,
struct berval *val,
int nmatch,
regmatch_t *matches,
slap_access_t *grant,
slap_access_t *deny )
{
pg_t *pg = (pg_t *)priv;
Entry *group = NULL,
*user = NULL;
int rc;
Backend *be = op->o_bd,
*group_be = NULL,
*user_be = NULL;
struct berval group_ndn;
ACL_INVALIDATE( *deny );
/* get user */
if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) {
user = target;
rc = LDAP_SUCCESS;
} else {
user_be = op->o_bd = select_backend( &op->o_ndn, 0 );
if ( op->o_bd == NULL ) {
op->o_bd = be;
return 0;
}
rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user );
}
if ( rc != LDAP_SUCCESS || user == NULL ) {
op->o_bd = be;
return 0;
}
/* get target */
if ( pg->pg_style == ACL_STYLE_EXPAND ) {
char buf[ 1024 ];
struct berval bv;
AclRegexMatches amatches = { 0 };
amatches.dn_count = nmatch;
AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
if ( acl_string_expand( &bv, &pg->pg_pat,
&target->e_nname,
NULL, &amatches ) )
{
goto cleanup;
}
if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn,
op->o_tmpmemctx ) != LDAP_SUCCESS )
{
/* did not expand to a valid dn */
goto cleanup;
}
} else {
group_ndn = pg->pg_pat;
}
if ( target && dn_match( &target->e_nname, &group_ndn ) ) {
group = target;
rc = LDAP_SUCCESS;
} else {
group_be = op->o_bd = select_backend( &group_ndn, 0 );
if ( op->o_bd == NULL ) {
goto cleanup;
}
rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group );
}
if ( group_ndn.bv_val != pg->pg_pat.bv_val ) {
op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx );
}
if ( rc == LDAP_SUCCESS && group != NULL ) {
Attribute *a_uid,
*a_member;
a_uid = attr_find( user->e_attrs, pg_uidNumber );
if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) {
rc = LDAP_NO_SUCH_ATTRIBUTE;
} else {
a_member = attr_find( group->e_attrs, pg_memberUid );
if ( !a_member ) {
rc = LDAP_NO_SUCH_ATTRIBUTE;
} else {
rc = value_find_ex( pg_memberUid,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
a_member->a_nvals, &a_uid->a_nvals[ 0 ],
op->o_tmpmemctx );
}
}
} else {
rc = LDAP_NO_SUCH_OBJECT;
}
if ( rc == LDAP_SUCCESS ) {
ACL_LVL_ASSIGN_WRITE( *grant );
}
cleanup:;
if ( group != NULL && group != target ) {
op->o_bd = group_be;
be_entry_release_r( op, group );
op->o_bd = be;
}
if ( user != NULL && user != target ) {
op->o_bd = user_be;
be_entry_release_r( op, user );
op->o_bd = be;
}
return 0;
}
static int
pg_dynacl_destroy(
void *priv )
{
pg_t *pg = (pg_t *)priv;
if ( pg != NULL ) {
if ( !BER_BVISNULL( &pg->pg_pat ) ) {
ber_memfree( pg->pg_pat.bv_val );
}
ch_free( pg );
}
return 0;
}
static struct slap_dynacl_t pg_dynacl = {
"posixGroup",
pg_dynacl_parse,
pg_dynacl_unparse,
pg_dynacl_mask,
pg_dynacl_destroy
};
int
init_module( int argc, char *argv[] )
{
return slap_dynacl_register( &pg_dynacl );
}
#endif /* SLAP_DYNACL */