mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
b5494457d8
This could cause problems on odd systems. The generic headers should be extended as needed to include necessary system headers or, if necessary, make explicit declarations. Extended ac/string.h header to look for string.h/strings.h if STDC_HEADERS is not defined. Also provide basic declarations for str*() functions. This could cause problems on odd systems. Extended ac/unistd.h header to define basic declaration for misc functions that might be missing from headers. This includes externs for getenv(), getopt(), mktemp(), tempname(). Protect fax500.h from multiple inclusion. Moved includes of system/generic headers back to source files. Made mail500 helper functions static. Fixed includes of ctype.h, signal.h, etc. to use generics. lutil/tempname.c: was including stdlib.h twice, one should stdio.h. Wrapped <sys/resource.h> with HAVE_SYS_RESOURCE_H. lber/io.c/ber_get_next(): Changed noctets back to signed. Used with BerRead which expects signed int as second arg and returns signed int.
1050 lines
24 KiB
C
1050 lines
24 KiB
C
/* centipede.c - generate and install indexing information (view w/tabstop=4) */
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <ac/ctype.h>
|
|
#include <ac/string.h>
|
|
#include <ac/time.h>
|
|
#include <ac/unistd.h> /* get link(), unlink() */
|
|
|
|
#include <lber.h>
|
|
#include <ldap.h>
|
|
|
|
#include <ldbm.h>
|
|
|
|
#define DEFAULT_LDAPFILTER "(objectclass=*)"
|
|
|
|
#define CENTROID_VALUE 1
|
|
#define CENTROID_WORD 2
|
|
|
|
#define CENTROID_RELATIVE 1
|
|
#define CENTROID_FULL 2
|
|
|
|
#define WORD_BREAKS " -',.()!;:&$%*\"/\\+_<>=?[]|^~"
|
|
|
|
char *centdir;
|
|
int ldbmcachesize;
|
|
int centroidvalues;
|
|
int centroidtype;
|
|
int doweights;
|
|
char *ldaphost;
|
|
char *srcldapbinddn;
|
|
char *srcldappasswd;
|
|
char *destldapbinddn;
|
|
char *destldappasswd;
|
|
char *ldapbase;
|
|
int srcldapauthmethod;
|
|
int destldapauthmethod;
|
|
int verbose;
|
|
int not;
|
|
|
|
static LDAP *start_ldap_search(char *ldapsrcurl, char *ldapfilter, char **attrs);
|
|
static LDAP *bind_to_destination_ldap(char *ldapsrcurl, char *ldapdesturl);
|
|
static int create_tmp_files(char **attrs, char ***tmpfile, LDBM **ldbm);
|
|
static int generate_new_centroids(LDAP *ld, char **attrs, LDBM *ldbm);
|
|
static LDAPMod **diff_centroids(char *attr, LDBM oldbm, LDBM nldbm, int nentries);
|
|
static LDAPMod **full_centroid(char *attr, LDBM ldbm, int nentries);
|
|
static char **charray_add_dup(char ***a, int *cur, int *max, char *s);
|
|
|
|
static void usage( char *name )
|
|
{
|
|
fprintf( stderr, "usage: %s [options] -s url -d url attributes\n", name );
|
|
fprintf( stderr, "where:\n" );
|
|
fprintf( stderr, "\t-s url\t\t[[ldap://][host[:port]]/]searchbasedn\n");
|
|
fprintf( stderr, "\t-d url\t\t[[ldap://][host[:port]]/]centroidentrydn\n");
|
|
fprintf( stderr, "options:\n" );
|
|
fprintf( stderr, "\t-v \t\tturn on verbose mode\n" );
|
|
fprintf( stderr, "\t-n \t\tgenerate, but do not install index info\n" );
|
|
fprintf( stderr, "\t-f filter\tentry selection filter\n" );
|
|
fprintf( stderr, "\t-F \t\tgenerate a full centroid\n" );
|
|
fprintf( stderr, "\t-R \t\tgenerate a relative centroid\n" );
|
|
fprintf( stderr, "\t-w \t\tgenerate a word-based centroid\n" );
|
|
fprintf( stderr, "\t-t directory\tcentroid directory\n" );
|
|
fprintf( stderr, "\t-b binddn\tsource bind dn\n" );
|
|
fprintf( stderr, "\t-p passwd\tsource bind passwd (for simple auth)\n" );
|
|
fprintf( stderr, "\t-m authmethod\tsource authmethod \"simple\" or \"kerberos\"\n" );
|
|
fprintf( stderr, "\t-B binddn\tdestination bind dn\n" );
|
|
fprintf( stderr, "\t-P passwd\tdestination bind passwd (for simple auth)\n" );
|
|
fprintf( stderr, "\t-M authmethod\tdestination authmethod \"simple\" or \"kerberos\"\n" );
|
|
fprintf( stderr, "\t-c size\t\tldbm cache size\n" );
|
|
}
|
|
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
char *ldapfilter;
|
|
char *ldapsrcurl, *ldapdesturl;
|
|
LDAP *ld;
|
|
LDAPMod **mods;
|
|
char **attrs;
|
|
char **tmpfile;
|
|
LDBM *ldbm;
|
|
LDBM oldbm;
|
|
char buf[BUFSIZ];
|
|
int i, j, k, count;
|
|
char *s;
|
|
|
|
ldapsrcurl = NULL;
|
|
ldapdesturl = NULL;
|
|
ldaphost = NULL;
|
|
ldapbase = NULL;
|
|
srcldapauthmethod = LDAP_AUTH_SIMPLE;
|
|
destldapauthmethod = LDAP_AUTH_SIMPLE;
|
|
srcldapbinddn = NULL;
|
|
srcldappasswd = NULL;
|
|
destldapbinddn = NULL;
|
|
destldappasswd = NULL;
|
|
ldapfilter = DEFAULT_LDAPFILTER;
|
|
centroidvalues = CENTROID_VALUE;
|
|
centroidtype = CENTROID_RELATIVE;
|
|
centdir = NULL;
|
|
tmpfile = NULL;
|
|
ldbmcachesize = 0;
|
|
|
|
while ( (i = getopt( argc, argv, "s:d:c:b:B:f:FRWp:P:m:M:t:vwn" ))
|
|
!= EOF ) {
|
|
switch ( i ) {
|
|
case 's': /* source url [[ldap://][host[:port]]/]basedn */
|
|
ldapsrcurl = strdup( optarg );
|
|
break;
|
|
|
|
case 'd': /* destination url [[ldap://][host[:port]]/]entrydn */
|
|
ldapdesturl = strdup( optarg );
|
|
break;
|
|
|
|
case 'f': /* specify a filter */
|
|
ldapfilter = strdup( optarg );
|
|
break;
|
|
|
|
case 'F': /* generate full centroid */
|
|
centroidtype = CENTROID_FULL;
|
|
break;
|
|
|
|
case 'R': /* generate relative centroid */
|
|
centroidtype = CENTROID_RELATIVE;
|
|
break;
|
|
|
|
case 'w': /* generate word centroid */
|
|
centroidvalues = CENTROID_WORD;
|
|
break;
|
|
|
|
case 'W': /* generate weights */
|
|
doweights = 1;
|
|
break;
|
|
|
|
case 't': /* temp file directory */
|
|
centdir = strdup( optarg );
|
|
break;
|
|
|
|
case 'b': /* src bind dn */
|
|
srcldapbinddn = strdup( optarg );
|
|
break;
|
|
|
|
case 'p': /* src bind password */
|
|
srcldappasswd = strdup( optarg );
|
|
while ( *optarg )
|
|
*optarg++ = 'x';
|
|
break;
|
|
|
|
case 'B': /* dest bind dn */
|
|
destldapbinddn = strdup( optarg );
|
|
break;
|
|
|
|
case 'P': /* dest bind password */
|
|
destldappasswd = strdup( optarg );
|
|
while ( *optarg )
|
|
*optarg++ = 'x';
|
|
break;
|
|
|
|
case 'm': /* src bind method */
|
|
if ( strcasecmp( optarg, "simple" ) == 0 ) {
|
|
srcldapauthmethod = LDAP_AUTH_SIMPLE;
|
|
} else if ( strcasecmp( optarg, "kerberos" ) == 0 ) {
|
|
srcldapauthmethod = LDAP_AUTH_KRBV4;
|
|
} else {
|
|
fprintf( stderr, "%s: unknown auth method\n", optarg );
|
|
fputs( "expecting \"simple\" or \"kerberos\"\n", stderr );
|
|
exit( 1 );
|
|
}
|
|
break;
|
|
|
|
case 'M': /* dest bind method */
|
|
if ( strcasecmp( optarg, "simple" ) == 0 ) {
|
|
destldapauthmethod = LDAP_AUTH_SIMPLE;
|
|
} else if ( strcasecmp( optarg, "kerberos" ) == 0 ) {
|
|
destldapauthmethod = LDAP_AUTH_KRBV4;
|
|
} else {
|
|
fprintf( stderr, "%s: unknown auth method\n", optarg );
|
|
fputs( "expecting \"simple\" or \"kerberos\"\n", stderr );
|
|
exit( 1 );
|
|
}
|
|
break;
|
|
|
|
case 'c': /* ldbm cache size */
|
|
ldbmcachesize = atoi( optarg );
|
|
break;
|
|
|
|
case 'v': /* turn on verbose mode */
|
|
verbose++;
|
|
break;
|
|
|
|
case 'n': /* don't actually install index info */
|
|
not++;
|
|
break;
|
|
|
|
default:
|
|
usage( argv[0] );
|
|
exit( 1 );
|
|
}
|
|
}
|
|
if ( optind == argc || ldapsrcurl == NULL || ldapdesturl == NULL ) {
|
|
usage( argv[0] );
|
|
exit( 1 );
|
|
}
|
|
attrs = &argv[optind];
|
|
|
|
/*
|
|
* open the ldap connection and start searching for the entries
|
|
* we will use to generate the centroids.
|
|
*/
|
|
|
|
if ( (ld = start_ldap_search( ldapsrcurl, ldapfilter, attrs )) == NULL ) {
|
|
fprintf( stderr, "could not initiate ldap search\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
if ( create_tmp_files( attrs, &tmpfile, &ldbm ) != 0 ) {
|
|
fprintf( stderr, "could not create temp files\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
/*
|
|
* go through the entries returned, building a centroid for each
|
|
* attribute as we go.
|
|
*/
|
|
|
|
if ( (count = generate_new_centroids( ld, attrs, ldbm )) < 1 ) {
|
|
if ( count == 0 ) {
|
|
fprintf( stderr, "no entries matched\n" );
|
|
exit( 0 );
|
|
} else {
|
|
fprintf( stderr, "could not generate new centroid\n" );
|
|
exit( 1 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* for each centroid we generated above, compare to the existing
|
|
* centroid, if any, and produce adds and deletes, or produce
|
|
* an entirely new centroid. in either case, update the "current"
|
|
* centroid version with the new one we just generated.
|
|
*/
|
|
|
|
if ( (ld = bind_to_destination_ldap( ldapsrcurl, ldapdesturl )) == NULL ) {
|
|
fprintf( stderr,
|
|
"could not bind to index server, or could not create index entry\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
for ( i = 0; ldbm[i] != NULL; i++ ) {
|
|
/* generate the name of the existing centroid, if any */
|
|
s = strrchr( tmpfile[i], '/' );
|
|
*s = '\0';
|
|
sprintf( buf, "%s/cent.%s", tmpfile[i], attrs[i] );
|
|
*s = '/';
|
|
|
|
/* generate the full centroid changes */
|
|
if ( centroidtype == CENTROID_FULL || (oldbm = ldbm_open( buf,
|
|
LDBM_WRITER, 0, ldbmcachesize )) == NULL ) {
|
|
if ( (mods = full_centroid( attrs[i], ldbm[i], count )) == NULL ) {
|
|
fprintf( stderr, "could not produce full centroid for %s\n",
|
|
attrs[i] );
|
|
continue;
|
|
}
|
|
|
|
/* generate the differential centroid changes */
|
|
} else {
|
|
if ( (mods = diff_centroids( attrs[i], oldbm, ldbm[i], count ))
|
|
== NULL ) {
|
|
fprintf( stderr, "could not diff centroids\n" );
|
|
ldbm_close( oldbm );
|
|
continue;
|
|
}
|
|
ldbm_close( oldbm );
|
|
}
|
|
|
|
if ( verbose > 1 ) {
|
|
printf("changes:\n");
|
|
for ( j = 0; mods[j] != NULL; j++ ) {
|
|
switch( mods[j]->mod_op ) {
|
|
case LDAP_MOD_ADD:
|
|
printf( "\tadd: %s\n",mods[j]->mod_type );
|
|
break;
|
|
case LDAP_MOD_DELETE:
|
|
printf( "\tdelete: %s\n",mods[j]->mod_type );
|
|
break;
|
|
case LDAP_MOD_REPLACE:
|
|
printf( "\treplace: %s\n",mods[j]->mod_type );
|
|
break;
|
|
}
|
|
if ( mods[j]->mod_values != NULL ) {
|
|
for ( k = 0; mods[j]->mod_values[k] != NULL; k++ ) {
|
|
printf( "\t\t%s\n", mods[j]->mod_values[k] );
|
|
}
|
|
}
|
|
}
|
|
printf("end changes:\n");
|
|
}
|
|
|
|
if ( verbose ) {
|
|
printf( "%sModifying centroid...", not ? "Not " : "" );
|
|
fflush( stdout );
|
|
}
|
|
|
|
/* attempt to make the changes to the index server entry */
|
|
if ( !not && ldap_modify_s( ld, ldapbase, mods ) != LDAP_SUCCESS ) {
|
|
fprintf( stderr, "could not apply centroid modification for %s\n",
|
|
attrs[i] );
|
|
ldap_perror( ld, ldapbase );
|
|
}
|
|
ldap_mods_free( mods, 1 );
|
|
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
fflush( stdout );
|
|
}
|
|
|
|
/* move the new centroid into the old one's place */
|
|
if ( ! not ) {
|
|
(void) unlink( buf );
|
|
if ( link( tmpfile[i], buf ) != 0 ) {
|
|
perror( "link" );
|
|
fprintf( stderr, "could not rename %s to %s\n", buf,
|
|
tmpfile[i] );
|
|
continue;
|
|
}
|
|
}
|
|
(void) unlink( tmpfile[i] );
|
|
}
|
|
|
|
/* clean up */
|
|
for ( i = 0; attrs[i] != NULL; i++ ) {
|
|
ldbm_close( ldbm[i] );
|
|
free( tmpfile[i] );
|
|
}
|
|
free( ldbm );
|
|
free( tmpfile );
|
|
|
|
exit( 0 );
|
|
}
|
|
|
|
/*
|
|
* open an ldap connection, bind, and initiate the search
|
|
*/
|
|
|
|
static LDAP *
|
|
start_ldap_search(
|
|
char *ldapsrcurl,
|
|
char *ldapfilter,
|
|
char **attrs
|
|
)
|
|
{
|
|
LDAP *ld;
|
|
char *s, *s2;
|
|
int i;
|
|
|
|
if ( strncmp( ldapsrcurl, "ldap://", 7 ) != 0 ) {
|
|
fputs( "Not an LDAP URL", stderr ); /* Should be smarter? */
|
|
return( NULL );
|
|
}
|
|
s = ldapsrcurl + 7;
|
|
if ( (s2 = strchr( s, '/' )) == NULL ) {
|
|
ldapbase = strdup( s );
|
|
} else {
|
|
if ( *s != '/' ) {
|
|
*s2 = '\0';
|
|
ldaphost = strdup( s );
|
|
*s2 = '/';
|
|
}
|
|
ldapbase = strdup( s2 + 1 );
|
|
}
|
|
|
|
if ( verbose ) {
|
|
printf( "Base: %s\n", ldapbase );
|
|
printf( "Attributes:" );
|
|
for ( i = 0; attrs[i] != NULL; i++ ) {
|
|
printf( " %s", attrs[i] );
|
|
}
|
|
printf( "\n" );
|
|
printf( "Binding to source LDAP server..." );
|
|
fflush( stdout );
|
|
}
|
|
|
|
if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
|
|
perror( "ldap_open" );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( ldap_bind_s( ld, srcldapbinddn, srcldappasswd, srcldapauthmethod )
|
|
!= LDAP_SUCCESS) {
|
|
ldap_perror( ld, "ldap_bind_s" );
|
|
ldap_unbind( ld );
|
|
return( NULL );
|
|
}
|
|
|
|
printf( "\nInitiating search..." );
|
|
if ( ldap_search( ld, ldapbase, LDAP_SCOPE_SUBTREE, ldapfilter, attrs, 0 )
|
|
== -1 ) {
|
|
ldap_perror( ld, "ldap_search" );
|
|
ldap_unbind( ld );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
}
|
|
|
|
return( ld );
|
|
}
|
|
|
|
/*
|
|
* create the temporary ldbm files we will use to hold the new centroids
|
|
*/
|
|
|
|
static int
|
|
create_tmp_files(
|
|
char **attrs,
|
|
char ***tmpfile,
|
|
LDBM **ldbm
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; attrs[i] != NULL; i++ )
|
|
; /* NULL */
|
|
i++;
|
|
|
|
if ( (*tmpfile = (char **) malloc( i * sizeof(char *) )) == NULL ) {
|
|
perror( "malloc" );
|
|
return( -1 );
|
|
}
|
|
if ( (*ldbm = (LDBM *) malloc( i * sizeof(LDBM) )) == NULL ) {
|
|
perror( "malloc" );
|
|
return( -1 );
|
|
}
|
|
for ( i = 0; attrs[i] != NULL; i++ ) {
|
|
if ( ((*tmpfile)[i] = tempnam( centdir, NULL )) == NULL ) {
|
|
perror( "tmpnam" );
|
|
return( -1 );
|
|
}
|
|
|
|
if ( ((*ldbm)[i] = ldbm_open( (*tmpfile)[i], LDBM_WRCREAT, 0600,
|
|
ldbmcachesize )) == NULL ) {
|
|
fprintf( stderr, "ldbm_open of \"%s\" failed\n", (*tmpfile)[i] );
|
|
perror( "ldbm_open" );
|
|
return( -1 );
|
|
}
|
|
}
|
|
(*tmpfile)[i] = NULL;
|
|
(*ldbm)[i] = NULL;
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* step through each entry returned from the search and generate
|
|
* the appropriate centroid values.
|
|
*/
|
|
|
|
static int
|
|
generate_new_centroids(
|
|
LDAP *ld,
|
|
char **attrs,
|
|
LDBM *ldbm
|
|
)
|
|
{
|
|
Datum key, data;
|
|
int rc, i, j, count;
|
|
LDAPMessage *res, *e;
|
|
char *dn, *s, *w;
|
|
char **val;
|
|
char last;
|
|
|
|
if ( verbose ) {
|
|
printf( "Generating new centroids for..." );
|
|
fflush( stdout );
|
|
}
|
|
|
|
data.dptr = "";
|
|
data.dsize = 1;
|
|
count = 0;
|
|
while ( (rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res ))
|
|
== LDAP_RES_SEARCH_ENTRY ) {
|
|
count++;
|
|
e = ldap_first_entry( ld, res );
|
|
dn = ldap_get_dn( ld, e );
|
|
|
|
/* for each attr we want to generate a centroid for */
|
|
for ( i = 0; attrs[i] != NULL; i++ ) {
|
|
if ( (val = ldap_get_values( ld, e, attrs[i] )) == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
/* for each value */
|
|
for ( j = 0; val[j] != NULL; j++ ) {
|
|
/* normalize the value */
|
|
for ( s = val[j]; *s; s++ ) {
|
|
if ( isascii( *s ) ) {
|
|
*s = TOLOWER( *s );
|
|
}
|
|
last = *s;
|
|
}
|
|
if ( isascii( last ) && isdigit( last ) ) {
|
|
continue;
|
|
}
|
|
|
|
/* generate a value-based centroid */
|
|
if ( centroidvalues == CENTROID_VALUE ) {
|
|
key.dptr = val[j];
|
|
key.dsize = strlen( key.dptr ) + 1;
|
|
(void) ldbm_store( ldbm[i], key, data, LDBM_INSERT );
|
|
|
|
/* generate a word-based centroid */
|
|
} else {
|
|
for ( w = strtok( val[j], WORD_BREAKS ); w != NULL;
|
|
w = strtok( NULL, WORD_BREAKS ) ) {
|
|
key.dptr = w;
|
|
key.dsize = strlen( key.dptr ) + 1;
|
|
(void) ldbm_store( ldbm[i], key, data, LDBM_INSERT );
|
|
}
|
|
}
|
|
}
|
|
ldap_value_free( val );
|
|
}
|
|
free( dn );
|
|
ldap_msgfree( res );
|
|
}
|
|
ldap_msgfree( res );
|
|
ldap_unbind( ld );
|
|
|
|
if ( verbose ) {
|
|
printf( "%d entries\n", count );
|
|
}
|
|
|
|
return( count );
|
|
}
|
|
|
|
/*
|
|
* compare the old and new centroids, generating the appropriate add
|
|
* and delete operations. if the underlying database is ordered, we
|
|
* can do this more efficiently.
|
|
*/
|
|
|
|
static LDAPMod **
|
|
diff_centroids(
|
|
char *attr,
|
|
LDBM oldbm,
|
|
LDBM nldbm,
|
|
int nentries
|
|
)
|
|
{
|
|
Datum okey, nkey;
|
|
Datum olast, nlast;
|
|
Datum lastkey, key;
|
|
Datum data;
|
|
LDAPMod **mods;
|
|
char **avals, **dvals;
|
|
int amax, acur, dmax, dcur;
|
|
char **vals;
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
DBC *ocursorp;
|
|
DBC *ncursorp;
|
|
#endif /* HAVE_BERKELEY_DB2 */
|
|
|
|
if ( verbose ) {
|
|
printf( "Generating mods for differential %s centroid...", attr );
|
|
fflush( stdout );
|
|
}
|
|
|
|
if ( (mods = (LDAPMod **) malloc( sizeof(LDAPMod *) * 4 )) == NULL ||
|
|
(mods[0] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
|
|
(mods[1] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
|
|
(mods[2] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
|
|
(vals = (char **) malloc( 2 * sizeof(char *) )) == NULL ||
|
|
(vals[0] = (char *) malloc( 20 )) == NULL )
|
|
{
|
|
perror( "malloc" );
|
|
exit( -1 );
|
|
}
|
|
/* add values in mods[0] */
|
|
mods[0]->mod_op = LDAP_MOD_ADD;
|
|
mods[0]->mod_type = attr;
|
|
mods[0]->mod_values = NULL;
|
|
avals = NULL;
|
|
acur = amax = 0;
|
|
/* delete values in mods[1] */
|
|
mods[1]->mod_op = LDAP_MOD_DELETE;
|
|
mods[1]->mod_type = attr;
|
|
mods[1]->mod_values = NULL;
|
|
dvals = NULL;
|
|
dcur = dmax = 0;
|
|
/* number of entries in mods[2] */
|
|
sprintf( vals[0], "%d", nentries );
|
|
vals[1] = NULL;
|
|
mods[2]->mod_op = LDAP_MOD_REPLACE;
|
|
mods[2]->mod_type = "nentries";
|
|
mods[2]->mod_values = vals;
|
|
/* null terminate list of mods */
|
|
mods[3] = NULL;
|
|
|
|
#ifdef LDBM_ORDERED
|
|
/*
|
|
* if the underlying database is ordered, we can do a more efficient
|
|
* dual traversal, yielding O(N) performance.
|
|
*/
|
|
|
|
olast.dptr = NULL;
|
|
nlast.dptr = NULL;
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
for ( okey = ldbm_firstkey( oldbm, &ocursorp ),
|
|
nkey = ldbm_firstkey( nldbm, &ncursorp );
|
|
okey.dptr != NULL && nkey.dptr != NULL; )
|
|
#else
|
|
for ( okey = ldbm_firstkey( oldbm ), nkey = ldbm_firstkey( nldbm );
|
|
okey.dptr != NULL && nkey.dptr != NULL; )
|
|
#endif
|
|
{
|
|
int rc = strcmp( okey.dptr, nkey.dptr );
|
|
|
|
if ( rc == 0 ) {
|
|
/* value is in both places - leave it */
|
|
if ( olast.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, olast );
|
|
}
|
|
olast = okey;
|
|
if ( nlast.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, nlast );
|
|
}
|
|
nlast = nkey;
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
okey = ldbm_nextkey( oldbm, olast, ocursorp );
|
|
nkey = ldbm_nextkey( nldbm, nlast, ncursorp );
|
|
#else
|
|
okey = ldbm_nextkey( oldbm, olast );
|
|
nkey = ldbm_nextkey( nldbm, nlast );
|
|
#endif
|
|
} else if ( rc > 0 ) {
|
|
/* new value is not in old centroid - add it */
|
|
if ( charray_add_dup( &avals, &acur, &amax, nkey.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( nlast.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, nlast );
|
|
}
|
|
nlast = nkey;
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
nkey = ldbm_nextkey( nldbm, nlast, ncursorp );
|
|
#else
|
|
nkey = ldbm_nextkey( nldbm, nlast );
|
|
#endif
|
|
} else {
|
|
/* old value is not in new centroid - delete it */
|
|
if ( charray_add_dup( &dvals, &dcur, &dmax, okey.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( olast.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, olast );
|
|
}
|
|
olast = okey;
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
okey = ldbm_nextkey( oldbm, olast, ocursorp );
|
|
#else
|
|
okey = ldbm_nextkey( oldbm, olast );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
while ( okey.dptr != NULL ) {
|
|
if ( charray_add_dup( &dvals, &dcur, &dmax, okey.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
okey = ldbm_nextkey( oldbm, olast, ocursorp );
|
|
#else
|
|
okey = ldbm_nextkey( oldbm, olast );
|
|
#endif
|
|
if ( olast.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, olast );
|
|
}
|
|
olast = okey;
|
|
}
|
|
if ( olast.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, olast );
|
|
}
|
|
while ( nkey.dptr != NULL ) {
|
|
if ( charray_add_dup( &avals, &acur, &amax, nkey.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
nkey = ldbm_nextkey( nldbm, nlast, ncursorp );
|
|
#else
|
|
nkey = ldbm_nextkey( nldbm, nlast );
|
|
#endif
|
|
if ( nlast.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, nlast );
|
|
}
|
|
nlast = nkey;
|
|
}
|
|
if ( nlast.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, nlast );
|
|
}
|
|
#else
|
|
/*
|
|
* if the underlying database is not ordered, we have to
|
|
* generate list of values to add by stepping through all new
|
|
* values and looking them up in the old centroid (not there => add),
|
|
* then stepping through all old values and looking them up in the
|
|
* new centroid (not there => delete). this yields O(Nf(N)) performance,
|
|
* where f(N) is the order to retrieve a single item.
|
|
*/
|
|
|
|
/* generate list of values to add */
|
|
lastkey.dptr = NULL;
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
for ( key = ldbm_firstkey( nldbm, &ncursorp ); key.dptr != NULL;
|
|
key = ldbm_nextkey( nldbm, lastkey, ncursorp ) )
|
|
#else
|
|
for ( key = ldbm_firstkey( nldbm ); key.dptr != NULL;
|
|
key = ldbm_nextkey( nldbm, lastkey ) )
|
|
#endif
|
|
{
|
|
/* see if it's in the old one */
|
|
data = ldbm_fetch( oldbm, key );
|
|
|
|
/* not there - add it */
|
|
if ( data.dptr == NULL ) {
|
|
if ( charray_add_dup( &avals, &acur, &amax, key.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
} else {
|
|
ldbm_datum_free( oldbm, data );
|
|
}
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, lastkey );
|
|
}
|
|
lastkey = key;
|
|
}
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( nldbm, lastkey );
|
|
}
|
|
|
|
/* generate list of values to delete */
|
|
lastkey.dptr = NULL;
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
for ( key = ldbm_firstkey( oldbm, &ocursorp ); key.dptr != NULL;
|
|
key = ldbm_nextkey( oldbm, lastkey, ocursorp ) )
|
|
#else
|
|
for ( key = ldbm_firstkey( oldbm ); key.dptr != NULL;
|
|
key = ldbm_nextkey( oldbm, lastkey ) )
|
|
#endif
|
|
{
|
|
/* see if it's in the new one */
|
|
data = ldbm_fetch( nldbm, key );
|
|
|
|
/* not there - delete it */
|
|
if ( data.dptr == NULL ) {
|
|
if ( charray_add_dup( &dvals, &dcur, &dmax, key.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
} else {
|
|
ldbm_datum_free( nldbm, data );
|
|
}
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, lastkey );
|
|
}
|
|
lastkey = key;
|
|
}
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( oldbm, lastkey );
|
|
}
|
|
#endif
|
|
|
|
mods[0]->mod_values = avals;
|
|
mods[1]->mod_values = dvals;
|
|
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
fflush( stdout );
|
|
}
|
|
|
|
if ( mods[1]->mod_values == NULL ) {
|
|
free( (char *) mods[1] );
|
|
mods[1] = NULL;
|
|
}
|
|
if ( mods[0]->mod_values == NULL ) {
|
|
free( (char *) mods[0] );
|
|
mods[0] = mods[1];
|
|
mods[1] = NULL;
|
|
}
|
|
if ( mods[0] == NULL ) {
|
|
free( (char *) mods );
|
|
return( NULL );
|
|
} else {
|
|
return( mods );
|
|
}
|
|
}
|
|
|
|
static LDAPMod **
|
|
full_centroid(
|
|
char *attr,
|
|
LDBM ldbm,
|
|
int nentries
|
|
)
|
|
{
|
|
Datum key, lastkey;
|
|
LDAPMod **mods;
|
|
char **vals;
|
|
int vcur, vmax;
|
|
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
DBC *cursorp;
|
|
#endif
|
|
|
|
if ( verbose ) {
|
|
printf( "Generating mods for full %s centroid...", attr );
|
|
fflush( stdout );
|
|
}
|
|
|
|
if ( (mods = (LDAPMod **) malloc( sizeof(LDAPMod *) * 3 )) == NULL ||
|
|
(mods[0] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
|
|
(mods[1] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
|
|
(vals = (char **) malloc( 2 * sizeof(char *) )) == NULL ||
|
|
(vals[0] = (char *) malloc( 20 )) == NULL )
|
|
{
|
|
perror( "malloc" );
|
|
exit( -1 );
|
|
}
|
|
mods[0]->mod_op = LDAP_MOD_REPLACE;
|
|
mods[0]->mod_type = attr;
|
|
mods[0]->mod_values = NULL;
|
|
sprintf( vals[0], "%d", nentries );
|
|
vals[1] = NULL;
|
|
mods[1]->mod_op = LDAP_MOD_REPLACE;
|
|
mods[1]->mod_type = "nentries";
|
|
mods[1]->mod_values = vals;
|
|
mods[2] = NULL;
|
|
|
|
lastkey.dptr = NULL;
|
|
vals = NULL;
|
|
vcur = vmax = 0;
|
|
#ifdef HAVE_BERKELEY_DB2
|
|
for ( key = ldbm_firstkey( ldbm, &cursorp ); key.dptr != NULL;
|
|
key = ldbm_nextkey( ldbm, lastkey, cursorp ) )
|
|
#else
|
|
for ( key = ldbm_firstkey( ldbm ); key.dptr != NULL;
|
|
key = ldbm_nextkey( ldbm, lastkey ) )
|
|
#endif
|
|
{
|
|
if ( charray_add_dup( &vals, &vcur, &vmax, key.dptr ) == NULL ) {
|
|
ldap_mods_free( mods, 1 );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( ldbm, lastkey );
|
|
}
|
|
lastkey = key;
|
|
}
|
|
if ( lastkey.dptr != NULL ) {
|
|
ldbm_datum_free( ldbm, lastkey );
|
|
}
|
|
mods[0]->mod_values = vals;
|
|
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
fflush( stdout );
|
|
}
|
|
|
|
if ( mods[0]->mod_values == NULL ) {
|
|
free( (char *) mods[0] );
|
|
free( (char *) mods );
|
|
return( NULL );
|
|
} else {
|
|
return( mods );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* extract the destination ldap host, port, and base object for the
|
|
* server to receive the index information. then, open a connection,
|
|
* bind, and see if the entry exists. if not, create it and set things
|
|
* up so the centroid full and diff routines can modify it to contain
|
|
* the new centroid information.
|
|
*/
|
|
|
|
static LDAP *
|
|
bind_to_destination_ldap(
|
|
char *ldapsrcurl,
|
|
char *ldapdesturl
|
|
)
|
|
{
|
|
LDAP *ld;
|
|
LDAPMessage *res;
|
|
int rc;
|
|
char *s, *s2, *d;
|
|
char *attrs[2], *refvalues[2], *ocvalues[2];
|
|
LDAPMod *mp[3];
|
|
LDAPMod m[2];
|
|
char buf[BUFSIZ];
|
|
|
|
if ( verbose ) {
|
|
printf( "Binding to destination LDAP server..." );
|
|
fflush( stdout );
|
|
}
|
|
|
|
/* first, pick out the destination ldap server info */
|
|
if ( ldapbase != NULL ) {
|
|
free( ldapbase );
|
|
ldapbase = NULL;
|
|
}
|
|
if ( strncmp( ldapdesturl, "ldap://", 7 ) != 0 ) {
|
|
fputs( "Not an LDAP URL", stderr ); /* Should be smarter? */
|
|
return( NULL );
|
|
}
|
|
s = ldapdesturl + 7;
|
|
if ( (s2 = strchr( s, '/' )) == NULL ) {
|
|
ldapbase = strdup( s );
|
|
} else {
|
|
if ( *s != '/' ) {
|
|
*s2 = '\0';
|
|
if ( ldaphost != NULL )
|
|
free( ldaphost );
|
|
ldaphost = strdup( s );
|
|
*s2 = '/';
|
|
}
|
|
ldapbase = strdup( s2 + 1 );
|
|
}
|
|
strcpy( buf, "ref=" );
|
|
if ( strpbrk( ldapsrcurl, " ,;" ) != NULL ) {
|
|
strcat( buf, "\"" );
|
|
}
|
|
for ( s = d = ldapsrcurl; *s; s++ ) {
|
|
if ( *s != '"' ) {
|
|
*d++ = *s;
|
|
}
|
|
}
|
|
*d = '\0';
|
|
strcat( buf, ldapsrcurl );
|
|
if ( strpbrk( ldapsrcurl, " ,;" ) != NULL ) {
|
|
strcat( buf, "\"" );
|
|
}
|
|
strcat( buf, ", " );
|
|
strcat( buf, ldapbase );
|
|
free( ldapbase );
|
|
ldapbase = strdup( buf );
|
|
|
|
if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
|
|
perror( "ldap_open" );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( ldap_bind_s( ld, destldapbinddn, destldappasswd, destldapauthmethod )
|
|
!= LDAP_SUCCESS) {
|
|
ldap_perror( ld, "ldap_bind_s" );
|
|
ldap_unbind( ld );
|
|
return( NULL );
|
|
}
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
}
|
|
|
|
attrs[0] = "c";
|
|
attrs[1] = NULL;
|
|
rc = ldap_search_s( ld, ldapbase, LDAP_SCOPE_BASE, "(objectclass=*)",
|
|
attrs, 0, &res );
|
|
ldap_msgfree( res );
|
|
|
|
if ( rc == LDAP_NO_SUCH_OBJECT ) {
|
|
if ( verbose ) {
|
|
printf( "%sCreating centroid entry...", not ? "Not " : "" );
|
|
fflush( stdout );
|
|
}
|
|
|
|
/* create the centroid index entry */
|
|
m[0].mod_op = 0;
|
|
m[0].mod_type = "ref";
|
|
refvalues[0] = ldapsrcurl;
|
|
refvalues[1] = NULL;
|
|
m[0].mod_values = refvalues;
|
|
m[1].mod_op = 0;
|
|
m[1].mod_type = "objectclass";
|
|
ocvalues[0] = "indexentry";
|
|
ocvalues[1] = NULL;
|
|
m[1].mod_values = ocvalues;
|
|
mp[0] = &m[0];
|
|
mp[1] = &m[1];
|
|
mp[2] = NULL;
|
|
|
|
if ( !not && ldap_add_s( ld, ldapbase, mp ) != LDAP_SUCCESS ) {
|
|
ldap_perror( ld, ldapbase );
|
|
ldap_unbind( ld );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( verbose ) {
|
|
printf( "\n" );
|
|
fflush( stdout );
|
|
}
|
|
} else if ( rc != LDAP_SUCCESS ) {
|
|
ldap_perror( ld, "ldap_search_s" );
|
|
ldap_unbind( ld );
|
|
return( NULL );
|
|
}
|
|
|
|
return( ld );
|
|
}
|
|
|
|
static char **
|
|
charray_add_dup(
|
|
char ***a,
|
|
int *cur,
|
|
int *max,
|
|
char *s
|
|
)
|
|
{
|
|
int n;
|
|
|
|
if ( *a == NULL ) {
|
|
*a = (char **) malloc( (BUFSIZ + 1) * sizeof(char *) );
|
|
*cur = 0;
|
|
*max = BUFSIZ;
|
|
} else if ( *cur >= *max ) {
|
|
*max += BUFSIZ;
|
|
*a = (char **) realloc( *a, (*max + 1) * sizeof(char *) );
|
|
}
|
|
if ( *a == NULL ) {
|
|
return( NULL );
|
|
}
|
|
|
|
(*a)[(*cur)++] = strdup( s );
|
|
(*a)[*cur] = NULL;
|
|
return( *a );
|
|
}
|