mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-02-18 18:18:06 -05:00
Merge remote-tracking branch 'origin/master' into OPENLDAP_REL_ENG_2_5
This commit is contained in:
commit
1dc0fc1197
24 changed files with 2002 additions and 40 deletions
|
|
@ -23,13 +23,13 @@ build-openssl-heimdal-lloadd:
|
|||
stage: build
|
||||
script:
|
||||
- apt update
|
||||
- DEBIAN_FRONTEND=noninteractive apt install -y build-essential pkg-config automake libsasl2-dev heimdal-multidev libssl-dev libltdl-dev groff-base unixodbc-dev libwiredtiger-dev libperl-dev heimdal-kdc libsasl2-modules-gssapi-heimdal sasl2-bin libevent-dev
|
||||
- DEBIAN_FRONTEND=noninteractive apt install -y build-essential python3 gdb procps pkg-config automake libsasl2-dev heimdal-multidev libssl-dev libltdl-dev groff-base unixodbc-dev libwiredtiger-dev libperl-dev heimdal-kdc libsasl2-modules-gssapi-heimdal sasl2-bin libevent-dev
|
||||
- autoreconf
|
||||
- ./configure --enable-backends=mod --enable-overlays=mod --enable-modules --enable-dynamic --disable-ndb --enable-balancer=mod --disable-asyncmeta
|
||||
- make depend
|
||||
- make
|
||||
- ulimit -n 4096 # back-monitor takes a while scanning a long connections array
|
||||
- make test
|
||||
- SLAPD_COMMON_WRAPPER=gdb make test
|
||||
artifacts:
|
||||
name: testdir
|
||||
when: on_failure
|
||||
|
|
@ -41,13 +41,13 @@ build-gnutls-mit-standalone-lloadd:
|
|||
stage: build
|
||||
script:
|
||||
- apt update
|
||||
- DEBIAN_FRONTEND=noninteractive apt install -y build-essential pkg-config automake libsasl2-dev libltdl-dev groff-base unixodbc-dev libwiredtiger-dev libperl-dev krb5-user krb5-kdc krb5-admin-server libsasl2-modules-gssapi-mit sasl2-bin libgnutls28-dev libevent-dev
|
||||
- DEBIAN_FRONTEND=noninteractive apt install -y build-essential python3 gdb procps pkg-config automake libsasl2-dev libltdl-dev groff-base unixodbc-dev libwiredtiger-dev libperl-dev krb5-user krb5-kdc krb5-admin-server libsasl2-modules-gssapi-mit sasl2-bin libgnutls28-dev libevent-dev
|
||||
- autoreconf
|
||||
- ./configure --enable-backends=mod --enable-overlays=mod --disable-autoca --enable-modules --enable-dynamic --disable-ndb --enable-balancer=yes --disable-asyncmeta
|
||||
- make depend
|
||||
- make
|
||||
- ulimit -n 4096 # back-monitor takes a while scanning a long connections array
|
||||
- make test
|
||||
- SLAPD_COMMON_WRAPPER=gdb make test
|
||||
artifacts:
|
||||
name: testdir
|
||||
when: on_failure
|
||||
|
|
|
|||
17
configure.ac
17
configure.ac
|
|
@ -350,6 +350,7 @@ Overlays="accesslog \
|
|||
ppolicy \
|
||||
proxycache \
|
||||
refint \
|
||||
remoteauth \
|
||||
retcode \
|
||||
rwm \
|
||||
seqmod \
|
||||
|
|
@ -390,6 +391,8 @@ OL_ARG_ENABLE(proxycache, [AS_HELP_STRING([--enable-proxycache], [Proxy Cache ov
|
|||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(refint, [AS_HELP_STRING([--enable-refint], [Referential Integrity overlay])],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(remoteauth, [AS_HELP_STRING([--enable-remoteauth], [Deferred Authentication overlay])],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(retcode, [AS_HELP_STRING([--enable-retcode], [Return Code testing overlay])],
|
||||
no, [no yes mod], ol_enable_overlays)
|
||||
OL_ARG_ENABLE(rwm, [AS_HELP_STRING([--enable-rwm], [Rewrite/Remap overlay])],
|
||||
|
|
@ -566,6 +569,7 @@ BUILD_MEMBEROF=no
|
|||
BUILD_PPOLICY=no
|
||||
BUILD_PROXYCACHE=no
|
||||
BUILD_REFINT=no
|
||||
BUILD_REMOTEAUTH=no
|
||||
BUILD_RETCODE=no
|
||||
BUILD_RWM=no
|
||||
BUILD_SEQMOD=no
|
||||
|
|
@ -2842,6 +2846,18 @@ if test "$ol_enable_refint" != no ; then
|
|||
AC_DEFINE_UNQUOTED(SLAPD_OVER_REFINT,$MFLAG,[define for Referential Integrity overlay])
|
||||
fi
|
||||
|
||||
if test "$ol_enable_remoteauth" != no ; then
|
||||
BUILD_REMOTEAUTH=$ol_enable_remoteauth
|
||||
if test "$ol_enable_remoteauth" = mod ; then
|
||||
MFLAG=SLAPD_MOD_DYNAMIC
|
||||
SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS remoteauth.la"
|
||||
else
|
||||
MFLAG=SLAPD_MOD_STATIC
|
||||
SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS remoteauth.o"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(SLAPD_OVER_REMOTEAUTH,$MFLAG,[define for Deferred Authentication overlay])
|
||||
fi
|
||||
|
||||
if test "$ol_enable_retcode" != no ; then
|
||||
BUILD_RETCODE=$ol_enable_retcode
|
||||
if test "$ol_enable_retcode" = mod ; then
|
||||
|
|
@ -3014,6 +3030,7 @@ dnl overlays
|
|||
AC_SUBST(BUILD_PPOLICY)
|
||||
AC_SUBST(BUILD_PROXYCACHE)
|
||||
AC_SUBST(BUILD_REFINT)
|
||||
AC_SUBST(BUILD_REMOTEAUTH)
|
||||
AC_SUBST(BUILD_RETCODE)
|
||||
AC_SUBST(BUILD_RWM)
|
||||
AC_SUBST(BUILD_SEQMOD)
|
||||
|
|
|
|||
|
|
@ -253,6 +253,12 @@ E: limits group/groupOfNames/member="cn=dirsync,dc=example,dc=org" size.prtota
|
|||
E: limits users size.soft=5 size.hard=100 size.prtotal=disabled
|
||||
E: limits anonymous size.soft=2 size.hard=5 size.prtotal=disabled
|
||||
|
||||
H2: Glued/Subordinate database configurations
|
||||
When using subordinate databases, it is necessary for any limits that
|
||||
are to be applied across the parent and its subordinates to be defined in both
|
||||
the parent and its subordinates. Otherwise the settings on the subordinate databases
|
||||
are not honored.
|
||||
|
||||
H2: Further Information
|
||||
|
||||
For further information please see {{slapd.conf}}(5), {{ldapsearch}}(1) and {{slapd.access}}(5)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,12 @@ slapd Configuration File}} chapters.
|
|||
|
||||
H2: Monitor configuration via cn=config(5)
|
||||
|
||||
{{This section has yet to be written.}}
|
||||
The {{monitor backend}} is statically built into slapd and can be
|
||||
instantiated via ldapadd.
|
||||
|
||||
> dn: olcDatabase=monitor,cn=config
|
||||
> objectClass: olcDatabaseConfig
|
||||
> olcDatabase: monitor
|
||||
|
||||
H2: Monitor configuration via slapd.conf(5)
|
||||
|
||||
|
|
|
|||
|
|
@ -1637,6 +1637,17 @@ is requested cannot exceed the
|
|||
size limit of regular searches unless extended by the
|
||||
.B prtotal
|
||||
switch.
|
||||
|
||||
The \fBolcLimits\fP statement is typically used to let an unlimited
|
||||
number of entries be returned by searches performed
|
||||
with the identity used by the consumer for synchronization purposes
|
||||
by means of the RFC 4533 LDAP Content Synchronization protocol
|
||||
(see \fBolcSyncrepl\fP for details).
|
||||
|
||||
When using subordinate databases, it is necessary for any limits that
|
||||
are to be applied across the parent and its subordinates to be defined in
|
||||
both the parent and its subordinates. Otherwise the settings on the
|
||||
subordinate databases are not honored.
|
||||
.RE
|
||||
.TP
|
||||
.B olcMaxDerefDepth: <depth>
|
||||
|
|
|
|||
|
|
@ -1583,7 +1583,7 @@ the use of the pagedResults control as a means to circumvent size
|
|||
limitations on regular searches; the keyword
|
||||
.I disabled
|
||||
disables the control, i.e. no paged results can be returned.
|
||||
Note that the total number of entries returned when the pagedResults control
|
||||
Note that the total number of entries returned when the pagedResults control
|
||||
is requested cannot exceed the
|
||||
.B hard
|
||||
size limit of regular searches unless extended by the
|
||||
|
|
@ -1595,6 +1595,11 @@ number of entries be returned by searches performed
|
|||
with the identity used by the consumer for synchronization purposes
|
||||
by means of the RFC 4533 LDAP Content Synchronization protocol
|
||||
(see \fBsyncrepl\fP for details).
|
||||
|
||||
When using subordinate databases, it is necessary for any limits that
|
||||
are to be applied across the parent and its subordinates to be defined in
|
||||
both the parent and its subordinates. Otherwise the settings on the
|
||||
subordinate databases are not honored.
|
||||
.RE
|
||||
.TP
|
||||
.B maxderefdepth <depth>
|
||||
|
|
|
|||
|
|
@ -137,6 +137,20 @@ The schema is loaded automatically by the overlay.
|
|||
The schema includes a number of object classes and associated
|
||||
attribute types as described below.
|
||||
|
||||
The root entry of the underlying accesslog database makes use
|
||||
of the
|
||||
.B auditContainer
|
||||
class which is as follows:
|
||||
.LP
|
||||
.RS 4
|
||||
( 1.3.6.1.4.1.4203.666.11.5.2.0
|
||||
NAME 'auditContainer'
|
||||
DESC 'AuditLog container'
|
||||
SUP top STRUCTURAL
|
||||
MAY ( cn $ reqStart $ reqEnd ) )
|
||||
.RE
|
||||
.P
|
||||
|
||||
There is
|
||||
a basic
|
||||
.B auditObject
|
||||
|
|
@ -378,7 +392,7 @@ filter.
|
|||
DESC 'ModRDN operation'
|
||||
SUP auditWriteObject STRUCTURAL
|
||||
MUST ( reqNewRDN $ reqDeleteOldRDN )
|
||||
MAY ( reqNewSuperior $ reqOld ) )
|
||||
MAY ( reqNewSuperior $ reqMod $ reqOld ) )
|
||||
.RE
|
||||
.P
|
||||
The
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ ETCDIR/slapd.d
|
|||
.SH DESCRIPTION
|
||||
The Audit Logging overlay can be used to record all changes on a given
|
||||
backend database to a specified log file. Changes are logged as standard
|
||||
LDIF, with an additional comment header giving the timestamp of the change
|
||||
and the identity of the user making the change.
|
||||
LDIF, with an additional comment header providing six fields of
|
||||
information about the change. A second comment header is added at the end
|
||||
of the operation to note the termination of the change.
|
||||
.LP
|
||||
For Add and Modify operations the identity comes from the modifiersName
|
||||
associated with the operation. This is usually the same as the requestor's
|
||||
|
|
@ -31,6 +32,19 @@ Specify the fully qualified path for the log file.
|
|||
.B olcAuditlogFile <filename>
|
||||
For use with
|
||||
.B cn=config
|
||||
.SH COMMENT FIELD INFORMATION
|
||||
The first field is the operation type.
|
||||
.br
|
||||
The second field is the timestamp of the operation in seconds since epoch.
|
||||
.br
|
||||
The third field is the suffix of the database.
|
||||
.br
|
||||
The fourth field is the recorded modifiersName.
|
||||
.br
|
||||
The fifth field is the originating IP address and port.
|
||||
.br
|
||||
The sixth field is the connection number. A connection number of -1
|
||||
indicates an internal slapd operation.
|
||||
.SH EXAMPLE
|
||||
The following LDIF could be used to add this overlay to
|
||||
.B cn=config
|
||||
|
|
@ -48,6 +62,30 @@ olcAuditlogFile: /tmp/auditlog.ldif
|
|||
.RE
|
||||
.LP
|
||||
.LP
|
||||
.SH EXAMPLE CHANGELOG
|
||||
.LP
|
||||
.RS
|
||||
.nf
|
||||
# modify 1614223245 dc=example,dc=com cn=admin,dc=example,dc=com IP=[::1]:47270 conn=1002
|
||||
dn: uid=joepublic,ou=people,dc=example,dc=com
|
||||
changetype: modify
|
||||
replace: displayName
|
||||
displayName: Joe Public
|
||||
-
|
||||
replace: entryCSN
|
||||
entryCSN: 20210225032045.045229Z#000000#001#000000
|
||||
-
|
||||
replace: modifiersName
|
||||
modifiersName: cn=admin,dc=example,dc=com
|
||||
-
|
||||
replace: modifyTimestamp
|
||||
modifyTimestamp: 20210225032045Z
|
||||
-
|
||||
# end modify 1614223245
|
||||
|
||||
.fi
|
||||
.RE
|
||||
.LP
|
||||
.SH FILES
|
||||
.TP
|
||||
ETCDIR/slapd.conf
|
||||
|
|
|
|||
160
doc/man/man5/slapo-remoteauth.5
Normal file
160
doc/man/man5/slapo-remoteauth.5
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
.TH SLAPO-REMOTEAUTH 5 "RELEASEDATE" "OpenLDAP LDVERSION"
|
||||
.\" Copyright 1998-2021 The OpenLDAP Foundation, All Rights Reserved.
|
||||
.\" Copying restrictions apply. See the COPYRIGHT file.
|
||||
.\" $OpenLDAP$
|
||||
.SH NAME
|
||||
slapo-remoteauth \- Delegate authentication requests to remote directories, e.g. Active Directory
|
||||
.SH SYNOPSIS
|
||||
ETCDIR/slapd.conf
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B remoteauth
|
||||
overlay to
|
||||
.BR slapd (8)
|
||||
provides passthrough authentication to remote directory servers, e.g.
|
||||
Active Directory, for LDAP simple bind operations. The local LDAP entry
|
||||
referenced in the bind operation is mapped to its counterpart in the remote
|
||||
directory. An LDAP bind operation is performed against the remote directory
|
||||
and results are returned based on those of the remote operation.
|
||||
.LP
|
||||
A slapd server configured with the
|
||||
.B remoteauth
|
||||
overlay handles an authentication request based on the presence of
|
||||
.B userPassword
|
||||
in the local entry. If the
|
||||
.B userPassword
|
||||
is present, authentication is performed locally, otherwise the
|
||||
.B remoteauth
|
||||
overlay performs the authentication request to the configured remote directory
|
||||
server.
|
||||
.LP
|
||||
|
||||
.SH CONFIGURATION
|
||||
|
||||
The following options can be applied to the
|
||||
.B remoteauth
|
||||
overlay within the slapd.conf file. All options should follow the
|
||||
.B overlay remoteauth
|
||||
directive.
|
||||
|
||||
.TP
|
||||
.B overlay remoteauth
|
||||
This directive adds the
|
||||
.B remoteauth
|
||||
overlay to the current database, see
|
||||
.BR slapd.conf (5)
|
||||
for details.
|
||||
|
||||
.TP
|
||||
.B remoteauth_dn_attribute <dnattr>
|
||||
Attribute in the local entry that is used to store the bind DN to a remote
|
||||
directory server.
|
||||
|
||||
.TP
|
||||
.B remoteauth_mapping <domain> <hostname|LDAP URI|file:///path/to/list_of_hostnames>
|
||||
For a non-Windows deployment, a domain can be considered as a collection of
|
||||
one or more hosts to which slapd server authentcates against on behalf of
|
||||
authenticating users.
|
||||
For a given domain name, the mapping specifies the target server(s),
|
||||
e.g., Active Directory domain controller(s), to connect to via LDAP.
|
||||
The second argument can be given either as a hostname, an LDAP URI, or a file
|
||||
containing a list of hostnames/URIs, one per line. The hostnames are tried in
|
||||
sequence until the connection succeeds.
|
||||
|
||||
This option can be provided more than once to provide mapping information for
|
||||
different domains. For example:
|
||||
|
||||
.nf
|
||||
remoteauth_mapping americas file:///path/to/americas.domain.hosts
|
||||
remoteauth_mapping asiapacific file:///path/to/asiapacific.domain.hosts
|
||||
remoteauth_mapping emea emeadc1.emea.example.com
|
||||
.fi
|
||||
|
||||
.TP
|
||||
.B remoteauth_domain_attribute <attr>
|
||||
Attribute in the local entry that specifies the domain name, any text after
|
||||
"\\" or ":" is ignored.
|
||||
|
||||
.TP
|
||||
.B remoteauth_default_domain <default domain>
|
||||
Default domain.
|
||||
|
||||
|
||||
.TP
|
||||
.B remoteauth_default_realm <server>
|
||||
Fallback server to connect to for domains not specified in
|
||||
.BR remoteauth_mapping .
|
||||
|
||||
.TP
|
||||
.B remoteauth_retry_count <num>
|
||||
Number of connection retries attempted. Default is 3.
|
||||
|
||||
.TP
|
||||
.B remoteauth_store <on|off>
|
||||
Whether to store the password in the local entry on successful bind. Default is
|
||||
off.
|
||||
|
||||
.HP
|
||||
.hy 0
|
||||
.B remoteauth_tls
|
||||
.B [starttls=yes]
|
||||
.B [tls_cert=<file>]
|
||||
.B [tls_key=<file>]
|
||||
.B [tls_cacert=<file>]
|
||||
.B [tls_cacertdir=<path>]
|
||||
.B [tls_reqcert=never|allow|try|demand]
|
||||
.B [tls_reqsan=never|allow|try|demand]
|
||||
.B [tls_cipher_suite=<ciphers>]
|
||||
.B [tls_ecname=<names>]
|
||||
.B [tls_crlcheck=none|peer|all]
|
||||
.RS
|
||||
Remoteauth specific TLS configuration, see
|
||||
.BR slapd.conf (5)
|
||||
for more details on each of the parameters and defaults.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B remoteauth_tls_peerkey_hash <hostname> <hashname>:<base64 of public key hash>
|
||||
Mapping between remote server hostnames and their public key hashes. Only one
|
||||
mapping per hostname is supported and if any pins are specified, all hosts
|
||||
need to be pinned. If set, pinning is in effect regardless of whether or not
|
||||
certificate name validation is enabled by
|
||||
.BR tls_reqcert .
|
||||
|
||||
.SH EXAMPLE
|
||||
A typical example configuration of
|
||||
.B remoteauth
|
||||
overlay for AD is shown below (as a
|
||||
.BR slapd.conf (5)
|
||||
snippet):
|
||||
|
||||
.LP
|
||||
.nf
|
||||
database <database>
|
||||
#...
|
||||
|
||||
overlay remoteauth
|
||||
remoteauth_dn_attribute seeAlso
|
||||
remoteauth_domain_attribute associatedDomain
|
||||
remoteauth_default_realm americas.example.com
|
||||
|
||||
remoteauth_mapping americas file:///home/ldap/etc/remoteauth.americas
|
||||
remoteauth_mapping emea emeadc1.emea.example.com
|
||||
|
||||
remoteauth_tls starttls=yes tls_reqcert=demand tls_cacert=/home/ldap/etc/example-ca.pem
|
||||
remoteauth_tls_peerkey_hash ldap.americas.tld sha256:Bxv3MkLoDm6gt/iDfeGNdNNqa5TTpPDdIwvZM/cIgeo=
|
||||
.fi
|
||||
|
||||
Where seeAlso contains the AD bind DN for the user, associatedDomain contains the
|
||||
Windows Domain Id in the form of <NT-domain-name>:<NT-username> in which
|
||||
anything following, including ":", is ignored.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR slapd.conf (5),
|
||||
.BR slapd (8).
|
||||
|
||||
.SH Copyrights
|
||||
Copyright 2004-2021 The OpenLDAP Foundation.
|
||||
Portions Copyright 2004-2017 Howard Chu, Symas Corporation.
|
||||
Portions Copyright 2017-2021 Ondřej Kuzník, Symas Corporation.
|
||||
Portions Copyright 2004 Hewlett-Packard Company
|
||||
|
|
@ -179,6 +179,7 @@ LDAP_BEGIN_DECL
|
|||
#define LDAP_OPT_X_TLS_PROTOCOL_TLS1_0 ((3 << 8) + 1)
|
||||
#define LDAP_OPT_X_TLS_PROTOCOL_TLS1_1 ((3 << 8) + 2)
|
||||
#define LDAP_OPT_X_TLS_PROTOCOL_TLS1_2 ((3 << 8) + 3)
|
||||
#define LDAP_OPT_X_TLS_PROTOCOL_TLS1_3 ((3 << 8) + 4)
|
||||
|
||||
#define LDAP_OPT_X_SASL_CBINDING_NONE 0
|
||||
#define LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE 1
|
||||
|
|
|
|||
|
|
@ -292,6 +292,13 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
|
|||
#ifdef SSL_OP_NO_TLSv1
|
||||
#ifdef SSL_OP_NO_TLSv1_1
|
||||
#ifdef SSL_OP_NO_TLSv1_2
|
||||
#ifdef SSL_OP_NO_TLSv1_3
|
||||
if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_3)
|
||||
SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 |
|
||||
SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3 );
|
||||
else
|
||||
#endif
|
||||
if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_2)
|
||||
SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 |
|
||||
|
|
@ -310,8 +317,10 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
|
|||
#endif
|
||||
if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 )
|
||||
SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 );
|
||||
else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 )
|
||||
else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
|
||||
SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 );
|
||||
SSL_CTX_clear_options( ctx, SSL_OP_NO_SSLv3 );
|
||||
}
|
||||
|
||||
if ( lo->ldo_tls_ciphersuite &&
|
||||
!SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) )
|
||||
|
|
|
|||
|
|
@ -283,6 +283,8 @@ static OidRec OidMacros[] = {
|
|||
* OLcfgOv{Oc|At}:19 -> collect
|
||||
* OLcfgOv{Oc|At}:20 -> retcode
|
||||
* OLcfgOv{Oc|At}:21 -> sssvlv
|
||||
* OLcfgOv{Oc|At}:22 -> autoca
|
||||
* OLcfgOv{Oc|At}:24 -> remoteauth
|
||||
*/
|
||||
|
||||
/* alphabetical ordering */
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ SRCS = overlays.c \
|
|||
collect.c \
|
||||
ppolicy.c \
|
||||
refint.c \
|
||||
remoteauth.c \
|
||||
retcode.c \
|
||||
rwm.c rwmconf.c rwmdn.c rwmmap.c \
|
||||
seqmod.c \
|
||||
|
|
@ -102,6 +103,9 @@ ppolicy.la : ppolicy.lo
|
|||
refint.la : refint.lo
|
||||
$(LTLINK_MOD) -module -o $@ refint.lo version.lo $(LINK_LIBS)
|
||||
|
||||
remoteauth.la : remoteauth.lo
|
||||
$(LTLINK_MOD) -module -o $@ remoteauth.lo version.lo $(LINK_LIBS)
|
||||
|
||||
retcode.la : retcode.lo
|
||||
$(LTLINK_MOD) -module -o $@ retcode.lo version.lo $(LINK_LIBS)
|
||||
|
||||
|
|
|
|||
996
servers/slapd/overlays/remoteauth.c
Normal file
996
servers/slapd/overlays/remoteauth.c
Normal file
|
|
@ -0,0 +1,996 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* remoteauth.c - Overlay to delegate bind processing to a remote server */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2004-2021 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2017-2021 Ondřej Kuzník, Symas Corporation.
|
||||
* Portions Copyright 2004-2017 Howard Chu, Symas Corporation.
|
||||
* Portions Copyright 2004 Hewlett-Packard Company.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <ldap.h>
|
||||
#if SLAPD_MODULES
|
||||
#define LIBLTDL_DLL_IMPORT /* Win32: don't re-export libltdl's symbols */
|
||||
#include <ltdl.h>
|
||||
#endif
|
||||
#include <ac/errno.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/ctype.h>
|
||||
#include "lutil.h"
|
||||
#include "slap.h"
|
||||
#include "slap-config.h"
|
||||
|
||||
#ifndef UP_STR
|
||||
#define UP_STR "userPassword"
|
||||
#endif /* UP_STR */
|
||||
|
||||
#ifndef LDAP_PREFIX
|
||||
#define LDAP_PREFIX "ldap://"
|
||||
#endif /* LDAP_PREFIX */
|
||||
|
||||
#ifndef FILE_PREFIX
|
||||
#define FILE_PREFIX "file://"
|
||||
#endif /* LDAP_PREFIX */
|
||||
|
||||
typedef struct _ad_info {
|
||||
struct _ad_info *next;
|
||||
char *domain;
|
||||
char *realm;
|
||||
} ad_info;
|
||||
|
||||
typedef struct _ad_pin {
|
||||
struct _ad_pin *next;
|
||||
char *hostname;
|
||||
char *pin;
|
||||
} ad_pin;
|
||||
|
||||
typedef struct _ad_private {
|
||||
char *dn;
|
||||
AttributeDescription *dn_ad;
|
||||
char *domain_attr;
|
||||
AttributeDescription *domain_ad;
|
||||
|
||||
AttributeDescription *up_ad;
|
||||
ad_info *mappings;
|
||||
|
||||
char *default_realm;
|
||||
char *default_domain;
|
||||
|
||||
int up_set;
|
||||
int retry_count;
|
||||
int store_on_success;
|
||||
|
||||
ad_pin *pins;
|
||||
slap_bindconf ad_tls;
|
||||
} ad_private;
|
||||
|
||||
enum {
|
||||
REMOTE_AUTH_MAPPING = 1,
|
||||
REMOTE_AUTH_DN_ATTRIBUTE,
|
||||
REMOTE_AUTH_DOMAIN_ATTRIBUTE,
|
||||
REMOTE_AUTH_DEFAULT_DOMAIN,
|
||||
REMOTE_AUTH_DEFAULT_REALM,
|
||||
REMOTE_AUTH_CACERT_DIR,
|
||||
REMOTE_AUTH_CACERT_FILE,
|
||||
REMOTE_AUTH_VALIDATE_CERTS,
|
||||
REMOTE_AUTH_RETRY_COUNT,
|
||||
REMOTE_AUTH_TLS,
|
||||
REMOTE_AUTH_TLS_PIN,
|
||||
REMOTE_AUTH_STORE_ON_SUCCESS,
|
||||
};
|
||||
|
||||
static ConfigDriver remoteauth_cf_gen;
|
||||
|
||||
static ConfigTable remoteauthcfg[] = {
|
||||
{ "remoteauth_mapping", "mapping between domain and realm", 2, 3, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_MAPPING,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.1 NAME 'olcRemoteAuthMapping' "
|
||||
"DESC 'Mapping from domain name to server' "
|
||||
"SYNTAX OMsDirectoryString )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_dn_attribute", "Attribute to use as AD bind DN", 2, 2, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_DN_ATTRIBUTE,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.2 NAME 'olcRemoteAuthDNAttribute' "
|
||||
"DESC 'Attribute in entry to use as bind DN for AD' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_domain_attribute", "Attribute to use as domain determinant", 2, 2, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_DOMAIN_ATTRIBUTE,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.3 NAME 'olcRemoteAuthDomainAttribute' "
|
||||
"DESC 'Attribute in entry to determine windows domain' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_default_domain", "Default Windows domain", 2, 2, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_DEFAULT_DOMAIN,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.4 NAME 'olcRemoteAuthDefaultDomain' "
|
||||
"DESC 'Default Windows domain to use' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_default_realm", "Default AD realm", 2, 2, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_DEFAULT_REALM,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.5 NAME 'olcRemoteAuthDefaultRealm' "
|
||||
"DESC 'Default AD realm to use' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_store", "on|off", 1, 2, 0,
|
||||
ARG_OFFSET|ARG_ON_OFF|REMOTE_AUTH_STORE_ON_SUCCESS,
|
||||
(void *)offsetof(ad_private, store_on_success),
|
||||
"( OLcfgOvAt:24.6 NAME 'olcRemoteAuthStore' "
|
||||
"DESC 'Store password locally on success' "
|
||||
"SYNTAX OMsBoolean SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_retry_count", "integer", 2, 2, 0,
|
||||
ARG_OFFSET|ARG_UINT|REMOTE_AUTH_RETRY_COUNT,
|
||||
(void *)offsetof(ad_private, retry_count),
|
||||
"( OLcfgOvAt:24.7 NAME 'olcRemoteAuthRetryCount' "
|
||||
"DESC 'Number of retries attempted' "
|
||||
"SYNTAX OMsInteger SINGLE-VALUE )",
|
||||
NULL, { .v_uint = 3 }
|
||||
},
|
||||
{ "remoteauth_tls", "tls settings", 2, 0, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_TLS,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.8 NAME 'olcRemoteAuthTLS' "
|
||||
"DESC 'StartTLS settings' "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL
|
||||
},
|
||||
{ "remoteauth_tls_peerkey_hash", "mapping between hostnames and their public key hash", 3, 3, 0,
|
||||
ARG_MAGIC|REMOTE_AUTH_TLS_PIN,
|
||||
remoteauth_cf_gen,
|
||||
"( OLcfgOvAt:24.9 NAME 'olcRemoteAuthTLSPeerkeyHash' "
|
||||
"DESC 'StartTLS hostname to public key pin mapping file' "
|
||||
"SYNTAX OMsDirectoryString )",
|
||||
NULL, NULL
|
||||
},
|
||||
|
||||
{ NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL }
|
||||
};
|
||||
|
||||
static ConfigOCs remoteauthocs[] = {
|
||||
{ "( OLcfgOvOc:24.1 "
|
||||
"NAME 'olcRemoteAuthCfg' "
|
||||
"DESC 'Remote Directory passthough authentication configuration' "
|
||||
"SUP olcOverlayConfig "
|
||||
"MUST olcRemoteAuthTLS "
|
||||
"MAY ( olcRemoteAuthMapping $ olcRemoteAuthDNAttribute $ "
|
||||
" olcRemoteAuthDomainAttribute $ olcRemoteAuthDefaultDomain $ "
|
||||
" olcRemoteAuthDefaultRealm $ olcRemoteAuthStore $ "
|
||||
" olcRemoteAuthRetryCount $ olcRemoteAuthTLSPeerkeyHash ) )",
|
||||
Cft_Overlay, remoteauthcfg },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
remoteauth_cf_gen( ConfigArgs *c )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)c->bi;
|
||||
ad_private *ad = (ad_private *)on->on_bi.bi_private;
|
||||
struct berval bv;
|
||||
int i, rc = 0;
|
||||
ad_info *map;
|
||||
const char *text = NULL;
|
||||
|
||||
switch ( c->op ) {
|
||||
case SLAP_CONFIG_EMIT:
|
||||
switch ( c->type ) {
|
||||
case REMOTE_AUTH_MAPPING:
|
||||
for ( map = ad->mappings; map; map = map->next ) {
|
||||
char *str;
|
||||
|
||||
str = ch_malloc( strlen( map->domain ) +
|
||||
strlen( map->realm ) + 2 );
|
||||
sprintf( str, "%s %s", map->domain, map->realm );
|
||||
ber_str2bv( str, strlen( str ), 1, &bv );
|
||||
ch_free( str );
|
||||
rc = value_add_one( &c->rvalue_vals, &bv );
|
||||
if ( rc ) return rc;
|
||||
rc = value_add_one( &c->rvalue_nvals, &bv );
|
||||
if ( rc ) return rc;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DN_ATTRIBUTE:
|
||||
if ( ad->dn )
|
||||
value_add_one( &c->rvalue_vals, &ad->dn_ad->ad_cname );
|
||||
break;
|
||||
case REMOTE_AUTH_DOMAIN_ATTRIBUTE:
|
||||
if ( ad->domain_attr )
|
||||
value_add_one(
|
||||
&c->rvalue_vals, &ad->domain_ad->ad_cname );
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_DOMAIN:
|
||||
if ( ad->default_domain ) {
|
||||
ber_str2bv( ad->default_domain, 0, 1, &bv );
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_REALM:
|
||||
if ( ad->default_realm ) {
|
||||
ber_str2bv( ad->default_realm, 0, 1, &bv );
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_TLS:
|
||||
bindconf_tls_unparse( &ad->ad_tls, &bv );
|
||||
|
||||
for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
|
||||
/* count spaces */ ;
|
||||
|
||||
if ( i ) {
|
||||
bv.bv_len -= i;
|
||||
AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
|
||||
bv.bv_len + 1 );
|
||||
}
|
||||
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
break;
|
||||
case REMOTE_AUTH_TLS_PIN: {
|
||||
ad_pin *pin = ad->pins;
|
||||
for ( pin = ad->pins; pin; pin = pin->next ) {
|
||||
bv.bv_val = ch_malloc( strlen( pin->hostname ) +
|
||||
strlen( pin->pin ) + 2 );
|
||||
bv.bv_len = sprintf(
|
||||
bv.bv_val, "%s %s", pin->hostname, pin->pin );
|
||||
rc = value_add_one( &c->rvalue_vals, &bv );
|
||||
if ( rc ) return rc;
|
||||
rc = value_add_one( &c->rvalue_nvals, &bv );
|
||||
if ( rc ) return rc;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case LDAP_MOD_DELETE:
|
||||
switch ( c->type ) {
|
||||
case REMOTE_AUTH_MAPPING:
|
||||
if ( c->valx < 0 ) {
|
||||
/* delete all mappings */
|
||||
while ( ad->mappings ) {
|
||||
map = ad->mappings;
|
||||
ad->mappings = ad->mappings->next;
|
||||
ch_free( map->domain );
|
||||
ch_free( map->realm );
|
||||
ch_free( map );
|
||||
}
|
||||
} else {
|
||||
/* delete a specific mapping indicated by 'valx'*/
|
||||
ad_info *pmap = NULL;
|
||||
|
||||
for ( map = ad->mappings, i = 0;
|
||||
( map ) && ( i < c->valx );
|
||||
pmap = map, map = map->next, i++ )
|
||||
;
|
||||
|
||||
if ( pmap ) {
|
||||
pmap->next = map->next;
|
||||
map->next = NULL;
|
||||
|
||||
ch_free( map->domain );
|
||||
ch_free( map->realm );
|
||||
ch_free( map );
|
||||
} else if ( ad->mappings ) {
|
||||
/* delete the first item in the list */
|
||||
map = ad->mappings;
|
||||
ad->mappings = map->next;
|
||||
ch_free( map->domain );
|
||||
ch_free( map->realm );
|
||||
ch_free( map );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DN_ATTRIBUTE:
|
||||
if ( ad->dn ) {
|
||||
ch_free( ad->dn );
|
||||
ad->dn = NULL; /* Don't free AttributeDescription */
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DOMAIN_ATTRIBUTE:
|
||||
if ( ad->domain_attr ) {
|
||||
ch_free( ad->domain_attr );
|
||||
/* Don't free AttributeDescription */
|
||||
ad->domain_attr = NULL;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_DOMAIN:
|
||||
if ( ad->default_domain ) {
|
||||
ch_free( ad->default_domain );
|
||||
ad->default_domain = NULL;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_REALM:
|
||||
if ( ad->default_realm ) {
|
||||
ch_free( ad->default_realm );
|
||||
ad->default_realm = NULL;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_TLS:
|
||||
/* MUST + SINGLE-VALUE -> this is a replace */
|
||||
bindconf_free( &ad->ad_tls );
|
||||
break;
|
||||
case REMOTE_AUTH_TLS_PIN:
|
||||
while ( ad->pins ) {
|
||||
ad_pin *pin = ad->pins;
|
||||
ad->pins = ad->pins->next;
|
||||
ch_free( pin->hostname );
|
||||
ch_free( pin->pin );
|
||||
ch_free( pin );
|
||||
}
|
||||
break;
|
||||
/* ARG_OFFSET */
|
||||
case REMOTE_AUTH_STORE_ON_SUCCESS:
|
||||
case REMOTE_AUTH_RETRY_COUNT:
|
||||
abort();
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case SLAP_CONFIG_ADD:
|
||||
case LDAP_MOD_ADD:
|
||||
switch ( c->type ) {
|
||||
case REMOTE_AUTH_MAPPING:
|
||||
/* add mapping to head of list */
|
||||
map = ch_malloc( sizeof(ad_info) );
|
||||
map->domain = ber_strdup( c->argv[1] );
|
||||
map->realm = ber_strdup( c->argv[2] );
|
||||
map->next = ad->mappings;
|
||||
ad->mappings = map;
|
||||
|
||||
break;
|
||||
case REMOTE_AUTH_DN_ATTRIBUTE:
|
||||
if ( slap_str2ad( c->argv[1], &ad->dn_ad, &text ) ==
|
||||
LDAP_SUCCESS ) {
|
||||
ad->dn = ber_strdup( ad->dn_ad->ad_cname.bv_val );
|
||||
} else {
|
||||
strncpy( c->cr_msg, text, sizeof(c->cr_msg) );
|
||||
c->cr_msg[sizeof(c->cr_msg) - 1] = '\0';
|
||||
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
|
||||
rc = ARG_BAD_CONF;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DOMAIN_ATTRIBUTE:
|
||||
if ( slap_str2ad( c->argv[1], &ad->domain_ad, &text ) ==
|
||||
LDAP_SUCCESS ) {
|
||||
ad->domain_attr =
|
||||
ber_strdup( ad->domain_ad->ad_cname.bv_val );
|
||||
} else {
|
||||
strncpy( c->cr_msg, text, sizeof(c->cr_msg) );
|
||||
c->cr_msg[sizeof(c->cr_msg) - 1] = '\0';
|
||||
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
|
||||
rc = ARG_BAD_CONF;
|
||||
}
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_DOMAIN:
|
||||
if ( ad->default_domain ) {
|
||||
ch_free( ad->default_domain );
|
||||
ad->default_domain = NULL;
|
||||
}
|
||||
ad->default_domain = ber_strdup( c->argv[1] );
|
||||
break;
|
||||
case REMOTE_AUTH_DEFAULT_REALM:
|
||||
if ( ad->default_realm ) {
|
||||
ch_free( ad->default_realm );
|
||||
ad->default_realm = NULL;
|
||||
}
|
||||
ad->default_realm = ber_strdup( c->argv[1] );
|
||||
break;
|
||||
case REMOTE_AUTH_TLS:
|
||||
for ( i=1; i < c->argc; i++ ) {
|
||||
if ( bindconf_tls_parse( c->argv[i], &ad->ad_tls ) ) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bindconf_tls_defaults( &ad->ad_tls );
|
||||
break;
|
||||
case REMOTE_AUTH_TLS_PIN: {
|
||||
ad_pin *pin = ch_calloc( 1, sizeof(ad_pin) );
|
||||
|
||||
pin->hostname = ber_strdup( c->argv[1] );
|
||||
pin->pin = ber_strdup( c->argv[2] );
|
||||
pin->next = ad->pins;
|
||||
ad->pins = pin;
|
||||
} break;
|
||||
/* ARG_OFFSET */
|
||||
case REMOTE_AUTH_STORE_ON_SUCCESS:
|
||||
case REMOTE_AUTH_RETRY_COUNT:
|
||||
abort();
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_realm(
|
||||
const char *domain,
|
||||
ad_info *mappings,
|
||||
const char *default_realm,
|
||||
int *isfile )
|
||||
{
|
||||
ad_info *ai;
|
||||
char *dom = NULL, *ch, *ret = NULL;
|
||||
|
||||
if ( isfile ) *isfile = 0;
|
||||
|
||||
if ( !domain ) {
|
||||
ret = default_realm ? ch_strdup( default_realm ) : NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* munge any DOMAIN\user or DOMAIN:user values into just DOMAIN */
|
||||
|
||||
ch = strchr( domain, '\\' );
|
||||
if ( !ch ) ch = strchr( domain, ':' );
|
||||
|
||||
if ( ch ) {
|
||||
dom = ch_malloc( ch - domain + 1 );
|
||||
strncpy( dom, domain, ch - domain );
|
||||
dom[ch - domain] = '\0';
|
||||
} else {
|
||||
dom = ch_strdup( domain );
|
||||
}
|
||||
|
||||
for ( ai = mappings; ai; ai = ai->next )
|
||||
if ( strcasecmp( ai->domain, dom ) == 0 ) {
|
||||
ret = ch_strdup( ai->realm );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !ai )
|
||||
ret = default_realm ? ch_strdup( default_realm ) :
|
||||
NULL; /* no mapping found */
|
||||
exit:
|
||||
if ( dom ) ch_free( dom );
|
||||
if ( ret &&
|
||||
( strncasecmp( ret, FILE_PREFIX, strlen( FILE_PREFIX ) ) == 0 ) ) {
|
||||
char *p;
|
||||
|
||||
p = ret;
|
||||
ret = ch_strdup( p + strlen( FILE_PREFIX ) );
|
||||
ch_free( p );
|
||||
if ( isfile ) *isfile = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_ldap_url( const char *realm, int isfile )
|
||||
{
|
||||
char *ldap_url = NULL;
|
||||
FILE *fp;
|
||||
|
||||
if ( !realm ) return NULL;
|
||||
|
||||
if ( !isfile ) {
|
||||
if ( strstr( realm, "://" ) ) {
|
||||
return ch_strdup( realm );
|
||||
}
|
||||
|
||||
ldap_url = ch_malloc( 1 + strlen( LDAP_PREFIX ) + strlen( realm ) );
|
||||
sprintf( ldap_url, "%s%s", LDAP_PREFIX, realm );
|
||||
return ldap_url;
|
||||
}
|
||||
|
||||
fp = fopen( realm, "r" );
|
||||
if ( !fp ) {
|
||||
char ebuf[128];
|
||||
int saved_errno = errno;
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth: "
|
||||
"Unable to open realm file (%s)\n",
|
||||
sock_errstr( saved_errno, ebuf, sizeof(ebuf) ) );
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Read each line in the file and return a URL of the form
|
||||
* "ldap://<line1> ldap://<line2> ... ldap://<lineN>"
|
||||
* which can be passed to ldap_initialize.
|
||||
*/
|
||||
while ( !feof( fp ) ) {
|
||||
char line[512], *p;
|
||||
|
||||
p = fgets( line, sizeof(line), fp );
|
||||
if ( !p ) continue;
|
||||
|
||||
/* terminate line at first whitespace */
|
||||
for ( p = line; *p; p++ )
|
||||
if ( isspace( *p ) ) {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ldap_url ) {
|
||||
char *nu;
|
||||
|
||||
nu = ch_malloc( strlen( ldap_url ) + 2 + strlen( LDAP_PREFIX ) +
|
||||
strlen( line ) );
|
||||
|
||||
if ( strstr( line, "://" ) ) {
|
||||
sprintf( nu, "%s %s", ldap_url, line );
|
||||
} else {
|
||||
sprintf( nu, "%s %s%s", ldap_url, LDAP_PREFIX, line );
|
||||
}
|
||||
ch_free( ldap_url );
|
||||
ldap_url = nu;
|
||||
} else {
|
||||
ldap_url = ch_malloc( 1 + strlen( line ) + strlen( LDAP_PREFIX ) );
|
||||
if ( strstr( line, "://" ) ) {
|
||||
strcpy( ldap_url, line );
|
||||
} else {
|
||||
sprintf( ldap_url, "%s%s", LDAP_PREFIX, line );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
|
||||
return ldap_url;
|
||||
}
|
||||
|
||||
static void
|
||||
trace_remoteauth_parameters( ad_private *ap )
|
||||
{
|
||||
ad_info *pad_info;
|
||||
struct berval bv;
|
||||
|
||||
if ( !ap ) return;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_dn_attribute: %s\n",
|
||||
ap->dn ? ap->dn : "NULL" );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_domain_attribute: %s\n",
|
||||
ap->domain_attr ? ap->domain_attr : "NULL" );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_default_realm: %s\n",
|
||||
ap->default_realm ? ap->default_realm : "NULL" );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_default_domain: %s\n",
|
||||
ap->default_domain ? ap->default_domain : "NULL" );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_retry_count: %d\n", ap->retry_count );
|
||||
|
||||
bindconf_tls_unparse( &ap->ad_tls, &bv );
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_tls:%s\n", bv.bv_val );
|
||||
ch_free( bv.bv_val );
|
||||
|
||||
pad_info = ap->mappings;
|
||||
while ( pad_info ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_mappings(%s,%s)\n",
|
||||
pad_info->domain ? pad_info->domain : "NULL",
|
||||
pad_info->realm ? pad_info->realm : "NULL" );
|
||||
pad_info = pad_info->next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
remoteauth_conn_cb(
|
||||
LDAP *ld,
|
||||
Sockbuf *sb,
|
||||
LDAPURLDesc *srv,
|
||||
struct sockaddr *addr,
|
||||
struct ldap_conncb *ctx )
|
||||
{
|
||||
ad_private *ap = ctx->lc_arg;
|
||||
ad_pin *pin = NULL;
|
||||
char *host;
|
||||
|
||||
host = srv->lud_host;
|
||||
if ( !host || !*host ) {
|
||||
host = "localhost";
|
||||
}
|
||||
|
||||
for ( pin = ap->pins; pin; pin = pin->next ) {
|
||||
if ( !strcasecmp( host, pin->hostname ) ) break;
|
||||
}
|
||||
|
||||
if ( pin ) {
|
||||
int rc = ldap_set_option( ld, LDAP_OPT_X_TLS_PEERKEY_HASH, pin->pin );
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_conn_cb: "
|
||||
"TLS Peerkey hash could not be set to '%s': %d\n",
|
||||
pin->pin, rc );
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_conn_cb: "
|
||||
"No TLS Peerkey hash found for host '%s'\n",
|
||||
host );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
remoteauth_conn_delcb( LDAP *ld, Sockbuf *sb, struct ldap_conncb *ctx )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
remoteauth_bind( Operation *op, SlapReply *rs )
|
||||
{
|
||||
Entry *e;
|
||||
int rc;
|
||||
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
||||
ad_private *ap = (ad_private *)on->on_bi.bi_private;
|
||||
Attribute *a_dom, *a_dn;
|
||||
struct ldap_conncb ad_conncb = { .lc_add = remoteauth_conn_cb,
|
||||
.lc_del = remoteauth_conn_delcb,
|
||||
.lc_arg = ap };
|
||||
struct berval dn = { 0 };
|
||||
char *dom_val, *realm = NULL;
|
||||
char *ldap_url = NULL;
|
||||
LDAP *ld = NULL;
|
||||
int protocol = LDAP_VERSION3, isfile = 0;
|
||||
int tries = 0;
|
||||
|
||||
if ( LogTest( LDAP_DEBUG_TRACE ) ) {
|
||||
trace_remoteauth_parameters( ap );
|
||||
}
|
||||
|
||||
if ( op->orb_method != LDAP_AUTH_SIMPLE )
|
||||
return SLAP_CB_CONTINUE; /* only do password auth */
|
||||
|
||||
/* Can't handle root via this mechanism */
|
||||
if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) return SLAP_CB_CONTINUE;
|
||||
|
||||
if ( !ap->up_set ) {
|
||||
const char *txt = NULL;
|
||||
|
||||
if ( slap_str2ad( UP_STR, &ap->up_ad, &txt ) )
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_bind: "
|
||||
"userPassword attr undefined: %s\n",
|
||||
txt ? txt : "" );
|
||||
ap->up_set = 1;
|
||||
}
|
||||
|
||||
if ( !ap->up_ad ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_bind: "
|
||||
"password attribute not configured\n" );
|
||||
return SLAP_CB_CONTINUE; /* userPassword not defined */
|
||||
}
|
||||
|
||||
if ( !ap->dn ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_bind: "
|
||||
"remote DN attribute not configured\n" );
|
||||
return SLAP_CB_CONTINUE; /* no mapped DN attribute */
|
||||
}
|
||||
|
||||
if ( !ap->domain_attr ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "remoteauth_bind: "
|
||||
"domain attribute not configured\n" );
|
||||
return SLAP_CB_CONTINUE; /* no way to know domain */
|
||||
}
|
||||
|
||||
op->o_bd->bd_info = (BackendInfo *)on->on_info;
|
||||
rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
|
||||
if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
|
||||
|
||||
rc = SLAP_CB_CONTINUE;
|
||||
/* if userPassword is defined in entry, skip to the end */
|
||||
if ( attr_find( e->e_attrs, ap->up_ad ) ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"user has a password, skipping\n",
|
||||
op->o_log_prefix );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
a_dom = attr_find( e->e_attrs, ap->domain_ad );
|
||||
if ( !a_dom )
|
||||
dom_val = ap->default_domain;
|
||||
else {
|
||||
dom_val = a_dom->a_vals[0].bv_val;
|
||||
}
|
||||
|
||||
if ( !dom_val ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"user has no domain nor do we have a default, skipping\n",
|
||||
op->o_log_prefix );
|
||||
goto exit; /* user has no domain */
|
||||
}
|
||||
|
||||
realm = get_realm( dom_val, ap->mappings, ap->default_realm, &isfile );
|
||||
if ( !realm ) goto exit;
|
||||
|
||||
a_dn = attr_find( e->e_attrs, ap->dn_ad );
|
||||
if ( !a_dn ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"no remote DN found on user\n",
|
||||
op->o_log_prefix );
|
||||
goto exit; /* user has no DN for the other directory */
|
||||
}
|
||||
|
||||
ber_dupbv_x( &dn, a_dn->a_vals, op->o_tmpmemctx );
|
||||
be_entry_release_r( op, e );
|
||||
e = NULL;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"(realm, dn) = (%s, %s)\n",
|
||||
op->o_log_prefix, realm, dn.bv_val );
|
||||
|
||||
ldap_url = get_ldap_url( realm, isfile );
|
||||
if ( !ldap_url ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"No LDAP URL obtained\n",
|
||||
op->o_log_prefix );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = ldap_initialize( &ld, ldap_url );
|
||||
if ( rc ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"Cannot initialize %s: %s\n",
|
||||
op->o_log_prefix, ldap_url, ldap_err2string( rc ) );
|
||||
goto exit; /* user has no DN for the other directory */
|
||||
}
|
||||
|
||||
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &protocol );
|
||||
|
||||
#ifdef HAVE_TLS
|
||||
rc = bindconf_tls_set( &ap->ad_tls, ld );
|
||||
if ( rc ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"bindconf_tls_set failed\n",
|
||||
op->o_log_prefix );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( ap->pins ) {
|
||||
if ( (rc = ldap_set_option( ld, LDAP_OPT_CONNECT_CB, &ad_conncb )) !=
|
||||
LDAP_SUCCESS ) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (rc = ldap_connect( ld )) != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"Cannot connect to %s: %s\n",
|
||||
op->o_log_prefix, ldap_url, ldap_err2string( rc ) );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( ap->ad_tls.sb_tls && !ldap_tls_inplace( ld ) ) {
|
||||
if ( (rc = ldap_start_tls_s( ld, NULL, NULL )) != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"LDAP TLS failed %s: %s\n",
|
||||
op->o_log_prefix, ldap_url, ldap_err2string( rc ) );
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_TLS */
|
||||
|
||||
rc = ldap_sasl_bind_s( ld, dn.bv_val, LDAP_SASL_SIMPLE,
|
||||
&op->oq_bind.rb_cred, NULL, NULL, NULL );
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
if ( ap->store_on_success ) {
|
||||
const char *txt;
|
||||
|
||||
Operation op2 = *op;
|
||||
SlapReply r2 = { REP_RESULT };
|
||||
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
|
||||
Modifications m = {};
|
||||
|
||||
op2.o_tag = LDAP_REQ_MODIFY;
|
||||
op2.o_callback = &cb;
|
||||
op2.orm_modlist = &m;
|
||||
op2.orm_no_opattrs = 0;
|
||||
op2.o_dn = op->o_bd->be_rootdn;
|
||||
op2.o_ndn = op->o_bd->be_rootndn;
|
||||
|
||||
m.sml_op = LDAP_MOD_ADD;
|
||||
m.sml_flags = 0;
|
||||
m.sml_next = NULL;
|
||||
m.sml_type = ap->up_ad->ad_cname;
|
||||
m.sml_desc = ap->up_ad;
|
||||
m.sml_numvals = 1;
|
||||
m.sml_values = op->o_tmpcalloc(
|
||||
sizeof(struct berval), 2, op->o_tmpmemctx );
|
||||
|
||||
slap_passwd_hash( &op->oq_bind.rb_cred, &m.sml_values[0], &txt );
|
||||
if ( m.sml_values[0].bv_val == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "%s remoteauth_bind: "
|
||||
"password hashing for '%s' failed, storing password in "
|
||||
"plain text\n",
|
||||
op->o_log_prefix, op->o_req_dn.bv_val );
|
||||
ber_dupbv( &m.sml_values[0], &op->oq_bind.rb_cred );
|
||||
}
|
||||
|
||||
/*
|
||||
* If this server is a shadow use the frontend to perform this
|
||||
* modify. That will trigger the update referral, which can then be
|
||||
* forwarded by the chain overlay. Obviously the updateref and
|
||||
* chain overlay must be configured appropriately for this to be
|
||||
* useful.
|
||||
*/
|
||||
if ( SLAP_SHADOW(op->o_bd) ) {
|
||||
op2.o_bd = frontendDB;
|
||||
} else {
|
||||
op2.o_bd->bd_info = (BackendInfo *)on->on_info;
|
||||
}
|
||||
|
||||
if ( op2.o_bd->be_modify( &op2, &r2 ) != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY, "%s remoteauth_bind: "
|
||||
"attempt to store password in entry '%s' failed, "
|
||||
"ignoring\n",
|
||||
op->o_log_prefix, op->o_req_dn.bv_val );
|
||||
}
|
||||
ch_free( m.sml_values[0].bv_val );
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( rc == LDAP_INVALID_CREDENTIALS ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"ldap_sasl_bind_s (%s) failed: invalid credentials\n",
|
||||
op->o_log_prefix, ldap_url );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ( tries < ap->retry_count ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"ldap_sasl_bind_s failed %s: %s (try #%d)\n",
|
||||
op->o_log_prefix, ldap_url, ldap_err2string( rc ), tries );
|
||||
if ( ld ) ldap_unbind_ext_s( ld, NULL, NULL );
|
||||
tries++;
|
||||
goto retry;
|
||||
} else
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if ( dn.bv_val ) {
|
||||
op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
if ( e ) {
|
||||
be_entry_release_r( op, e );
|
||||
}
|
||||
if ( ld ) ldap_unbind_ext_s( ld, NULL, NULL );
|
||||
if ( ldap_url ) ch_free( ldap_url );
|
||||
if ( realm ) ch_free( realm );
|
||||
if ( rc == SLAP_CB_CONTINUE ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"continue\n", op->o_log_prefix );
|
||||
return rc;
|
||||
} else {
|
||||
/* for rc == 0, frontend sends result */
|
||||
if ( rc ) {
|
||||
if ( rc > 0 ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"failed\n", op->o_log_prefix );
|
||||
send_ldap_error( op, rs, rc, "remoteauth_bind failed" );
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_TRACE, "%s remoteauth_bind: "
|
||||
"operations error\n", op->o_log_prefix );
|
||||
send_ldap_error( op, rs, LDAP_OPERATIONS_ERROR,
|
||||
"remoteauth_bind operations error" );
|
||||
}
|
||||
}
|
||||
|
||||
return rs->sr_err;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
remoteauth_db_init( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)be->bd_info;
|
||||
ad_private *ap;
|
||||
|
||||
if ( SLAP_ISGLOBALOVERLAY(be) ) {
|
||||
Debug( LDAP_DEBUG_ANY, "remoteauth_db_init: "
|
||||
"remoteauth overlay must be instantiated within a "
|
||||
"database.\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
ap = ch_calloc( 1, sizeof(ad_private) );
|
||||
|
||||
ap->dn = NULL;
|
||||
ap->dn_ad = NULL;
|
||||
ap->domain_attr = NULL;
|
||||
ap->domain_ad = NULL;
|
||||
|
||||
ap->up_ad = NULL;
|
||||
ap->mappings = NULL;
|
||||
|
||||
ap->default_realm = NULL;
|
||||
ap->default_domain = NULL;
|
||||
|
||||
ap->pins = NULL;
|
||||
|
||||
ap->up_set = 0;
|
||||
ap->retry_count = 3;
|
||||
|
||||
on->on_bi.bi_private = ap;
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
remoteauth_db_destroy( BackendDB *be, ConfigReply *cr )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)be->bd_info;
|
||||
ad_private *ap = (ad_private *)on->on_bi.bi_private;
|
||||
ad_info *ai = ap->mappings;
|
||||
|
||||
while ( ai ) {
|
||||
if ( ai->domain ) ch_free( ai->domain );
|
||||
if ( ai->realm ) ch_free( ai->realm );
|
||||
ai = ai->next;
|
||||
}
|
||||
|
||||
if ( ap->dn ) ch_free( ap->dn );
|
||||
if ( ap->default_domain ) ch_free( ap->default_domain );
|
||||
if ( ap->default_realm ) ch_free( ap->default_realm );
|
||||
|
||||
bindconf_free( &ap->ad_tls );
|
||||
|
||||
ch_free( ap );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static slap_overinst remoteauth;
|
||||
|
||||
int
|
||||
remoteauth_initialize( void )
|
||||
{
|
||||
int rc;
|
||||
|
||||
remoteauth.on_bi.bi_type = "remoteauth";
|
||||
remoteauth.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
|
||||
|
||||
remoteauth.on_bi.bi_cf_ocs = remoteauthocs;
|
||||
rc = config_register_schema( remoteauthcfg, remoteauthocs );
|
||||
if ( rc ) return rc;
|
||||
|
||||
remoteauth.on_bi.bi_db_init = remoteauth_db_init;
|
||||
remoteauth.on_bi.bi_db_destroy = remoteauth_db_destroy;
|
||||
remoteauth.on_bi.bi_op_bind = remoteauth_bind;
|
||||
|
||||
return overlay_register( &remoteauth );
|
||||
}
|
||||
|
||||
#if SLAPD_OVER_ACCESSLOG == SLAPD_MOD_DYNAMIC
|
||||
int
|
||||
init_module( int argc, char *argv[] )
|
||||
{
|
||||
return remoteauth_initialize();
|
||||
}
|
||||
#endif
|
||||
21
tests/data/remoteauth/config.ldif
Normal file
21
tests/data/remoteauth/config.ldif
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
dn: olcOverlay={0}remoteauth,olcDatabase={1}@BACKEND@,cn=config
|
||||
objectClass: olcOverlayConfig
|
||||
objectclass: olcRemoteAuthCfg
|
||||
olcOverlay: {0}remoteauth
|
||||
olcRemoteAuthRetryCount: 3
|
||||
olcRemoteAuthTLS: starttls=critical
|
||||
tls_cert="@TESTDIR@/tls/certs/localhost.crt"
|
||||
tls_key="@TESTDIR@/tls/private/localhost.key"
|
||||
tls_cacert="@TESTDIR@/tls/ca/certs/testsuiteCA.crt"
|
||||
tls_reqcert=demand tls_reqsan=allow
|
||||
#openssl# tls_crlcheck=none
|
||||
olcRemoteAuthDNAttribute: seeAlso
|
||||
olcRemoteAuthDomainAttribute: o
|
||||
olcRemoteAuthDefaultDomain: default
|
||||
olcRemoteAuthDefaultRealm: @SURIP3@
|
||||
olcRemoteAuthStore: FALSE
|
||||
olcRemoteAuthMapping: default file://@TESTDIR@/default_domain
|
||||
olcRemoteAuthMapping: working_ldaps @SURIP3@
|
||||
olcRemoteAuthMapping: failing_ldaps @SURIP2@
|
||||
olcRemoteAuthMapping: self @URIP1@
|
||||
|
||||
3
tests/data/remoteauth/default_domain
Normal file
3
tests/data/remoteauth/default_domain
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
ldap://we/should/not/be/able/to/connect/to
|
||||
@SURIP2@
|
||||
@SURIP3@
|
||||
21
tests/data/remoteauth/remoteauth.conf
Normal file
21
tests/data/remoteauth/remoteauth.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
overlay remoteauth
|
||||
|
||||
# defaults
|
||||
#remoteauth_retry_count 3
|
||||
#remoteauth_store off
|
||||
|
||||
remoteauth_tls starttls=critical
|
||||
tls_cert=@TESTDIR@/tls/certs/localhost.crt
|
||||
tls_key=@TESTDIR@/tls/private/localhost.key
|
||||
tls_cacert=@TESTDIR@/tls/ca/certs/testsuiteCA.crt
|
||||
|
||||
remoteauth_dn_attribute seeAlso
|
||||
remoteauth_domain_attribute o
|
||||
remoteauth_default_domain default
|
||||
remoteauth_default_realm @SURIP3@
|
||||
|
||||
# It's a trap! (ehm... stack) cn=config entries will be emitted in reverse order
|
||||
remoteauth_mapping self @URIP1@
|
||||
remoteauth_mapping failing_ldaps @SURIP2@
|
||||
remoteauth_mapping working_ldaps @SURIP3@
|
||||
remoteauth_mapping default file://@TESTDIR@/default_domain
|
||||
|
|
@ -49,6 +49,7 @@ AC_memberof=memberof@BUILD_MEMBEROF@
|
|||
AC_pcache=pcache@BUILD_PROXYCACHE@
|
||||
AC_ppolicy=ppolicy@BUILD_PPOLICY@
|
||||
AC_refint=refint@BUILD_REFINT@
|
||||
AC_remoteauth=remoteauth@BUILD_REMOTEAUTH@
|
||||
AC_retcode=retcode@BUILD_RETCODE@
|
||||
AC_translucent=translucent@BUILD_TRANSLUCENT@
|
||||
AC_unique=unique@BUILD_UNIQUE@
|
||||
|
|
@ -75,8 +76,9 @@ if test "${AC_asyncmeta}" = "asyncmetamod" && test "${AC_LIBS_DYNAMIC}" = "stati
|
|||
AC_meta="asyncmetano"
|
||||
fi
|
||||
export AC_ldap AC_mdb AC_meta AC_asyncmeta AC_monitor AC_null AC_perl AC_relay AC_sql \
|
||||
AC_accesslog AC_autoca AC_constraint AC_dds AC_dynlist AC_memberof AC_pcache AC_ppolicy \
|
||||
AC_refint AC_retcode AC_rwm AC_unique AC_syncprov AC_translucent \
|
||||
AC_accesslog AC_autoca AC_constraint AC_dds AC_dynlist AC_memberof \
|
||||
AC_pcache AC_ppolicy AC_refint AC_remoteauth \
|
||||
AC_retcode AC_rwm AC_unique AC_syncprov AC_translucent \
|
||||
AC_valsort \
|
||||
AC_lloadd \
|
||||
AC_WITH_SASL AC_WITH_TLS AC_WITH_MODULES_ENABLED AC_ACI_ENABLED \
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ sed -e "s/@BACKEND@/${BACKEND}/" \
|
|||
-e "s/@RELAY@/${RELAY}/" \
|
||||
-e "s/^#relay-${RELAY}#//" \
|
||||
-e "s/^#${BACKENDTYPE}#//" \
|
||||
-e "s/^#${AC_TLS_TYPE}#//" \
|
||||
-e "s/^#${AC_ldap}#//" \
|
||||
-e "s/^#${AC_meta}#//" \
|
||||
-e "s/^#${AC_asyncmeta}#//" \
|
||||
|
|
@ -42,6 +43,7 @@ sed -e "s/@BACKEND@/${BACKEND}/" \
|
|||
-e "s/^#${AC_ppolicy}#//" \
|
||||
-e "s/^#${AC_refint}#//" \
|
||||
-e "s/^#${AC_retcode}#//" \
|
||||
-e "s/^#${AC_remoteauth}#//" \
|
||||
-e "s/^#${AC_rwm}#//" \
|
||||
-e "s/^#${AC_syncprov}#//" \
|
||||
-e "s/^#${AC_translucent}#//" \
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ MEMBEROF=${AC_memberof-memberofno}
|
|||
PROXYCACHE=${AC_pcache-pcacheno}
|
||||
PPOLICY=${AC_ppolicy-ppolicyno}
|
||||
REFINT=${AC_refint-refintno}
|
||||
REMOTEAUTH=${AC_remoteauth-remoteauthno}
|
||||
RETCODE=${AC_retcode-retcodeno}
|
||||
RWM=${AC_rwm-rwmno}
|
||||
SYNCPROV=${AC_syncprov-syncprovno}
|
||||
|
|
@ -54,7 +55,7 @@ ACI=${AC_ACI_ENABLED-acino}
|
|||
SLEEP0=${SLEEP0-1}
|
||||
SLEEP1=${SLEEP1-7}
|
||||
SLEEP2=${SLEEP2-15}
|
||||
TIMEOUT=${TIMEOUT-4}
|
||||
TIMEOUT=${TIMEOUT-8}
|
||||
|
||||
# dirs
|
||||
PROGDIR=./progs
|
||||
|
|
@ -65,6 +66,10 @@ case "$SCHEMADIR" in
|
|||
.*) ABS_SCHEMADIR="$TESTWD/$SCHEMADIR" ;;
|
||||
*) ABS_SCHEMADIR="$SCHEMADIR" ;;
|
||||
esac
|
||||
case "$SRCDIR" in
|
||||
.*) ABS_SRCDIR="$TESTWD/$SRCDIR" ;;
|
||||
*) ABS_SRCDIR="$SRCDIR" ;;
|
||||
esac
|
||||
|
||||
DBDIR1A=$TESTDIR/db.1.a
|
||||
DBDIR1B=$TESTDIR/db.1.b
|
||||
|
|
@ -181,6 +186,23 @@ SLURPLOG=$TESTDIR/slurp.log
|
|||
|
||||
CONFIGPWF=$TESTDIR/configpw
|
||||
|
||||
# wrappers (valgrind, gdb, environment variables, etc.)
|
||||
if [ -n "$WRAPPER" ]; then
|
||||
: # skip
|
||||
elif [ "$SLAPD_COMMON_WRAPPER" = gdb ]; then
|
||||
WRAPPER="$ABS_SRCDIR/scripts/grandchild_wrapper.py gdb -nx -x $ABS_SRCDIR/scripts/gdb.py -batch-silent -return-child-result --args"
|
||||
elif [ "$SLAPD_COMMON_WRAPPER" = valgrind ]; then
|
||||
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --fullpath-after=`dirname $ABS_SRCDIR` --keep-debuginfo=yes --leak-check=full"
|
||||
elif [ "$SLAPD_COMMON_WRAPPER" = "valgrind-errstop" ]; then
|
||||
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=1"
|
||||
elif [ "$SLAPD_COMMON_WRAPPER" = vgdb ]; then
|
||||
WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=0"
|
||||
fi
|
||||
|
||||
if [ -n "$WRAPPER" ]; then
|
||||
SLAPD_WRAPPER="$TESTWD/../libtool --mode=execute env $WRAPPER"
|
||||
fi
|
||||
|
||||
# args
|
||||
SASLARGS="-Q"
|
||||
TOOLARGS="-x $LDAP_TOOLARGS"
|
||||
|
|
@ -192,11 +214,11 @@ CONFDIRSYNC=$SRCDIR/scripts/confdirsync.sh
|
|||
|
||||
MONITORDATA=$SRCDIR/scripts/monitor_data.sh
|
||||
|
||||
SLAPADD="$TESTWD/../servers/slapd/slapd -Ta -d 0 $LDAP_VERBOSE"
|
||||
SLAPCAT="$TESTWD/../servers/slapd/slapd -Tc -d 0 $LDAP_VERBOSE"
|
||||
SLAPINDEX="$TESTWD/../servers/slapd/slapd -Ti -d 0 $LDAP_VERBOSE"
|
||||
SLAPMODIFY="$TESTWD/../servers/slapd/slapd -Tm -d 0 $LDAP_VERBOSE"
|
||||
SLAPPASSWD="$TESTWD/../servers/slapd/slapd -Tpasswd"
|
||||
SLAPADD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Ta -d 0 $LDAP_VERBOSE"
|
||||
SLAPCAT="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tc -d 0 $LDAP_VERBOSE"
|
||||
SLAPINDEX="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Ti -d 0 $LDAP_VERBOSE"
|
||||
SLAPMODIFY="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tm -d 0 $LDAP_VERBOSE"
|
||||
SLAPPASSWD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -Tpasswd"
|
||||
|
||||
unset DIFF_OPTIONS
|
||||
# NOTE: -u/-c is not that portable...
|
||||
|
|
@ -204,8 +226,8 @@ DIFF="diff -i"
|
|||
CMP="diff -i"
|
||||
BCMP="diff -iB"
|
||||
CMPOUT=/dev/null
|
||||
SLAPD="$TESTWD/../servers/slapd/slapd -s0"
|
||||
LLOADD="$TESTWD/../servers/lloadd/lloadd -s0"
|
||||
SLAPD="$SLAPD_WRAPPER $TESTWD/../servers/slapd/slapd -s0"
|
||||
LLOADD="$SLAPD_WRAPPER $TESTWD/../servers/lloadd/lloadd -s0"
|
||||
LDAPPASSWD="$CLIENTDIR/ldappasswd $TOOLARGS"
|
||||
LDAPSASLSEARCH="$CLIENTDIR/ldapsearch $SASLARGS $TOOLPROTO $LDAP_TOOLARGS -LLL"
|
||||
LDAPSASLWHOAMI="$CLIENTDIR/ldapwhoami $SASLARGS $LDAP_TOOLARGS"
|
||||
|
|
|
|||
85
tests/scripts/gdb.py
Normal file
85
tests/scripts/gdb.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# $OpenLDAP$
|
||||
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
##
|
||||
## Copyright 2020-2021 The OpenLDAP Foundation.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
"""
|
||||
This GDB script sets up the debugger to run the program and see if it finishes
|
||||
of its own accord or is terminated by a signal (like SIGABRT/SIGSEGV). In the
|
||||
latter case, it saves a full backtrace and core file.
|
||||
|
||||
These signals are considered part of normal operation and will not trigger the
|
||||
above handling:
|
||||
- SIGPIPE: normal in a networked environment
|
||||
- SIGHUP: normally used to tell a process to shut down
|
||||
"""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import gdb
|
||||
|
||||
|
||||
def format_program(inferior=None, thread=None):
|
||||
"Format program name and p(t)id"
|
||||
|
||||
if thread:
|
||||
inferior = thread.inferior
|
||||
elif inferior is None:
|
||||
inferior = gdb.selected_inferior()
|
||||
|
||||
try:
|
||||
name = os.path.basename(inferior.progspace.filename)
|
||||
except AttributeError: # inferior has died already
|
||||
name = "unknown"
|
||||
|
||||
if thread:
|
||||
pid = ".".join(tid for tid in thread.ptid if tid)
|
||||
else:
|
||||
pid = inferior.pid
|
||||
|
||||
return "{}.{}".format(name, pid)
|
||||
|
||||
|
||||
def stop_handler(event):
|
||||
"Inferior stopped on a signal, record core, backtrace and exit"
|
||||
|
||||
if not isinstance(event, gdb.SignalEvent):
|
||||
# Ignore breakpoints
|
||||
return
|
||||
|
||||
thread = event.inferior_thread
|
||||
|
||||
identifier = format_program(thread=thread)
|
||||
prefix = os.path.expandvars("${TESTDIR}/") + identifier
|
||||
|
||||
if event.stop_signal == "SIGHUP":
|
||||
# TODO: start a timer to catch shutdown issues/deadlocks
|
||||
gdb.execute("continue")
|
||||
return
|
||||
|
||||
gdb.execute('generate-core-file {}.core'.format(prefix))
|
||||
|
||||
with open(prefix + ".backtrace", "w") as bt_file:
|
||||
backtrace = gdb.execute("thread apply all backtrace full",
|
||||
to_string=True)
|
||||
bt_file.write(backtrace)
|
||||
|
||||
gdb.execute("continue")
|
||||
|
||||
|
||||
# We or we could allow the runner to disable randomisation
|
||||
gdb.execute("set disable-randomization off")
|
||||
|
||||
gdb.execute("handle SIGPIPE noprint")
|
||||
gdb.execute("handle SIGINT pass")
|
||||
gdb.events.stop.connect(stop_handler)
|
||||
gdb.execute("run")
|
||||
72
tests/scripts/grandchild_wrapper.py
Executable file
72
tests/scripts/grandchild_wrapper.py
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
# $OpenLDAP$
|
||||
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
##
|
||||
## Copyright 2020-2021 The OpenLDAP Foundation.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
"""
|
||||
Running slapd under GDB in our testsuite, KILLPIDS would record gdb's PID
|
||||
rather than slapd's. When we want the server to shut down, SIGHUP is sent to
|
||||
KILLPIDS but GDB cannot handle being signalled directly and the entire thing is
|
||||
terminated immediately. There might be tests that rely on slapd being given the
|
||||
chance to shut down gracefully, to do this, we need to make sure the signal is
|
||||
actually sent to slapd.
|
||||
|
||||
This script attempts to address this shortcoming in our test suite, serving as
|
||||
the front for gdb/other wrappers, catching SIGHUPs and redirecting them to the
|
||||
oldest living grandchild. The way we start up gdb, that process should be
|
||||
slapd, our intended target.
|
||||
|
||||
This requires the pgrep utility provided by the procps package on Debian
|
||||
systems.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
|
||||
|
||||
async def signal_to_grandchild(child):
|
||||
# Get the first child, that should be the one we're after
|
||||
pgrep = await asyncio.create_subprocess_exec(
|
||||
"pgrep", "-o", "--parent", str(child.pid),
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
|
||||
stdout, _ = await pgrep.communicate()
|
||||
if not stdout:
|
||||
return
|
||||
|
||||
grandchild = [int(pid) for pid in stdout.split()][0]
|
||||
|
||||
os.kill(grandchild, signal.SIGHUP)
|
||||
|
||||
|
||||
def sighup_handler(child):
|
||||
asyncio.create_task(signal_to_grandchild(child))
|
||||
|
||||
|
||||
async def main(args=None):
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
|
||||
child = await asyncio.create_subprocess_exec(*args)
|
||||
|
||||
# If we got a SIGHUP before we got the child fully started, there's no
|
||||
# point signalling anyway
|
||||
loop = asyncio.get_running_loop()
|
||||
loop.add_signal_handler(signal.SIGHUP, sighup_handler, child)
|
||||
|
||||
raise SystemExit(await child.wait())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
|
|
@ -48,6 +48,24 @@ if test $WAIT != 0 ; then
|
|||
read foo
|
||||
fi
|
||||
|
||||
echo "Using ldapsearch to check that slapd is running..."
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting $SLEEP1 seconds for slapd to start..."
|
||||
sleep $SLEEP1
|
||||
done
|
||||
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
#
|
||||
# Start ldapd that will proxy for the remote server
|
||||
#
|
||||
|
|
@ -66,15 +84,32 @@ fi
|
|||
|
||||
KILLPIDS="$SERVERPID $PROXYPID"
|
||||
|
||||
sleep $SLEEP0
|
||||
echo "Using ldapsearch to check that slapd is running..."
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting $SLEEP1 seconds for slapd to start..."
|
||||
sleep $SLEEP1
|
||||
done
|
||||
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Test 1: Test that shared connections are timed out
|
||||
#
|
||||
|
||||
NOW=`date +%s`
|
||||
echo "Create shared connection towards remote LDAP (time_t now=$NOW timeout=`expr $NOW + $TIMEOUT`)"
|
||||
CONN_BEGINS=`date +%s`
|
||||
CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
|
||||
echo "Create shared connection towards remote LDAP (time_t now=$CONN_BEGINS timeout=$CONN_EXPIRES)"
|
||||
|
||||
$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
|
|
@ -102,7 +137,7 @@ fi
|
|||
|
||||
# Check that connections are established by searching for olmDbConnURI from Monitor
|
||||
|
||||
echo "Checking that proxy has created connections towards backend"
|
||||
echo "Checking that proxy has created connections towards backend (time_t now=`date +%s`)"
|
||||
|
||||
$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
|
|
@ -129,9 +164,10 @@ fi
|
|||
# Wait for connections to be closed, either due to
|
||||
# - idle-timeout and
|
||||
# - conn-ttl
|
||||
|
||||
# sleep 2 second overtime for robustness of the test case
|
||||
echo "Sleeping until idle-timeout and conn-ttl have passed"
|
||||
sleep `expr $TIMEOUT + 1`
|
||||
NOW=`date +%s`
|
||||
sleep `expr $CONN_EXPIRES - $NOW + 2`
|
||||
|
||||
echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
|
||||
|
||||
|
|
@ -163,8 +199,9 @@ fi
|
|||
# Test 2: Test that private connections are timed out
|
||||
#
|
||||
|
||||
NOW=`date +%s`
|
||||
echo "Create private connection towards remote LDAP (time_t now=$NOW timeout=`expr $NOW + $TIMEOUT`)"
|
||||
CONN_BEGINS=`date +%s`
|
||||
CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
|
||||
echo "Create private connection towards remote LDAP (time_t now=$CONN_BEGINS timeout=$CONN_EXPIRES)"
|
||||
|
||||
# Create fifos that are used to pass searches from the test case to ldapsearch
|
||||
rm -f $TESTDIR/ldapsearch1.fifo $TESTDIR/ldapsearch2.fifo
|
||||
|
|
@ -192,9 +229,11 @@ exec 4>$TESTDIR/ldapsearch2.fifo
|
|||
# Trigger LDAP connections towards the proxy by executing a search
|
||||
echo 'objectclass=*' >&3
|
||||
echo 'objectclass=*' >&4
|
||||
sleep 1
|
||||
|
||||
echo "Checking that proxy has created connections towards backend"
|
||||
# wait for ldapsearches (running as background processes) to execute search operations
|
||||
sleep 2
|
||||
|
||||
echo "Checking that proxy has created connections towards backend (time_t now=`date +%s`)"
|
||||
|
||||
$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
|
|
@ -218,9 +257,13 @@ if test $RC != 0 ; then
|
|||
exit $RC
|
||||
fi
|
||||
|
||||
|
||||
# Wait for connections to be closed, either due to
|
||||
# - idle-timeout and
|
||||
# - conn-ttl
|
||||
# sleep 2 second overtime for robustness of the test case
|
||||
echo "Sleeping until idle-timeout and conn-ttl have passed"
|
||||
sleep `expr $TIMEOUT + 1`
|
||||
NOW=`date +%s`
|
||||
sleep `expr $CONN_EXPIRES - $NOW + 2`
|
||||
|
||||
echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
|
||||
|
||||
|
|
@ -258,8 +301,9 @@ exec 4>&-
|
|||
#
|
||||
|
||||
echo "Checking that idle-timeout is reset on activity"
|
||||
NOW=`date +%s`
|
||||
echo "Create cached connection: idle-timeout timeout starts (time_t now=$NOW, original_timeout=`expr $NOW + $TIMEOUT`)"
|
||||
CONN_BEGINS=`date +%s`
|
||||
CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
|
||||
echo "Create cached connection: idle-timeout timeout starts (time_t now=$CONN_BEGINS, original_timeout=$CONN_EXPIRES)"
|
||||
$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
-H $URI2 \
|
||||
|
|
@ -272,10 +316,13 @@ if test $RC != 0 ; then
|
|||
exit $RC
|
||||
fi
|
||||
|
||||
# sleep second less than idle-timeout to extend the timeout
|
||||
sleep `expr $TIMEOUT - 1`
|
||||
# sleep until 2 seconds before idle-timeout, then extend the timeout by executing another search operation
|
||||
NOW=`date +%s`
|
||||
echo "Do another search to reset the timeout (time_t now=$NOW, new_timeout=`expr $NOW + $TIMEOUT`)"
|
||||
sleep `expr $CONN_EXPIRES - $NOW - 2`
|
||||
|
||||
CONN_BEGINS=`date +%s`
|
||||
CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
|
||||
echo "Do another search to reset the timeout (time_t now=$CONN_BEGINS, new_timeout=$CONN_EXPIRES)"
|
||||
$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
-H $URI2 \
|
||||
|
|
@ -288,7 +335,9 @@ if test $RC != 0 ; then
|
|||
exit $RC
|
||||
fi
|
||||
|
||||
sleep `expr $TIMEOUT - 1`
|
||||
# sleep until 2 seconds before new extended idle-timeout, check that connection still exist
|
||||
NOW=`date +%s`
|
||||
sleep `expr $CONN_EXPIRES - $NOW - 2`
|
||||
echo "Check that connection is still alive due to idle-timeout reset (time_t now=`date +%s`)"
|
||||
$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
|
|
@ -301,7 +350,9 @@ if test $RC != 0 ; then
|
|||
exit $RC
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
# sleep until 2 seconds after timeout, check that connection does not exist
|
||||
NOW=`date +%s`
|
||||
sleep `expr $CONN_EXPIRES - $NOW + 2`
|
||||
echo "Check that connection is closed after extended idle-timeout has passed (time_t now=`date +%s`)"
|
||||
$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
|
||||
-D "cn=Manager,dc=local,dc=com" \
|
||||
|
|
@ -314,7 +365,6 @@ if test $RC != 1 ; then
|
|||
exit $RC
|
||||
fi
|
||||
|
||||
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
|
||||
echo ">>>>> Test succeeded"
|
||||
|
|
|
|||
417
tests/scripts/test082-remoteauth
Executable file
417
tests/scripts/test082-remoteauth
Executable file
|
|
@ -0,0 +1,417 @@
|
|||
#! /bin/sh
|
||||
# $OpenLDAP$
|
||||
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
##
|
||||
## Copyright 2016-2021 Ondřej Kuzník, Symas Corp.
|
||||
## Copyright 1998-2021 The OpenLDAP Foundation.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
|
||||
echo "running defines.sh"
|
||||
. $SRCDIR/scripts/defines.sh
|
||||
|
||||
if test $WITH_TLS = no ; then
|
||||
echo "TLS support not available, test skipped"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test $REMOTEAUTH = remoteauthno; then
|
||||
echo "RemoteAuth overlay not available, test skipped"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $TESTDIR/confdir
|
||||
cp -r $DATADIR/tls $TESTDIR
|
||||
|
||||
. $CONFFILTER < $DATADIR/remoteauth/default_domain > $TESTDIR/default_domain
|
||||
|
||||
. $CONFFILTER $BACKEND < $TLSCONF > $CONF1
|
||||
|
||||
$SLAPPASSWD -g -n >$CONFIGPWF
|
||||
echo "database config" >>$CONF1
|
||||
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
|
||||
echo "TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt" >>$CONF1
|
||||
|
||||
$SLAPD -Tt -n 0 -f $CONF1 -F $TESTDIR/confdir -d $LVL > $LOG1 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "slaptest failed ($RC)!"
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "Running slapadd to build slapd database... "
|
||||
$SLAPADD -F $TESTDIR/confdir -l $LDIFORDERED
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "slapadd failed ($RC)!"
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "DB tweaks..."
|
||||
$SLAPMODIFY -f $CONF1 >>$LOG1 2>&1 <<EOMODS
|
||||
dn: $MELLIOTDN
|
||||
changetype: modify
|
||||
add: o
|
||||
o: self
|
||||
-
|
||||
replace: seeAlso
|
||||
seeAlso: $BJORNSDN
|
||||
|
||||
dn: $JOHNDDN
|
||||
changetype: modify
|
||||
replace: seeAlso
|
||||
seeAlso: $BJORNSDN
|
||||
EOMODS
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "slapmodify failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "Starting slapd on TCP/IP port $PORT1 for configuration..."
|
||||
$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
|
||||
REMOTEAUTH_PID=$!
|
||||
if test $WAIT != 0 ; then
|
||||
echo REMOTEAUTH_PID $REMOTEAUTH_PID
|
||||
read foo
|
||||
fi
|
||||
KILLPIDS="$REMOTEAUTH_PID"
|
||||
|
||||
sleep $SLEEP0
|
||||
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting ${SLEEP1} seconds for slapd to start..."
|
||||
sleep ${SLEEP1}
|
||||
done
|
||||
|
||||
if [ "$REMOTEAUTH" = remoteauthmod ]; then
|
||||
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF \
|
||||
>> $TESTOUT 2>&1 <<EOMOD
|
||||
dn: cn=module,cn=config
|
||||
objectClass: olcModuleList
|
||||
cn: module
|
||||
olcModulePath: $TESTWD/../servers/slapd/overlays
|
||||
olcModuleLoad: remoteauth.la
|
||||
EOMOD
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapmodify failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Loading test remoteauth configuration..."
|
||||
. $CONFFILTER $BACKEND < $DATADIR/remoteauth/config.ldif | \
|
||||
$LDAPADD -v -D cn=config -H $URI1 -y $CONFIGPWF \
|
||||
>> $TESTOUT 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapadd failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "Preparing second server on $URI2 and $SURIP3... "
|
||||
. $CONFFILTER $BACKEND < $TLSCONF | sed -e "s,$DBDIR1,$DBDIR2," > $CONF2
|
||||
|
||||
echo -n "loading data... "
|
||||
$SLAPADD -f $CONF2 -l $LDIFORDERED
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "slapadd failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "tweaking DB contents... "
|
||||
$SLAPMODIFY -f $CONF2 >>$LOG2 2>&1 <<EOMODS
|
||||
dn: $BJORNSDN
|
||||
changetype: modify
|
||||
replace: userPassword
|
||||
userPassword: bjorn2
|
||||
EOMODS
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "slapmodify failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "starting up... "
|
||||
$SLAPD -f $CONF2 -h "$URI2 $SURIP3" -d $LVL > $LOG2 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
if test $WAIT != 0 ; then
|
||||
echo BACKEND_PID $BACKEND_PID
|
||||
read foo
|
||||
fi
|
||||
KILLPIDS="$KILLPIDS $BACKEND_PID"
|
||||
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting ${SLEEP1} seconds for slapd to start..."
|
||||
sleep ${SLEEP1}
|
||||
done
|
||||
|
||||
if test $RC != 0 ; then
|
||||
echo "failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
. $CONFFILTER $BACKEND < $TLSCONF > $CONF1
|
||||
|
||||
echo "TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt" >>$CONF1
|
||||
echo "database config" >>$CONF1
|
||||
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
|
||||
|
||||
# We check basic remoteauth operation and generated configuration in these
|
||||
# circumstances:
|
||||
# 1. configured online through cn=config (what we set up above)
|
||||
# 2. the server from 1. restarted (loading from cn=config on startup)
|
||||
# 3. configured and started through a slapd.conf
|
||||
#
|
||||
# All of the above should present the same behaviour and cn=config output
|
||||
|
||||
echo "Saving generated config before server restart..."
|
||||
echo "# search output from dynamically configured server..." >> $SERVER1OUT
|
||||
$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
|
||||
-b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
|
||||
>> $SERVER1OUT 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "Checking bind handling... "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "1 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "2 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "3 "
|
||||
|
||||
echo "ok"
|
||||
|
||||
echo "Stopping slapd on TCP/IP port $PORT1..."
|
||||
kill -HUP $REMOTEAUTH_PID
|
||||
KILLPIDS="$BACKEND_PID"
|
||||
sleep $SLEEP0
|
||||
echo "Starting slapd on TCP/IP port $PORT1..."
|
||||
$SLAPD -F $TESTDIR/confdir -h $URI1 -d $LVL >> $LOG1 2>&1 &
|
||||
REMOTEAUTH_PID=$!
|
||||
if test $WAIT != 0 ; then
|
||||
echo REMOTEAUTH_PID $REMOTEAUTH_PID
|
||||
read foo
|
||||
fi
|
||||
KILLPIDS="$KILLPIDS $REMOTEAUTH_PID"
|
||||
|
||||
sleep $SLEEP0
|
||||
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting ${SLEEP1} seconds for slapd to start..."
|
||||
sleep ${SLEEP1}
|
||||
done
|
||||
|
||||
echo "Saving generated config after server restart..."
|
||||
echo "# search output from dynamically configured server after restart..." >> $SERVER2OUT
|
||||
$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
|
||||
-b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
|
||||
>> $SERVER2OUT 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "Checking bind handling... "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "1 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "2 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "3 "
|
||||
|
||||
echo "ok"
|
||||
|
||||
echo "Stopping slapd on TCP/IP port $PORT1..."
|
||||
kill -HUP $REMOTEAUTH_PID
|
||||
KILLPIDS="$BACKEND_PID"
|
||||
sleep $SLEEP0
|
||||
|
||||
echo "Testing slapd.conf support..."
|
||||
sed -e "s,database\\s*monitor,\\
|
||||
TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt\\
|
||||
\\
|
||||
#remoteauthmod#moduleload ../servers/slapd/overlays/remoteauth.la\\
|
||||
include $TESTDIR/remoteauth.conf\\
|
||||
\\
|
||||
database monitor," $TLSCONF | . $CONFFILTER $BACKEND >$CONF1
|
||||
echo "database config" >>$CONF1
|
||||
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
|
||||
|
||||
. $CONFFILTER $BACKEND < $DATADIR/remoteauth/remoteauth.conf >$TESTDIR/remoteauth.conf
|
||||
|
||||
echo "Starting slapd on TCP/IP port $PORT1..."
|
||||
$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
|
||||
REMOTEAUTH_PID=$!
|
||||
if test $WAIT != 0 ; then
|
||||
echo REMOTEAUTH_PID $REMOTEAUTH_PID
|
||||
read foo
|
||||
fi
|
||||
KILLPIDS="$KILLPIDS $REMOTEAUTH_PID"
|
||||
|
||||
sleep $SLEEP0
|
||||
|
||||
for i in 0 1 2 3 4 5; do
|
||||
$LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
|
||||
'objectclass=*' > /dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting ${SLEEP1} seconds for slapd to start..."
|
||||
sleep ${SLEEP1}
|
||||
done
|
||||
|
||||
echo "Saving generated config from a slapd.conf sourced server..."
|
||||
echo "# search output from server running from slapd.conf..." >> $SERVER3OUT
|
||||
$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
|
||||
-b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
|
||||
>> $SERVER3OUT 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo -n "Checking bind handling... "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "1 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "2 "
|
||||
|
||||
$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapwhoami failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
echo -n "3 "
|
||||
|
||||
echo "ok"
|
||||
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
|
||||
# LDIFFILTER doesn't (un)wrap long lines yet, so the result would differ
|
||||
#. $CONFFILTER $BACKEND < $DATADIR/remoteauth/config.ldif \
|
||||
# | $LDIFFILTER -s a > $SERVER6FLT
|
||||
|
||||
# We've already filtered out the ordering markers, now sort the entries
|
||||
echo "Filtering ldapsearch results..."
|
||||
$LDIFFILTER -s a < $SERVER1OUT > $SERVER1FLT
|
||||
$LDIFFILTER -s a < $SERVER2OUT > $SERVER2FLT
|
||||
$LDIFFILTER -s a < $SERVER3OUT > $SERVER3FLT
|
||||
echo "Filtering expected entries..."
|
||||
|
||||
echo "Comparing filter output..."
|
||||
#$CMP $SERVER6FLT $SERVER1FLT > $CMPOUT && \
|
||||
$CMP $SERVER1FLT $SERVER2FLT > $CMPOUT && \
|
||||
$CMP $SERVER2FLT $SERVER3FLT > $CMPOUT
|
||||
|
||||
if test $? != 0 ; then
|
||||
echo "Comparison failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ">>>>> Test succeeded"
|
||||
|
||||
test $KILLSERVERS != no && wait
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in a new issue