Strong bind doesn't work in slapd-ldap when used by slapd-relay or slapo-translucent
by Martin Rubáš
Hello.
This is a kind of follow-up on my previous message "Trouble with
slapd-ldap in various scenarios (LdarErr: DSID-0C090627)" sent to
OpenLDAP-Technical. I did more research on topic including a code
debugging. I finally found the reason why it doesn't work and fixed the
code.
I have to use slapd-ldap in "strong bind" mode which means that user
binds using its own credentials and no identity assertion is performed.
If slapd-ldap is the only module that is processing request then
everything works fine. If slapd-ldap is processing an request forwarded
from slapd-relay (with slapo-rwm) or request to database with
slapo-translucent then the authentication problem occurs.
Let's suppose that we have remote LDAP server with disabled anonymous
binding. It could be Active Directory or OpenLDAP with following
configuration:
# --- config for remote server (remote.host.net) ---
# [cut-off] command schema, slapd files & logs definitions
# Load of modules:
modulepath /usr/lib/ldap
moduleload back_hdb.la
# VERY IMPORTANT: Disable anonymous binding
disallow bind_anon
# Configuration Database
database config
rootdn "cn=admin,cn=config"
rootpw secret
# realone.net - local Repository
database hdb
suffix "dc=realone,dc=net"
rootdn "cn=admin,dc=realone,dc=net"
rootpw secret
directory /var/lib/slapd/realone.net
index objectClass eq
index cn eq
index uid eq
Let's say there is a common content in database:
# --- Directory content (just an overview) ---
dn: dc=realone,dc=net # top, domain
dn: ou=people,dc=realone,dc=net # organizationalUnit
dn: ou=groups,dc=realone,dc=net # organizationalUnit
dn: cn=idassert,dc=realone,dc=net # simpleSecurityObject,
organizationalRole
dn: cn=admin,dc=realone,dc=net # same as above
dn: uid=super.account,ou=people,dc=realone,dc=net # inetOrgPerson,
posixAccount, shadowAccount
dn: uid=power.account,ou=people,dc=realone,dc=net # same as above
dn: uid=basic.account,ou=people,dc=realone,dc=net # same as above
dn: cn=admins,ou=groups,dc=realone,dc=net # posixGroup
dn: cn=users,ou=groups,dc=realone,dc=net # same as above
I want to use another OpenLDAP server that is configured with
slapo-translucent:
# --- config for local server (trans.local.net) ---
# [cut-off] command schema, slapd files & logs definitions
# Configuration Database
database config
rootdn "cn=admin,cn=config"
rootpw secret
# realone.net - local database extending the remote one
database bdb
suffix "dc=realone,dc=net"
directory ./database/realone.net
index objectClass eq
index cn eq
index uid eq
overlay translucent
uri ldap://remote.host.net:389/
chase-referrals true
rebind-as-user true
... or with slapd-relay (this is probably very very very rare use case
but I used it for debugging):
# --- config for local server (relay.local.net) ---
# [cut-off] command
schema, slapd files & logs definitions
# Configuration Database
database config
rootdn "cn=admin,cn=config"
rootpw secret
# domain (forwarded to remote repository)
database ldap
suffix "dc=realone,dc=net"
uri ldap://remote.host.net
chase-referrals yes
# domain alias
database relay
suffix "dc=virtual,dc=net"
relay "dc=realone,dc=net"
overlay rwm
rwm-suffixmassage "dc=virtual,dc=net" "dc=realone,dc=net"
Now, we can do usual search:
ldapsearch -x -w secret -h <host> -D <bindDN> -b <baseDN> -s sub
"(objectClass=inetOrgPerson)" dn displayName mail
(in my environment I should receive 3 records below
ou=people,dc=realone,dc=net).
But the story is getting interesting here. The command works only in
cases that slapd-ldap is used dirrectly:
===================================================================================================
# | Host | BindDN | BaseDN | Result
--+-----------------+----------------------------+-------------------+-----------------------------
1 | remote.host.net | cn=admin,dc=realone,dc=net | dc=realone,dc=net | Success (3 records)
--+-----------------+----------------------------+-------------------+-----------------------------
2 | trans.local.net | cn=admin,dc=realone,dc=net | dc=realone,dc=net | Failure: Anon.bind.n.allwd.
--+-----------------+----------------------------+-------------------+-----------------------------
3 | relay.local.net | cn=admin,dc=realone,dc=net | dc=realone,dc=net | Success (3 records)
--+-----------------+----------------------------+-------------------+-----------------------------
4 | relay.local.net | cn=admin,dc=realone,dc=net | dc=virtual,dc=net | Success (3 records) !!!!
--+-----------------+----------------------------+-------------------+-----------------------------
5 | relay.local.net | cn=admin,dc=virtual,dc=net | dc=virtual,dc=net | Failure: Anon.bind.n.allwd.
===================================================================================================
The failures of case #2 and #5 are not expected because the connection
to remote server is handled by slapd-ldap configured the same way like
in case 3. The success in case #3 is correct (although I didn't expected
it) and it was guide to solution. I noticed that each time the request
fail the LDAP connection is correctly opened and bind request is
successful. But the search request was processed using a new connection
that was created for it and anonymous bind executed with failure.
While debugging, I found that ldap_back_getconn() is called by
ldap_back_bind() as well as ldap_back_search() request handlers. For
operations other then op_bind it tests whether connection associated
with Operation (op->o_hdr->oh_conn) was used for authentication in
previous step. If slapd-ldap is NOT using identity assertion then it
checks Operation using SLAP_IS_AUTHZ_BACKEND macro whether
op->o_conn->c_authz_backend is not NULL and is equal to current backend.
This test works fine is the slapd-ldap backend is the only which
processes the LDAP request because op->o_conn->c_authz_backend is set in
the binding handler of the frontend module - fe_op_bind(). In this, case
the test succeeds and connection created during the binding is used also
for searching.
If the slapd-ldap module is used as nested module in slapo-translucent
(case #2), then the fe_op_bind() sets variable
op->o_conn->c_authz_backend to the backend extended by
slapo-translucent. Macro SLAP_IS_AUTHZ_BACKEND returns false and a new
LDAP connection is allocated causing failure due anonymouse binding.
If the slapd-ldap module is target for slapd-relay then it behaves
similar way. In case #5 the bind request is forwarded to slapd-ldap but
slapd-relay is associated with connection as the backend who did the
bind (op->o_conn->c_authz_backend) and subsequent search request fails
the same way like above.
The success in case #4 is a kind of singularity ;-) - bind request is
forwarded directly from frontend to slapd-ldap and therefore
op->o_conn->c_authz_backend is set correctly, the subsequent search
request goes first to slapd-relay which forwards it to slapd-ldap but
SLAP_IS_AUTHZ_BACKEND test succeeds.
I attached unified diffs of changes I made to OpenLDAP (2.4.18) source
code to make it working (fix for back-relay/op.c was much more easier in
2.4.15).
It looks like everyone uses the identity assertion mechanism because it
make the above mentioned use cases working in certain configurations.
Unfortunately, it's not a solution for me to use identity assertion.
Could someone confirm my findings?
Martin Rubas
--- openldap/servers/slapd/overlays/translucent.2_4_15.c Wed Sep 16 16:27:33 2009
+++ openldap/servers/slapd/overlays/translucent.custom.c Wed Sep 16 16:27:34 2009
@@ -1199,6 +1199,10 @@
op->o_bd = &ov->db;
ov->db.be_acl = op->o_bd->be_acl;
rc = ov->db.bd_info->bi_op_bind(op, rs);
+ if (0 == rc && 0 == rs->sr_err
+ && op->o_hdr->oh_conn && !op->o_hdr->oh_conn->c_authz_backend) {
+ op->o_hdr->oh_conn->c_authz_backend = op->o_bd;
+ }
op->o_bd = db;
if (ov->bind_local) {
--- openldap/servers/slapd/back-relay/op.2_4_15.c Wed Sep 16 16:55:08 2009
+++ openldap/servers/slapd/back-relay/op.custom.c Wed Sep 16 16:55:09 2009
@@ -170,6 +170,7 @@
relay_back_op_bind( Operation *op, SlapReply *rs )
{
BackendDB *bd;
+ int rc;
/* allow rootdn as a means to auth without the need to actually
* contact the proxied DSA */
@@ -187,8 +188,14 @@
return rs->sr_err;
}
- return relay_back_op( op, rs, bd, bd->be_bind,
+ rc = relay_back_op( op, rs, bd, bd->be_bind,
( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
+
+ if (0 == rc && 0 == rs->sr_err
+ && op->o_hdr->oh_conn && !op->o_hdr->oh_conn->c_authz_backend) {
+ op->o_hdr->oh_conn->c_authz_backend = bd;
+ }
+ return rc;
}
int
--- openldap/servers/slapd/back-relay/op.2_4_18.c Wed Sep 16 17:34:54 2009
+++ openldap/servers/slapd/back-relay/op.custom.c Wed Sep 09 14:36:14 2009
@@ -208,11 +208,6 @@
if ( op->o_callback == (slap_callback *) &rcb ) {
op->o_callback = op->o_callback->sc_next;
}
- if (op_bind == which && 0 == rc && 0 == rs->sr_err
- && op->o_hdr->oh_conn && !op->o_hdr->oh_conn->c_authz_backend) {
- op->o_hdr->oh_conn->c_authz_backend = bd;
- }
-
} else if ( fail_mode & RB_OPERR ) {
rs->sr_err = rc;
14 years
Creating database, catch-22
by Peter Mogensen
Hi,
I've been trying to script database creation via cn=config.
Creating the HDB database works fine, but when I try to add the LDIF for
the root node, I get:
# ldapadd -YEXTERNAL -H ldapi:/// -f ./bootstrap.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "dc=app,dc=example,dc=com"
ldap_add: Insufficient access (50)
additional info: no write access to parent
... which is understandable. However, I would prefer not to set a
temporary rootpw for the database. Is there any way around that?
I considered Proxy authorization, but the root DN for the database I'm
creating is in the LDIF I'm trying to add.
/Peter
PS: As you can probably see, all access goes through SASL EXTERNAL. UNIX
root maps to cn=config via ldapi:/// , remote access uses x509 certificates.
14 years
Wired issue with slurpd
by Dawei Wang
Hi,
I am using slurpd to do replication (openldap 2.3.33) and encountered a
strange issue:
The master have an entry which has a binary field, size of filed is about 10
meg. When never this field is updated ( and it's the only field get
updated), slurpd is triggered to replicate the change to the slave. But
slurpd seems gone wild on this binary filed, when i check the replication
log, i saw this binary filed becomes huge, i mean really huge, gigabytes in
size.
Is there any problem with slurpd to read the binary filed?
Regards
Dawei
14 years
set.regex and substring substitution
by Ronie Gilberto Henrich
Hi,
I am trying to grant users access to a ldap object when
user/allowedDomain match the Mail object ou.
To accomplish that I have to use set.regex and substring
substitution, but I was not able to figure out what I am doing wrong.
This is the current ACL:
access to dn.regex="^(.+,)?ou=([^,]+),ou=Mail,o=example,c=BR$"
by set="user/allowedDomain & this/ou" write
result (tested using "slapacl -D"):
=======
"ou=example.com,ou=Mail,o=example,c=BR" = write(=wrscxd)
"mail=test(a)example.com,ou=example.com,ou=Mail,o=example,c=BR" = 0
This is the ACL that I am trying to build. It was expecting both
results as = write(=wrscxd), but I am getting only = 0.
access to dn.regex="^(.+,)?ou=([^,]+),ou=Mail,o=example,c=BR$"
by set.regex="user/allowedDomain & $2" write
result (tested using "slapacl -D"):
=======
"ou=example.com,ou=Mail,o=example,c=BR" = 0
"mail=test(a)example.com,ou=example.com,ou=Mail,o=example,c=BR" = 0
Any ideas about what I should do for this to work?
Thanks!
Ronie
14 years
virtual list view, control value absent
by Dieter Kluenter
Hi,
I am experimenting with server side sorting and virtual list
view. While SSS does what it should do, vlv provides some
headaches. Although sss control and vlv control are passed to the
server, I get following error:
,----[ slapd debug output ]
| => get_ctrls: oid="1.2.840.113556.1.4.473" (critical)
| => get_ctrls: oid="2.16.840.1.113730.3.4.9" (critical)
| <= get_ctrls: n=2 rc=2 err="vlv control value is absent"
`----
What kind of vlv control value is missing?
My vlv object, written in perl, is:
,----[ vlv object ]
| $vlv = Net::LDAP::Control::VLV->new(
| after => 1,
| before => 0,
| content => 0,
| offset => 1,
| critical => 'TRUE',
| );
`----
my sss object looks like
,----[ sss object ]
| $sort = Net::LDAP::Control::Sort->new(
| order => 'sn:2.5.13.3',
| critical => 'TRUE',
| );
`----
my search object:
,----[ search object ]
| my @args = (
| base => 'ou=benchmark,o=avci,c=de',
| scope => 'one',
| attrs => [ "$attrs[0]","$attrs[1]","$attrs[2]" ]);
| filter => $filter,
| control => [ $sort, $vlv ],
| );
| $msg = $ldap->search( @args );
`----
-Dieter
--
Dieter Klünter | Systemberatung
http://dkluenter.de
GPG Key ID:8EF7B6C6
53°37'09,95"N
10°08'02,42"E
14 years
Re: Emulating replication from an LDAP client (not another slapd)
by Pierangelo Masarati
Pierangelo Masarati wrote:
> Hallvard B Furuseth wrote:
>> Brandon Hume writes:
>>> So my question is this: Is it possible for me to write some code, using
>>> perl or C or whatever is needed, that will connect as a syncrepl
>>> consumer, and "refresh and persist"? Are there docs for how the
>>> synchronization protocol works? Is it just an odd LDAP query?
>>
>> RFC 4533 describes the sync protocol. You might also have a look at the
>> auditlog and accesslog overlays for alternate solutions to your probelm.
>
> Following on to Hallvard's comment, OpenLDAP's libldap provides
> primitives to implement consumer-side syncrepl (as per RFC4533, no
> support for OpenLDAP extensions like delta-syncrepl and so). If you
> want to design your own consumer-side code based on RFC 4533, I'd
> recommend to start there. Of course, other solutions based on e.g.
> accesslog might be preferable if you prefer to limit the amount of
> required coding.
Forgot to point you to ldap_sync(3)
p.
14 years
Emulating replication from an LDAP client (not another slapd)
by Brandon Hume
Most of my organization's data is kept in LDAP, along with groups and
affiliations and titles and positions and everything else. We've got a
simple single-master, multi-slave setup, built back in the OpenLDAP 2.0
days.
We also have a provisioning service, which essentially monitors LDAP,
and as new people arrive, change position, or what have you, it runs off
and provisions accounts, mailboxes, services and permissions as needed
for the person, all automatically.
Currently, this monitoring - trying to keep it as "live" as possible -
is done by essentially making the provisioning server an LDAP replicant,
using slurpd. It works "well enough", though it has some problems.
But slurpd is going away, and I'm trying to kill it off in our
structure. The provisioning server is one of the last holdouts.
So my question is this: Is it possible for me to write some code, using
perl or C or whatever is needed, that will connect as a syncrepl
consumer, and "refresh and persist"? Are there docs for how the
synchronization protocol works? Is it just an odd LDAP query?
14 years
OpenLDAP and SASL
by Jittinan Suwanrueangsri
Hi
I have seen configuration which sasl get password from sasldb .I must
run saslpasswd2 to create user and password for authentication but Is it
possible to configure openldap and sasl verify authentication by getting
password from openldap self like it happen in simple
binding(userPassword attribute).How can I do it?
jittinan
14 years
TLS negotiation failure
by manu@netbsd.org
Hello
I experience a wierd problem with OpenLDAP and TLS connexions. slapd
will randomly reject connexions, with "TLS negotiation failure" error
message.
That happens with various clients (MacOS, NetBSD, Linux), and it happens
on multiples machines that run slapd, the current setup is below:
OpenLDAP 2.4.16
OpenSSL 0.9.9-dev 09 May 2008
NetBSD 5.0.1
But the problem also existed before upgrades with NetBSD 4.0 and
OpenLDAP 2.4.14. It seems to become worse over time.
Here is a trace obtained with a breakpoint set on the error message in
slapd.
conn=0 fd=19 ACCEPT from IP=193.54.82.248:59782 (IP=193.54.82.23:636)
TLS: can't accept: (null).
Breakpoint 1, connection_read (s=19, cri=0xa63ff8ac) at
connection.c:1326
1326 connection_closing( c, "TLS negotiation failure" );
(gdb) bt
#0 connection_read (s=19, cri=0xa63ff8ac) at connection.c:1326
#1 0x08078bf9 in connection_read_thread (ctx=0xa63ff900, argv=0x13) at
connection.c:1216
#2 0xbbbaad3a in ldap_int_thread_pool_wrapper (xpool=0xbb540080) at
tpool.c:663
#3 0xbb85e9df in pthread_create () from /usr/lib/libpthread.so.0
#4 0xbb7aa640 in swapcontext () from /usr/lib/libc.so.12
(gdb) c
Continuing.
conn=1 fd=20 ACCEPT from IP=193.54.82.248:59783 (IP=193.54.82.23:636)
conn=0 fd=19 closed (TLS negotiation failure)
So connection_read() reports an error from ldap_pvt_tls_accept(), which
is caused by tls_imp->ti_session_accept(). For OpenSSL, that is
tlso_session_accept(), which just calls SSL_accept()
Does that ring a bell to anyone? Any suggestion for a workaround?
--
Emmanuel Dreyfus
http://hcpnet.free.fr/pubz
manu(a)netbsd.org
14 years