lloadd ahoy

This commit is contained in:
Ondřej Kuzník 2017-03-08 22:59:57 +00:00 committed by Ondřej Kuzník
parent a87ae275e1
commit 46ddb4039c
25 changed files with 6537 additions and 1 deletions

1
.gitignore vendored
View file

@ -96,6 +96,7 @@ servers/slapd/slapmodify
servers/slapd/slappasswd
servers/slapd/slapschema
servers/slapd/slaptest
servers/lloadd/lloadd
tests/progs/ldif-filter
tests/progs/slapd-addel
tests/progs/slapd-bind

View file

@ -164,6 +164,8 @@ LTHREAD_LIBS = @LTHREAD_LIBS@
SLAPD_NDB_LIBS = @SLAPD_NDB_LIBS@
WT_LIBS = @WT_LIBS@
LEVENT_LIBS = @LEVENT_LIBS@
LDAP_LIBLBER_LA = $(LDAP_LIBDIR)/liblber/liblber.la
LDAP_LIBLDAP_LA = $(LDAP_LIBDIR)/libldap/libldap.la
@ -175,6 +177,8 @@ LDAP_L = $(LDAP_LIBLUTIL_A) \
$(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA)
SLAPD_L = $(LDAP_LIBLUNICODE_A) $(LDAP_LIBREWRITE_A) \
$(LDAP_LIBLUTIL_A) $(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA)
LLOADD_L = $(LDAP_LIBLUTIL_A) $(LDAP_LIBLDAP_LA) \
$(LDAP_LIBLBER_LA)
WRAP_LIBS = @WRAP_LIBS@
# AutoConfig generated
@ -202,6 +206,7 @@ SLAPD_SQL_INCLUDES = @SLAPD_SQL_INCLUDES@
SLAPD_SQL_LIBS = @SLAPD_SQL_LIBS@
SLAPD_LIBS = @SLAPD_LIBS@ @SLAPD_PERL_LDFLAGS@ @SLAPD_SQL_LDFLAGS@ @SLAPD_SQL_LIBS@ @SLAPD_SLP_LIBS@ @SLAPD_GMP_LIBS@
LLOADD_LIBS = @BALANCER_LIBS@ $(LEVENT_LIBS)
# Our Defaults
CC = $(AC_CC)

View file

