mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-18 12:54:09 -05:00
slurpd is strongly deprecated
This commit is contained in:
parent
d06a8bd198
commit
3d1fe19acc
25 changed files with 1 additions and 6264 deletions
|
|
@ -13,5 +13,5 @@
|
|||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
|
||||
SUBDIRS= slapd slurpd
|
||||
SUBDIRS= slapd
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
Design Notes: slurpd
|
||||
|
||||
This new version differs significantly from previous versions:
|
||||
|
||||
- It uses a multithreaded, single-process model. Previous versions forked
|
||||
a separate process for each replica. This new design should facilitate
|
||||
porting to NT, and is more straightforward.
|
||||
|
||||
- Only one copy of the replication log is made. Previous versions made
|
||||
one copy of the replication log for each replica
|
||||
|
||||
- This newer version is more object-oriented. Although still written in
|
||||
ANSI C (and compilable on k&r compilers), it encapsulates within the
|
||||
major data structures the methods used to access "private" data.
|
||||
|
||||
General design overview:
|
||||
|
||||
The main data structure in slurpd is a replication queue (struct rq).
|
||||
The rq data structure is currently implemented as a linked list of
|
||||
replication entries (struct re). The rq structure contains member functions
|
||||
used to initialize, add to, remove, and return the next re struct.
|
||||
|
||||
In addition to the rq structure, there is one ri (replication information)
|
||||
struct for each replica. The ri struct encapsulates all information
|
||||
about a particular replica, e.g. hostname, port, bind dn. The single
|
||||
public member function, ri_process, is called to begin processing
|
||||
the replication entries in the queue.
|
||||
|
||||
There is also a status structure (struct st) which contains the timestamp
|
||||
of the last successful replication operation for each replica. The
|
||||
contents of the st struct are flushed to disk after every successful
|
||||
operation. This disk file is read upon startup, and is used to allow
|
||||
slapd to "pick up where it left off".
|
||||
|
||||
Threading notes:
|
||||
|
||||
The LDAP liblthread quasi-pthreads interface is used for threading. At
|
||||
this point, machines which do not support pthreads, sun threads or lwp
|
||||
will probably not be able to run slurpd. Given the current threading
|
||||
method, discussed in the next paragraph, it will probably be necessary to
|
||||
have a separate hunk of code which handles non-threaded architectures
|
||||
(or we might just not worry about it). This needs further discussion.
|
||||
|
||||
Upon startup, command-line arguments and the slapd configuration file
|
||||
are processed. One thread is started for each replica. Thread replicas,
|
||||
when no more work exists, wait on a condition variable, and the main
|
||||
thread's file manager routine broadcasts on this condition variable
|
||||
when new work is added to the queue.
|
||||
|
||||
Additional notes:
|
||||
See doc/devel/replication-notes.txt
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
# Makefile.in for slurpd
|
||||
# $OpenLDAP$
|
||||
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
##
|
||||
## Copyright 1998-2007 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 = slurpd
|
||||
XPROGRAMS = sslurpd
|
||||
|
||||
XSRCS = version.c
|
||||
|
||||
NT_SRCS = nt_svc.c
|
||||
NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res
|
||||
|
||||
SRCS = admin.c args.c ch_malloc.c config.c \
|
||||
fm.c globals.c ldap_op.c lock.c main.c re.c \
|
||||
reject.c replica.c replog.c ri.c rq.c sanity.c st.c \
|
||||
$(@PLAT@_SRCS)
|
||||
OBJS = admin.o args.o ch_malloc.o config.o \
|
||||
fm.o globals.o ldap_op.o lock.o main.o re.o \
|
||||
reject.o replica.o replog.o ri.o rq.o sanity.o st.o \
|
||||
$(@PLAT@_OBJS)
|
||||
|
||||
LDAP_INCDIR= ../../include
|
||||
LDAP_LIBDIR= ../../libraries
|
||||
|
||||
BUILD_OPT = "--enable-slurpd"
|
||||
BUILD_SRV = @BUILD_SLURPD@
|
||||
|
||||
all-local-srv: $(PROGRAMS)
|
||||
|
||||
# $(LTHREAD_LIBS) must be last!
|
||||
XLIBS = $(SLURPD_L)
|
||||
XXLIBS = $(SLURPD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS)
|
||||
XXXLIBS = $(LTHREAD_LIBS)
|
||||
|
||||
slurpd: version.o
|
||||
$(LTLINK) -o $@ $(OBJS) version.o $(LIBS)
|
||||
|
||||
sslurpd: version.o
|
||||
$(LTLINK) -static -o $@ $(OBJS) version.o $(LIBS)
|
||||
|
||||
version.c: Makefile
|
||||
@-$(RM) $@
|
||||
$(MKVERSION) -s -n Versionstr slurpd > $@
|
||||
|
||||
version.o: version.c $(OBJS) $(SLURPD_L)
|
||||
|
||||
install-local-srv: FORCE
|
||||
-$(MKDIR) $(DESTDIR)$(libexecdir)
|
||||
@-$(INSTALL) -m 700 -d $(DESTDIR)$(localstatedir)/openldap-slurp
|
||||
@( \
|
||||
for prg in $(PROGRAMS); do \
|
||||
$(LTINSTALL) $(INSTALLFLAGS) $(STRIP) -m 755 $$prg$(EXEEXT) \
|
||||
$(DESTDIR)$(libexecdir); \
|
||||
done \
|
||||
)
|
||||
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
Written by Ganesan Rajagopal <rganesan@debian.org> and placed in the public
|
||||
domain.
|
||||
|
||||
Replication in OpenLDAP
|
||||
-----------------------
|
||||
|
||||
Please read "Section 10. Replication with slurpd" in the OpenLDAP guide for
|
||||
an overview and configuration of single-master replication. This document
|
||||
describes the internals of the replication mechanism.
|
||||
|
||||
slapd/repl.c contains routines add_replica_info() and
|
||||
add_replica_suffix(). add_replica_info() adds a new host to the list of
|
||||
replicas for a backend. add_replica_info() returns a number for the
|
||||
replica. add_replica_suffix() must then be called with the replica number to
|
||||
add a suffix that is hosted on this replica. add_replica_info() and add_replica_suffix() do not lock the
|
||||
replog_mutex.
|
||||
|
||||
Replicas are specified in the slapd.conf file. When slapd/config.c sees a
|
||||
"replica" line in slapd.conf, it calls add_replica_info() with the host
|
||||
specified in the "host=" directive and then calls add_replica_suffix() with
|
||||
the replica number and and the suffix specified in the "suffix="
|
||||
directive.
|
||||
|
||||
slapd writes out a replication log file containing LDIF change records for
|
||||
each configured replica for a suffix. The change records are generated for
|
||||
add, modify, delete and modrdn operations. A function called replog() is
|
||||
called at the end of the routines do_add (slapd/add.c),
|
||||
do_modify(slapd/modify.c), do_delete(slapd/delete.c) and
|
||||
do_modrdn(slapd/modrnd.c) to write out the change records.
|
||||
|
||||
In master/slave replication, updates are not allowed on slave
|
||||
replicas. Therefore replog() is not called if the suffix is configured with
|
||||
a updatedn (which indicates that this is a slave replica), instead a
|
||||
referral is returned back to the client. If multi-master replication is
|
||||
enabled, replog() is always called whenever any of the above updates happen
|
||||
unless the dn which is making the change is the updatedn. When the dn making
|
||||
the change is the same as the updatedn, it is assumed that this entry is
|
||||
being replicated by a slurpd instance on another host. (Note: For this
|
||||
reason, the updatedn must not be a "regular" admin/user object in
|
||||
multi-master replication).
|
||||
|
||||
The function replog() in slapd/repl.c generates the actual change
|
||||
records. Each change record is preceded by the list of replicas to which
|
||||
this change record needs to be replicated, the time when this change
|
||||
happened and the dn this change applies to. The pseudo code for replog() is
|
||||
follows
|
||||
|
||||
1. Check that a replog exists.
|
||||
2. Lock the replog mutex.
|
||||
3. Open and lock the replog file.
|
||||
4. Normalize the dn for the entry and write out a "replica:" entry for each
|
||||
replica with a matching suffix.
|
||||
5. Write out the the timestamp and the dn for the entry.
|
||||
6. Depending on the type of change, write out an appropriate changetype
|
||||
record.
|
||||
7. Close the replication log
|
||||
8. Unlock the replog mutex
|
||||
|
||||
slurpd has a file manager routine (function fm()) which watches for any
|
||||
change in the replication log. Whenever fm() detects a change in the
|
||||
replication log it locks the log, appends the records to slurpd's private
|
||||
copy of the replication log and truncates the log. See the slurpd/DESIGN
|
||||
file for a description of how slurpd works.
|
||||
|
||||
slapd can be configured to write out a replication log even if no replicas
|
||||
are configured. In this case the administrator has to truncate the
|
||||
replication log manually (under a lock!).
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* admin.c - routines for performing administrative tasks, e.g. on-the-fly
|
||||
* reconfiguration of slurpd.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/stdlib.h>
|
||||
|
||||
#include <ac/signal.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
/*
|
||||
* Eventually, do_admin will be the entry point for performing
|
||||
* administrative tasks. General idea: put commands in a file
|
||||
* somewhere, send slurpd a USR2 signal. The handler for
|
||||
* USR2 (this routine) reads the file and takes some action.
|
||||
*
|
||||
* For right now, this routine has been hijacked for debugging. When
|
||||
* slurpd receives a USR2 signal, it will dump its replication
|
||||
* queue to the disk file given by SLURPD_DUMPFILE.
|
||||
*/
|
||||
RETSIGTYPE
|
||||
do_admin( int sig )
|
||||
{
|
||||
sglob->rq->rq_dump( sglob->rq );
|
||||
(void) SIGNAL_REINSTALL( sig, do_admin );
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* args.c - process command-line arguments, and set appropriate globals.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include <ldap.h>
|
||||
#include <lutil.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
static void
|
||||
usage( char *name )
|
||||
{
|
||||
fprintf( stderr, "usage: %s\t[-d debug-level] [-s syslog-level]\n", name );
|
||||
fprintf( stderr, "\t\t[-f slapd-config-file] [-r replication-log-file]\n" );
|
||||
fprintf( stderr, "\t\t[-t tmp-dir] [-o]\n" );
|
||||
fprintf( stderr, "\t\t[-n service-name]\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Interpret argv, and fill in any appropriate globals.
|
||||
*/
|
||||
int
|
||||
doargs(
|
||||
int argc,
|
||||
char **argv,
|
||||
Globals *g
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int rflag = 0;
|
||||
|
||||
g->myname = strdup( lutil_progname( "slurpd", argc, argv ));
|
||||
|
||||
while ( (i = getopt( argc, argv, "d:f:n:or:t:V" )) != EOF ) {
|
||||
switch ( i ) {
|
||||
case 'd': { /* set debug level and 'do not detach' flag */
|
||||
int level;
|
||||
g->no_detach = 1;
|
||||
if ( optarg[0] == '?' ) {
|
||||
#ifdef LDAP_DEBUG
|
||||
printf( "Debug levels:\n" );
|
||||
printf( "\tLDAP_DEBUG_TRACE\t%d\n",
|
||||
LDAP_DEBUG_TRACE );
|
||||
printf( "\tLDAP_DEBUG_PACKETS\t%d\n",
|
||||
LDAP_DEBUG_PACKETS );
|
||||
printf( "\tLDAP_DEBUG_ARGS\t\t%d\n",
|
||||
LDAP_DEBUG_ARGS );
|
||||
printf( "\tLDAP_DEBUG_CONNS\t%d\n",
|
||||
LDAP_DEBUG_CONNS );
|
||||
printf( "\tLDAP_DEBUG_BER\t\t%d\n",
|
||||
LDAP_DEBUG_BER );
|
||||
printf( "\tLDAP_DEBUG_FILTER\t%d\n",
|
||||
LDAP_DEBUG_FILTER );
|
||||
printf( "\tLDAP_DEBUG_CONFIG\t%d\n",
|
||||
LDAP_DEBUG_CONFIG );
|
||||
printf( "\tLDAP_DEBUG_ACL\t\t%d\n",
|
||||
LDAP_DEBUG_ACL );
|
||||
printf( "\tLDAP_DEBUG_ANY\t\t%d\n",
|
||||
LDAP_DEBUG_ANY );
|
||||
puts( "\tThe -d flag also prevents slurpd from detaching." );
|
||||
#endif /* LDAP_DEBUG */
|
||||
puts( "\tDebugging is disabled. -d 0 prevents slurpd from detaching." );
|
||||
return( -1 );
|
||||
}
|
||||
#ifdef LDAP_DEBUG
|
||||
if ( lutil_atoix( &level, optarg, 0 ) != 0 ) {
|
||||
fprintf( stderr, "unable to parse debug flag \"%s\".\n", optarg );
|
||||
usage( g->myname );
|
||||
return( -1 );
|
||||
}
|
||||
ldap_debug |= level;
|
||||
#else /* !LDAP_DEBUG */
|
||||
if ( lutil_atoi( &level, optarg ) != 0 || level != 0 )
|
||||
/* can't enable debugging - not built with debug code */
|
||||
fputs( "must compile with LDAP_DEBUG for debugging\n",
|
||||
stderr );
|
||||
#endif /* LDAP_DEBUG */
|
||||
} break;
|
||||
case 'f': /* slapd config file */
|
||||
LUTIL_SLASHPATH( optarg );
|
||||
g->slapd_configfile = strdup( optarg );
|
||||
break;
|
||||
case 'n': /* NT service name */
|
||||
if ( g->serverName ) free( g->serverName );
|
||||
g->serverName = strdup( optarg );
|
||||
break;
|
||||
case 'o':
|
||||
g->one_shot_mode = 1;
|
||||
break;
|
||||
case 'r': /* slapd replog file */
|
||||
LUTIL_SLASHPATH( optarg );
|
||||
snprintf( g->slapd_replogfile, sizeof g->slapd_replogfile,
|
||||
"%s", optarg );
|
||||
rflag++;
|
||||
break;
|
||||
case 't': { /* dir to use for our copies of replogs */
|
||||
size_t sz;
|
||||
LUTIL_SLASHPATH( optarg );
|
||||
g->slurpd_rdir = (char *)malloc (sz = (strlen(optarg) + sizeof(LDAP_DIRSEP "replica")));
|
||||
snprintf(g->slurpd_rdir, sz,
|
||||
"%s" LDAP_DIRSEP "replica", optarg);
|
||||
} break;
|
||||
case 'V':
|
||||
(g->version)++;
|
||||
break;
|
||||
default:
|
||||
usage( g->myname );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( g->one_shot_mode && !rflag ) {
|
||||
fprintf( stderr, "If -o flag is given, -r flag must also be given.\n" );
|
||||
usage( g->myname );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Set location/name of our private copy of the slapd replog file */
|
||||
snprintf( g->slurpd_replogfile, sizeof g->slurpd_replogfile,
|
||||
"%s" LDAP_DIRSEP "%s", g->slurpd_rdir,
|
||||
DEFAULT_SLURPD_REPLOGFILE );
|
||||
|
||||
/* Set location/name of the slurpd status file */
|
||||
snprintf( g->slurpd_status_file, sizeof g->slurpd_status_file,
|
||||
"%s" LDAP_DIRSEP "%s", g->slurpd_rdir,
|
||||
DEFAULT_SLURPD_STATUS_FILE );
|
||||
|
||||
ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug);
|
||||
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug);
|
||||
ldif_debug = ldap_debug;
|
||||
|
||||
#ifdef LOG_LOCAL4
|
||||
openlog( g->myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
|
||||
#elif LOG_DEBUG
|
||||
openlog( g->myname, OPENLOG_OPTIONS );
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
#define CH_FREE 1
|
||||
|
||||
/*
|
||||
* ch_malloc.c - malloc() and friends, with check for NULL return.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include "../slapd/slap.h"
|
||||
|
||||
|
||||
#ifndef CSRIMALLOC
|
||||
|
||||
/*
|
||||
* Just like malloc, except we check the returned value and exit
|
||||
* if anything goes wrong.
|
||||
*/
|
||||
void *
|
||||
ch_malloc(
|
||||
ber_len_t size
|
||||
)
|
||||
{
|
||||
void *new;
|
||||
|
||||
if ( (new = (void *) ber_memalloc( size )) == NULL ) {
|
||||
fprintf( stderr, "malloc of %lu bytes failed\n",
|
||||
(long) size );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
return( new );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Just like realloc, except we check the returned value and exit
|
||||
* if anything goes wrong.
|
||||
*/
|
||||
void *
|
||||
ch_realloc(
|
||||
void *block,
|
||||
ber_len_t size
|
||||
)
|
||||
{
|
||||
void *new;
|
||||
|
||||
if ( block == NULL ) {
|
||||
return( ch_malloc( size ) );
|
||||
}
|
||||
|
||||
if ( size == 0 ) {
|
||||
ch_free( block );
|
||||
}
|
||||
|
||||
if ( (new = (void *) ber_memrealloc( block, size )) == NULL ) {
|
||||
fprintf( stderr, "realloc of %lu bytes failed\n",
|
||||
(long) size );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
return( new );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Just like calloc, except we check the returned value and exit
|
||||
* if anything goes wrong.
|
||||
*/
|
||||
void *
|
||||
ch_calloc(
|
||||
ber_len_t nelem,
|
||||
ber_len_t size
|
||||
)
|
||||
{
|
||||
void *new;
|
||||
|
||||
if ( (new = (void *) ber_memcalloc( nelem, size )) == NULL ) {
|
||||
fprintf( stderr, "calloc of %lu elems of %lu bytes failed\n",
|
||||
(long) nelem, (long) size );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
return( new );
|
||||
}
|
||||
|
||||
/*
|
||||
* Just like strdup, except we check the returned value and exit
|
||||
* if anything goes wrong.
|
||||
*/
|
||||
char *
|
||||
ch_strdup(
|
||||
const char *string
|
||||
)
|
||||
{
|
||||
char *new;
|
||||
|
||||
if ( (new = ber_strdup( string )) == NULL ) {
|
||||
fprintf( stderr, "ch_strdup: duplication of \"%s\" failed\n",
|
||||
string );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
return( new );
|
||||
}
|
||||
|
||||
/*
|
||||
* Just like free, except we check to see if p is null.
|
||||
*/
|
||||
void
|
||||
ch_free(
|
||||
void *p
|
||||
)
|
||||
{
|
||||
if ( p != NULL ) {
|
||||
ber_memfree( p );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,675 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2003 Mark Benson.
|
||||
* Portions Copyright 2002 John Morrissey.
|
||||
* 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP). Additional signficant contributors
|
||||
* include:
|
||||
* John Morrissey
|
||||
* Mark Benson
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* config.c - configuration file handling routines
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
#include <ac/ctype.h>
|
||||
|
||||
#include <ldap.h>
|
||||
#include <lutil.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
#define ARGS_STEP 512
|
||||
|
||||
/* Forward declarations */
|
||||
static void add_replica LDAP_P(( char **, int ));
|
||||
static int parse_replica_line LDAP_P(( char **, int, Ri *));
|
||||
static void parse_line LDAP_P(( char * ));
|
||||
static char *slurpd_getline LDAP_P(( FILE * ));
|
||||
static char *strtok_quote LDAP_P(( char *, char * ));
|
||||
|
||||
int cargc = 0, cargv_size = 0;
|
||||
char **cargv;
|
||||
/* current config file line # */
|
||||
static int lineno;
|
||||
|
||||
char *slurpd_pid_file = NULL;
|
||||
char *slurpd_args_file = NULL;
|
||||
|
||||
/*
|
||||
* Read the slapd config file, looking only for config options we're
|
||||
* interested in. Since we haven't detached from the controlling
|
||||
* terminal yet, we just perror() and fprintf here.
|
||||
*/
|
||||
int
|
||||
slurpd_read_config(
|
||||
char *fname
|
||||
)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line;
|
||||
|
||||
#define GOT_REPLOG_NO (0)
|
||||
#define GOT_REPLOG_ONE (1)
|
||||
#define GOT_REPLOG_YES (2)
|
||||
#define GOT_REPLOG_DONE (3)
|
||||
#define GOT_REPLOG_MASK (0xF)
|
||||
#define GOT_REPLOG(i) ((i) & GOT_REPLOG_MASK)
|
||||
#define GOT_REPLOG_SET(i,v) ((i) = ((i) & ~GOT_REPLOG_MASK) | ((v) & GOT_REPLOG_MASK))
|
||||
|
||||
#define GOT_REPLOG_PID (0x10)
|
||||
#define GOT_REPLOG_ARGS (0x20)
|
||||
#define GOT_REPLOG_INTERVAL (0x40)
|
||||
int got_replog = GOT_REPLOG_NO;
|
||||
|
||||
/*
|
||||
* replica-pidfile and replica-argsfile can appear before any replog;
|
||||
* in this case they're global (legacy behavior); otherwise, since
|
||||
* each replog needs a slurpd, they can appear after a replogfile line;
|
||||
* in that case, the replog specific values are used.
|
||||
*/
|
||||
|
||||
if ( cargv == NULL ) {
|
||||
cargv = ch_calloc( ARGS_STEP + 1, sizeof(*cargv) );
|
||||
cargv_size = ARGS_STEP + 1;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
|
||||
fname, 0, 0 );
|
||||
|
||||
if ( (fp = fopen( fname, "r" )) == NULL ) {
|
||||
perror( fname );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
lineno = 0;
|
||||
while ( (line = slurpd_getline( fp )) != NULL ) {
|
||||
/* skip comments and blank lines */
|
||||
if ( line[0] == '#' || line[0] == '\0' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
|
||||
|
||||
parse_line( line );
|
||||
|
||||
if ( cargc < 1 ) {
|
||||
fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* replication log file to which changes are appended */
|
||||
if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
|
||||
/*
|
||||
* if slapd_replogfile has a value, the -r option was given,
|
||||
* so use that value. If slapd_replogfile has length == 0,
|
||||
* then we should use the value in the config file we're reading.
|
||||
*/
|
||||
if ( cargc < 2 ) {
|
||||
fprintf( stderr,
|
||||
"line %d: missing filename in \"replogfile ",
|
||||
lineno );
|
||||
fprintf( stderr, "<filename>\" line\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
|
||||
} else if ( cargc > 2 && *cargv[2] != '#' ) {
|
||||
fprintf( stderr,
|
||||
"line %d: extra cruft at the end of \"replogfile %s\"",
|
||||
lineno, cargv[1] );
|
||||
fprintf( stderr, "line (ignored)\n" );
|
||||
}
|
||||
|
||||
LUTIL_SLASHPATH( cargv[1] );
|
||||
if ( sglob->slapd_replogfile[0] == '\0' ) {
|
||||
strcpy( sglob->slapd_replogfile, cargv[1] );
|
||||
GOT_REPLOG_SET(got_replog, GOT_REPLOG_YES);
|
||||
|
||||
} else {
|
||||
if ( strcmp( sglob->slapd_replogfile, cargv[1] ) == 0 ) {
|
||||
GOT_REPLOG_SET(got_replog, GOT_REPLOG_YES);
|
||||
|
||||
} else if ( GOT_REPLOG(got_replog) == GOT_REPLOG_YES ) {
|
||||
GOT_REPLOG_SET(got_replog, GOT_REPLOG_DONE);
|
||||
|
||||
} else {
|
||||
GOT_REPLOG_SET(got_replog, GOT_REPLOG_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
} else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
|
||||
add_replica( cargv, cargc );
|
||||
|
||||
/* include another config file */
|
||||
} else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
|
||||
char *savefname;
|
||||
int savelineno;
|
||||
|
||||
if ( cargc < 2 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: line %d: missing filename in \"include <filename>\" line\n",
|
||||
fname, lineno, 0 );
|
||||
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
LUTIL_SLASHPATH( cargv[1] );
|
||||
savefname = strdup( cargv[1] );
|
||||
savelineno = lineno;
|
||||
|
||||
if ( slurpd_read_config( savefname ) != 0 ) {
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
free( savefname );
|
||||
lineno = savelineno - 1;
|
||||
|
||||
} else if ( strcasecmp( cargv[0], "replica-pidfile" ) == 0 ) {
|
||||
if ( cargc < 2 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: line %d: missing file name in \"replica-pidfile <file>\" line\n",
|
||||
fname, lineno, 0 );
|
||||
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
switch ( GOT_REPLOG(got_replog) ) {
|
||||
case GOT_REPLOG_YES:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"got replog specific replica-pidfile \"%s\".\n",
|
||||
fname, lineno, cargv[1] );
|
||||
case GOT_REPLOG_NO:
|
||||
LUTIL_SLASHPATH( cargv[1] );
|
||||
if ( slurpd_pid_file != NULL ) {
|
||||
ch_free( slurpd_pid_file );
|
||||
}
|
||||
slurpd_pid_file = ch_strdup( cargv[1] );
|
||||
got_replog |= GOT_REPLOG_PID;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"replica-pidfile \"%s\" not mine.\n",
|
||||
fname, lineno, cargv[1] );
|
||||
break;
|
||||
}
|
||||
|
||||
} else if ( strcasecmp( cargv[0], "replica-argsfile" ) == 0 ) {
|
||||
if ( cargc < 2 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: line %d: missing file name in \"argsfile <file>\" line\n",
|
||||
fname, lineno, 0 );
|
||||
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
switch ( GOT_REPLOG(got_replog) ) {
|
||||
case GOT_REPLOG_YES:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"got replog specific replica-argsfile \"%s\".\n",
|
||||
fname, lineno, cargv[1] );
|
||||
case GOT_REPLOG_NO:
|
||||
LUTIL_SLASHPATH( cargv[1] );
|
||||
if ( slurpd_args_file != NULL ) {
|
||||
ch_free( slurpd_args_file );
|
||||
}
|
||||
slurpd_args_file = ch_strdup( cargv[1] );
|
||||
got_replog |= GOT_REPLOG_ARGS;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"replica-argsfile \"%s\" not mine.\n",
|
||||
fname, lineno, cargv[1] );
|
||||
break;
|
||||
}
|
||||
|
||||
} else if ( strcasecmp( cargv[0], "replicationinterval" ) == 0 ) {
|
||||
int c;
|
||||
|
||||
if ( cargc < 2 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "%s: line %d: missing interval in "
|
||||
"\"replicationinterval <seconds>\" line\n",
|
||||
fname, lineno, 0 );
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
if ( lutil_atoi( &c, cargv[1] ) != 0 || c < 1 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "%s: line %d: invalid interval "
|
||||
"(%d) in \"replicationinterval <seconds>\" line\n",
|
||||
fname, lineno, c );
|
||||
|
||||
fclose( fp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
switch ( GOT_REPLOG(got_replog) ) {
|
||||
case GOT_REPLOG_YES:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"got replog specific replicationinterval \"%s\".\n",
|
||||
fname, lineno, cargv[1] );
|
||||
case GOT_REPLOG_NO:
|
||||
sglob->no_work_interval = c;
|
||||
got_replog |= GOT_REPLOG_INTERVAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_CONFIG, "%s: line %d: "
|
||||
"replicationinterval \"%s\" not mine.\n",
|
||||
fname, lineno, cargv[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
Debug( LDAP_DEBUG_CONFIG,
|
||||
"Config: ** configuration file successfully read and parsed\n",
|
||||
0, 0, 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Parse one line of input.
|
||||
*/
|
||||
static void
|
||||
parse_line(
|
||||
char *line
|
||||
)
|
||||
{
|
||||
char * token;
|
||||
|
||||
cargc = 0;
|
||||
for ( token = strtok_quote( line, " \t" ); token != NULL;
|
||||
token = strtok_quote( NULL, " \t" ) )
|
||||
{
|
||||
if ( cargc == cargv_size - 1 ) {
|
||||
char **tmp;
|
||||
tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
|
||||
sizeof(*cargv) );
|
||||
if (tmp == NULL) {
|
||||
cargc = 0;
|
||||
return;
|
||||
}
|
||||
cargv = tmp;
|
||||
cargv_size += ARGS_STEP;
|
||||
}
|
||||
|
||||
cargv[cargc++] = token;
|
||||
}
|
||||
cargv[cargc] = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static char *
|
||||
strtok_quote(
|
||||
char *line,
|
||||
char *sep
|
||||
)
|
||||
{
|
||||
int inquote;
|
||||
char *tmp;
|
||||
static char *next;
|
||||
|
||||
if ( line != NULL ) {
|
||||
next = line;
|
||||
}
|
||||
while ( *next && strchr( sep, *next ) ) {
|
||||
next++;
|
||||
}
|
||||
|
||||
if ( *next == '\0' ) {
|
||||
next = NULL;
|
||||
return( NULL );
|
||||
}
|
||||
tmp = next;
|
||||
|
||||
for ( inquote = 0; *next; ) {
|
||||
switch ( *next ) {
|
||||
case '"':
|
||||
if ( inquote ) {
|
||||
inquote = 0;
|
||||
} else {
|
||||
inquote = 1;
|
||||
}
|
||||
AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if ( next[1] )
|
||||
AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
|
||||
next++; /* dont parse the escaped character */
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( ! inquote ) {
|
||||
if ( strchr( sep, *next ) != NULL ) {
|
||||
*next++ = '\0';
|
||||
return( tmp );
|
||||
}
|
||||
}
|
||||
next++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return( tmp );
|
||||
}
|
||||
|
||||
#define CATLINE( buf ) { \
|
||||
int len; \
|
||||
len = strlen( buf ); \
|
||||
while ( lcur + len + 1 > lmax ) { \
|
||||
lmax += BUFSIZ; \
|
||||
line = (char *) ch_realloc( line, lmax ); \
|
||||
} \
|
||||
strcpy( line + lcur, buf ); \
|
||||
lcur += len; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Get a line of input.
|
||||
*/
|
||||
static char *
|
||||
slurpd_getline(
|
||||
FILE *fp
|
||||
)
|
||||
{
|
||||
char *p;
|
||||
static char buf[BUFSIZ];
|
||||
static char *line;
|
||||
static int lmax, lcur;
|
||||
|
||||
lcur = 0;
|
||||
CATLINE( buf );
|
||||
while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
|
||||
if ( (p = strchr( buf, '\n' )) != NULL ) {
|
||||
if( p > buf && p[-1] == '\r' ) --p;
|
||||
*p = '\0';
|
||||
}
|
||||
lineno++;
|
||||
if ( ! isspace( (unsigned char) buf[0] ) ) {
|
||||
return( line );
|
||||
}
|
||||
|
||||
/* change leading whitespace to space */
|
||||
buf[0] = ' ';
|
||||
|
||||
CATLINE( buf );
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
return( line[0] ? line : NULL );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a node to the array of replicas.
|
||||
*/
|
||||
static void
|
||||
add_replica(
|
||||
char **cargv,
|
||||
int cargc
|
||||
)
|
||||
{
|
||||
int nr;
|
||||
|
||||
nr = ++sglob->num_replicas;
|
||||
sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
|
||||
( nr + 1 ) * sizeof( Re * ));
|
||||
if ( sglob->replicas == NULL ) {
|
||||
fprintf( stderr, "out of memory, add_replica\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
sglob->replicas[ nr ] = NULL;
|
||||
|
||||
if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
|
||||
fprintf( stderr, "out of memory, Ri_init\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
if ( parse_replica_line( cargv, cargc,
|
||||
sglob->replicas[ nr - 1] ) < 0 ) {
|
||||
/* Something bad happened - back out */
|
||||
fprintf( stderr,
|
||||
"Warning: failed to add replica \"%s:%d - ignoring replica\n",
|
||||
sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
|
||||
"(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
|
||||
sglob->replicas[ nr - 1 ]->ri_port );
|
||||
sglob->replicas[ nr - 1] = NULL;
|
||||
sglob->num_replicas--;
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_CONFIG,
|
||||
"Config: ** successfully added replica \"%s:%d\"\n",
|
||||
sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
|
||||
"(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
|
||||
sglob->replicas[ nr - 1 ]->ri_port, 0 );
|
||||
sglob->replicas[ nr - 1]->ri_stel =
|
||||
sglob->st->st_add( sglob->st,
|
||||
sglob->replicas[ nr - 1 ] );
|
||||
if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
|
||||
fprintf( stderr, "Failed to add status element structure\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Parse a "replica" line from the config file. replica lines should be
|
||||
* in the following format:
|
||||
* replica host=<hostname:portnumber> binddn=<binddn>
|
||||
* bindmethod="simple" credentials=<creds>
|
||||
*
|
||||
* where:
|
||||
* <hostname:portnumber> describes the host name and port number where the
|
||||
* replica is running,
|
||||
*
|
||||
* <binddn> is the DN to bind to the replica slapd as,
|
||||
*
|
||||
* bindmethod is "simple", and
|
||||
*
|
||||
* <creds> are the credentials (e.g. password) for binddn. <creds> are
|
||||
* only used for bindmethod=simple.
|
||||
*
|
||||
* The "replica" config file line may be split across multiple lines. If
|
||||
* a line begins with whitespace, it is considered a continuation of the
|
||||
* previous line.
|
||||
*/
|
||||
#define GOT_HOST 1
|
||||
#define GOT_DN 2
|
||||
#define GOT_METHOD 4
|
||||
#define GOT_ALL ( GOT_HOST | GOT_DN | GOT_METHOD )
|
||||
#define GOT_MECH 8
|
||||
|
||||
static int
|
||||
parse_replica_line(
|
||||
char **cargv,
|
||||
int cargc,
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
int gots = 0;
|
||||
int i;
|
||||
char *hp, *val;
|
||||
LDAPURLDesc *ludp;
|
||||
|
||||
for ( i = 1; i < cargc; i++ ) {
|
||||
if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
|
||||
if ( gots & GOT_HOST ) {
|
||||
fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
|
||||
fprintf( stderr, "file, too many host or uri names specified, line %d\n",
|
||||
lineno );
|
||||
return -1;
|
||||
}
|
||||
val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
|
||||
if (( hp = strchr( val, ':' )) != NULL ) {
|
||||
*hp = '\0';
|
||||
hp++;
|
||||
if ( lutil_atoi( &ri->ri_port, hp ) != 0 ) {
|
||||
fprintf( stderr, "unable to parse port \"%s\", line %d\n",
|
||||
hp, lineno );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( ri->ri_port <= 0 ) {
|
||||
ri->ri_port = LDAP_PORT;
|
||||
}
|
||||
ri->ri_hostname = strdup( val );
|
||||
gots |= GOT_HOST;
|
||||
} else if ( !strncasecmp( cargv[ i ], URISTR, sizeof( URISTR ) - 1 ) ) {
|
||||
if ( gots & GOT_HOST ) {
|
||||
fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
|
||||
fprintf( stderr, "file, too many host or uri names specified, line %d\n",
|
||||
lineno );
|
||||
return -1;
|
||||
}
|
||||
if ( ldap_url_parse( cargv[ i ] + sizeof( URISTR ), &ludp ) != LDAP_SUCCESS ) {
|
||||
fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
|
||||
fprintf( stderr, "file, bad uri format specified, line %d\n",
|
||||
lineno );
|
||||
return -1;
|
||||
}
|
||||
if (ludp->lud_host == NULL) {
|
||||
fprintf( stderr, "Error: Malformed \"replica\" line in slapd config " );
|
||||
fprintf( stderr, "file, missing uri hostname, line %d\n",
|
||||
lineno );
|
||||
ldap_free_urldesc( ludp );
|
||||
return -1;
|
||||
}
|
||||
ri->ri_hostname = strdup ( ludp->lud_host );
|
||||
ri->ri_port = ludp->lud_port;
|
||||
ri->ri_uri = strdup ( cargv[ i ] + sizeof( URISTR ) );
|
||||
ldap_free_urldesc( ludp );
|
||||
gots |= GOT_HOST;
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) {
|
||||
/* ignore it */ ;
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) {
|
||||
/* ignore it */ ;
|
||||
} else if ( !strncasecmp( cargv[i], STARTTLSSTR, sizeof(STARTTLSSTR)-1 )) {
|
||||
val = cargv[ i ] + sizeof( STARTTLSSTR );
|
||||
if( !strcasecmp( val, CRITICALSTR ) ) {
|
||||
ri->ri_tls = TLS_CRITICAL;
|
||||
} else {
|
||||
ri->ri_tls = TLS_ON;
|
||||
}
|
||||
} else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( TLSSTR );
|
||||
if( !strcasecmp( val, CRITICALSTR ) ) {
|
||||
ri->ri_tls = TLS_CRITICAL;
|
||||
} else {
|
||||
ri->ri_tls = TLS_ON;
|
||||
}
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( BINDDNSTR );
|
||||
ri->ri_bind_dn = strdup( val );
|
||||
gots |= GOT_DN;
|
||||
} else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
|
||||
sizeof( BINDMETHSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( BINDMETHSTR );
|
||||
if ( !strcasecmp( val, SIMPLESTR )) {
|
||||
ri->ri_bind_method = LDAP_AUTH_SIMPLE;
|
||||
gots |= GOT_METHOD;
|
||||
} else if ( !strcasecmp( val, SASLSTR )) {
|
||||
ri->ri_bind_method = LDAP_AUTH_SASL;
|
||||
gots |= GOT_METHOD;
|
||||
} else {
|
||||
ri->ri_bind_method = -1;
|
||||
}
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( SASLMECHSTR );
|
||||
gots |= GOT_MECH;
|
||||
ri->ri_saslmech = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
CREDSTR, sizeof( CREDSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( CREDSTR );
|
||||
ri->ri_password = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( SECPROPSSTR );
|
||||
ri->ri_secprops = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
REALMSTR, sizeof( REALMSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( REALMSTR );
|
||||
ri->ri_realm = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( AUTHCSTR );
|
||||
ri->ri_authcId = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) {
|
||||
/* Old authcID is provided for some backwards compatibility */
|
||||
val = cargv[ i ] + sizeof( OLDAUTHCSTR );
|
||||
ri->ri_authcId = strdup( val );
|
||||
} else if ( !strncasecmp( cargv[ i ],
|
||||
AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) {
|
||||
val = cargv[ i ] + sizeof( AUTHZSTR );
|
||||
ri->ri_authzId = strdup( val );
|
||||
} else {
|
||||
fprintf( stderr,
|
||||
"Error: parse_replica_line: unknown keyword \"%s\"\n",
|
||||
cargv[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ri->ri_bind_method == LDAP_AUTH_SASL) {
|
||||
if ((gots & GOT_MECH) == 0) {
|
||||
fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " );
|
||||
fprintf( stderr, "slapd config file, line %d\n", lineno );
|
||||
return -1;
|
||||
}
|
||||
} else if ( gots != GOT_ALL ) {
|
||||
fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
|
||||
fprintf( stderr, "config file, line %d\n", lineno );
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* fm.c - file management routines.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/signal.h>
|
||||
#include <ac/socket.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
#include "lutil.h"
|
||||
|
||||
|
||||
/*
|
||||
* Forward references
|
||||
*/
|
||||
static char *get_record LDAP_P(( FILE * ));
|
||||
static void populate_queue LDAP_P(( char *f ));
|
||||
|
||||
|
||||
/*
|
||||
* Main file manager routine. Watches for new data to be appended to the
|
||||
* slapd replication log. When new data is appended, fm does the following:
|
||||
* - appends the data to slurpd's private copy of the replication log.
|
||||
* - truncates the slapd replog
|
||||
* - adds items to the internal queue of replication work to do
|
||||
* - signals the replication threads to let them know new work has arrived.
|
||||
*/
|
||||
void *
|
||||
fm(
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
fd_set readfds;
|
||||
|
||||
/* Set up our signal handlers:
|
||||
* SIG{TERM,INT,HUP} causes a shutdown
|
||||
*/
|
||||
(void) SIGNAL( SIGTERM, slurp_set_shutdown );
|
||||
(void) SIGNAL( SIGINT, slurp_set_shutdown );
|
||||
#ifdef SIGHUP
|
||||
(void) SIGNAL( SIGHUP, slurp_set_shutdown );
|
||||
#endif
|
||||
#if defined(SIGBREAK)
|
||||
(void) SIGNAL( SIGBREAK, slurp_set_shutdown );
|
||||
#endif
|
||||
|
||||
if ( sglob->one_shot_mode ) {
|
||||
if ( file_nonempty( sglob->slapd_replogfile )) {
|
||||
populate_queue( sglob->slapd_replogfile );
|
||||
}
|
||||
printf( "Processing in one-shot mode:\n" );
|
||||
printf( "%d total replication records in file,\n",
|
||||
sglob->rq->rq_getcount( sglob->rq, RQ_COUNT_ALL ));
|
||||
printf( "%d replication records to process.\n",
|
||||
sglob->rq->rq_getcount( sglob->rq, RQ_COUNT_NZRC ));
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* There may be some leftover replication records in our own
|
||||
* copy of the replication log. If any exist, add them to the
|
||||
* queue.
|
||||
*/
|
||||
if ( file_nonempty( sglob->slurpd_replogfile )) {
|
||||
populate_queue( sglob->slurpd_replogfile );
|
||||
}
|
||||
|
||||
FD_ZERO( &readfds );
|
||||
|
||||
while ( !sglob->slurpd_shutdown ) {
|
||||
if ( file_nonempty( sglob->slapd_replogfile )) {
|
||||
/* New work found - copy to slurpd replog file */
|
||||
Debug( LDAP_DEBUG_ARGS, "new work in %s\n",
|
||||
sglob->slapd_replogfile, 0, 0 );
|
||||
if (( rc = copy_replog( sglob->slapd_replogfile,
|
||||
sglob->slurpd_replogfile )) == 0 ) {
|
||||
populate_queue( sglob->slurpd_replogfile );
|
||||
} else {
|
||||
if ( rc < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Fatal error while copying replication log\n",
|
||||
0, 0, 0 );
|
||||
sglob->slurpd_shutdown = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct timeval tv;
|
||||
|
||||
FD_SET( sglob->wake_sds[0], &readfds );
|
||||
tv.tv_sec = sglob->no_work_interval;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
rc = select( sglob->wake_sds[0]+1, &readfds, NULL, NULL, &tv );
|
||||
}
|
||||
|
||||
/* Garbage-collect queue */
|
||||
sglob->rq->rq_gc( sglob->rq );
|
||||
|
||||
/* Trim replication log file, if needed */
|
||||
if ( sglob->rq->rq_needtrim( sglob->rq )) {
|
||||
FILE *fp, *lfp;
|
||||
if (( rc = acquire_lock( sglob->slurpd_replogfile, &fp,
|
||||
&lfp )) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: cannot acquire lock on \"%s\" for trimming\n",
|
||||
sglob->slurpd_replogfile, 0, 0 );
|
||||
} else {
|
||||
sglob->rq->rq_write( sglob->rq, fp );
|
||||
(void) relinquish_lock( sglob->slurpd_replogfile, fp, lfp );
|
||||
}
|
||||
}
|
||||
}
|
||||
sglob->rq->rq_lock( sglob->rq ); /* lock queue */
|
||||
ldap_pvt_thread_cond_broadcast( &(sglob->rq->rq_more) ); /* wake repl threads */
|
||||
for ( i = 0; i < sglob->num_replicas; i++ ) {
|
||||
(sglob->replicas[ i ])->ri_wake( sglob->replicas[ i ]);
|
||||
}
|
||||
sglob->rq->rq_unlock( sglob->rq ); /* unlock queue */
|
||||
Debug( LDAP_DEBUG_ARGS, "fm: exiting\n", 0, 0, 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set a global flag which signals that we're shutting down.
|
||||
*/
|
||||
RETSIGTYPE
|
||||
slurp_set_shutdown(int sig)
|
||||
{
|
||||
#if HAVE_NT_SERVICE_MANAGER && SIGBREAK
|
||||
if (is_NT_Service && sig == SIGBREAK) {
|
||||
/* empty */;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
sglob->slurpd_shutdown = 1; /* set flag */
|
||||
tcp_write( sglob->wake_sds[1], "0", 1); /* wake up file mgr */
|
||||
}
|
||||
|
||||
(void) SIGNAL_REINSTALL( sig, slurp_set_shutdown ); /* reinstall handlers */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A do-nothing signal handler.
|
||||
*/
|
||||
RETSIGTYPE
|
||||
do_nothing(int sig)
|
||||
{
|
||||
(void) SIGNAL_REINSTALL( sig, do_nothing );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Open the slurpd replication log, seek to our last known position, and
|
||||
* process any pending replication entries.
|
||||
*/
|
||||
static void
|
||||
populate_queue(
|
||||
char *f
|
||||
)
|
||||
{
|
||||
FILE *fp, *lfp;
|
||||
char *p;
|
||||
|
||||
if ( acquire_lock( f, &fp, &lfp ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"error: can't lock file \"%s\": %s\n",
|
||||
f, sys_errlist[ errno ], 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read replication records from fp and append them the
|
||||
* the queue.
|
||||
*/
|
||||
if ( fseek( fp, sglob->srpos, 0 ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"error: can't seek to offset %ld in file \"%s\"\n",
|
||||
sglob->srpos, f, 0 );
|
||||
} else {
|
||||
while (( p = get_record( fp )) != NULL ) {
|
||||
if ( sglob->rq->rq_add( sglob->rq, p ) < 0 ) {
|
||||
char *t;
|
||||
/* Print an error message. Only print first line. */
|
||||
if (( t = strchr( p, '\n' )) != NULL ) {
|
||||
*t = '\0';
|
||||
}
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"error: malformed replog entry (begins with \"%s\")\n",
|
||||
p, 0, 0 );
|
||||
}
|
||||
free( p );
|
||||
ldap_pvt_thread_yield();
|
||||
}
|
||||
sglob->srpos = ftell( fp );
|
||||
}
|
||||
(void) relinquish_lock( f, fp, lfp );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Get the next "record" from the file pointed to by fp. A "record"
|
||||
* is delimited by two consecutive newlines. Returns NULL on EOF.
|
||||
*/
|
||||
static char *
|
||||
get_record(
|
||||
FILE *fp
|
||||
)
|
||||
{
|
||||
int len;
|
||||
static char line[BUFSIZ];
|
||||
char *buf = NULL;
|
||||
static int lcur, lmax;
|
||||
|
||||
lcur = lmax = 0;
|
||||
|
||||
while (( fgets( line, sizeof(line), fp ) != NULL ) &&
|
||||
(( len = strlen( line )) > 1 )) {
|
||||
|
||||
while ( lcur + len + 1 > lmax ) {
|
||||
lmax += BUFSIZ;
|
||||
buf = (char *) ch_realloc( buf, lmax );
|
||||
}
|
||||
strcpy( buf + lcur, line );
|
||||
lcur += len;
|
||||
}
|
||||
return( buf );
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* globals.c - initialization code for global data
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
Globals *sglob;
|
||||
static Globals glob;
|
||||
|
||||
int ldap_syslog = 0;
|
||||
#ifdef LOG_DEBUG
|
||||
int ldap_syslog_level = LOG_DEBUG;
|
||||
#else
|
||||
int ldap_syslog_level = 0;
|
||||
#endif
|
||||
int ldap_debug = 0;
|
||||
|
||||
/*
|
||||
* Initialize the globals
|
||||
*/
|
||||
Globals *
|
||||
init_globals( void )
|
||||
{
|
||||
Globals *g;
|
||||
|
||||
g = &glob;
|
||||
|
||||
g->wake_sds[0] = -1;
|
||||
g->wake_sds[1] = -1;
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
g->slapd_configfile = ".\\slapd.conf";
|
||||
g->slurpd_rdir = ".\\replica";
|
||||
#else
|
||||
g->slapd_configfile = SLAPD_DEFAULT_CONFIGFILE;
|
||||
g->slurpd_rdir = DEFAULT_SLURPD_REPLICA_DIR "/replica";
|
||||
#endif
|
||||
|
||||
g->no_work_interval = DEFAULT_NO_WORK_INTERVAL;
|
||||
g->slurpd_shutdown = 0;
|
||||
g->num_replicas = 0;
|
||||
g->replicas = NULL;
|
||||
g->slapd_replogfile[ 0 ] = '\0';
|
||||
g->slurpd_replogfile[ 0 ] = '\0';
|
||||
g->slurpd_status_file[ 0 ] = '\0';
|
||||
g->one_shot_mode = 0;
|
||||
g->no_detach = 0;
|
||||
g->myname = NULL;
|
||||
g->serverName = NULL;
|
||||
g->srpos = 0L;
|
||||
g->version = 0;
|
||||
if ( St_init( &(g->st)) < 0 ) {
|
||||
fprintf( stderr, "Cannot initialize status data\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
ldap_pvt_thread_mutex_init( &(g->rej_mutex) );
|
||||
if ( Rq_init( &(g->rq)) < 0 ) {
|
||||
fprintf( stderr, "Cannot initialize queue\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
#ifndef SLURPD_GLOBALS_H
|
||||
#define SLURPD_GLOBALS_H 1
|
||||
|
||||
/*
|
||||
* globals.h - definition of structure holding global data.
|
||||
*/
|
||||
|
||||
#include "slurp.h"
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
|
||||
typedef struct globals {
|
||||
/* Thread ID for file manager thread */
|
||||
ldap_pvt_thread_t fm_tid;
|
||||
/* pipe/socket used to wake manager from signal handler */
|
||||
int wake_sds[2];
|
||||
/* The name of the slapd config file (which is also our config file) */
|
||||
char *slapd_configfile;
|
||||
/* How long the master slurpd sleeps when there's no work to do */
|
||||
int no_work_interval;
|
||||
/* We keep running until slurpd_shutdown is nonzero. HUP signal set this */
|
||||
sig_atomic_t slurpd_shutdown;
|
||||
/* Number of replicas we're servicing */
|
||||
int num_replicas;
|
||||
/* Array of pointers to replica info */
|
||||
Ri **replicas;
|
||||
/* Directory where our replica files are written/read */
|
||||
char *slurpd_rdir;
|
||||
/* Name of slurpd status file (timestamp of last replog */
|
||||
char slurpd_status_file[ MAXPATHLEN ];
|
||||
/* Name of the replication log slapd is writing (and we are reading) */
|
||||
char slapd_replogfile[ MAXPATHLEN ];
|
||||
/* Name of local copy of replogfile we maintain */
|
||||
char slurpd_replogfile[ MAXPATHLEN ];
|
||||
/* Non-zero if we were given a replog file to process on command-line */
|
||||
int one_shot_mode;
|
||||
/* Non-zero if we should not detach the process */
|
||||
int no_detach;
|
||||
/* Name of program */
|
||||
char *myname;
|
||||
/* NT service name */
|
||||
char *serverName;
|
||||
/* Current offset into slurpd replica logfile */
|
||||
off_t srpos;
|
||||
/* mutex to serialize access to reject file */
|
||||
ldap_pvt_thread_mutex_t rej_mutex;
|
||||
/* pointer to status struct */
|
||||
St *st;
|
||||
/* Pointer to replication queue */
|
||||
Rq *rq;
|
||||
/* Non-zero if we shall print the version */
|
||||
int version;
|
||||
} Globals;
|
||||
|
||||
|
||||
extern Globals *sglob;
|
||||
|
||||
LDAP_END_DECL
|
||||
|
||||
#endif /* SLURPD_GLOBALS_H */
|
||||
|
|
@ -1,918 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2003 Mark Benson.
|
||||
* 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP). Additional significant contributors
|
||||
* include:
|
||||
* Mark Benson
|
||||
*/
|
||||
|
||||
/*
|
||||
* ldap_op.c - routines to perform LDAP operations
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
|
||||
#include <ac/errno.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/ctype.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#define LDAP_DEPRECATED 1
|
||||
#include <ldap.h>
|
||||
#include "lutil_ldap.h"
|
||||
#include "slurp.h"
|
||||
|
||||
/* Forward references */
|
||||
static struct berval **make_singlevalued_berval LDAP_P(( char *, int ));
|
||||
static int op_ldap_add LDAP_P(( Ri *, Re *, char **, int * ));
|
||||
static int op_ldap_modify LDAP_P(( Ri *, Re *, char **, int * ));
|
||||
static int op_ldap_delete LDAP_P(( Ri *, Re *, char **, int * ));
|
||||
static int op_ldap_modrdn LDAP_P(( Ri *, Re *, char **, int * ));
|
||||
static LDAPMod *alloc_ldapmod LDAP_P(( void ));
|
||||
static void free_ldapmod LDAP_P(( LDAPMod * ));
|
||||
static void free_ldmarr LDAP_P(( LDAPMod ** ));
|
||||
static int getmodtype LDAP_P(( char * ));
|
||||
#ifdef SLAPD_UNUSED
|
||||
static void dump_ldm_array LDAP_P(( LDAPMod ** ));
|
||||
#endif
|
||||
static int do_bind LDAP_P(( Ri *, int * ));
|
||||
static int do_unbind LDAP_P(( Ri * ));
|
||||
|
||||
|
||||
/*
|
||||
* Determine the type of ldap operation being performed and call the
|
||||
* appropriate routine.
|
||||
* - If successful, returns DO_LDAP_OK
|
||||
* - If a retryable error occurs, ERR_DO_LDAP_RETRYABLE is returned.
|
||||
* The caller should wait a while and retry the operation.
|
||||
* - If a fatal error occurs, ERR_DO_LDAP_FATAL is returned. The caller
|
||||
* should reject the operation and continue with the next replication
|
||||
* entry.
|
||||
*/
|
||||
int
|
||||
do_ldap(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
char **errmsg,
|
||||
int *errfree
|
||||
)
|
||||
{
|
||||
int retry = 2;
|
||||
*errmsg = NULL;
|
||||
*errfree = 0;
|
||||
|
||||
do {
|
||||
int lderr;
|
||||
if ( ri->ri_ldp == NULL ) {
|
||||
lderr = do_bind( ri, &lderr );
|
||||
|
||||
if ( lderr != BIND_OK ) {
|
||||
return DO_LDAP_ERR_RETRYABLE;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( re->re_changetype ) {
|
||||
case T_ADDCT:
|
||||
lderr = op_ldap_add( ri, re, errmsg, errfree );
|
||||
if ( lderr != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_add_s failed adding DN \"%s\": %s\n",
|
||||
re->re_dn, *errmsg && (*errmsg)[0] ?
|
||||
*errmsg : ldap_err2string( lderr ), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case T_MODIFYCT:
|
||||
lderr = op_ldap_modify( ri, re, errmsg, errfree );
|
||||
if ( lderr != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_modify_s failed modifying DN \"%s\": %s\n",
|
||||
re->re_dn, *errmsg && (*errmsg)[0] ?
|
||||
*errmsg : ldap_err2string( lderr ), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case T_DELETECT:
|
||||
lderr = op_ldap_delete( ri, re, errmsg, errfree );
|
||||
if ( lderr != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_delete_s failed deleting DN \"%s\": %s\n",
|
||||
re->re_dn, *errmsg && (*errmsg)[0] ?
|
||||
*errmsg : ldap_err2string( lderr ), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case T_MODRDNCT:
|
||||
lderr = op_ldap_modrdn( ri, re, errmsg, errfree );
|
||||
if ( lderr != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_modrdn_s failed modifying DN \"%s\": %s\n",
|
||||
re->re_dn, *errmsg && (*errmsg)[0] ?
|
||||
*errmsg : ldap_err2string( lderr ), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: do_ldap: bad op \"%d\", DN \"%s\"\n",
|
||||
re->re_changetype, re->re_dn, 0 );
|
||||
return DO_LDAP_ERR_FATAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze return code. If ok, just return. If LDAP_SERVER_DOWN,
|
||||
* we may have been idle long enough that the remote slapd timed
|
||||
* us out. Rebind and try again.
|
||||
*/
|
||||
switch( lderr ) {
|
||||
case LDAP_SUCCESS:
|
||||
return DO_LDAP_OK;
|
||||
|
||||
default:
|
||||
return DO_LDAP_ERR_FATAL;
|
||||
|
||||
case LDAP_SERVER_DOWN: /* server went down */
|
||||
(void) do_unbind( ri );
|
||||
retry--;
|
||||
}
|
||||
} while ( retry > 0 );
|
||||
|
||||
return DO_LDAP_ERR_RETRYABLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform an ldap add operation.
|
||||
*/
|
||||
static int
|
||||
op_ldap_add(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
char **errmsg,
|
||||
int *errfree
|
||||
)
|
||||
{
|
||||
Mi *mi;
|
||||
int nattrs, rc = 0, i;
|
||||
LDAPMod *ldm, **ldmarr;
|
||||
int lderr = 0;
|
||||
|
||||
nattrs = i = 0;
|
||||
ldmarr = NULL;
|
||||
|
||||
/*
|
||||
* Construct a null-terminated array of LDAPMod structs.
|
||||
*/
|
||||
mi = re->re_mods;
|
||||
while ( mi[ i ].mi_type != NULL ) {
|
||||
ldm = alloc_ldapmod();
|
||||
ldmarr = ( LDAPMod ** ) ch_realloc( ldmarr,
|
||||
( nattrs + 2 ) * sizeof( LDAPMod * ));
|
||||
ldmarr[ nattrs ] = ldm;
|
||||
ldm->mod_op = LDAP_MOD_BVALUES;
|
||||
ldm->mod_type = mi[ i ].mi_type;
|
||||
ldm->mod_bvalues =
|
||||
make_singlevalued_berval( mi[ i ].mi_val, mi[ i ].mi_len );
|
||||
i++;
|
||||
nattrs++;
|
||||
}
|
||||
|
||||
if ( ldmarr != NULL ) {
|
||||
ldmarr[ nattrs ] = NULL;
|
||||
|
||||
/* Perform the operation */
|
||||
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n",
|
||||
ri->ri_hostname, ri->ri_port, re->re_dn );
|
||||
rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr );
|
||||
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_RESULT_CODE, &lderr);
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
|
||||
*errfree = 1;
|
||||
|
||||
} else {
|
||||
*errmsg = "No modifications to do";
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_add: no mods to do (%s)!\n", re->re_dn, 0, 0 );
|
||||
}
|
||||
free_ldmarr( ldmarr );
|
||||
return( lderr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform an ldap modify operation.
|
||||
*/
|
||||
#define AWAITING_OP -1
|
||||
static int
|
||||
op_ldap_modify(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
char **errmsg,
|
||||
int *errfree
|
||||
)
|
||||
{
|
||||
Mi *mi;
|
||||
int state; /* This code is a simple-minded state machine */
|
||||
int nvals; /* Number of values we're modifying */
|
||||
int nops; /* Number of LDAPMod structs in ldmarr */
|
||||
LDAPMod *ldm = NULL, **ldmarr;
|
||||
int i, len;
|
||||
char *type, *value;
|
||||
int rc = 0;
|
||||
|
||||
state = AWAITING_OP;
|
||||
nvals = 0;
|
||||
nops = 0;
|
||||
ldmarr = NULL;
|
||||
|
||||
if ( re->re_mods == NULL ) {
|
||||
*errmsg = "No arguments given";
|
||||
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modify: no arguments\n",
|
||||
0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a null-terminated array of LDAPMod structs.
|
||||
*/
|
||||
for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
|
||||
type = mi[ i ].mi_type;
|
||||
value = mi[ i ].mi_val;
|
||||
len = mi[ i ].mi_len;
|
||||
switch ( getmodtype( type )) {
|
||||
case T_MODSEP:
|
||||
state = T_MODSEP; /* Got a separator line "-\n" */
|
||||
continue;
|
||||
case T_MODOPADD:
|
||||
state = T_MODOPADD;
|
||||
ldmarr = ( LDAPMod ** )
|
||||
ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
|
||||
ldmarr[ nops ] = ldm = alloc_ldapmod();
|
||||
ldm->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||||
ldm->mod_type = value;
|
||||
nvals = 0;
|
||||
nops++;
|
||||
break;
|
||||
case T_MODOPREPLACE:
|
||||
state = T_MODOPREPLACE;
|
||||
ldmarr = ( LDAPMod ** )
|
||||
ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
|
||||
ldmarr[ nops ] = ldm = alloc_ldapmod();
|
||||
ldm->mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
|
||||
ldm->mod_type = value;
|
||||
nvals = 0;
|
||||
nops++;
|
||||
break;
|
||||
case T_MODOPDELETE:
|
||||
state = T_MODOPDELETE;
|
||||
ldmarr = ( LDAPMod ** )
|
||||
ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
|
||||
ldmarr[ nops ] = ldm = alloc_ldapmod();
|
||||
ldm->mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
|
||||
ldm->mod_type = value;
|
||||
nvals = 0;
|
||||
nops++;
|
||||
break;
|
||||
case T_MODOPINCREMENT:
|
||||
state = T_MODOPINCREMENT;
|
||||
ldmarr = ( LDAPMod ** )
|
||||
ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
|
||||
ldmarr[ nops ] = ldm = alloc_ldapmod();
|
||||
ldm->mod_op = LDAP_MOD_INCREMENT | LDAP_MOD_BVALUES;
|
||||
ldm->mod_type = value;
|
||||
nvals = 0;
|
||||
nops++;
|
||||
break;
|
||||
default:
|
||||
if ( state == AWAITING_OP ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_modify: unknown mod type \"%s\"\n",
|
||||
type, 0, 0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
assert( ldm != NULL );
|
||||
|
||||
/*
|
||||
* We should have an attribute: value pair here.
|
||||
* Construct the mod_bvalues part of the ldapmod struct.
|
||||
*/
|
||||
if ( strcasecmp( type, ldm->mod_type )) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: malformed modify op, %s: %s (expecting %s:)\n",
|
||||
type, value, ldm->mod_type );
|
||||
continue;
|
||||
}
|
||||
ldm->mod_bvalues = ( struct berval ** )
|
||||
ch_realloc( ldm->mod_bvalues,
|
||||
( nvals + 2 ) * sizeof( struct berval * ));
|
||||
ldm->mod_bvalues[ nvals + 1 ] = NULL;
|
||||
ldm->mod_bvalues[ nvals ] = ( struct berval * )
|
||||
ch_malloc( sizeof( struct berval ));
|
||||
ldm->mod_bvalues[ nvals ]->bv_val = value;
|
||||
ldm->mod_bvalues[ nvals ]->bv_len = len;
|
||||
nvals++;
|
||||
}
|
||||
}
|
||||
ldmarr[ nops ] = NULL;
|
||||
|
||||
if ( nops > 0 ) {
|
||||
/* Actually perform the LDAP operation */
|
||||
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
|
||||
ri->ri_hostname, ri->ri_port, re->re_dn );
|
||||
rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
|
||||
*errfree = 1;
|
||||
}
|
||||
free_ldmarr( ldmarr );
|
||||
return( rc );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform an ldap delete operation.
|
||||
*/
|
||||
static int
|
||||
op_ldap_delete(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
char **errmsg,
|
||||
int *errfree
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
|
||||
ri->ri_hostname, ri->ri_port, re->re_dn );
|
||||
rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
|
||||
*errfree = 1;
|
||||
|
||||
return( rc );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform an ldap modrdn operation.
|
||||
*/
|
||||
#define GOT_NEWRDN 0x1
|
||||
#define GOT_DELOLDRDN 0x2
|
||||
#define GOT_NEWSUP 0x4
|
||||
|
||||
#define GOT_MODDN_REQ (GOT_NEWRDN|GOT_DELOLDRDN)
|
||||
#define GOT_ALL_MODDN(f) (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ)
|
||||
static int
|
||||
op_ldap_modrdn(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
char **errmsg,
|
||||
int *errfree
|
||||
)
|
||||
{
|
||||
int rc = 0;
|
||||
Mi *mi;
|
||||
int i;
|
||||
int lderr = 0;
|
||||
int state = 0;
|
||||
int drdnflag = -1;
|
||||
char *newrdn = NULL;
|
||||
char *newsup = NULL;
|
||||
|
||||
if ( re->re_mods == NULL ) {
|
||||
*errmsg = "No arguments given";
|
||||
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
|
||||
0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the arguments: should see newrdn: and deleteoldrdn: args.
|
||||
*/
|
||||
for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
|
||||
if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
|
||||
if( state & GOT_NEWRDN ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
|
||||
mi[ i ].mi_val, 0, 0 );
|
||||
*errmsg = "Multiple newrdn argument";
|
||||
return -1;
|
||||
}
|
||||
|
||||
newrdn = mi[ i ].mi_val;
|
||||
state |= GOT_NEWRDN;
|
||||
|
||||
} else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
|
||||
if( state & GOT_DELOLDRDN ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
|
||||
mi[ i ].mi_val, 0, 0 );
|
||||
*errmsg = "Multiple newrdn argument";
|
||||
return -1;
|
||||
}
|
||||
|
||||
state |= GOT_DELOLDRDN;
|
||||
if ( !strcmp( mi[ i ].mi_val, "0" )) {
|
||||
drdnflag = 0;
|
||||
} else if ( !strcmp( mi[ i ].mi_val, "1" )) {
|
||||
drdnflag = 1;
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
|
||||
mi[ i ].mi_val, 0, 0 );
|
||||
*errmsg = "Incorrect argument to deleteoldrdn";
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
|
||||
if( state & GOT_NEWSUP ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
|
||||
mi[ i ].mi_val, 0, 0 );
|
||||
*errmsg = "Multiple newsuperior argument";
|
||||
return -1;
|
||||
}
|
||||
|
||||
newsup = mi[ i ].mi_val;
|
||||
state |= GOT_NEWSUP;
|
||||
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
|
||||
mi[ i ].mi_type, 0, 0 );
|
||||
*errmsg = "Bad value in replication log entry";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Punt if we don't have all the args.
|
||||
*/
|
||||
if ( !GOT_ALL_MODDN(state) ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
|
||||
0, 0, 0 );
|
||||
*errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LDAP_DEBUG
|
||||
if ( ldap_debug & LDAP_DEBUG_ARGS ) {
|
||||
char buf[ 256 ];
|
||||
char *buf2;
|
||||
int buf2len = strlen( re->re_dn ) + strlen( mi->mi_val ) + 11;
|
||||
|
||||
snprintf( buf, sizeof(buf), "%s:%d", ri->ri_hostname, ri->ri_port );
|
||||
|
||||
buf2 = (char *) ch_malloc( buf2len );
|
||||
snprintf( buf2, buf2len, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"replica %s - modify rdn %s (flag: %d)\n",
|
||||
buf, buf2, drdnflag );
|
||||
free( buf2 );
|
||||
}
|
||||
#endif /* LDAP_DEBUG */
|
||||
|
||||
assert( newrdn != NULL );
|
||||
|
||||
/* Do the modrdn */
|
||||
rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag );
|
||||
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_RESULT_CODE, &lderr);
|
||||
ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
|
||||
*errfree = 1;
|
||||
return( lderr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialize an ldapmod struct.
|
||||
*/
|
||||
static LDAPMod *
|
||||
alloc_ldapmod( void )
|
||||
{
|
||||
LDAPMod *ldm;
|
||||
|
||||
ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
|
||||
ldm->mod_type = NULL;
|
||||
ldm->mod_bvalues = ( struct berval ** ) NULL;
|
||||
return( ldm );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Free an ldapmod struct associated mod_bvalues. NOTE - it is assumed
|
||||
* that mod_bvalues and mod_type contain pointers to the same block of memory
|
||||
* pointed to by the repl struct. Therefore, it's not freed here.
|
||||
*/
|
||||
static void
|
||||
free_ldapmod(
|
||||
LDAPMod *ldm )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( ldm == NULL ) {
|
||||
return;
|
||||
}
|
||||
if ( ldm->mod_bvalues != NULL ) {
|
||||
for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
|
||||
free( ldm->mod_bvalues[ i ] );
|
||||
}
|
||||
free( ldm->mod_bvalues );
|
||||
}
|
||||
free( ldm );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free an an array of LDAPMod pointers and the LDAPMod structs they point
|
||||
* to.
|
||||
*/
|
||||
static void
|
||||
free_ldmarr(
|
||||
LDAPMod **ldmarr )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
|
||||
free_ldapmod( ldmarr[ i ] );
|
||||
}
|
||||
free( ldmarr );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a berval with a single value.
|
||||
*/
|
||||
static struct berval **
|
||||
make_singlevalued_berval(
|
||||
char *value,
|
||||
int len )
|
||||
{
|
||||
struct berval **p;
|
||||
|
||||
p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
|
||||
p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
|
||||
p[ 1 ] = NULL;
|
||||
p[ 0 ]->bv_val = value;
|
||||
p[ 0 ]->bv_len = len;
|
||||
return( p );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a modification type (string), return an enumerated type.
|
||||
* Avoids ugly copy in op_ldap_modify - lets us use a switch statement
|
||||
* there.
|
||||
*/
|
||||
static int
|
||||
getmodtype(
|
||||
char *type )
|
||||
{
|
||||
if ( !strcmp( type, T_MODSEPSTR )) {
|
||||
return( T_MODSEP );
|
||||
}
|
||||
if ( !strcmp( type, T_MODOPADDSTR )) {
|
||||
return( T_MODOPADD );
|
||||
}
|
||||
if ( !strcmp( type, T_MODOPREPLACESTR )) {
|
||||
return( T_MODOPREPLACE );
|
||||
}
|
||||
if ( !strcmp( type, T_MODOPDELETESTR )) {
|
||||
return( T_MODOPDELETE );
|
||||
}
|
||||
if ( !strcmp( type, T_MODOPINCREMENTSTR )) {
|
||||
return( T_MODOPINCREMENT );
|
||||
}
|
||||
return( T_ERR );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Perform an LDAP unbind operation. If replica is NULL, or the
|
||||
* repl_ldp is NULL, just return LDAP_SUCCESS. Otherwise, unbind,
|
||||
* set the ldp to NULL, and return the result of the unbind call.
|
||||
*/
|
||||
static int
|
||||
do_unbind(
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
|
||||
rc = ldap_unbind( ri->ri_ldp );
|
||||
if ( rc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
|
||||
ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
|
||||
}
|
||||
ri->ri_ldp = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform an LDAP bind operation to the replication site given
|
||||
* by replica. If replica->repl_ldp is non-NULL, then we unbind
|
||||
* from the replica before rebinding. It should be safe to call
|
||||
* this to re-connect if the replica's connection goes away
|
||||
* for some reason.
|
||||
*
|
||||
* Returns 0 on success, -1 if an LDAP error occurred, and a return
|
||||
* code > 0 if some other error occurred, e.g. invalid bind method.
|
||||
* If an LDAP error occurs, the LDAP error is returned in lderr.
|
||||
*/
|
||||
static int
|
||||
do_bind(
|
||||
Ri *ri,
|
||||
int *lderr
|
||||
)
|
||||
{
|
||||
int ldrc;
|
||||
int do_tls;
|
||||
|
||||
*lderr = 0;
|
||||
|
||||
if ( ri == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
|
||||
return( BIND_ERR_BADRI );
|
||||
}
|
||||
|
||||
do_tls = ri->ri_tls;
|
||||
|
||||
retry:
|
||||
if ( ri->ri_ldp != NULL ) {
|
||||
ldrc = ldap_unbind( ri->ri_ldp );
|
||||
if ( ldrc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: do_bind: ldap_unbind failed: %s\n",
|
||||
ldap_err2string( ldrc ), 0, 0 );
|
||||
}
|
||||
ri->ri_ldp = NULL;
|
||||
}
|
||||
|
||||
if ( ri->ri_uri != NULL ) { /* new URI style */
|
||||
Debug( LDAP_DEBUG_ARGS, "Initializing session to %s\n",
|
||||
ri->ri_uri, 0, 0 );
|
||||
|
||||
ldrc = ldap_initialize( &(ri->ri_ldp), ri->ri_uri);
|
||||
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: ldap_initialize(0, %s) failed: %s\n",
|
||||
ri->ri_uri, ldap_err2string(ldrc), 0 );
|
||||
return( BIND_ERR_OPEN );
|
||||
}
|
||||
} else { /* old HOST style */
|
||||
Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
|
||||
ri->ri_hostname, ri->ri_port, 0 );
|
||||
|
||||
ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
|
||||
if ( ri->ri_ldp == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
|
||||
ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
|
||||
return( BIND_ERR_OPEN );
|
||||
}
|
||||
}
|
||||
|
||||
{ /* set version 3 */
|
||||
int err, version = LDAP_VERSION3;
|
||||
err = ldap_set_option(ri->ri_ldp,
|
||||
LDAP_OPT_PROTOCOL_VERSION, &version);
|
||||
|
||||
if( err != LDAP_OPT_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
|
||||
ri->ri_hostname, NULL, NULL );
|
||||
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return BIND_ERR_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set ldap library options to (1) not follow referrals, and
|
||||
* (2) restart the select() system call.
|
||||
*/
|
||||
{
|
||||
int err;
|
||||
err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
|
||||
|
||||
if( err != LDAP_OPT_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
|
||||
ri->ri_hostname, NULL, NULL );
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return BIND_ERR_REFERRALS;
|
||||
}
|
||||
}
|
||||
ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
|
||||
|
||||
if( do_tls ) {
|
||||
int err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
|
||||
|
||||
if( err != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: ldap_start_tls failed: %s (%d)\n",
|
||||
ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
|
||||
ldap_err2string( err ), err );
|
||||
|
||||
if( ri->ri_tls == TLS_CRITICAL ) {
|
||||
*lderr = err;
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return BIND_ERR_TLS_FAILED;
|
||||
}
|
||||
do_tls = TLS_OFF;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( ri->ri_bind_method ) {
|
||||
case LDAP_AUTH_SIMPLE:
|
||||
/*
|
||||
* Bind with a plaintext password.
|
||||
*/
|
||||
Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
|
||||
ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
|
||||
ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
|
||||
ri->ri_password );
|
||||
if ( ldrc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_simple_bind_s for %s:%d failed: %s\n",
|
||||
ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
|
||||
*lderr = ldrc;
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return( BIND_ERR_SIMPLE_FAILED );
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_AUTH_SASL:
|
||||
Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
|
||||
ri->ri_hostname,
|
||||
ri->ri_authcId ? ri->ri_authcId : "-",
|
||||
ri->ri_saslmech );
|
||||
|
||||
#ifdef HAVE_CYRUS_SASL
|
||||
if( ri->ri_secprops != NULL ) {
|
||||
int err = ldap_set_option(ri->ri_ldp,
|
||||
LDAP_OPT_X_SASL_SECPROPS, ri->ri_secprops);
|
||||
|
||||
if( err != LDAP_OPT_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
|
||||
ri->ri_hostname, ri->ri_secprops, NULL );
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return BIND_ERR_SASL_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
|
||||
ri->ri_realm, ri->ri_authcId, ri->ri_password, ri->ri_authzId );
|
||||
|
||||
ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
|
||||
ri->ri_saslmech, NULL, NULL,
|
||||
LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
|
||||
|
||||
lutil_sasl_freedefs( defaults );
|
||||
if ( ldrc != LDAP_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
|
||||
ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
|
||||
*lderr = ldrc;
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return( BIND_ERR_SASL_FAILED );
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: do_bind: SASL not supported %s:%d\n",
|
||||
ri->ri_hostname, ri->ri_port, NULL );
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return( BIND_ERR_BAD_ATYPE );
|
||||
#endif
|
||||
|
||||
default:
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
|
||||
ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return( BIND_ERR_BAD_ATYPE );
|
||||
}
|
||||
|
||||
{
|
||||
int err;
|
||||
LDAPControl c;
|
||||
LDAPControl *ctrls[2];
|
||||
ctrls[0] = &c;
|
||||
ctrls[1] = NULL;
|
||||
|
||||
c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
|
||||
c.ldctl_value.bv_val = NULL;
|
||||
c.ldctl_value.bv_len = 0;
|
||||
c.ldctl_iscritical = 0;
|
||||
|
||||
err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
|
||||
|
||||
if( err != LDAP_OPT_SUCCESS ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: "
|
||||
"ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
|
||||
ri->ri_hostname, NULL, NULL );
|
||||
ldap_unbind( ri->ri_ldp );
|
||||
ri->ri_ldp = NULL;
|
||||
return BIND_ERR_MANAGEDSAIT;
|
||||
}
|
||||
}
|
||||
|
||||
return( BIND_OK );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* For debugging. Print the contents of an ldmarr array.
|
||||
*/
|
||||
#ifdef SLAPD_UNUSED
|
||||
static void
|
||||
dump_ldm_array(
|
||||
LDAPMod **ldmarr
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
LDAPMod *ldm;
|
||||
struct berval *b;
|
||||
char *msgbuf;
|
||||
|
||||
for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
|
||||
ldm = ldmarr[ i ];
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Trace (%ld): *** ldmarr[ %d ] contents:\n",
|
||||
(long) getpid(), i, 0 );
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Trace (%ld): *** ldm->mod_op: %d\n",
|
||||
(long) getpid(), ldm->mod_op, 0 );
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Trace (%ld): *** ldm->mod_type: %s\n",
|
||||
(long) getpid(), ldm->mod_type, 0 );
|
||||
if ( ldm->mod_bvalues != NULL ) {
|
||||
for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
|
||||
msgbuf = ch_malloc( b->bv_len + 512 );
|
||||
sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
|
||||
j, b->bv_len, b->bv_val );
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
|
||||
free( msgbuf );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* lock.c - routines to open and apply an advisory lock to a file
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/param.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/socket.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#include "slurp.h"
|
||||
|
||||
|
||||
FILE *
|
||||
lock_fopen(
|
||||
const char *fname,
|
||||
const char *type,
|
||||
FILE **lfp
|
||||
)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[MAXPATHLEN];
|
||||
|
||||
/* open the lock file */
|
||||
snprintf( buf, sizeof buf, "%s.lock", fname );
|
||||
|
||||
if ( (*lfp = fopen( buf, "w" )) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: could not open \"%s\"\n", buf, 0, 0 );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* acquire the lock */
|
||||
ldap_lockf( fileno(*lfp) );
|
||||
|
||||
/* open the log file */
|
||||
if ( (fp = fopen( fname, type )) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: could not open \"%s\"\n", fname, 0, 0 );
|
||||
ldap_unlockf( fileno(*lfp) );
|
||||
fclose( *lfp );
|
||||
*lfp = NULL;
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( fp );
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
lock_fclose(
|
||||
FILE *fp,
|
||||
FILE *lfp
|
||||
)
|
||||
{
|
||||
int rc = fclose( fp );
|
||||
|
||||
/* unlock */
|
||||
ldap_unlockf( fileno(lfp) );
|
||||
fclose( lfp );
|
||||
|
||||
return( rc );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Apply an advisory lock on a file. Just calls lock_fopen()
|
||||
*/
|
||||
int
|
||||
acquire_lock(
|
||||
const char *file,
|
||||
FILE **rfp,
|
||||
FILE **lfp
|
||||
)
|
||||
{
|
||||
if (( *rfp = lock_fopen( file, "r+", lfp )) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: acquire_lock(%ld): Could not acquire lock on \"%s\"\n",
|
||||
(long) getpid(), file, 0);
|
||||
return( -1 );
|
||||
}
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Relinquish a lock on a file. Calls lock_fclose() and also removes the
|
||||
* lock file.
|
||||
*/
|
||||
int
|
||||
relinquish_lock(
|
||||
const char *file,
|
||||
FILE *rfp,
|
||||
FILE *lfp
|
||||
)
|
||||
{
|
||||
if ( lock_fclose( rfp, lfp ) == EOF ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: relinquish_lock (%ld): Error closing \"%s\"\n",
|
||||
(long) getpid(), file, 0 );
|
||||
return( -1 );
|
||||
}
|
||||
return( 0 );
|
||||
}
|
||||
|
|
@ -1,355 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP). Additional significant contributors
|
||||
* include:
|
||||
* Howard Chu
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* main.c - main routine for slurpd.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
#include "lutil.h"
|
||||
|
||||
#include <ldap_pvt.h>
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
#define MAIN_RETURN(x) return
|
||||
#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
|
||||
|
||||
#ifndef HAVE_MKVERSION
|
||||
const char Versionstr[] =
|
||||
OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Replicator (slurpd)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
|
||||
#else
|
||||
int main( int argc, char **argv )
|
||||
#endif
|
||||
{
|
||||
#ifdef NO_THREADS
|
||||
/* Haven't yet written the non-threaded version */
|
||||
fputs( "slurpd currently requires threads support\n", stderr );
|
||||
return( 1 );
|
||||
#else
|
||||
|
||||
int i, rc = 0;
|
||||
|
||||
/* initialize thread package */
|
||||
ldap_pvt_thread_initialize();
|
||||
|
||||
/*
|
||||
* Create and initialize globals. init_globals() also initializes
|
||||
* the main replication queue.
|
||||
*/
|
||||
if (( sglob = init_globals()) == NULL ) {
|
||||
fprintf( stderr, "Out of memory initializing globals\n" );
|
||||
SERVICE_EXIT( ERROR_NOT_ENOUGH_MEMORY, 0 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
{
|
||||
int *i;
|
||||
char *newConfigFile;
|
||||
char *regService = NULL;
|
||||
|
||||
if ( is_NT_Service ) {
|
||||
sglob->serverName = argv[0];
|
||||
lutil_CommenceStartupProcessing( sglob->serverName, slurp_set_shutdown );
|
||||
if ( strcmp(sglob->serverName, SERVICE_NAME) )
|
||||
regService = sglob->serverName;
|
||||
}
|
||||
|
||||
i = (int*)lutil_getRegParam( regService, "DebugLevel" );
|
||||
if ( i != NULL )
|
||||
{
|
||||
ldap_debug = *i;
|
||||
Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", ldap_debug, 0, 0 );
|
||||
}
|
||||
|
||||
newConfigFile = (char*)lutil_getRegParam( regService, "ConfigFile" );
|
||||
if ( newConfigFile != NULL )
|
||||
{
|
||||
sglob->slapd_configfile = newConfigFile;
|
||||
Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", sglob->slapd_configfile, 0, 0 );
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Process command-line args and fill in globals.
|
||||
*/
|
||||
if ( doargs( argc, argv, sglob ) < 0 ) {
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
if ( sglob->version ) {
|
||||
fprintf(stderr, "%s\n", Versionstr);
|
||||
if (sglob->version > 1 ) {
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
}
|
||||
|
||||
Debug ( LDAP_DEBUG_ANY, "%s\n", Versionstr, 0, 0 );
|
||||
|
||||
/*
|
||||
* Read slapd config file and initialize Re (per-replica) structs.
|
||||
*/
|
||||
if ( slurpd_read_config( sglob->slapd_configfile ) < 0 ) {
|
||||
fprintf( stderr,
|
||||
"Errors encountered while processing config file \"%s\"\n",
|
||||
sglob->slapd_configfile );
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TLS
|
||||
if( ldap_pvt_tls_init() || ldap_pvt_tls_init_def_ctx( 0 ) ) {
|
||||
rc = 0;
|
||||
/* See if we actually need TLS */
|
||||
for ( i=0; i < sglob->num_replicas; i++ ) {
|
||||
if ( sglob->replicas[i]->ri_tls || ( sglob->replicas[i]->ri_uri &&
|
||||
!strncmp( sglob->replicas[i]->ri_uri, "ldaps:", 6 ))) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( rc ) {
|
||||
fprintf( stderr, "TLS Initialization failed.\n" );
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
|
||||
goto stop;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure our directory exists
|
||||
*/
|
||||
if ( mkdir(sglob->slurpd_rdir, 0755) == -1 && errno != EEXIST) {
|
||||
perror(sglob->slurpd_rdir);
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get any saved state information off the disk.
|
||||
*/
|
||||
if ( sglob->st->st_read( sglob->st )) {
|
||||
fprintf( stderr, "Malformed slurpd status file \"%s\"\n",
|
||||
sglob->slurpd_status_file );
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 17 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
/*
|
||||
* All readonly data should now be initialized.
|
||||
* Check for any fatal error conditions before we get started
|
||||
*/
|
||||
if ( sanity() < 0 ) {
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Detach from the controlling terminal
|
||||
* unless the -d flag is given or in one-shot mode.
|
||||
*/
|
||||
#ifndef HAVE_WINSOCK
|
||||
if ( ! (sglob->no_detach || sglob->one_shot_mode) ) {
|
||||
lutil_detach( 0, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* don't open pid/args file in one-shot mode (ITS#4152)
|
||||
*
|
||||
* bail out if files were specified but cannot be opened (ITS#4074)
|
||||
*/
|
||||
if ( !sglob->one_shot_mode) {
|
||||
if ( slurpd_pid_file != NULL ) {
|
||||
FILE *fp = fopen( slurpd_pid_file, "w" );
|
||||
|
||||
if ( fp == NULL ) {
|
||||
int save_errno = errno;
|
||||
|
||||
fprintf( stderr, "unable to open pid file "
|
||||
"\"%s\": %d (%s)\n",
|
||||
slurpd_pid_file,
|
||||
save_errno, strerror( save_errno ) );
|
||||
|
||||
free( slurpd_pid_file );
|
||||
slurpd_pid_file = NULL;
|
||||
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
fprintf( fp, "%d\n", (int) getpid() );
|
||||
fclose( fp );
|
||||
}
|
||||
|
||||
if ( slurpd_args_file != NULL ) {
|
||||
FILE *fp = fopen( slurpd_args_file, "w" );
|
||||
|
||||
if ( fp == NULL ) {
|
||||
int save_errno = errno;
|
||||
|
||||
fprintf( stderr, "unable to open args file "
|
||||
"\"%s\": %d (%s)\n",
|
||||
slurpd_args_file,
|
||||
save_errno, strerror( save_errno ) );
|
||||
|
||||
free( slurpd_args_file );
|
||||
slurpd_pid_file = NULL;
|
||||
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
for ( i = 0; i < argc; i++ ) {
|
||||
fprintf( fp, "%s ", argv[i] );
|
||||
}
|
||||
fprintf( fp, "\n" );
|
||||
fclose( fp );
|
||||
}
|
||||
}
|
||||
|
||||
if ( (rc = lutil_pair( sglob->wake_sds )) < 0 ) {
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NT_EVENT_LOG
|
||||
if (is_NT_Service) lutil_LogStartedEvent( sglob->serverName, ldap_debug, sglob->slapd_configfile, "n/a" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start the main file manager thread (in fm.c).
|
||||
*/
|
||||
if ( ldap_pvt_thread_create( &(sglob->fm_tid),
|
||||
0, fm, (void *) NULL ) != 0 )
|
||||
{
|
||||
Debug( LDAP_DEBUG_ANY, "file manager ldap_pvt_thread_create failed\n",
|
||||
0, 0, 0 );
|
||||
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
|
||||
rc = 1;
|
||||
goto stop;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for fm to finish if in oneshot mode
|
||||
*/
|
||||
if ( sglob->one_shot_mode ) {
|
||||
ldap_pvt_thread_join( sglob->fm_tid, (void *) NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
* Start threads - one thread for each replica
|
||||
*/
|
||||
for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) {
|
||||
start_replica_thread( sglob->replicas[ i ]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
if ( started_event ) ldap_pvt_thread_cond_signal( &started_event );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wait for the fm thread to finish.
|
||||
*/
|
||||
if ( !sglob->one_shot_mode ) {
|
||||
ldap_pvt_thread_join( sglob->fm_tid, (void *) NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the replica threads to finish.
|
||||
*/
|
||||
for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) {
|
||||
ldap_pvt_thread_join( sglob->replicas[ i ]->ri_tid, (void *) NULL );
|
||||
}
|
||||
|
||||
stop:
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
if (is_NT_Service) {
|
||||
ldap_pvt_thread_cond_destroy( &started_event );
|
||||
lutil_LogStoppedEvent( sglob->serverName );
|
||||
lutil_ReportShutdownComplete();
|
||||
}
|
||||
#endif
|
||||
/* destroy the thread package */
|
||||
ldap_pvt_thread_destroy();
|
||||
|
||||
#ifdef HAVE_TLS
|
||||
ldap_pvt_tls_destroy();
|
||||
#endif
|
||||
|
||||
Debug( LDAP_DEBUG_ANY, "slurpd: terminated.\n", 0, 0, 0 );
|
||||
|
||||
if ( slurpd_pid_file != NULL ) {
|
||||
unlink( slurpd_pid_file );
|
||||
}
|
||||
if ( slurpd_args_file != NULL ) {
|
||||
unlink( slurpd_args_file );
|
||||
}
|
||||
|
||||
|
||||
MAIN_RETURN(rc);
|
||||
#endif /* !NO_THREADS */
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
#include <stdio.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/stdlib.h>
|
||||
#include "slurp.h"
|
||||
#include "lutil.h"
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
|
||||
/* in main.c */
|
||||
void WINAPI ServiceMain( DWORD argc, LPTSTR *argv );
|
||||
|
||||
int main( int argc, LPTSTR *argv )
|
||||
{
|
||||
int length;
|
||||
char filename[MAX_PATH], *fname_start;
|
||||
|
||||
/*
|
||||
* Because the service was registered as SERVICE_WIN32_OWN_PROCESS,
|
||||
* the lpServiceName element of the SERVICE_TABLE_ENTRY will be
|
||||
* ignored.
|
||||
*/
|
||||
|
||||
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
||||
{ "", (LPSERVICE_MAIN_FUNCTION) ServiceMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* set the service's current directory to the installation directory
|
||||
* for the service. this way we don't have to write absolute paths
|
||||
* in the configuration files
|
||||
*/
|
||||
GetModuleFileName( NULL, filename, sizeof( filename ) );
|
||||
fname_start = strrchr( filename, *LDAP_DIRSEP );
|
||||
|
||||
if ( argc > 1 ) {
|
||||
if ( _stricmp( "install", argv[1] ) == 0 )
|
||||
{
|
||||
char *svcName = SERVICE_NAME;
|
||||
char *displayName = "OpenLDAP Replication Service";
|
||||
BOOL auto_start = FALSE;
|
||||
|
||||
if ( (argc > 2) && (argv[2] != NULL) )
|
||||
svcName = argv[2];
|
||||
|
||||
if ( argc > 3 && argv[3])
|
||||
displayName = argv[3];
|
||||
|
||||
if ( argc > 4 && stricmp(argv[4], "auto") == 0)
|
||||
auto_start = TRUE;
|
||||
|
||||
strcat(filename, " service");
|
||||
if ( !lutil_srv_install(svcName, displayName, filename, auto_start) )
|
||||
{
|
||||
fputs( "service failed installation ...\n", stderr );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fputs( "service has been installed ...\n", stderr );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( _stricmp( "remove", argv[1] ) == 0 )
|
||||
{
|
||||
char *svcName = SERVICE_NAME;
|
||||
if ( (argc > 2) && (argv[2] != NULL) )
|
||||
svcName = argv[2];
|
||||
if ( !lutil_srv_remove(svcName, filename) )
|
||||
{
|
||||
fputs( "failed to remove the service ...\n", stderr );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fputs( "service has been removed ...\n", stderr );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if ( _stricmp( "service", argv[1] ) == 0 )
|
||||
{
|
||||
is_NT_Service = 1;
|
||||
*fname_start = '\0';
|
||||
SetCurrentDirectory( filename );
|
||||
}
|
||||
}
|
||||
|
||||
if (is_NT_Service)
|
||||
{
|
||||
StartServiceCtrlDispatcher(DispatchTable);
|
||||
} else
|
||||
{
|
||||
ServiceMain( argc, argv );
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_SLURP
|
||||
#define _PROTO_SLURP
|
||||
|
||||
#include <ldap_cdefs.h>
|
||||
|
||||
struct globals;
|
||||
|
||||
/* admin.c */
|
||||
RETSIGTYPE do_admin LDAP_P((int sig));
|
||||
|
||||
/* args.c */
|
||||
int doargs LDAP_P((int argc, char **argv, struct globals *g));
|
||||
|
||||
/* ch_malloc.c */
|
||||
#ifdef CSRIMALLOC
|
||||
#define ch_malloc malloc
|
||||
#define ch_realloc realloc
|
||||
#define ch_calloc calloc
|
||||
#define ch_strdup strdup
|
||||
#define ch_free free
|
||||
#else
|
||||
void *ch_malloc LDAP_P((ber_len_t size));
|
||||
void *ch_realloc LDAP_P((void *block, ber_len_t size));
|
||||
void *ch_calloc LDAP_P((ber_len_t nelem, ber_len_t size));
|
||||
char *ch_strdup LDAP_P((const char *str));
|
||||
void ch_free LDAP_P((void *p));
|
||||
#endif
|
||||
|
||||
/* config.c */
|
||||
int slurpd_read_config LDAP_P((char *fname));
|
||||
|
||||
extern char *slurpd_pid_file;
|
||||
extern char *slurpd_args_file;
|
||||
|
||||
/* ch_malloc.c */
|
||||
void ch_free LDAP_P(( void *p ));
|
||||
|
||||
/* fm.c */
|
||||
void *fm LDAP_P((void *arg));
|
||||
RETSIGTYPE do_nothing LDAP_P((int i));
|
||||
RETSIGTYPE slurp_set_shutdown LDAP_P((int));
|
||||
|
||||
/* globals.c */
|
||||
extern struct globals *sglob;
|
||||
extern int ldap_syslog;
|
||||
extern int ldap_syslog_level;
|
||||
extern int ldap_debug;
|
||||
extern struct globals *init_globals LDAP_P((void));
|
||||
|
||||
/* ldap_op.c */
|
||||
int do_ldap LDAP_P((Ri *ri, Re *re, char **errmsg, int *errfree));
|
||||
|
||||
/* lock.c */
|
||||
FILE *lock_fopen LDAP_P((const char *fname, const char *type, FILE **lfp));
|
||||
int lock_fclose LDAP_P((FILE *fp, FILE *lfp));
|
||||
int acquire_lock LDAP_P((const char *file, FILE **rfp, FILE **lfp));
|
||||
int relinquish_lock LDAP_P((const char *file, FILE *rfp, FILE *lfp));
|
||||
|
||||
/* reject.c */
|
||||
void write_reject LDAP_P((Ri *ri, Re *re, int lderr, char *errmsg));
|
||||
|
||||
/* replica.c */
|
||||
int start_replica_thread LDAP_P((Ri *ri));
|
||||
|
||||
/* replog.c */
|
||||
int copy_replog LDAP_P((char *src, char *dst));
|
||||
int file_nonempty LDAP_P((char *filename));
|
||||
|
||||
/* sanity.c */
|
||||
int sanity LDAP_P((void));
|
||||
|
||||
/* st.c */
|
||||
int St_init LDAP_P((St **st));
|
||||
|
||||
/* tsleep.c */
|
||||
int tsleep LDAP_P((time_t interval));
|
||||
#if defined( HAVE_LWP )
|
||||
void start_lwp_scheduler LDAP_P(( void ));
|
||||
#endif
|
||||
|
||||
/*main.c */
|
||||
extern const char Versionstr[];
|
||||
|
||||
#endif /* _PROTO_SLURP */
|
||||
|
|
@ -1,793 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* re.c - routines which deal with Re (Replication entry) structures.
|
||||
* An Re struct is an in-core representation of one replication to
|
||||
* be performed, along with member functions which are called by other
|
||||
* routines. The Re struct is defined in slurp.h.
|
||||
*/
|
||||
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/errno.h>
|
||||
#include <ac/socket.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/ctype.h>
|
||||
|
||||
#include "../slapd/slap.h"
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
#include "lutil.h"
|
||||
|
||||
/* Forward references */
|
||||
static Rh *get_repl_hosts LDAP_P(( char *, int *, char ** ));
|
||||
static int gettype LDAP_P(( char * ));
|
||||
static int getchangetype LDAP_P(( char * ));
|
||||
static int Re_parse LDAP_P(( Re *re, char *replbuf ));
|
||||
static void Re_dump LDAP_P(( Re *re, FILE *fp ));
|
||||
static void warn_unknown_replica LDAP_P(( char *, int port ));
|
||||
|
||||
/* Globals, scoped within this file */
|
||||
static int nur = 0; /* Number of unknown replicas */
|
||||
static Rh *ur = NULL; /* array of unknown replica names */
|
||||
|
||||
|
||||
/*
|
||||
* Return the next Re in a linked list.
|
||||
*/
|
||||
static Re *
|
||||
Re_getnext(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
return(( re == NULL ) ? NULL : re->re_next );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Free an Re
|
||||
* ??? Something should apparently return nonzero here, but I dont know what.
|
||||
*/
|
||||
static int
|
||||
Re_free(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
Rh *rh;
|
||||
Mi *mi;
|
||||
int i;
|
||||
|
||||
if ( re == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
if ( re->re_refcnt > 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Warning: freeing re (dn: %s) with nonzero refcnt\n",
|
||||
re->re_dn, 0, 0 );
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_destroy( &re->re_mutex );
|
||||
|
||||
if (( rh = re->re_replicas ) != NULL ) {
|
||||
for ( i = 0; rh[ i ].rh_hostname != NULL; i++ ) {
|
||||
free( rh[ i ].rh_hostname );
|
||||
}
|
||||
free( rh );
|
||||
}
|
||||
ch_free( re->re_dn );
|
||||
if (( mi = re->re_mods ) != NULL ) {
|
||||
for ( i = 0; mi[ i ].mi_type != NULL; i++ ) {
|
||||
free( mi[ i ].mi_type );
|
||||
ch_free( mi[ i ].mi_val );
|
||||
}
|
||||
free( mi );
|
||||
}
|
||||
free( re );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read a buffer of data from a replication log file and fill in
|
||||
* an (already allocated) Re.
|
||||
*/
|
||||
|
||||
#define BEGIN 0
|
||||
#define GOT_DN 1
|
||||
#define GOT_TIME 2
|
||||
#define GOT_CHANGETYPE 4
|
||||
#define GOT_ALL ( GOT_DN | GOT_TIME | GOT_CHANGETYPE )
|
||||
|
||||
static int
|
||||
Re_parse(
|
||||
Re *re,
|
||||
char *replbuf
|
||||
)
|
||||
{
|
||||
int state;
|
||||
int nml;
|
||||
char *buf, *rp, *p;
|
||||
size_t buflen;
|
||||
char *type, *value;
|
||||
ber_len_t len;
|
||||
int nreplicas;
|
||||
|
||||
if ( re == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Re_parse: error: re is NULL\n", 0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
if ( replbuf == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Re_parse: error: replbuf is NULL\n", 0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
state = BEGIN;
|
||||
nml = 0; /* number of modification information entries */
|
||||
rp = replbuf;
|
||||
|
||||
re->re_replicas = get_repl_hosts( replbuf, &nreplicas, &rp );
|
||||
re->re_refcnt = sglob->num_replicas;
|
||||
|
||||
for (;;) {
|
||||
if (( state == GOT_ALL ) || ( buf = ldif_getline( &rp )) == NULL ) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If we're processing a rejection log, then the first line
|
||||
* of each replication record will begin with "ERROR" - just
|
||||
* ignore it.
|
||||
*/
|
||||
if ( strncmp( buf, ERROR_STR, strlen( ERROR_STR )) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
buflen = strlen( buf );
|
||||
if ( ldif_parse_line( buf, &type, &value, &len ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: Re_parse: malformed replog file\n",
|
||||
0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
switch ( gettype( type )) {
|
||||
case T_CHANGETYPE:
|
||||
re->re_changetype = getchangetype( value );
|
||||
state |= GOT_CHANGETYPE;
|
||||
break;
|
||||
case T_TIME: {
|
||||
unsigned long t;
|
||||
|
||||
if (( p = strchr( value, '.' )) != NULL ) {
|
||||
/* there was a sequence number */
|
||||
*p++ = '\0';
|
||||
}
|
||||
if ( lutil_atoul( &t, value ) != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: Re_parse: unable to parse timestamp \"%s\"\n",
|
||||
value, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
re->re_timestamp = (time_t)t;
|
||||
if ( p != NULL && isdigit( (unsigned char) *p )
|
||||
&& lutil_atoi( &re->re_seq, p ) != 0 )
|
||||
{
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: Re_parse: unable to parse sequence number \"%s\"\n",
|
||||
p, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
state |= GOT_TIME;
|
||||
} break;
|
||||
case T_DN:
|
||||
re->re_dn = ch_malloc( len + 1 );
|
||||
AC_MEMCPY( re->re_dn, value, len );
|
||||
re->re_dn[ len ]='\0';
|
||||
state |= GOT_DN;
|
||||
break;
|
||||
default:
|
||||
if ( !( state == GOT_ALL )) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: Re_parse: bad type <%s>\n",
|
||||
type, 0, 0 );
|
||||
free( type );
|
||||
free( value );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free( type );
|
||||
free( value );
|
||||
}
|
||||
|
||||
if ( state != GOT_ALL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: Re_parse: malformed replog file\n",
|
||||
0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
char *const dash = "-";
|
||||
|
||||
if (( buf = ldif_getline( &rp )) == NULL ) {
|
||||
break;
|
||||
}
|
||||
buflen = strlen( buf );
|
||||
if (( buflen == 1 ) && ( buf[ 0 ] == '-' )) {
|
||||
type = dash;
|
||||
value = NULL;
|
||||
} else {
|
||||
if ( ldif_parse_line( buf, &type, &value, &len ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: malformed replog line \"%s\"\n",
|
||||
buf, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
re->re_mods = ( Mi *) ch_realloc( (char *) re->re_mods,
|
||||
sizeof( Mi ) * ( nml + 2 ));
|
||||
re->re_mods[ nml ].mi_type = strdup( type );
|
||||
if ( value != NULL ) {
|
||||
re->re_mods[ nml ].mi_val = ch_malloc( len + 1 );
|
||||
AC_MEMCPY( re->re_mods[ nml ].mi_val, value, len );
|
||||
re->re_mods[ nml ].mi_val[ len ] = '\0';
|
||||
re->re_mods[ nml ].mi_len = len;
|
||||
} else {
|
||||
re->re_mods[ nml ].mi_val = NULL;
|
||||
re->re_mods[ nml ].mi_len = 0;
|
||||
}
|
||||
re->re_mods[ nml + 1 ].mi_type = NULL;
|
||||
re->re_mods[ nml + 1 ].mi_val = NULL;
|
||||
nml++;
|
||||
|
||||
if ( type != dash )
|
||||
free( type );
|
||||
if ( value != NULL )
|
||||
free( value );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Extract the replication hosts from a repl buf. Check to be sure that
|
||||
* each replica host and port number are ones we know about (that is, they're
|
||||
* in the slapd config file we read at startup). Without that information
|
||||
* from the config file, we won't have the appropriate credentials to
|
||||
* make modifications. If there are any unknown replica names, don't
|
||||
* add them the the Re struct. Instead, log a warning message.
|
||||
*/
|
||||
static Rh *
|
||||
get_repl_hosts(
|
||||
char *replbuf,
|
||||
int *r_nreplicas,
|
||||
char **r_rp
|
||||
)
|
||||
{
|
||||
char *type, *value, *line, *p;
|
||||
Rh *rh = NULL;
|
||||
int nreplicas;
|
||||
ber_len_t len;
|
||||
int port;
|
||||
int repl_ok;
|
||||
int i;
|
||||
|
||||
if ( replbuf == NULL ) {
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
nreplicas = 0;
|
||||
|
||||
/*
|
||||
* Get the host names of the replicas
|
||||
*/
|
||||
*r_nreplicas = 0;
|
||||
*r_rp = replbuf;
|
||||
for (;;) {
|
||||
/* If this is a reject log, we need to skip over the ERROR: line */
|
||||
if ( !strncmp( *r_rp, ERROR_STR, strlen( ERROR_STR ))) {
|
||||
line = ldif_getline( r_rp );
|
||||
if ( line == NULL ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( strncasecmp( *r_rp, "replica:", 7 )) {
|
||||
break;
|
||||
}
|
||||
line = ldif_getline( r_rp );
|
||||
if ( line == NULL ) {
|
||||
break;
|
||||
}
|
||||
if ( ldif_parse_line( line, &type, &value, &len ) < 0 ) {
|
||||
return( NULL );
|
||||
}
|
||||
port = LDAP_PORT;
|
||||
if (( p = strchr( value, ':' )) != NULL ) {
|
||||
*p = '\0';
|
||||
p++;
|
||||
if ( *p != '\0' && lutil_atoi( &port, p ) != 0 ) {
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that we've heard of this replica before */
|
||||
repl_ok = 0;
|
||||
for ( i = 0; i < sglob->num_replicas; i++ ) {
|
||||
if ( strcmp( sglob->replicas[ i ]->ri_hostname, value )) {
|
||||
continue;
|
||||
}
|
||||
if ( sglob->replicas[ i ]->ri_port == port ) {
|
||||
repl_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free( type );
|
||||
if ( !repl_ok ) {
|
||||
warn_unknown_replica( value, port );
|
||||
free( value );
|
||||
continue;
|
||||
}
|
||||
|
||||
rh = (Rh *) ch_realloc((char *) rh, ( nreplicas + 2 ) * sizeof( Rh ));
|
||||
if ( rh == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Out of memory in get_repl_hosts\n",
|
||||
0, 0, 0 );
|
||||
return NULL;
|
||||
}
|
||||
rh[ nreplicas ].rh_hostname = strdup( value );
|
||||
rh[ nreplicas ].rh_port = port;
|
||||
nreplicas++;
|
||||
|
||||
free( value );
|
||||
}
|
||||
|
||||
if ( nreplicas == 0 ) {
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
rh[ nreplicas ].rh_hostname = NULL;
|
||||
*r_nreplicas = nreplicas;
|
||||
|
||||
return( rh );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert "type" to an int.
|
||||
*/
|
||||
static int
|
||||
gettype(
|
||||
char *type
|
||||
)
|
||||
{
|
||||
if ( !strcmp( type, T_CHANGETYPESTR )) {
|
||||
return( T_CHANGETYPE );
|
||||
}
|
||||
if ( !strcmp( type, T_TIMESTR )) {
|
||||
return( T_TIME );
|
||||
}
|
||||
if ( !strcmp( type, T_DNSTR )) {
|
||||
return( T_DN );
|
||||
}
|
||||
return( T_ERR );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert "changetype" to an int.
|
||||
*/
|
||||
static int
|
||||
getchangetype(
|
||||
char *changetype
|
||||
)
|
||||
{
|
||||
if ( !strcmp( changetype, T_ADDCTSTR )) {
|
||||
return( T_ADDCT );
|
||||
}
|
||||
if ( !strcmp( changetype, T_MODIFYCTSTR )) {
|
||||
return( T_MODIFYCT );
|
||||
}
|
||||
if ( !strcmp( changetype, T_DELETECTSTR )) {
|
||||
return( T_DELETECT );
|
||||
}
|
||||
if ( !strcmp( changetype, T_MODRDNCTSTR )) {
|
||||
return( T_MODRDNCT );
|
||||
}
|
||||
return( T_ERR );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Find the first line which is not a "replica:" line in buf.
|
||||
* Returns a pointer to the line. Returns NULL if there are
|
||||
* only "replica:" lines in buf.
|
||||
*/
|
||||
static char *
|
||||
skip_replica_lines(
|
||||
char *buf
|
||||
)
|
||||
{
|
||||
char *p = buf;
|
||||
for (;;) {
|
||||
if ( strncasecmp( p, "replica:", 8 )) {
|
||||
return( p );
|
||||
}
|
||||
while (( *p != '\0' ) && ( *p != '\n' )) {
|
||||
p++;
|
||||
}
|
||||
if ( *p == '\0' ) {
|
||||
return ( NULL );
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* For debugging purposes: dump the contents of a replication entry.
|
||||
* to the given stream.
|
||||
*/
|
||||
static void
|
||||
Re_dump(
|
||||
Re *re,
|
||||
FILE *fp
|
||||
)
|
||||
{
|
||||
int i;
|
||||
Mi *mi;
|
||||
|
||||
if ( re == NULL ) {
|
||||
Debug( LDAP_DEBUG_TRACE, "Re_dump: re is NULL\n", 0, 0, 0 );
|
||||
return;
|
||||
}
|
||||
fprintf( fp, "Re_dump: ******\n" );
|
||||
fprintf( fp, "re_refcnt: %d\n", re->re_refcnt );
|
||||
fprintf( fp, "re_timestamp: %ld\n", (long) re->re_timestamp );
|
||||
fprintf( fp, "re_seq: %d\n", re->re_seq );
|
||||
for ( i = 0; re->re_replicas && re->re_replicas[ i ].rh_hostname != NULL;
|
||||
i++ ) {
|
||||
fprintf( fp, "re_replicas[%d]: %s:%d\n",
|
||||
i, re->re_replicas[ i ].rh_hostname,
|
||||
re->re_replicas[ i ].rh_port );
|
||||
}
|
||||
fprintf( fp, "re_dn: %s\n", re->re_dn );
|
||||
switch ( re->re_changetype ) {
|
||||
case T_ADDCT:
|
||||
fprintf( fp, "re_changetype: add\n" );
|
||||
break;
|
||||
case T_MODIFYCT:
|
||||
fprintf( fp, "re_changetype: modify\n" );
|
||||
break;
|
||||
case T_DELETECT:
|
||||
fprintf( fp, "re_changetype: delete\n" );
|
||||
break;
|
||||
case T_MODRDNCT:
|
||||
fprintf( fp, "re_changetype: modrdn\n" );
|
||||
break;
|
||||
default:
|
||||
fprintf( fp, "re_changetype: (unknown, type = %d\n",
|
||||
re->re_changetype );
|
||||
}
|
||||
if ( re->re_mods == NULL ) {
|
||||
fprintf( fp, "re_mods: (none)\n" );
|
||||
} else {
|
||||
mi = re->re_mods;
|
||||
fprintf( fp, "re_mods:\n" );
|
||||
for ( i = 0; mi[ i ].mi_type != NULL; i++ ) {
|
||||
fprintf( fp, " %s, \"%s\", (%d bytes)\n",
|
||||
mi[ i ].mi_type,
|
||||
mi[ i ].mi_val == NULL ? "(null)" : mi[ i ].mi_val,
|
||||
mi[ i ].mi_len );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given an Ri, an Re, and a file pointer, write a replication record to
|
||||
* the file pointer. If ri is NULL, then include all replicas in the
|
||||
* output. If ri is non-NULL, then only include a single "replica:" line
|
||||
* (used when writing rejection records). Returns 0 on success, -1
|
||||
* on failure. Note that Re_write will not write anything out if the
|
||||
* refcnt is zero.
|
||||
*/
|
||||
static int
|
||||
Re_write(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
FILE *fp )
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
int rc = 0;
|
||||
|
||||
if ( re == NULL || fp == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Internal error: Re_write: NULL argument\n",
|
||||
0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( re->re_refcnt < 1 ) {
|
||||
return 0; /* this is not an error */
|
||||
}
|
||||
|
||||
if ( ri != NULL ) { /* write a single "replica:" line */
|
||||
if ( ri->ri_port != 0 ) {
|
||||
rc = fprintf( fp, "replica: %s:%d\n", ri->ri_hostname,
|
||||
ri->ri_port );
|
||||
} else {
|
||||
rc = fprintf( fp, "replica: %s\n", ri->ri_hostname );
|
||||
}
|
||||
if ( rc < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
} else { /* write multiple "replica:" lines */
|
||||
for ( i = 0; re->re_replicas && re->re_replicas[ i ].rh_hostname != NULL; i++ ) {
|
||||
if ( fprintf( fp, "replica: %s:%d\n",
|
||||
re->re_replicas[ i ].rh_hostname,
|
||||
re->re_replicas[ i ].rh_port ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( fprintf( fp, "time: %ld.%d\n", (long) re->re_timestamp, re->re_seq ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
if ( fprintf( fp, "dn: %s\n", re->re_dn ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
if ( fprintf( fp, "changetype: " ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
switch ( re->re_changetype ) {
|
||||
case T_ADDCT:
|
||||
s = T_ADDCTSTR;
|
||||
break;
|
||||
case T_MODIFYCT:
|
||||
s = T_MODIFYCTSTR;
|
||||
break;
|
||||
case T_DELETECT:
|
||||
s = T_DELETECTSTR;
|
||||
break;
|
||||
case T_MODRDNCT:
|
||||
s = T_MODRDNCTSTR;
|
||||
break;
|
||||
default:
|
||||
s = "IllegalModifyType!!!";
|
||||
}
|
||||
if ( fprintf( fp, "%s\n", s ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
for ( i = 0; (( re->re_mods != NULL ) &&
|
||||
( re->re_mods[ i ].mi_type != NULL )); i++ ) {
|
||||
if ( !strcmp( re->re_mods[ i ].mi_type, T_MODSEPSTR )) {
|
||||
if ( fprintf( fp, "%s\n", T_MODSEPSTR ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
char *obuf;
|
||||
obuf = ldif_put( LDIF_PUT_VALUE,
|
||||
re->re_mods[ i ].mi_type,
|
||||
re->re_mods[ i ].mi_val ? re->re_mods[ i ].mi_val : "",
|
||||
re->re_mods[ i ].mi_len );
|
||||
if ( fputs( obuf, fp ) < 0 ) {
|
||||
rc = -1;
|
||||
free( obuf );
|
||||
goto bad;
|
||||
} else {
|
||||
ber_memfree( obuf );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( fprintf( fp, "\n" ) < 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
if ( fflush( fp ) != 0 ) {
|
||||
rc = -1;
|
||||
goto bad;
|
||||
}
|
||||
bad:
|
||||
if ( rc != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error while writing: %s\n",
|
||||
sys_errlist[ errno ], 0, 0 );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Decrement the refcnt. Locking handled internally.
|
||||
*/
|
||||
static int
|
||||
Re_decrefcnt(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
re->re_lock( re );
|
||||
re->re_refcnt--;
|
||||
re->re_unlock( re );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Get the refcnt. Locking handled internally.
|
||||
*/
|
||||
static int
|
||||
Re_getrefcnt(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
re->re_lock( re );
|
||||
ret = re->re_refcnt;
|
||||
re->re_unlock( re );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Lock this replication entry
|
||||
*/
|
||||
static int
|
||||
Re_lock(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_lock( &re->re_mutex ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Unlock this replication entry
|
||||
*/
|
||||
static int
|
||||
Re_unlock(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_unlock( &re->re_mutex ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Instantiate and initialize an Re.
|
||||
*/
|
||||
int
|
||||
Re_init(
|
||||
Re **re
|
||||
)
|
||||
{
|
||||
/* Instantiate */
|
||||
(*re) = (Re *) malloc( sizeof( Re ));
|
||||
if ( *re == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in the member function pointers */
|
||||
(*re)->re_free = Re_free;
|
||||
(*re)->re_getnext = Re_getnext;
|
||||
(*re)->re_parse = Re_parse;
|
||||
(*re)->re_write = Re_write;
|
||||
(*re)->re_dump = Re_dump;
|
||||
(*re)->re_lock = Re_lock;
|
||||
(*re)->re_unlock = Re_unlock;
|
||||
(*re)->re_decrefcnt = Re_decrefcnt;
|
||||
(*re)->re_getrefcnt = Re_getrefcnt;
|
||||
|
||||
/* Initialize private data */
|
||||
(*re)->re_refcnt = sglob->num_replicas;
|
||||
(*re)->re_timestamp = (time_t) 0L;
|
||||
(*re)->re_replicas = NULL;
|
||||
(*re)->re_dn = NULL;
|
||||
(*re)->re_changetype = 0;
|
||||
(*re)->re_seq = 0;
|
||||
(*re)->re_mods = NULL;
|
||||
(*re)->re_next = NULL;
|
||||
|
||||
ldap_pvt_thread_mutex_init( &((*re)->re_mutex) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Given a host and port, generate a warning message iff we haven't already
|
||||
* generated a message for this host:port combination.
|
||||
*/
|
||||
static void
|
||||
warn_unknown_replica(
|
||||
char *host,
|
||||
int port
|
||||
)
|
||||
{
|
||||
int found = 0;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < nur; i++ ) {
|
||||
if ( strcmp( ur[ i ].rh_hostname, host )) {
|
||||
continue;
|
||||
}
|
||||
if ( ur[ i ].rh_port == port ) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !found ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Warning: unknown replica %s:%d found in replication log\n",
|
||||
host, port, 0 );
|
||||
nur++;
|
||||
ur = (Rh *) ch_realloc( (char *) ur, ( nur * sizeof( Rh )));
|
||||
ur[ nur - 1 ].rh_hostname = strdup( host );
|
||||
ur[ nur - 1 ].rh_port = port;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* reject.c - routines to write replication records to reject files.
|
||||
* An Re struct is writted to a reject file if it cannot be propagated
|
||||
* to a replica LDAP server.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/errno.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include "lber_pvt.h"
|
||||
#include "lutil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PORTSEP ","
|
||||
#else
|
||||
#define PORTSEP ":"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Write a replication record to a reject file. The reject file has the
|
||||
* same name as the replica's private copy of the file but with ".rej"
|
||||
* appended (e.g. "/usr/tmp/<hostname>:<port>.rej")
|
||||
*
|
||||
* If errmsg is non-NULL, use that as the error message in the reject
|
||||
* file. Otherwise, use ldap_err2string( lderr ).
|
||||
*/
|
||||
void
|
||||
write_reject(
|
||||
Ri *ri,
|
||||
Re *re,
|
||||
int lderr,
|
||||
char *errmsg
|
||||
)
|
||||
{
|
||||
char rejfile[ MAXPATHLEN ];
|
||||
FILE *rfp, *lfp;
|
||||
int rc;
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &sglob->rej_mutex );
|
||||
snprintf( rejfile, sizeof rejfile, "%s" LDAP_DIRSEP "%s" PORTSEP "%d.rej",
|
||||
sglob->slurpd_rdir, ri->ri_hostname, ri->ri_port );
|
||||
|
||||
if ( access( rejfile, F_OK ) < 0 ) {
|
||||
/* Doesn't exist - try to create */
|
||||
int rjfd;
|
||||
if (( rjfd = open( rejfile, O_RDWR|O_APPEND|O_CREAT|O_EXCL,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP )) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: write_reject: Cannot create \"%s\": %s\n",
|
||||
rejfile, sys_errlist[ errno ], 0 );
|
||||
ldap_pvt_thread_mutex_unlock( &sglob->rej_mutex );
|
||||
return;
|
||||
} else {
|
||||
close( rjfd );
|
||||
}
|
||||
}
|
||||
if (( rc = acquire_lock( rejfile, &rfp, &lfp )) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: cannot open reject file \"%s\"\n",
|
||||
rejfile, 0, 0 );
|
||||
} else {
|
||||
struct berval bv = BER_BVNULL,
|
||||
errstrbv,
|
||||
errmsgbv = BER_BVNULL;
|
||||
char *ptr;
|
||||
|
||||
ber_str2bv( ldap_err2string( lderr ), 0, 0, &errstrbv );
|
||||
if ( errmsg && *errmsg ) {
|
||||
ber_str2bv( errmsg, 0, 0, &errmsgbv );
|
||||
bv.bv_len = errstrbv.bv_len
|
||||
+ STRLENOF( ": " ) + errmsgbv.bv_len;
|
||||
|
||||
ptr = bv.bv_val = ber_memalloc( bv.bv_len + 1 );
|
||||
ptr = lutil_strcopy( ptr, errstrbv.bv_val );
|
||||
ptr = lutil_strcopy( ptr, ": " );
|
||||
ptr = lutil_strcopy( ptr, errmsgbv.bv_val );
|
||||
|
||||
} else {
|
||||
bv = errstrbv;
|
||||
}
|
||||
|
||||
fseek( rfp, 0, 2 );
|
||||
|
||||
ptr = ldif_put( LDIF_PUT_VALUE, ERROR_STR, bv.bv_val, bv.bv_len );
|
||||
if ( bv.bv_val != errstrbv.bv_val ) {
|
||||
ber_memfree( bv.bv_val );
|
||||
}
|
||||
if ( ptr == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: cannot convert error message(s) \"%s%s%s\" "
|
||||
"into LDIF format\n",
|
||||
errstrbv.bv_val,
|
||||
BER_BVISNULL( &errmsgbv ) ? "" : ": ",
|
||||
BER_BVISNULL( &errmsgbv ) ? "" : errmsgbv.bv_val );
|
||||
return;
|
||||
}
|
||||
|
||||
fputs( ptr, rfp );
|
||||
ber_memfree( ptr );
|
||||
|
||||
if ((rc = re->re_write( ri, re, rfp )) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: cannot write reject file \"%s\"\n",
|
||||
rejfile, 0, 0 );
|
||||
}
|
||||
(void) relinquish_lock( rejfile, rfp, lfp );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: ldap operation failed, data written to \"%s\"\n",
|
||||
rejfile, 0, 0 );
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &sglob->rej_mutex );
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* replica.c - code to start up replica threads.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ac/stdlib.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
/*
|
||||
* Just invoke the Ri's process() member function, and log the start and
|
||||
* finish.
|
||||
*/
|
||||
static void *
|
||||
replicate(
|
||||
void *ri_arg
|
||||
)
|
||||
{
|
||||
Ri *ri = (Ri *) ri_arg;
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, "begin replication thread for %s:%d\n",
|
||||
ri->ri_hostname, ri->ri_port, 0 );
|
||||
|
||||
ri->ri_process( ri );
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, "end replication thread for %s:%d\n",
|
||||
ri->ri_hostname, ri->ri_port, 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Start a detached thread for the given replica.
|
||||
*/
|
||||
int
|
||||
start_replica_thread(
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
/* POSIX_THREADS or compatible */
|
||||
if ( ldap_pvt_thread_create( &(ri->ri_tid), 0, replicate,
|
||||
(void *) ri ) != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "replica \"%s:%d\" ldap_pvt_thread_create failed\n",
|
||||
ri->ri_hostname, ri->ri_port, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* replog.c - routines which read and write replication log files.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/errno.h>
|
||||
#include <ac/param.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/syslog.h>
|
||||
#include <ac/time.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
/*
|
||||
* Copy the replication log. Returns 0 on success, 1 if a temporary
|
||||
* error occurs, and -1 if a fatal error occurs.
|
||||
*/
|
||||
int
|
||||
copy_replog(
|
||||
char *src,
|
||||
char *dst
|
||||
)
|
||||
{
|
||||
int rc = 0;
|
||||
FILE *rfp; /* replog fp */
|
||||
FILE *lfp; /* replog lockfile fp */
|
||||
FILE *dfp; /* duplicate replog fp */
|
||||
FILE *dlfp; /* duplicate replog lockfile fp */
|
||||
static char buf[ MAXPATHLEN ];
|
||||
static char rbuf[ 1024 ];
|
||||
char *p;
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"copy replog \"%s\" to \"%s\"\n",
|
||||
src, dst, 0 );
|
||||
|
||||
/*
|
||||
* Make sure the destination directory is writable. If not, exit
|
||||
* with a fatal error.
|
||||
*/
|
||||
strcpy( buf, src );
|
||||
if (( p = strrchr( buf, LDAP_DIRSEP[0] )) == NULL ) {
|
||||
strcpy( buf, "." );
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
if ( access( buf, W_OK ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog (%ld): Directory %s is not writable\n",
|
||||
(long) getpid(), buf, 0 );
|
||||
return( -1 );
|
||||
}
|
||||
strcpy( buf, dst );
|
||||
if (( p = strrchr( buf, LDAP_DIRSEP[0] )) == NULL ) {
|
||||
strcpy( buf, "." );
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
if ( access( buf, W_OK ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog (%ld): Directory %s is not writable\n",
|
||||
(long) getpid(), buf, 0 );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* lock src */
|
||||
rfp = lock_fopen( src, "r", &lfp );
|
||||
if ( rfp == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog: Can't lock replog \"%s\" for read: %s\n",
|
||||
src, sys_errlist[ errno ], 0 );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/* lock dst */
|
||||
dfp = lock_fopen( dst, "a", &dlfp );
|
||||
if ( dfp == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog: Can't lock replog \"%s\" for write: %s\n",
|
||||
dst, sys_errlist[ errno ], 0 );
|
||||
lock_fclose( rfp, lfp );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Make our own private copy of the replication log.
|
||||
*/
|
||||
while (( p = fgets( rbuf, sizeof( rbuf ), rfp )) != NULL ) {
|
||||
fputs( rbuf, dfp );
|
||||
}
|
||||
/* Only truncate the source file if we're not in one-shot mode */
|
||||
if ( !sglob->one_shot_mode ) {
|
||||
/* truncate replication log */
|
||||
truncate( src, (off_t) 0 );
|
||||
}
|
||||
|
||||
if ( lock_fclose( dfp, dlfp ) == EOF ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog: Error closing \"%s\"\n",
|
||||
dst, 0, 0 );
|
||||
}
|
||||
if ( lock_fclose( rfp, lfp ) == EOF ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: copy_replog: Error closing \"%s\"\n",
|
||||
src, 0, 0 );
|
||||
}
|
||||
return( rc );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return 1 if the given file exists and has a nonzero size,
|
||||
* 0 if it is empty or nonexistent.
|
||||
*/
|
||||
int
|
||||
file_nonempty(
|
||||
char *filename
|
||||
)
|
||||
{
|
||||
static struct stat stbuf;
|
||||
|
||||
if ( stat( filename, &stbuf ) < 0 ) {
|
||||
return( 0 );
|
||||
} else {
|
||||
return( stbuf.st_size > (off_t ) 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,285 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* ri.c - routines used to manipulate Ri structures. An Ri (Replica
|
||||
* information) struct contains all information about one replica
|
||||
* instance. The Ri struct is defined in slurp.h
|
||||
*/
|
||||
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/signal.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
/* Forward references */
|
||||
static int ismine LDAP_P(( Ri *, Re * ));
|
||||
static int isnew LDAP_P(( Ri *, Re * ));
|
||||
|
||||
|
||||
/*
|
||||
* Process any unhandled replication entries in the queue.
|
||||
*/
|
||||
static int
|
||||
Ri_process(
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
Rq *rq = sglob->rq;
|
||||
Re *re = NULL, *new_re = NULL;
|
||||
int rc ;
|
||||
char *errmsg;
|
||||
int errfree;
|
||||
|
||||
(void) SIGNAL( LDAP_SIGUSR1, do_nothing );
|
||||
#ifdef SIGPIPE
|
||||
(void) SIGNAL( SIGPIPE, SIG_IGN );
|
||||
#endif
|
||||
if ( ri == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: Ri_process: ri == NULL!\n", 0, 0, 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Startup code. See if there's any work to do. If not, wait on the
|
||||
* rq->rq_more condition variable.
|
||||
*/
|
||||
rq->rq_lock( rq );
|
||||
while ( !sglob->slurpd_shutdown &&
|
||||
(( re = rq->rq_gethead( rq )) == NULL )) {
|
||||
/* No work */
|
||||
if ( sglob->one_shot_mode ) {
|
||||
/* give up if in one shot mode */
|
||||
rq->rq_unlock( rq );
|
||||
return 0;
|
||||
}
|
||||
/* wait on condition variable */
|
||||
ldap_pvt_thread_cond_wait( &rq->rq_more, &rq->rq_mutex );
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get here, there's work in the queue, and we have the
|
||||
* queue locked. re should be pointing to the head of the queue.
|
||||
*/
|
||||
rq->rq_unlock( rq );
|
||||
while ( !sglob->slurpd_shutdown ) {
|
||||
if ( re != NULL ) {
|
||||
if ( !ismine( ri, re )) {
|
||||
/* The Re doesn't list my host:port */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Replica %s:%d, skip repl record for %s (not mine)\n",
|
||||
ri->ri_hostname, ri->ri_port, re->re_dn );
|
||||
} else if ( !isnew( ri, re )) {
|
||||
/* This Re is older than my saved status information */
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"Replica %s:%d, skip repl record for %s (old)\n",
|
||||
ri->ri_hostname, ri->ri_port, re->re_dn );
|
||||
} else {
|
||||
rc = do_ldap( ri, re, &errmsg, &errfree );
|
||||
switch ( rc ) {
|
||||
case DO_LDAP_ERR_RETRYABLE:
|
||||
ldap_pvt_thread_sleep( RETRY_SLEEP_TIME );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Retrying operation for DN %s on replica %s:%d\n",
|
||||
re->re_dn, ri->ri_hostname, ri->ri_port );
|
||||
continue;
|
||||
break;
|
||||
case DO_LDAP_ERR_FATAL: {
|
||||
/* Non-retryable error. Write rejection log. */
|
||||
int ld_errno = 0;
|
||||
ldap_get_option(ri->ri_ldp, LDAP_OPT_RESULT_CODE, &ld_errno);
|
||||
write_reject( ri, re, ld_errno, errmsg );
|
||||
/* Update status ... */
|
||||
(void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
|
||||
/* ... and write to disk */
|
||||
(void) sglob->st->st_write( sglob->st );
|
||||
} break;
|
||||
default:
|
||||
/* LDAP op completed ok - update status... */
|
||||
(void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
|
||||
/* ... and write to disk */
|
||||
(void) sglob->st->st_write( sglob->st );
|
||||
break;
|
||||
}
|
||||
if ( errfree && errmsg ) {
|
||||
ch_free( errmsg );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: re is null in Ri_process\n",
|
||||
0, 0, 0 );
|
||||
}
|
||||
rq->rq_lock( rq );
|
||||
while ( !sglob->slurpd_shutdown &&
|
||||
((new_re = re->re_getnext( re )) == NULL )) {
|
||||
if ( sglob->one_shot_mode ) {
|
||||
rq->rq_unlock( rq );
|
||||
return 0;
|
||||
}
|
||||
/* No work - wait on condition variable */
|
||||
ldap_pvt_thread_cond_wait( &rq->rq_more, &rq->rq_mutex );
|
||||
}
|
||||
re->re_decrefcnt( re );
|
||||
re = new_re;
|
||||
rq->rq_unlock( rq );
|
||||
if ( sglob->slurpd_shutdown ) {
|
||||
if ( ri->ri_ldp ) {
|
||||
ldap_unbind_ext( ri->ri_ldp, NULL, NULL );
|
||||
ri->ri_ldp = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wake a replication thread which may be sleeping.
|
||||
* Send it a LDAP_SIGUSR1.
|
||||
*/
|
||||
static void
|
||||
Ri_wake(
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
if ( ri == NULL ) {
|
||||
return;
|
||||
}
|
||||
ldap_pvt_thread_kill( ri->ri_tid, LDAP_SIGUSR1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialize an Ri struct.
|
||||
*/
|
||||
int
|
||||
Ri_init(
|
||||
Ri **ri
|
||||
)
|
||||
{
|
||||
(*ri) = ( Ri * ) calloc( 1, sizeof( Ri ));
|
||||
if ( *ri == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize member functions */
|
||||
(*ri)->ri_process = Ri_process;
|
||||
(*ri)->ri_wake = Ri_wake;
|
||||
|
||||
/* Initialize private data */
|
||||
(*ri)->ri_hostname = NULL;
|
||||
(*ri)->ri_uri = NULL;
|
||||
(*ri)->ri_ldp = NULL;
|
||||
(*ri)->ri_bind_dn = NULL;
|
||||
(*ri)->ri_password = NULL;
|
||||
(*ri)->ri_authcId = NULL;
|
||||
(*ri)->ri_curr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return 1 if the hostname and port in re match the hostname and port
|
||||
* in ri, otherwise return zero.
|
||||
*/
|
||||
static int
|
||||
ismine(
|
||||
Ri *ri,
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
Rh *rh;
|
||||
int i;
|
||||
|
||||
if ( ri == NULL || re == NULL || ri->ri_hostname == NULL ||
|
||||
re->re_replicas == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
rh = re->re_replicas;
|
||||
for ( i = 0; rh[ i ].rh_hostname != NULL; i++ ) {
|
||||
if ( !strcmp( rh[ i ].rh_hostname, ri->ri_hostname) &&
|
||||
rh[ i ].rh_port == ri->ri_port ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return 1 if the Re's timestamp/seq combination are greater than the
|
||||
* timestamp and seq in the Ri's ri_stel member. In other words, if we
|
||||
* find replication entries in the log which we've already processed,
|
||||
* don't process them. If the re is "old," return 0.
|
||||
* No check for NULL pointers is done.
|
||||
*/
|
||||
static int
|
||||
isnew(
|
||||
Ri *ri,
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
long x;
|
||||
int ret;
|
||||
|
||||
/* Lock the St struct to avoid a race */
|
||||
sglob->st->st_lock( sglob->st );
|
||||
x = re->re_timestamp - ri->ri_stel->last;
|
||||
if ( x > 0 ) {
|
||||
/* re timestamp is newer */
|
||||
ret = 1;
|
||||
} else if ( x < 0 ) {
|
||||
ret = 0;
|
||||
} else {
|
||||
/* timestamps were equal */
|
||||
if ( re->re_seq > ri->ri_stel->seq ) {
|
||||
/* re seq is newer */
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
sglob->st->st_unlock( sglob->st );
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,444 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/*
|
||||
* rq.c - routines used to manage the queue of replication entries.
|
||||
* An Rq (Replication queue) struct contains a linked list of Re
|
||||
* (Replication entry) structures.
|
||||
*
|
||||
* Routines wishing to access the replication queue should do so through
|
||||
* the Rq struct's member functions, e.g. rq->rq_gethead() and friends.
|
||||
* For example, Re structs should be added to the queue by calling
|
||||
* the rq_add() member function.
|
||||
*
|
||||
* Access to the queue is serialized by a mutex. Member functions which do
|
||||
* not do their own locking should only be called after locking the queue
|
||||
* using the rq_lock() member function. The queue should be unlocked with
|
||||
* the rq_unlock() member function.
|
||||
*
|
||||
* Note that some member functions handle their own locking internally.
|
||||
* Callers should not lock the queue before calling these functions.
|
||||
* See the comment block for each function below.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/unistd.h> /* get ftruncate() */
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
/*
|
||||
* Lock the replication queue.
|
||||
*/
|
||||
static int
|
||||
Rq_lock(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_lock( &rq->rq_mutex ));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unlock the replication queue.
|
||||
*/
|
||||
static int
|
||||
Rq_unlock(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_unlock( &rq->rq_mutex ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return the head of the queue. Callers should lock the queue before
|
||||
* calling this routine.
|
||||
*/
|
||||
static Re *
|
||||
Rq_gethead(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
return( rq == NULL ? NULL : rq->rq_head );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the next item in the queue. Callers should lock the queue before
|
||||
* calling this routine.
|
||||
*/
|
||||
static Re *
|
||||
Rq_getnext(
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
if ( re == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
return( re->re_getnext( re ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete the item at the head of the list. The queue should be locked
|
||||
* by the caller before calling this routine.
|
||||
*/
|
||||
static int
|
||||
Rq_delhead(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
Re *savedhead;
|
||||
int rc;
|
||||
|
||||
if ( rq == NULL ) {
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
savedhead = rq->rq_head;
|
||||
if ( savedhead == NULL ) {
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if ( savedhead->re_getrefcnt( savedhead ) != 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Warning: attempt to delete when refcnt != 0\n",
|
||||
0, 0, 0 );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
rq->rq_head = rq->rq_head->re_getnext( rq->rq_head );
|
||||
rc = savedhead->re_free( savedhead );
|
||||
rq->rq_nre--; /* decrement count of Re's in queue */
|
||||
return( rc );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an entry to the tail of the replication queue. Locking is handled
|
||||
* internally. When items are added to the queue, this routine wakes
|
||||
* up any threads which are waiting for more work by signaling on the
|
||||
* rq->rq_more condition variable.
|
||||
*/
|
||||
static int
|
||||
Rq_add(
|
||||
Rq *rq,
|
||||
char *buf
|
||||
)
|
||||
{
|
||||
Re *re;
|
||||
int wasempty = 0;
|
||||
|
||||
/* Lock the queue */
|
||||
rq->rq_lock( rq );
|
||||
|
||||
/* Create a new Re */
|
||||
if ( Re_init( &re ) < 0 ) {
|
||||
rq->rq_unlock( rq );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parse buf and fill in the re struct */
|
||||
if ( re->re_parse( re, buf ) < 0 ) {
|
||||
re->re_free( re );
|
||||
rq->rq_unlock( rq );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Insert into queue */
|
||||
if ( rq->rq_head == NULL ) {
|
||||
rq->rq_head = re;
|
||||
rq->rq_tail = re;
|
||||
wasempty = 1;
|
||||
} else {
|
||||
rq->rq_tail->re_next = re;
|
||||
}
|
||||
|
||||
/* set the sequence number */
|
||||
re->re_seq = 0;
|
||||
if ( !wasempty && ( rq->rq_tail->re_timestamp == re->re_timestamp )) {
|
||||
/*
|
||||
* Our new re has the same timestamp as the tail's timestamp.
|
||||
* Increment the seq number in the tail and use it as our seq number.
|
||||
*/
|
||||
re->re_seq = rq->rq_tail->re_seq + 1;
|
||||
}
|
||||
rq->rq_tail = re;
|
||||
|
||||
/* Increment count of items in queue */
|
||||
rq->rq_nre++;
|
||||
/* wake up any threads waiting for more work */
|
||||
ldap_pvt_thread_cond_broadcast( &rq->rq_more );
|
||||
|
||||
/* ... and unlock the queue */
|
||||
rq->rq_unlock( rq );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Garbage-collect the replication queue. Locking is handled internally.
|
||||
*/
|
||||
static void
|
||||
Rq_gc(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
if ( rq == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Rq_gc: rq is NULL!\n", 0, 0, 0 );
|
||||
return;
|
||||
}
|
||||
rq->rq_lock( rq );
|
||||
while (( rq->rq_head != NULL ) &&
|
||||
( rq->rq_head->re_getrefcnt( rq->rq_head ) == 0 )) {
|
||||
rq->rq_delhead( rq );
|
||||
rq->rq_ndel++; /* increment count of deleted entries */
|
||||
}
|
||||
rq->rq_unlock( rq );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For debugging: dump the contents of the replication queue to a file.
|
||||
* Locking is handled internally.
|
||||
*/
|
||||
static void
|
||||
Rq_dump(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
Re *re;
|
||||
FILE *fp;
|
||||
int tmpfd;
|
||||
|
||||
if ( rq == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Rq_dump: rq is NULL!\n", 0, 0, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlink(SLURPD_DUMPFILE) == -1 && errno != ENOENT) {
|
||||
Debug( LDAP_DEBUG_ANY, "Rq_dump: \"%s\" exists, and cannot unlink\n",
|
||||
SLURPD_DUMPFILE, 0, 0 );
|
||||
return;
|
||||
}
|
||||
if (( tmpfd = open(SLURPD_DUMPFILE, O_CREAT|O_RDWR|O_EXCL, 0600)) == -1) {
|
||||
Debug( LDAP_DEBUG_ANY, "Rq_dump: cannot open \"%s\" for write\n",
|
||||
SLURPD_DUMPFILE, 0, 0 );
|
||||
return;
|
||||
}
|
||||
if (( fp = fdopen( tmpfd, "w" )) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Rq_dump: cannot fdopen \"%s\" for write\n",
|
||||
SLURPD_DUMPFILE, 0, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
rq->rq_lock( rq );
|
||||
for ( re = rq->rq_gethead( rq ); re != NULL; re = rq->rq_getnext( re )) {
|
||||
re->re_dump( re, fp );
|
||||
}
|
||||
rq->rq_unlock( rq );
|
||||
fclose( fp );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write the contents of a replication queue to a file. Returns zero if
|
||||
* successful, -1 if not. Handles queue locking internally. Callers should
|
||||
* provide an open file pointer, which should refer to a locked file.
|
||||
*/
|
||||
static int
|
||||
Rq_write(
|
||||
Rq *rq,
|
||||
FILE *fp
|
||||
)
|
||||
{
|
||||
Re *re;
|
||||
time_t now;
|
||||
|
||||
if ( rq == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_ARGS, "re-write on-disk replication log\n",
|
||||
0, 0, 0 );
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
fseek( fp, 0L, SEEK_SET ); /* Go to beginning of file */
|
||||
rq->rq_lock( rq );
|
||||
|
||||
for ( re = rq->rq_gethead( rq ); re != NULL; re = rq->rq_getnext( re )) {
|
||||
if ( re->re_write( NULL, re, fp ) < 0 ) {
|
||||
fflush( fp );
|
||||
rq->rq_unlock( rq );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
fflush( fp );
|
||||
sglob->srpos = ftell( fp ); /* update replog file position */
|
||||
/* and truncate to correct len */
|
||||
if ( ftruncate( fileno( fp ), sglob->srpos ) < 0 ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error truncating replication log: %s\n",
|
||||
sys_errlist[ errno ], 0, 0 );
|
||||
}
|
||||
rq->rq_ndel = 0; /* reset count of deleted re's */
|
||||
time( &now );
|
||||
rq->rq_lasttrim = now; /* reset last trim time */
|
||||
rq->rq_unlock( rq );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check to see if the private slurpd replication log needs trimming.
|
||||
* The current criteria are:
|
||||
* - The last trim was more than 5 minutes ago, *and*
|
||||
* - We've finished with at least 50 replication log entries since the
|
||||
* last time we re-wrote the replication log.
|
||||
*
|
||||
* Return 1 if replogfile should be trimmed, 0 if not.
|
||||
* Any different policy should be implemented by replacing this function.
|
||||
*/
|
||||
static int
|
||||
Rq_needtrim(
|
||||
Rq *rq
|
||||
)
|
||||
{
|
||||
int rc = 0;
|
||||
time_t now;
|
||||
|
||||
if ( rq == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rq->rq_lock( rq );
|
||||
|
||||
time( &now );
|
||||
|
||||
if ( now > ( rq->rq_lasttrim + TRIMCHECK_INTERVAL )) {
|
||||
rc = ( rq->rq_ndel >= 50 );
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
rq->rq_unlock( rq );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return counts of Re structs in the queue.
|
||||
*/
|
||||
static int
|
||||
Rq_getcount(
|
||||
Rq *rq,
|
||||
int type
|
||||
)
|
||||
{
|
||||
int count = 0;
|
||||
Re *re;
|
||||
|
||||
if ( rq == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rq->rq_lock( rq );
|
||||
if ( type == RQ_COUNT_ALL ) {
|
||||
count = rq->rq_nre;
|
||||
} else {
|
||||
for ( re = rq->rq_gethead( rq ); re != NULL;
|
||||
re = rq->rq_getnext( re )) {
|
||||
if ( type == RQ_COUNT_NZRC ) {
|
||||
if ( re->re_getrefcnt( re ) > 0 ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rq->rq_unlock( rq );
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialize an Rq object.
|
||||
*/
|
||||
int
|
||||
Rq_init(
|
||||
Rq **rq
|
||||
)
|
||||
{
|
||||
/* Instantiate the struct */
|
||||
(*rq) = (Rq *) malloc( sizeof( Rq ));
|
||||
if ( *rq == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in all the function pointers */
|
||||
(*rq)->rq_gethead = Rq_gethead;
|
||||
(*rq)->rq_getnext = Rq_getnext;
|
||||
(*rq)->rq_delhead = Rq_delhead;
|
||||
(*rq)->rq_add = Rq_add;
|
||||
(*rq)->rq_gc = Rq_gc;
|
||||
(*rq)->rq_lock = Rq_lock;
|
||||
(*rq)->rq_unlock = Rq_unlock;
|
||||
(*rq)->rq_dump = Rq_dump;
|
||||
(*rq)->rq_needtrim = Rq_needtrim;
|
||||
(*rq)->rq_write = Rq_write;
|
||||
(*rq)->rq_getcount = Rq_getcount;
|
||||
|
||||
/* Initialize private data */
|
||||
ldap_pvt_thread_mutex_init( &((*rq)->rq_mutex) );
|
||||
ldap_pvt_thread_cond_init( &((*rq)->rq_more) );
|
||||
(*rq)->rq_head = NULL;
|
||||
(*rq)->rq_tail = NULL;
|
||||
(*rq)->rq_nre = 0;
|
||||
(*rq)->rq_ndel = 0;
|
||||
(*rq)->rq_lasttrim = (time_t) 0L;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* sanity.c - perform sanity checks on the environment at startup time,
|
||||
* and report any errors before we disassociate from the controlling tty,
|
||||
* start up our threads, and do other stuff which makes it hard to give
|
||||
* feedback to the users.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/unistd.h>
|
||||
#include <ac/string.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
|
||||
#define FC_DIRBAD 1
|
||||
#define FC_DIRUNREAD 2
|
||||
#define FC_DIRUNWRITE 4
|
||||
#define FC_FILEBAD 8
|
||||
#define FC_FILEUNREAD 16
|
||||
#define FC_FILEUNWRITE 32
|
||||
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
static unsigned int filecheck LDAP_P(( char * ));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Take a look around to catch any fatal errors. For example, make sure the
|
||||
* destination directory for our working files exists, check that all
|
||||
* pathnames make sense, and so on. Returns 0 is everything's ok,
|
||||
# -1 if there's something wrong which will keep us from functioning
|
||||
* correctly.
|
||||
*
|
||||
* We do all these checks at startup so we can print a reasonable error
|
||||
* message on stderr before we disassociate from the controlling tty. This
|
||||
* keeps some fatal error messages from "disappearing" into syslog.
|
||||
*/
|
||||
|
||||
int
|
||||
sanity( void )
|
||||
{
|
||||
int err = 0;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Are there any replicas listed in the slapd config file?
|
||||
*/
|
||||
if ( sglob->replicas == NULL ) {
|
||||
fprintf( stderr, "No replicas in slapd.conf file \"%s\"!\n",
|
||||
sglob->slapd_configfile );
|
||||
err++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the directory housing the slapd replogfile exists, and
|
||||
* that the slapd replogfile is readable, if it exists.
|
||||
*/
|
||||
if ( sglob->slapd_replogfile == NULL ) {
|
||||
fprintf( stderr, "Fatal error: no \"replogfile\" "
|
||||
"slapd.conf directive given\n" );
|
||||
err++;
|
||||
} else {
|
||||
rc = filecheck( sglob->slapd_replogfile );
|
||||
if ( rc & FC_DIRBAD ) {
|
||||
fprintf( stderr, "Error: %s: directory specified in "
|
||||
"\"replogfile\" slapd.conf directive does not exist\n",
|
||||
sglob->slapd_replogfile );
|
||||
err++;
|
||||
} else if ( rc & FC_DIRUNREAD ) {
|
||||
fprintf( stderr, "Error: %s: directory specified in "
|
||||
"\"replogfile\" slapd.conf directive is not readable\n",
|
||||
sglob->slapd_replogfile );
|
||||
err++;
|
||||
} else if (!( rc & FC_FILEBAD) && ( rc & FC_FILEUNREAD )) {
|
||||
fprintf( stderr, "Error: %s: file specified in "
|
||||
"\"replogfile\" slapd.conf directive is not readable\n",
|
||||
sglob->slapd_replogfile );
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the directory for the slurpd replogfile is there, and
|
||||
* that the slurpd replogfile is readable and writable, if it exists.
|
||||
*/
|
||||
if ( sglob->slurpd_replogfile == NULL ) {
|
||||
fprintf( stderr, "Fatal error: no \"replogfile\" directive given\n" );
|
||||
err++;
|
||||
} else {
|
||||
rc = filecheck( sglob->slurpd_replogfile );
|
||||
if ( rc & FC_DIRBAD ) {
|
||||
fprintf( stderr, "Error: %s: slurpd \"replogfile\" "
|
||||
"directory does not exist\n",
|
||||
sglob->slurpd_replogfile );
|
||||
err++;
|
||||
} else if ( rc & FC_DIRUNREAD ) {
|
||||
fprintf( stderr, "Error: %s: slurpd \"replogfile\" "
|
||||
"directory not readable\n",
|
||||
sglob->slurpd_replogfile );
|
||||
err++;
|
||||
} else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNREAD )) {
|
||||
fprintf( stderr, "Error: %s: slurpd \"replogfile\" not readable\n",
|
||||
sglob->slurpd_replogfile );
|
||||
err++;
|
||||
} else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNWRITE )) {
|
||||
fprintf( stderr, "Error: %s: slurpd \"replogfile\" not writeable\n",
|
||||
sglob->slurpd_replogfile );
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the directory for the slurpd status file is there, and
|
||||
* that the slurpd status file is writable, if it exists.
|
||||
*/
|
||||
rc = filecheck( sglob->slurpd_status_file );
|
||||
if ( rc & FC_DIRBAD ) {
|
||||
fprintf( stderr, "Error: %s: status directory does not exist\n",
|
||||
sglob->slurpd_status_file );
|
||||
err++;
|
||||
} else if ( rc & FC_DIRUNREAD ) {
|
||||
fprintf( stderr, "Error: %s: status directory not readable\n",
|
||||
sglob->slurpd_status_file );
|
||||
err++;
|
||||
} else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNREAD )) {
|
||||
fprintf( stderr, "Error: %s: status file not readable\n",
|
||||
sglob->slurpd_status_file );
|
||||
err++;
|
||||
} else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNWRITE )) {
|
||||
fprintf( stderr, "Error: %s: status file not writeable\n",
|
||||
sglob->slurpd_status_file );
|
||||
err++;
|
||||
}
|
||||
|
||||
return ( err == 0 ? 0 : -1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Check for the existence of the file and directory leading to the file.
|
||||
* Returns a bitmask which is the logical OR of the following flags:
|
||||
*
|
||||
* FC_DIRBAD: directory containing "f" does not exist.
|
||||
* FC_DIRUNREAD: directory containing "f" exists but is not readable.
|
||||
* FC_DIRUNWRITE: directory containing "f" exists but is not writable.
|
||||
* FC_FILEBAD: "f" does not exist.
|
||||
* FC_FILEUNREAD: "f" exists but is unreadable.
|
||||
* FC_FILEUNWRITE: "f" exists but is unwritable.
|
||||
*
|
||||
* The calling routine is responsible for determining which, if any, of
|
||||
* the returned flags is a problem for a particular file.
|
||||
*/
|
||||
static unsigned int
|
||||
filecheck(
|
||||
char *f
|
||||
)
|
||||
{
|
||||
char dir[ MAXPATHLEN ];
|
||||
char *p;
|
||||
unsigned int ret = 0;
|
||||
|
||||
snprintf( dir, sizeof dir, "%s", f );
|
||||
p = strrchr( dir, LDAP_DIRSEP[0] );
|
||||
if ( p != NULL ) {
|
||||
*p = '\0';
|
||||
}
|
||||
if ( access( dir, F_OK ) < 0 ) {
|
||||
ret |= FC_DIRBAD;
|
||||
}
|
||||
if ( access( dir, R_OK ) < 0 ) {
|
||||
ret |= FC_DIRUNREAD;
|
||||
}
|
||||
if ( access( dir, W_OK ) < 0 ) {
|
||||
ret |= FC_DIRUNWRITE;
|
||||
}
|
||||
if ( access( f, F_OK ) < 0 ) {
|
||||
ret |= FC_FILEBAD;
|
||||
}
|
||||
if ( access( f, R_OK ) < 0 ) {
|
||||
ret |= FC_FILEUNREAD;
|
||||
}
|
||||
if ( access( f, W_OK ) < 0 ) {
|
||||
ret |= FC_FILEUNWRITE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,415 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
/* slurp.h - Standalone Ldap Update Replication Daemon (slurpd) */
|
||||
|
||||
#ifndef _SLURPD_H_
|
||||
#define _SLURPD_H_
|
||||
|
||||
#if !defined(HAVE_WINSOCK) && !defined(LDAP_SYSLOG)
|
||||
#define LDAP_SYSLOG 1
|
||||
#endif
|
||||
|
||||
#include <ac/errno.h>
|
||||
#include <ac/param.h>
|
||||
#include <ac/signal.h>
|
||||
#include <ac/syslog.h>
|
||||
#include <ac/time.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ldap.h>
|
||||
|
||||
#undef ldap_debug
|
||||
#define ldap_debug slurp_debug
|
||||
#include "ldap_log.h"
|
||||
|
||||
#include "ldap_pvt_thread.h"
|
||||
#include "ldap_defaults.h"
|
||||
#include "ldif.h"
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
/* should be moved to portable.h.nt */
|
||||
#define ftruncate(a,b) _chsize(a,b)
|
||||
#define truncate(a,b) _lclose( _lcreat(a, 0))
|
||||
#define mkdir(a,b) mkdir(a)
|
||||
#define S_IRGRP 0
|
||||
#define S_IWGRP 0
|
||||
#ifndef F_OK
|
||||
#define F_OK 0
|
||||
#endif
|
||||
#ifndef W_OK
|
||||
#define W_OK 2
|
||||
#endif
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#endif
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR S_IREAD
|
||||
#endif
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR S_IWRITE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef SERVICE_NAME
|
||||
#define SERVICE_NAME OPENLDAP_PACKAGE "-slurpd"
|
||||
|
||||
/* Default directory for slurpd's private copy of replication logs */
|
||||
#define DEFAULT_SLURPD_REPLICA_DIR LDAP_RUNDIR LDAP_DIRSEP "openldap-slurp"
|
||||
|
||||
/* Default name for slurpd's private copy of the replication log */
|
||||
#define DEFAULT_SLURPD_REPLOGFILE "slurpd.replog"
|
||||
|
||||
/* Name of file which stores saved slurpd state info, for restarting */
|
||||
#define DEFAULT_SLURPD_STATUS_FILE "slurpd.status"
|
||||
|
||||
/* slurpd dump file - contents of rq struct are written here (debugging) */
|
||||
#define SLURPD_DUMPFILE LDAP_TMPDIR LDAP_DIRSEP "slurpd.dump"
|
||||
|
||||
/* Amount of time to sleep if no more work to do */
|
||||
#define DEFAULT_NO_WORK_INTERVAL 3
|
||||
|
||||
/* The time we wait between checks to see if the replog file needs trimming */
|
||||
#define TRIMCHECK_INTERVAL ( 60 * 5 )
|
||||
|
||||
/* Only try to trim slurpd replica files larger than this size */
|
||||
#define MIN_TRIM_FILESIZE ( 10L * 1024L )
|
||||
|
||||
/* Maximum line length we can read from replication log */
|
||||
#define REPLBUFLEN 256
|
||||
|
||||
/* TLS flags */
|
||||
#define TLS_OFF 0
|
||||
#define TLS_ON 1
|
||||
#define TLS_CRITICAL 2
|
||||
|
||||
/* Rejection records are prefaced with this string */
|
||||
#define ERROR_STR "ERROR"
|
||||
|
||||
/* Strings found in replication entries */
|
||||
#define T_CHANGETYPESTR "changetype"
|
||||
#define T_CHANGETYPE 1
|
||||
#define T_TIMESTR "time"
|
||||
#define T_TIME 2
|
||||
#define T_DNSTR "dn"
|
||||
#define T_DN 3
|
||||
|
||||
#define T_ADDCTSTR "add"
|
||||
#define T_ADDCT 4
|
||||
#define T_MODIFYCTSTR "modify"
|
||||
#define T_MODIFYCT 5
|
||||
#define T_DELETECTSTR "delete"
|
||||
#define T_DELETECT 6
|
||||
#define T_MODRDNCTSTR "modrdn"
|
||||
#define T_MODDNCTSTR "moddn"
|
||||
#define T_RENAMECTSTR "rename"
|
||||
#define T_MODRDNCT 7
|
||||
|
||||
#define T_MODOPADDSTR "add"
|
||||
#define T_MODOPADD 8
|
||||
#define T_MODOPREPLACESTR "replace"
|
||||
#define T_MODOPREPLACE 9
|
||||
#define T_MODOPDELETESTR "delete"
|
||||
#define T_MODOPDELETE 10
|
||||
#define T_MODOPINCREMENTSTR "increment"
|
||||
#define T_MODOPINCREMENT 11
|
||||
#define T_MODSEPSTR "-"
|
||||
#define T_MODSEP 12
|
||||
|
||||
#define T_NEWRDNSTR "newrdn"
|
||||
#define T_DELOLDRDNSTR "deleteoldrdn"
|
||||
#define T_NEWSUPSTR "newsuperior"
|
||||
|
||||
#define T_ERR -1
|
||||
|
||||
/* Config file keywords */
|
||||
#define HOSTSTR "host"
|
||||
#define URISTR "uri"
|
||||
#define ATTRSTR "attr"
|
||||
#define SUFFIXSTR "suffix"
|
||||
#define BINDDNSTR "binddn"
|
||||
#define BINDMETHSTR "bindmethod"
|
||||
#define SIMPLESTR "simple"
|
||||
#define SASLSTR "sasl"
|
||||
#define CREDSTR "credentials"
|
||||
#define OLDAUTHCSTR "bindprincipal"
|
||||
#define AUTHCSTR "authcID"
|
||||
#define AUTHZSTR "authzID"
|
||||
#define SASLMECHSTR "saslmech"
|
||||
#define REALMSTR "realm"
|
||||
#define SECPROPSSTR "secprops"
|
||||
#define STARTTLSSTR "starttls"
|
||||
#define TLSSTR "tls"
|
||||
#define CRITICALSTR "critical"
|
||||
|
||||
#define REPLICA_SLEEP_TIME ( 10 )
|
||||
|
||||
/* Enumeration of various types of bind failures */
|
||||
#define BIND_OK 0
|
||||
#define BIND_ERR_BADLDP 1
|
||||
#define BIND_ERR_OPEN 2
|
||||
#define BIND_ERR_BAD_ATYPE 3
|
||||
#define BIND_ERR_SIMPLE_FAILED 4
|
||||
#define BIND_ERR_BADRI 6
|
||||
#define BIND_ERR_VERSION 7
|
||||
#define BIND_ERR_REFERRALS 8
|
||||
#define BIND_ERR_MANAGEDSAIT 9
|
||||
#define BIND_ERR_SASL_FAILED 10
|
||||
#define BIND_ERR_TLS_FAILED 11
|
||||
|
||||
/* Return codes for do_ldap() */
|
||||
#define DO_LDAP_OK 0
|
||||
#define DO_LDAP_ERR_RETRYABLE 1
|
||||
#define DO_LDAP_ERR_FATAL 2
|
||||
|
||||
/*
|
||||
* Types of counts one can request from the Rq rq_getcount()
|
||||
* member function
|
||||
*/
|
||||
/* all elements */
|
||||
#define RQ_COUNT_ALL 1
|
||||
/* all elements with nonzero refcnt */
|
||||
#define RQ_COUNT_NZRC 2
|
||||
|
||||
/* Amount of time, in seconds, for a thread to sleep when it encounters
|
||||
* a retryable error in do_ldap().
|
||||
*/
|
||||
#define RETRY_SLEEP_TIME 60
|
||||
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
|
||||
/*
|
||||
* ****************************************************************************
|
||||
* Data types for replication queue and queue elements.
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Replica host information. An Ri struct will contain an array of these,
|
||||
* with one entry for each replica. The end of the array is signaled
|
||||
* by a NULL value in the rh_hostname field.
|
||||
*/
|
||||
typedef struct rh {
|
||||
char *rh_hostname; /* replica hostname */
|
||||
int rh_port; /* replica port */
|
||||
} Rh;
|
||||
|
||||
|
||||
/*
|
||||
* Per-replica information.
|
||||
*
|
||||
* Notes:
|
||||
* - Private data should not be manipulated expect by Ri member functions.
|
||||
*/
|
||||
typedef struct ri Ri;
|
||||
struct ri {
|
||||
/* Private data */
|
||||
char *ri_hostname; /* canonical hostname of replica */
|
||||
int ri_port; /* port where slave slapd running */
|
||||
char *ri_uri; /* e.g. "ldaps://ldap-1.example.com:636" */
|
||||
LDAP *ri_ldp; /* LDAP struct for this replica */
|
||||
int ri_tls; /* TLS: 0=no, 1=yes, 2=critical */
|
||||
int ri_bind_method; /* AUTH_SIMPLE or AUTH_SASL */
|
||||
char *ri_bind_dn; /* DN to bind as when replicating */
|
||||
char *ri_password; /* Password for any method */
|
||||
char *ri_secprops; /* SASL security properties */
|
||||
char *ri_realm; /* realm for any mechanism */
|
||||
char *ri_authcId; /* authentication ID for any mechanism */
|
||||
char *ri_authzId; /* authorization ID for any mechanism */
|
||||
char *ri_saslmech; /* SASL mechanism to use */
|
||||
struct re *ri_curr; /* current repl entry being processed */
|
||||
struct stel *ri_stel; /* pointer to Stel for this replica */
|
||||
unsigned long
|
||||
ri_seq; /* seq number of last repl */
|
||||
ldap_pvt_thread_t ri_tid; /* ID of thread for this replica */
|
||||
|
||||
/* Member functions */
|
||||
int (*ri_process) LDAP_P(( Ri * )); /* process the next repl entry */
|
||||
void (*ri_wake) LDAP_P(( Ri * )); /* wake up a sleeping thread */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about one particular modification to make. This data should
|
||||
* be considered private to routines in re.c, and to routines in ri.c.
|
||||
*/
|
||||
typedef struct mi {
|
||||
/* Private data */
|
||||
char *mi_type; /* attr or type */
|
||||
char *mi_val; /* value */
|
||||
int mi_len; /* length of mi_val */
|
||||
} Mi;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about one particular replication entry. Only routines in
|
||||
* re.c and rq.c should touch the private data. Other routines should
|
||||
* only use member functions.
|
||||
*/
|
||||
typedef struct re Re;
|
||||
struct re {
|
||||
/* Private data */
|
||||
ldap_pvt_thread_mutex_t
|
||||
re_mutex; /* mutex for this Re */
|
||||
int re_refcnt; /* ref count, 0 = done */
|
||||
time_t re_timestamp; /* timestamp of this re */
|
||||
int re_seq; /* sequence number */
|
||||
Rh *re_replicas; /* array of replica info */
|
||||
char *re_dn; /* dn of entry being modified */
|
||||
int re_changetype; /* type of modification */
|
||||
Mi *re_mods; /* array of modifications to make */
|
||||
struct re *re_next; /* pointer to next element */
|
||||
|
||||
/* Public functions */
|
||||
int (*re_free) LDAP_P(( Re * )); /* free an re struct */
|
||||
Re *(*re_getnext) LDAP_P(( Re * )); /* return next Re in linked list */
|
||||
int (*re_parse) LDAP_P(( Re *, char * )); /* parse replication log entry */
|
||||
int (*re_write) LDAP_P(( Ri *, Re *, FILE * )); /* write repl. log entry */
|
||||
void (*re_dump) LDAP_P(( Re *, FILE * )); /* debugging - print contents */
|
||||
int (*re_lock) LDAP_P(( Re * )); /* lock this re */
|
||||
int (*re_unlock) LDAP_P(( Re * )); /* unlock this re */
|
||||
int (*re_decrefcnt) LDAP_P(( Re * )); /* decrement the refcnt */
|
||||
int (*re_getrefcnt) LDAP_P(( Re * )); /* get the refcnt */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Definition for the queue of replica information. Private data is
|
||||
* private to rq.c. Other routines should only touch public data or
|
||||
* use member functions. Note that although we have a member function
|
||||
* for locking the queue's mutex, we need to expose the rq_mutex
|
||||
* variable so routines in ri.c can use it as a mutex for the
|
||||
* rq_more condition variable.
|
||||
*/
|
||||
typedef struct rq Rq;
|
||||
struct rq {
|
||||
|
||||
/* Private data */
|
||||
Re *rq_head; /* pointer to head */
|
||||
Re *rq_tail; /* pointer to tail */
|
||||
int rq_nre; /* total number of Re's in queue */
|
||||
int rq_ndel; /* number of deleted Re's in queue */
|
||||
time_t rq_lasttrim; /* Last time we trimmed file */
|
||||
|
||||
/* Public data */
|
||||
ldap_pvt_thread_mutex_t
|
||||
rq_mutex; /* mutex for whole queue */
|
||||
ldap_pvt_thread_cond_t
|
||||
rq_more; /* condition var - more work added */
|
||||
|
||||
/* Member functions */
|
||||
Re * (*rq_gethead) LDAP_P(( Rq * )); /* get the element at head */
|
||||
Re * (*rq_getnext) LDAP_P(( Re * )); /* get the next element */
|
||||
int (*rq_delhead) LDAP_P(( Rq * )); /* delete the element at head */
|
||||
int (*rq_add) LDAP_P(( Rq *, char * )); /* add at tail */
|
||||
void (*rq_gc) LDAP_P(( Rq * )); /* garbage-collect queue */
|
||||
int (*rq_lock) LDAP_P(( Rq * )); /* lock the queue */
|
||||
int (*rq_unlock) LDAP_P(( Rq * )); /* unlock the queue */
|
||||
int (*rq_needtrim) LDAP_P(( Rq * )); /* see if queue needs trimming */
|
||||
int (*rq_write) LDAP_P(( Rq *, FILE * )); /*write Rq contents to file*/
|
||||
int (*rq_getcount) LDAP_P(( Rq *, int )); /* return queue counts */
|
||||
void (*rq_dump) LDAP_P(( Rq * )); /* debugging - print contents */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* An Stel (status element) contains information about one replica.
|
||||
* Stel structs are associated with the St (status) struct, defined
|
||||
* below.
|
||||
*/
|
||||
typedef struct stel {
|
||||
char *hostname; /* host name of replica */
|
||||
int port; /* port number of replica */
|
||||
time_t last; /* timestamp of last successful repl */
|
||||
int seq; /* Sequence number of last repl */
|
||||
} Stel;
|
||||
|
||||
|
||||
/*
|
||||
* An St struct in an in-core structure which contains the current
|
||||
* slurpd state. Most importantly, it contains an array of Stel
|
||||
* structs which contain the timestamp and sequence number of the last
|
||||
* successful replication for each replica. The st_write() member
|
||||
* function is called periodically to flush status information to
|
||||
* disk. At startup time, slurpd checks for the status file, and
|
||||
* if present, uses the timestamps to avoid "replaying" replications
|
||||
* which have already been sent to a given replica.
|
||||
*/
|
||||
typedef struct st St;
|
||||
struct st {
|
||||
/* Private data */
|
||||
ldap_pvt_thread_mutex_t
|
||||
st_mutex; /* mutex to serialize access */
|
||||
Stel **st_data; /* array of pointers to Stel structs */
|
||||
int st_nreplicas; /* number of repl hosts */
|
||||
int st_err_logged; /* 1 if fopen err logged */
|
||||
FILE *st_fp; /* st file kept open */
|
||||
FILE *st_lfp; /* lockfile fp */
|
||||
|
||||
/* Public member functions */
|
||||
int (*st_update) LDAP_P(( St *, Stel*, Re* ));/*update entry for a host*/
|
||||
Stel*(*st_add) LDAP_P(( St *, Ri * )); /*add a new repl host*/
|
||||
int (*st_write) LDAP_P(( St * )); /* write status to disk */
|
||||
int (*st_read) LDAP_P(( St * )); /* read status info from disk */
|
||||
int (*st_lock) LDAP_P(( St * )); /* read status info from disk */
|
||||
int (*st_unlock) LDAP_P(( St * )); /* read status info from disk */
|
||||
};
|
||||
|
||||
#if defined( HAVE_LWP )
|
||||
typedef struct tl {
|
||||
thread_t tl_tid; /* thread being managed */
|
||||
time_t tl_wake; /* time thread should be resumed */
|
||||
struct tl *tl_next; /* next node in list */
|
||||
} tl_t;
|
||||
|
||||
typedef struct tsl {
|
||||
tl_t *tsl_list;
|
||||
mon_t tsl_mon;
|
||||
} tsl_t;
|
||||
#endif /* HAVE_LWP */
|
||||
|
||||
/*
|
||||
* Public functions used to instantiate and initialize queue objects.
|
||||
*/
|
||||
extern int Ri_init LDAP_P(( Ri **ri ));
|
||||
extern int Rq_init LDAP_P(( Rq **rq ));
|
||||
extern int Re_init LDAP_P(( Re **re ));
|
||||
|
||||
#include "proto-slurp.h"
|
||||
|
||||
LDAP_END_DECL
|
||||
|
||||
#endif /* _SLURPD_H_ */
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 1998-2007 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 file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/* Portions Copyright (c) 1996 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.
|
||||
*/
|
||||
/* ACKNOWLEDGEMENTS:
|
||||
* This work was originally developed by the University of Michigan
|
||||
* (as part of U-MICH LDAP).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* st.c - routines for managing the status structure, and for reading and
|
||||
* writing status information to disk.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/string.h>
|
||||
#include <ac/unistd.h>
|
||||
|
||||
#include "slurp.h"
|
||||
#include "globals.h"
|
||||
#include "lutil.h"
|
||||
|
||||
/*
|
||||
* Add information about replica host specified by Ri to list
|
||||
* of hosts.
|
||||
*/
|
||||
static Stel *
|
||||
St_add(
|
||||
St *st,
|
||||
Ri *ri
|
||||
)
|
||||
{
|
||||
int ind;
|
||||
|
||||
if ( st == NULL || ri == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Serialize access to the St struct */
|
||||
ldap_pvt_thread_mutex_lock( &(st->st_mutex ));
|
||||
|
||||
st->st_nreplicas++;
|
||||
ind = st->st_nreplicas - 1;
|
||||
st->st_data = ( Stel ** ) ch_realloc( st->st_data,
|
||||
( st->st_nreplicas * sizeof( Stel * )));
|
||||
if ( st->st_data == NULL ) {
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return NULL;
|
||||
}
|
||||
st->st_data[ ind ] = ( Stel * ) ch_malloc( sizeof( Stel ) );
|
||||
if ( st->st_data[ ind ] == NULL ) {
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st->st_data[ ind ]->hostname = strdup( ri->ri_hostname );
|
||||
st->st_data[ ind ]->port = ri->ri_port;
|
||||
st->st_data[ ind ]->last = 0;
|
||||
st->st_data[ ind ]->seq = 0;
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return st->st_data[ ind ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Write the contents of an St to disk.
|
||||
*/
|
||||
static int
|
||||
St_write (
|
||||
St *st
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
Stel *stel;
|
||||
int i;
|
||||
|
||||
if ( st == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
ldap_pvt_thread_mutex_lock( &(st->st_mutex ));
|
||||
if ( st->st_fp == NULL ) {
|
||||
/* Open file */
|
||||
if (( rc = acquire_lock( sglob->slurpd_status_file, &(st->st_fp),
|
||||
&(st->st_lfp))) < 0 ) {
|
||||
if ( !st->st_err_logged ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Error: cannot open status file \"%s\": %s\n",
|
||||
sglob->slurpd_status_file, sys_errlist[ errno ], 0 );
|
||||
st->st_err_logged = 1;
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
st->st_err_logged = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write data to the file */
|
||||
truncate( sglob->slurpd_status_file, 0L );
|
||||
fseek( st->st_fp, 0L, 0 );
|
||||
for ( i = 0; i < st->st_nreplicas; i++ ) {
|
||||
stel = st->st_data[ i ];
|
||||
fprintf( st->st_fp, "%s:%d:%ld:%d\n",
|
||||
stel->hostname, stel->port,
|
||||
(long) stel->last, stel->seq );
|
||||
}
|
||||
fflush( st->st_fp );
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Update the entry for a given host.
|
||||
*/
|
||||
static int
|
||||
St_update(
|
||||
St *st,
|
||||
Stel *stel,
|
||||
Re *re
|
||||
)
|
||||
{
|
||||
if ( stel == NULL || re == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &(st->st_mutex ));
|
||||
stel->last = re->re_timestamp;
|
||||
stel->seq = re->re_seq;
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read status information from disk file.
|
||||
*/
|
||||
static int
|
||||
St_read(
|
||||
St *st
|
||||
)
|
||||
{
|
||||
FILE *fp;
|
||||
FILE *lfp;
|
||||
char buf[ 255 ];
|
||||
int i;
|
||||
int rc;
|
||||
char *hostname, *port, *timestamp, *seq, *p, *t;
|
||||
int found;
|
||||
|
||||
if ( st == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
ldap_pvt_thread_mutex_lock( &(st->st_mutex ));
|
||||
if ( access( sglob->slurpd_status_file, F_OK ) < 0 ) {
|
||||
/*
|
||||
* File doesn't exist, so create it and return.
|
||||
*/
|
||||
if (( fp = fopen( sglob->slurpd_status_file, "w" )) == NULL ) {
|
||||
Debug( LDAP_DEBUG_ANY, "Error: cannot create status file \"%s\"\n",
|
||||
sglob->slurpd_status_file, 0, 0 );
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return -1;
|
||||
}
|
||||
(void) fclose( fp );
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
Debug( LDAP_DEBUG_ARGS, "No status file found, defaulting values\n",
|
||||
0, 0, 0 );
|
||||
return 0;
|
||||
}
|
||||
if (( rc = acquire_lock( sglob->slurpd_status_file, &fp, &lfp)) < 0 ) {
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return 0;
|
||||
}
|
||||
while ( fgets( buf, sizeof( buf ), fp ) != NULL ) {
|
||||
p = buf;
|
||||
hostname = p;
|
||||
if (( t = strchr( p, ':' )) == NULL ) {
|
||||
goto bad;
|
||||
}
|
||||
*t++ = '\0';
|
||||
p = t;
|
||||
port = p;
|
||||
if (( t = strchr( p, ':' )) == NULL ) {
|
||||
goto bad;
|
||||
}
|
||||
*t++ = '\0';
|
||||
p = t;
|
||||
timestamp = p;
|
||||
if (( t = strchr( p, ':' )) == NULL ) {
|
||||
goto bad;
|
||||
}
|
||||
*t++ = '\0';
|
||||
seq = t;
|
||||
if (( t = strchr( seq, '\n' )) != NULL ) {
|
||||
*t = '\0';
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for ( i = 0; i < sglob->st->st_nreplicas; i++ ) {
|
||||
int p;
|
||||
if ( !strcmp( hostname, sglob->st->st_data[ i ]->hostname ) &&
|
||||
lutil_atoi( &p, port ) == 0 && p == sglob->st->st_data[ i ]->port )
|
||||
{
|
||||
found = 1;
|
||||
if ( lutil_atol( &sglob->st->st_data[ i ]->last, timestamp ) != 0
|
||||
|| lutil_atoi( &sglob->st->st_data[ i ]->seq, seq ) != 0 )
|
||||
{
|
||||
found = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( found ) {
|
||||
char tbuf[ 255 ];
|
||||
sprintf( tbuf, "%s.%s", timestamp, seq );
|
||||
Debug( LDAP_DEBUG_ARGS,
|
||||
"Retrieved state information for %s:%s (timestamp %s)\n",
|
||||
hostname, port, tbuf );
|
||||
} else {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"Warning: saved state for %s:%s, not a known replica\n",
|
||||
hostname, port, 0 );
|
||||
}
|
||||
}
|
||||
(void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
(void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
|
||||
ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Lock an St struct.
|
||||
*/
|
||||
static int
|
||||
St_lock(
|
||||
St *st
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_lock( &st->st_mutex ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Lock an St struct.
|
||||
*/
|
||||
static int
|
||||
St_unlock(
|
||||
St *st
|
||||
)
|
||||
{
|
||||
return( ldap_pvt_thread_mutex_unlock( &st->st_mutex ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialize an St struct.
|
||||
*/
|
||||
int
|
||||
St_init(
|
||||
St **st
|
||||
)
|
||||
{
|
||||
if ( st == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*st) = (St *) malloc( sizeof( St ));
|
||||
if ( *st == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_init( &((*st)->st_mutex) );
|
||||
(*st)->st_data = NULL;
|
||||
(*st)->st_fp = NULL;
|
||||
(*st)->st_lfp = NULL;
|
||||
(*st)->st_nreplicas = 0;
|
||||
(*st)->st_err_logged = 0;
|
||||
(*st)->st_update = St_update;
|
||||
(*st)->st_add = St_add;
|
||||
(*st)->st_write = St_write;
|
||||
(*st)->st_read = St_read;
|
||||
(*st)->st_lock = St_lock;
|
||||
(*st)->st_unlock = St_unlock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue