slurpd is strongly deprecated

This commit is contained in:
Howard Chu 2007-04-05 23:20:04 +00:00
parent d06a8bd198
commit 3d1fe19acc
25 changed files with 1 additions and 6264 deletions

View file

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

View file

@ -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

View file

@ -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 \
)

View file

@ -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!).

View file

@ -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 );
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 );
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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 );
}

View file

@ -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 */
}

View file

@ -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

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 );
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
}