Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • openldap/openldap
  • hyc/openldap
  • ryan/openldap
  • iboukris/openldap
  • ondra/openldap
  • sshanks-kx/openldap
  • blaggacao/openldap
  • pbrezina/openldap
  • quanah/openldap
  • dragos_h/openldap
  • lorenz/openldap
  • tsaarni/openldap
  • fei.ding/openldap
  • orent/openldap
  • arrowplum/openldap
  • barchiesi/openldap
  • jotik/openldap
  • hamano/openldap
  • ingovoss/openldap
  • henson/openldap
  • jlrine2/openldap
  • howeverAT/openldap
  • nivanova/openldap
  • orbea/openldap
  • rdubner/openldap
  • smckinney/openldap
  • jklowden/openldap
  • dpa-openldap/openldap
  • rouzier/openldap
  • orgads/openldap
  • ffontaine/openldap
  • jiaqingz/openldap
  • dcoutadeur/openldap
  • begeragus/openldap
  • pubellit/openldap
  • glandium/openldap
  • facboy/openldap
  • thesamesam/openldap
  • Johan/openldap
  • fkooman/openldap
  • gburd/openldap
  • h-homma/openldap
  • sgallagher/openldap
  • ahmed_zaki/openldap
  • gnoe/openldap
  • mid/openldap
  • clan/openldap
47 results
Show changes
Showing
with 2633 additions and 796 deletions
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -259,7 +259,7 @@ rewrite_xmap_apply(
ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
rc = REWRITE_NO_SUCH_OBJECT;
rc = LDAP_NO_SUCH_OBJECT;
break;
}
......
# servers Makefile.in for OpenLDAP
# $OpenLDAP$
## Copyright 1998-2004 The OpenLDAP Foundation.
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2005 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
......
......@@ -2,7 +2,7 @@
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2004 The OpenLDAP Foundation.
## Copyright 1998-2005 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
......@@ -23,7 +23,7 @@ SUBDIRS=back-* shell-backends slapi overlays
NT_SRCS = nt_svc.c
NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res
SRCS = main.c globals.c config.c daemon.c \
SRCS = main.c globals.c bconfig.c config.c daemon.c \
connection.c search.c filter.c add.c cr.c \
attr.c entry.c backend.c result.c operation.c \
dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \
......@@ -35,14 +35,14 @@ SRCS = main.c globals.c config.c daemon.c \
oidm.c starttls.c index.c sets.c referral.c root_dse.c \
sasl.c module.c mra.c mods.c sl_malloc.c zn_malloc.c limits.c \
operational.c matchedValues.c cancel.c syncrepl.c \
backover.c ctxcsn.c ldapsync.c sessionlog.c frontend.c \
backover.c ctxcsn.c ldapsync.c frontend.c \
slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \
slappasswd.c slaptest.c slapauth.c slapacl.c component.c \
$(@PLAT@_SRCS)
OBJS = main.o globals.o config.o daemon.o \
OBJS = main.o globals.o bconfig.o config.o daemon.o \
connection.o search.o filter.o add.o cr.o \
attr.o entry.o backend.o result.o operation.o \
attr.o entry.o backend.o backends.o result.o operation.o \
dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \
value.o ava.o bind.o unbind.o abandon.o filterentry.o \
phonetic.o acl.o str2filter.o aclparse.o init.o user.o \
......@@ -52,16 +52,16 @@ OBJS = main.o globals.o config.o daemon.o \
oidm.o starttls.o index.o sets.o referral.o root_dse.o \
sasl.o module.o mra.o mods.o sl_malloc.o zn_malloc.o limits.o \
operational.o matchedValues.o cancel.o syncrepl.o \
backover.o ctxcsn.o ldapsync.o sessionlog.o frontend.o \
backover.o ctxcsn.o ldapsync.o frontend.o \
slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \
slappasswd.o slaptest.o slapauth.o slapacl.o component.o \
$(@PLAT@_OBJS)
LDAP_INCDIR= ../../include -I$(srcdir)/slapi -I.
LDAP_INCDIR= ../../include -I$(srcdir) -I$(srcdir)/slapi -I.
LDAP_LIBDIR= ../../libraries
SLAP_DIR=
SLAPD_STATIC_DEPENDS=@SLAPD_NO_STATIC@ libbackends.a
SLAPD_STATIC_DEPENDS=@SLAPD_NO_STATIC@ libbackends.a liboverlays.a
SLAPD_STATIC_BACKENDS=@SLAPD_STATIC_BACKENDS@
SLAPD_DYNAMIC_BACKENDS=@SLAPD_DYNAMIC_BACKENDS@
......@@ -70,7 +70,7 @@ SLAPI_LIBS=@LIBSLAPI@ @SLAPI_LIBS@
XDEFS = $(MODULES_CPPFLAGS)
XLDFLAGS = $(MODULES_LDFLAGS)
XLIBS = $(SLAPD_STATIC_DEPENDS) $(SLAPD_L) liboverlays.a
XLIBS = $(SLAPD_STATIC_DEPENDS) $(SLAPD_L)
XXLIBS = $(SLAPD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS)
XXXLIBS = $(LTHREAD_LIBS) $(SLAPI_LIBS) $(MODULES_LIBS)
......@@ -85,7 +85,7 @@ NT_SLAPD_OBJECTS = slapd.exp symdummy.o $(OBJS) version.o
UNIX_SLAPD_DEPENDS = $(SLAPD_STATIC_DEPENDS) version.o $(SLAPD_L)
UNIX_SLAPD_OBJECTS = $(OBJS) version.o
SLAPD_DEPENDS = liboverlays.a $(@PLAT@_SLAPD_DEPENDS)
SLAPD_DEPENDS = $(@PLAT@_SLAPD_DEPENDS)
SLAPD_OBJECTS = $(@PLAT@_SLAPD_OBJECTS)
# Notes about slapd for Windows
......@@ -189,6 +189,13 @@ slapd.def: libbackends.a liboverlays.a version.o
done; \
test -z "$$obj" && continue; \
;; \
*.la) \
if test -n "$LTSTATIC"; then \
base=`expr "$$i" : ".*/\(.*\).la"`; \
path=`expr "$$i" : "\(.*/\).*"`; \
obj=$$path.libs/$$base.a; \
fi; \
;; \
*.o | *.a) \
obj=$$i; \
esac; \
......@@ -269,6 +276,9 @@ dummy $(SLAPD_DYNAMIC_BACKENDS): slapd
cd $@; $(MAKE) $(MFLAGS) all
@touch $@
dynamic_overlays: slapd
cd overlays; $(MAKE) $(MFLAGS) dynamic
#
# In Windows, dynamic backends have to be built after slapd. For this
# reason, we only build static backends now and dynamic backends later.
......@@ -311,9 +321,7 @@ libbackends.a: .backend
@ls -l libbackends.a; echo ""
liboverlays.a: FORCE
@cd overlays; $(MAKE) $(MFLAGS) all
backend.c: backend.h
cd overlays; $(MAKE) $(MFLAGS) static
version.c: Makefile
@-$(RM) $@
......@@ -321,6 +329,8 @@ version.c: Makefile
version.o: version.c $(OBJS) $(SLAPD_LIBDEPEND)
backends.o: backends.c $(srcdir)/slap.h
depend-local-srv: FORCE
@for i in $(SUBDIRS); do \
if test -d $$i -a -f $$i/Makefile ; then \
......@@ -334,6 +344,9 @@ depend-local-srv: FORCE
clean-local:
$(RM) *.exp *.def *.base *.a *.objs symdummy.c
veryclean-local:
$(RM) backends.c
clean-local-srv: FORCE
@for i in $(SUBDIRS); do \
if test -d $$i -a -f $$i/Makefile ; then \
......@@ -358,7 +371,7 @@ install-local-srv: install-slapd install-tools \
install-slapd: FORCE
-$(MKDIR) $(DESTDIR)$(libexecdir)
-$(MKDIR) $(DESTDIR)$(localstatedir)/run
$(LTINSTALL) $(INSTALLFLAGS) -s -m 755 \
$(LTINSTALL) $(INSTALLFLAGS) $(STRIP) -m 755 \
slapd$(EXEEXT) $(DESTDIR)$(libexecdir)
@for i in $(SUBDIRS); do \
if test -d $$i -a -f $$i/Makefile ; then \
......@@ -368,7 +381,7 @@ install-slapd: FORCE
fi; \
done
all-cffiles: slapd $(SLAPD_DYNAMIC_BACKENDS)
all-cffiles: slapd $(SLAPD_DYNAMIC_BACKENDS) dynamic_overlays
@if test $(PLAT) = NT; then \
sysconfdir=`cygpath -w $(sysconfdir) | \
$(SED) -e 's/\\\\/\\\\\\\\\\\\\\\\/g'`; \
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -75,27 +75,29 @@ do_abandon( Operation *op, SlapReply *rs )
LDAP_STAILQ_FOREACH( o, &op->o_conn->c_ops, o_next ) {
if ( o->o_msgid == id ) {
o->o_abandon = 1;
goto done;
break;
}
}
LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) {
if ( o->o_msgid == id ) {
LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops,
o, slap_op, o_next );
LDAP_STAILQ_NEXT(o, o_next) = NULL;
op->o_conn->c_n_ops_pending--;
slap_op_free( o );
goto done;
if ( o ) {
op->orn_msgid = id;
op->o_bd = frontendDB;
rs->sr_err = frontendDB->be_abandon( op, rs );
} else {
LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) {
if ( o->o_msgid == id ) {
LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops,
o, slap_op, o_next );
LDAP_STAILQ_NEXT(o, o_next) = NULL;
op->o_conn->c_n_ops_pending--;
slap_op_free( o );
break;
}
}
}
done:
op->orn_msgid = id;
op->o_bd = frontendDB;
rs->sr_err = frontendDB->be_abandon( op, rs );
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n",
......@@ -106,10 +108,7 @@ done:
int
fe_op_abandon( Operation *op, SlapReply *rs )
{
int i;
for ( i = 0; i < nbackends; i++ ) {
op->o_bd = &backends[i];
LDAP_STAILQ_FOREACH( op->o_bd, &backendDB, be_next ) {
if ( op->o_bd->be_abandon ) {
(void)op->o_bd->be_abandon( op, rs );
}
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -35,6 +35,7 @@
#include "slap.h"
#include "sets.h"
#include "lber_pvt.h"
#include "lutil.h"
#ifdef LDAP_SLAPI
#include "slapi/slapi.h"
......@@ -53,7 +54,9 @@ static struct berval
aci_bv_br_entry = BER_BVC("[entry]"),
aci_bv_br_all = BER_BVC("[all]"),
aci_bv_access_id = BER_BVC("access-id"),
#if 0
aci_bv_anonymous = BER_BVC("anonymous"),
#endif
aci_bv_public = BER_BVC("public"),
aci_bv_users = BER_BVC("users"),
aci_bv_self = BER_BVC("self"),
......@@ -68,7 +71,9 @@ static struct berval
aci_bv_ip_eq = BER_BVC("IP="),
#ifdef LDAP_PF_LOCAL
aci_bv_path_eq = BER_BVC("PATH="),
#if 0
aci_bv_dirsep = BER_BVC(LDAP_DIRSEP),
#endif
#endif /* LDAP_PF_LOCAL */
aci_bv_group_class = BER_BVC(SLAPD_GROUP_CLASS),
......@@ -112,7 +117,7 @@ static int aci_mask(
slap_access_t *grant,
slap_access_t *deny,
slap_aci_scope_t scope);
#endif
#endif /* SLAPD_ACI_ENABLED */
static int regex_matches(
struct berval *pat, char *str, char *buf,
......@@ -150,6 +155,340 @@ static int aci_match_set ( struct berval *subj, Operation *op,
* - can be legally called with op->o_bd == NULL
*/
#ifdef SLAP_OVERLAY_ACCESS
int
slap_access_always_allowed(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
assert( maskp );
ACL_PRIV_SET( *maskp, ACL_ACCESS2PRIV( access ) );
return 1;
}
int
slap_access_allowed(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
int ret = 1;
int count;
AccessControl *a = NULL;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
#endif
slap_mask_t mask;
slap_control_t control;
slap_access_t access_level;
const char *attr;
regmatch_t matches[MAXREMATCHES];
int st_same_attr = 0;
assert( op != NULL );
assert( e != NULL );
assert( desc != NULL );
assert( maskp != NULL );
access_level = ACL_LEVEL( access );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
#ifdef LDAP_SLAPI
if ( op->o_pb != NULL ) {
ret = slapi_int_access_allowed( op, e, desc, val, access, state );
if ( ret == 0 ) {
/* ACL plugin denied access */
goto done;
}
}
#endif /* LDAP_SLAPI */
/* grant database root access */
if ( be_isroot( op ) ) {
Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 );
mask = ACL_LVL_MANAGE;
goto done;
}
/*
* no-user-modification operational attributes are ignored
* by ACL_WRITE checking as any found here are not provided
* by the user
*/
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 )
{
Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
" %s access granted\n",
attr, 0, 0 );
goto done;
}
/* use backend default access if no backend acls */
if ( op->o_bd->be_acl == NULL ) {
int i;
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: backend default %s "
"access %s to \"%s\"\n",
access2str( access ),
op->o_bd->be_dfltaccess >= access_level ? "granted" : "denied",
op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
ret = op->o_bd->be_dfltaccess >= access_level;
mask = ACL_PRIV_LEVEL;
for ( i = ACL_NONE; i <= op->o_bd->be_dfltaccess; i++ ) {
ACL_PRIV_SET( mask, ACL_ACCESS2PRIV( i ) );
}
goto done;
}
ret = 0;
control = ACL_BREAK;
if ( st_same_attr ) {
assert( state->as_vd_acl != NULL );
a = state->as_vd_acl;
count = state->as_vd_acl_count;
if ( !ACL_IS_INVALID( state->as_vd_acl_mask ) ) {
mask = state->as_vd_acl_mask;
AC_MEMCPY( matches, state->as_vd_acl_matches, sizeof(matches) );
goto vd_access;
}
} else {
if ( state ) state->as_vi_acl = NULL;
a = NULL;
ACL_PRIV_ASSIGN( mask, *maskp );
count = 0;
memset( matches, '\0', sizeof( matches ) );
}
while ( ( a = acl_get( a, &count, op, e, desc, val,
MAXREMATCHES, matches, state ) ) != NULL )
{
int i;
for ( i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++ ) {
Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
(int)matches[i].rm_so, (int)matches[i].rm_eo );
if ( matches[i].rm_so <= matches[0].rm_eo ) {
int n;
for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++ ) {
Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
}
}
Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
}
if ( state ) {
if ( state->as_vi_acl == a &&
( state->as_recorded & ACL_STATE_RECORDED_NV ) )
{
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: result from state (%s)\n",
attr, 0, 0 );
ret = state->as_result;
goto done;
} else {
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: no res from state (%s)\n",
attr, 0, 0 );
}
}
vd_access:
control = acl_mask( a, &mask, op,
e, desc, val, MAXREMATCHES, matches, count, state );
if ( control != ACL_BREAK ) {
break;
}
memset( matches, '\0', sizeof( matches ) );
}
if ( ACL_IS_INVALID( mask ) ) {
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: \"%s\" (%s) invalid!\n",
e->e_dn, attr, 0 );
ACL_PRIV_ASSIGN( mask, *maskp );
} else if ( control == ACL_BREAK ) {
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: no more rules\n", 0, 0, 0 );
goto done;
}
ret = ACL_GRANT( mask, access );
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: %s access %s by %s\n",
access2str( access ), ret ? "granted" : "denied",
accessmask2str( mask, accessmaskbuf, 1 ) );
done:
ACL_PRIV_ASSIGN( *maskp, mask );
return ret;
}
int
access_allowed_mask(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
int ret = 1;
AccessControl *a = NULL;
int be_null = 0;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
#endif
slap_mask_t mask;
slap_control_t control;
slap_access_t access_level;
const char *attr;
int st_same_attr = 0;
static AccessControlState state_init = ACL_STATE_INIT;
BI_access_allowed *bi_access_allowed = NULL;
assert( e != NULL );
assert( desc != NULL );
access_level = ACL_LEVEL( access );
assert( access_level > ACL_NONE );
ACL_INIT( mask );
if ( maskp ) ACL_INVALIDATE( *maskp );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
if ( op && op->o_is_auth_check &&
( access_level == ACL_SEARCH || access_level == ACL_READ ) )
{
access = ACL_AUTH;
}
if ( state ) {
if ( state->as_vd_ad == desc ) {
if ( state->as_recorded ) {
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
}
}
st_same_attr = 1;
} else {
*state = state_init;
}
state->as_vd_ad = desc;
}
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
access2str( access ), e->e_dn, attr );
if ( op == NULL ) {
/* no-op call */
goto done;
}
if ( op->o_bd == NULL ) {
op->o_bd = LDAP_STAILQ_FIRST( &backendDB );
be_null = 1;
#ifdef LDAP_DEVEL
/*
* FIXME: experimental; use first backend rules
* iff there is no global_acl (ITS#3100) */
if ( frontendDB->be_acl != NULL ) {
op->o_bd = frontendDB;
}
#endif /* LDAP_DEVEL */
}
assert( op->o_bd != NULL );
/* this is enforced in backend_add() */
if ( op->o_bd->bd_info->bi_access_allowed ) {
/* delegate to backend */
ret = op->o_bd->bd_info->bi_access_allowed( op, e, desc, val, access, state, &mask );
} else {
/* use default */
ret = slap_access_allowed( op, e, desc, val, access, state, &mask );
}
if ( !ret ) {
if ( ACL_IS_INVALID( mask ) ) {
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: \"%s\" (%s) invalid!\n",
e->e_dn, attr, 0 );
ACL_INIT( mask );
} else if ( control == ACL_BREAK ) {
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: no more rules\n", 0, 0, 0 );
goto done;
}
ret = ACL_GRANT( mask, access );
}
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: %s access %s by %s\n",
access2str( access ), ret ? "granted" : "denied",
accessmask2str( mask, accessmaskbuf, 1 ) );
done:
if ( state != NULL ) {
/* If not value-dependent, save ACL in case of more attrs */
if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) {
state->as_vi_acl = a;
state->as_result = ret;
}
state->as_recorded |= ACL_STATE_RECORDED;
}
if ( be_null ) op->o_bd = NULL;
if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask );
return ret;
}
#else /* !SLAP_OVERLAY_ACCESS */
int
access_allowed_mask(
Operation *op,
......@@ -163,42 +502,47 @@ access_allowed_mask(
int ret = 1;
int count;
AccessControl *a = NULL;
Backend *be;
int be_null = 0;
Backend *be;
int be_null = 0;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
char accessmaskbuf[ACCESSMASK_MAXLEN];
#endif
slap_mask_t mask;
slap_control_t control;
const char *attr;
regmatch_t matches[MAXREMATCHES];
int st_same_attr = 0;
static AccessControlState state_init = ACL_STATE_INIT;
slap_mask_t mask;
slap_control_t control;
slap_access_t access_level;
const char *attr;
regmatch_t matches[MAXREMATCHES];
int st_same_attr = 0;
static AccessControlState state_init = ACL_STATE_INIT;
assert( e != NULL );
assert( desc != NULL );
assert( access > ACL_NONE );
access_level = ACL_LEVEL( access );
assert( access_level > ACL_NONE );
if ( maskp ) ACL_INVALIDATE( *maskp );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
if( op && op->o_is_auth_check &&
( access == ACL_SEARCH || access == ACL_READ ))
if ( op && op->o_is_auth_check &&
( access_level == ACL_SEARCH || access_level == ACL_READ ) )
{
access = ACL_AUTH;
}
if( state ) {
if ( state->as_vd_ad==desc) {
if ( state ) {
if ( state->as_vd_ad == desc ) {
if ( state->as_recorded ) {
if( state->as_recorded & ACL_STATE_RECORDED_NV &&
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
} else if ( state->as_recorded & ACL_STATE_RECORDED_VD &&
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
......@@ -214,7 +558,7 @@ access_allowed_mask(
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
access2str( access ), e->e_dn, attr );
access2str( access ), e->e_dn, attr );
if ( op == NULL ) {
/* no-op call */
......@@ -223,7 +567,7 @@ access_allowed_mask(
be = op->o_bd;
if ( be == NULL ) {
be = &backends[0];
be = LDAP_STAILQ_FIRST(&backendDB);
be_null = 1;
#ifdef LDAP_DEVEL
/*
......@@ -248,12 +592,10 @@ access_allowed_mask(
#endif /* LDAP_SLAPI */
/* grant database root access */
if ( be != NULL && be_isroot( op ) ) {
Debug( LDAP_DEBUG_ACL,
"<= root access granted\n",
0, 0, 0 );
if ( be_isroot( op ) ) {
Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 );
if ( maskp ) {
mask = ACL_LVL_WRITE;
mask = ACL_LVL_MANAGE;
}
goto done;
......@@ -264,7 +606,7 @@ access_allowed_mask(
* by ACL_WRITE checking as any found here are not provided
* by the user
*/
if ( access >= 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 )
{
......@@ -275,13 +617,14 @@ access_allowed_mask(
}
/* use backend default access if no backend acls */
if( be != NULL && be->be_acl == NULL ) {
if ( be->be_acl == NULL ) {
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: backend default %s access %s to \"%s\"\n",
"=> access_allowed: backend default %s "
"access %s to \"%s\"\n",
access2str( access ),
be->be_dfltaccess >= access ? "granted" : "denied",
be->be_dfltaccess >= access_level ? "granted" : "denied",
op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
ret = be->be_dfltaccess >= access;
ret = be->be_dfltaccess >= access_level;
if ( maskp ) {
int i;
......@@ -301,8 +644,9 @@ access_allowed_mask(
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: global default %s access %s to \"%s\"\n",
access2str( access ),
frontendDB->be_dfltaccess >= access ? "granted" : "denied", op->o_dn.bv_val );
ret = frontendDB->be_dfltaccess >= access;
frontendDB->be_dfltaccess >= access_level ?
"granted" : "denied", op->o_dn.bv_val );
ret = frontendDB->be_dfltaccess >= access_level;
if ( maskp ) {
int i;
......@@ -320,12 +664,12 @@ access_allowed_mask(
ret = 0;
control = ACL_BREAK;
if( st_same_attr ) {
if ( st_same_attr ) {
assert( state->as_vd_acl != NULL );
a = state->as_vd_acl;
count = state->as_vd_acl_count;
if ( !ACL_IS_INVALID( state->as_vd_acl_mask )) {
if ( !ACL_IS_INVALID( state->as_vd_acl_mask ) ) {
mask = state->as_vd_acl_mask;
AC_MEMCPY( matches, state->as_vd_acl_matches, sizeof(matches) );
goto vd_access;
......@@ -336,33 +680,39 @@ access_allowed_mask(
a = NULL;
ACL_INIT(mask);
count = 0;
memset(matches, '\0', sizeof(matches));
memset( matches, '\0', sizeof(matches) );
}
while((a = acl_get( a, &count, op, e, desc, val,
MAXREMATCHES, matches, state )) != NULL)
while ( ( a = acl_get( a, &count, op, e, desc, val,
MAXREMATCHES, matches, state ) ) != NULL )
{
int i;
for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
for ( i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++ ) {
Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
(int)matches[i].rm_so, (int)matches[i].rm_eo );
if( matches[i].rm_so <= matches[0].rm_eo ) {
(int)matches[i].rm_so, (int)matches[i].rm_eo );
if ( matches[i].rm_so <= matches[0].rm_eo ) {
int n;
for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++ ) {
Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
}
}
Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
}
if (state) {
if (state->as_vi_acl == a && (state->as_recorded & ACL_STATE_RECORDED_NV)) {
Debug( LDAP_DEBUG_ACL, "access_allowed: result from state (%s)\n", attr, 0, 0 );
if ( state ) {
if ( state->as_vi_acl == a &&
( state->as_recorded & ACL_STATE_RECORDED_NV ) )
{
Debug( LDAP_DEBUG_ACL,
"access_allowed: result from state (%s)\n",
attr, 0, 0 );
ret = state->as_result;
goto done;
} else {
Debug( LDAP_DEBUG_ACL, "access_allowed: no res from state (%s)\n", attr, 0, 0);
Debug( LDAP_DEBUG_ACL,
"access_allowed: no res from state (%s)\n",
attr, 0, 0 );
}
}
......@@ -374,7 +724,7 @@ vd_access:
break;
}
memset(matches, '\0', sizeof(matches));
memset( matches, '\0', sizeof(matches) );
}
if ( ACL_IS_INVALID( mask ) ) {
......@@ -385,7 +735,7 @@ vd_access:
} else if ( control == ACL_BREAK ) {
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: no more rules\n", 0, 0, 0);
"=> access_allowed: no more rules\n", 0, 0, 0 );
goto done;
}
......@@ -394,24 +744,25 @@ vd_access:
"=> access_allowed: %s access %s by %s\n",
access2str( access ),
ACL_GRANT(mask, access) ? "granted" : "denied",
accessmask2str( mask, accessmaskbuf ) );
accessmask2str( mask, accessmaskbuf, 1 ) );
ret = ACL_GRANT(mask, access);
done:
if( state != NULL ) {
if ( state != NULL ) {
/* If not value-dependent, save ACL in case of more attrs */
if ( !(state->as_recorded & ACL_STATE_RECORDED_VD) ) {
if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) {
state->as_vi_acl = a;
state->as_result = ret;
}
state->as_recorded |= ACL_STATE_RECORDED;
}
if (be_null) op->o_bd = NULL;
if ( be_null ) op->o_bd = NULL;
if ( maskp ) *maskp = mask;
return ret;
}
#endif /* SLAP_OVERLAY_ACCESS */
/*
* acl_get - return the acl applicable to entry e, attribute
......@@ -541,8 +892,11 @@ acl_get(
Debug( LDAP_DEBUG_ACL,
"acl_get: valpat %s\n",
a->acl_attrval.bv_val, 0, 0 );
if (regexec(&a->acl_attrval_re, val->bv_val, 0, NULL, 0))
if ( regexec( &a->acl_attrval_re, val->bv_val, 0, NULL, 0 ) )
{
continue;
}
} else {
int match = 0;
const char *text;
......@@ -566,11 +920,11 @@ acl_get(
if ( vdnlen < patlen )
continue;
if ( a->acl_dn_style == ACL_STYLE_BASE ) {
if ( a->acl_attrval_style == ACL_STYLE_BASE ) {
if ( vdnlen > patlen )
continue;
} else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
} else if ( a->acl_attrval_style == ACL_STYLE_ONE ) {
int rdnlen = -1;
if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
......@@ -580,11 +934,11 @@ acl_get(
if ( rdnlen != vdnlen - patlen - 1 )
continue;
} else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
} else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) {
if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
continue;
} else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
} else if ( a->acl_attrval_style == ACL_STYLE_CHILDREN ) {
if ( vdnlen <= patlen )
continue;
......@@ -598,20 +952,295 @@ acl_get(
}
}
if ( a->acl_filter != NULL ) {
ber_int_t rc = test_filter( NULL, e, a->acl_filter );
if ( rc != LDAP_COMPARE_TRUE ) {
continue;
if ( a->acl_filter != NULL ) {
ber_int_t rc = test_filter( NULL, e, a->acl_filter );
if ( rc != LDAP_COMPARE_TRUE ) {
continue;
}
}
Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
*count, attr, 0);
return a;
}
Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
return( NULL );
}
static int
acl_mask_dn(
Operation *op,
Entry *e,
AccessControl *a,
int nmatch,
regmatch_t *matches,
slap_dn_access *b,
struct berval *opndn )
{
/*
* if access applies to the entry itself, and the
* user is bound as somebody in the same namespace as
* the entry, OR the given dn matches the dn pattern
*/
/*
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
* is maintaned in a_dn_pat.
*/
if ( b->a_style == ACL_STYLE_ANONYMOUS ) {
if ( !BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( b->a_style == ACL_STYLE_USERS ) {
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( b->a_style == ACL_STYLE_SELF ) {
struct berval ndn, selfndn;
int level;
if ( BER_BVISEMPTY( opndn ) || BER_BVISNULL( &e->e_nname ) ) {
return 1;
}
level = b->a_self_level;
if ( level < 0 ) {
selfndn = *opndn;
ndn = e->e_nname;
level = -level;
} else {
ndn = *opndn;
selfndn = e->e_nname;
}
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
break;
}
dnParent( &ndn, &ndn );
}
if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) )
{
return 1;
}
} else if ( b->a_style == ACL_STYLE_REGEX ) {
if ( !ber_bvccmp( &b->a_pat, '*' ) ) {
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( !regex_matches( &b->a_pat, opndn->bv_val,
e->e_ndn, tmp_nmatch, tmp_matchesp ) )
{
return 1;
}
}
} else {
struct berval pat;
ber_len_t patlen, odnlen;
int got_match = 0;
if ( e->e_dn == NULL )
return 1;
if ( b->a_expand ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( string_expand( &bv, &b->a_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
return 1;
}
if ( dnNormalize(0, NULL, NULL, &bv,
&pat, op->o_tmpmemctx )
!= LDAP_SUCCESS )
{
/* did not expand to a valid dn */
return 1;
}
} else {
pat = b->a_pat;
}
patlen = pat.bv_len;
odnlen = opndn->bv_len;
if ( odnlen < patlen ) {
goto dn_match_cleanup;
}
if ( b->a_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_ONE ) {
int rdnlen = -1;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
rdnlen = dn_rdnlen( NULL, opndn );
if ( rdnlen != odnlen - patlen - 1 ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_SUBTREE ) {
if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_CHILDREN ) {
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_LEVEL ) {
int level;
struct berval ndn;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( level > 0 && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) )
{
goto dn_match_cleanup;
}
level = b->a_level;
ndn = *opndn;
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
goto dn_match_cleanup;
}
dnParent( &ndn, &ndn );
if ( ndn.bv_len < patlen ) {
goto dn_match_cleanup;
}
}
if ( ndn.bv_len != patlen ) {
goto dn_match_cleanup;
}
}
Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
*count, attr, 0);
return a;
got_match = !strcmp( pat.bv_val, &opndn->bv_val[ odnlen - patlen ] );
dn_match_cleanup:;
if ( pat.bv_val != b->a_pat.bv_val ) {
slap_sl_free( pat.bv_val, op->o_tmpmemctx );
}
if ( !got_match ) {
return 1;
}
}
Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
return( NULL );
return 0;
}
/*
......@@ -629,6 +1258,100 @@ acl_get(
} \
} while( 0 )
static int
acl_mask_dnattr(
Operation *op,
Entry *e,
struct berval *val,
AccessControl *a,
Access *b,
int i,
regmatch_t *matches,
int count,
AccessControlState *state,
slap_dn_access *bdn,
struct berval *opndn )
{
Attribute *at;
struct berval bv;
int rc, match = 0;
const char *text;
const char *attr = bdn->a_at->ad_cname.bv_val;
assert( attr != NULL );
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n", attr, 0, 0 );
bv = *opndn;
/* see if asker is listed in dnattr */
for ( at = attrs_find( e->e_attrs, bdn->a_at );
at != NULL;
at = attrs_find( at->a_next, bdn->a_at ) )
{
if ( value_find_ex( bdn->a_at,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
at->a_nvals,
&bv, op->o_tmpmemctx ) == 0 )
{
/* found it */
match = 1;
break;
}
}
if ( match ) {
/* have a dnattr match. if this is a self clause then
* the target must also match the op dn.
*/
if ( bdn->a_self ) {
/* check if the target is an attribute. */
if ( val == NULL ) return 1;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, bdn->a_at,
bdn->a_at->ad_type->sat_equality, 0,
val, &bv, &text );
/* on match error or no match, fail the ACL clause */
if ( rc != LDAP_SUCCESS || match != 0 )
return 1;
}
} else {
/* no dnattr match, check if this is a self clause */
if ( ! bdn->a_self )
return 1;
ACL_RECORD_VALUE_STATE;
/* this is a self clause, check if the target is an
* attribute.
*/
if ( val == NULL )
return 1;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, bdn->a_at,
bdn->a_at->ad_type->sat_equality, 0,
val, &bv, &text );
/* on match error or no match, fail the ACL clause */
if ( rc != LDAP_SUCCESS || match != 0 )
return 1;
}
return 0;
}
/*
* acl_mask - modifies mask based upon the given acl and the
* requested access to entry e, attribute attr, value val. if val
......@@ -651,12 +1374,14 @@ acl_mask(
int count,
AccessControlState *state )
{
int i, odnlen, patlen;
int i;
Access *b;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
#if !defined( SLAP_DYNACL ) && defined( SLAPD_ACI_ENABLED )
char accessmaskbuf1[ACCESSMASK_MAXLEN];
#endif
#endif /* !SLAP_DYNACL && SLAPD_ACI_ENABLED */
#endif /* DEBUG */
const char *attr;
assert( a != NULL );
......@@ -675,7 +1400,7 @@ acl_mask(
"=> acl_mask: to %s by \"%s\", (%s) \n",
val ? "value" : "all values",
op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
accessmask2str( *mask, accessmaskbuf ) );
accessmask2str( *mask, accessmaskbuf, 1 ) );
if( state && ( state->as_recorded & ACL_STATE_RECORDED_VD )
......@@ -709,204 +1434,42 @@ acl_mask(
* value is set in a_dn_style; however, the string
* is maintaned in a_dn_pat.
*/
if ( b->a_dn_style == ACL_STYLE_ANONYMOUS ) {
if ( op->o_ndn.bv_len != 0 ) {
continue;
}
} else if ( b->a_dn_style == ACL_STYLE_USERS ) {
if ( op->o_ndn.bv_len == 0 ) {
continue;
}
} else if ( b->a_dn_style == ACL_STYLE_SELF ) {
if ( op->o_ndn.bv_len == 0 ) {
continue;
}
if ( e->e_dn == NULL || !dn_match( &e->e_nname, &op->o_ndn ) ) {
continue;
}
} else if ( b->a_dn_style == ACL_STYLE_REGEX ) {
if ( !ber_bvccmp( &b->a_dn_pat, '*' ) ) {
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( acl_mask_dn( op, e, a, nmatch, matches,
&b->a_dn, &op->o_ndn ) )
{
continue;
}
}
if ( rc ) {
continue;
}
if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
struct berval ndn;
if ( !regex_matches( &b->a_dn_pat,
op->o_ndn.bv_val, e->e_ndn,
tmp_nmatch, tmp_matchesp ) )
{
continue;
}
}
Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n",
b->a_realdn_pat.bv_val, 0, 0);
/*
* if access applies to the entry itself, and the
* user is bound as somebody in the same namespace as
* the entry, OR the given dn matches the dn pattern
*/
/*
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
* is maintaned in a_dn_pat.
*/
if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
{
ndn = op->o_conn->c_ndn;
} else {
struct berval pat;
int got_match = 0;
if ( e->e_dn == NULL )
continue;
if ( b->a_dn_expand ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
continue;
}
if ( string_expand( &bv, &b->a_dn_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
continue;
}
if ( dnNormalize(0, NULL, NULL, &bv,
&pat, op->o_tmpmemctx )
!= LDAP_SUCCESS )
{
/* did not expand to a valid dn */
continue;
}
} else {
pat = b->a_dn_pat;
}
patlen = pat.bv_len;
odnlen = op->o_ndn.bv_len;
if ( odnlen < patlen ) {
goto dn_match_cleanup;
}
if ( b->a_dn_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_ONE ) {
int rdnlen = -1;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
rdnlen = dn_rdnlen( NULL, &op->o_ndn );
if ( rdnlen != odnlen - patlen - 1 ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) {
if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) {
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
}
got_match = !strcmp( pat.bv_val, op->o_ndn.bv_val + odnlen - patlen );
dn_match_cleanup:;
if ( pat.bv_val != b->a_dn_pat.bv_val ) {
slap_sl_free( pat.bv_val, op->o_tmpmemctx );
}
ndn = op->o_ndn;
}
if ( !got_match ) {
continue;
}
if ( acl_mask_dn( op, e, a, nmatch, matches,
&b->a_realdn, &ndn ) )
{
continue;
}
}
......@@ -1153,80 +1716,29 @@ dn_match_cleanup:;
}
if ( b->a_dn_at != NULL ) {
Attribute *at;
struct berval bv;
int rc, match = 0;
const char *text;
const char *attr = b->a_dn_at->ad_cname.bv_val;
assert( attr != NULL );
if ( op->o_ndn.bv_len == 0 ) {
if ( acl_mask_dnattr( op, e, val, a, b, i,
matches, count, state,
&b->a_dn, &op->o_ndn ) )
{
continue;
}
}
Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n",
attr, 0, 0);
bv = op->o_ndn;
if ( b->a_realdn_at != NULL ) {
struct berval ndn;
/* see if asker is listed in dnattr */
for( at = attrs_find( e->e_attrs, b->a_dn_at );
at != NULL;
at = attrs_find( at->a_next, b->a_dn_at ) )
if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
{
if( value_find_ex( b->a_dn_at,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
at->a_nvals,
&bv, op->o_tmpmemctx ) == 0 )
{
/* found it */
match = 1;
break;
}
}
if( match ) {
/* have a dnattr match. if this is a self clause then
* the target must also match the op dn.
*/
if ( b->a_dn_self ) {
/* check if the target is an attribute. */
if ( val == NULL ) continue;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, b->a_dn_at,
b->a_dn_at->ad_type->sat_equality, 0,
val, &bv, &text );
/* on match error or no match, fail the ACL clause */
if (rc != LDAP_SUCCESS || match != 0 )
continue;
}
ndn = op->o_conn->c_ndn;
} else {
/* no dnattr match, check if this is a self clause */
if ( ! b->a_dn_self )
continue;
ACL_RECORD_VALUE_STATE;
/* this is a self clause, check if the target is an
* attribute.
*/
if ( val == NULL )
continue;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, b->a_dn_at,
b->a_dn_at->ad_type->sat_equality, 0,
val, &bv, &text );
ndn = op->o_ndn;
}
/* on match error or no match, fail the ACL clause */
if (rc != LDAP_SUCCESS || match != 0 )
continue;
if ( acl_mask_dnattr( op, e, val, a, b, i,
matches, count, state,
&b->a_realdn, &ndn ) )
{
continue;
}
}
......@@ -1491,8 +2003,7 @@ dn_match_cleanup:;
if ( b->a_aci_at != NULL ) {
Attribute *at;
slap_access_t grant, deny, tgrant, tdeny;
struct berval parent_ndn,
old_parent_ndn = BER_BVNULL;
struct berval parent_ndn;
BerVarray bvals = NULL;
int ret, stop;
......@@ -1540,8 +2051,8 @@ dn_match_cleanup:;
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str(tgrant,accessmaskbuf),
accessmask2str(tdeny, accessmaskbuf1), 0);
accessmask2str(tgrant, accessmaskbuf, 1),
accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
/* If the entry level aci didn't contain anything valid for the
......@@ -1549,9 +2060,8 @@ dn_match_cleanup:;
* acis with scope set to subtree
*/
if ( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ) {
dnParent(&(e->e_nname), &parent_ndn);
while ( parent_ndn.bv_val != old_parent_ndn.bv_val ) {
old_parent_ndn = parent_ndn;
dnParent( &e->e_nname, &parent_ndn );
while ( !BER_BVISEMPTY( &parent_ndn ) ) {
Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
ret = backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals, ACL_AUTH);
switch(ret){
......@@ -1581,8 +2091,8 @@ dn_match_cleanup:;
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str(tgrant,accessmaskbuf),
accessmask2str(tdeny, accessmaskbuf1), 0);
accessmask2str(tgrant, accessmaskbuf, 1),
accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
break;
......@@ -1607,7 +2117,7 @@ dn_match_cleanup:;
if (stop){
break;
}
dnParent(&old_parent_ndn, &parent_ndn);
dnParent( &parent_ndn, &parent_ndn );
}
}
......@@ -1648,7 +2158,7 @@ dn_match_cleanup:;
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: [%d] applying %s (%s)\n",
i, accessmask2str( modmask, accessmaskbuf ),
i, accessmask2str( modmask, accessmaskbuf, 1 ),
b->a_type == ACL_CONTINUE
? "continue"
: b->a_type == ACL_BREAK
......@@ -1678,7 +2188,7 @@ dn_match_cleanup:;
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: [%d] mask: %s\n",
i, accessmask2str(*mask, accessmaskbuf), 0 );
i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
if( b->a_type == ACL_CONTINUE ) {
continue;
......@@ -1696,7 +2206,7 @@ dn_match_cleanup:;
Debug( LDAP_DEBUG_ACL,
"<= acl_mask: no more <who> clauses, returning %s (stop)\n",
accessmask2str(*mask, accessmaskbuf), 0, 0 );
accessmask2str(*mask, accessmaskbuf, 1), 0, 0 );
return ACL_STOP;
}
......@@ -1722,7 +2232,7 @@ acl_check_modlist(
be = op->o_bd;
if ( be == NULL ) {
be = &backends[0];
be = LDAP_STAILQ_FIRST(&backendDB);
be_null = 1;
op->o_bd = be;
}
......@@ -1741,12 +2251,24 @@ acl_check_modlist(
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: backend default %s access %s to \"%s\"\n",
access2str( ACL_WRITE ),
op->o_bd->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn.bv_val );
op->o_bd->be_dfltaccess >= ACL_WRITE
? "granted" : "denied",
op->o_dn.bv_val );
ret = (op->o_bd->be_dfltaccess >= ACL_WRITE);
goto done;
}
for ( ; mlist != NULL; mlist = mlist->sml_next ) {
/*
* Internal mods are ignored by ACL_WRITE checking
*/
if ( mlist->sml_flags & SLAP_MOD_INTERNAL ) {
Debug( LDAP_DEBUG_ACL, "acl: internal mod %s:"
" modify access granted\n",
mlist->sml_desc->ad_cname.bv_val, 0, 0 );
continue;
}
/*
* no-user-modification operational attributes are ignored
* by ACL_WRITE checking as any found here are not provided
......@@ -1767,7 +2289,7 @@ acl_check_modlist(
* This prevents abuse from selfwriters.
*/
if ( ! access_allowed( op, e,
mlist->sml_desc, NULL, ACL_WRITE, &state ) )
mlist->sml_desc, NULL, ACL_WDEL, &state ) )
{
ret = 0;
goto done;
......@@ -1785,7 +2307,7 @@ acl_check_modlist(
bv->bv_val != NULL; bv++ )
{
if ( ! access_allowed( op, e,
mlist->sml_desc, bv, ACL_WRITE, &state ) )
mlist->sml_desc, bv, ACL_WADD, &state ) )
{
ret = 0;
goto done;
......@@ -1796,7 +2318,7 @@ acl_check_modlist(
case LDAP_MOD_DELETE:
if ( mlist->sml_values == NULL ) {
if ( ! access_allowed( op, e,
mlist->sml_desc, NULL, ACL_WRITE, NULL ) )
mlist->sml_desc, NULL, ACL_WDEL, NULL ) )
{
ret = 0;
goto done;
......@@ -1808,7 +2330,7 @@ acl_check_modlist(
bv->bv_val != NULL; bv++ )
{
if ( ! access_allowed( op, e,
mlist->sml_desc, bv, ACL_WRITE, &state ) )
mlist->sml_desc, bv, ACL_WDEL, &state ) )
{
ret = 0;
goto done;
......@@ -2037,6 +2559,7 @@ aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_attrs = anlistp;
op2.ors_attrsonly = 0;
op2.o_private = cp->op->o_private;
cb.sc_private = &p;
......@@ -2111,8 +2634,9 @@ aci_match_set (
int rc = 0;
AciSetCookie cookie;
if (setref == 0) {
if ( setref == 0 ) {
ber_dupbv_x( &set, subj, op->o_tmpmemctx );
} else {
struct berval subjdn, ndn = BER_BVNULL;
struct berval setat;
......@@ -2122,7 +2646,7 @@ aci_match_set (
/* format of string is "entry/setAttrName" */
if ( aci_get_part( subj, 0, '/', &subjdn ) < 0 ) {
return(0);
return 0;
}
if ( aci_get_part( subj, 1, '/', &setat ) < 0 ) {
......@@ -2635,6 +3159,11 @@ aci_mask(
}
#ifdef SLAP_DYNACL
/*
* FIXME: there is a silly dependence that makes it difficult
* to move ACIs in a run-time loadable module under the "dynacl"
* umbrella, because sets share some helpers with ACIs.
*/
static int
dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *right, void **privp )
{
......@@ -2674,13 +3203,17 @@ dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *r
}
static int
dynacl_aci_print( void *priv )
dynacl_aci_unparse( void *priv, struct berval *bv )
{
AttributeDescription *ad = ( AttributeDescription * )priv;
char *ptr;
assert( ad );
fprintf( stderr, " aci=%s", ad->ad_cname.bv_val );
bv->bv_val = ch_malloc( STRLENOF(" aci=") + ad->ad_cname.bv_len + 1 );
ptr = lutil_strcopy( bv->bv_val, " aci=" );
ptr = lutil_strcopy( ptr, ad->ad_cname.bv_val );
bv->bv_len = ptr - bv->bv_val;
return 0;
}
......@@ -2730,8 +3263,8 @@ dynacl_aci_mask(
}
Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str( tgrant, accessmaskbuf ),
accessmask2str( tdeny, accessmaskbuf1 ), 0 );
accessmask2str( tgrant, accessmaskbuf, 1 ),
accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
}
/* If the entry level aci didn't contain anything valid for the
......@@ -2740,7 +3273,6 @@ dynacl_aci_mask(
*/
if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
struct berval parent_ndn;
struct berval old_parent_ndn = BER_BVNULL;
#if 1
/* to solve the chicken'n'egg problem of accessing
......@@ -2764,12 +3296,11 @@ dynacl_aci_mask(
#endif
dnParent( &e->e_nname, &parent_ndn );
while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
while ( !BER_BVISEMPTY( &parent_ndn ) ){
int i;
BerVarray bvals = NULL;
int ret, stop;
old_parent_ndn = parent_ndn;
Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
......@@ -2797,8 +3328,8 @@ dynacl_aci_mask(
}
}
Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str( tgrant, accessmaskbuf ),
accessmask2str( tdeny, accessmaskbuf1 ), 0 );
accessmask2str( tgrant, accessmaskbuf, 1 ),
accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
}
break;
......@@ -2824,7 +3355,7 @@ dynacl_aci_mask(
if ( stop ) {
break;
}
dnParent( &old_parent_ndn, &parent_ndn );
dnParent( &parent_ndn, &parent_ndn );
}
}
......@@ -2838,7 +3369,7 @@ dynacl_aci_mask(
static slap_dynacl_t dynacl_aci = {
"aci",
dynacl_aci_parse,
dynacl_aci_print,
dynacl_aci_unparse,
dynacl_aci_mask,
NULL,
NULL,
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -38,14 +38,19 @@
#include "lber_pvt.h"
#include "lutil.h"
static const char style_base[] = "base";
static char *style_strings[] = {
"regex",
"expand",
"base",
"exact",
"one",
"subtree",
"children",
"level",
"attrof",
"anonymous",
"users",
"self",
"ip",
"path",
NULL
......@@ -59,13 +64,9 @@ static void acl_regex_normalized_dn(const char *src, struct berval *pat);
#ifdef LDAP_DEBUG
static void print_acl(Backend *be, AccessControl *a);
static void print_access(Access *b);
#endif
#ifdef LDAP_DEVEL
static int
check_scope( BackendDB *be, AccessControl *a );
#endif /* LDAP_DEVEL */
static int check_scope( BackendDB *be, AccessControl *a );
#ifdef SLAP_DYNACL
static int
......@@ -160,7 +161,6 @@ regtest(const char *fname, int lineno, char *pat) {
regfree(&re);
}
#ifdef LDAP_DEVEL
/*
* Experimental
*
......@@ -181,6 +181,10 @@ check_scope( BackendDB *be, AccessControl *a )
dn = be->be_nsuffix[0];
if ( BER_BVISEMPTY( &dn ) ) {
return ACL_SCOPE_OK;
}
if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
a->acl_dn_style != ACL_STYLE_REGEX )
{
......@@ -295,7 +299,6 @@ regex_done:;
return ACL_SCOPE_UNKNOWN;
}
#endif /* LDAP_DEVEL */
void
parse_acl(
......@@ -303,8 +306,8 @@ parse_acl(
const char *fname,
int lineno,
int argc,
char **argv
)
char **argv,
int pos )
{
int i;
char *left, *right, *style, *next;
......@@ -436,8 +439,9 @@ parse_acl(
acl_usage();
}
} else if ( strcasecmp( left, "attr" ) == 0
|| strcasecmp( left, "attrs" ) == 0 ) {
} else if ( strcasecmp( left, "attr" ) == 0 /* TOLERATED */
|| strcasecmp( left, "attrs" ) == 0 ) /* DOCUMENTED */
{
a->acl_attrs = str2anlist( a->acl_attrs,
right, "," );
if ( a->acl_attrs == NULL ) {
......@@ -462,58 +466,63 @@ parse_acl(
acl_usage();
}
ber_str2bv( right, 0, 1, &a->acl_attrval );
if ( style && strcasecmp( style, "regex" ) == 0 ) {
int e = regcomp( &a->acl_attrval_re, a->acl_attrval.bv_val,
REG_EXTENDED | REG_ICASE | REG_NOSUB );
if ( e ) {
char buf[512];
regerror( e, &a->acl_attrval_re, buf, sizeof(buf) );
fprintf( stderr, "%s: line %d: "
"regular expression \"%s\" bad because of %s\n",
fname, lineno, right, buf );
acl_usage();
}
a->acl_attrval_style = ACL_STYLE_REGEX;
} else {
/* FIXME: if the attribute has DN syntax, we might
* allow one, subtree and children styles as well */
if ( !strcasecmp( style, "exact" ) ) {
a->acl_attrval_style = ACL_STYLE_BASE;
a->acl_attrval_style = ACL_STYLE_BASE;
if ( style != NULL ) {
if ( strcasecmp( style, "regex" ) == 0 ) {
int e = regcomp( &a->acl_attrval_re, a->acl_attrval.bv_val,
REG_EXTENDED | REG_ICASE | REG_NOSUB );
if ( e ) {
char buf[512];
regerror( e, &a->acl_attrval_re, buf, sizeof(buf) );
fprintf( stderr, "%s: line %d: "
"regular expression \"%s\" bad because of %s\n",
fname, lineno, right, buf );
acl_usage();
}
a->acl_attrval_style = ACL_STYLE_REGEX;
} else if ( a->acl_attrs[0].an_desc->ad_type->
sat_syntax == slap_schema.si_syn_distinguishedName )
{
if ( !strcasecmp( style, "baseObject" ) ||
!strcasecmp( style, "base" ) )
{
} else {
/* FIXME: if the attribute has DN syntax, we might
* allow one, subtree and children styles as well */
if ( !strcasecmp( style, "base" ) ||
!strcasecmp( style, "exact" ) ) {
a->acl_attrval_style = ACL_STYLE_BASE;
} else if ( !strcasecmp( style, "onelevel" ) ||
!strcasecmp( style, "one" ) )
{
a->acl_attrval_style = ACL_STYLE_ONE;
} else if ( !strcasecmp( style, "subtree" ) ||
!strcasecmp( style, "sub" ) )
} else if ( a->acl_attrs[0].an_desc->ad_type->
sat_syntax == slap_schema.si_syn_distinguishedName )
{
a->acl_attrval_style = ACL_STYLE_SUBTREE;
} else if ( !strcasecmp( style, "children" ) ) {
a->acl_attrval_style = ACL_STYLE_CHILDREN;
if ( !strcasecmp( style, "baseObject" ) ||
!strcasecmp( style, "base" ) )
{
a->acl_attrval_style = ACL_STYLE_BASE;
} else if ( !strcasecmp( style, "onelevel" ) ||
!strcasecmp( style, "one" ) )
{
a->acl_attrval_style = ACL_STYLE_ONE;
} else if ( !strcasecmp( style, "subtree" ) ||
!strcasecmp( style, "sub" ) )
{
a->acl_attrval_style = ACL_STYLE_SUBTREE;
} else if ( !strcasecmp( style, "children" ) ) {
a->acl_attrval_style = ACL_STYLE_CHILDREN;
} else {
fprintf( stderr,
"%s: line %d: unknown val.<style> \"%s\" "
"for attributeType \"%s\" with DN syntax; "
"using \"base\"\n",
fname, lineno, style,
a->acl_attrs[0].an_desc->ad_cname.bv_val );
a->acl_attrval_style = ACL_STYLE_BASE;
}
} else {
fprintf( stderr,
"%s: line %d: unknown val.<style> \"%s\" "
"for attributeType \"%s\" with DN syntax; "
"using \"base\"\n",
"for attributeType \"%s\"; using \"exact\"\n",
fname, lineno, style,
a->acl_attrs[0].an_desc->ad_cname.bv_val );
a->acl_attrval_style = ACL_STYLE_BASE;
}
} else {
fprintf( stderr,
"%s: line %d: unknown val.<style> \"%s\" "
"for attributeType \"%s\"; using \"exact\"\n",
fname, lineno, style,
a->acl_attrs[0].an_desc->ad_cname.bv_val );
a->acl_attrval_style = ACL_STYLE_BASE;
}
}
......@@ -530,6 +539,7 @@ parse_acl(
{
free( a->acl_dn_pat.bv_val );
BER_BVZERO( &a->acl_dn_pat );
a->acl_dn_style = ACL_STYLE_REGEX;
}
if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
......@@ -587,14 +597,39 @@ parse_acl(
/* get <who> */
for ( ; i < argc; i++ ) {
slap_style_t sty = ACL_STYLE_REGEX;
char *style_modifier = NULL;
int expand = 0;
slap_style_t sty = ACL_STYLE_REGEX;
char *style_modifier = NULL;
char *style_level = NULL;
int level = 0;
int expand = 0;
slap_dn_access *bdn = &b->a_dn;
int is_realdn = 0;
split( argv[i], '=', &left, &right );
split( left, '.', &left, &style );
if ( style ) {
split( style, ',', &style, &style_modifier);
split( style, ',', &style, &style_modifier );
if ( strncasecmp( style, "level", STRLENOF( "level" ) ) == 0 ) {
split( style, '{', &style, &style_level );
if ( style_level != NULL ) {
char *p = strchr( style_level, '}' );
if ( p == NULL ) {
fprintf( stderr,
"%s: line %d: premature eol: "
"expecting closing '}' in \"level{n}\"\n",
fname, lineno );
acl_usage();
} else if ( p == style_level ) {
fprintf( stderr,
"%s: line %d: empty level "
"in \"level{n}\"\n",
fname, lineno );
acl_usage();
}
p[0] = '\0';
}
}
}
if ( style == NULL || *style == '\0' ||
......@@ -617,6 +652,21 @@ parse_acl(
} else if ( strcasecmp( style, "children" ) == 0 ) {
sty = ACL_STYLE_CHILDREN;
} else if ( strcasecmp( style, "level" ) == 0 )
{
char *next;
level = strtol( style_level, &next, 10 );
if ( next[0] != '\0' ) {
fprintf( stderr,
"%s: line %d: unable to parse level "
"in \"level{n}\"\n",
fname, lineno );
acl_usage();
}
sty = ACL_STYLE_LEVEL;
} else if ( strcasecmp( style, "regex" ) == 0 ) {
sty = ACL_STYLE_REGEX;
......@@ -648,8 +698,12 @@ parse_acl(
case ACL_STYLE_REGEX:
fprintf( stderr, "%s: line %d: "
"\"regex\" style implies "
"\"expand\" modifier (ignored)\n",
"\"expand\" modifier"
SLAPD_CONF_UNKNOWN_IGNORED ".\n",
fname, lineno );
#ifdef SLAPD_CONF_UNKNOWN_BAILOUT
acl_usage();
#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */
break;
case ACL_STYLE_EXPAND:
......@@ -658,8 +712,12 @@ parse_acl(
fprintf( stderr, "%s: line %d: "
"\"expand\" style used "
"in conjunction with "
"\"expand\" modifier (ignored)\n",
"\"expand\" modifier"
SLAPD_CONF_UNKNOWN_IGNORED ".\n",
fname, lineno );
#ifdef SLAPD_CONF_UNKNOWN_BAILOUT
acl_usage();
#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */
#endif
break;
......@@ -681,38 +739,48 @@ parse_acl(
fname, lineno );
}
if ( strcasecmp( argv[i], "*" ) == 0 ) {
if ( strncasecmp( left, "real", STRLENOF( "real" ) ) == 0 ) {
is_realdn = 1;
bdn = &b->a_realdn;
left += STRLENOF( "real" );
}
if ( strcasecmp( left, "*" ) == 0 ) {
if ( is_realdn ) {
acl_usage();
}
ber_str2bv( "*", STRLENOF( "*" ), 1, &bv );
sty = ACL_STYLE_REGEX;
} else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) {
} else if ( strcasecmp( left, "anonymous" ) == 0 ) {
ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
sty = ACL_STYLE_ANONYMOUS;
} else if ( strcasecmp( argv[i], "users" ) == 0 ) {
} else if ( strcasecmp( left, "users" ) == 0 ) {
ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
sty = ACL_STYLE_USERS;
} else if ( strcasecmp( argv[i], "self" ) == 0 ) {
} else if ( strcasecmp( left, "self" ) == 0 ) {
ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
sty = ACL_STYLE_SELF;
} else if ( strcasecmp( left, "dn" ) == 0 ) {
if ( sty == ACL_STYLE_REGEX ) {
b->a_dn_style = ACL_STYLE_REGEX;
bdn->a_style = ACL_STYLE_REGEX;
if ( right == NULL ) {
/* no '=' */
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if (*right == '\0' ) {
/* dn="" */
ber_str2bv("anonymous",
STRLENOF( "anonymous" ),
1, &bv);
b->a_dn_style = ACL_STYLE_ANONYMOUS;
bdn->a_style = ACL_STYLE_ANONYMOUS;
} else if ( strcmp( right, "*" ) == 0 ) {
/* dn=* */
......@@ -720,7 +788,7 @@ parse_acl(
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if ( strcmp( right, ".+" ) == 0
|| strcmp( right, "^.+" ) == 0
......@@ -732,7 +800,7 @@ parse_acl(
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if ( strcmp( right, ".*" ) == 0
|| strcmp( right, "^.*" ) == 0
......@@ -768,7 +836,7 @@ parse_acl(
}
if ( !BER_BVISNULL( &bv ) ) {
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
if ( !BER_BVISEMPTY( &bdn->a_pat ) ) {
fprintf( stderr,
"%s: line %d: dn pattern already specified.\n",
fname, lineno );
......@@ -782,7 +850,7 @@ parse_acl(
expand == 0 )
{
rc = dnNormalize(0, NULL, NULL,
&bv, &b->a_dn_pat, NULL);
&bv, &bdn->a_pat, NULL);
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"%s: line %d: bad DN \"%s\" in by DN clause\n",
......@@ -792,10 +860,61 @@ parse_acl(
free( bv.bv_val );
} else {
b->a_dn_pat = bv;
bdn->a_pat = bv;
}
bdn->a_style = sty;
if ( expand ) {
char *exp;
int gotit = 0;
for ( exp = strchr( bdn->a_pat.bv_val, '$' );
exp && exp - bdn->a_pat.bv_val < bdn->a_pat.bv_len;
exp = strchr( exp, '$' ) )
{
if ( isdigit( exp[ 1 ] ) ) {
gotit = 1;
break;
}
}
if ( gotit == 1 ) {
bdn->a_expand = expand;
} else {
fprintf( stderr,
"%s: line %d: \"expand\" used "
"with no expansions in \"pattern\""
SLAPD_CONF_UNKNOWN_IGNORED ".\n",
fname, lineno );
#ifdef SLAPD_CONF_UNKNOWN_BAILOUT
acl_usage();
#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */
}
}
if ( sty == ACL_STYLE_SELF ) {
bdn->a_self_level = level;
} else {
if ( level < 0 ) {
fprintf( stderr,
"%s: line %d: bad negative level \"%d\" "
"in by DN clause\n",
fname, lineno, level );
acl_usage();
} else if ( level == 1 ) {
fprintf( stderr,
"%s: line %d: \"onelevel\" should be used "
"instead of \"level{1}\" in by DN clause\n",
fname, lineno, 0 );
} else if ( level == 0 && sty == ACL_STYLE_LEVEL ) {
fprintf( stderr,
"%s: line %d: \"base\" should be used "
"instead of \"level{0}\" in by DN clause\n",
fname, lineno, 0 );
}
bdn->a_level = level;
}
b->a_dn_style = sty;
b->a_dn_expand = expand;
continue;
}
......@@ -808,14 +927,14 @@ parse_acl(
acl_usage();
}
if( b->a_dn_at != NULL ) {
if( bdn->a_at != NULL ) {
fprintf( stderr,
"%s: line %d: dnattr already specified.\n",
fname, lineno );
acl_usage();
}
rc = slap_str2ad( right, &b->a_dn_at, &text );
rc = slap_str2ad( right, &bdn->a_at, &text );
if( rc != LDAP_SUCCESS ) {
fprintf( stderr,
......@@ -825,20 +944,20 @@ parse_acl(
}
if( !is_at_syntax( b->a_dn_at->ad_type,
if( !is_at_syntax( bdn->a_at->ad_type,
SLAPD_DN_SYNTAX ) &&
!is_at_syntax( b->a_dn_at->ad_type,
!is_at_syntax( bdn->a_at->ad_type,
SLAPD_NAMEUID_SYNTAX ))
{
fprintf( stderr,
"%s: line %d: dnattr \"%s\": "
"inappropriate syntax: %s\n",
fname, lineno, right,
b->a_dn_at->ad_type->sat_syntax_oid );
bdn->a_at->ad_type->sat_syntax_oid );
acl_usage();
}
if( b->a_dn_at->ad_type->sat_equality == NULL ) {
if( bdn->a_at->ad_type->sat_equality == NULL ) {
fprintf( stderr,
"%s: line %d: dnattr \"%s\": "
"inappropriate matching (no EQUALITY)\n",
......@@ -1586,9 +1705,13 @@ parse_acl(
}
/* get <access> */
if ( strncasecmp( left, "self", 4 ) == 0 ) {
if ( strncasecmp( left, "self", STRLENOF( "self" ) ) == 0 ) {
b->a_dn_self = 1;
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) );
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[ STRLENOF( "self" ) ] ) );
} else if ( strncasecmp( left, "realself", STRLENOF( "realself" ) ) == 0 ) {
b->a_realdn_self = 1;
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[ STRLENOF( "realself" ) ] ) );
} else {
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) );
......@@ -1653,7 +1776,6 @@ parse_acl(
}
if ( be != NULL ) {
#ifdef LDAP_DEVEL
if ( !BER_BVISNULL( &be->be_nsuffix[ 1 ] ) ) {
fprintf( stderr, "%s: line %d: warning: "
"scope checking only applies to single-valued "
......@@ -1693,17 +1815,16 @@ parse_acl(
default:
break;
}
#endif /* LDAP_DEVEL */
acl_append( &be->be_acl, a );
acl_append( &be->be_acl, a, pos );
} else {
acl_append( &frontendDB->be_acl, a );
acl_append( &frontendDB->be_acl, a, pos );
}
}
}
char *
accessmask2str( slap_mask_t mask, char *buf )
accessmask2str( slap_mask_t mask, char *buf, int debug )
{
int none = 1;
char *ptr = buf;
......@@ -1720,6 +1841,9 @@ accessmask2str( slap_mask_t mask, char *buf )
if ( ACL_LVL_IS_NONE(mask) ) {
ptr = lutil_strcopy( ptr, "none" );
} else if ( ACL_LVL_IS_DISCLOSE(mask) ) {
ptr = lutil_strcopy( ptr, "disclose" );
} else if ( ACL_LVL_IS_AUTH(mask) ) {
ptr = lutil_strcopy( ptr, "auth" );
......@@ -1734,10 +1858,24 @@ accessmask2str( slap_mask_t mask, char *buf )
} else if ( ACL_LVL_IS_WRITE(mask) ) {
ptr = lutil_strcopy( ptr, "write" );
} else if ( ACL_LVL_IS_WADD(mask) ) {
ptr = lutil_strcopy( ptr, "add" );
} else if ( ACL_LVL_IS_WDEL(mask) ) {
ptr = lutil_strcopy( ptr, "delete" );
} else if ( ACL_LVL_IS_MANAGE(mask) ) {
ptr = lutil_strcopy( ptr, "manage" );
} else {
ptr = lutil_strcopy( ptr, "unknown" );
}
if ( !debug ) {
*ptr = '\0';
return buf;
}
*ptr++ = '(';
}
......@@ -1751,9 +1889,22 @@ accessmask2str( slap_mask_t mask, char *buf )
*ptr++ = '=';
}
if ( ACL_PRIV_ISSET(mask, ACL_PRIV_MANAGE) ) {
none = 0;
*ptr++ = 'm';
}
if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
none = 0;
*ptr++ = 'w';
} else if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WADD) ) {
none = 0;
*ptr++ = 'a';
} else if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WDEL) ) {
none = 0;
*ptr++ = 'z';
}
if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
......@@ -1776,13 +1927,18 @@ accessmask2str( slap_mask_t mask, char *buf )
*ptr++ = 'x';
}
if ( ACL_PRIV_ISSET(mask, ACL_PRIV_DISCLOSE) ) {
none = 0;
*ptr++ = 'd';
}
if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
none = 0;
*ptr++ = 'n';
*ptr++ = '0';
}
if ( none ) {
*ptr++ = '0';
ptr = buf;
}
if ( ACL_IS_LEVEL( mask ) ) {
......@@ -1817,9 +1973,18 @@ str2accessmask( const char *str )
}
for( i=1; str[i] != '\0'; i++ ) {
if( TOLOWER((unsigned char) str[i]) == 'w' ) {
if( TOLOWER((unsigned char) str[i]) == 'm' ) {
ACL_PRIV_SET(mask, ACL_PRIV_MANAGE);
} else if( TOLOWER((unsigned char) str[i]) == 'w' ) {
ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
} else if( TOLOWER((unsigned char) str[i]) == 'a' ) {
ACL_PRIV_SET(mask, ACL_PRIV_WADD);
} else if( TOLOWER((unsigned char) str[i]) == 'z' ) {
ACL_PRIV_SET(mask, ACL_PRIV_WDEL);
} else if( TOLOWER((unsigned char) str[i]) == 'r' ) {
ACL_PRIV_SET(mask, ACL_PRIV_READ);
......@@ -1832,6 +1997,9 @@ str2accessmask( const char *str )
} else if( TOLOWER((unsigned char) str[i]) == 'x' ) {
ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
} else if( TOLOWER((unsigned char) str[i]) == 'd' ) {
ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
} else if( str[i] != '0' ) {
ACL_INVALIDATE(mask);
return mask;
......@@ -1844,6 +2012,9 @@ str2accessmask( const char *str )
if ( strcasecmp( str, "none" ) == 0 ) {
ACL_LVL_ASSIGN_NONE(mask);
} else if ( strcasecmp( str, "disclose" ) == 0 ) {
ACL_LVL_ASSIGN_DISCLOSE(mask);
} else if ( strcasecmp( str, "auth" ) == 0 ) {
ACL_LVL_ASSIGN_AUTH(mask);
......@@ -1856,9 +2027,18 @@ str2accessmask( const char *str )
} else if ( strcasecmp( str, "read" ) == 0 ) {
ACL_LVL_ASSIGN_READ(mask);
} else if ( strcasecmp( str, "add" ) == 0 ) {
ACL_LVL_ASSIGN_WADD(mask);
} else if ( strcasecmp( str, "delete" ) == 0 ) {
ACL_LVL_ASSIGN_WDEL(mask);
} else if ( strcasecmp( str, "write" ) == 0 ) {
ACL_LVL_ASSIGN_WRITE(mask);
} else if ( strcasecmp( str, "manage" ) == 0 ) {
ACL_LVL_ASSIGN_MANAGE(mask);
} else {
ACL_INVALIDATE( mask );
}
......@@ -1873,25 +2053,32 @@ acl_usage( void )
"<access clause> ::= access to <what> "
"[ by <who> <access> [ <control> ] ]+ \n"
"<what> ::= * | [dn[.<dnstyle>]=<DN>] [filter=<filter>] [attrs=<attrlist>]\n"
"<attrlist> ::= <attr> [val[.<style>]=<value>] | <attr> , <attrlist>\n"
"<attrlist> ::= <attr> [val[.<attrstyle>]=<value>] | <attr> , <attrlist>\n"
"<attr> ::= <attrname> | entry | children\n",
"<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n"
"\t[ realanonymous | realusers | realself | realdn[.<dnstyle>]=<DN> ]\n"
"\t[dnattr=<attrname>]\n"
"\t[realdnattr=<attrname>]\n"
"\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n"
"\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n"
"\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
#ifdef SLAPD_ACI_ENABLED
"\t[aci=<attrname>]\n"
"\t[aci=[<attrname>]]\n"
#endif
#ifdef SLAP_DYNACL
"\t[dynacl/<name>[.<dynstyle>][=<pattern>]]\n"
#endif /* SLAP_DYNACL */
"\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n",
"<style> ::= exact | regex | base(Object)\n"
"<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | "
"exact | regex\n"
"<style> ::= exact | regex | base(Object)\n"
"<attrstyle> ::= exact | regex | base(Object) | one(level) | "
"sub(tree) | children\n"
"<peernamestyle> ::= exact | regex | ip | path\n"
"<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n"
"<access> ::= [self]{<level>|<priv>}\n"
"<level> ::= none | auth | compare | search | read | write\n"
"<priv> ::= {=|+|-}{w|r|s|c|x|0}+\n"
"<access> ::= [[real]self]{<level>|<priv>}\n"
"<level> ::= none|disclose|auth|compare|search|read|{write|add|delete}|manage\n"
"<priv> ::= {=|+|-}{0|d|x|c|s|r|{w|a|z}|m}+\n"
"<control> ::= [ stop | continue | break ]\n"
);
exit( EXIT_FAILURE );
......@@ -1968,12 +2155,15 @@ access_append( Access **l, Access *a )
}
void
acl_append( AccessControl **l, AccessControl *a )
acl_append( AccessControl **l, AccessControl *a, int pos )
{
for ( ; *l != NULL; l = &(*l)->acl_next ) {
int i;
for (i=0 ; i != pos && *l != NULL; l = &(*l)->acl_next, i++ ) {
; /* Empty */
}
if ( *l && a )
a->acl_next = *l;
*l = a;
}
......@@ -1983,6 +2173,9 @@ access_free( Access *a )
if ( !BER_BVISNULL( &a->a_dn_pat ) ) {
free( a->a_dn_pat.bv_val );
}
if ( !BER_BVISNULL( &a->a_realdn_pat ) ) {
free( a->a_realdn_pat.bv_val );
}
if ( !BER_BVISNULL( &a->a_peername_pat ) ) {
free( a->a_peername_pat.bv_val );
}
......@@ -2053,6 +2246,9 @@ access2str( slap_access_t access )
if ( access == ACL_NONE ) {
return "none";
} else if ( access == ACL_DISCLOSE ) {
return "disclose";
} else if ( access == ACL_AUTH ) {
return "auth";
......@@ -2067,6 +2263,16 @@ access2str( slap_access_t access )
} else if ( access == ACL_WRITE ) {
return "write";
} else if ( access == ACL_WADD ) {
return "add";
} else if ( access == ACL_WDEL ) {
return "delete";
} else if ( access == ACL_MANAGE ) {
return "manage";
}
return "unknown";
......@@ -2078,6 +2284,13 @@ str2access( const char *str )
if ( strcasecmp( str, "none" ) == 0 ) {
return ACL_NONE;
} else if ( strcasecmp( str, "disclose" ) == 0 ) {
#ifndef SLAP_ACL_HONOR_DISCLOSE
fprintf( stderr, "str2access: warning, "
"\"disclose\" privilege disabled.\n" );
#endif /* SLAP_ACL_HONOR_DISCLOSE */
return ACL_DISCLOSE;
} else if ( strcasecmp( str, "auth" ) == 0 ) {
return ACL_AUTH;
......@@ -2092,64 +2305,160 @@ str2access( const char *str )
} else if ( strcasecmp( str, "write" ) == 0 ) {
return ACL_WRITE;
} else if ( strcasecmp( str, "add" ) == 0 ) {
return ACL_WADD;
} else if ( strcasecmp( str, "delete" ) == 0 ) {
return ACL_WDEL;
} else if ( strcasecmp( str, "manage" ) == 0 ) {
return ACL_MANAGE;
}
return( ACL_INVALID_ACCESS );
}
#ifdef LDAP_DEBUG
#define ACLBUF_MAXLEN 8192
static void
print_access( Access *b )
static char aclbuf[ACLBUF_MAXLEN];
static char *
dnaccess2text( slap_dn_access *bdn, char *ptr, int is_realdn )
{
char maskbuf[ACCESSMASK_MAXLEN];
*ptr++ = ' ';
fprintf( stderr, "\tby" );
if ( is_realdn ) {
ptr = lutil_strcopy( ptr, "real" );
}
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
if ( ber_bvccmp( &b->a_dn_pat, '*' ) ||
b->a_dn_style == ACL_STYLE_ANONYMOUS /* strcmp( b->a_dn_pat.bv_val, "anonymous" ) == 0 */ ||
b->a_dn_style == ACL_STYLE_USERS /* strcmp( b->a_dn_pat.bv_val, "users" ) == 0 */ ||
b->a_dn_style == ACL_STYLE_SELF /* strcmp( b->a_dn_pat.bv_val, "self" ) == 0 */ )
{
fprintf( stderr, " %s", b->a_dn_pat.bv_val );
if ( ber_bvccmp( &bdn->a_pat, '*' ) ||
bdn->a_style == ACL_STYLE_ANONYMOUS ||
bdn->a_style == ACL_STYLE_USERS ||
bdn->a_style == ACL_STYLE_SELF )
{
if ( is_realdn ) {
assert( ! ber_bvccmp( &bdn->a_pat, '*' ) );
}
ptr = lutil_strcopy( ptr, bdn->a_pat.bv_val );
if ( bdn->a_style == ACL_STYLE_SELF && bdn->a_self_level != 0 ) {
int n = sprintf( ptr, ".level{%d}", bdn->a_self_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
} else {
fprintf( stderr, " dn.%s=\"%s\"",
style_strings[b->a_dn_style], b->a_dn_pat.bv_val );
} else {
ptr = lutil_strcopy( ptr, "dn." );
if ( bdn->a_style == ACL_STYLE_BASE )
ptr = lutil_strcopy( ptr, style_base );
else
ptr = lutil_strcopy( ptr, style_strings[bdn->a_style] );
if ( bdn->a_style == ACL_STYLE_LEVEL ) {
int n = sprintf( ptr, "{%d}", bdn->a_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
if ( bdn->a_expand ) {
ptr = lutil_strcopy( ptr, ",expand" );
}
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, bdn->a_pat.bv_val );
*ptr++ = '"';
}
return ptr;
}
static char *
access2text( Access *b, char *ptr )
{
char maskbuf[ACCESSMASK_MAXLEN];
ptr = lutil_strcopy( ptr, "\tby" );
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
ptr = dnaccess2text( &b->a_dn, ptr, 0 );
}
if ( b->a_dn_at ) {
ptr = lutil_strcopy( ptr, " dnattr=" );
ptr = lutil_strcopy( ptr, b->a_dn_at->ad_cname.bv_val );
}
if ( b->a_dn_at != NULL ) {
fprintf( stderr, " dnattr=%s", b->a_dn_at->ad_cname.bv_val );
if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
ptr = dnaccess2text( &b->a_realdn, ptr, 1 );
}
if ( b->a_realdn_at ) {
ptr = lutil_strcopy( ptr, " realdnattr=" );
ptr = lutil_strcopy( ptr, b->a_realdn_at->ad_cname.bv_val );
}
if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
fprintf( stderr, " group/%s/%s.%s=\"%s\"",
b->a_group_oc ? b->a_group_oc->soc_cname.bv_val : "groupOfNames",
b->a_group_at ? b->a_group_at->ad_cname.bv_val : "member",
style_strings[b->a_group_style],
b->a_group_pat.bv_val );
ptr = lutil_strcopy( ptr, " group/" );
ptr = lutil_strcopy( ptr, b->a_group_oc ?
b->a_group_oc->soc_cname.bv_val : "groupOfNames" );
*ptr++ = '/';
ptr = lutil_strcopy( ptr, b->a_group_at ?
b->a_group_at->ad_cname.bv_val : "member" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_group_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_group_pat.bv_val );
*ptr++ = '"';
}
if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
fprintf( stderr, " peername=\"%s\"", b->a_peername_pat.bv_val );
ptr = lutil_strcopy( ptr, " peername" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_peername_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_peername_pat.bv_val );
*ptr++ = '"';
}
if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) {
fprintf( stderr, " sockname=\"%s\"", b->a_sockname_pat.bv_val );
ptr = lutil_strcopy( ptr, " sockname" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_sockname_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_sockname_pat.bv_val );
*ptr++ = '"';
}
if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
fprintf( stderr, " domain=%s", b->a_domain_pat.bv_val );
ptr = lutil_strcopy( ptr, " domain" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_domain_style] );
if ( b->a_domain_expand ) {
ptr = lutil_strcopy( ptr, ",expand" );
}
*ptr++ = '=';
ptr = lutil_strcopy( ptr, b->a_domain_pat.bv_val );
}
if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
fprintf( stderr, " sockurl=\"%s\"", b->a_sockurl_pat.bv_val );
ptr = lutil_strcopy( ptr, " sockurl" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_sockurl_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_sockurl_pat.bv_val );
*ptr++ = '"';
}
if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
fprintf( stderr, " set=\"%s\"", b->a_set_pat.bv_val );
ptr = lutil_strcopy( ptr, " set" );
*ptr++ = '.';
ptr = lutil_strcopy( ptr, style_strings[b->a_set_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_set_pat.bv_val );
*ptr++ = '"';
}
#ifdef SLAP_DYNACL
......@@ -2157,68 +2466,90 @@ print_access( Access *b )
slap_dynacl_t *da;
for ( da = b->a_dynacl; da; da = da->da_next ) {
if ( da->da_print ) {
(void)( *da->da_print )( da->da_private );
if ( da->da_unparse ) {
struct berval bv;
(void)( *da->da_unparse )( da->da_private, &bv );
ptr = lutil_strcopy( ptr, bv.bv_val );
ch_free( bv.bv_val );
}
}
}
#else /* ! SLAP_DYNACL */
#ifdef SLAPD_ACI_ENABLED
if ( b->a_aci_at != NULL ) {
fprintf( stderr, " aci=%s", b->a_aci_at->ad_cname.bv_val );
ptr = lutil_strcopy( ptr, " aci=" );
ptr = lutil_strcopy( ptr, b->a_aci_at->ad_cname.bv_val );
}
#endif
#endif /* SLAP_DYNACL */
/* Security Strength Factors */
if ( b->a_authz.sai_ssf ) {
fprintf( stderr, " ssf=%u",
ptr += sprintf( ptr, " ssf=%u",
b->a_authz.sai_ssf );
}
if ( b->a_authz.sai_transport_ssf ) {
fprintf( stderr, " transport_ssf=%u",
ptr += sprintf( ptr, " transport_ssf=%u",
b->a_authz.sai_transport_ssf );
}
if ( b->a_authz.sai_tls_ssf ) {
fprintf( stderr, " tls_ssf=%u",
ptr += sprintf( ptr, " tls_ssf=%u",
b->a_authz.sai_tls_ssf );
}
if ( b->a_authz.sai_sasl_ssf ) {
fprintf( stderr, " sasl_ssf=%u",
ptr += sprintf( ptr, " sasl_ssf=%u",
b->a_authz.sai_sasl_ssf );
}
fprintf( stderr, " %s%s",
b->a_dn_self ? "self" : "",
accessmask2str( b->a_access_mask, maskbuf ) );
*ptr++ = ' ';
if ( b->a_dn_self ) {
ptr = lutil_strcopy( ptr, "self" );
} else if ( b->a_realdn_self ) {
ptr = lutil_strcopy( ptr, "realself" );
}
ptr = lutil_strcopy( ptr, accessmask2str( b->a_access_mask, maskbuf, 0 ));
if ( !maskbuf[0] ) ptr--;
if( b->a_type == ACL_BREAK ) {
fprintf( stderr, " break" );
ptr = lutil_strcopy( ptr, " break" );
} else if( b->a_type == ACL_CONTINUE ) {
fprintf( stderr, " continue" );
ptr = lutil_strcopy( ptr, " continue" );
} else if( b->a_type != ACL_STOP ) {
fprintf( stderr, " unknown-control" );
ptr = lutil_strcopy( ptr, " unknown-control" );
} else {
if ( !maskbuf[0] ) ptr = lutil_strcopy( ptr, " stop" );
}
*ptr++ = '\n';
fprintf( stderr, "\n" );
return ptr;
}
static void
print_acl( Backend *be, AccessControl *a )
void
acl_unparse( AccessControl *a, struct berval *bv )
{
int to = 0;
Access *b;
char *ptr;
int to = 0;
fprintf( stderr, "%s ACL: access to",
be == NULL ? "Global" : "Backend" );
bv->bv_val = aclbuf;
bv->bv_len = 0;
if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ) {
ptr = bv->bv_val;
ptr = lutil_strcopy( ptr, "to" );
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
to++;
fprintf( stderr, " dn.%s=\"%s\"\n",
style_strings[a->acl_dn_style], a->acl_dn_pat.bv_val );
ptr = lutil_strcopy( ptr, " dn." );
if ( a->acl_dn_style == ACL_STYLE_BASE )
ptr = lutil_strcopy( ptr, style_base );
else
ptr = lutil_strcopy( ptr, style_strings[a->acl_dn_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, a->acl_dn_pat.bv_val );
ptr = lutil_strcopy( ptr, "\"\n" );
}
if ( a->acl_filter != NULL ) {
......@@ -2226,7 +2557,10 @@ print_acl( Backend *be, AccessControl *a )
to++;
filter2bv( a->acl_filter, &bv );
fprintf( stderr, " filter=%s\n", bv.bv_val );
ptr = lutil_strcopy( ptr, " filter=\"" );
ptr = lutil_strcopy( ptr, bv.bv_val );
*ptr++ = '"';
*ptr++ = '\n';
ch_free( bv.bv_val );
}
......@@ -2235,34 +2569,57 @@ print_acl( Backend *be, AccessControl *a )
AttributeName *an;
to++;
fprintf( stderr, " attrs=" );
ptr = lutil_strcopy( ptr, " attrs=" );
for ( an = a->acl_attrs; an && !BER_BVISNULL( &an->an_name ); an++ ) {
if ( ! first ) fprintf( stderr, "," );
if ( ! first ) *ptr++ = ',';
if (an->an_oc) {
fputc( an->an_oc_exclude ? '!' : '@', stderr);
fputs( an->an_oc->soc_cname.bv_val, stderr );
*ptr++ = an->an_oc_exclude ? '!' : '@';
ptr = lutil_strcopy( ptr, an->an_oc->soc_cname.bv_val );
} else {
fputs( an->an_name.bv_val, stderr );
ptr = lutil_strcopy( ptr, an->an_name.bv_val );
}
first = 0;
}
fprintf( stderr, "\n" );
*ptr++ = '\n';
}
if ( !BER_BVISEMPTY( &a->acl_attrval ) ) {
to++;
fprintf( stderr, " val.%s=\"%s\"\n",
style_strings[a->acl_attrval_style], a->acl_attrval.bv_val );
ptr = lutil_strcopy( ptr, " val." );
if ( a->acl_attrval_style == ACL_STYLE_BASE &&
a->acl_attrs[0].an_desc->ad_type->sat_syntax ==
slap_schema.si_syn_distinguishedName )
ptr = lutil_strcopy( ptr, style_base );
else
ptr = lutil_strcopy( ptr, style_strings[a->acl_attrval_style] );
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, a->acl_attrval.bv_val );
*ptr++ = '"';
*ptr++ = '\n';
}
if( !to ) fprintf( stderr, " *\n" );
if( !to ) {
ptr = lutil_strcopy( ptr, " *\n" );
}
for ( b = a->acl_access; b != NULL; b = b->a_next ) {
print_access( b );
ptr = access2text( b, ptr );
}
*ptr = '\0';
bv->bv_len = ptr - bv->bv_val;
}
#ifdef LDAP_DEBUG
static void
print_acl( Backend *be, AccessControl *a )
{
struct berval bv;
fprintf( stderr, "\n" );
acl_unparse( a, &bv );
fprintf( stderr, "%s ACL: access %s\n",
be == NULL ? "Global" : "Backend", bv.bv_val );
}
#endif /* LDAP_DEBUG */
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -49,7 +49,6 @@ do_add( Operation *op, SlapReply *rs )
struct berval dn = BER_BVNULL;
ber_len_t len;
ber_tag_t tag;
Entry *e;
Modifications *modlist = NULL;
Modifications **modtail = &modlist;
Modifications tmp;
......@@ -77,7 +76,7 @@ do_add( Operation *op, SlapReply *rs )
return SLAPD_DISCONNECT;
}
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
op->ora_e = (Entry *) ch_calloc( 1, sizeof(Entry) );
rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
op->o_tmpmemctx );
......@@ -88,10 +87,10 @@ do_add( Operation *op, SlapReply *rs )
goto done;
}
ber_dupbv( &e->e_name, &op->o_req_dn );
ber_dupbv( &e->e_nname, &op->o_req_ndn );
ber_dupbv( &op->ora_e->e_name, &op->o_req_dn );
ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
Debug( LDAP_DEBUG_ARGS, "do_add: dn (%s)\n", e->e_dn, 0, 0 );
Debug( LDAP_DEBUG_ARGS, "do_add: dn (%s)\n", op->ora_e->e_dn, 0, 0 );
/* get the attrs */
for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
......@@ -121,6 +120,7 @@ do_add( Operation *op, SlapReply *rs )
mod = (Modifications *) ch_malloc( sizeof(Modifications) );
mod->sml_op = LDAP_MOD_ADD;
mod->sml_flags = 0;
mod->sml_next = NULL;
mod->sml_desc = NULL;
mod->sml_type = tmp.sml_type;
......@@ -150,22 +150,22 @@ do_add( Operation *op, SlapReply *rs )
}
Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n",
op->o_log_prefix, e->e_name.bv_val, 0, 0, 0 );
op->o_log_prefix, op->ora_e->e_name.bv_val, 0, 0, 0 );
if ( dn_match( &e->e_nname, &slap_empty_bv ) ) {
if ( dn_match( &op->ora_e->e_nname, &slap_empty_bv ) ) {
/* protocolError may be a more appropriate error */
send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
"root DSE already exists" );
goto done;
} else if ( dn_match( &e->e_nname, &frontendDB->be_schemandn ) ) {
} else if ( dn_match( &op->ora_e->e_nname, &frontendDB->be_schemandn ) ) {
send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
"subschema subentry already exists" );
goto done;
}
rs->sr_err = slap_mods_check( modlist, &rs->sr_text,
textbuf, textlen, NULL );
textbuf, textlen, NULL );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
......@@ -173,13 +173,23 @@ do_add( Operation *op, SlapReply *rs )
}
/* temporary; remove if not invoking backend function */
op->ora_e = e;
op->ora_modlist = modlist;
op->o_bd = frontendDB;
rc = frontendDB->be_add( op, rs );
if ( rc == 0 ) {
e = NULL;
if ( op->ora_e != NULL && op->o_private != NULL ) {
BackendDB *bd = op->o_bd;
op->o_bd = (BackendDB *)op->o_private;
op->o_private = NULL;
be_entry_release_w( op, op->ora_e );
op->ora_e = NULL;
op->o_bd = bd;
op->o_private = NULL;
}
}
done:;
......@@ -188,8 +198,8 @@ done:;
if ( modlist != NULL ) {
slap_mods_free( modlist );
}
if ( e != NULL ) {
entry_free( e );
if ( op->ora_e != NULL ) {
entry_free( op->ora_e );
}
op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
......@@ -201,10 +211,12 @@ int
fe_op_add( Operation *op, SlapReply *rs )
{
int manageDSAit;
Entry *e = op->ora_e;
Modifications *modlist = op->ora_modlist;
Modifications **modtail = &modlist;
int rc = 0;
BackendDB *op_be;
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
manageDSAit = get_manageDSAit( op );
......@@ -213,25 +225,35 @@ fe_op_add( Operation *op, SlapReply *rs )
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
op->o_bd = select_backend( &e->e_nname, manageDSAit, 1 );
op->o_bd = select_backend( &op->ora_e->e_nname, manageDSAit, 1 );
if ( op->o_bd == NULL ) {
rs->sr_ref = referral_rewrite( default_referral,
NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
NULL, &op->ora_e->e_name, LDAP_SCOPE_DEFAULT );
if ( !rs->sr_ref ) rs->sr_ref = default_referral;
if ( rs->sr_ref ) {
rs->sr_err = LDAP_REFERRAL;
op->o_bd = frontendDB;
send_ldap_result( op, rs );
op->o_bd = NULL;
if ( rs->sr_ref != default_referral ) {
ber_bvarray_free( rs->sr_ref );
}
} else {
op->o_bd = frontendDB;
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"no global superior knowledge" );
op->o_bd = NULL;
}
goto done;
}
/* If we've got a glued backend, check the real backend */
op_be = op->o_bd;
if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
op->o_bd = select_backend( &op->ora_e->e_nname, manageDSAit, 0 );
}
/* check restrictions */
if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
......@@ -243,8 +265,16 @@ fe_op_add( Operation *op, SlapReply *rs )
goto done;
}
rs->sr_err = slap_mods_obsolete_check( op, modlist,
&rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
#ifdef LDAP_SLAPI
if ( op->o_pb ) init_add_pblock( op, &op->o_req_dn, e, manageDSAit );
if ( op->o_pb ) init_add_pblock( op, &op->o_req_dn, op->ora_e, manageDSAit );
#endif /* LDAP_SLAPI */
/*
......@@ -261,14 +291,13 @@ fe_op_add( Operation *op, SlapReply *rs )
#endif
{
int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
op->o_bd = op_be;
if ( !update ) {
rs->sr_err = slap_mods_no_update_check( modlist,
&rs->sr_text,
textbuf, textlen );
rs->sr_err = slap_mods_no_user_mod_check( op, modlist,
&rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
......@@ -295,8 +324,8 @@ fe_op_add( Operation *op, SlapReply *rs )
}
}
rs->sr_err = slap_mods2entry( modlist, &e, repl_user, 0,
&rs->sr_text, textbuf, textlen );
rs->sr_err = slap_mods2entry( modlist, &op->ora_e,
repl_user, 0, &rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
......@@ -316,7 +345,6 @@ fe_op_add( Operation *op, SlapReply *rs )
}
#endif /* LDAP_SLAPI */
op->ora_e = e;
#ifdef SLAPD_MULTIMASTER
if ( !repl_user )
#endif
......@@ -324,16 +352,14 @@ fe_op_add( Operation *op, SlapReply *rs )
cb.sc_next = op->o_callback;
op->o_callback = &cb;
}
rc = (op->o_bd->be_add)( op, rs );
if ( rc == 0 ) {
/* FIXME: be_entry_release_w() should be
rc = op->o_bd->be_add( op, rs );
if ( rc == LDAP_SUCCESS ) {
/* NOTE: be_entry_release_w() is
* called by do_add(), so that global
* overlays on the way back can
* at least read the entry */
be_entry_release_w( op, e );
e = NULL;
op->o_private = op->o_bd;
}
op->ora_e = NULL;
#ifndef SLAPD_MULTIMASTER
} else {
......@@ -357,7 +383,7 @@ fe_op_add( Operation *op, SlapReply *rs )
if ( defref != NULL ) {
rs->sr_ref = referral_rewrite( defref,
NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
NULL, &op->ora_e->e_name, LDAP_SCOPE_DEFAULT );
if ( rs->sr_ref == NULL ) rs->sr_ref = defref;
rs->sr_err = LDAP_REFERRAL;
if (!rs->sr_ref) rs->sr_ref = default_referral;
......@@ -486,56 +512,34 @@ slap_mods2entry(
if( mods->sml_values[1].bv_val != NULL ) {
/* check for duplicates */
int i, j;
int i, j, rc, match;
MatchingRule *mr = mods->sml_desc->ad_type->sat_equality;
/* check if the values we're adding already exist */
if( mr == NULL || !mr->smr_match ) {
for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
/* test asserted values against themselves */
for( j = 0; j < i; j++ ) {
if ( bvmatch( &mods->sml_values[i],
&mods->sml_values[j] ) )
{
/* value exists already */
snprintf( textbuf, textlen,
"%s: value #%d provided more than once",
mods->sml_desc->ad_cname.bv_val, j );
return LDAP_TYPE_OR_VALUE_EXISTS;
}
}
}
} else {
int rc;
int match;
for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
/* test asserted values against themselves */
for( j = 0; j < i; j++ ) {
rc = value_match( &match, mods->sml_desc, mr,
SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
mods->sml_nvalues
? &mods->sml_nvalues[i]
: &mods->sml_values[i],
mods->sml_nvalues
? &mods->sml_nvalues[j]
: &mods->sml_values[j],
text );
if ( rc == LDAP_SUCCESS && match == 0 ) {
/* value exists already */
snprintf( textbuf, textlen,
"%s: value #%d provided more than once",
mods->sml_desc->ad_cname.bv_val, j );
return LDAP_TYPE_OR_VALUE_EXISTS;
} else if ( rc != LDAP_SUCCESS ) {
return rc;
}
for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
/* test asserted values against themselves */
for( j = 0; j < i; j++ ) {
rc = ordered_value_match( &match, mods->sml_desc, mr,
SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
mods->sml_nvalues
? &mods->sml_nvalues[i]
: &mods->sml_values[i],
mods->sml_nvalues
? &mods->sml_nvalues[j]
: &mods->sml_values[j],
text );
if ( rc == LDAP_SUCCESS && match == 0 ) {
/* value exists already */
snprintf( textbuf, textlen,
"%s: value #%d provided more than once",
mods->sml_desc->ad_cname.bv_val, j );
return LDAP_TYPE_OR_VALUE_EXISTS;
} else if ( rc != LDAP_SUCCESS ) {
return rc;
}
}
}
......@@ -583,6 +587,8 @@ slap_mods2entry(
tail = &attr->a_next;
}
*text = NULL;
return LDAP_SUCCESS;
}
......@@ -607,6 +613,7 @@ slap_entry2mods(
mod = (Modifications *) malloc( sizeof( Modifications ));
mod->sml_op = LDAP_MOD_REPLACE;
mod->sml_flags = 0;
mod->sml_type = a_new_desc->ad_cname;
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -57,8 +57,11 @@ struct aindexrec {
};
static Avlnode *attr_index = NULL;
static LDAP_SLIST_HEAD(ATList, slap_attribute_type) attr_list
= LDAP_SLIST_HEAD_INITIALIZER(&attr_list);
static Avlnode *attr_cache = NULL;
static LDAP_STAILQ_HEAD(ATList, slap_attribute_type) attr_list
= LDAP_STAILQ_HEAD_INITIALIZER(attr_list);
int at_oc_cache;
static int
attr_index_cmp(
......@@ -100,8 +103,18 @@ at_bvfind( struct berval *name )
{
struct aindexrec *air;
if ( attr_cache ) {
air = avl_find( attr_cache, name, attr_index_name_cmp );
if ( air ) return air->air_at;
}
air = avl_find( attr_index, name, attr_index_name_cmp );
if ( air && ( slapMode & SLAP_TOOL_MODE ) && at_oc_cache ) {
avl_insert( &attr_cache, (caddr_t) air,
attr_index_cmp, avl_dup_error );
}
return air != NULL ? air->air_at : NULL;
}
......@@ -197,9 +210,9 @@ at_destroy( void )
AttributeType *a;
avl_free(attr_index, ldap_memfree);
while( !LDAP_SLIST_EMPTY(&attr_list) ) {
a = LDAP_SLIST_FIRST(&attr_list);
LDAP_SLIST_REMOVE_HEAD(&attr_list, sat_next);
while( !LDAP_STAILQ_EMPTY(&attr_list) ) {
a = LDAP_STAILQ_FIRST(&attr_list);
LDAP_STAILQ_REMOVE_HEAD(&attr_list, sat_next);
if (a->sat_subtypes) ldap_memfree(a->sat_subtypes);
ad_destroy(a->sat_ad);
......@@ -217,7 +230,7 @@ at_start( AttributeType **at )
{
assert( at );
*at = LDAP_SLIST_FIRST(&attr_list);
*at = LDAP_STAILQ_FIRST(&attr_list);
return (*at != NULL);
}
......@@ -231,7 +244,7 @@ at_next( AttributeType **at )
{
AttributeType *tmp = NULL;
LDAP_SLIST_FOREACH(tmp,&attr_list,sat_next) {
LDAP_STAILQ_FOREACH(tmp,&attr_list,sat_next) {
if ( tmp == *at ) {
break;
}
......@@ -241,11 +254,61 @@ at_next( AttributeType **at )
}
#endif
*at = LDAP_SLIST_NEXT(*at,sat_next);
*at = LDAP_STAILQ_NEXT(*at,sat_next);
return (*at != NULL);
}
/*
* check whether the two attributeTypes actually __are__ identical,
* or rather inconsistent
*/
static int
at_check_dup(
AttributeType *sat,
AttributeType *new_sat )
{
if ( new_sat->sat_oid != NULL ) {
if ( sat->sat_oid == NULL ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
if ( strcmp( sat->sat_oid, new_sat->sat_oid ) != 0 ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
} else {
if ( sat->sat_oid != NULL ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
}
if ( new_sat->sat_names ) {
int i;
if ( sat->sat_names == NULL ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
for ( i = 0; new_sat->sat_names[ i ]; i++ ) {
if ( sat->sat_names[ i ] == NULL ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
if ( strcasecmp( sat->sat_names[ i ],
new_sat->sat_names[ i ] ) != 0 )
{
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
}
} else {
if ( sat->sat_names != NULL ) {
return SLAP_SCHERR_ATTR_INCONSISTENT;
}
}
return SLAP_SCHERR_ATTR_DUP;
}
static int
......@@ -256,8 +319,6 @@ at_insert(
struct aindexrec *air;
char **names;
LDAP_SLIST_NEXT( sat, sat_next ) = NULL;
LDAP_SLIST_INSERT_HEAD( &attr_list, sat, sat_next );
if ( sat->sat_oid ) {
air = (struct aindexrec *)
......@@ -266,16 +327,27 @@ at_insert(
air->air_name.bv_len = strlen(sat->sat_oid);
air->air_at = sat;
if ( avl_insert( &attr_index, (caddr_t) air,
attr_index_cmp, avl_dup_error ) ) {
attr_index_cmp, avl_dup_error ) )
{
AttributeType *old_sat;
int rc;
*err = sat->sat_oid;
ldap_memfree(air);
return SLAP_SCHERR_ATTR_DUP;
old_sat = at_bvfind( &air->air_name );
assert( old_sat != NULL );
rc = at_check_dup( old_sat, sat );
ldap_memfree( air );
return rc;
}
/* FIX: temporal consistency check */
at_bvfind(&air->air_name);
at_bvfind( &air->air_name );
}
if ( (names = sat->sat_names) ) {
names = sat->sat_names;
if ( names ) {
while ( *names ) {
air = (struct aindexrec *)
ch_calloc( 1, sizeof(struct aindexrec) );
......@@ -283,10 +355,20 @@ at_insert(
air->air_name.bv_len = strlen(*names);
air->air_at = sat;
if ( avl_insert( &attr_index, (caddr_t) air,
attr_index_cmp, avl_dup_error ) ) {
attr_index_cmp, avl_dup_error ) )
{
AttributeType *old_sat;
int rc;
*err = *names;
old_sat = at_bvfind( &air->air_name );
assert( old_sat != NULL );
rc = at_check_dup( old_sat, sat );
ldap_memfree(air);
return SLAP_SCHERR_ATTR_DUP;
return rc;
}
/* FIX: temporal consistency check */
at_bvfind(&air->air_name);
......@@ -294,12 +376,16 @@ at_insert(
}
}
LDAP_STAILQ_INSERT_TAIL( &attr_list, sat, sat_next );
return 0;
}
int
at_add(
LDAPAttributeType *at,
int user,
AttributeType **rsat,
const char **err )
{
AttributeType *sat;
......@@ -309,6 +395,7 @@ at_add(
int code;
char *cname;
char *oid;
char *oidm = NULL;
if ( !OID_LEADCHAR( at->at_oid[0] )) {
/* Expand OID macros */
......@@ -318,7 +405,7 @@ at_add(
return SLAP_SCHERR_OIDM;
}
if ( oid != at->at_oid ) {
ldap_memfree( at->at_oid );
oidm = at->at_oid;
at->at_oid = oid;
}
}
......@@ -380,6 +467,7 @@ at_add(
sat->sat_cname.bv_val = cname;
sat->sat_cname.bv_len = strlen( cname );
sat->sat_oidmacro = oidm;
ldap_pvt_thread_mutex_init(&sat->sat_ad_mutex);
if ( at->at_sup_oid ) {
......@@ -425,6 +513,29 @@ at_add(
sat->sat_substr = sat->sat_sup->sat_substr;
}
/*
* check for X-ORDERED attributes
*/
if ( sat->sat_extensions ) {
for (i=0; sat->sat_extensions[i]; i++) {
if (!strcasecmp( sat->sat_extensions[i]->lsei_name,
"X-ORDERED" ) && sat->sat_extensions[i]->lsei_values ) {
if ( !strcasecmp( sat->sat_extensions[i]->lsei_values[0],
"VALUES" )) {
sat->sat_flags |= SLAP_AT_ORDERED_VAL;
break;
} else if ( !strcasecmp( sat->sat_extensions[i]->lsei_values[0],
"SIBLINGS" )) {
sat->sat_flags |= SLAP_AT_ORDERED_SIB;
break;
}
}
}
}
if ( !user )
sat->sat_flags |= SLAP_AT_HARDCODE;
if ( at->at_syntax_oid ) {
syn = syn_find(sat->sat_syntax_oid);
if ( syn == NULL ) {
......@@ -565,7 +676,9 @@ at_add(
sat->sat_substr = mr;
}
code = at_insert(sat,err);
code = at_insert( sat, err );
if ( code == 0 && rsat )
*rsat = sat;
return code;
}
......@@ -588,6 +701,63 @@ at_index_print( void )
}
#endif
void
at_unparse( BerVarray *res, AttributeType *start, AttributeType *end, int sys )
{
AttributeType *at;
int i, num;
struct berval bv, *bva = NULL, idx;
char ibuf[32];
if ( !start )
start = LDAP_STAILQ_FIRST( &attr_list );
/* count the result size */
i = 0;
for ( at=start; at; at=LDAP_STAILQ_NEXT(at, sat_next)) {
if ( sys && !(at->sat_flags & SLAP_AT_HARDCODE)) continue;
i++;
if ( at == end ) break;
}
if (!i) return;
num = i;
bva = ch_malloc( (num+1) * sizeof(struct berval) );
BER_BVZERO( bva );
idx.bv_val = ibuf;
if ( sys ) {
idx.bv_len = 0;
ibuf[0] = '\0';
}
i = 0;
for ( at=start; at; at=LDAP_STAILQ_NEXT(at, sat_next)) {
LDAPAttributeType lat, *latp;
if ( sys && !(at->sat_flags & SLAP_AT_HARDCODE)) continue;
if ( at->sat_oidmacro ) {
lat = at->sat_atype;
lat.at_oid = at->sat_oidmacro;
latp = &lat;
} else {
latp = &at->sat_atype;
}
if ( ldap_attributetype2bv( latp, &bv ) == NULL ) {
ber_bvarray_free( bva );
}
if ( !sys ) {
idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
}
bva[i].bv_len = idx.bv_len + bv.bv_len;
bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
strcpy( bva[i].bv_val, ibuf );
strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
i++;
bva[i].bv_val = NULL;
ldap_memfree( bv.bv_val );
if ( at == end ) break;
}
*res = bva;
}
int
at_schema_info( Entry *e )
{
......@@ -596,15 +766,14 @@ at_schema_info( Entry *e )
struct berval val;
struct berval nval;
LDAP_SLIST_FOREACH(at,&attr_list,sat_next) {
LDAP_STAILQ_FOREACH(at,&attr_list,sat_next) {
if( at->sat_flags & SLAP_AT_HIDE ) continue;
if ( ldap_attributetype2bv( &at->sat_atype, &val ) == NULL ) {
return -1;
}
nval.bv_val = at->sat_oid;
nval.bv_len = strlen(at->sat_oid);
ber_str2bv( at->sat_oid, 0, 0, &nval );
if( attr_merge_one( e, ad_attributeTypes, &val, &nval ) )
{
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -40,13 +40,36 @@
#include "slap.h"
Attribute *
attr_alloc( AttributeDescription *ad )
{
Attribute *a = ch_malloc( sizeof(Attribute) );
a->a_desc = ad;
a->a_next = NULL;
a->a_flags = 0;
a->a_vals = NULL;
a->a_nvals = NULL;
#ifdef LDAP_COMP_MATCH
a->a_comp_data = NULL;
#endif
return a;
}
void
attr_free( Attribute *a )
{
if ( a->a_nvals && a->a_nvals != a->a_vals ) {
ber_bvarray_free( a->a_nvals );
}
ber_bvarray_free( a->a_vals );
/* a_vals may be equal to slap_dummy_bv, a static empty berval;
* this is used as a placeholder for attributes that do not carry
* values, e.g. when proxying search entries with the "attrsonly"
* bit set. */
if ( a->a_vals != &slap_dummy_bv ) {
ber_bvarray_free( a->a_vals );
}
free( a );
}
......@@ -85,7 +108,7 @@ attr_dup( Attribute *a )
if ( a == NULL) return NULL;
tmp = ch_malloc( sizeof(Attribute) );
tmp = attr_alloc( a->a_desc );
if ( a->a_vals != NULL ) {
int i;
......@@ -122,14 +145,6 @@ attr_dup( Attribute *a )
tmp->a_vals = NULL;
tmp->a_nvals = NULL;
}
tmp->a_desc = a->a_desc;
tmp->a_next = NULL;
tmp->a_flags = 0;
#ifdef LDAP_COMP_MATCH
tmp->a_comp_data = NULL;
#endif
return tmp;
}
......@@ -153,7 +168,6 @@ attrs_dup( Attribute *a )
}
/*
* attr_merge - merge the given type and value with the list of
* attributes in attrs.
......@@ -177,21 +191,20 @@ attr_merge(
Attribute **a;
for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
if ( ad_cmp( (*a)->a_desc, desc ) == 0 ) {
if ( (*a)->a_desc == desc ) {
break;
}
}
if ( *a == NULL ) {
*a = (Attribute *) ch_malloc( sizeof(Attribute) );
(*a)->a_desc = desc;
(*a)->a_vals = NULL;
(*a)->a_nvals = NULL;
(*a)->a_next = NULL;
(*a)->a_flags = 0;
#ifdef LDAP_COMP_MATCH
(*a)->a_comp_data = NULL;
#endif
*a = attr_alloc( desc );
} else {
/*
* FIXME: if the attribute already exists, the presence
* of nvals and the value of (*a)->a_nvals must be consistent
*/
assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals )
|| ( nvals != NULL && (*a)->a_nvals != (*a)->a_vals ) );
}
rc = value_add( &(*a)->a_vals, vals );
......@@ -261,21 +274,13 @@ attr_merge_one(
Attribute **a;
for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
if ( ad_cmp( (*a)->a_desc, desc ) == 0 ) {
if ( (*a)->a_desc == desc ) {
break;
}
}
if ( *a == NULL ) {
*a = (Attribute *) ch_malloc( sizeof(Attribute) );
(*a)->a_desc = desc;
(*a)->a_vals = NULL;
(*a)->a_nvals = NULL;
(*a)->a_next = NULL;
(*a)->a_flags = 0;
#ifdef LDAP_COMP_MATCH
(*a)->a_comp_data = NULL;
#endif
*a = attr_alloc( desc );
}
rc = value_add_one( &(*a)->a_vals, val );
......@@ -353,7 +358,7 @@ attr_find(
AttributeDescription *desc )
{
for ( ; a != NULL; a = a->a_next ) {
if ( ad_cmp( a->a_desc, desc ) == 0 ) {
if ( a->a_desc == desc ) {
return( a );
}
}
......@@ -376,7 +381,7 @@ attr_delete(
Attribute **a;
for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
if ( ad_cmp( (*a)->a_desc, desc ) == 0 ) {
if ( (*a)->a_desc == desc ) {
Attribute *save = *a;
*a = (*a)->a_next;
attr_free( save );
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2004 The OpenLDAP Foundation.
* Copyright 1998-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -33,6 +33,9 @@
#include "slap.h"
#ifdef LDAP_COMP_MATCH
#include "component.h"
#endif
void
ava_free(
......@@ -40,6 +43,10 @@ ava_free(
AttributeAssertion *ava,
int freeit )
{
#ifdef LDAP_COMP_MATCH
if ( ava->aa_cf && ava->aa_cf->cf_ca->ca_comp_data.cd_mem_op )
nibble_mem_free ( ava->aa_cf->cf_ca->ca_comp_data.cd_mem_op );
#endif
op->o_tmpfree( ava->aa_value.bv_val, op->o_tmpmemctx );
if ( freeit ) op->o_tmpfree( (char *) ava, op->o_tmpmemctx );
}
......@@ -56,6 +63,9 @@ get_ava(
ber_tag_t rtag;
struct berval type, value;
AttributeAssertion *aa;
#ifdef LDAP_COMP_MATCH
AttributeAliasing* a_alias = NULL;
#endif
rtag = ber_scanf( ber, "{mm}", &type, &value );
......@@ -68,6 +78,9 @@ get_ava(
aa = op->o_tmpalloc( sizeof( AttributeAssertion ), op->o_tmpmemctx );
aa->aa_desc = NULL;
aa->aa_value.bv_val = NULL;
#ifdef LDAP_COMP_MATCH
aa->aa_cf = NULL;
#endif
rc = slap_bv2ad( &type, &aa->aa_desc, text );
......@@ -89,6 +102,19 @@ get_ava(
return rc;
}
#ifdef LDAP_COMP_MATCH
if( is_aliased_attribute ) {
a_alias = is_aliased_attribute ( aa->aa_desc );
if ( a_alias ) {
rc = get_aliased_filter_aa ( op, aa, a_alias, text );
if( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_FILTER,
"get_ava:Invalid Attribute Aliasing\n", 0, 0, 0 );
return rc;
}
}
}
#endif
*ava = aa;
return LDAP_SUCCESS;
}
......@@ -2,7 +2,7 @@
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2004 The OpenLDAP Foundation.
## Copyright 1998-2005 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
......@@ -18,14 +18,14 @@ SRCS = init.c tools.c config.c \
extended.c referral.c operational.c \
attr.c index.c key.c dbcache.c filterindex.c \
dn2entry.c dn2id.c error.c id2entry.c idl.c \
nextid.c cache.c trans.c ctxcsn.c
nextid.c cache.c trans.c alock.c
OBJS = init.lo tools.lo config.lo \
add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \
extended.lo referral.lo operational.lo \
attr.lo index.lo key.lo dbcache.lo filterindex.lo \
dn2entry.lo dn2id.lo error.lo id2entry.lo idl.lo \
nextid.lo cache.lo trans.lo ctxcsn.lo
nextid.lo cache.lo trans.lo alock.lo
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
......
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -42,12 +42,6 @@ bdb_add(Operation *op, SlapReply *rs )
int num_retries = 0;
Operation* ps_list;
int rc;
EntryInfo *suffix_ei = NULL;
Entry *ctxcsn_e;
int ctxcsn_added = 0;
LDAPControl **postread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
......@@ -58,8 +52,8 @@ bdb_add(Operation *op, SlapReply *rs )
ctrls[num_ctrls] = 0;
/* check entry's schema */
rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
NULL, &rs->sr_text, textbuf, textlen );
rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e, NULL,
get_manageDIT(op), &rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(bdb_add) ": entry failed schema check: "
......@@ -101,6 +95,10 @@ retry: /* transaction retry */
rs->sr_text = "internal error";
goto return_results;
}
if ( op->o_abandon ) {
rs->sr_err = SLAPD_ABANDON;
goto return_results;
}
ldap_pvt_thread_yield();
bdb_trans_backoff( ++num_retries );
}
......@@ -183,7 +181,7 @@ retry: /* transaction retry */
}
rs->sr_err = access_allowed( op, p,
children, NULL, ACL_WRITE, NULL );
children, NULL, ACL_WADD, NULL );
if ( ! rs->sr_err ) {
switch( opinfo.boi_err ) {
......@@ -193,8 +191,8 @@ retry: /* transaction retry */
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(bdb_add) ": no write access "
"to parent\n", 0, 0, 0 );
LDAP_XSTRING(bdb_add) ": no write access to parent\n",
0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to parent";
goto return_results;;
......@@ -278,7 +276,7 @@ retry: /* transaction retry */
}
rs->sr_err = access_allowed( op, op->oq_add.rs_e,
entry, NULL, ACL_WRITE, NULL );
entry, NULL, ACL_WADD, NULL );
if ( ! rs->sr_err ) {
switch( opinfo.boi_err ) {
......@@ -367,19 +365,6 @@ retry: /* transaction retry */
goto return_results;
}
#ifdef BDB_PSEARCH
if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei,
&ctxcsn_e, &ctxcsn_added, locker );
switch ( rc ) {
case BDB_CSN_ABORT :
goto return_results;
case BDB_CSN_RETRY :
goto retry;
}
}
#endif
/* post-read */
if( op->o_postread ) {
if( postread_ctrl == NULL ) {
......@@ -417,35 +402,6 @@ retry: /* transaction retry */
bdb_cache_add( bdb, ei, e, &nrdn, locker );
if ( suffix_ei == NULL ) {
suffix_ei = BEI(e);
}
#ifdef BDB_PSEARCH
if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
if ( ctxcsn_added ) {
bdb_cache_add( bdb, suffix_ei, ctxcsn_e,
(struct berval *)&slap_ldapsync_cn_bv, locker );
}
}
if ( rs->sr_err == LDAP_SUCCESS && !op->o_no_psearch ) {
ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
assert( BEI(e) );
LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
rc = bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_ADD );
if ( rc ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(bdb_add)
": persistent search failed "
"(%d,%d)\n",
rc, rs->sr_err, 0 );
}
}
ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
}
#endif
if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
rs->sr_text = "txn_commit failed";
} else {
......
/* alock.c - access lock library */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2005 The OpenLDAP Foundation.
* Portions Copyright 2004-2005 Symas Corporation.
* 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
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was initially developed by Matthew Backes at Symas
* Corporation for inclusion in OpenLDAP Software.
*/
#include "portable.h"
#include "alock.h"
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include <ac/errno.h>
#include <ac/assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#ifdef _WIN32
#include <stdio.h>
#include <io.h>
#include <sys/locking.h>
#endif
static int
alock_grab_lock ( int fd, int slot )
{
int res;
#if defined( HAVE_LOCKF )
res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
if (res == -1) return -1;
res = lockf (fd, F_LOCK, (off_t) ALOCK_SLOT_SIZE);
#elif defined( HAVE_FCNTL )
struct flock lock_info;
(void) memset ((void *) &lock_info, 0, sizeof (struct flock));
lock_info.l_type = F_WRLCK;
lock_info.l_whence = SEEK_SET;
lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
res = fcntl (fd, F_SETLKW, &lock_info);
#elif defined( _WIN32 )
if( _lseek( fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET ) < 0 )
return -1;
/*
* _lock will try for the lock once per second, returning EDEADLOCK
* after ten tries. We just loop until we either get the lock
* or some other error is returned.
*/
while((res = _locking( fd, _LK_LOCK, ALOCK_SLOT_SIZE )) < 0 ) {
if( errno != EDEADLOCK )
break;
}
#else
# error alock needs lockf, fcntl, or _locking
#endif
if (res == -1) {
assert (errno != EDEADLK);
return -1;
}
return 0;
}
static int
alock_release_lock ( int fd, int slot )
{
int res;
#if defined( HAVE_LOCKF )
res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
if (res == -1) return -1;
res = lockf (fd, F_ULOCK, (off_t) ALOCK_SLOT_SIZE);
if (res == -1) return -1;
#elif defined ( HAVE_FCNTL )
struct flock lock_info;
(void) memset ((void *) &lock_info, 0, sizeof (struct flock));
lock_info.l_type = F_UNLCK;
lock_info.l_whence = SEEK_SET;
lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
res = fcntl (fd, F_SETLKW, &lock_info);
if (res == -1) return -1;
#elif defined( _WIN32 )
res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
if (res == -1) return -1;
res = _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
if (res == -1) return -1;
#else
# error alock needs lockf, fcntl, or _locking
#endif
return 0;
}
static int
alock_test_lock ( int fd, int slot )
{
int res;
#if defined( HAVE_LOCKF )
res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
if (res == -1) return -1;
res = lockf (fd, F_TEST, (off_t) ALOCK_SLOT_SIZE);
if (res == -1) {
if (errno == EACCES || errno == EAGAIN) {
return ALOCK_LOCKED;
} else {
return -1;
}
}
#elif defined( HAVE_FCNTL )
struct flock lock_info;
(void) memset ((void *) &lock_info, 0, sizeof (struct flock));
lock_info.l_type = F_WRLCK;
lock_info.l_whence = SEEK_SET;
lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
res = fcntl (fd, F_GETLK, &lock_info);
if (res == -1) return -1;
if (lock_info.l_type != F_UNLCK) return ALOCK_LOCKED;
#elif defined( _WIN32 )
res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
if (res == -1) return -1;
res = _locking( fd, _LK_NBLCK, ALOCK_SLOT_SIZE );
_locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
if (res == -1) {
if( errno == EACCES ) {
return ALOCK_LOCKED;
} else {
return -1;
}
}
#else
# error alock needs lockf, fcntl, or _locking
#endif
return 0;
}
/* Read a 64bit LE value */
static unsigned long int
alock_read_iattr ( unsigned char * bufptr )
{
unsigned long int val = 0;
int count;
assert (bufptr != NULL);
bufptr += sizeof (unsigned long int);
for (count=0; count <= sizeof (unsigned long int); ++count) {
val <<= 8;
val += (unsigned long int) *bufptr--;
}
return val;
}
/* Write a 64bit LE value */
static void
alock_write_iattr ( unsigned char * bufptr,
unsigned long int val )
{
int count;
assert (bufptr != NULL);
for (count=0; count < 8; ++count) {
*bufptr++ = (unsigned char) (val & 0xff);
val >>= 8;
}
}
static int
alock_read_slot ( alock_info_t * info,
alock_slot_t * slot_data )
{
unsigned char slotbuf [ALOCK_SLOT_SIZE];
int res, size, size_total, err;
assert (info != NULL);
assert (slot_data != NULL);
assert (info->al_slot > 0);
res = lseek (info->al_fd,
(off_t) (ALOCK_SLOT_SIZE * info->al_slot),
SEEK_SET);
if (res == -1) return -1;
size_total = 0;
while (size_total < ALOCK_SLOT_SIZE) {
size = read (info->al_fd,
slotbuf + size_total,
ALOCK_SLOT_SIZE - size_total);
if (size == 0) return -1;
if (size < 0) {
err = errno;
if (err != EINTR && err != EAGAIN) return -1;
} else {
size_total += size;
}
}
if (alock_read_iattr (slotbuf) != ALOCK_MAGIC) {
return 1;
}
slot_data->al_lock = alock_read_iattr (slotbuf+8);
slot_data->al_stamp = alock_read_iattr (slotbuf+16);
slot_data->al_pid = alock_read_iattr (slotbuf+24);
if (slot_data->al_appname) free (slot_data->al_appname);
slot_data->al_appname = calloc (1, ALOCK_MAX_APPNAME);
strncpy (slot_data->al_appname, slotbuf+32, ALOCK_MAX_APPNAME-1);
(slot_data->al_appname) [ALOCK_MAX_APPNAME-1] = '\0';
return 0;
}
static int
alock_write_slot ( alock_info_t * info,
alock_slot_t * slot_data )
{
unsigned char slotbuf [ALOCK_SLOT_SIZE];
int res, size, size_total, err;
assert (info != NULL);
assert (slot_data != NULL);
assert (info->al_slot > 0);
(void) memset ((void *) slotbuf, 0, ALOCK_SLOT_SIZE);
alock_write_iattr (slotbuf, ALOCK_MAGIC);
assert (alock_read_iattr (slotbuf) == ALOCK_MAGIC);
alock_write_iattr (slotbuf+8, slot_data->al_lock);
alock_write_iattr (slotbuf+16, slot_data->al_stamp);
alock_write_iattr (slotbuf+24, slot_data->al_pid);
strncpy (slotbuf+32, slot_data->al_appname, ALOCK_MAX_APPNAME-1);
slotbuf[ALOCK_SLOT_SIZE-1] = '\0';
res = lseek (info->al_fd,
(off_t) (ALOCK_SLOT_SIZE * info->al_slot),
SEEK_SET);
if (res == -1) return -1;
size_total = 0;
while (size_total < ALOCK_SLOT_SIZE) {
size = write (info->al_fd,
slotbuf + size_total,
ALOCK_SLOT_SIZE - size_total);
if (size == 0) return -1;
if (size < 0) {
err = errno;
if (err != EINTR && err != EAGAIN) return -1;
} else {
size_total += size;
}
}
return 0;
}
static int
alock_query_slot ( alock_info_t * info )
{
int res;
alock_slot_t slot_data;
assert (info != NULL);
assert (info->al_slot > 0);
(void) memset ((void *) &slot_data, 0, sizeof (alock_slot_t));
alock_read_slot (info, &slot_data);
if (slot_data.al_lock == ALOCK_UNLOCKED) return ALOCK_UNLOCKED;
if (slot_data.al_appname != NULL) free (slot_data.al_appname);
slot_data.al_appname = NULL;
res = alock_test_lock (info->al_fd, info->al_slot);
if (res < 0) return -1;
if (res > 0) {
if (slot_data.al_lock == ALOCK_UNIQUE) {
return ALOCK_UNIQUE;
} else {
return ALOCK_LOCKED;
}
}
return ALOCK_DIRTY;
}
int
alock_open ( alock_info_t * info,
const char * appname,
const char * envdir,
int locktype )
{
struct stat statbuf;
alock_info_t scan_info;
alock_slot_t slot_data;
char * filename;
int res, max_slot;
int dirty_count, live_count;
assert (info != NULL);
assert (appname != NULL);
assert (envdir != NULL);
assert (locktype >= 1 && locktype <= 2);
slot_data.al_lock = locktype;
slot_data.al_stamp = time(NULL);
slot_data.al_pid = getpid();
slot_data.al_appname = calloc (1, ALOCK_MAX_APPNAME);
strncpy (slot_data.al_appname, appname, ALOCK_MAX_APPNAME-1);
slot_data.al_appname [ALOCK_MAX_APPNAME-1] = '\0';
filename = calloc (1, strlen (envdir) + strlen ("/alock") + 1);
strcpy (filename, envdir);
strcat (filename, "/alock");
info->al_fd = open (filename, O_CREAT|O_RDWR, 0666);
free (filename);
if (info->al_fd < 0) {
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
info->al_slot = 0;
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
res = fstat (info->al_fd, &statbuf);
if (res == -1) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
dirty_count = 0;
live_count = 0;
scan_info.al_fd = info->al_fd;
for (scan_info.al_slot = 1;
scan_info.al_slot < max_slot;
++ scan_info.al_slot) {
if (scan_info.al_slot != info->al_slot) {
res = alock_query_slot (&scan_info);
if (res == ALOCK_UNLOCKED
&& info->al_slot == 0) {
info->al_slot = scan_info.al_slot;
} else if (res == ALOCK_LOCKED) {
++live_count;
} else if (res == ALOCK_UNIQUE
&& locktype == ALOCK_UNIQUE) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_BUSY;
} else if (res == ALOCK_DIRTY) {
++dirty_count;
} else if (res == -1) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
}
}
if (dirty_count && live_count) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
if (info->al_slot == 0) info->al_slot = max_slot + 1;
res = alock_grab_lock (info->al_fd,
info->al_slot);
if (res == -1) {
close (info->al_fd);
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
res = alock_write_slot (info, &slot_data);
free (slot_data.al_appname);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
if (dirty_count) return ALOCK_RECOVER;
return ALOCK_CLEAN;
}
int
alock_scan ( alock_info_t * info )
{
struct stat statbuf;
alock_info_t scan_info;
int res, max_slot;
int dirty_count, live_count;
assert (info != NULL);
scan_info.al_fd = info->al_fd;
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
res = fstat (info->al_fd, &statbuf);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
dirty_count = 0;
live_count = 0;
for (scan_info.al_slot = 1;
scan_info.al_slot < max_slot;
++ scan_info.al_slot) {
if (scan_info.al_slot != info->al_slot) {
res = alock_query_slot (&scan_info);
if (res == ALOCK_LOCKED) {
++live_count;
} else if (res == ALOCK_DIRTY) {
++dirty_count;
} else if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
}
}
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
if (dirty_count) {
if (live_count) {
close (info->al_fd);
return ALOCK_UNSTABLE;
} else {
return ALOCK_RECOVER;
}
}
return ALOCK_CLEAN;
}
int
alock_close ( alock_info_t * info )
{
alock_slot_t slot_data;
int res;
(void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t));
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
/* mark our slot as clean */
res = alock_read_slot (info, &slot_data);
if (res == -1) {
close (info->al_fd);
if (slot_data.al_appname != NULL)
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
slot_data.al_lock = ALOCK_UNLOCKED;
res = alock_write_slot (info, &slot_data);
if (res == -1) {
close (info->al_fd);
if (slot_data.al_appname != NULL)
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
if (slot_data.al_appname != NULL) {
free (slot_data.al_appname);
slot_data.al_appname = NULL;
}
res = alock_release_lock (info->al_fd, info->al_slot);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
res = close (info->al_fd);
if (res == -1) return ALOCK_UNSTABLE;
return ALOCK_CLEAN;
}
int
alock_recover ( alock_info_t * info )
{
struct stat statbuf;
alock_slot_t slot_data;
alock_info_t scan_info;
int res, max_slot;
assert (info != NULL);
scan_info.al_fd = info->al_fd;
(void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t));
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
res = fstat (info->al_fd, &statbuf);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
for (scan_info.al_slot = 1;
scan_info.al_slot < max_slot;
++ scan_info.al_slot) {
if (scan_info.al_slot != info->al_slot) {
res = alock_query_slot (&scan_info);
if (res == ALOCK_LOCKED
|| res == ALOCK_UNIQUE) {
/* recovery attempt on an active db? */
close (info->al_fd);
return ALOCK_UNSTABLE;
} else if (res == ALOCK_DIRTY) {
/* mark it clean */
res = alock_read_slot (&scan_info, &slot_data);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
slot_data.al_lock = ALOCK_UNLOCKED;
res = alock_write_slot (&scan_info, &slot_data);
if (res == -1) {
close (info->al_fd);
if (slot_data.al_appname != NULL)
free (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
if (slot_data.al_appname != NULL) {
free (slot_data.al_appname);
slot_data.al_appname = NULL;
}
} else if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
}
}
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
return ALOCK_CLEAN;
}
/* alock.h - access lock header */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2005 The OpenLDAP Foundation.
* Portions Copyright 2004-2005 Symas Corporation.
* 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
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was initially developed by Matthew Backes at Symas
* Corporation for inclusion in OpenLDAP Software.
*/
#ifndef _ALOCK_H_
#define _ALOCK_H_
#include "portable.h"
#include <ac/time.h>
#include <ac/unistd.h>
/* environment states (all the slots together) */
#define ALOCK_CLEAN (0)
#define ALOCK_RECOVER (1)
#define ALOCK_BUSY (2)
#define ALOCK_UNSTABLE (3)
/* lock user types and states */
#define ALOCK_UNLOCKED (0)
#define ALOCK_LOCKED (1)
#define ALOCK_UNIQUE (2)
#define ALOCK_DIRTY (3)
/* constants */
#define ALOCK_SLOT_SIZE (1024)
#define ALOCK_SLOT_IATTRS (4)
#define ALOCK_MAX_APPNAME (ALOCK_SLOT_SIZE - 8 * ALOCK_SLOT_IATTRS)
#define ALOCK_MAGIC (0x12345678)
LDAP_BEGIN_DECL
typedef struct alock_info {
int al_fd;
int al_slot;
} alock_info_t;
typedef struct alock_slot {
unsigned int al_lock;
time_t al_stamp;
pid_t al_pid;
char * al_appname;
} alock_slot_t;
extern int alock_open LDAP_P(( alock_info_t * info, const char * appname,
const char * envdir, int locktype ));
extern int alock_scan LDAP_P(( alock_info_t * info ));
extern int alock_close LDAP_P(( alock_info_t * info ));
extern int alock_recover LDAP_P(( alock_info_t * info ));
LDAP_END_DECL
#endif
......@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2004 The OpenLDAP Foundation.
* Copyright 2000-2005 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -23,15 +23,8 @@
#include "slap.h"
#include "back-bdb.h"
#include "lutil.h"
/* for the cache of attribute information (which are indexed, etc.) */
typedef struct bdb_attrinfo {
AttributeDescription *ai_desc; /* attribute description cn;lang-en */
slap_mask_t ai_indexmask; /* how the attr is indexed */
#ifdef LDAP_COMP_MATCH
ComponentReference* ai_cr; /*component indexing*/
#endif
} AttrInfo;
static int
ainfo_type_cmp(
......@@ -54,32 +47,13 @@ ainfo_cmp(
return SLAP_PTRCMP(a->ai_desc, b->ai_desc);
}
#ifdef LDAP_COMP_MATCH
void
bdb_attr_comp_ref(
struct bdb_info *bdb,
AttributeDescription *desc,
ComponentReference** cr )
{
AttrInfo *a;
a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
*cr = a != NULL ? a->ai_cr : 0 ;
}
#endif
void
AttrInfo *
bdb_attr_mask(
struct bdb_info *bdb,
AttributeDescription *desc,
slap_mask_t *indexmask )
AttributeDescription *desc )
{
AttrInfo *a;
a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
*indexmask = a != NULL ? a->ai_indexmask : 0;
return avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
}
int
......@@ -235,7 +209,15 @@ bdb_attr_index_config(
ad->ad_cname.bv_val, mask, 0 );
a->ai_desc = ad;
a->ai_indexmask = mask;
if ( bdb->bi_flags & BDB_IS_OPEN ) {
a->ai_indexmask = 0;
a->ai_newmask = mask;
} else {
a->ai_indexmask = mask;
a->ai_newmask = 0;
}
#ifdef LDAP_COMP_MATCH
if ( cr ) {
a_cr = avl_find( bdb->bi_attrs, ad, ainfo_type_cmp );
......@@ -264,8 +246,19 @@ bdb_attr_index_config(
ainfo_cmp, avl_dup_error );
if( rc ) {
if ( bdb->bi_flags & BDB_IS_OPEN ) {
AttrInfo *b = avl_find( bdb->bi_attrs, ad, ainfo_type_cmp );
/* If we were editing this attr, reset it */
b->ai_indexmask &= ~BDB_INDEX_DELETING;
/* If this is leftover from a previous add, commit it */
if ( b->ai_newmask )
b->ai_indexmask = b->ai_newmask;
b->ai_newmask = a->ai_newmask;
ch_free( a );
continue;
}
fprintf( stderr, "%s: line %d: duplicate index definition "
"for attr \"%s\" (ignored)\n",
"for attr \"%s\"" SLAPD_CONF_UNKNOWN_IGNORED ".\n",
fname, lineno, attrs[i] );
return LDAP_PARAM_ERROR;
......@@ -278,9 +271,96 @@ bdb_attr_index_config(
return LDAP_SUCCESS;
}
static int
bdb_attr_index_unparser( void *v1, void *v2 )
{
AttrInfo *ai = v1;
BerVarray *bva = v2;
struct berval bv;
char *ptr;
slap_index2bvlen( ai->ai_indexmask, &bv );
if ( bv.bv_len ) {
bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
ptr = ch_malloc( bv.bv_len+1 );
bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
*bv.bv_val++ = ' ';
slap_index2bv( ai->ai_indexmask, &bv );
bv.bv_val = ptr;
ber_bvarray_add( bva, &bv );
}
}
static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
static AttrInfo aidef = { &addef };
void
bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva )
{
if ( bdb->bi_defaultmask ) {
aidef.ai_indexmask = bdb->bi_defaultmask;
bdb_attr_index_unparser( &aidef, bva );
}
avl_apply( bdb->bi_attrs, bdb_attr_index_unparser, bva, -1, AVL_INORDER );
}
static void
bdb_attrinfo_free( void *v )
{
AttrInfo *ai = v;
#ifdef LDAP_COMP_MATCH
free( ai->ai_cr );
#endif
free( ai );
}
void
bdb_attr_index_destroy( Avlnode *tree )
{
avl_free( tree, free );
avl_free( tree, bdb_attrinfo_free );
}
void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
{
AttrInfo *ai;
ai = avl_delete( &bdb->bi_attrs, ad, ainfo_type_cmp );
if ( ai )
bdb_attrinfo_free( ai );
}
/* Get a list of AttrInfo's to delete */
typedef struct Alist {
struct Alist *next;
AttrInfo *ptr;
} Alist;
static int
bdb_attrinfo_flush( void *v1, void *arg )
{
AttrInfo *ai = v1;
if ( ai->ai_indexmask & BDB_INDEX_DELETING ) {
Alist **al = arg;
Alist *a = ch_malloc( sizeof( Alist ));
a->ptr = ai;
a->next = *al;
*al = a;
}
return 0;
}
void bdb_attr_flush( struct bdb_info *bdb )
{
Alist *al = NULL, *a2;
avl_apply( bdb->bi_attrs, bdb_attrinfo_flush, &al, -1, AVL_INORDER );
while (( a2 = al )) {
al = al->next;
avl_delete( &bdb->bi_attrs, a2->ptr, ainfo_cmp );
bdb_attrinfo_free( a2->ptr );
ch_free( a2 );
}
}