@ -410,6 +410,12 @@ OL_ARG_ENABLE(unique, [AS_HELP_STRING([--enable-unique], [Attribute Uniqueness o
OL_ARG_ENABLE(valsort, [AS_HELP_STRING([--enable-valsort], [Value Sorting overlay])],
no, [no yes mod], ol_enable_overlays)
dnl ----------------------------------------------------------------
dnl BALANCER OPTIONS
AC_ARG_ENABLE(balanceroptions,[
LLOADD (Load Balancer Daemon) Options:])
OL_ARG_ENABLE(balancer,[ --enable-balancer enable building load balancer], auto)dnl
dnl ----------------------------------------------------------------
AC_ARG_ENABLE(xxliboptions,[
Library Generation & Linking Options])
@ -481,6 +487,13 @@ if test $ol_enable_modules = yes ; then
ol_enable_dynamic=yes
fi
if test $ol_enable_balancer = yes ; then
dnl Load Balancer was specifically enabled
if test $ol_with_threads = no ; then
AC_MSG_ERROR([Load balancer requires threads])
fi
fi
if test $ol_enable_spasswd = yes ; then
if test $ol_with_cyrus_sasl = no ; then
AC_MSG_ERROR([--enable-spasswd requires --with-cyrus-sasl])
@ -504,13 +517,16 @@ LDAP_LIBS=
SLAPD_NDB_LIBS=
SLAPD_NDB_INCS=
LTHREAD_LIBS=
LEVENT_LIBS=
LUTIL_LIBS=
CLIENT_LIBS=
SLAPD_LIBS=
BALANCER_LIBS=
BUILD_SLAPD=no
BUILD_BALANCER=no
BUILD_THREAD=no
@ -2128,6 +2144,24 @@ if test $ol_enable_slp != no ; then
fi
fi
dnl ----------------------------------------------------------------
dnl Libevent
if test $ol_enable_balancer != no ; then
AC_CHECK_LIB(event_core, evconnlistener_set_error_cb,
[have_libevent=yes
LEVENT_LIBS="$LEVENT_LIBS -levent_core"],
[AC_CHECK_LIB(event, evconnlistener_set_error_cb,
[have_libevent=yes
LEVENT_LIBS="$LEVENT_LIBS -levent"],
[have_libevent=no])])
if test $have_libevent = yes ; then
AC_DEFINE(HAVE_LIBEVENT, 1, [define if you have -levent])
elif test $ol_enable_balancer = yes ; then
AC_MSG_ERROR([You need libevent 2.0 or later to build the load balancer])
fi
fi
dnl ----------------------------------------------------------------
dnl Checks for typedefs, structures, and compiler characteristics.
@ -2930,6 +2964,12 @@ if test "$ol_enable_valsort" != no ; then
AC_DEFINE_UNQUOTED(SLAPD_OVER_VALSORT,$MFLAG,[define for Value Sorting overlay])
fi
if test "$ol_enable_balancer" != no \
-a "$ol_with_threads" != no \
-a "$have_libevent" = yes ; then
BUILD_BALANCER=yes
fi
if test "$ol_enable_slapi" != no ; then
AC_DEFINE(ENABLE_SLAPI,1,[define to enable slapi library])
BUILD_SLAPI=yes
@ -3002,14 +3042,17 @@ dnl overlays
AC_SUBST(BUILD_TRANSLUCENT)
AC_SUBST(BUILD_UNIQUE)
AC_SUBST(BUILD_VALSORT)
AC_SUBST(BUILD_BALANCER)
AC_SUBST(LDAP_LIBS)
AC_SUBST(CLIENT_LIBS)
AC_SUBST(SLAPD_LIBS)
AC_SUBST(BALANCER_LIBS)
AC_SUBST(SLAPD_NDB_LIBS)
AC_SUBST(SLAPD_NDB_INCS)
AC_SUBST(LTHREAD_LIBS)
AC_SUBST(LUTIL_LIBS)
AC_SUBST(LEVENT_LIBS)
AC_SUBST(WRAP_LIBS)
AC_SUBST(SLAPD_MODULES_CPPFLAGS)
@ -3091,6 +3134,7 @@ AC_CONFIG_FILES([Makefile:build/top.mk:Makefile.in:build/dir.mk]
[servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk]
[servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk]
[servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk]
[servers/lloadd/Makefile:build/top.mk:servers/lloadd/Makefile.in:build/srv.mk]
[tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk]
[tests/run]
[tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk])

282
doc/devel/lloadd/design.md Normal file
View file

@ -0,0 +1,282 @@
TODO:
- [ ] keep a global op in-flight counter? (might need locking)
- [-] scheduling (who does what, more than one select thread? How does the proxy
work get distributed between threads?)
- [ ] managing timeouts?
- [X] outline locking policy: seems like there might be a lock inversion in the
design looming: when working with op, might need a lock on both client and
upstream but depending on where we started, we might want to start with
locking one, then other
- [ ] how to deal with the balancer running out of fds? Especially when we hit
the limit, then lose an upstream connection and accept() a client, we
wouldn't be able to initiate a new one. A bit of a DoS... But probably not
a concern for Ericsson
- [ ] non-Linux? No idea how anything other than poll works (moot if building a
libevent/libuv-based load balancer since they take care of that, except
edge-triggered I/O?)
- [-] rootDSE? Controls and exops might have different semantics and need
binding to the same upstream connection.
- [ ] Just piggybacking on OpenLDAP as a module? Would still need some updates
in the core and the module/subsystem would be a very invasive one. On the
other hand, allows to expose live configuration and monitoring over LDAP
over the current slapd listeners without re-inventing the wheel.
Expecting to handle only LDAPv3
terms:
server - configured target
upstream - a single connection to a server
client - an incoming connection
To maintain fairness `G( requested => ( F( progressed | failed ) ) )`, use
queues and put timeouts in
Runtime organisation
------
- main thread with its own event base handling signals
- one thread (later possibly more) listening on the rendezvous sockets, handing
the new sockets to worker threads
- n worker threads dealing with client and server I/O (dispatching actual work
to the thread pool most likely)
- a thread pool to handle actual work
Operational behaviour
------
- client read -> upstream write:
- client read:
- if TLS_SETUP, keep processing, set state back when finished and note that
we're under TLS
- ber_get_next(), if we don't have a tag, finished (unless we have true
edge-triggered I/O, also put the fd back into the ones we're waiting for)
- peek at op tag:
- unbind:
- with a single lock, mark all pending ops in upstreams abandoned, clear
client link (would it be fast enough if we remove them from upstream
map instead?)
- locked per op:
- remove op from upstream map
- check upstream is not write-suspended, if it is ...
- try to write the abandon op to upstream, suspend upstream if not
fully sent
- remove op from client map (how if we're in avl_apply?, another pass?)
- would be nice if we could wipe the complete client map then, otherwise
we need to queue it to have it freed when all abandons get passed onto
the upstream (just dropping them might put extra strain on upstreams,
will probably have a queue on each client/upstream anyway, not just a
single Ber)
- bind:
- check mechanism is not EXTERNAL (or implement it)
- abandon existing ops (see unbind)
- set state to BINDING, put DN into authzid
- pick upstream, create PDU and sent
- abandon:
- find op, mark for abandon, send to appropriate upstream
- Exop:
- check not BINDING (unless it's a cancel?)
- check OID:
- STARTTLS:
- check we don't have TLS yet
- abandon all
- set state to TLS_SETUP
- send the hello
- VC(?):
- similar to bind except for the abandons/state change
- other:
- check not BINDING
- pick an upstream
- create a PDU, send (marking upstream suspended if not written in full)
- check if should read again (keep a counter of number of times to read
off a connection in a single pass so that we maintain fairness)
- if read enough requests and can still read, re-queue ourselves (if we
don't have true edge-triggered I/O, we can just register the fd again)
- upstream write (only when suspended):
- flush the current BER
- there shouldn't be anything else?
- upstream read -> client write:
- upstream read:
- ber_get_next(), if we don't have a tag, finished (unless we have true
edge-triggered I/O, also put the fd back into the ones we're waiting for)
- when we get it, peek at msgid, resolve client connection, lock, check:
- if unsolicited, handle as close (and mark connection closing)
- if op is abandoned or does not exist, drop PDU and op, update counters
- if client backlogged, suspend upstream, register callback to unsuspend
(on progress when writing to client or abandon from client (connection
death, abandon proper, ...))
- reconstruct final PDU, write BER to client, if did not write fully,
suspend client
- if a final response, decrement operation counts on upstream and client
- check if should read again (keep a counter of number of responses to read
off a connection in a single pass so that we don't starve any?)
- client write ready (only checked for when suspended):
- write the rest of pending BER if any
- on successful write, pick all pending ops that need failure response, push
to client (are there any controls that need to be present in response even
in the case of failure?, what to do with them?)
- on successfully flushing them, walk through suspended upstreams, picking
the pending PDU (unsuspending the upstream) and writing, if PDU flushed
successfully, pick next upstream
- if we successfully flushed all suspended upstreams, unsuspend client
(and disable the write callback)
- upstream close/error:
- look up pending ops, try to write to clients, mark clients suspended that
have ops that need responses (another queue associated with client to speed
up?)
- schedule a new connection open
- client close/error:
- same as unbind
- client inactive (no pending ops and nothing happened in x seconds)
- might just send notice of disconnection and close
- op timeout handling:
- mark for abandon
- send abandon
- send timeLimitExceeded/adminLimitExceeded to client
Picking an upstream:
- while there is a level available:
- pick a random ordering of upstreams based on weights
- while there is an upstream in the level:
- check number of ops in-flight (this is where we lock the upstream map)
- find the least busy connection (and check if a new connection should be
opened)
- try to lock for socket write, if available (no BER queued) we have our
upstream
PDU processing:
- request (have an upstream selected):
- get new msgid from upstream
- create an Op structure (actually, with the need for freelist lock, we can
make it a cache for freed operation structures, avoiding some malloc
traffic, to reset, we need slap_sl_mem_create( ,,, 1 ))
- check proxyauthz is not present? or just let upstream reject it if there are
two?
- add own controls at the end:
- construct proxyauthz from authzid
- construct session tracking from remote IP, own name, authzid
- send over
- insert Op into client and upstream maps
- response/intermediate/entry:
- look up Op in upstream's map
- write old msgid, rest of the response can go unchanged
- if a response, remove Op from all maps (client and upstream)
Managing upstreams:
- async connect up to min_connections (is there a point in having a connection
count range if we can't use it when needed since all of the below is async?)
- when connected, set up TLS (if requested)
- when done, send a bind
- go for the bind interaction
- when done, add it to the upstream's connection list
- (if a connection is suspended or connections are over 75 % op limit, schedule
creating a new connection setup unless connection limit has been hit)
Managing timeouts:
- two options:
- maintain a separate locked priority queue to give a perfect ordering to when
each operation is to time out, would need to maintain yet another place
where operations can be found.
- the locking protocol for disposing of the operation would need to be
adjusted and might become even more complicated, might do the alternative
initially and then attempt this if it helps performance
- just do a sweep over all clients (that mutex is less contended) every so
often. With many in-flight operations might be a lot of wasted work.
- we still need to sweep over all clients to check if they should be killed
anyway
Dispatcher thread (2^n of them, fd x is handled by thread no x % (2^n)):
- poll on all registered fds
- remove each fd that's ready from the registered list and schedule the work
- work threads can put their fd back in if they deem necessary (=not suspended)
- this works as a poor man's edge-triggered polling, with enough workers, should
we do proper edge triggered I/O? What about non-Linux?
Listener thread:
- slapd has just one, which then reassigns the sockets to separate I/O
threads
Threading:
- if using slap_sl_malloc, how much perf do we gain? To allocate a context per
op, we should have a dedicated parent context so that when we free it, we can
use that exclusively. The parent context's parent would be the main thread's
context. This implies a lot of slap_sl_mem_setctx/slap_sl_mem_create( ,,, 0 )
and making sure an op does not allocate/free things from two threads at the
same time (might need an Op mutex after all? Not such a huge cost if we
routinely reuse Op structures)
Locking policy:
- read mutexes are unnecessary, we only have one thread receiving data from the
connection - the one started from the dispatcher
- two reference counters of operation structures (an op is accessible from
client and upstream map, each counter is consistent when thread has a lock on
corresponding map), when decreasing the counter to zero, start freeing
procedure
- place to mark disposal finished for each side, consistency enforced by holding
the freelist lock when reading/manipulating
- when op is created, we already have a write lock on upstream socket and map,
start writing, insert to upstream map with upstream refcount 1, unlock, lock
client, insert (client refcount 0), unlock, lock upstream, decrement refcount
(triggers a test if we need to drop it now), unlock upstream, done
- when upstream processes a PDU, locks its map, increments counter, (potentially
removes if it's a response), unlocks, locks client's map, write mutex (this
order?) and full client mutex (if a bind response)
- when client side wants to work with a PDU (abandon, (un)bind), locks its map,
increase refcount, unlocks, locks upstream map, write mutex, sends or queues
abandon, unlocks write mutex, initiates freeing procedure from upstream side
(or if having to remember we've already increased client-side refcount, mark
for deletion, lose upstream lock, lock client, decref, either triggering
deletion from client or mark for it)
- if we have operation lock, we can simplify a bit (no need for three-stage
locking above)
Shutdown:
- stop accept() thread(s) - potentially add a channel to hand these listening
sockets over for zero-downtime restart
- if very gentle, mark connections as closing, start timeout and:
- when a new non-abandon PDU comes in from client - return LDAP_UNAVAILABLE
- when receiving a PDU from upstream, send over to client, if no ops pending,
send unsolicited response and close (RFC4511 suggests unsolicited response
is the last PDU coming from the upstream and libldap agrees, so we can't
send it for a socket we want to shut down more gracefully)
- gentle (or very gentle timed out):
- set timeout
- mark all ops as abandoned
- send unbind to all upstreams
- send unsolicited to all clients
- imminent (or gentle timed out):
- async close all connections?
- exit()
RootDSE:
- default option is not to care and if a control/exop has special restrictions,
it is the admin's job to flag it as such in the load-balancer's config
- another is not to care about the search request but check each search entry
being passed back, check DN and if it's a rootDSE, filter the list of
controls/exops/sasl mechs (external!) that are supported
- last one is to check all search requests for the DN/scope and synthesise the
response locally - probably not (would need to configure the complete list of
controls, exops, sasl mechs, naming contexts in the balancer)
Potential red flags:
- we suspend upstreams, if we ever suspend clients we need to be sure we can't
create dependency cycles
- is this an issue when only suspending the read side of each? Because even if
we stop reading from everything, we should eventually flush data to those we
can still talk to, as upstreams are flushed, we can start sending new
requests from live clients (those that are suspended are due to their own
inability to accept data)
- we might need to suspend a client if there is a reason to choose a
particular upstream (multi-request operation - bind, VC, PR, TXN, ...)
- a SASL bind, but that means there are no outstanding ops to receive
it holds that !suspended(client) \or !suspended(upstream), so they
cannot participate in a cycle
- VC - multiple binds at the same time - !!! more analysis needed
- PR - should only be able to have one per connection (that's a problem
for later, maybe even needs a dedicated upstream connection)
- TXN - ??? probably same situation as PR
- or if we have a queue for pending Bers on the server, we not need to suspend
clients, upstream is only chosen if the queue is free or there is a reason
to send it to that particular upstream (multi-stage bind/VC, PR, ...), but
that still makes it possible for a client to exhaust all our memory by
sending requests (VC or other ones bound to a slow upstream or by not
reading the responses at all)

View file

@ -63,4 +63,9 @@
/* dn of the default "monitor" subentry */
#define SLAPD_MONITOR_DN "cn=Monitor"
/*
* LLOADD DEFINITIONS
*/
#define LLOADD_DEFAULT_CONFIGFILE LDAP_SYSCONFDIR LDAP_DIRSEP "lloadd.conf"
#endif /* _LDAP_CONFIG_H */

View file

@ -13,5 +13,5 @@
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
SUBDIRS= slapd
SUBDIRS= slapd lloadd

View file

@ -0,0 +1,74 @@
# Makefile.in for Load Balancer
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2020 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>.
PROGRAMS = lloadd
XPROGRAMS = slloadd
XSRCS = version.c
NT_SRCS = nt_svc.c
NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res
SRCS = main.c globals.c config.c connection.c client.c daemon.c \
ch_malloc.c init.c user.c sl_malloc.c value.c \
libevent_support.c \
$(@PLAT@_SRCS)
OBJS = $(patsubst %.c,%.o,$(SRCS)) $(@PLAT@_OBJS)
LDAP_INCDIR= ../../include -I$(srcdir)
LDAP_LIBDIR= ../../libraries
BUILD_OPT = "--enable-balancer"
BUILD_SRV = @BUILD_BALANCER@
all-local-srv: $(PROGRAMS)
# $(LTHREAD_LIBS) must be last!
XLIBS = $(LLOADD_L)
XXLIBS = $(LLOADD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS)
XXXLIBS = $(LTHREAD_LIBS)
NT_DEPENDS = slapd.exp
NT_OBJECTS = slapd.exp symdummy.o $(LLOADD_OBJS) version.o
UNIX_DEPENDS = version.o $(LLOADD_L)
UNIX_OBJECTS = $(OBJS) version.o
LLOADD_DEPENDS = $(@PLAT@_DEPENDS)
LLOADD_OBJECTS = $(@PLAT@_OBJECTS)
lloadd: $(LLOADD_DEPENDS) version.o
$(LTLINK) -o $@ $(OBJS) version.o $(LIBS)
slloadd: version.o
$(LTLINK) -static -o $@ $(OBJS) version.o $(LIBS)
version.c: Makefile
@-$(RM) $@
$(MKVERSION) -s -n Versionstr lloadd > $@
version.o: version.c $(OBJS) $(LLOADD_L)
install-local-srv: FORCE
-$(MKDIR) $(DESTDIR)$(libexecdir)
@-$(INSTALL) -m 700 -d $(DESTDIR)$(localstatedir)/openldap-lloadd
@( \
for prg in $(PROGRAMS); do \
$(LTINSTALL) $(INSTALLFLAGS) $(STRIP) -m 755 $$prg$(EXEEXT) \
$(DESTDIR)$(libexecdir); \
done \
)

1
servers/lloadd/ch_malloc.c Symbolic link
View file

@ -0,0 +1 @@
../slapd/ch_malloc.c

103
servers/lloadd/client.c Normal file
View file

@ -0,0 +1,103 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 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>.
*/
#include "portable.h"
#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include "lutil.h"
#include "slap.h"
static void client_destroy( Connection *c );
static void
client_read_cb( evutil_socket_t s, short what, void *arg )
{
Connection *c = arg;
Debug( LDAP_DEBUG_CONNS, "client_read_cb: "
"connection %lu ready to read\n",
c->c_connid );
evutil_closesocket( s );
client_destroy( c );
}
static void
client_write_cb( evutil_socket_t s, short what, void *arg )
{
Connection *c = arg;
}
Connection *
client_init(
ber_socket_t s,
Listener *listener,
const char *peername,
struct event_base *base,
int flags )
{
Connection *c;
struct event *event;
assert( listener != NULL );
c = connection_init( s, peername, flags );
event = event_new( base, s, EV_READ|EV_PERSIST, client_read_cb, c );
if ( !event ) {
Debug( LDAP_DEBUG_ANY, "Read event could not be allocated\n" );
goto fail;
}
event_add( event, NULL );
c->c_read_event = event;
event = event_new( base, s, EV_WRITE, client_write_cb, c );
if ( !event ) {
Debug( LDAP_DEBUG_ANY, "Write event could not be allocated\n" );
goto fail;
}
/* We only register the write event when we have data pending */
c->c_write_event = event;
c->c_private = listener;
return c;
fail:
if ( c->c_write_event ) {
event_del( c->c_write_event );
event_free( c->c_write_event );
}
if ( c->c_read_event ) {
event_del( c->c_read_event );
event_free( c->c_read_event );
}
connection_destroy( c );
return NULL;
}
static void
client_destroy( Connection *c )
{
event_del( c->c_read_event );
event_free( c->c_read_event );
event_del( c->c_write_event );
event_free( c->c_write_event );
connection_destroy( c );
}

2374
servers/lloadd/config.c Normal file

File diff suppressed because it is too large Load diff

147
servers/lloadd/config.h Normal file
View file

@ -0,0 +1,147 @@
/* config.h - configuration abstraction structure */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 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>.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <ac/string.h>
LDAP_BEGIN_DECL
typedef struct ConfigTable {
const char *name;
const char *what;
int min_args;
int max_args;
int length;
unsigned int arg_type;
void *arg_item;
} ConfigTable;
/* search entries are returned according to this order */
typedef enum {
Cft_Abstract = 0,
Cft_Global,
Cft_Module,
Cft_Schema,
Cft_Backend,
Cft_Database,
Cft_Overlay,
Cft_Misc /* backend/overlay defined */
} ConfigType;
#define ARGS_USERLAND 0x00000fff
/* types are enumerated, not a bitmask */
#define ARGS_TYPES 0x0000f000
#define ARG_INT 0x00001000
#define ARG_LONG 0x00002000
#define ARG_BER_LEN_T 0x00003000
#define ARG_ON_OFF 0x00004000
#define ARG_STRING 0x00005000
#define ARG_BERVAL 0x00006000
#define ARG_UINT 0x00008000
#define ARG_ULONG 0x0000a000
#define ARG_BINARY 0x0000b000
#define ARGS_SYNTAX 0xffff0000
#define ARG_IGNORED 0x00080000
#define ARG_PAREN 0x01000000
#define ARG_NONZERO 0x02000000
#define ARG_NO_INSERT 0x04000000 /* no arbitrary inserting */
#define ARG_NO_DELETE 0x08000000 /* no runtime deletes */
#define ARG_UNIQUE 0x10000000
#define ARG_QUOTE 0x20000000 /* wrap with quotes before parsing */
#define ARG_OFFSET 0x40000000
#define ARG_MAGIC 0x80000000
#define ARG_BAD_CONF 0xdead0000 /* overload return values */
struct config_args_s;
typedef int (ConfigDriver)( struct config_args_s *c );
struct config_reply_s {
int err;
char msg[SLAP_TEXT_BUFLEN];
};
typedef struct config_args_s {
int argc;
char **argv;
int argv_size;
char *line;
char *tline;
const char *fname;
int lineno;
int linelen;
char log[MAXPATHLEN + STRLENOF(": line ") +
LDAP_PVT_INTTYPE_CHARS(unsigned long)];
#define cr_msg reply.msg
ConfigReply reply;
int depth;
int valx; /* multi-valued value index */
/* parsed first val for simple cases */
union {
int v_int;
unsigned v_uint;
long v_long;
size_t v_ulong;
ber_len_t v_ber_t;
char *v_string;
struct berval v_bv;
} values;
/* return values for emit mode */
BerVarray rvalue_vals;
BerVarray rvalue_nvals;
#define SLAP_CONFIG_EMIT 0x2000 /* emit instead of set */
#define SLAP_CONFIG_ADD 0x4000 /* config file add vs LDAP add */
int op;
int type; /* ConfigTable.arg_type & ARGS_USERLAND */
void *ca_private; /* anything */
#ifndef SLAP_CONFIG_CLEANUP_MAX
#define SLAP_CONFIG_CLEANUP_MAX 16
#endif
ConfigDriver *cleanups[SLAP_CONFIG_CLEANUP_MAX];
ConfigType table; /* which config table did we come from */
int num_cleanups;
} ConfigArgs;
#define value_int values.v_int
#define value_uint values.v_uint
#define value_long values.v_long
#define value_ulong values.v_ulong
#define value_ber_t values.v_ber_t
#define value_string values.v_string
#define value_bv values.v_bv
int config_fp_parse_line( ConfigArgs *c );
int config_set_vals( ConfigTable *ct, ConfigArgs *c );
int config_add_vals( ConfigTable *ct, ConfigArgs *c );
int config_push_cleanup( ConfigArgs *c, ConfigDriver *cleanup );
void init_config_argv( ConfigArgs *c );
int read_config_file( const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft );
ConfigTable *config_find_keyword( ConfigTable *ct, ConfigArgs *c );
Listener *config_check_my_url( const char *url, LDAPURLDesc *lud );
LDAP_END_DECL
#endif /* CONFIG_H */

148
servers/lloadd/connection.c Normal file
View file

@ -0,0 +1,148 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 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>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include "lutil.h"
#include "slap.h"
static ldap_pvt_thread_mutex_t conn_nextid_mutex;
static unsigned long conn_nextid = 0;
static void
connection_assign_nextid( Connection *conn )
{
ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
conn->c_connid = conn_nextid++;
ldap_pvt_thread_mutex_unlock( &conn_nextid_mutex );
}
void
connection_destroy( Connection *c )
{
assert( c );
ldap_pvt_thread_mutex_destroy( &c->c_io_mutex );
ldap_pvt_thread_mutex_destroy( &c->c_mutex );
ber_sockbuf_free( c->c_sb );
ch_free( c );
}
Connection *
connection_init( ber_socket_t s, const char *peername, int flags )
{
Connection *c;
assert( peername != NULL );
#ifndef HAVE_TLS
assert( !(flags & CONN_IS_TLS) );
#endif
if ( s == AC_SOCKET_INVALID ) {
Debug( LDAP_DEBUG_ANY, "connection_init: "
"init of socket fd=%ld invalid.\n",
(long)s );
return NULL;
}
assert( s >= 0 );
c = ch_calloc( 1, sizeof(Connection) );
c->c_sb = ber_sockbuf_alloc();
ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
{
ber_len_t max = sockbuf_max_incoming;
ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
}
#ifdef LDAP_PF_LOCAL
if ( flags & CONN_IS_IPC ) {
#ifdef LDAP_DEBUG
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
#endif
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_fd,
LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
#ifdef LDAP_PF_LOCAL_SENDMSG
if ( !BER_BVISEMPTY( peerbv ) )
ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_UNGET_BUF, peerbv );
#endif
} else
#endif /* LDAP_PF_LOCAL */
{
#ifdef LDAP_DEBUG
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
#endif
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
}
#ifdef LDAP_DEBUG
ber_sockbuf_add_io(
c->c_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"lload_" );
#endif
#ifdef HAVE_TLS
if ( flags & CONN_IS_TLS ) {
/* TODO: will need an asynchronous TLS implementation in libldap */
assert(0);
c->c_is_tls = 1;
c->c_needs_tls_accept = 1;
} else {
c->c_is_tls = 0;
c->c_needs_tls_accept = 0;
}
#endif
ldap_pvt_thread_mutex_init( &c->c_mutex );
ldap_pvt_thread_mutex_init( &c->c_io_mutex );
connection_assign_nextid( c );
Debug( LDAP_DEBUG_CONNS, "connection_init: "
"connection connid=%lu allocated for socket fd=%d\n",
c->c_connid, s );
return c;
fail:
connection_destroy( c );
return NULL;
}

1400
servers/lloadd/daemon.c Normal file

File diff suppressed because it is too large Load diff

1
servers/lloadd/design.md Symbolic link
View file

@ -0,0 +1 @@
../../doc/devel/lloadd/design.md

1
servers/lloadd/globals.c Symbolic link
View file

@ -0,0 +1 @@
../slapd/globals.c

144
servers/lloadd/init.c Normal file
View file

@ -0,0 +1,144 @@
/* init.c - initialize various things */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 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>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "slap.h"
#include "lber_pvt.h"
#include "ldap_rq.h"
/*
* read-only global variables or variables only written by the listener
* thread (after they are initialized) - no need to protect them with a mutex.
*/
int slap_debug = 0;
#ifdef LDAP_DEBUG
int ldap_syslog = LDAP_DEBUG_STATS;
#else
int ldap_syslog;
#endif
#ifdef LOG_DEBUG
int ldap_syslog_level = LOG_DEBUG;
#endif
/*
* global variables that need mutex protection
*/
ldap_pvt_thread_pool_t connection_pool;
int connection_pool_max = SLAP_MAX_WORKER_THREADS;
int connection_pool_queues = 1;
int slap_tool_thread_max = 1;
static const char *slap_name = NULL;
int slapMode = SLAP_UNDEFINED_MODE;
int
slap_init( int mode, const char *name )
{
int rc = LDAP_SUCCESS;
assert( mode );
if ( slapMode != SLAP_UNDEFINED_MODE ) {
/* Make sure we write something to stderr */
slap_debug |= LDAP_DEBUG_NONE;
Debug( LDAP_DEBUG_ANY, "%s init: "
"init called twice (old=%d, new=%d)\n",
name, slapMode, mode );
return 1;
}
slapMode = mode;
switch ( slapMode & SLAP_MODE ) {
case SLAP_SERVER_MODE:
Debug( LDAP_DEBUG_TRACE, "%s init: "
"initiated server.\n",
name );
slap_name = name;
ldap_pvt_thread_pool_init_q( &connection_pool, connection_pool_max,
0, connection_pool_queues );
ldap_pvt_thread_mutex_init( &slapd_rq.rq_mutex );
LDAP_STAILQ_INIT( &slapd_rq.task_list );
LDAP_STAILQ_INIT( &slapd_rq.run_list );
break;
default:
slap_debug |= LDAP_DEBUG_NONE;
Debug( LDAP_DEBUG_ANY, "%s init: "
"undefined mode (%d).\n",
name, mode );
rc = 1;
break;
}
return rc;
}
int
slap_destroy( void )
{
int rc = LDAP_SUCCESS;
Debug( LDAP_DEBUG_TRACE, "%s destroy: "
"freeing system resources.\n",
slap_name );
ldap_pvt_thread_pool_free( &connection_pool );
switch ( slapMode & SLAP_MODE ) {
case SLAP_SERVER_MODE:
break;
default:
Debug( LDAP_DEBUG_ANY, "slap_destroy(): "
"undefined mode (%d).\n",
slapMode );
rc = 1;
break;
}
ldap_pvt_thread_destroy();
/* should destroy the above mutex */
return rc;
}

View file

@ -0,0 +1,161 @@
/* libevent_support.c - routines to bridge libldap and libevent */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2017-2020 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>.
*/
#include "portable.h"
#include <ac/time.h>
#include <event2/event.h>
#include <event2/thread.h>
#include "slap.h"
#include "ldap_pvt_thread.h"
static void *
lload_libevent_mutex_init( unsigned locktype )
{
int rc;
ldap_pvt_thread_mutex_t *mutex =
ch_malloc( sizeof(ldap_pvt_thread_mutex_t) );
if ( locktype & EVTHREAD_LOCKTYPE_RECURSIVE ) {
rc = ldap_pvt_thread_mutex_recursive_init( mutex );
} else {
rc = ldap_pvt_thread_mutex_init( mutex );
}
if ( rc ) {
ch_free( mutex );
mutex = NULL;
}
return mutex;
}
static void
lload_libevent_mutex_destroy( void *lock, unsigned locktype )
{
int rc;
ldap_pvt_thread_mutex_t *mutex = lock;
rc = ldap_pvt_thread_mutex_destroy( mutex );
assert( rc == 0 );
ch_free( mutex );
}
static int
lload_libevent_mutex_lock( unsigned mode, void *lock )
{
ldap_pvt_thread_mutex_t *mutex = lock;
if ( mode & EVTHREAD_TRY ) {
return ldap_pvt_thread_mutex_trylock( mutex );
} else {
return ldap_pvt_thread_mutex_lock( mutex );
}
}
static int
lload_libevent_mutex_unlock( unsigned mode, void *lock )
{
ldap_pvt_thread_mutex_t *mutex = lock;
return ldap_pvt_thread_mutex_unlock( mutex );
}
static void *
lload_libevent_cond_init( unsigned condtype )
{
int rc;
ldap_pvt_thread_cond_t *cond =
ch_malloc( sizeof(ldap_pvt_thread_cond_t) );
assert( condtype == 0 );
rc = ldap_pvt_thread_cond_init( cond );
if ( rc ) {
ch_free( cond );
cond = NULL;
}
return cond;
}
static void
lload_libevent_cond_destroy( void *c )
{
int rc;
ldap_pvt_thread_cond_t *cond = c;
rc = ldap_pvt_thread_cond_destroy( cond );
assert( rc == 0 );
ch_free( c );
}
static int
lload_libevent_cond_signal( void *c, int broadcast )
{
ldap_pvt_thread_cond_t *cond = c;
if ( broadcast ) {
return ldap_pvt_thread_cond_broadcast( cond );
} else {
return ldap_pvt_thread_cond_signal( cond );
}
}
static int
lload_libevent_cond_timedwait(
void *c,
void *lock,
const struct timeval *timeout )
{
ldap_pvt_thread_cond_t *cond = c;
ldap_pvt_thread_mutex_t *mutex = lock;
/*
* libevent does not seem to request a timeout, this is true as of 2.1.8
* that has just been marked the first stable release of the 2.1 series
*/
assert( timeout == NULL );
return ldap_pvt_thread_cond_wait( cond, mutex );
}
int
lload_libevent_init( void )
{
struct evthread_lock_callbacks cbs = {
EVTHREAD_LOCK_API_VERSION,
EVTHREAD_LOCKTYPE_RECURSIVE,
lload_libevent_mutex_init,
lload_libevent_mutex_destroy,
lload_libevent_mutex_lock,
lload_libevent_mutex_unlock
};
struct evthread_condition_callbacks cond_cbs = {
EVTHREAD_CONDITION_API_VERSION,
lload_libevent_cond_init,
lload_libevent_cond_destroy,
lload_libevent_cond_signal,
lload_libevent_cond_timedwait
};
if ( ldap_pvt_thread_initialize() ) {
return -1;
}
evthread_set_lock_callbacks( &cbs );
evthread_set_condition_callbacks( &cond_cbs );
evthread_set_id_callback( ldap_pvt_thread_self );
return 0;
}

974
servers/lloadd/main.c Normal file
View file

@ -0,0 +1,974 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2015 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>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/ctype.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include <ac/wait.h>
#include <ac/errno.h>
#include <event2/event.h>
#include "slap.h"
#include "lutil.h"
#include "ldif.h"
#ifdef LDAP_SIGCHLD
static void wait4child( evutil_socket_t sig, short what, void *arg );
#endif
#ifdef SIGPIPE
static void sigpipe( evutil_socket_t sig, short what, void *arg );
#endif
#ifdef HAVE_NT_SERVICE_MANAGER
#define MAIN_RETURN(x) return
static struct sockaddr_in bind_addr;
#define SERVICE_EXIT( e, n ) \
do { \
if ( is_NT_Service ) { \
lutil_ServiceStatus.dwWin32ExitCode = (e); \
lutil_ServiceStatus.dwServiceSpecificExitCode = (n); \
} \
} while (0)
#else
#define SERVICE_EXIT( e, n )
#define MAIN_RETURN(x) return (x)
#endif
struct signal_handler {
int signal;
event_callback_fn handler;
struct event *event;
} signal_handlers[] = {
{ LDAP_SIGUSR2, slap_sig_shutdown },
#ifdef SIGPIPE
{ SIGPIPE, sigpipe },
#endif
#ifdef SIGHUP
{ SIGHUP, slap_sig_shutdown },
#endif
{ SIGINT, slap_sig_shutdown },
{ SIGTERM, slap_sig_shutdown },
#ifdef SIGTRAP
{ SIGTRAP, slap_sig_shutdown },
#endif
#ifdef LDAP_SIGCHLD
{ LDAP_SIGCHLD, wait4child },
#endif
#ifdef SIGBREAK
/* SIGBREAK is generated when Ctrl-Break is pressed. */
{ SIGBREAK, slap_sig_shutdown },
#endif
{ 0, NULL }
};
/*
* when more than one lloadd is running on one machine, each one might have
* it's own LOCAL for syslogging and must have its own pid/args files
*/
#ifndef HAVE_MKVERSION
const char Versionstr[] = OPENLDAP_PACKAGE
" " OPENLDAP_VERSION " LDAP Load Balancer Server (lloadd)";
#endif
#define CHECK_NONE 0x00
#define CHECK_CONFIG 0x01
#define CHECK_LOGLEVEL 0x02
static int check = CHECK_NONE;
static int version = 0;
void *slap_tls_ctx;
LDAP *slap_tls_ld;
static int
slapd_opt_slp( const char *val, void *arg )
{
#ifdef HAVE_SLP
/* NULL is default */
if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) {
slapd_register_slp = 1;
slapd_slp_attrs = ( val != NULL && *val == '(' ) ? val : NULL;
} else if ( strcasecmp( val, "off" ) == 0 ) {
slapd_register_slp = 0;
/* NOTE: add support for URL specification? */
} else {
fprintf( stderr, "unrecognized value \"%s\" for SLP option\n", val );
return -1;
}
return 0;
#else
fputs( "lloadd: SLP support is not available\n", stderr );
return 0;
#endif
}
/*
* Option helper structure:
*
* oh_nam is left-hand part of <option>[=<value>]
* oh_fnc is handler function
* oh_arg is an optional arg to oh_fnc
* oh_usage is the one-line usage string related to the option,
* which is assumed to start with <option>[=<value>]
*
* please leave valid options in the structure, and optionally #ifdef
* their processing inside the helper, so that reasonable and helpful
* error messages can be generated if a disabled option is requested.
*/
struct option_helper {
struct berval oh_name;
int (*oh_fnc)( const char *val, void *arg );
void *oh_arg;
const char *oh_usage;
} option_helpers[] = {
{ BER_BVC("slp"), slapd_opt_slp, NULL,
"slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" },
{ BER_BVNULL, 0, NULL, NULL }
};
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
#ifdef LOG_LOCAL4
int
parse_syslog_user( const char *arg, int *syslogUser )
{
static slap_verbmasks syslogUsers[] = {
{ BER_BVC("LOCAL0"), LOG_LOCAL0 },
{ BER_BVC("LOCAL1"), LOG_LOCAL1 },
{ BER_BVC("LOCAL2"), LOG_LOCAL2 },
{ BER_BVC("LOCAL3"), LOG_LOCAL3 },
{ BER_BVC("LOCAL4"), LOG_LOCAL4 },
{ BER_BVC("LOCAL5"), LOG_LOCAL5 },
{ BER_BVC("LOCAL6"), LOG_LOCAL6 },
{ BER_BVC("LOCAL7"), LOG_LOCAL7 },
#ifdef LOG_USER
{ BER_BVC("USER"), LOG_USER },
#endif /* LOG_USER */
#ifdef LOG_DAEMON
{ BER_BVC("DAEMON"), LOG_DAEMON },
#endif /* LOG_DAEMON */
{ BER_BVNULL, 0 }
};
int i = verb_to_mask( arg, syslogUsers );
if ( BER_BVISNULL( &syslogUsers[i].word ) ) {
Debug( LDAP_DEBUG_ANY, "unrecognized syslog user \"%s\".\n", arg );
return 1;
}
*syslogUser = syslogUsers[i].mask;
return 0;
}
#endif /* LOG_LOCAL4 */
int
parse_syslog_level( const char *arg, int *levelp )
{
static slap_verbmasks str2syslog_level[] = {
{ BER_BVC("EMERG"), LOG_EMERG },
{ BER_BVC("ALERT"), LOG_ALERT },
{ BER_BVC("CRIT"), LOG_CRIT },
{ BER_BVC("ERR"), LOG_ERR },
{ BER_BVC("WARNING"), LOG_WARNING },
{ BER_BVC("NOTICE"), LOG_NOTICE },
{ BER_BVC("INFO"), LOG_INFO },
{ BER_BVC("DEBUG"), LOG_DEBUG },
{ BER_BVNULL, 0 }
};
int i = verb_to_mask( arg, str2syslog_level );
if ( BER_BVISNULL( &str2syslog_level[i].word ) ) {
Debug( LDAP_DEBUG_ANY, "unknown syslog level \"%s\".\n", arg );
return 1;
}
*levelp = str2syslog_level[i].mask;
return 0;
}
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
int
parse_debug_unknowns( char **unknowns, int *levelp )
{
int i, level, rc = 0;
for ( i = 0; unknowns[i] != NULL; i++ ) {
level = 0;
if ( str2loglevel( unknowns[i], &level ) ) {
fprintf( stderr, "unrecognized log level \"%s\"\n", unknowns[i] );
rc = 1;
} else {
*levelp |= level;
}
}
return rc;
}
int
parse_debug_level( const char *arg, int *levelp, char ***unknowns )
{
int level;
if ( arg && arg[0] != '-' && !isdigit( (unsigned char)arg[0] ) ) {
int i;
char **levels;
levels = ldap_str2charray( arg, "," );
for ( i = 0; levels[i] != NULL; i++ ) {
level = 0;
if ( str2loglevel( levels[i], &level ) ) {
/* remember this for later */
ldap_charray_add( unknowns, levels[i] );
fprintf( stderr, "unrecognized log level \"%s\" (deferred)\n",
levels[i] );
} else {
*levelp |= level;
}
}
ldap_charray_free( levels );
} else {
int rc;
if ( arg[0] == '-' ) {
rc = lutil_atoix( &level, arg, 0 );
} else {
unsigned ulevel;
rc = lutil_atoux( &ulevel, arg, 0 );
level = (int)ulevel;
}
if ( rc ) {
fprintf( stderr,
"unrecognized log level "
"\"%s\"\n",
arg );
return 1;
}
if ( level == 0 ) {
*levelp = 0;
} else {
*levelp |= level;
}
}
return 0;
}
static void
usage( char *name )
{
fprintf( stderr, "usage: %s options\n", name );
fprintf( stderr,
"\t-4\t\tIPv4 only\n"
"\t-6\t\tIPv6 only\n"
"\t-d level\tDebug level"
"\n"
"\t-f filename\tConfiguration file\n"
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
"\t-g group\tGroup (id or name) to run as\n"
#endif
"\t-h URLs\t\tList of URLs to serve\n"
#ifdef SLAP_DEFAULT_SYSLOG_USER
"\t-l facility\tSyslog facility (default: LOCAL4)\n"
#endif
"\t-n serverName\tService name\n"
"\t-o <opt>[=val] generic means to specify options" );
if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) {
int i;
fprintf( stderr, "; supported options:\n" );
for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) {
fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage );
}
} else {
fprintf( stderr, "\n" );
}
fprintf( stderr,
#ifdef HAVE_CHROOT
"\t-r directory\tSandbox directory to chroot to\n"
#endif
"\t-s level\tSyslog level\n"
"\t-t\t\tCheck configuration file\n"
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
"\t-u user\t\tUser (id or name) to run as\n"
#endif
"\t-V\t\tprint version info (-VV exit afterwards)\n" );
}
#ifdef HAVE_NT_SERVICE_MANAGER
void WINAPI
ServiceMain( DWORD argc, LPTSTR *argv )
#else
int
main( int argc, char **argv )
#endif
{
int i, no_detach = 0;
int rc = 1;
char *urls = NULL;
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
char *username = NULL;
char *groupname = NULL;
#endif
#if defined(HAVE_CHROOT)
char *sandbox = NULL;
#endif
#ifdef SLAP_DEFAULT_SYSLOG_USER
int syslogUser = SLAP_DEFAULT_SYSLOG_USER;
#endif
#ifndef HAVE_WINSOCK
int pid, waitfds[2];
#endif
int g_argc = argc;
char **g_argv = argv;
char *configfile = NULL;
char *configdir = NULL;
char *serverName;
int serverMode = SLAP_SERVER_MODE;
char **debug_unknowns = NULL;
char **syslog_unknowns = NULL;
int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0;
int firstopt = 1;
struct event_base *daemon_base = NULL;
slap_sl_mem_init();
(void)lload_libevent_init();
serverName = lutil_progname( "lloadd", argc, argv );
#ifdef HAVE_NT_SERVICE_MANAGER
{
int *ip;
char *newConfigFile;
char *newConfigDir;
char *newUrls;
char *regService = NULL;
if ( is_NT_Service ) {
lutil_CommenceStartupProcessing( serverName, slap_sig_shutdown );
if ( strcmp( serverName, SERVICE_NAME ) ) regService = serverName;
}
ip = (int *)lutil_getRegParam( regService, "DebugLevel" );
if ( ip != NULL ) {
slap_debug = *ip;
Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n",
slap_debug );
}
newUrls = (char *)lutil_getRegParam( regService, "Urls" );
if ( newUrls ) {
if ( urls ) ch_free( urls );
urls = ch_strdup( newUrls );
Debug( LDAP_DEBUG_ANY, "new urls from registry: %s\n", urls );
}
newConfigFile = (char *)lutil_getRegParam( regService, "ConfigFile" );
if ( newConfigFile != NULL ) {
configfile = ch_strdup( newConfigFile );
Debug( LDAP_DEBUG_ANY, "new config file from registry is: %s\n",
configfile );
}
newConfigDir = (char *)lutil_getRegParam( regService, "ConfigDir" );
if ( newConfigDir != NULL ) {
configdir = ch_strdup( newConfigDir );
Debug( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n",
configdir );
}
}
#endif
while ( (i = getopt( argc, argv,
"c:d:f:F:h:n:o:s:tV"
#ifdef LDAP_PF_INET6
"46"
#endif
#ifdef HAVE_CHROOT
"r:"
#endif
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
"S:"
#ifdef LOG_LOCAL4
"l:"
#endif
#endif
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
"u:g:"
#endif
)) != EOF ) {
switch ( i ) {
#ifdef LDAP_PF_INET6
case '4':
slap_inet4or6 = AF_INET;
break;
case '6':
slap_inet4or6 = AF_INET6;
break;
#endif
case 'h': /* listen URLs */
if ( urls != NULL ) free( urls );
urls = ch_strdup( optarg );
break;
case 'd': { /* set debug level and 'do not detach' flag */
int level = 0;
if ( strcmp( optarg, "?" ) == 0 ) {
check |= CHECK_LOGLEVEL;
break;
}
no_detach = 1;
if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
goto destroy;
}
#ifdef LDAP_DEBUG
slap_debug |= level;
#else
if ( level != 0 )
fputs( "must compile with LDAP_DEBUG for debugging\n",
stderr );
#endif
} break;
case 'f': /* read config file */
configfile = ch_strdup( optarg );
break;
case 'o': {
char *val = strchr( optarg, '=' );
struct berval opt;
opt.bv_val = optarg;
if ( val ) {
opt.bv_len = ( val - optarg );
val++;
} else {
opt.bv_len = strlen( optarg );
}
for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name );
i++ ) {
if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) ==
0 ) {
assert( option_helpers[i].oh_fnc != NULL );
if ( (*option_helpers[i].oh_fnc)(
val, option_helpers[i].oh_arg ) == -1 ) {
/* we assume the option parsing helper
* issues appropriate and self-explanatory
* error messages... */
goto stop;
}
break;
}
}
if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) {
goto unhandled_option;
}
break;
}
case 's': /* set syslog level */
if ( strcmp( optarg, "?" ) == 0 ) {
check |= CHECK_LOGLEVEL;
break;
}
if ( parse_debug_level(
optarg, &ldap_syslog, &syslog_unknowns ) ) {
goto destroy;
}
break;
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
case 'S':
if ( parse_syslog_level( optarg, &ldap_syslog_level ) ) {
goto destroy;
}
break;
#ifdef LOG_LOCAL4
case 'l': /* set syslog local user */
if ( parse_syslog_user( optarg, &syslogUser ) ) {
goto destroy;
}
break;
#endif
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
#ifdef HAVE_CHROOT
case 'r':
if ( sandbox ) free( sandbox );
sandbox = ch_strdup( optarg );
break;
#endif
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
case 'u': /* user name */
if ( username ) free( username );
username = ch_strdup( optarg );
break;
case 'g': /* group name */
if ( groupname ) free( groupname );
groupname = ch_strdup( optarg );
break;
#endif /* SETUID && GETUID */
case 'n': /* NT service name */
serverName = ch_strdup( optarg );
break;
case 't':
check |= CHECK_CONFIG;
break;
case 'V':
version++;
break;
default:
unhandled_option:;
usage( argv[0] );
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
goto stop;
}
if ( firstopt ) {
firstopt = 0;
}
}
if ( optind != argc ) goto unhandled_option;
ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug );
ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug );
ldif_debug = slap_debug;
if ( version ) {
fprintf( stderr, "%s\n", Versionstr );
if ( version > 1 ) goto stop;
}
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
{
char *logName;
#ifdef HAVE_EBCDIC
logName = ch_strdup( serverName );
__atoe( logName );
#else
logName = serverName;
#endif
#ifdef LOG_LOCAL4
openlog( logName, OPENLOG_OPTIONS, syslogUser );
#elif defined LOG_DEBUG
openlog( logName, OPENLOG_OPTIONS );
#endif
#ifdef HAVE_EBCDIC
free( logName );
#endif
}
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
Debug( LDAP_DEBUG_ANY, "%s", Versionstr );
global_host = ldap_pvt_get_fqdn( NULL );
if ( check == CHECK_NONE && slapd_daemon_init( urls ) != 0 ) {
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
goto stop;
}
#if defined(HAVE_CHROOT)
if ( sandbox ) {
if ( chdir( sandbox ) ) {
perror( "chdir" );
rc = 1;
goto stop;
}
if ( chroot( sandbox ) ) {
perror( "chroot" );
rc = 1;
goto stop;
}
if ( chdir( "/" ) ) {
perror( "chdir" );
rc = 1;
goto stop;
}
}
#endif
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
if ( username != NULL || groupname != NULL ) {
slap_init_user( username, groupname );
}
#endif
#ifdef HAVE_TLS
rc = ldap_create( &slap_tls_ld );
if ( rc ) {
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
goto destroy;
}
/* Library defaults to full certificate checking. This is correct when
* a client is verifying a server because all servers should have a
* valid cert. But few clients have valid certs, so we want our default
* to be no checking. The config file can override this as usual.
*/
rc = LDAP_OPT_X_TLS_NEVER;
(void)ldap_pvt_tls_set_option(
slap_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc );
#endif
rc = slap_init( serverMode, serverName );
if ( rc ) {
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
goto destroy;
}
if ( read_config( configfile, configdir ) != 0 ) {
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
if ( check & CHECK_CONFIG ) {
fprintf( stderr, "config check failed\n" );
}
goto destroy;
}
if ( debug_unknowns ) {
rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
ldap_charray_free( debug_unknowns );
debug_unknowns = NULL;
if ( rc ) goto destroy;
}
if ( syslog_unknowns ) {
rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog );
ldap_charray_free( syslog_unknowns );
syslog_unknowns = NULL;
if ( rc ) goto destroy;
}
if ( check & CHECK_LOGLEVEL ) {
rc = 0;
goto destroy;
}
if ( check & CHECK_CONFIG ) {
fprintf( stderr, "config check succeeded\n" );
check &= ~CHECK_CONFIG;
if ( check == CHECK_NONE ) {
rc = 0;
goto destroy;
}
}
#ifdef HAVE_TLS
rc = ldap_pvt_tls_init();
if ( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "main: "
"TLS init failed: %d\n",
rc );
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
goto destroy;
}
{
int opt = 1;
/* Force new ctx to be created */
rc = ldap_pvt_tls_set_option(
slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
if ( rc == 0 ) {
/* The ctx's refcount is bumped up here */
ldap_pvt_tls_get_option(
slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
} else if ( rc != LDAP_NOT_SUPPORTED ) {
Debug( LDAP_DEBUG_ANY, "main: "
"TLS init def ctx failed: %d\n",
rc );
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
goto destroy;
}
}
#endif
daemon_base = event_base_new();
if ( !daemon_base ) {
Debug( LDAP_DEBUG_ANY, "main: "
"main event base allocation failed\n" );
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
goto destroy;
}
for ( i = 0; signal_handlers[i].signal; i++ ) {
struct event *event;
event = evsignal_new( daemon_base, signal_handlers[i].signal,
signal_handlers[i].handler, daemon_base );
if ( !event || event_add( event, NULL ) ) {
Debug( LDAP_DEBUG_ANY, "main: "
"failed to register a handler for signal %d\n",
signal_handlers[i].signal );
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
goto destroy;
}
signal_handlers[i].event = event;
}
#ifndef HAVE_WINSOCK
if ( !no_detach ) {
if ( lutil_pair( waitfds ) < 0 ) {
Debug( LDAP_DEBUG_ANY, "main: "
"lutil_pair failed\n" );
rc = 1;
goto destroy;
}
pid = lutil_detach( no_detach, 0 );
if ( pid ) {
char buf[4];
rc = EXIT_SUCCESS;
close( waitfds[1] );
if ( read( waitfds[0], buf, 1 ) != 1 ) rc = EXIT_FAILURE;
_exit( rc );
} else {
close( waitfds[0] );
}
}
#endif /* HAVE_WINSOCK */
if ( slapd_pid_file != NULL ) {
FILE *fp = fopen( slapd_pid_file, "w" );
if ( fp == NULL ) {
char ebuf[128];
int save_errno = errno;
Debug( LDAP_DEBUG_ANY, "unable to open pid file "
"\"%s\": %d (%s)\n",
slapd_pid_file, save_errno,
AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
free( slapd_pid_file );
slapd_pid_file = NULL;
rc = 1;
goto destroy;
}
fprintf( fp, "%d\n", (int)getpid() );
fclose( fp );
slapd_pid_file_unlink = 1;
}
if ( slapd_args_file != NULL ) {
FILE *fp = fopen( slapd_args_file, "w" );
if ( fp == NULL ) {
char ebuf[128];
int save_errno = errno;
Debug( LDAP_DEBUG_ANY, "unable to open args file "
"\"%s\": %d (%s)\n",
slapd_args_file, save_errno,
AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
free( slapd_args_file );
slapd_args_file = NULL;
rc = 1;
goto destroy;
}
for ( i = 0; i < g_argc; i++ ) {
fprintf( fp, "%s ", g_argv[i] );
}
fprintf( fp, "\n" );
fclose( fp );
slapd_args_file_unlink = 1;
}
/*
* FIXME: moved here from slapd_daemon_task()
* because back-monitor db_open() needs it
*/
time( &starttime );
Debug( LDAP_DEBUG_ANY, "lloadd starting\n" );
#ifndef HAVE_WINSOCK
if ( !no_detach ) {
write( waitfds[1], "1", 1 );
close( waitfds[1] );
}
#endif
#ifdef HAVE_NT_EVENT_LOG
if ( is_NT_Service )
lutil_LogStartedEvent( serverName, slap_debug,
configfile ? configfile : LLOADD_DEFAULT_CONFIGFILE, urls );
#endif
rc = slapd_daemon( daemon_base );
#ifdef HAVE_NT_SERVICE_MANAGER
/* Throw away the event that we used during the startup process. */
if ( is_NT_Service ) ldap_pvt_thread_cond_destroy( &started_event );
#endif
destroy:
if ( check & CHECK_LOGLEVEL ) {
(void)loglevel_print( stdout );
}
/* remember an error during destroy */
rc |= slap_destroy();
stop:
#ifdef HAVE_NT_EVENT_LOG
if ( is_NT_Service ) lutil_LogStoppedEvent( serverName );
#endif
Debug( LDAP_DEBUG_ANY, "lloadd stopped.\n" );
#ifdef HAVE_NT_SERVICE_MANAGER
lutil_ReportShutdownComplete();
#endif
#ifdef LOG_DEBUG
closelog();
#endif
slapd_daemon_destroy();
#ifdef HAVE_TLS
if ( slap_tls_ld ) {
ldap_pvt_tls_ctx_free( slap_tls_ctx );
ldap_unbind_ext( slap_tls_ld, NULL, NULL );
}
ldap_pvt_tls_destroy();
#endif
if ( slapd_pid_file_unlink ) {
unlink( slapd_pid_file );
}
if ( slapd_args_file_unlink ) {
unlink( slapd_args_file );
}
config_destroy();
if ( configfile ) ch_free( configfile );
if ( configdir ) ch_free( configdir );
if ( urls ) ch_free( urls );
if ( global_host ) ch_free( global_host );
/* kludge, get symbols referenced */
tavl_free( NULL, NULL );
MAIN_RETURN(rc);
}
#ifdef SIGPIPE
/*
* Catch and discard terminated child processes, to avoid zombies.
*/
static void
sigpipe( evutil_socket_t sig, short what, void *arg )
{
}
#endif /* SIGPIPE */
#ifdef LDAP_SIGCHLD
/*
* Catch and discard terminated child processes, to avoid zombies.
*/
static void
wait4child( evutil_socket_t sig, short what, void *arg )
{
int save_errno = errno;
#ifdef WNOHANG
do
errno = 0;
#ifdef HAVE_WAITPID
while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR );
#else
while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR );
#endif
#else
(void)wait( NULL );
#endif
errno = save_errno;
}
#endif /* LDAP_SIGCHLD */

1
servers/lloadd/nt_svc.c Symbolic link
View file

@ -0,0 +1 @@
../slapd/nt_svc.c

268
servers/lloadd/proto-slap.h Normal file
View file

@ -0,0 +1,268 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2015 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>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#ifndef PROTO_SLAP_H
#define PROTO_SLAP_H
#include <ldap_cdefs.h>
#include "ldap_pvt.h"
#include <event2/event.h>
LDAP_BEGIN_DECL
struct config_args_s; /* config.h */
struct config_reply_s; /* config.h */
/*
* ch_malloc.c
*/
LDAP_SLAPD_V (BerMemoryFunctions) ch_mfuncs;
LDAP_SLAPD_F (void *) ch_malloc( ber_len_t size );
LDAP_SLAPD_F (void *) ch_realloc( void *block, ber_len_t size );
LDAP_SLAPD_F (void *) ch_calloc( ber_len_t nelem, ber_len_t size );
LDAP_SLAPD_F (char *) ch_strdup( const char *string );
LDAP_SLAPD_F (void) ch_free( void * );
#ifndef CH_FREE
#undef free
#define free ch_free
#endif
/*
* config.c
*/
LDAP_SLAPD_F (int) read_config( const char *fname, const char *dir );
LDAP_SLAPD_F (void) config_destroy( void );
LDAP_SLAPD_F (int) verb_to_mask( const char *word, slap_verbmasks *v );
LDAP_SLAPD_F (int) str2loglevel( const char *s, int *l );
LDAP_SLAPD_F (void) bindconf_free( slap_bindconf *bc );
/*
* connection.c
*/
LDAP_SLAPD_F (Connection *) connection_init( ber_socket_t s, const char *peername, int use_tls );
LDAP_SLAPD_F (Connection *) client_init( ber_socket_t s, Listener *url, const char *peername, struct event_base *base, int use_tls );
LDAP_SLAPD_F (void) connection_destroy( Connection *c );
/*
* daemon.c
*/
LDAP_SLAPD_F (int) slapd_daemon_init( const char *urls );
LDAP_SLAPD_F (int) slapd_daemon_destroy( void );
LDAP_SLAPD_F (int) slapd_daemon( struct event_base *daemon_base );
LDAP_SLAPD_F (Listener **) slapd_get_listeners( void );
LDAP_SLAPD_F (void) slap_sig_shutdown( evutil_socket_t sig, short what, void *arg );
LDAP_SLAPD_V (volatile sig_atomic_t) slapd_shutdown;
LDAP_SLAPD_V (int) lloadd_inited;
LDAP_SLAPD_V (struct runqueue_s) slapd_rq;
LDAP_SLAPD_V (int) slapd_daemon_threads;
LDAP_SLAPD_V (int) slapd_daemon_mask;
#ifdef LDAP_TCP_BUFFER
LDAP_SLAPD_V (int) slapd_tcp_rmem;
LDAP_SLAPD_V (int) slapd_tcp_wmem;
#endif /* LDAP_TCP_BUFFER */
#define bvmatch( bv1, bv2 ) \
( ( (bv1)->bv_len == (bv2)->bv_len ) && \
( memcmp( (bv1)->bv_val, (bv2)->bv_val, (bv1)->bv_len ) == 0 ) )
/*
* globals.c
*/
LDAP_SLAPD_V (const struct berval) slap_empty_bv;
LDAP_SLAPD_V (const struct berval) slap_unknown_bv;
LDAP_SLAPD_V (const struct berval) slap_true_bv;
LDAP_SLAPD_V (const struct berval) slap_false_bv;
LDAP_SLAPD_V (struct slap_sync_cookie_s) slap_sync_cookie;
LDAP_SLAPD_V (void *) slap_tls_ctx;
LDAP_SLAPD_V (LDAP *) slap_tls_ld;
/*
* init.c
*/
LDAP_SLAPD_F (int) slap_init( int mode, const char *name );
LDAP_SLAPD_F (int) slap_destroy( void );
/*
* libevent_support.c
*/
LDAP_SLAPD_F (int) lload_libevent_init( void );
/*
* main.c
*/
LDAP_SLAPD_V (int) slapd_register_slp;
LDAP_SLAPD_V (const char *) slapd_slp_attrs;
/*
* sl_malloc.c
*/
LDAP_SLAPD_F (void *) slap_sl_malloc( ber_len_t size, void *ctx );
LDAP_SLAPD_F (void *) slap_sl_realloc( void *block, ber_len_t size, void *ctx );
LDAP_SLAPD_F (void *) slap_sl_calloc( ber_len_t nelem, ber_len_t size, void *ctx );
LDAP_SLAPD_F (void) slap_sl_free( void *, void *ctx );
LDAP_SLAPD_V (BerMemoryFunctions) slap_sl_mfuncs;
LDAP_SLAPD_F (void) slap_sl_mem_init( void );
LDAP_SLAPD_F (void *) slap_sl_mem_create( ber_len_t size, int stack, void *ctx, int flag );
LDAP_SLAPD_F (void) slap_sl_mem_setctx( void *ctx, void *memctx );
LDAP_SLAPD_F (void) slap_sl_mem_destroy( void *key, void *data );
LDAP_SLAPD_F (void *) slap_sl_context( void *ptr );
/* assumes (x) > (y) returns 1 if true, 0 otherwise */
#define SLAP_PTRCMP(x, y) ( (x) < (y) ? -1 : (x) > (y) )
/*
* user.c
*/
#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
LDAP_SLAPD_F (void) slap_init_user( char *username, char *groupname );
#endif
/*
* value.c
*/
LDAP_SLAPD_F (int) value_add_one( BerVarray *vals, struct berval *addval );
#ifdef SLAP_ZONE_ALLOC
/*
* zn_malloc.c
*/
LDAP_SLAPD_F (void *) slap_zn_malloc( ber_len_t, void * );
LDAP_SLAPD_F (void *) slap_zn_realloc( void *, ber_len_t, void * );
LDAP_SLAPD_F (void *) slap_zn_calloc( ber_len_t, ber_len_t, void * );
LDAP_SLAPD_F (void) slap_zn_free( void *, void * );
LDAP_SLAPD_F (void *) slap_zn_mem_create( ber_len_t, ber_len_t, ber_len_t, ber_len_t );
LDAP_SLAPD_F (void) slap_zn_mem_destroy( void * );
LDAP_SLAPD_F (int) slap_zn_validate( void *, void *, int );
LDAP_SLAPD_F (int) slap_zn_invalidate( void *, void * );
LDAP_SLAPD_F (int) slap_zh_rlock( void * );
LDAP_SLAPD_F (int) slap_zh_runlock( void * );
LDAP_SLAPD_F (int) slap_zh_wlock( void * );
LDAP_SLAPD_F (int) slap_zh_wunlock( void * );
LDAP_SLAPD_F (int) slap_zn_rlock( void *, void * );
LDAP_SLAPD_F (int) slap_zn_runlock( void *, void * );
LDAP_SLAPD_F (int) slap_zn_wlock( void *, void * );
LDAP_SLAPD_F (int) slap_zn_wunlock( void *, void * );
#endif
LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming;
LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming_auth;
LDAP_SLAPD_V (slap_mask_t) global_allows;
LDAP_SLAPD_V (slap_mask_t) global_disallows;
LDAP_SLAPD_V (const char) Versionstr[];
LDAP_SLAPD_V (int) global_gentlehup;
LDAP_SLAPD_V (int) global_idletimeout;
LDAP_SLAPD_V (char *) global_host;
LDAP_SLAPD_V (int) lber_debug;
LDAP_SLAPD_V (int) ldap_syslog;
LDAP_SLAPD_V (char *) slapd_pid_file;
LDAP_SLAPD_V (char *) slapd_args_file;
LDAP_SLAPD_V (time_t) starttime;
/* use time(3) -- no mutex */
#define slap_get_time() time( NULL )
LDAP_SLAPD_V (ldap_pvt_thread_pool_t) connection_pool;
LDAP_SLAPD_V (int) connection_pool_max;
LDAP_SLAPD_V (int) connection_pool_queues;
LDAP_SLAPD_V (int) slap_tool_thread_max;
#ifdef USE_MP_BIGNUM
#define UI2BVX( bv, ui, ctx ) \
do { \
char *val; \
ber_len_t len; \
val = BN_bn2dec( ui ); \
if (val) { \
len = strlen( val ); \
if ( len > (bv)->bv_len ) { \
(bv)->bv_val = ber_memrealloc_x( (bv)->bv_val, len + 1, (ctx) ); \
} \
AC_MEMCPY( (bv)->bv_val, val, len + 1 ); \
(bv)->bv_len = len; \
OPENSSL_free( val ); \
} else { \
ber_memfree_x( (bv)->bv_val, (ctx) ); \
BER_BVZERO( (bv) ); \
} \
} while (0)
#elif defined(USE_MP_GMP)
/* NOTE: according to the documentation, the result
* of mpz_sizeinbase() can exceed the length of the
* string representation of the number by 1
*/
#define UI2BVX( bv, ui, ctx ) \
do { \
ber_len_t len = mpz_sizeinbase( (ui), 10 ); \
if ( len > (bv)->bv_len ) { \
(bv)->bv_val = ber_memrealloc_x( (bv)->bv_val, len + 1, (ctx) ); \
} \
(void)mpz_get_str( (bv)->bv_val, 10, (ui) ); \
if ( (bv)->bv_val[len - 1] == '\0' ) { \
len--; \
} \
(bv)->bv_len = len; \
} while (0)
#else
#ifdef USE_MP_LONG_LONG
#define UI2BV_FORMAT "%llu"
#elif defined USE_MP_LONG
#define UI2BV_FORMAT "%lu"
#elif defined HAVE_LONG_LONG
#define UI2BV_FORMAT "%llu"
#else
#define UI2BV_FORMAT "%lu"
#endif
#define UI2BVX( bv, ui, ctx ) \
do { \
char buf[LDAP_PVT_INTTYPE_CHARS(long)]; \
ber_len_t len; \
len = snprintf( buf, sizeof( buf ), UI2BV_FORMAT, (ui) ); \
if ( len > (bv)->bv_len ) { \
(bv)->bv_val = ber_memrealloc_x( (bv)->bv_val, len + 1, (ctx) ); \
} \
(bv)->bv_len = len; \
AC_MEMCPY( (bv)->bv_val, buf, len + 1 ); \
} while (0)
#endif
#define UI2BV( bv, ui ) UI2BVX( bv, ui, NULL )
LDAP_END_DECL
#endif /* PROTO_SLAP_H */

1
servers/lloadd/sl_malloc.c Symbolic link
View file

@ -0,0 +1 @@
../slapd/sl_malloc.c

332
servers/lloadd/slap.h Normal file
View file

@ -0,0 +1,332 @@
/* slap.h - stand alone ldap server include file */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2015 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>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#ifndef _SLAP_H_
#define _SLAP_H_
#include "ldap_defaults.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <sys/types.h>
#include <ac/syslog.h>
#include <ac/regex.h>
#include <ac/signal.h>
#include <ac/socket.h>
#include <ac/time.h>
#include <ac/param.h>
#include "avl.h"
#ifndef ldap_debug
#define ldap_debug slap_debug
#endif
#include "ldap_log.h"
#include <ldap.h>
#include <ldap_schema.h>
#include "lber_pvt.h"
#include "ldap_pvt.h"
#include "ldap_pvt_thread.h"
#include "ldap_queue.h"
#include <event2/event.h>
LDAP_BEGIN_DECL
/*
* SLAPD Memory allocation macros
*
* Unlike ch_*() routines, these routines do not assert() upon
* allocation error. They are intended to be used instead of
* ch_*() routines where the caller has implemented proper
* checking for and handling of allocation errors.
*
* Patches to convert ch_*() calls to SLAP_*() calls welcomed.
*/
#define SLAP_MALLOC(s) ber_memalloc( ( s ) )
#define SLAP_CALLOC(n, s) ber_memcalloc( ( n ), ( s ) )
#define SLAP_REALLOC(p, s) ber_memrealloc( ( p ), ( s ) )
#define SLAP_FREE(p) ber_memfree( ( p ) )
#define SLAP_VFREE(v) ber_memvfree( (void **)( v ) )
#define SLAP_STRDUP(s) ber_strdup( ( s ) )
#define SLAP_STRNDUP(s, l) ber_strndup( ( s ), ( l ) )
#define SERVICE_NAME OPENLDAP_PACKAGE "-slapd"
#define SLAPD_ANONYMOUS ""
#define SLAP_STRING_UNKNOWN "unknown"
#define SLAP_MAX_WORKER_THREADS ( 16 )
#define SLAP_SB_MAX_INCOMING_DEFAULT ( ( 1 << 18 ) - 1 )
#define SLAP_SB_MAX_INCOMING_AUTH ( ( 1 << 24 ) - 1 )
#define SLAP_TEXT_BUFLEN ( 256 )
/* unknown config file directive */
#define SLAP_CONF_UNKNOWN ( -1026 )
LDAP_SLAPD_V (int) slap_debug;
typedef unsigned long slap_mask_t;
typedef struct Connection Connection;
/* end of forward declarations */
typedef union Sockaddr {
struct sockaddr sa_addr;
struct sockaddr_in sa_in_addr;
#ifdef LDAP_PF_INET6
struct sockaddr_storage sa_storage;
struct sockaddr_in6 sa_in6_addr;
#endif
#ifdef LDAP_PF_LOCAL
struct sockaddr_un sa_un_addr;
#endif
} Sockaddr;
#ifdef LDAP_PF_INET6
extern int slap_inet4or6;
#endif
LDAP_SLAPD_V (int) slapMode;
#define SLAP_UNDEFINED_MODE 0x0000
#define SLAP_SERVER_MODE 0x0001
#define SLAP_TOOL_MODE 0x0002
#define SLAP_MODE 0x0003
#define SLAP_SERVER_RUNNING 0x8000
#define SB_TLS_DEFAULT ( -1 )
#define SB_TLS_OFF 0
#define SB_TLS_ON 1
#define SB_TLS_CRITICAL 2
typedef struct slap_keepalive {
int sk_idle;
int sk_probes;
int sk_interval;
} slap_keepalive;
typedef struct slap_bindconf {
struct berval sb_uri;
int sb_version;
int sb_tls;
int sb_method;
int sb_timeout_api;
int sb_timeout_net;
struct berval sb_binddn;
struct berval sb_cred;
struct berval sb_saslmech;
char *sb_secprops;
struct berval sb_realm;
struct berval sb_authcId;
struct berval sb_authzId;
slap_keepalive sb_keepalive;
#ifdef HAVE_TLS
void *sb_tls_ctx;
char *sb_tls_cert;
char *sb_tls_key;
char *sb_tls_cacert;
char *sb_tls_cacertdir;
char *sb_tls_reqcert;
char *sb_tls_reqsan;
char *sb_tls_cipher_suite;
char *sb_tls_protocol_min;
char *sb_tls_ecname;
#ifdef HAVE_OPENSSL
char *sb_tls_crlcheck;
#endif
int sb_tls_int_reqcert;
int sb_tls_int_reqsan;
int sb_tls_do_init;
#endif
} slap_bindconf;
typedef struct slap_verbmasks {
struct berval word;
const slap_mask_t mask;
} slap_verbmasks;
typedef struct slap_cf_aux_table {
struct berval key;
int off;
char type;
char quote;
void *aux;
} slap_cf_aux_table;
typedef int slap_cf_aux_table_parse_x( struct berval *val,
void *bc,
slap_cf_aux_table *tab0,
const char *tabmsg,
int unparse );
#define SLAP_RESTRICT_OP_ADD 0x0001U
#define SLAP_RESTRICT_OP_BIND 0x0002U
#define SLAP_RESTRICT_OP_COMPARE 0x0004U
#define SLAP_RESTRICT_OP_DELETE 0x0008U
#define SLAP_RESTRICT_OP_EXTENDED 0x0010U
#define SLAP_RESTRICT_OP_MODIFY 0x0020U
#define SLAP_RESTRICT_OP_RENAME 0x0040U
#define SLAP_RESTRICT_OP_SEARCH 0x0080U
#define SLAP_RESTRICT_OP_MASK 0x00FFU
#define SLAP_RESTRICT_READONLY 0x80000000U
#define SLAP_RESTRICT_EXOP_START_TLS 0x0100U
#define SLAP_RESTRICT_EXOP_MODIFY_PASSWD 0x0200U
#define SLAP_RESTRICT_EXOP_WHOAMI 0x0400U
#define SLAP_RESTRICT_EXOP_CANCEL 0x0800U
#define SLAP_RESTRICT_EXOP_MASK 0xFF00U
#define SLAP_RESTRICT_OP_READS \
( SLAP_RESTRICT_OP_COMPARE | SLAP_RESTRICT_OP_SEARCH )
#define SLAP_RESTRICT_OP_WRITES \
( SLAP_RESTRICT_OP_ADD | SLAP_RESTRICT_OP_DELETE | SLAP_RESTRICT_OP_MODIFY | SLAP_RESTRICT_OP_RENAME )
#define SLAP_RESTRICT_OP_ALL \
( SLAP_RESTRICT_OP_READS | SLAP_RESTRICT_OP_WRITES | SLAP_RESTRICT_OP_BIND | SLAP_RESTRICT_OP_EXTENDED )
typedef struct config_reply_s ConfigReply; /* config.h */
typedef struct Listener Listener;
/*
* represents a connection from an ldap client
*/
/* structure state (protected by connections_mutex) */
enum sc_struct_state {
SLAP_C_UNINITIALIZED = 0, /* MUST BE ZERO (0) */
SLAP_C_UNUSED,
SLAP_C_USED,
SLAP_C_PENDING
};
/* connection state (protected by c_mutex) */
enum sc_conn_state {
SLAP_C_INVALID = 0, /* MUST BE ZERO (0) */
SLAP_C_INACTIVE, /* zero threads */
SLAP_C_CLOSING, /* closing */
SLAP_C_ACTIVE, /* one or more threads */
SLAP_C_BINDING, /* binding */
SLAP_C_CLIENT /* outbound client conn */
};
struct Connection {
enum sc_struct_state c_struct_state; /* structure management state */
enum sc_conn_state c_conn_state; /* connection state */
ber_socket_t c_sd;
ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */
Sockbuf *c_sb; /* ber connection stuff */
/* set by connection_init */
unsigned long c_connid; /* unique id of this connection */
struct berval c_peer_name; /* peer name (trans=addr:port) */
time_t c_starttime; /* when the connection was opened */
time_t c_activitytime; /* when the connection was last used */
struct event *c_read_event, *c_write_event;
/* can only be changed by binding thread */
struct berval c_sasl_bind_mech; /* mech in progress */
ldap_pvt_thread_mutex_t c_io_mutex; /* only one pdu written at a time */
BerElement *c_currentber; /* ber we're attempting to read */
struct berval c_pendingber; /* ber we're attempting to write */
#define CONN_IS_TLS 1
#define CONN_IS_CLIENT 4
#define CONN_IS_IPC 8
#ifdef HAVE_TLS
char c_is_tls; /* true if this LDAP over raw TLS */
char c_needs_tls_accept; /* true if SSL_accept should be called */
#endif
long c_n_ops_executing; /* num of ops currently executing */
long c_n_ops_completed; /* num of ops completed */
void *c_private;
};
#ifdef LDAP_DEBUG
#ifdef LDAP_SYSLOG
#ifdef LOG_LOCAL4
#define SLAP_DEFAULT_SYSLOG_USER LOG_LOCAL4
#endif /* LOG_LOCAL4 */
#define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 ) \
Log( (level), ldap_syslog_level, (fmt), (connid), (opid), \
( arg1 ), ( arg2 ), ( arg3 ) )
#define StatslogTest( level ) ( ( ldap_debug | ldap_syslog ) & ( level ) )
#else /* !LDAP_SYSLOG */
#define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 ) \
do { \
if ( ldap_debug & (level) ) \
lutil_debug( ldap_debug, (level), (fmt), (connid), (opid), \
( arg1 ), ( arg2 ), ( arg3 ) ); \
} while (0)
#define StatslogTest( level ) ( ldap_debug & ( level ) )
#endif /* !LDAP_SYSLOG */
#else /* !LDAP_DEBUG */
#define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 ) ( (void)0 )
#define StatslogTest( level ) ( 0 )
#endif /* !LDAP_DEBUG */
/*
* listener; need to access it from monitor backend
*/
struct Listener {
struct berval sl_url;
struct berval sl_name;
mode_t sl_perms;
#ifdef HAVE_TLS
int sl_is_tls;
#endif
struct event_base *base;
struct evconnlistener *listener;
int sl_mute; /* Listener is temporarily disabled due to emfile */
int sl_busy; /* Listener is busy (accept thread activated) */
ber_socket_t sl_sd;
Sockaddr sl_sa;
#define sl_addr sl_sa.sa_in_addr
#define LDAP_TCP_BUFFER
#ifdef LDAP_TCP_BUFFER
int sl_tcp_rmem; /* custom TCP read buffer size */
int sl_tcp_wmem; /* custom TCP write buffer size */
#endif
};
LDAP_END_DECL
#include "proto-slap.h"
#endif /* _SLAP_H_ */

1
servers/lloadd/user.c Symbolic link
View file

@ -0,0 +1 @@
../slapd/user.c

67
servers/lloadd/value.c Normal file
View file

@ -0,0 +1,67 @@
/* value.c - routines for dealing with values */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2015 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>.
*/
/*
* Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include "slap.h"
int
value_add_one( BerVarray *vals, struct berval *addval )
{
int n;
BerVarray v2;
if ( *vals == NULL ) {
*vals = (BerVarray)SLAP_MALLOC( 2 * sizeof(struct berval) );
if ( *vals == NULL ) {
Debug( LDAP_DEBUG_TRACE, "value_add_one: "
"SLAP_MALLOC failed.\n" );
return LBER_ERROR_MEMORY;
}
n = 0;
} else {
for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) {
; /* Empty */
}
*vals = (BerVarray)SLAP_REALLOC(
(char *)*vals, ( n + 2 ) * sizeof(struct berval) );
if ( *vals == NULL ) {
Debug( LDAP_DEBUG_TRACE, "value_add_one: "
"SLAP_MALLOC failed.\n" );
return LBER_ERROR_MEMORY;
}
}
v2 = &(*vals)[n];
ber_dupbv( v2, addval );
v2++;
BER_BVZERO( v2 );
return LDAP_SUCCESS;
}

View file

@ -257,6 +257,7 @@ static OidRec OidMacros[] = {
* OLcfg{Bk|Db}{Oc|At}:10 -> back-shell
* OLcfg{Bk|Db}{Oc|At}:11 -> back-perl
* OLcfg{Bk|Db}{Oc|At}:12 -> back-mdb
* OLcfg{Bk|Db}{Oc|At}:13 -> lloadd
*/
/*