--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright (c) 1990 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.
+ *
+ * Copyright 1998-2002 The OpenLDAP Foundation
+ * COPYING RESTRICTIONS APPLY. See COPYRIGHT File in top level directory
+ * of this package for details.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/param.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/sysexits.h>
+#include <ac/syslog.h>
+#include <ac/time.h>
+#include <ac/unistd.h>
+#include <ac/wait.h>
+
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <ldap.h>
+
+#include "ldap_defaults.h"
+
+#ifndef MAIL500_BOUNCEFROM
+#define MAIL500_BOUNCEFROM "<>"
+#endif
+
+#define USER 0x01
+#define GROUP_ERRORS 0x02
+#define GROUP_REQUEST 0x04
+#define GROUP_MEMBERS 0x08
+#define GROUP_OWNER 0x10
+
+#define ERROR "error"
+#define ERRORS "errors"
+#define REQUEST "request"
+#define REQUESTS "requests"
+#define MEMBERS "members"
+#define OWNER "owner"
+#define OWNERS "owners"
+
+LDAP *ld;
+char *vacationhost = NULL;
+char *errorsfrom = MAIL500_BOUNCEFROM;
+char *mailfrom = NULL;
+char *host = NULL;
+char *ldaphost = NULL;
+int hostlen = 0;
+int debug;
+
+typedef struct errs {
+ int e_code;
+#define E_USERUNKNOWN 1
+#define E_AMBIGUOUS 2
+#define E_NOEMAIL 3
+#define E_NOREQUEST 4
+#define E_NOERRORS 5
+#define E_BADMEMBER 6
+#define E_JOINMEMBERNOEMAIL 7
+#define E_MEMBERNOEMAIL 8
+#define E_LOOP 9
+#define E_NOMEMBERS 10
+#define E_NOOWNER 11
+#define E_GROUPUNKNOWN 12
+#define E_NOOWNADDRESS 13
+ char *e_addr;
+ union e_union_u {
+ char *e_u_loop;
+ LDAPMessage *e_u_msg;
+ } e_union;
+#define e_msg e_union.e_u_msg
+#define e_loop e_union.e_u_loop
+} Error;
+
+typedef struct groupto {
+ char *g_dn;
+ char *g_errorsto;
+ char **g_members;
+ int g_nmembers;
+} Group;
+
+typedef struct baseinfo {
+ char *b_url;
+ int b_m_entries;
+ char b_rdnpref; /* give rdn's preference when searching? */
+ int b_search; /* ORed with the type of thing the address */
+ /* looks like (USER, GROUP_ERRORS, etc.) */
+ /* to see if this should be searched */
+} Base;
+
+Base **base = NULL;
+
+char *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrLDAP", "-odi", "-oi", "-f", NULL, NULL };
+
+typedef struct attr_semantics {
+ char *as_name;
+ int as_m_valued; /* Is multivalued? */
+ int as_priority; /* Priority level of this attribut type */
+ int as_syntax; /* How to interpret values */
+ int as_m_entries; /* Can resolve to several entries? */
+ int as_kind; /* Recipient, sender, etc. */
+ char *as_param; /* Extra info for filters and things alike */
+} AttrSemantics;
+
+#define AS_SYNTAX_UNKNOWN 0
+#define AS_SYNTAX_NATIVE_MB 1 /* Unqualified mailbox name */
+#define AS_SYNTAX_RFC822 2 /* RFC822 mail address */
+#define AS_SYNTAX_HOST 3
+#define AS_SYNTAX_DN 4 /* A directory entry */
+#define AS_SYNTAX_RFC822_EXT 5
+#define AS_SYNTAX_URL 6 /* mailto: or ldap: URL */
+#define AS_SYNTAX_BOOL_FILTER 7 /* For joinable, filter in as_param */
+#define AS_SYNTAX_PRESENT 8 /* Value irrelevant, only presence is
+ * considered. */
+
+#define AS_KIND_UNKNOWN 0
+#define AS_KIND_RECIPIENT 1
+#define AS_KIND_ERRORS 2 /* For ErrorsTo and similar */
+#define AS_KIND_REQUEST 3
+#define AS_KIND_OWNER 4
+#define AS_KIND_ROUTE_TO_HOST 5 /* Expand at some other host */
+#define AS_KIND_ALLOWED_SENDER 6 /* Can send to group */
+#define AS_KIND_MODERATOR 7
+#define AS_KIND_ROUTE_TO_ADDR 8 /* Rewrite recipient address as */
+#define AS_KIND_OWN_ADDR 9 /* RFC822 name of this entry */
+#define AS_KIND_DELIVERY_TYPE 10 /* How to deliver mail to this entry */
+
+AttrSemantics **attr_semantics = NULL;
+int current_priority = 0;
+
+typedef struct subst {
+ char sub_char;
+ char *sub_value;
+} Subst;
+
+char **groupclasses = NULL;
+char **def_attr = NULL;
+char **myhosts = NULL; /* FQDNs not to route elsewhere */
+char **mydomains = NULL; /* If an RFC822 address points to one
+ of these domains, search it in the
+ directory instead of returning it
+ to hte MTA */
+
+static void load_config( char *filespec );
+static void split_address( char *address, char **localpart, char **domainpart);
+static int entry_engine( LDAPMessage *e, char *dn, char *address, char ***to, int *nto, Group ***togroups, int *ngroups, Error **err, int *nerr, int type );
+static void do_address( char *name, char ***to, int *nto, Group ***togroups, int *ngroups, Error **err, int *nerr, int type );
+static void send_message( char **to );
+static void send_errors( Error *err, int nerr );
+static void do_noemail( FILE *fp, Error *err, int namelen );
+static void do_ambiguous( FILE *fp, Error *err, int namelen );
+static int count_values( char **list );
+static void add_to( char ***list, int *nlist, char **new );
+static void add_single_to( char ***list, char *new );
+static int isgroup( LDAPMessage *e );
+static void add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg );
+static void unbind_and_exit( int rc ) LDAP_GCCATTR((noreturn));
+static void send_group( Group **group, int ngroup );
+
+static int connect_to_x500( void );
+
+
+int
+main ( int argc, char **argv )
+{
+ char *myname;
+ char **tolist;
+ Error *errlist;
+ Group **togroups;
+ int numto, ngroups, numerr, nargs;
+ int i, j;
+ char *conffile = NULL;
+
+ if ( (myname = strrchr( argv[0], *LDAP_DIRSEP )) == NULL )
+ myname = strdup( argv[0] );
+ else
+ myname = strdup( myname + 1 );
+
+#ifdef SIGPIPE
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
+#ifdef LOG_MAIL
+ openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
+#elif LOG_DEBUG
+ openlog( myname, OPENLOG_OPTIONS );
+#endif
+
+ while ( (i = getopt( argc, argv, "d:C:f:h:l:m:v:" )) != EOF ) {
+ switch( i ) {
+ case 'd': /* turn on debugging */
+ debug |= atoi( optarg );
+ break;
+
+ case 'C': /* path to configuration file */
+ conffile = strdup( optarg );
+ break;
+
+ case 'f': /* who it's from & where errors should go */
+ mailfrom = strdup( optarg );
+ /* Deal with <> */
+ if ( mailfrom[0] == '\0' ) {
+ free( mailfrom );
+ mailfrom = strdup( "<>" );
+ }
+ for ( j = 0; sendmailargs[j] != NULL; j++ ) {
+ if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
+ sendmailargs[j+1] = mailfrom;
+ break;
+ }
+ }
+ break;
+
+ case 'h': /* hostname */
+ host = strdup( optarg );
+ hostlen = strlen(host);
+ break;
+
+ case 'l': /* ldap host */
+ ldaphost = strdup( optarg );
+ break;
+
+ /* mailer-daemon address - who we should */
+ case 'm': /* say errors come from */
+ errorsfrom = strdup( optarg );
+ break;
+
+ case 'v': /* vacation host */
+ vacationhost = strdup( optarg );
+ break;
+
+ default:
+ syslog( LOG_ALERT, "unknown option" );
+ break;
+ }
+ }
+
+ if ( mailfrom == NULL ) {
+ syslog( LOG_ALERT, "required argument -f not present" );
+ exit( EX_TEMPFAIL );
+ }
+ if ( errorsfrom == NULL ) {
+ syslog( LOG_ALERT, "required argument -m not present" );
+ exit( EX_TEMPFAIL );
+ }
+/* if ( host == NULL ) { */
+/* syslog( LOG_ALERT, "required argument -h not present" ); */
+/* exit( EX_TEMPFAIL ); */
+/* } */
+ if ( conffile == NULL ) {
+ syslog( LOG_ALERT, "required argument -C not present" );
+ exit( EX_TEMPFAIL );
+ }
+
+ load_config( conffile );
+
+ if ( connect_to_x500() != 0 )
+ exit( EX_TEMPFAIL );
+
+ setuid( geteuid() );
+
+ if ( debug ) {
+ char buf[1024];
+ int i;
+
+ syslog( LOG_ALERT, "running as %d", geteuid() );
+ strcpy( buf, argv[0] );
+ for ( i = 1; i < argc; i++ ) {
+ strcat( buf, " " );
+ strcat( buf, argv[i] );
+ }
+
+ syslog( LOG_ALERT, "args: (%s)", buf );
+ }
+
+ tolist = NULL;
+ numto = 0;
+ add_to( &tolist, &numto, sendmailargs );
+ nargs = numto;
+ ngroups = numerr = 0;
+ togroups = NULL;
+ errlist = NULL;
+ for ( i = optind; i < argc; i++ ) {
+ char *s;
+ int type;
+ char *localpart = NULL, *domainpart = NULL;
+ char address[1024];
+
+ type = USER;
+ split_address( argv[i], &localpart, &domainpart );
+ if ( (s = strrchr( localpart, '-' )) != NULL ) {
+ s++;
+
+ if ((strcasecmp(s, ERROR) == 0) ||
+ (strcasecmp(s, ERRORS) == 0)) {
+ type = GROUP_ERRORS;
+ *(--s) = '\0';
+ } else if ((strcasecmp(s, REQUEST) == 0) ||
+ (strcasecmp(s, REQUESTS) == 0)) {
+ type = GROUP_REQUEST;
+ *(--s) = '\0';
+ } else if ( strcasecmp( s, MEMBERS ) == 0 ) {
+ type = GROUP_MEMBERS;
+ *(--s) = '\0';
+ } else if ((strcasecmp(s, OWNER) == 0) ||
+ (strcasecmp(s, OWNERS) == 0)) {
+ type = GROUP_OWNER;
+ *(--s) = '\0';
+ }
+ }
+
+ if ( domainpart ) {
+ sprintf( address, "%s@%s", localpart, domainpart );
+ free( localpart );
+ free( domainpart );
+ } else {
+ sprintf( address, "%s", localpart );
+ free( localpart );
+ }
+ do_address( address, &tolist, &numto, &togroups, &ngroups,
+ &errlist, &numerr, type );
+ }
+
+ /*
+ * If we have both errors and successful deliveries to make or if
+ * if there are any groups to deliver to, we basically need to read
+ * the message twice. So, we have to put it in a tmp file.
+ */
+
+ if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
+ FILE *fp;
+ char buf[BUFSIZ];
+
+ umask( 077 );
+ if ( (fp = tmpfile()) == NULL ) {
+ syslog( LOG_ALERT, "could not open tmp file" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ /* copy the message to a temp file */
+ while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+ if ( fputs( buf, fp ) == EOF ) {
+ syslog( LOG_ALERT, "error writing tmpfile" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+ }
+
+ if ( dup2( fileno( fp ), 0 ) == -1 ) {
+ syslog( LOG_ALERT, "could not dup2 tmpfile" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ fclose( fp );
+ }
+
+ /* deal with errors */
+ if ( numerr > 0 ) {
+ if ( debug ) {
+ syslog( LOG_ALERT, "sending errors" );
+ }
+ (void) rewind( stdin );
+ send_errors( errlist, numerr );
+ }
+
+ (void) ldap_unbind( ld );
+
+ /* send to groups with errorsTo */
+ if ( ngroups > 0 ) {
+ if ( debug ) {
+ syslog( LOG_ALERT, "sending to groups with errorsto" );
+ }
+ (void) rewind( stdin );
+ send_group( togroups, ngroups );
+ }
+
+ /* send to expanded aliases and groups w/o errorsTo */
+ if ( numto > nargs ) {
+ if ( debug ) {
+ syslog( LOG_ALERT, "sending to aliases and groups" );
+ }
+ (void) rewind( stdin );
+ send_message( tolist );
+ }
+
+ return( EX_OK );
+}
+
+static char *
+get_config_line( FILE *cf, int *lineno)
+{
+ static char buf[2048];
+ int len;
+ int pos;
+ int room;
+
+ pos = 0;
+ room = sizeof( buf );
+ while ( fgets( &buf[pos], room, cf ) ) {
+ (*lineno)++;
+ if ( pos > 0 ) {
+ /* Delete whitespace at the beginning of new data */
+ if ( isspace( (unsigned char) buf[pos] ) ) {
+ char *s, *d;
+ for ( s = buf+pos; isspace((unsigned char) *s); s++ )
+ ;
+ for ( d = buf+pos; *s; s++, d++ ) {
+ *d = *s;
+ }
+ *d = *s;
+ }
+ }
+ len = strlen( buf );
+ if ( buf[len-1] != '\n' ) {
+ syslog( LOG_ALERT, "Definition too long at line %d",
+ *lineno );
+ exit( EX_TEMPFAIL );
+ }
+ if ( buf[0] == '#' )
+ continue;
+ if ( strspn( buf, " \t\n" ) == len )
+ continue;
+ if ( len >= 2 && buf[len-2] == '\\' ) {
+ pos = len - 2;
+ room = sizeof(buf) - pos;
+ continue;
+ }
+ /* We have a real line, we will exit the loop */
+ buf[len-1] = '\0';
+ return( buf );
+ }
+ return( NULL );
+}
+
+static void
+add_url ( char *url, int rdnpref, int typemask )
+{
+ Base **list_temp;
+ int size;
+ Base *b;
+
+ b = calloc(1, sizeof(Base));
+ if ( !b ) {
+ syslog( LOG_ALERT, "Out of memory" );
+ exit( EX_TEMPFAIL );
+ }
+ b->b_url = strdup( url );
+ b->b_rdnpref = rdnpref;
+ b->b_search = typemask;
+
+ if ( base == NULL ) {
+ base = calloc(2, sizeof(LDAPURLDesc *));
+ if ( !base ) {
+ syslog( LOG_ALERT, "Out of memory" );
+ exit( EX_TEMPFAIL );
+ }
+ base[0] = b;
+ } else {
+ for ( size = 0; base[size]; size++ )
+ ;
+ size += 2;
+ list_temp = realloc( base, size*sizeof(LDAPURLDesc *) );
+ if ( !list_temp ) {
+ syslog( LOG_ALERT, "Out of memory" );
+ exit( EX_TEMPFAIL );
+ }
+ base = list_temp;
+ base[size-2] = b;
+ base[size-1] = NULL;
+ }
+}
+
+static void
+add_def_attr( char *s )
+{
+ char *p, *q;
+
+ p = s;
+ while ( *p ) {
+ p += strspn( p, "\t," );
+ q = strpbrk( p, " \t," );
+ if ( q ) {
+ *q = '\0';
+ add_single_to( &def_attr, p );
+ } else {
+ add_single_to( &def_attr, p );
+ break;
+ }
+ p = q + 1;
+ }
+}
+
+static void
+add_attr_semantics( char *s )
+{
+ char *p, *q;
+ AttrSemantics *as;
+
+ as = calloc( 1, sizeof( AttrSemantics ) );
+ as->as_priority = current_priority;
+ p = s;
+ while ( isspace ( (unsigned char) *p ) )
+ p++;
+ q = p;
+ while ( !isspace ( (unsigned char) *q ) && *q != '\0' )
+ q++;
+ *q = '\0';
+ as->as_name = strdup( p );
+ p = q + 1;
+
+ while ( *p ) {
+ while ( isspace ( (unsigned char) *p ) )
+ p++;
+ q = p;
+ while ( !isspace ( (unsigned char) *q ) && *q != '\0' )
+ q++;
+ *q = '\0';
+ if ( !strcasecmp( p, "multivalued" ) ) {
+ as->as_m_valued = 1;
+ } else if ( !strcasecmp( p, "multiple-entries" ) ) {
+ as->as_m_entries = 1;
+ } else if ( !strcasecmp( p, "local-native-mailbox" ) ) {
+ as->as_syntax = AS_SYNTAX_NATIVE_MB;
+ } else if ( !strcasecmp( p, "rfc822" ) ) {
+ as->as_syntax = AS_SYNTAX_RFC822;
+ } else if ( !strcasecmp( p, "rfc822-extended" ) ) {
+ as->as_syntax = AS_SYNTAX_RFC822_EXT;
+ } else if ( !strcasecmp( p, "dn" ) ) {
+ as->as_syntax = AS_SYNTAX_DN;
+ } else if ( !strcasecmp( p, "url" ) ) {
+ as->as_syntax = AS_SYNTAX_URL;
+ } else if ( !strcasecmp( p, "search-with-filter" ) ) {
+ as->as_syntax = AS_SYNTAX_BOOL_FILTER;
+ } else if ( !strncasecmp( p, "param=", 6 ) ) {
+ q = strchr( p, '=' );
+ if ( q ) {
+ p = q + 1;
+ while ( *q && !isspace( (unsigned char) *q ) ) {
+ q++;
+ }
+ if ( *q ) {
+ *q = '\0';
+ as->as_param = strdup( p );
+ p = q + 1;
+ } else {
+ as->as_param = strdup( p );
+ p = q;
+ }
+ }
+ } else if ( !strcasecmp( p, "host" ) ) {
+ as->as_kind = AS_SYNTAX_HOST;
+ } else if ( !strcasecmp( p, "present" ) ) {
+ as->as_kind = AS_SYNTAX_PRESENT;
+ } else if ( !strcasecmp( p, "route-to-host" ) ) {
+ as->as_kind = AS_KIND_ROUTE_TO_HOST;
+ } else if ( !strcasecmp( p, "route-to-address" ) ) {
+ as->as_kind = AS_KIND_ROUTE_TO_ADDR;
+ } else if ( !strcasecmp( p, "own-address" ) ) {
+ as->as_kind = AS_KIND_OWN_ADDR;
+ } else if ( !strcasecmp( p, "recipient" ) ) {
+ as->as_kind = AS_KIND_RECIPIENT;
+ } else if ( !strcasecmp( p, "errors" ) ) {
+ as->as_kind = AS_KIND_ERRORS;
+ } else if ( !strcasecmp( p, "request" ) ) {
+ as->as_kind = AS_KIND_REQUEST;
+ } else if ( !strcasecmp( p, "owner" ) ) {
+ as->as_kind = AS_KIND_OWNER;
+ } else if ( !strcasecmp( p, "delivery-type" ) ) {
+ as->as_kind = AS_KIND_DELIVERY_TYPE;
+ } else {
+ syslog( LOG_ALERT,
+ "Unknown semantics word %s", p );
+ exit( EX_TEMPFAIL );
+ }
+ p = q + 1;
+ }
+ if ( attr_semantics == NULL ) {
+ attr_semantics = calloc(2, sizeof(AttrSemantics *));
+ if ( !attr_semantics ) {
+ syslog( LOG_ALERT, "Out of memory" );
+ exit( EX_TEMPFAIL );
+ }
+ attr_semantics[0] = as;
+ } else {
+ int size;
+ AttrSemantics **list_temp;
+ for ( size = 0; attr_semantics[size]; size++ )
+ ;
+ size += 2;
+ list_temp = realloc( attr_semantics,
+ size*sizeof(AttrSemantics *) );
+ if ( !list_temp ) {
+ syslog( LOG_ALERT, "Out of memory" );
+ exit( EX_TEMPFAIL );
+ }
+ attr_semantics = list_temp;
+ attr_semantics[size-2] = as;
+ attr_semantics[size-1] = NULL;
+ }
+}
+
+static void
+load_config( char *filespec )
+{
+ FILE *cf;
+ char *line;
+ int lineno = 0;
+ char *p;
+ int rdnpref;
+ int typemask;
+
+ cf = fopen( filespec, "r" );
+ if ( !cf ) {
+ perror( "Opening config file" );
+ exit( EX_TEMPFAIL );
+ }
+
+ while ( ( line = get_config_line( cf,&lineno ) ) ) {
+ p = strpbrk( line, " \t" );
+ if ( !p ) {
+ syslog( LOG_ALERT,
+ "Missing space at line %d", lineno );
+ exit( EX_TEMPFAIL );
+ }
+ if ( !strncmp( line, "search", p-line ) ) {
+ p += strspn( p, " \t" );
+ /* TBC, get these */
+ rdnpref = 0;
+ typemask = 0xFF;
+ add_url( p, rdnpref, typemask );
+ } else if ( !strncmp(line, "attribute", p-line) ) {
+ p += strspn(p, " \t");
+ add_attr_semantics( p );
+ } else if ( !strncmp(line, "default-attributes", p-line) ) {
+ p += strspn(p, " \t");
+ add_def_attr( p );
+ } else if ( !strncmp(line, "group-classes", p-line) ) {
+ p += strspn(p, " \t");
+ add_single_to( &groupclasses, p );
+ } else if ( !strncmp(line, "priority", p-line) ) {
+ p += strspn(p, " \t");
+ current_priority = atoi(p);
+ } else if ( !strncmp(line, "domain", p-line) ) {
+ p += strspn(p, " \t");
+ add_single_to( &mydomains, p );
+ } else if ( !strncmp(line, "host", p-line) ) {
+ p += strspn(p, " \t");
+ add_single_to( &myhosts, p );
+ } else {
+ syslog( LOG_ALERT,
+ "Unparseable config definition at line %d",
+ lineno );
+ exit( EX_TEMPFAIL );
+ }
+ }
+ fclose( cf );
+}
+
+static int
+connect_to_x500( void )
+{
+ int opt;
+
+ if ( (ld = ldap_init( ldaphost, 0 )) == NULL ) {
+ syslog( LOG_ALERT, "ldap_init failed" );
+ return( -1 );
+ }
+
+ /* TBC: Set this only when it makes sense
+ opt = MAIL500_MAXAMBIGUOUS;
+ ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &opt);
+ */
+ opt = LDAP_DEREF_ALWAYS;
+ ldap_set_option(ld, LDAP_OPT_DEREF, &opt);
+
+ if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
+ syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+static Group *
+new_group( char *dn, Group ***list, int *nlist )
+{
+ int i;
+ Group *this_group;
+
+ for ( i = 0; i < *nlist; i++ ) {
+ if ( strcasecmp( dn, (*list)[i]->g_dn ) == 0 ) {
+ syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
+ return NULL;
+ }
+ }
+
+ this_group = (Group *) malloc( sizeof(Group) );
+
+ if ( *nlist == 0 ) {
+ *list = (Group **) malloc( sizeof(Group *) );
+ } else {
+ *list = (Group **) realloc( *list, (*nlist + 1) *
+ sizeof(Group *) );
+ }
+
+ this_group->g_errorsto = NULL;
+ this_group->g_members = NULL;
+ this_group->g_nmembers = 0;
+ /* save the group's dn so we can check for loops above */
+ this_group->g_dn = strdup( dn );
+
+ (*list)[*nlist] = this_group;
+ (*nlist)++;
+
+ return( this_group );
+}
+
+static void
+split_address(
+ char *address,
+ char **localpart,
+ char **domainpart
+)
+{
+ char *p;
+
+ if ( ( p = strrchr( address, '@' ) ) == NULL ) {
+ *localpart = strdup( address );
+ *domainpart = NULL;
+ } else {
+ *localpart = malloc( p - address + 1 );
+ strncpy( *localpart, address, p - address );
+ (*localpart)[p - address] = '\0';
+ p++;
+ *domainpart = strdup( p );
+ }
+}
+
+static int
+dn_search(
+ char **dnlist,
+ char *address,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr
+)
+{
+ int rc;
+ int i;
+ int resolved = 0;
+ LDAPMessage *res, *e;
+ struct timeval timeout;
+
+ timeout.tv_sec = MAIL500_TIMEOUT;
+ timeout.tv_usec = 0;
+ for ( i = 0; dnlist[i]; i++ ) {
+ if ( (rc = ldap_search_st( ld, dnlist[i], LDAP_SCOPE_BASE,
+ NULL, def_attr, 0,
+ &timeout, &res )) != LDAP_SUCCESS ) {
+ if ( rc == LDAP_NO_SUCH_OBJECT ) {
+ add_error( err, nerr, E_BADMEMBER, dnlist[i], NULL );
+ continue;
+ } else {
+ syslog( LOG_ALERT, "member search return 0x%x", rc );
+
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+ } else {
+ if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+ syslog( LOG_ALERT, "member search error parsing entry" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+ if ( entry_engine( e, dnlist[i], address, to, nto,
+ togroups, ngroups, err, nerr,
+ USER | GROUP_MEMBERS ) ) {
+ resolved = 1;
+ }
+ }
+ }
+ return( resolved );
+}
+
+static int
+search_ldap_url(
+ char *url,
+ Subst *substs,
+ char *address,
+ int rdnpref,
+ int multi_entry,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ LDAPURLDesc *ludp;
+ char *p, *s, *d;
+ int i;
+ char filter[1024];
+ LDAPMessage *e, *res;
+ int rc;
+ char **attrlist;
+ struct timeval timeout;
+ int match;
+ int resolved = 0;
+ char *dn;
+
+ timeout.tv_sec = MAIL500_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ rc = ldap_url_parse( url, &ludp );
+ if ( rc ) {
+ switch ( rc ) {
+ case LDAP_URL_ERR_BADSCHEME:
+ syslog( LOG_ALERT,
+ "Not an LDAP URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADENCLOSURE:
+ syslog( LOG_ALERT,
+ "Bad Enclosure in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADURL:
+ syslog( LOG_ALERT,
+ "Bad URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADHOST:
+ syslog( LOG_ALERT,
+ "Host is invalid in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADATTRS:
+ syslog( LOG_ALERT,
+ "Attributes are invalid in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADSCOPE:
+ syslog( LOG_ALERT,
+ "Scope is invalid in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADFILTER:
+ syslog( LOG_ALERT,
+ "Filter is invalid in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_BADEXTS:
+ syslog( LOG_ALERT,
+ "Extensions are invalid in URL: %s", url );
+ break;
+ case LDAP_URL_ERR_MEM:
+ syslog( LOG_ALERT,
+ "Out of memory parsing URL: %s", url );
+ break;
+ case LDAP_URL_ERR_PARAM:
+ syslog( LOG_ALERT,
+ "bad parameter parsing URL: %s", url );
+ break;
+ default:
+ syslog( LOG_ALERT,
+ "Unknown error %d parsing URL: %s",
+ rc, url );
+ break;
+ }
+ add_error( err, nerr, E_BADMEMBER,
+ url, NULL );
+ return 0;
+ }
+
+ if ( substs ) {
+ for ( s = ludp->lud_filter, d = filter; *s; s++,d++ ) {
+ if ( *s == '%' ) {
+ s++;
+ if ( *s == '%' ) {
+ *d = '%';
+ continue;
+ }
+ for ( i = 0; substs[i].sub_char != '\0';
+ i++ ) {
+ if ( *s == substs[i].sub_char ) {
+ for ( p = substs[i].sub_value;
+ *p; p++,d++ ) {
+ *d = *p;
+ }
+ d--;
+ break;
+ }
+ }
+ if ( substs[i].sub_char == '\0' ) {
+ syslog( LOG_ALERT,
+ "unknown format %c", *s );
+ }
+ } else {
+ *d = *s;
+ }
+ }
+ *d = *s;
+ } else {
+ strncpy( filter, ludp->lud_filter, sizeof( filter ) - 1 );
+ filter[ sizeof( filter ) - 1 ] = '\0';
+ }
+
+ if ( ludp->lud_attrs ) {
+ attrlist = ludp->lud_attrs;
+ } else {
+ attrlist = def_attr;
+ }
+ res = NULL;
+ /* TBC: we don't read the host, dammit */
+ rc = ldap_search_st( ld, ludp->lud_dn, ludp->lud_scope,
+ filter, attrlist, 0,
+ &timeout, &res );
+
+ /* some other trouble - try again later */
+ if ( rc != LDAP_SUCCESS &&
+ rc != LDAP_SIZELIMIT_EXCEEDED ) {
+ syslog( LOG_ALERT, "return 0x%x from X.500",
+ rc );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ match = ldap_count_entries( ld, res );
+
+ /* trouble - try again later */
+ if ( match == -1 ) {
+ syslog( LOG_ALERT, "error parsing result from X.500" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ if ( match == 1 || multi_entry ) {
+ for ( e = ldap_first_entry( ld, res ); e != NULL;
+ e = ldap_next_entry( ld, e ) ) {
+ dn = ldap_get_dn( ld, e );
+ resolved = entry_engine( e, dn, address, to, nto,
+ togroups, ngroups,
+ err, nerr, type );
+ if ( !resolved ) {
+ add_error( err, nerr, E_NOEMAIL, address, res );
+ }
+ }
+ return ( resolved );
+ }
+
+ /* more than one match - bounce with ambiguous user? */
+ if ( match > 1 ) {
+ LDAPMessage *next, *tmpres = NULL;
+ char *dn;
+ char **xdn;
+
+ /* not giving rdn preference - bounce with ambiguous user */
+ if ( rdnpref == 0 ) {
+ add_error( err, nerr, E_AMBIGUOUS, address, res );
+ return 0;
+ }
+
+ /*
+ * giving rdn preference - see if any entries were matched
+ * because of their rdn. If so, collect them to deal with
+ * later (== 1 we deliver, > 1 we bounce).
+ */
+
+ for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
+ next = ldap_next_entry( ld, e );
+ dn = ldap_get_dn( ld, e );
+ xdn = ldap_explode_dn( dn, 1 );
+
+ /* XXX bad, but how else can we do it? XXX */
+ if ( strcasecmp( xdn[0], address ) == 0 ) {
+ ldap_delete_result_entry( &res, e );
+ ldap_add_result_entry( &tmpres, e );
+ }
+
+ ldap_value_free( xdn );
+ free( dn );
+ }
+
+ /* nothing matched by rdn - go ahead and bounce */
+ if ( tmpres == NULL ) {
+ add_error( err, nerr, E_AMBIGUOUS, address, res );
+ return 0;
+
+ /* more than one matched by rdn - bounce with rdn matches */
+ } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
+ add_error( err, nerr, E_AMBIGUOUS, address, tmpres );
+ return 0;
+
+ /* trouble... */
+ } else if ( match < 0 ) {
+ syslog( LOG_ALERT, "error parsing result from X.500" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ /* otherwise one matched by rdn - send to it */
+ ldap_msgfree( res );
+ res = tmpres;
+
+ /* trouble */
+ if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+ syslog( LOG_ALERT, "error parsing entry from X.500" );
+ unbind_and_exit( EX_TEMPFAIL );
+ }
+
+ dn = ldap_get_dn( ld, e );
+
+ resolved = entry_engine( e, dn, address, to, nto,
+ togroups, ngroups,
+ err, nerr, type );
+ if ( !resolved ) {
+ add_error( err, nerr, E_NOEMAIL, address, res );
+ /* Don't free res if we passed it to add_error */
+ } else {
+ ldap_msgfree( res );
+ }
+ }
+ return( resolved );
+}
+
+static int
+url_list_search(
+ char **urllist,
+ char *address,
+ int multi_entry,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ int i;
+ int resolved = 0;
+
+ for ( i = 0; urllist[i]; i++ ) {
+
+ if ( !strncasecmp( urllist[i], "mail:", 5 ) ) {
+ char *vals[2];
+
+ vals[0] = urllist[i] + 5;
+ vals[1] = NULL;
+ add_to( to, nto, vals );
+ resolved = 1;
+
+ } else if ( ldap_is_ldap_url( urllist[i] ) ) {
+
+ resolved = search_ldap_url( urllist[i], NULL,
+ address, 0, multi_entry,
+ to, nto, togroups, ngroups,
+ err, nerr, type );
+ } else {
+ /* Produce some sensible error here */
+ resolved = 0;
+ }
+ }
+ return( resolved );
+}
+
+/*
+ * We should probably take MX records into account to cover all bases,
+ * but really, routing belongs in the MTA.
+ */
+static int
+is_my_host(
+ char * host
+)
+{
+ char **d;
+
+ if ( myhosts == NULL )
+ return 0;
+ for ( d = myhosts; *d; d++ ) {
+ if ( !strcasecmp(*d,host) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+is_my_domain(
+ char * address
+)
+{
+ char **d;
+ char *p;
+
+ if ( mydomains == NULL )
+ return 0;
+ p = strchr( address, '@' );
+ if ( p == NULL)
+ return 0;
+ for ( d = mydomains; *d; d++ ) {
+ if ( !strcasecmp(*d,p+1) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+do_addresses(
+ char **addresses,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ int i, j;
+ int n;
+
+ /*
+ * Well, this is tricky, every address in my_addresses will be
+ * removed from the list while we shift the other values down
+ * and we do it in a single scan of the address list and
+ * without using additional memory. We are going to be
+ * modifying the value list in a way that the later
+ * ldap_value_free works.
+ */
+ j = 0;
+ for ( i = 0; addresses[i]; i++ ) {
+ if ( is_my_domain(addresses[i]) ) {
+ do_address( addresses[i], to, nto, togroups, ngroups,
+ err, nerr, type );
+ ldap_memfree( addresses[i] );
+ } else {
+ if ( j < i ) {
+ addresses[j] = addresses[i];
+ }
+ j++;
+ }
+ }
+ addresses[j] = NULL;
+ if ( addresses[0] ) {
+ add_to( to, nto, addresses );
+ }
+}
+
+/*
+ * The entry engine processes an entry. Normally, each entry will resolve
+ * to one or more values that will be added to the 'to' argument. This
+ * argument needs not be the global 'to' list, it may be the g_to field
+ * in a group. Groups have no special treatment, unless they require
+ * a special sender.
+ */
+
+static int
+entry_engine(
+ LDAPMessage *e,
+ char *dn,
+ char *address,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ char **vals;
+ int i;
+ int resolved = 0;
+ char ***current_to = to;
+ int *current_nto = nto;
+ Group *current_group = NULL;
+ char buf[1024];
+ char *localpart = NULL, *domainpart = NULL;
+ Subst substs[2];
+ int cur_priority = 0;
+ char *route_to_host = NULL;
+ char *route_to_address = NULL;
+ int needs_mta_routing = 0;
+ char **own_addresses = NULL;
+ int own_addresses_total = 0;
+ char **delivery_types = NULL;
+ int delivery_types_total = 0;
+ char *nvals[2];
+
+ for ( i=0; attr_semantics[i] != NULL; i++ ) {
+ AttrSemantics *as = attr_semantics[i];
+ int nent;
+ int j;
+
+ if ( as->as_priority < cur_priority ) {
+ /*
+ * We already got higher priority information,
+ * so no further work to do, ignore the rest.
+ */
+ break;
+ }
+ vals = ldap_get_values( ld, e, as->as_name );
+ if ( !vals || vals[0] == NULL ) {
+ continue;
+ }
+ nent = count_values( vals );
+ if ( nent > 1 && !as->as_m_valued ) {
+ add_error( err, nerr, E_AMBIGUOUS, address, e );
+ return( 0 );
+ }
+ switch ( as->as_kind ) {
+ case AS_KIND_RECIPIENT:
+ cur_priority = as->as_priority;
+ if ( ! ( type & ( USER | GROUP_MEMBERS ) ) )
+ break;
+ switch ( as->as_syntax ) {
+ case AS_SYNTAX_RFC822:
+ do_addresses( vals, current_to, current_nto,
+ togroups, ngroups, err, nerr,
+ USER );
+ resolved = 1;
+ break;
+ case AS_SYNTAX_RFC822_EXT:
+ do_addresses( vals, current_to, current_nto,
+ togroups, ngroups, err, nerr,
+ USER );
+ resolved = 1;
+ break;
+ case AS_SYNTAX_NATIVE_MB:
+ /* We used to concatenate mailHost if set here */
+ /*
+ * We used to send a copy to the vacation host
+ * if onVacation to uid@vacationhost
+ */
+ if ( as->as_param ) {
+ for ( j=0; j<delivery_types_total; j++ ) {
+ if ( !strcasecmp( as->as_param, delivery_types[j] ) ) {
+ add_to( current_to, current_nto, vals );
+ resolved = 1;
+ break;
+ }
+ }
+ } else {
+ add_to( current_to, current_nto, vals );
+ resolved = 1;
+ }
+ break;
+
+ case AS_SYNTAX_DN:
+ if ( dn_search( vals, address,
+ current_to, current_nto,
+ togroups, ngroups,
+ err, nerr ) ) {
+ resolved = 1;
+ }
+ break;
+
+ case AS_SYNTAX_URL:
+ if ( url_list_search( vals, address,
+ as->as_m_entries,
+ current_to, current_nto,
+ togroups, ngroups,
+ err, nerr, type ) ) {
+ resolved = 1;
+ }
+ break;
+
+ case AS_SYNTAX_BOOL_FILTER:
+ if ( strcasecmp( vals[0], "true" ) ) {
+ break;
+ }
+ substs[0].sub_char = 'D';
+ substs[0].sub_value = dn;
+ substs[1].sub_char = '\0';
+ substs[1].sub_value = NULL;
+ if ( url_list_search( vals, address,
+ as->as_m_entries,
+ current_to, current_nto,
+ togroups, ngroups,
+ err, nerr, type ) ) {
+ resolved = 1;
+ }
+ break;
+
+ default:
+ syslog( LOG_ALERT,
+ "Invalid syntax %d for kind %d",
+ as->as_syntax, as->as_kind );
+ break;
+ }
+ break;
+
+ case AS_KIND_ERRORS:
+ cur_priority = as->as_priority;
+ /* This is a group with special processing */
+ if ( type & GROUP_ERRORS ) {
+ switch (as->as_kind) {
+ case AS_SYNTAX_RFC822:
+ add_to( current_to, current_nto, vals );
+ resolved = 1;
+ break;
+ case AS_SYNTAX_URL:
+ default:
+ syslog( LOG_ALERT,
+ "Invalid syntax %d for kind %d",
+ as->as_syntax, as->as_kind );
+ }
+ } else {
+ current_group = new_group( dn, togroups,
+ ngroups );
+ if ( ! current_group )
+ /*
+ * We have already considered
+ * this group, so we just
+ * return resolved.
+ */
+ return 1;
+ current_to = ¤t_group->g_members;
+ current_nto = ¤t_group->g_nmembers;
+ split_address( address,
+ &localpart, &domainpart );
+ if ( domainpart ) {
+ sprintf( buf, "%s-%s@%s",
+ localpart, ERRORS,
+ domainpart );
+ free( localpart );
+ free( domainpart );
+ } else {
+ sprintf( buf, "%s-%s@%s",
+ localpart, ERRORS,
+ host );
+ free( localpart );
+ }
+ current_group->g_errorsto = strdup( buf );
+ }
+ break;
+
+ case AS_KIND_REQUEST:
+ cur_priority = as->as_priority;
+ /* This is a group with special processing */
+ if ( type & GROUP_REQUEST ) {
+ add_to( current_to, current_nto, vals );
+ resolved = 1;
+ }
+ break;
+
+ case AS_KIND_OWNER:
+ cur_priority = as->as_priority;
+ /* This is a group with special processing */
+ if ( type & GROUP_REQUEST ) {
+ add_to( current_to, current_nto, vals );
+ resolved = 1;
+ }
+ break;
+
+ case AS_KIND_ROUTE_TO_HOST:
+ if ( !is_my_host( vals[0] ) ) {
+ cur_priority = as->as_priority;
+ if ( as->as_syntax == AS_SYNTAX_PRESENT ) {
+ needs_mta_routing = 1;
+ } else {
+ route_to_host = strdup( vals[0] );
+ }
+ }
+ break;
+
+ case AS_KIND_ROUTE_TO_ADDR:
+ for ( j=0; j<own_addresses_total; j++ ) {
+ if ( strcasecmp( vals[0], own_addresses[j] ) ) {
+ cur_priority = as->as_priority;
+ if ( as->as_syntax == AS_SYNTAX_PRESENT ) {
+ needs_mta_routing = 1;
+ } else {
+ route_to_address = strdup( vals[0] );
+ }
+ }
+ break;
+ }
+
+ case AS_KIND_OWN_ADDR:
+ add_to( &own_addresses, &own_addresses_total, vals );
+ cur_priority = as->as_priority;
+ break;
+
+ case AS_KIND_DELIVERY_TYPE:
+ add_to( &delivery_types, &delivery_types_total, vals );
+ cur_priority = as->as_priority;
+ break;
+
+ default:
+ syslog( LOG_ALERT,
+ "Invalid kind %d", as->as_kind );
+ /* Error, TBC */
+ }
+ ldap_value_free( vals );
+ }
+ /*
+ * Now check if we are dealing with mail routing. We support
+ * two modes.
+ *
+ * The first mode and by far the most robust method is doing
+ * routing at the MTA. In this case, we just checked if the
+ * routing attributes were present and did not seem like
+ * pointing to ourselves. The only thing we have to do here
+ * is adding to the recipient list any of the RFC822 addresses
+ * of this entry. That means we needed to retrieve them from
+ * the entry itself because we might have arrived here through
+ * some directory search. The address received as argument is
+ * not the address of the entry we are processing, but rather
+ * the RFC822 address we are expanding now. Unfortunately,
+ * this requires an MTA that understands LDAP routing.
+ * Sendmail 8.10.0 does, if compiled properly.
+ *
+ * The second method, that is most emphatically not recommended
+ * is routing in maildap. This is going to require using the
+ * percent hack. Moreover, this may occasionally loop.
+ */
+ if ( needs_mta_routing ) {
+ if ( !own_addresses ) {
+ add_error( err, nerr, E_NOOWNADDRESS, address, e );
+ return( 0 );
+ }
+ nvals[0] = own_addresses[0]; /* Anyone will do */
+ nvals[1] = NULL;
+ add_to( current_to, current_nto, nvals );
+ resolved = 1;
+ } else if ( route_to_host ) {
+ char *p;
+ if ( !route_to_address ) {
+ if ( !own_addresses ) {
+ add_error( err, nerr, E_NOOWNADDRESS, address, e );
+ return( 0 );
+ }
+ route_to_address = strdup( own_addresses[0] );
+ }
+ /* This makes use of the percent hack, but there's no choice */
+ p = strchr( route_to_address, '@' );
+ if ( p ) {
+ *p = '%';
+ }
+ sprintf( buf, "%s@%s", route_to_address, route_to_host );
+ nvals[0] = buf;
+ nvals[1] = NULL;
+ add_to( current_to, current_nto, nvals );
+ resolved = 1;
+ free( route_to_host );
+ free( route_to_address );
+ } else if ( route_to_address ) {
+ nvals[0] = route_to_address;
+ nvals[1] = NULL;
+ add_to( current_to, current_nto, nvals );
+ resolved = 1;
+ free( route_to_address );
+ }
+ if ( own_addresses ) {
+ ldap_value_free( own_addresses );
+ }
+ if ( delivery_types ) {
+ ldap_value_free( delivery_types );
+ }
+
+ return( resolved );
+}
+
+static int
+search_bases(
+ char *filter,
+ Subst *substs,
+ char *name,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ int b, resolved = 0;
+
+ for ( b = 0; base[b] != NULL; b++ ) {
+
+ if ( ! (base[b]->b_search & type) ) {
+ continue;
+ }
+
+ resolved = search_ldap_url( base[b]->b_url, substs, name,
+ base[b]->b_rdnpref,
+ base[b]->b_m_entries,
+ to, nto, togroups, ngroups,
+ err, nerr, type );
+ if ( resolved )
+ break;
+ }
+ return( resolved );
+}
+
+static void
+do_address(
+ char *name,
+ char ***to,
+ int *nto,
+ Group ***togroups,
+ int *ngroups,
+ Error **err,
+ int *nerr,
+ int type
+)
+{
+ char *localpart = NULL, *domainpart = NULL;
+ char *synthname = NULL;
+ int resolved;
+ int i;
+ Subst substs[6];
+
+ /*
+ * Look up the name in X.500, add the appropriate addresses found
+ * to the to list, or to the err list in case of error. Groups are
+ * handled by the do_group routine, individuals are handled here.
+ * When looking up name, we follow the bases hierarchy, looking
+ * in base[0] first, then base[1], etc. For each base, there is
+ * a set of search filters to try, in order. If something goes
+ * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
+ * If the b_rdnpref flag is set, then we give preference to entries
+ * that matched name because it's their rdn, otherwise not.
+ */
+
+ split_address( name, &localpart, &domainpart );
+ synthname = strdup( localpart );
+ for ( i = 0; synthname[i] != '\0'; i++ ) {
+ if ( synthname[i] == '.' || synthname[i] == '_' )
+ synthname[i] = ' ';
+ }
+ substs[0].sub_char = 'm';
+ substs[0].sub_value = name;
+ substs[1].sub_char = 'h';
+ substs[1].sub_value = host;
+ substs[2].sub_char = 'l';
+ substs[2].sub_value = localpart;
+ substs[3].sub_char = 'd';
+ substs[3].sub_value = domainpart;
+ substs[4].sub_char = 's';
+ substs[4].sub_value = synthname;
+ substs[5].sub_char = '\0';
+ substs[5].sub_value = NULL;
+
+ resolved = search_bases( NULL, substs, name,
+ to, nto, togroups, ngroups,
+ err, nerr, type );
+
+ if ( localpart ) {
+ free( localpart );
+ }
+ if ( domainpart ) {
+ free( domainpart );
+ }
+ if ( synthname ) {
+ free( synthname );
+ }
+
+ if ( !resolved ) {
+ /* not resolved - bounce with user unknown */
+ if ( type == USER ) {
+ add_error( err, nerr, E_USERUNKNOWN, name, NULL );
+ } else {
+ add_error( err, nerr, E_GROUPUNKNOWN, name, NULL );
+ }
+ }
+}
+
+static void
+send_message( char **to )
+{
+ int pid;
+#ifndef HAVE_WAITPID
+ WAITSTATUSTYPE status;
+#endif
+
+ if ( debug ) {
+ char buf[1024];
+ int i;
+
+ strcpy( buf, to[0] );
+ for ( i = 1; to[i] != NULL; i++ ) {
+ strcat( buf, " " );
+ strcat( buf, to[i] );
+ }
+
+ syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf );
+ }
+
+ /* parent */
+ if ( (pid = fork()) != 0 ) {
+#ifdef HAVE_WAITPID
+ waitpid( pid, (int *) NULL, 0 );
+#else
+ wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+ /* child */
+ } else {
+ /* to includes sendmailargs */
+ execv( MAIL500_SENDMAIL, to );
+
+ syslog( LOG_ALERT, "execv failed" );
+
+ exit( EX_TEMPFAIL );
+ }
+}
+
+static void
+send_group( Group **group, int ngroup )
+{
+ int i, pid;
+ char **argv;
+ int argc;
+ char *iargv[7];
+#ifndef HAVE_WAITPID
+ WAITSTATUSTYPE status;
+#endif
+
+ for ( i = 0; i < ngroup; i++ ) {
+ (void) rewind( stdin );
+
+ iargv[0] = MAIL500_SENDMAIL;
+ iargv[1] = "-f";
+ iargv[2] = group[i]->g_errorsto;
+ iargv[3] = "-oMrX.500";
+ iargv[4] = "-odi";
+ iargv[5] = "-oi";
+ iargv[6] = NULL;
+
+ argv = NULL;
+ argc = 0;
+ add_to( &argv, &argc, iargv );
+ add_to( &argv, &argc, group[i]->g_members );
+
+ if ( debug ) {
+ char buf[1024];
+ int i;
+
+ strcpy( buf, argv[0] );
+ for ( i = 1; i < argc; i++ ) {
+ strcat( buf, " " );
+ strcat( buf, argv[i] );
+ }
+
+ syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
+ }
+
+ /* parent */
+ if ( (pid = fork()) != 0 ) {
+#ifdef HAVE_WAITPID
+ waitpid( pid, (int *) NULL, 0 );
+#else
+ wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+ /* child */
+ } else {
+ execv( MAIL500_SENDMAIL, argv );
+
+ syslog( LOG_ALERT, "execv failed" );
+
+ exit( EX_TEMPFAIL );
+ }
+ }
+}
+
+static void
+send_errors( Error *err, int nerr )
+{
+ int pid, i, namelen;
+ FILE *fp;
+ int fd[2];
+ char *argv[8];
+ char buf[1024];
+#ifndef HAVE_WAITPID
+ WAITSTATUSTYPE status;
+#endif
+
+ if ( strcmp( MAIL500_BOUNCEFROM, mailfrom ) == 0 ) {
+ mailfrom = errorsfrom;
+ }
+
+ argv[0] = MAIL500_SENDMAIL;
+ argv[1] = "-oMrX.500";
+ argv[2] = "-odi";
+ argv[3] = "-oi";
+ argv[4] = "-f";
+ argv[5] = MAIL500_BOUNCEFROM;
+ argv[6] = mailfrom;
+ argv[7] = NULL;
+
+ if ( debug ) {
+ int i;
+
+ strcpy( buf, argv[0] );
+ for ( i = 1; argv[i] != NULL; i++ ) {
+ strcat( buf, " " );
+ strcat( buf, argv[i] );
+ }
+
+ syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
+ }
+
+ if ( pipe( fd ) == -1 ) {
+ syslog( LOG_ALERT, "cannot create pipe" );
+ exit( EX_TEMPFAIL );
+ }
+
+ if ( (pid = fork()) != 0 ) {
+ if ( (fp = fdopen( fd[1], "w" )) == NULL ) {
+ syslog( LOG_ALERT, "cannot fdopen pipe" );
+ exit( EX_TEMPFAIL );
+ }
+
+ fprintf( fp, "To: %s\n", mailfrom );
+ fprintf( fp, "From: %s\n", errorsfrom );
+ fprintf( fp, "Subject: undeliverable mail\n" );
+ fprintf( fp, "\n" );
+ fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
+ for ( i = 0; i < nerr; i++ ) {
+ namelen = strlen( err[i].e_addr );
+ fprintf( fp, "\n" );
+
+ switch ( err[i].e_code ) {
+ case E_USERUNKNOWN:
+ fprintf( fp, "%s: User unknown\n", err[i].e_addr );
+ break;
+
+ case E_GROUPUNKNOWN:
+ fprintf( fp, "%s: Group unknown\n", err[i].e_addr );
+ break;
+
+ case E_BADMEMBER:
+ fprintf( fp, "%s: Group member does not exist\n",
+ err[i].e_addr );
+ fprintf( fp, "This could be because the distinguished name of the person has changed\n" );
+ fprintf( fp, "If this is the case, the problem can be solved by removing and\n" );
+ fprintf( fp, "then re-adding the person to the group.\n" );
+ break;
+
+ case E_NOREQUEST:
+ fprintf( fp, "%s: Group exists but has no request address\n",
+ err[i].e_addr );
+ break;
+
+ case E_NOERRORS:
+ fprintf( fp, "%s: Group exists but has no errors-to address\n",
+ err[i].e_addr );
+ break;
+
+ case E_NOOWNER:
+ fprintf( fp, "%s: Group exists but has no owner\n",
+ err[i].e_addr );
+ break;
+
+ case E_AMBIGUOUS:
+ do_ambiguous( fp, &err[i], namelen );
+ break;
+
+ case E_NOEMAIL:
+ do_noemail( fp, &err[i], namelen );
+ break;
+
+ case E_MEMBERNOEMAIL:
+ fprintf( fp, "%s: Group member exists but does not have an email address\n",
+ err[i].e_addr );
+ break;
+
+ case E_JOINMEMBERNOEMAIL:
+ fprintf( fp, "%s: User has joined group but does not have an email address\n",
+ err[i].e_addr );
+ break;
+
+ case E_LOOP:
+ fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n",
+ err[i].e_addr, err[i].e_loop );
+ break;
+
+ case E_NOMEMBERS:
+ fprintf( fp, "%s: Group has no members\n",
+ err[i].e_addr );
+ break;
+
+ case E_NOOWNADDRESS:
+ fprintf( fp, "%s: Not enough information to perform required routing\n",
+ err[i].e_addr );
+ break;
+
+ default:
+ syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
+ unbind_and_exit( EX_TEMPFAIL );
+ break;
+ }
+ }
+
+ fprintf( fp, "\n------- The original message sent:\n\n" );
+
+ while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+ fputs( buf, fp );
+ }
+ fclose( fp );
+
+#ifdef HAVE_WAITPID
+ waitpid( pid, (int *) NULL, 0 );
+#else
+ wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+ } else {
+ dup2( fd[0], 0 );
+
+ execv( MAIL500_SENDMAIL, argv );
+
+ syslog( LOG_ALERT, "execv failed" );
+
+ exit( EX_TEMPFAIL );
+ }
+}
+
+static void
+do_noemail( FILE *fp, Error *err, int namelen )
+{
+ int i, last;
+ char *dn, *rdn;
+ char **ufn, **vals;
+
+ fprintf(fp, "%s: User has no email address registered.\n",
+ err->e_addr );
+ fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n",
+ namelen, " ", err->e_addr );
+
+ /* name */
+ dn = ldap_get_dn( ld, err->e_msg );
+ ufn = ldap_explode_dn( dn, 1 );
+ rdn = strdup( ufn[0] );
+ if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+ if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
+ != NULL ) {
+ for ( i = 0; vals[i]; i++ ) {
+ last = strlen( vals[i] ) - 1;
+ if ( isdigit((unsigned char) vals[i][last]) ) {
+ rdn = strdup( vals[i] );
+ break;
+ }
+ }
+
+ ldap_value_free( vals );
+ }
+ }
+ fprintf( fp, "%*s %s\n", namelen, " ", rdn );
+ free( dn );
+ free( rdn );
+ ldap_value_free( ufn );
+
+ /* titles or descriptions */
+ if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
+ (vals = ldap_get_values( ld, err->e_msg, "description" ))
+ == NULL ) {
+ fprintf( fp, "%*s No title or description registered\n",
+ namelen, " " );
+ } else {
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
+ }
+
+ ldap_value_free( vals );
+ }
+
+ /* postal address */
+ if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
+ == NULL ) {
+ fprintf( fp, "%*s No postal address registered\n", namelen,
+ " " );
+ } else {
+ fprintf( fp, "%*s ", namelen, " " );
+ for ( i = 0; vals[0][i] != '\0'; i++ ) {
+ if ( vals[0][i] == '$' ) {
+ fprintf( fp, "\n%*s ", namelen, " " );
+ while ( isspace((unsigned char) vals[0][i+1]) )
+ i++;
+ } else {
+ fprintf( fp, "%c", vals[0][i] );
+ }
+ }
+ fprintf( fp, "\n" );
+
+ ldap_value_free( vals );
+ }
+
+ /* telephone number */
+ if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
+ == NULL ) {
+ fprintf( fp, "%*s No phone number registered\n", namelen,
+ " " );
+ } else {
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ fprintf( fp, "%*s %s\n", namelen, " ", vals[i] );
+ }
+
+ ldap_value_free( vals );
+ }
+}
+
+/* ARGSUSED */
+static void
+do_ambiguous( FILE *fp, Error *err, int namelen )
+{
+ int i, last;
+ char *dn, *rdn;
+ char **ufn, **vals;
+ LDAPMessage *e;
+
+ i = ldap_result2error( ld, err->e_msg, 0 );
+
+ fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n",
+ err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
+ ldap_count_entries( ld, err->e_msg ) );
+
+ for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
+ e = ldap_next_entry( ld, e ) ) {
+ dn = ldap_get_dn( ld, e );
+ ufn = ldap_explode_dn( dn, 1 );
+ rdn = strdup( ufn[0] );
+ if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+ if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
+ for ( i = 0; vals[i]; i++ ) {
+ last = strlen( vals[i] ) - 1;
+ if (isdigit((unsigned char) vals[i][last])) {
+ rdn = strdup( vals[i] );
+ break;
+ }
+ }
+
+ ldap_value_free( vals );
+ }
+ }
+
+ /*
+ if ( isgroup( e ) ) {
+ vals = ldap_get_values( ld, e, "description" );
+ } else {
+ vals = ldap_get_values( ld, e, "title" );
+ }
+ */
+ vals = ldap_get_values( ld, e, "description" );
+
+ fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" );
+ for ( i = 1; vals && vals[i] != NULL; i++ ) {
+ fprintf( fp, " %s\n", vals[i] );
+ }
+
+ free( dn );
+ free( rdn );
+ ldap_value_free( ufn );
+ if ( vals != NULL )
+ ldap_value_free( vals );
+ }
+}
+
+static int
+count_values( char **list )
+{
+ int i;
+
+ for ( i = 0; list && list[i] != NULL; i++ )
+ ; /* NULL */
+
+ return( i );
+}
+
+static void
+add_to( char ***list, int *nlist, char **new )
+{
+ int i, nnew, oldnlist;
+
+ nnew = count_values( new );
+
+ oldnlist = *nlist;
+ if ( *list == NULL || *nlist == 0 ) {
+ *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
+ *nlist = nnew;
+ } else {
+ *list = (char **) realloc( *list, *nlist * sizeof(char *) +
+ nnew * sizeof(char *) + sizeof(char *) );
+ *nlist += nnew;
+ }
+
+ for ( i = 0; i < nnew; i++ )
+ (*list)[i + oldnlist] = strdup( new[i] );
+ (*list)[*nlist] = NULL;
+}
+
+static void
+add_single_to( char ***list, char *new )
+{
+ int nlist;
+
+ if ( *list == NULL ) {
+ nlist = 0;
+ *list = (char **) malloc( 2 * sizeof(char *) );
+ } else {
+ nlist = count_values( *list );
+ *list = (char **) realloc( *list,
+ ( nlist + 2 ) * sizeof(char *) );
+ }
+
+ (*list)[nlist] = strdup( new );
+ (*list)[nlist+1] = NULL;
+}
+
+static int
+isgroup( LDAPMessage *e )
+{
+ int i, j;
+ char **oclist;
+
+ if ( !groupclasses ) {
+ return( 0 );
+ }
+
+ oclist = ldap_get_values( ld, e, "objectClass" );
+
+ for ( i = 0; oclist[i] != NULL; i++ ) {
+ for ( j = 0; groupclasses[j] != NULL; j++ ) {
+ if ( strcasecmp( oclist[i], groupclasses[j] ) == 0 ) {
+ ldap_value_free( oclist );
+ return( 1 );
+ }
+ }
+ }
+ ldap_value_free( oclist );
+
+ return( 0 );
+}
+
+static void
+add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg )
+{
+ if ( *nerr == 0 ) {
+ *err = (Error *) malloc( sizeof(Error) );
+ } else {
+ *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
+ }
+
+ (*err)[*nerr].e_code = code;
+ (*err)[*nerr].e_addr = strdup( addr );
+ (*err)[*nerr].e_msg = msg;
+ (*nerr)++;
+}
+
+static void
+unbind_and_exit( int rc )
+{
+ int i;
+
+ if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
+ syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
+
+ exit( rc );
+}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/* ldapmodify.c - generic program to modify or add entries using LDAP */
+#include "portable.h"
+
#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <sys/types.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
+#endif
+#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#ifndef VMS
-#include <unistd.h>
-#endif /* VMS */
-#include <lber.h>
+#endif
+
#include <ldap.h>
-#include <ldif.h>
-#include "ldapconfig.h"
+#include "lutil_ldap.h"
+#include "ldif.h"
+#include "ldap_defaults.h"
+#include "ldap_log.h"
static char *prog;
-static char *binddn = LDAPMODIFY_BINDDN;
-static char *passwd = NULL;
-static char *ldaphost = LDAPHOST;
-static int ldapport = LDAP_PORT;
-static int new, replace, not, verbose, contoper, force, valsfromfiles;
-static LDAP *ld;
-
-#ifdef LDAP_DEBUG
-extern int ldap_debug, lber_debug;
-#endif /* LDAP_DEBUG */
-
-#define safe_realloc( ptr, size ) ( ptr == NULL ? malloc( size ) : \
- realloc( ptr, size ))
+static char *binddn = NULL;
+static struct berval passwd = { 0, NULL };
+static char *ldapuri = NULL;
+static char *ldaphost = NULL;
+static int ldapport = 0;
+#ifdef HAVE_CYRUS_SASL
+static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
+static char *sasl_realm = NULL;
+static char *sasl_authc_id = NULL;
+static char *sasl_authz_id = NULL;
+static char *sasl_mech = NULL;
+static char *sasl_secprops = NULL;
+#endif
+static int use_tls = 0;
+static int ldapadd, not, verbose, contoper, force;
+static LDAP *ld = NULL;
#define LDAPMOD_MAXLINE 4096
/* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
+#define T_VERSION_STR "version"
#define T_REPLICA_STR "replica"
#define T_DN_STR "dn"
#define T_CHANGETYPESTR "changetype"
#define T_MODIFYCTSTR "modify"
#define T_DELETECTSTR "delete"
#define T_MODRDNCTSTR "modrdn"
+#define T_MODDNCTSTR "moddn"
+#define T_RENAMECTSTR "rename"
#define T_MODOPADDSTR "add"
#define T_MODOPREPLACESTR "replace"
#define T_MODOPDELETESTR "delete"
#define T_MODSEPSTR "-"
#define T_NEWRDNSTR "newrdn"
#define T_DELETEOLDRDNSTR "deleteoldrdn"
+#define T_NEWSUPSTR "newsuperior"
+
+
+static void usage LDAP_P(( const char *prog )) LDAP_GCCATTR((noreturn));
+static int process_ldif_rec LDAP_P(( char *rbuf, int count ));
+static void addmodifyop LDAP_P((
+ LDAPMod ***pmodsp, int modop,
+ const char *attr,
+ struct berval *value ));
+static int domodify LDAP_P((
+ const char *dn,
+ LDAPMod **pmods,
+ int newentry ));
+static int dodelete LDAP_P((
+ const char *dn ));
+static int dorename LDAP_P((
+ const char *dn,
+ const char *newrdn,
+ const char *newsup,
+ int deleteoldrdn ));
+static char *read_one_record LDAP_P(( FILE *fp ));
+
+static void
+usage( const char *prog )
+{
+ fprintf( stderr,
+"Add or modify entries from an LDAP server\n\n"
+"usage: %s [options]\n"
+" The list of desired operations are read from stdin or from the file\n"
+" specified by \"-f file\".\n"
+"Add or modify options:\n"
+" -a add values (default%s)\n"
+" -F force all changes records to be used\n"
+
+"Common options:\n"
+" -d level set LDAP debugging level to `level'\n"
+" -D binddn bind DN\n"
+" -f file read operations from `file'\n"
+" -h host LDAP server\n"
+" -H URI LDAP Uniform Resource Indentifier(s)\n"
+" -I use SASL Interactive mode\n"
+" -k use Kerberos authentication\n"
+" -K like -k, but do only step 1 of the Kerberos bind\n"
+" -M enable Manage DSA IT control (-MM to make critical)\n"
+" -n show what would be done but don't actually update\n"
+" -O props SASL security properties\n"
+" -p port port on LDAP server\n"
+" -P version procotol version (default: 3)\n"
+" -Q use SASL Quiet mode\n"
+" -R realm SASL realm\n"
+" -U authcid SASL authentication identity\n"
+" -v run in verbose mode (diagnostics to standard output)\n"
+" -w passwd bind passwd (for simple authentication)\n"
+" -W prompt for bind passwd\n"
+" -x Simple authentication\n"
+" -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
+" -Y mech SASL mechanism\n"
+" -Z Start TLS request (-ZZ to require successful response)\n"
+ , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
+
+ exit( EXIT_FAILURE );
+}
-#ifdef NEEDPROTOS
-static int process_ldapmod_rec( char *rbuf );
-static int process_ldif_rec( char *rbuf );
-static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr,
- char *value, int vlen );
-static int domodify( char *dn, LDAPMod **pmods, int newentry );
-static int dodelete( char *dn );
-static int domodrdn( char *dn, char *newrdn, int deleteoldrdn );
-static void freepmods( LDAPMod **pmods );
-static int fromfile( char *path, struct berval *bv );
-static char *read_one_record( FILE *fp );
-#else /* NEEDPROTOS */
-static int process_ldapmod_rec();
-static int process_ldif_rec();
-static void addmodifyop();
-static int domodify();
-static int dodelete();
-static int domodrdn();
-static void freepmods();
-static int fromfile();
-static char *read_one_record();
-#endif /* NEEDPROTOS */
-
-
-main( argc, argv )
- int argc;
- char **argv;
+int
+main( int argc, char **argv )
{
- char *infile, *rbuf, *start, *p, *q;
+ char *infile, *rbuf, *start;
FILE *fp;
- int rc, i, kerberos, use_ldif, authmethod;
- char *usage = "usage: %s [-abcknrvF] [-d debug-level] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile ]\n";
+ int rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals;
+ int count;
- extern char *optarg;
- extern int optind;
-
- if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
+ if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
prog = argv[ 0 ];
} else {
++prog;
}
- new = ( strcmp( prog, "ldapadd" ) == 0 );
+
+ /* Print usage when no parameters */
+ if( argc < 2 ) usage( prog );
+
+ /* strncmp instead of strcmp since NT binaries carry .exe extension */
+ ldapadd = ( strncmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
infile = NULL;
- kerberos = not = verbose = valsfromfiles = 0;
+ not = verbose = want_bindpw = debug = manageDSAit = referrals = 0;
+ authmethod = -1;
+ version = -1;
- while (( i = getopt( argc, argv, "FabckKnrtvh:p:D:w:d:f:" )) != EOF ) {
+ while (( i = getopt( argc, argv, "acrf:F"
+ "Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF )
+ {
switch( i ) {
+ /* Modify Options */
case 'a': /* add */
- new = 1;
- break;
- case 'b': /* read values from files (for binary attributes) */
- valsfromfiles = 1;
+ ldapadd = 1;
break;
case 'c': /* continuous operation */
contoper = 1;
break;
- case 'r': /* default is to replace rather than add values */
- replace = 1;
- break;
- case 'k': /* kerberos bind */
- kerberos = 2;
- break;
- case 'K': /* kerberos bind, part 1 only */
- kerberos = 1;
+ case 'f': /* read from file */
+ if( infile != NULL ) {
+ fprintf( stderr, "%s: -f previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ infile = strdup( optarg );
break;
case 'F': /* force all changes records to be used */
force = 1;
break;
- case 'h': /* ldap host */
- ldaphost = strdup( optarg );
+
+ /* Common Options */
+ case 'C':
+ referrals++;
+ break;
+ case 'd':
+ debug |= atoi( optarg );
break;
case 'D': /* bind DN */
+ if( binddn != NULL ) {
+ fprintf( stderr, "%s: -D previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
binddn = strdup( optarg );
break;
- case 'w': /* password */
- passwd = strdup( optarg );
+ case 'h': /* ldap host */
+ if( ldapuri != NULL ) {
+ fprintf( stderr, "%s: -h incompatible with -H\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( ldaphost != NULL ) {
+ fprintf( stderr, "%s: -h previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ ldaphost = strdup( optarg );
break;
- case 'd':
-#ifdef LDAP_DEBUG
- ldap_debug = lber_debug = atoi( optarg ); /* */
-#else /* LDAP_DEBUG */
- fprintf( stderr, "%s: compile with -DLDAP_DEBUG for debugging\n",
- prog );
-#endif /* LDAP_DEBUG */
+ case 'H': /* ldap URI */
+ if( ldaphost != NULL ) {
+ fprintf( stderr, "%s: -H incompatible with -h\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( ldapport ) {
+ fprintf( stderr, "%s: -H incompatible with -p\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( ldapuri != NULL ) {
+ fprintf( stderr, "%s: -H previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ ldapuri = strdup( optarg );
break;
- case 'f': /* read from file */
- infile = strdup( optarg );
+ case 'I':
+#ifdef HAVE_CYRUS_SASL
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -I incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible previous "
+ "authentication choice\n",
+ prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_flags = LDAP_SASL_INTERACTIVE;
+ break;
+#else
+ fprintf( stderr, "%s: was not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ case 'k': /* kerberos bind */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+ if( version > LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+
+ if( authmethod != -1 ) {
+ fprintf( stderr, "%s: -k incompatible with previous "
+ "authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+
+ authmethod = LDAP_AUTH_KRBV4;
+#else
+ fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+ return EXIT_FAILURE;
+#endif
break;
- case 'p':
- ldapport = atoi( optarg );
+ case 'K': /* kerberos bind, part one only */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+ if( version > LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 ) {
+ fprintf( stderr, "%s: incompatible with previous "
+ "authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+
+ authmethod = LDAP_AUTH_KRBV41;
+#else
+ fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+ return( EXIT_FAILURE );
+#endif
break;
- case 'n': /* print adds, don't actually do them */
+ case 'M':
+ /* enable Manage DSA IT */
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ manageDSAit++;
+ version = LDAP_VERSION3;
+ break;
+ case 'n': /* print deletes, don't actually do them */
++not;
break;
+ case 'O':
+#ifdef HAVE_CYRUS_SASL
+ if( sasl_secprops != NULL ) {
+ fprintf( stderr, "%s: -O previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible previous "
+ "authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_secprops = strdup( optarg );
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
+ case 'p':
+ if( ldapport ) {
+ fprintf( stderr, "%s: -p previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ ldapport = atoi( optarg );
+ break;
+ case 'P':
+ switch( atoi(optarg) ) {
+ case 2:
+ if( version == LDAP_VERSION3 ) {
+ fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ version = LDAP_VERSION2;
+ break;
+ case 3:
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ version = LDAP_VERSION3;
+ break;
+ default:
+ fprintf( stderr, "%s: protocol version should be 2 or 3\n",
+ prog );
+ usage( prog );
+ return( EXIT_FAILURE );
+ } break;
+ case 'Q':
+#ifdef HAVE_CYRUS_SASL
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -Q incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible previous "
+ "authentication choice\n",
+ prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_flags = LDAP_SASL_QUIET;
+ break;
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ case 'r': /* replace (obsolete) */
+ break;
+
+ case 'R':
+#ifdef HAVE_CYRUS_SASL
+ if( sasl_realm != NULL ) {
+ fprintf( stderr, "%s: -R previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -R incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible previous "
+ "authentication choice\n",
+ prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_realm = strdup( optarg );
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
+ case 'U':
+#ifdef HAVE_CYRUS_SASL
+ if( sasl_authc_id != NULL ) {
+ fprintf( stderr, "%s: -U previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -U incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible previous "
+ "authentication choice\n",
+ prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_authc_id = strdup( optarg );
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
case 'v': /* verbose mode */
verbose++;
break;
+ case 'w': /* password */
+ passwd.bv_val = strdup( optarg );
+ {
+ char* p;
+
+ for( p = optarg; *p != '\0'; p++ ) {
+ *p = '\0';
+ }
+ }
+ passwd.bv_len = strlen( passwd.bv_val );
+ break;
+ case 'W':
+ want_bindpw++;
+ break;
+ case 'Y':
+#ifdef HAVE_CYRUS_SASL
+ if( sasl_mech != NULL ) {
+ fprintf( stderr, "%s: -Y previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -Y incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_mech = strdup( optarg );
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
+ case 'x':
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
+ fprintf( stderr, "%s: incompatible with previous "
+ "authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SIMPLE;
+ break;
+ case 'X':
+#ifdef HAVE_CYRUS_SASL
+ if( sasl_authz_id != NULL ) {
+ fprintf( stderr, "%s: -X previously specified\n", prog );
+ return EXIT_FAILURE;
+ }
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+ fprintf( stderr, "%s: -X incompatible with "
+ "authentication choice\n", prog );
+ return EXIT_FAILURE;
+ }
+ authmethod = LDAP_AUTH_SASL;
+ version = LDAP_VERSION3;
+ sasl_authz_id = strdup( optarg );
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
+ case 'Z':
+#ifdef HAVE_TLS
+ if( version == LDAP_VERSION2 ) {
+ fprintf( stderr, "%s: -Z incompatible with version %d\n",
+ prog, version );
+ return EXIT_FAILURE;
+ }
+ version = LDAP_VERSION3;
+ use_tls++;
+#else
+ fprintf( stderr, "%s: not compiled with TLS support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
+ break;
default:
- fprintf( stderr, usage, prog );
- exit( 1 );
+ fprintf( stderr, "%s: unrecognized option -%c\n",
+ prog, optopt );
+ usage( prog );
}
}
- if ( argc - optind != 0 ) {
- fprintf( stderr, usage, prog );
- exit( 1 );
- }
+ if (version == -1) {
+ version = LDAP_VERSION3;
+ }
+ if (authmethod == -1 && version > LDAP_VERSION2) {
+#ifdef HAVE_CYRUS_SASL
+ authmethod = LDAP_AUTH_SASL;
+#else
+ authmethod = LDAP_AUTH_SIMPLE;
+#endif
+ }
+
+ if ( argc != optind )
+ usage( prog );
if ( infile != NULL ) {
if (( fp = fopen( infile, "r" )) == NULL ) {
perror( infile );
- exit( 1 );
+ return( EXIT_FAILURE );
}
} else {
fp = stdin;
}
+ if ( debug ) {
+ if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
+ fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
+ }
+ if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
+ fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
+ }
+ ldif_debug = debug;
+ }
+
+#ifdef SIGPIPE
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
+#ifdef NEW_LOGGING
+ lutil_log_initialize( argc, argv );
+#endif
if ( !not ) {
- if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
- perror( "ldap_open" );
- exit( 1 );
- }
+ if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
+ if ( verbose ) {
+ fprintf( stderr, "ldap_init( %s, %d )\n",
+ ldaphost != NULL ? ldaphost : "<DEFAULT>",
+ ldapport );
+ }
- ld->ld_deref = LDAP_DEREF_NEVER; /* this seems prudent */
+ ld = ldap_init( ldaphost, ldapport );
+ if( ld == NULL ) {
+ perror("ldapmodify: ldap_init");
+ return EXIT_FAILURE;
+ }
- if ( !kerberos ) {
- authmethod = LDAP_AUTH_SIMPLE;
- } else if ( kerberos == 1 ) {
- authmethod = LDAP_AUTH_KRBV41;
} else {
- authmethod = LDAP_AUTH_KRBV4;
+ if ( verbose ) {
+ fprintf( stderr, "ldap_initialize( %s )\n",
+ ldapuri != NULL ? ldapuri : "<DEFAULT>" );
+ }
+
+ rc = ldap_initialize( &ld, ldapuri );
+ if( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
+ rc, ldap_err2string(rc) );
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* referrals */
+ if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
+ referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
+ {
+ fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
+ referrals ? "on" : "off" );
+ return EXIT_FAILURE;
+ }
+
+
+ if (version == -1 ) {
+ version = LDAP_VERSION3;
+ }
+
+ if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
+ != LDAP_OPT_SUCCESS )
+ {
+ fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
+ version );
+ return EXIT_FAILURE;
}
- if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
- ldap_perror( ld, "ldap_bind" );
- exit( 1 );
+
+ if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
+ ldap_perror( ld, "ldap_start_tls" );
+ if ( use_tls > 1 ) {
+ return( EXIT_FAILURE );
+ }
+ }
+
+ if (want_bindpw) {
+ passwd.bv_val = getpassphrase("Enter LDAP Password: ");
+ passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
+ }
+
+ if ( authmethod == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+ void *defaults;
+
+ if( sasl_secprops != NULL ) {
+ rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
+ (void *) sasl_secprops );
+
+ if( rc != LDAP_OPT_SUCCESS ) {
+ fprintf( stderr,
+ "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
+ sasl_secprops );
+ return( EXIT_FAILURE );
+ }
+ }
+
+ defaults = lutil_sasl_defaults( ld,
+ sasl_mech,
+ sasl_realm,
+ sasl_authc_id,
+ passwd.bv_val,
+ sasl_authz_id );
+
+ rc = ldap_sasl_interactive_bind_s( ld, binddn,
+ sasl_mech, NULL, NULL,
+ sasl_flags, lutil_sasl_interact, defaults );
+
+ if( rc != LDAP_SUCCESS ) {
+ ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
+ return( EXIT_FAILURE );
+ }
+#else
+ fprintf( stderr, "%s: not compiled with SASL support\n",
+ prog );
+ return( EXIT_FAILURE );
+#endif
}
+ else {
+ if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
+ != LDAP_SUCCESS ) {
+ ldap_perror( ld, "ldap_bind" );
+ return( EXIT_FAILURE );
+ }
+ }
+
}
rc = 0;
+ if ( manageDSAit ) {
+ 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 = manageDSAit > 1;
+
+ err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
+
+ if( err != LDAP_OPT_SUCCESS ) {
+ fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
+ c.ldctl_iscritical ? "critical " : "" );
+ if( c.ldctl_iscritical ) {
+ exit( EXIT_FAILURE );
+ }
+ }
+ }
+
+ count = 0;
while (( rc == 0 || contoper ) &&
( rbuf = read_one_record( fp )) != NULL ) {
- /*
- * we assume record is ldif/slapd.replog if the first line
- * has a colon that appears to the left of any equal signs, OR
- * if the first line consists entirely of digits (an entry id)
- */
- use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
- ( q = strchr( rbuf, '\n' )) != NULL && p < q &&
- (( q = strchr( rbuf, '=' )) == NULL || p < q );
+ count++;
start = rbuf;
- if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
- for ( p = rbuf; p < q; ++p ) {
- if ( !isdigit( *p )) {
- break;
- }
- }
- if ( p >= q ) {
- use_ldif = 1;
- start = q + 1;
- }
- }
-
- if ( use_ldif ) {
- rc = process_ldif_rec( start );
- } else {
- rc = process_ldapmod_rec( start );
- }
+ rc = process_ldif_rec( start, count );
- free( rbuf );
+ if( rc )
+ fprintf( stderr, "ldif_record() = %d\n", rc );
+ free( rbuf );
}
if ( !not ) {
- ldap_unbind( ld );
+ ldap_unbind( ld );
}
- exit( rc );
+ return( rc );
}
static int
-process_ldif_rec( char *rbuf )
+process_ldif_rec( char *rbuf, int count )
{
- char *line, *dn, *type, *value, *newrdn, *p;
- int rc, linenum, vlen, modop, replicaport;
- int expect_modop, expect_sep, expect_ct, expect_newrdn;
+ char *line, *dn, *type, *newrdn, *newsup, *p;
+ int rc, linenum, modop, replicaport;
+ int expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
int expect_deleteoldrdn, deleteoldrdn;
int saw_replica, use_record, new_entry, delete_entry, got_all;
LDAPMod **pmods;
+ int version;
+ struct berval val;
- new_entry = new;
+ new_entry = ldapadd;
- rc = got_all = saw_replica = delete_entry = expect_modop = 0;
- expect_deleteoldrdn = expect_newrdn = expect_sep = expect_ct = 0;
+ rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
+ expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
+ expect_sep = expect_ct = 0;
linenum = 0;
+ version = 0;
deleteoldrdn = 1;
use_record = force;
pmods = NULL;
- dn = newrdn = NULL;
+ dn = newrdn = newsup = NULL;
- while ( rc == 0 && ( line = str_getline( &rbuf )) != NULL ) {
+ while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
++linenum;
+
if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
expect_sep = 0;
expect_ct = 1;
continue;
}
- if ( str_parse_line( line, &type, &value, &vlen ) < 0 ) {
- fprintf( stderr, "%s: invalid format (line %d of entry: %s\n",
+ if ( ldif_parse_line( line, &type, &val.bv_val, &val.bv_len ) < 0 ) {
+ fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
prog, linenum, dn == NULL ? "" : dn );
rc = LDAP_PARAM_ERROR;
break;
if ( dn == NULL ) {
if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
++saw_replica;
- if (( p = strchr( value, ':' )) == NULL ) {
- replicaport = LDAP_PORT;
+ if (( p = strchr( val.bv_val, ':' )) == NULL ) {
+ replicaport = 0;
} else {
*p++ = '\0';
replicaport = atoi( p );
}
- if ( strcasecmp( value, ldaphost ) == 0 &&
+ if ( ldaphost != NULL && strcasecmp( val.bv_val, ldaphost ) == 0 &&
replicaport == ldapport ) {
use_record = 1;
}
+ } else if ( count == 1 && linenum == 1 &&
+ strcasecmp( type, T_VERSION_STR ) == 0 )
+ {
+ if( val.bv_len == 0 || atoi(val.bv_val) != 1 ) {
+ fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
+ prog, val.bv_val == NULL ? "(null)" : val.bv_val, linenum );
+ }
+ version++;
+
} else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
- if (( dn = strdup( value )) == NULL ) {
+ if (( dn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
perror( "strdup" );
- exit( 1 );
+ exit( EXIT_FAILURE );
}
expect_ct = 1;
}
- continue; /* skip all lines until we see "dn:" */
+ goto end_line; /* skip all lines until we see "dn:" */
}
if ( expect_ct ) {
expect_ct = 0;
if ( !use_record && saw_replica ) {
- printf( "%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n",
+ printf( "%s: skipping change record for entry: %s\n"
+ "\t(LDAP host/port does not match replica: lines)\n",
prog, dn );
free( dn );
+ ber_memfree( type );
+ ber_memfree( val.bv_val );
return( 0 );
}
if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
- if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
+#ifdef LIBERAL_CHANGETYPE_MODOP
+ /* trim trailing spaces (and log warning ...) */
+
+ int icnt;
+ for ( icnt = val.bv_len; --icnt > 0; ) {
+ if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
+ break;
+ }
+ }
+
+ if ( ++icnt != val.bv_len ) {
+ fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
+ prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
+ val.bv_val[icnt] = '\0';
+ }
+#endif /* LIBERAL_CHANGETYPE_MODOP */
+
+ if ( strcasecmp( val.bv_val, T_MODIFYCTSTR ) == 0 ) {
new_entry = 0;
expect_modop = 1;
- } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
+ } else if ( strcasecmp( val.bv_val, T_ADDCTSTR ) == 0 ) {
new_entry = 1;
- } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) {
+ } else if ( strcasecmp( val.bv_val, T_MODRDNCTSTR ) == 0
+ || strcasecmp( val.bv_val, T_MODDNCTSTR ) == 0
+ || strcasecmp( val.bv_val, T_RENAMECTSTR ) == 0)
+ {
expect_newrdn = 1;
- } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
+ } else if ( strcasecmp( val.bv_val, T_DELETECTSTR ) == 0 ) {
got_all = delete_entry = 1;
} else {
fprintf( stderr,
- "%s: unknown %s \"%s\" (line %d of entry: %s)\n",
- prog, T_CHANGETYPESTR, value, linenum, dn );
+ "%s: unknown %s \"%s\" (line %d of entry \"%s\")\n",
+ prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
- continue;
- } else if ( new ) { /* missing changetype => add */
+ goto end_line;
+ } else if ( ldapadd ) { /* missing changetype => add */
new_entry = 1;
modop = LDAP_MOD_ADD;
} else {
}
if ( expect_modop ) {
+#ifdef LIBERAL_CHANGETYPE_MODOP
+ /* trim trailing spaces (and log warning ...) */
+
+ int icnt;
+ for ( icnt = val.bv_len; --icnt > 0; ) {
+ if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
+ break;
+ }
+ }
+
+ if ( ++icnt != val.bv_len ) {
+ fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
+ prog, type, val.bv_val, linenum, dn );
+ val.bv_val[icnt] = '\0';
+ }
+#endif /* LIBERAL_CHANGETYPE_MODOP */
+
expect_modop = 0;
expect_sep = 1;
if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
modop = LDAP_MOD_ADD;
- continue;
+ goto end_line;
} else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
modop = LDAP_MOD_REPLACE;
- continue;
+ addmodifyop( &pmods, modop, val.bv_val, NULL );
+ goto end_line;
} else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
modop = LDAP_MOD_DELETE;
- addmodifyop( &pmods, modop, value, NULL, 0 );
- continue;
+ addmodifyop( &pmods, modop, val.bv_val, NULL );
+ goto end_line;
} else { /* no modify op: use default */
- modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
+ modop = ldapadd ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
}
}
if ( expect_newrdn ) {
if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
- if (( newrdn = strdup( value )) == NULL ) {
+ if (( newrdn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
perror( "strdup" );
- exit( 1 );
+ exit( EXIT_FAILURE );
}
expect_deleteoldrdn = 1;
expect_newrdn = 0;
} else {
- fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
+ fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
prog, T_NEWRDNSTR, type, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
} else if ( expect_deleteoldrdn ) {
if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
- deleteoldrdn = ( *value == '0' ) ? 0 : 1;
+ deleteoldrdn = ( *val.bv_val == '0' ) ? 0 : 1;
+ expect_deleteoldrdn = 0;
+ expect_newsup = 1;
got_all = 1;
} else {
- fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
+ fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
prog, T_DELETEOLDRDNSTR, type, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
+ } else if ( expect_newsup ) {
+ if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
+ if (( newsup = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
+ perror( "strdup" );
+ exit( EXIT_FAILURE );
+ }
+ expect_newsup = 0;
+ } else {
+ fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
+ prog, T_NEWSUPSTR, type, linenum, dn );
+ rc = LDAP_PARAM_ERROR;
+ }
} else if ( got_all ) {
fprintf( stderr,
- "%s: extra lines at end (line %d of entry %s)\n",
+ "%s: extra lines at end (line %d of entry \"%s\")\n",
prog, linenum, dn );
rc = LDAP_PARAM_ERROR;
} else {
- addmodifyop( &pmods, modop, type, value, vlen );
+ addmodifyop( &pmods, modop, type, val.bv_val == NULL ? NULL : &val );
}
+
+end_line:
+ ber_memfree( type );
+ ber_memfree( val.bv_val );
}
+ if( linenum == 0 ) {
+ return 0;
+ }
+
+ if( version && linenum == 1 ) {
+ return 0;
+ }
+
if ( rc == 0 ) {
if ( delete_entry ) {
rc = dodelete( dn );
} else if ( newrdn != NULL ) {
- rc = domodrdn( dn, newrdn, deleteoldrdn );
+ rc = dorename( dn, newrdn, newsup, deleteoldrdn );
} else {
rc = domodify( dn, pmods, new_entry );
}
free( newrdn );
}
if ( pmods != NULL ) {
- freepmods( pmods );
+ ldap_mods_free( pmods, 1 );
}
return( rc );
}
-static int
-process_ldapmod_rec( char *rbuf )
+static void
+addmodifyop(
+ LDAPMod ***pmodsp,
+ int modop,
+ const char *attr,
+ struct berval *val )
{
- char *line, *dn, *p, *q, *attr, *value;
- int rc, linenum, modop;
- LDAPMod **pmods;
-
- pmods = NULL;
- dn = NULL;
- linenum = 0;
- line = rbuf;
- rc = 0;
-
- while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
- ++linenum;
- if (( p = strchr( rbuf, '\n' )) == NULL ) {
- rbuf = NULL;
- } else {
- if ( *(p-1) == '\\' ) { /* lines ending in '\' are continued */
- strcpy( p - 1, p );
- rbuf = p;
- continue;
- }
- *p++ = '\0';
- rbuf = p;
+ LDAPMod **pmods;
+ int i, j;
+
+ pmods = *pmodsp;
+ modop |= LDAP_MOD_BVALUES;
+
+ i = 0;
+ if ( pmods != NULL ) {
+ for ( ; pmods[ i ] != NULL; ++i ) {
+ if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
+ pmods[ i ]->mod_op == modop )
+ {
+ break;
+ }
+ }
}
- if ( dn == NULL ) { /* first line contains DN */
- if (( dn = strdup( line )) == NULL ) {
- perror( "strdup" );
- exit( 1 );
- }
- } else {
- if (( p = strchr( line, '=' )) == NULL ) {
- value = NULL;
- p = line + strlen( line );
- } else {
- *p++ = '\0';
- value = p;
- }
-
- for ( attr = line; *attr != '\0' && isspace( *attr ); ++attr ) {
- ; /* skip attribute leading white space */
- }
-
- for ( q = p - 1; q > attr && isspace( *q ); --q ) {
- *q = '\0'; /* remove attribute trailing white space */
- }
-
- if ( value != NULL ) {
- while ( isspace( *value )) {
- ++value; /* skip value leading white space */
- }
- for ( q = value + strlen( value ) - 1; q > value &&
- isspace( *q ); --q ) {
- *q = '\0'; /* remove value trailing white space */
- }
- if ( *value == '\0' ) {
- value = NULL;
+ if ( pmods == NULL || pmods[ i ] == NULL ) {
+ if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
+ sizeof( LDAPMod * ))) == NULL )
+ {
+ perror( "realloc" );
+ exit( EXIT_FAILURE );
}
- }
+ *pmodsp = pmods;
+ pmods[ i + 1 ] = NULL;
- if ( value == NULL && new ) {
- fprintf( stderr, "%s: missing value on line %d (attr is %s)\n",
- prog, linenum, attr );
- rc = LDAP_PARAM_ERROR;
- } else {
- switch ( *attr ) {
- case '-':
- modop = LDAP_MOD_DELETE;
- ++attr;
- break;
- case '+':
- modop = LDAP_MOD_ADD;
- ++attr;
- break;
- default:
- modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
+ pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod ));
+ if ( pmods[ i ] == NULL ) {
+ perror( "calloc" );
+ exit( EXIT_FAILURE );
}
- addmodifyop( &pmods, modop, attr, value,
- ( value == NULL ) ? 0 : strlen( value ));
- }
- }
-
- line = rbuf;
- }
-
- if ( rc == 0 ) {
- if ( dn == NULL ) {
- rc = LDAP_PARAM_ERROR;
- } else if (( rc = domodify( dn, pmods, new )) == LDAP_SUCCESS ) {
- rc = 0;
- }
- }
-
- if ( pmods != NULL ) {
- freepmods( pmods );
- }
- if ( dn != NULL ) {
- free( dn );
- }
-
- return( rc );
-}
-
-
-static void
-addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
-{
- LDAPMod **pmods;
- int i, j;
- struct berval *bvp;
-
- pmods = *pmodsp;
- modop |= LDAP_MOD_BVALUES;
-
- i = 0;
- if ( pmods != NULL ) {
- for ( ; pmods[ i ] != NULL; ++i ) {
- if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
- pmods[ i ]->mod_op == modop ) {
- break;
- }
+ pmods[ i ]->mod_op = modop;
+ pmods[ i ]->mod_type = ber_strdup( attr );
+ if ( pmods[ i ]->mod_type == NULL ) {
+ perror( "strdup" );
+ exit( EXIT_FAILURE );
+ }
}
- }
- if ( pmods == NULL || pmods[ i ] == NULL ) {
- if (( pmods = (LDAPMod **)safe_realloc( pmods, (i + 2) *
- sizeof( LDAPMod * ))) == NULL ) {
- perror( "safe_realloc" );
- exit( 1 );
- }
- *pmodsp = pmods;
- pmods[ i + 1 ] = NULL;
- if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
- == NULL ) {
- perror( "calloc" );
- exit( 1 );
- }
- pmods[ i ]->mod_op = modop;
- if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
- perror( "strdup" );
- exit( 1 );
- }
- }
+ if ( val != NULL ) {
+ j = 0;
+ if ( pmods[ i ]->mod_bvalues != NULL ) {
+ for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
+ /* Empty */;
+ }
+ }
- if ( value != NULL ) {
- j = 0;
- if ( pmods[ i ]->mod_bvalues != NULL ) {
- for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
- ;
- }
- }
- if (( pmods[ i ]->mod_bvalues =
- (struct berval **)safe_realloc( pmods[ i ]->mod_bvalues,
- (j + 2) * sizeof( struct berval * ))) == NULL ) {
- perror( "safe_realloc" );
- exit( 1 );
- }
- pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
- if (( bvp = (struct berval *)malloc( sizeof( struct berval )))
- == NULL ) {
- perror( "malloc" );
- exit( 1 );
- }
- pmods[ i ]->mod_bvalues[ j ] = bvp;
+ pmods[ i ]->mod_bvalues = (struct berval **) ber_memrealloc(
+ pmods[ i ]->mod_bvalues, (j + 2) * sizeof( struct berval * ));
+ if ( pmods[ i ]->mod_bvalues == NULL ) {
+ perror( "ber_realloc" );
+ exit( EXIT_FAILURE );
+ }
- if ( valsfromfiles && *value == '/' ) { /* get value from file */
- if ( fromfile( value, bvp ) < 0 ) {
- exit( 1 );
- }
- } else {
- bvp->bv_len = vlen;
- if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) {
- perror( "malloc" );
- exit( 1 );
- }
- SAFEMEMCPY( bvp->bv_val, value, vlen );
- bvp->bv_val[ vlen ] = '\0';
+ pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
+ pmods[ i ]->mod_bvalues[ j ] = ber_bvdup( val );
+ if ( pmods[ i ]->mod_bvalues[ j ] == NULL ) {
+ perror( "ber_bvdup" );
+ exit( EXIT_FAILURE );
+ }
}
- }
}
static int
-domodify( char *dn, LDAPMod **pmods, int newentry )
+domodify(
+ const char *dn,
+ LDAPMod **pmods,
+ int newentry )
{
int i, j, k, notascii, op;
struct berval *bvp;
if ( pmods == NULL ) {
- fprintf( stderr, "%s: no attributes to change or add (entry %s)\n",
+ fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
prog, dn );
return( LDAP_PARAM_ERROR );
+ }
+
+ for ( i = 0; pmods[ i ] != NULL; ++i ) {
+ op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
+ if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) {
+ fprintf( stderr,
+ "%s: attribute \"%s\" has no values (entry=\"%s\")\n",
+ prog, pmods[i]->mod_type, dn );
+ return LDAP_PARAM_ERROR;
+ }
}
if ( verbose ) {
for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
bvp = pmods[ i ]->mod_bvalues[ j ];
notascii = 0;
- for ( k = 0; k < bvp->bv_len; ++k ) {
+ for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
if ( !isascii( bvp->bv_val[ k ] )) {
notascii = 1;
break;
}
if ( newentry ) {
- printf( "%sadding new entry %s\n", not ? "!" : "", dn );
+ printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
} else {
- printf( "%smodifying entry %s\n", not ? "!" : "", dn );
+ printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
}
if ( !not ) {
i = ldap_modify_s( ld, dn, pmods );
}
if ( i != LDAP_SUCCESS ) {
- ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
+ /* print error message about failed update including DN */
+ fprintf( stderr, "%s: update failed: %s\n", prog, dn );
+ ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
} else if ( verbose ) {
printf( "modify complete\n" );
}
static int
-dodelete( char *dn )
+dodelete(
+ const char *dn )
{
int rc;
- printf( "%sdeleting entry %s\n", not ? "!" : "", dn );
+ printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
if ( !not ) {
if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
- ldap_perror( ld, "ldap_delete" );
+ fprintf( stderr, "%s: delete failed: %s\n", prog, dn );
+ ldap_perror( ld, "ldap_delete" );
} else if ( verbose ) {
printf( "delete complete" );
}
static int
-domodrdn( char *dn, char *newrdn, int deleteoldrdn )
+dorename(
+ const char *dn,
+ const char *newrdn,
+ const char* newsup,
+ int deleteoldrdn )
{
int rc;
+
+ printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
if ( verbose ) {
- printf( "new RDN: %s (%skeep existing values)\n",
+ printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
newrdn, deleteoldrdn ? "do not " : "" );
}
-
- printf( "%smodifying rdn of entry %s\n", not ? "!" : "", dn );
if ( !not ) {
- if (( rc = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
- != LDAP_SUCCESS ) {
- ldap_perror( ld, "ldap_modrdn" );
+ if (( rc = ldap_rename2_s( ld, dn, newrdn, newsup, deleteoldrdn ))
+ != LDAP_SUCCESS )
+ {
+ fprintf( stderr, "%s: rename failed: %s\n", prog, dn );
+ ldap_perror( ld, "ldap_modrdn" );
} else {
printf( "modrdn completed\n" );
}
}
-
-static void
-freepmods( LDAPMod **pmods )
-{
- int i;
-
- for ( i = 0; pmods[ i ] != NULL; ++i ) {
- if ( pmods[ i ]->mod_bvalues != NULL ) {
- ber_bvecfree( pmods[ i ]->mod_bvalues );
- }
- if ( pmods[ i ]->mod_type != NULL ) {
- free( pmods[ i ]->mod_type );
- }
- free( pmods[ i ] );
- }
- free( pmods );
-}
-
-
-static int
-fromfile( char *path, struct berval *bv )
-{
- FILE *fp;
- long rlen;
- int eof;
-
- if (( fp = fopen( path, "r" )) == NULL ) {
- perror( path );
- return( -1 );
- }
-
- if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
- perror( path );
- fclose( fp );
- return( -1 );
- }
-
- bv->bv_len = ftell( fp );
-
- if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
- perror( "malloc" );
- fclose( fp );
- return( -1 );
- }
-
- if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
- perror( path );
- fclose( fp );
- return( -1 );
- }
-
- rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
- eof = feof( fp );
- fclose( fp );
-
- if ( rlen != bv->bv_len ) {
- perror( path );
- free( bv->bv_val );
- return( -1 );
- }
-
- return( bv->bv_len );
-}
-
-
static char *
read_one_record( FILE *fp )
{
- int len;
char *buf, line[ LDAPMOD_MAXLINE ];
int lcur, lmax;
lcur = lmax = 0;
buf = NULL;
- while (( fgets( line, sizeof(line), fp ) != NULL ) &&
- (( len = strlen( line )) > 1 )) {
- if ( lcur + len + 1 > lmax ) {
- lmax = LDAPMOD_MAXLINE
- * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
- if (( buf = (char *)safe_realloc( buf, lmax )) == NULL ) {
- perror( "safe_realloc" );
- exit( 1 );
- }
- }
- strcpy( buf + lcur, line );
- lcur += len;
+ while ( fgets( line, sizeof(line), fp ) != NULL ) {
+ int len = strlen( line );
+
+ if( len < 2 || ( len == 3 && *line == '\r' )) {
+ if( buf == NULL ) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if ( lcur + len + 1 > lmax ) {
+ lmax = LDAPMOD_MAXLINE
+ * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
+
+ if (( buf = (char *)realloc( buf, lmax )) == NULL ) {
+ perror( "realloc" );
+ exit( EXIT_FAILURE );
+ }
+ }
+
+ strcpy( buf + lcur, line );
+ lcur += len;
}
return( buf );
--- /dev/null
+.TH LDAP_SCHEMA 3 "4 June 2000" "OpenLDAP LDVERSION"
+.\" $OpenLDAP$
+.\" Copyright 2000-2002 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
+.SH NAME
+ldap_str2syntax, ldap_syntax2str, ldap_syntax2name, ldap_syntax_free,
+ldap_str2matchingrule, ldap_matchingrule2str, ldap_matchingrule2name,
+ldap_matchingrule_free,
+ldap_str2attributetype, ldap_attributetype2str,
+ldap_attributetype2name, ldap_attributetype_free,
+ldap_str2objectclass, ldap_objectclass2str, ldap_objectclass2name,
+ldap_objectclass_free,
+ldap_scherr2str \- Schema definition handling routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <ldap.h>
+#include <ldap_schema.h>
+.LP
+.ft B
+LDAPSyntax * ldap_str2syntax(s, code, errp, flags)
+.ft
+const char * s;
+int * code;
+const char ** errp;
+const int flags;
+.LP
+.ft B
+char * ldap_syntax2str(syn)
+.ft
+const LDAPSyntax * syn;
+.LP
+.ft B
+const char * ldap_syntax2name(syn)
+.ft
+LDAPSyntax * syn;
+.LP
+.ft B
+ldap_syntax_free(syn)
+.ft
+LDAPSyntax * syn;
+.LP
+.ft B
+LDAPMatchingRule * ldap_str2matchingrule(s, code, errp, flags)
+.ft
+const char * s;
+int * code;
+const char ** errp;
+const int flags;
+.LP
+.ft B
+char * ldap_matchingrule2str(mr);
+.ft
+const LDAPMatchingRule * mr;
+.LP
+.ft B
+const char * ldap_matchingrule2name(mr)
+.ft
+LDAPMatchingRule * mr;
+.LP
+.ft B
+ldap_matchingrule_free(mr)
+.ft
+LDAPMatchingRule * mr;
+.LP
+.ft B
+LDAPAttributeType * ldap_str2attributetype(s, code, errp, flags)
+.ft
+const char * s;
+int * code;
+const char ** errp;
+const int flags;
+.LP
+.ft B
+char * ldap_attributetype2str(at)
+.ft
+const LDAPAttributeType * at;
+.LP
+.ft B
+const char * ldap_attributetype2name(at)
+.ft
+LDAPAttributeType * at;
+.LP
+.ft B
+ldap_attributetype_free(at)
+.ft
+LDAPAttributeType * at;
+.LP
+.ft B
+LDAPObjectClass * ldap_str2objectclass(s, code, errp, flags)
+.ft
+const char * s;
+int * code;
+const char ** errp;
+const int flags;
+.LP
+.ft B
+char * ldap_objectclass2str(oc)
+.ft
+const LDAPObjectClass * oc;
+.LP
+.ft B
+const char * ldap_objectclass2name(oc)
+.ft
+LDAPObjectClass * oc;
+.LP
+.ft B
+ldap_objectclass_free(oc)
+.ft
+LDAPObjectClass * oc;
+.LP
+.ft B
+char * ldap_scherr2str(code)
+.ft
+int code;
+.SH DESCRIPTION
+These routines are used to parse schema definitions in the syntax
+defined in RFC 2252 into structs and handle these structs. These
+routines handle four kinds of definitions: syntaxes, matching rules,
+attribute types and objectclasses. For each definition kind, four
+routines are provided.
+.LP
+.B ldap_str2xxx()
+takes a definition in RFC 2252 format in argument
+.IR s
+as a NUL-terminated string and returns, if possible, a pointer to a
+newly allocated struct of the appropriate kind. The caller is
+responsible for freeing the struct by calling
+.B ldap_xxx_free()
+when not needed any longer. The routine returns NULL if some problem
+happened. In this case, the integer pointed at by argument
+.IR code
+will receive an error code (see below the description of
+.B ldap_scherr2str()
+for an explanation of the values) and a pointer to a NUL-terminated
+string will be placed where requested by argument
+.IR errp
+, indicating where in argument
+.IR s
+the error happened, so it must not be freed by the caller. Argument
+.IR flags
+is a bit mask of parsing options controlling the relaxation of the
+syntax recognized. The following values are defined:
+.TP
+.B LDAP_SCHEMA_ALLOW_NONE
+strict parsing according to RFC 2252.
+.TP
+.B LDAP_SCHEMA_ALLOW_NO_OID
+permit definitions that do not contain an initial OID.
+.TP
+.B LDAP_SCHEMA_ALLOW_QUOTED
+permit quotes around some items that should not have them.
+.TP
+.B LDAP_SCHEMA_ALLOW_DESCR
+permit a
+.B descr
+instead of a numeric OID in places where the syntax expect the latter.
+.TP
+.B LDAP_SCHEMA_ALLOW_DESCR_PREFIX
+permit that the initial numeric OID contains a prefix in
+.B descr
+format.
+.TP
+.B LDAP_SCHEMA_ALLOW_ALL
+be very liberal, include all options.
+.LP
+The structures returned are as follows:
+.sp
+.RS
+.nf
+.ne 7
+.ta 8n 16n 32n
+typedef struct ldap_schema_extension_item {
+ char *lsei_name; /* Extension name */
+ char **lsei_values; /* Extension values */
+} LDAPSchemaExtensionItem;
+
+typedef struct ldap_syntax {
+ char *syn_oid; /* OID */
+ char **syn_names; /* Names */
+ char *syn_desc; /* Description */
+ LDAPSchemaExtensionItem **syn_extensions; /* Extension */
+} LDAPSyntax;
+
+typedef struct ldap_matchingrule {
+ char *mr_oid; /* OID */
+ char **mr_names; /* Names */
+ char *mr_desc; /* Description */
+ int mr_obsolete; /* Is obsolete? */
+ char *mr_syntax_oid; /* Syntax of asserted values */
+ LDAPSchemaExtensionItem **mr_extensions; /* Extensions */
+} LDAPMatchingRule;
+
+typedef struct ldap_attributetype {
+ char *at_oid; /* OID */
+ char **at_names; /* Names */
+ char *at_desc; /* Description */
+ int at_obsolete; /* Is obsolete? */
+ char *at_sup_oid; /* OID of superior type */
+ char *at_equality_oid; /* OID of equality matching rule */
+ char *at_ordering_oid; /* OID of ordering matching rule */
+ char *at_substr_oid; /* OID of substrings matching rule */
+ char *at_syntax_oid; /* OID of syntax of values */
+ int at_syntax_len; /* Suggested minimum maximum length */
+ int at_single_value; /* Is single-valued? */
+ int at_collective; /* Is collective? */
+ int at_no_user_mod; /* Are changes forbidden through LDAP? */
+ int at_usage; /* Usage, see below */
+ LDAPSchemaExtensionItem **at_extensions; /* Extensions */
+} LDAPAttributeType;
+
+typedef struct ldap_objectclass {
+ char *oc_oid; /* OID */
+ char **oc_names; /* Names */
+ char *oc_desc; /* Description */
+ int oc_obsolete; /* Is obsolete? */
+ char **oc_sup_oids; /* OIDs of superior classes */
+ int oc_kind; /* Kind, see below */
+ char **oc_at_oids_must; /* OIDs of required attribute types */
+ char **oc_at_oids_may; /* OIDs of optional attribute types */
+ LDAPSchemaExtensionItem **oc_extensions; /* Extensions */
+} LDAPObjectClass;
+.ta
+.fi
+.RE
+.PP
+Some integer fields (those described with a question mark) have a
+truth value, for these fields the possible values are:
+.TP
+.B LDAP_SCHEMA_NO
+The answer to the question is no.
+.TP
+.B LDAP_SCHEMA_YES
+The answer to the question is yes.
+.LP
+For attribute types, the following usages are possible:
+.TP
+.B LDAP_SCHEMA_USER_APPLICATIONS
+the attribute type is non-operational.
+.TP
+.B LDAP_SCHEMA_DIRECTORY_OPERATION
+the attribute type is operational and is pertinent to the directory
+itself, i.e. it has the same value on all servers that master the
+entry containing this attribute type.
+.TP
+.B LDAP_SCHEMA_DISTRIBUTED_OPERATION
+the attribute type is operational and is pertinent to replication,
+shadowing or other distributed directory aspect. TBC.
+.TP
+.B LDAP_SCHEMA_DSA_OPERATION
+the attribute type is operational and is pertinent to the directory
+server itself, i.e. it may have different values for the same entry
+when retrieved from different servers that master the entry.
+.LP
+Object classes can be of three kinds:
+.TP
+.B LDAP_SCHEMA_ABSTRACT
+the object class is abstract, i.e. there cannot be entries of this
+class alone.
+.TP
+.B LDAP_SCHEMA_STRUCTURAL
+the object class is structural, i.e. it describes the main role of the
+entry. On some servers, once the entry is created the set of
+structural object classes assigned cannot be changed: none of those
+present can be removed and none other can be added.
+.TP
+.B LDAP_SCHEMA_AUXILIARY
+the object class is auxiliary, i.e. it is intended to go with other,
+structural, object classes. These can be added or removed at any time
+if attribute types are added or removed at the same time as needed by
+the set of object classes resulting from the operation.
+.LP
+Routines
+.B ldap_xxx2name()
+return a canonical name for the definition.
+.LP
+Routines
+.B ldap_xxx2str()
+return a string representation in the format described by RFC 2252 of
+the struct passed in the argument. The string is a newly allocated
+string that must be freed by the caller. These routines may return
+NULL if no memory can be allocated for the string.
+.LP
+.B ldap_scherr2str()
+returns a NUL-terminated string with a text description of the error
+found. This is a pointer to a static area, so it must not be freed by
+the caller. The argument
+.IR code
+comes from one of the parsing routines and can adopt the following
+values:
+.TP
+.B LDAP_SCHERR_OUTOFMEM
+Out of memory.
+.TP
+.B LDAP_SCHERR_UNEXPTOKEN
+Unexpected token.
+.TP
+.B LDAP_SCHERR_NOLEFTPAREN
+Missing opening parenthesis.
+.TP
+.B LDAP_SCHERR_NORIGHTPAREN
+Missing closing parenthesis.
+.TP
+.B LDAP_SCHERR_NODIGIT
+Expecting digit.
+.TP
+.B LDAP_SCHERR_BADNAME
+Expecting a name.
+.TP
+.B LDAP_SCHERR_BADDESC
+Bad description.
+.TP
+.B LDAP_SCHERR_BADSUP
+Bad superiors.
+.TP
+.B LDAP_SCHERR_DUPOPT
+Duplicate option.
+.TP
+.B LDAP_SCHERR_EMPTY
+Unexpected end of data.
+
+.SH SEE ALSO
+.BR ldap (3),
+.SH ACKNOWLEDGEMENTS
+.B OpenLDAP
+is developed and maintained by The OpenLDAP Project (http://www.openldap.org/).
+.B OpenLDAP
+is derived from University of Michigan LDAP 3.3 Release.
+
slapd \- Stand-alone LDAP Daemon
.SH SYNOPSIS
.B LIBEXECDIR/slapd
+.B [\-d debug\-level]
.B [\-f slapd\-config\-file]
.B [\-h URLs]
-.B [\-d debug\-level]
.B [\-n service\-name] [\-s syslog\-level] [\-l syslog\-local\-user]
.B [\-r directory]
-.B [\-u user] [\-g group]
+.B [\-u user] [\-g group] [\-t]
.B
.SH DESCRIPTION
.LP
Note that on some systems, running as a non-privileged user will prevent
passwd back-ends from accessing the encrypted passwords. Note also that
any shell back-ends will run as the specified non-privileged user.
+.TP
+.BI \-t
+.B slapd
+will read the configuration file (the default if none is given with the
+\fI\-f\fP switch) and check its syntax, without opening any listener
+or database.
.SH EXAMPLES
To start
.I slapd
.ft
.fi
.LP
+To test whether the configuration file is correct or not, type:
+.LP
+.nf
+.ft tt
+ LIBEXECDIR/slapd -t
+.ft
+.fi
+.LP
.SH "SEE ALSO"
.BR ldap (3),
.BR slapd.conf (5),
off = BP_GRAPH + n + ((n >= 8)?1:0);
- if ( isprint( data[i] )) {
+ if ( isprint( (unsigned char) data[i] )) {
line[ BP_GRAPH + n ] = data[i];
} else {
line[ BP_GRAPH + n ] = '.';
} else if( !strncasecmp(props[i],
"minssf=", sizeof("minssf")) )
{
- if( isdigit( props[i][sizeof("minssf")] ) ) {
+ if( isdigit( (unsigned char) props[i][sizeof("minssf")] ) ) {
got_min_ssf++;
min_ssf = atoi( &props[i][sizeof("minssf")] );
} else {
} else if( !strncasecmp(props[i],
"maxssf=", sizeof("maxssf")) )
{
- if( isdigit( props[i][sizeof("maxssf")] ) ) {
+ if( isdigit( (unsigned char) props[i][sizeof("maxssf")] ) ) {
got_max_ssf++;
max_ssf = atoi( &props[i][sizeof("maxssf")] );
} else {
} else if( !strncasecmp(props[i],
"maxbufsize=", sizeof("maxbufsize")) )
{
- if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
+ if( isdigit( (unsigned char) props[i][sizeof("maxbufsize")] ) ) {
got_maxbufsize++;
maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
} else {
{
tmpber = *ber; /* struct copy */
if ( v3ref == 1 ) {
- ; /* V3 search reference or V3 referral sucessfully chased */
+ /* V3 search reference or V3 referral successfully chased */
+ refer_cnt = 0;
} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
&lr->lr_res_matched, &lr->lr_res_error )
!= LBER_ERROR ) {
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/*
+ * Copyright 2001 Computing Research Labs, New Mexico State University
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* $Id: ucdata.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */
+
+#include "portable.h"
+#include "ldap_config.h"
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+
+#include "ucdata.h"
+
+/**************************************************************************
+ *
+ * Miscellaneous types, data, and support functions.
+ *
+ **************************************************************************/
+
+typedef struct {
+ unsigned short bom;
+ unsigned short cnt;
+ union {
+ unsigned long bytes;
+ unsigned short len[2];
+ } size;
+} _ucheader_t;
+
+/*
+ * A simple array of 32-bit masks for lookup.
+ */
+static unsigned long masks32[32] = {
+ 0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL,
+ 0x00000010UL, 0x00000020UL, 0x00000040UL, 0x00000080UL,
+ 0x00000100UL, 0x00000200UL, 0x00000400UL, 0x00000800UL,
+ 0x00001000UL, 0x00002000UL, 0x00004000UL, 0x00008000UL,
+ 0x00010000UL, 0x00020000UL, 0x00040000UL, 0x00080000UL,
+ 0x00100000UL, 0x00200000UL, 0x00400000UL, 0x00800000UL,
+ 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
+ 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL
+};
+
+#define endian_short(cc) (((cc) >> 8) | (((cc) & 0xff) << 8))
+#define endian_long(cc) ((((cc) & 0xff) << 24)|((((cc) >> 8) & 0xff) << 16)|\
+ ((((cc) >> 16) & 0xff) << 8)|((cc) >> 24))
+
+static FILE *
+_ucopenfile(char *paths, char *filename, char *mode)
+{
+ FILE *f;
+ char *fp, *dp, *pp, path[BUFSIZ];
+
+ if (filename == 0 || *filename == 0)
+ return 0;
+
+ dp = paths;
+ while (dp && *dp) {
+ pp = path;
+ while (*dp && *dp != ':')
+ *pp++ = *dp++;
+ *pp++ = *LDAP_DIRSEP;
+
+ fp = filename;
+ while (*fp)
+ *pp++ = *fp++;
+ *pp = 0;
+
+ if ((f = fopen(path, mode)) != 0)
+ return f;
+
+ if (*dp == ':')
+ dp++;
+ }
+
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Support for the character properties.
+ *
+ **************************************************************************/
+
+static unsigned long _ucprop_size;
+static unsigned short *_ucprop_offsets;
+static unsigned long *_ucprop_ranges;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_ucprop_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long size, i;
+ _ucheader_t hdr;
+
+ if (_ucprop_size > 0) {
+ if (!reload)
+ /*
+ * The character properties have already been loaded.
+ */
+ return 0;
+
+ /*
+ * Unload the current character property data in preparation for
+ * loading a new copy. Only the first array has to be deallocated
+ * because all the memory for the arrays is allocated as a single
+ * block.
+ */
+ free((char *) _ucprop_offsets);
+ _ucprop_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "ctype.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.bytes = endian_long(hdr.size.bytes);
+ }
+
+ if ((_ucprop_size = hdr.cnt) == 0) {
+ fclose(in);
+ return -1;
+ }
+
+ /*
+ * Allocate all the storage needed for the lookup table.
+ */
+ _ucprop_offsets = (unsigned short *) malloc(hdr.size.bytes);
+
+ /*
+ * Calculate the offset into the storage for the ranges. The offsets
+ * array is on a 4-byte boundary and one larger than the value provided in
+ * the header count field. This means the offset to the ranges must be
+ * calculated after aligning the count to a 4-byte boundary.
+ */
+ if ((size = ((hdr.cnt + 1) * sizeof(unsigned short))) & 3)
+ size += 4 - (size & 3);
+ size >>= 1;
+ _ucprop_ranges = (unsigned long *) (_ucprop_offsets + size);
+
+ /*
+ * Load the offset array.
+ */
+ fread((char *) _ucprop_offsets, sizeof(unsigned short), size, in);
+
+ /*
+ * Do an endian swap if necessary. Don't forget there is an extra node on
+ * the end with the final index.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i <= _ucprop_size; i++)
+ _ucprop_offsets[i] = endian_short(_ucprop_offsets[i]);
+ }
+
+ /*
+ * Load the ranges. The number of elements is in the last array position
+ * of the offsets.
+ */
+ fread((char *) _ucprop_ranges, sizeof(unsigned long),
+ _ucprop_offsets[_ucprop_size], in);
+
+ fclose(in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < _ucprop_offsets[_ucprop_size]; i++)
+ _ucprop_ranges[i] = endian_long(_ucprop_ranges[i]);
+ }
+ return 0;
+}
+
+static void
+_ucprop_unload(void)
+{
+ if (_ucprop_size == 0)
+ return;
+
+ /*
+ * Only need to free the offsets because the memory is allocated as a
+ * single block.
+ */
+ free((char *) _ucprop_offsets);
+ _ucprop_size = 0;
+}
+
+static int
+_ucprop_lookup(unsigned long code, unsigned long n)
+{
+ long l, r, m;
+
+ if (_ucprop_size == 0)
+ return 0;
+
+ /*
+ * There is an extra node on the end of the offsets to allow this routine
+ * to work right. If the index is 0xffff, then there are no nodes for the
+ * property.
+ */
+ if ((l = _ucprop_offsets[n]) == 0xffff)
+ return 0;
+
+ /*
+ * Locate the next offset that is not 0xffff. The sentinel at the end of
+ * the array is the max index value.
+ */
+ for (m = 1;
+ n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++) ;
+
+ r = _ucprop_offsets[n + m] - 1;
+
+ while (l <= r) {
+ /*
+ * Determine a "mid" point and adjust to make sure the mid point is at
+ * the beginning of a range pair.
+ */
+ m = (l + r) >> 1;
+ m -= (m & 1);
+ if (code > _ucprop_ranges[m + 1])
+ l = m + 2;
+ else if (code < _ucprop_ranges[m])
+ r = m - 2;
+ else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1])
+ return 1;
+ }
+ return 0;
+}
+
+int
+ucisprop(unsigned long code, unsigned long mask1, unsigned long mask2)
+{
+ unsigned long i;
+
+ if (mask1 == 0 && mask2 == 0)
+ return 0;
+
+ for (i = 0; mask1 && i < 32; i++) {
+ if ((mask1 & masks32[i]) && _ucprop_lookup(code, i))
+ return 1;
+ }
+
+ for (i = 32; mask2 && i < _ucprop_size; i++) {
+ if ((mask2 & masks32[i & 31]) && _ucprop_lookup(code, i))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Support for case mapping.
+ *
+ **************************************************************************/
+
+static unsigned long _uccase_size;
+static unsigned short _uccase_len[2];
+static unsigned long *_uccase_map;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_uccase_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long i;
+ _ucheader_t hdr;
+
+ if (_uccase_size > 0) {
+ if (!reload)
+ /*
+ * The case mappings have already been loaded.
+ */
+ return 0;
+
+ free((char *) _uccase_map);
+ _uccase_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "case.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.len[0] = endian_short(hdr.size.len[0]);
+ hdr.size.len[1] = endian_short(hdr.size.len[1]);
+ }
+
+ /*
+ * Set the node count and lengths of the upper and lower case mapping
+ * tables.
+ */
+ _uccase_size = hdr.cnt * 3;
+ _uccase_len[0] = hdr.size.len[0] * 3;
+ _uccase_len[1] = hdr.size.len[1] * 3;
+
+ _uccase_map = (unsigned long *)
+ malloc(_uccase_size * sizeof(unsigned long));
+
+ /*
+ * Load the case mapping table.
+ */
+ fread((char *) _uccase_map, sizeof(unsigned long), _uccase_size, in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < _uccase_size; i++)
+ _uccase_map[i] = endian_long(_uccase_map[i]);
+ }
+ fclose(in);
+ return 0;
+}
+
+static void
+_uccase_unload(void)
+{
+ if (_uccase_size == 0)
+ return;
+
+ free((char *) _uccase_map);
+ _uccase_size = 0;
+}
+
+static unsigned long
+_uccase_lookup(unsigned long code, long l, long r, int field)
+{
+ long m;
+
+ /*
+ * Do the binary search.
+ */
+ while (l <= r) {
+ /*
+ * Determine a "mid" point and adjust to make sure the mid point is at
+ * the beginning of a case mapping triple.
+ */
+ m = (l + r) >> 1;
+ m -= (m % 3);
+ if (code > _uccase_map[m])
+ l = m + 3;
+ else if (code < _uccase_map[m])
+ r = m - 3;
+ else if (code == _uccase_map[m])
+ return _uccase_map[m + field];
+ }
+
+ return code;
+}
+
+unsigned long
+uctoupper(unsigned long code)
+{
+ int field;
+ long l, r;
+
+ if (ucisupper(code))
+ return code;
+
+ if (ucislower(code)) {
+ /*
+ * The character is lower case.
+ */
+ field = 2;
+ l = _uccase_len[0];
+ r = (l + _uccase_len[1]) - 3;
+ } else {
+ /*
+ * The character is title case.
+ */
+ field = 1;
+ l = _uccase_len[0] + _uccase_len[1];
+ r = _uccase_size - 3;
+ }
+ return _uccase_lookup(code, l, r, field);
+}
+
+unsigned long
+uctolower(unsigned long code)
+{
+ int field;
+ long l, r;
+
+ if (ucislower(code))
+ return code;
+
+ if (ucisupper(code)) {
+ /*
+ * The character is upper case.
+ */
+ field = 1;
+ l = 0;
+ r = _uccase_len[0] - 3;
+ } else {
+ /*
+ * The character is title case.
+ */
+ field = 2;
+ l = _uccase_len[0] + _uccase_len[1];
+ r = _uccase_size - 3;
+ }
+ return _uccase_lookup(code, l, r, field);
+}
+
+unsigned long
+uctotitle(unsigned long code)
+{
+ int field;
+ long l, r;
+
+ if (ucistitle(code))
+ return code;
+
+ /*
+ * The offset will always be the same for converting to title case.
+ */
+ field = 2;
+
+ if (ucisupper(code)) {
+ /*
+ * The character is upper case.
+ */
+ l = 0;
+ r = _uccase_len[0] - 3;
+ } else {
+ /*
+ * The character is lower case.
+ */
+ l = _uccase_len[0];
+ r = (l + _uccase_len[1]) - 3;
+ }
+ return _uccase_lookup(code, l, r, field);
+}
+
+/**************************************************************************
+ *
+ * Support for compositions.
+ *
+ **************************************************************************/
+
+static unsigned long _uccomp_size;
+static unsigned long *_uccomp_data;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_uccomp_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long size, i;
+ _ucheader_t hdr;
+
+ if (_uccomp_size > 0) {
+ if (!reload)
+ /*
+ * The compositions have already been loaded.
+ */
+ return 0;
+
+ free((char *) _uccomp_data);
+ _uccomp_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "comp.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.bytes = endian_long(hdr.size.bytes);
+ }
+
+ _uccomp_size = hdr.cnt;
+ _uccomp_data = (unsigned long *) malloc(hdr.size.bytes);
+
+ /*
+ * Read the composition data in.
+ */
+ size = hdr.size.bytes / sizeof(unsigned long);
+ fread((char *) _uccomp_data, sizeof(unsigned long), size, in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < size; i++)
+ _uccomp_data[i] = endian_long(_uccomp_data[i]);
+ }
+
+ /*
+ * Assume that the data is ordered on count, so that all compositions
+ * of length 2 come first. Only handling length 2 for now.
+ */
+ for (i = 1; i < size; i += 4)
+ if (_uccomp_data[i] != 2)
+ break;
+ _uccomp_size = i - 1;
+
+ fclose(in);
+ return 0;
+}
+
+static void
+_uccomp_unload(void)
+{
+ if (_uccomp_size == 0)
+ return;
+
+ free((char *) _uccomp_data);
+ _uccomp_size = 0;
+}
+
+int
+uccomp(unsigned long node1, unsigned long node2, unsigned long *comp)
+{
+ int l, r, m;
+
+ l = 0;
+ r = _uccomp_size - 1;
+
+ while (l <= r) {
+ m = ((r + l) >> 1);
+ m -= m & 3;
+ if (node1 > _uccomp_data[m+2])
+ l = m + 4;
+ else if (node1 < _uccomp_data[m+2])
+ r = m - 4;
+ else if (node2 > _uccomp_data[m+3])
+ l = m + 4;
+ else if (node2 < _uccomp_data[m+3])
+ r = m - 4;
+ else {
+ *comp = _uccomp_data[m];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+uccomp_hangul(unsigned long *str, int len)
+{
+ const int SBase = 0xAC00, LBase = 0x1100,
+ VBase = 0x1161, TBase = 0x11A7,
+ LCount = 19, VCount = 21, TCount = 28,
+ NCount = VCount * TCount, /* 588 */
+ SCount = LCount * NCount; /* 11172 */
+
+ int i, rlen;
+ unsigned long ch, last, lindex, sindex;
+
+ last = str[0];
+ rlen = 1;
+ for ( i = 1; i < len; i++ ) {
+ ch = str[i];
+
+ /* check if two current characters are L and V */
+ lindex = last - LBase;
+ if (lindex < (unsigned long) LCount) {
+ unsigned long vindex = ch - VBase;
+ if (vindex < (unsigned long) VCount) {
+ /* make syllable of form LV */
+ last = SBase + (lindex * VCount + vindex) * TCount;
+ str[rlen-1] = last; /* reset last */
+ continue;
+ }
+ }
+
+ /* check if two current characters are LV and T */
+ sindex = last - SBase;
+ if (sindex < (unsigned long) SCount
+ && (sindex % TCount) == 0)
+ {
+ unsigned long tindex = ch - TBase;
+ if (tindex <= (unsigned long) TCount) {
+ /* make syllable of form LVT */
+ last += tindex;
+ str[rlen-1] = last; /* reset last */
+ continue;
+ }
+ }
+
+ /* if neither case was true, just add the character */
+ last = ch;
+ str[rlen] = ch;
+ rlen++;
+ }
+ return rlen;
+}
+
+int
+uccanoncomp(unsigned long *str, int len)
+{
+ int i, stpos, copos;
+ unsigned long cl, prevcl, st, ch, co;
+
+ st = str[0];
+ stpos = 0;
+ copos = 1;
+ prevcl = uccombining_class(st) == 0 ? 0 : 256;
+
+ for (i = 1; i < len; i++) {
+ ch = str[i];
+ cl = uccombining_class(ch);
+ if (uccomp(st, ch, &co) && (prevcl < cl || prevcl == 0))
+ st = str[stpos] = co;
+ else {
+ if (cl == 0) {
+ stpos = copos;
+ st = ch;
+ }
+ prevcl = cl;
+ str[copos++] = ch;
+ }
+ }
+
+ return uccomp_hangul(str, copos);
+}
+
+/**************************************************************************
+ *
+ * Support for decompositions.
+ *
+ **************************************************************************/
+
+static unsigned long _ucdcmp_size;
+static unsigned long *_ucdcmp_nodes;
+static unsigned long *_ucdcmp_decomp;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_ucdcmp_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long size, i;
+ _ucheader_t hdr;
+
+ if (_ucdcmp_size > 0) {
+ if (!reload)
+ /*
+ * The decompositions have already been loaded.
+ */
+ return 0;
+
+ free((char *) _ucdcmp_nodes);
+ _ucdcmp_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "decomp.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.bytes = endian_long(hdr.size.bytes);
+ }
+
+ _ucdcmp_size = hdr.cnt << 1;
+ _ucdcmp_nodes = (unsigned long *) malloc(hdr.size.bytes);
+ _ucdcmp_decomp = _ucdcmp_nodes + (_ucdcmp_size + 1);
+
+ /*
+ * Read the decomposition data in.
+ */
+ size = hdr.size.bytes / sizeof(unsigned long);
+ fread((char *) _ucdcmp_nodes, sizeof(unsigned long), size, in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < size; i++)
+ _ucdcmp_nodes[i] = endian_long(_ucdcmp_nodes[i]);
+ }
+ fclose(in);
+ return 0;
+}
+
+static void
+_ucdcmp_unload(void)
+{
+ if (_ucdcmp_size == 0)
+ return;
+
+ /*
+ * Only need to free the offsets because the memory is allocated as a
+ * single block.
+ */
+ free((char *) _ucdcmp_nodes);
+ _ucdcmp_size = 0;
+}
+
+int
+ucdecomp(unsigned long code, unsigned long *num, unsigned long **decomp)
+{
+ long l, r, m;
+
+ l = 0;
+ r = _ucdcmp_nodes[_ucdcmp_size] - 1;
+
+ while (l <= r) {
+ /*
+ * Determine a "mid" point and adjust to make sure the mid point is at
+ * the beginning of a code+offset pair.
+ */
+ m = (l + r) >> 1;
+ m -= (m & 1);
+ if (code > _ucdcmp_nodes[m])
+ l = m + 2;
+ else if (code < _ucdcmp_nodes[m])
+ r = m - 2;
+ else if (code == _ucdcmp_nodes[m]) {
+ *num = _ucdcmp_nodes[m + 3] - _ucdcmp_nodes[m + 1];
+ *decomp = &_ucdcmp_decomp[_ucdcmp_nodes[m + 1]];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+ucdecomp_hangul(unsigned long code, unsigned long *num, unsigned long decomp[])
+{
+ if (!ucishangul(code))
+ return 0;
+
+ code -= 0xac00;
+ decomp[0] = 0x1100 + (unsigned long) (code / 588);
+ decomp[1] = 0x1161 + (unsigned long) ((code % 588) / 28);
+ decomp[2] = 0x11a7 + (unsigned long) (code % 28);
+ *num = (decomp[2] != 0x11a7) ? 3 : 2;
+
+ return 1;
+}
+
+int
+uccanondecomp(const unsigned long *in, int inlen,
+ unsigned long **out, int *outlen)
+{
+ int l, size;
+ unsigned i, j, k;
+ unsigned long num, class, *decomp, hangdecomp[3];
+
+ size = inlen;
+ *out = (unsigned long *) malloc(size * sizeof(**out));
+ if (*out == NULL)
+ return *outlen = -1;
+
+ i = 0;
+ for (j = 0; j < (unsigned) inlen; j++) {
+ if (ucdecomp(in[j], &num, &decomp)) {
+ if ( size - i < num) {
+ size = inlen + i - j + num - 1;
+ *out = (unsigned long *) realloc(*out, size * sizeof(**out));
+ if (*out == NULL)
+ return *outlen = -1;
+ }
+ for (k = 0; k < num; k++) {
+ class = uccombining_class(decomp[k]);
+ if (class == 0) {
+ (*out)[i] = decomp[k];
+ } else {
+ for (l = i; l > 0; l--)
+ if (class >= uccombining_class((*out)[l-1]))
+ break;
+ AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
+ (*out)[l] = decomp[k];
+ }
+ i++;
+ }
+ } else if (ucdecomp_hangul(in[j], &num, hangdecomp)) {
+ if (size - i < num) {
+ size = inlen + i - j + num - 1;
+ *out = (unsigned long *) realloc(*out, size * sizeof(**out));
+ if (*out == NULL)
+ return *outlen = -1;
+ }
+ for (k = 0; k < num; k++) {
+ (*out)[i] = hangdecomp[k];
+ i++;
+ }
+ } else {
+ if (size - i < 1) {
+ size = inlen + i - j;
+ *out = (unsigned long *) realloc(*out, size * sizeof(**out));
+ if (*out == NULL)
+ return *outlen = -1;
+ }
+ class = uccombining_class(in[j]);
+ if (class == 0) {
+ (*out)[i] = in[j];
+ } else {
+ for (l = i; l > 0; l--)
+ if (class >= uccombining_class((*out)[l-1]))
+ break;
+ AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
+ (*out)[l] = in[j];
+ }
+ i++;
+ }
+ }
+ return *outlen = i;
+}
+
+/**************************************************************************
+ *
+ * Support for combining classes.
+ *
+ **************************************************************************/
+
+static unsigned long _uccmcl_size;
+static unsigned long *_uccmcl_nodes;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_uccmcl_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long i;
+ _ucheader_t hdr;
+
+ if (_uccmcl_size > 0) {
+ if (!reload)
+ /*
+ * The combining classes have already been loaded.
+ */
+ return 0;
+
+ free((char *) _uccmcl_nodes);
+ _uccmcl_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "cmbcl.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.bytes = endian_long(hdr.size.bytes);
+ }
+
+ _uccmcl_size = hdr.cnt * 3;
+ _uccmcl_nodes = (unsigned long *) malloc(hdr.size.bytes);
+
+ /*
+ * Read the combining classes in.
+ */
+ fread((char *) _uccmcl_nodes, sizeof(unsigned long), _uccmcl_size, in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < _uccmcl_size; i++)
+ _uccmcl_nodes[i] = endian_long(_uccmcl_nodes[i]);
+ }
+ fclose(in);
+ return 0;
+}
+
+static void
+_uccmcl_unload(void)
+{
+ if (_uccmcl_size == 0)
+ return;
+
+ free((char *) _uccmcl_nodes);
+ _uccmcl_size = 0;
+}
+
+unsigned long
+uccombining_class(unsigned long code)
+{
+ long l, r, m;
+
+ l = 0;
+ r = _uccmcl_size - 1;
+
+ while (l <= r) {
+ m = (l + r) >> 1;
+ m -= (m % 3);
+ if (code > _uccmcl_nodes[m + 1])
+ l = m + 3;
+ else if (code < _uccmcl_nodes[m])
+ r = m - 3;
+ else if (code >= _uccmcl_nodes[m] && code <= _uccmcl_nodes[m + 1])
+ return _uccmcl_nodes[m + 2];
+ }
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Support for numeric values.
+ *
+ **************************************************************************/
+
+static unsigned long *_ucnum_nodes;
+static unsigned long _ucnum_size;
+static short *_ucnum_vals;
+
+/*
+ * Return -1 on error, 0 if okay
+ */
+static int
+_ucnumb_load(char *paths, int reload)
+{
+ FILE *in;
+ unsigned long size, i;
+ _ucheader_t hdr;
+
+ if (_ucnum_size > 0) {
+ if (!reload)
+ /*
+ * The numbers have already been loaded.
+ */
+ return 0;
+
+ free((char *) _ucnum_nodes);
+ _ucnum_size = 0;
+ }
+
+ if ((in = _ucopenfile(paths, "num.dat", "rb")) == 0)
+ return -1;
+
+ /*
+ * Load the header.
+ */
+ fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
+
+ if (hdr.bom == 0xfffe) {
+ hdr.cnt = endian_short(hdr.cnt);
+ hdr.size.bytes = endian_long(hdr.size.bytes);
+ }
+
+ _ucnum_size = hdr.cnt;
+ _ucnum_nodes = (unsigned long *) malloc(hdr.size.bytes);
+ _ucnum_vals = (short *) (_ucnum_nodes + _ucnum_size);
+
+ /*
+ * Read the combining classes in.
+ */
+ fread((char *) _ucnum_nodes, sizeof(unsigned char), hdr.size.bytes, in);
+
+ /*
+ * Do an endian swap if necessary.
+ */
+ if (hdr.bom == 0xfffe) {
+ for (i = 0; i < _ucnum_size; i++)
+ _ucnum_nodes[i] = endian_long(_ucnum_nodes[i]);
+
+ /*
+ * Determine the number of values that have to be adjusted.
+ */
+ size = (hdr.size.bytes -
+ (_ucnum_size * (sizeof(unsigned long) << 1))) /
+ sizeof(short);
+
+ for (i = 0; i < size; i++)
+ _ucnum_vals[i] = endian_short(_ucnum_vals[i]);
+ }
+ fclose(in);
+ return 0;
+}
+
+static void
+_ucnumb_unload(void)
+{
+ if (_ucnum_size == 0)
+ return;
+
+ free((char *) _ucnum_nodes);
+ _ucnum_size = 0;
+}
+
+int
+ucnumber_lookup(unsigned long code, struct ucnumber *num)
+{
+ long l, r, m;
+ short *vp;
+
+ l = 0;
+ r = _ucnum_size - 1;
+ while (l <= r) {
+ /*
+ * Determine a "mid" point and adjust to make sure the mid point is at
+ * the beginning of a code+offset pair.
+ */
+ m = (l + r) >> 1;
+ m -= (m & 1);
+ if (code > _ucnum_nodes[m])
+ l = m + 2;
+ else if (code < _ucnum_nodes[m])
+ r = m - 2;
+ else {
+ vp = _ucnum_vals + _ucnum_nodes[m + 1];
+ num->numerator = (int) *vp++;
+ num->denominator = (int) *vp;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+ucdigit_lookup(unsigned long code, int *digit)
+{
+ long l, r, m;
+ short *vp;
+
+ l = 0;
+ r = _ucnum_size - 1;
+ while (l <= r) {
+ /*
+ * Determine a "mid" point and adjust to make sure the mid point is at
+ * the beginning of a code+offset pair.
+ */
+ m = (l + r) >> 1;
+ m -= (m & 1);
+ if (code > _ucnum_nodes[m])
+ l = m + 2;
+ else if (code < _ucnum_nodes[m])
+ r = m - 2;
+ else {
+ vp = _ucnum_vals + _ucnum_nodes[m + 1];
+ if (*vp == *(vp + 1)) {
+ *digit = *vp;
+ return 1;
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+struct ucnumber
+ucgetnumber(unsigned long code)
+{
+ struct ucnumber num;
+
+ /*
+ * Initialize with some arbitrary value, because the caller simply cannot
+ * tell for sure if the code is a number without calling the ucisnumber()
+ * macro before calling this function.
+ */
+ num.numerator = num.denominator = -111;
+
+ (void) ucnumber_lookup(code, &num);
+
+ return num;
+}
+
+int
+ucgetdigit(unsigned long code)
+{
+ int dig;
+
+ /*
+ * Initialize with some arbitrary value, because the caller simply cannot
+ * tell for sure if the code is a number without calling the ucisdigit()
+ * macro before calling this function.
+ */
+ dig = -111;
+
+ (void) ucdigit_lookup(code, &dig);
+
+ return dig;
+}
+
+/**************************************************************************
+ *
+ * Setup and cleanup routines.
+ *
+ **************************************************************************/
+
+/*
+ * Return 0 if okay, negative on error
+ */
+int
+ucdata_load(char *paths, int masks)
+{
+ int error = 0;
+
+ if (masks & UCDATA_CTYPE)
+ error |= _ucprop_load(paths, 0) < 0 ? UCDATA_CTYPE : 0;
+ if (masks & UCDATA_CASE)
+ error |= _uccase_load(paths, 0) < 0 ? UCDATA_CASE : 0;
+ if (masks & UCDATA_DECOMP)
+ error |= _ucdcmp_load(paths, 0) < 0 ? UCDATA_DECOMP : 0;
+ if (masks & UCDATA_CMBCL)
+ error |= _uccmcl_load(paths, 0) < 0 ? UCDATA_CMBCL : 0;
+ if (masks & UCDATA_NUM)
+ error |= _ucnumb_load(paths, 0) < 0 ? UCDATA_NUM : 0;
+ if (masks & UCDATA_COMP)
+ error |= _uccomp_load(paths, 0) < 0 ? UCDATA_COMP : 0;
+
+ return -error;
+}
+
+void
+ucdata_unload(int masks)
+{
+ if (masks & UCDATA_CTYPE)
+ _ucprop_unload();
+ if (masks & UCDATA_CASE)
+ _uccase_unload();
+ if (masks & UCDATA_DECOMP)
+ _ucdcmp_unload();
+ if (masks & UCDATA_CMBCL)
+ _uccmcl_unload();
+ if (masks & UCDATA_NUM)
+ _ucnumb_unload();
+ if (masks & UCDATA_COMP)
+ _uccomp_unload();
+}
+
+/*
+ * Return 0 if okay, negative on error
+ */
+int
+ucdata_reload(char *paths, int masks)
+{
+ int error = 0;
+
+ if (masks & UCDATA_CTYPE)
+ error |= _ucprop_load(paths, 1) < 0 ? UCDATA_CTYPE : 0;
+ if (masks & UCDATA_CASE)
+ error |= _uccase_load(paths, 1) < 0 ? UCDATA_CASE : 0;
+ if (masks & UCDATA_DECOMP)
+ error |= _ucdcmp_load(paths, 1) < 0 ? UCDATA_DECOMP : 0;
+ if (masks & UCDATA_CMBCL)
+ error |= _uccmcl_load(paths, 1) < 0 ? UCDATA_CMBCL : 0;
+ if (masks & UCDATA_NUM)
+ error |= _ucnumb_load(paths, 1) < 0 ? UCDATA_NUM : 0;
+ if (masks & UCDATA_COMP)
+ error |= _uccomp_load(paths, 1) < 0 ? UCDATA_COMP : 0;
+
+ return -error;
+}
+
+#ifdef TEST
+
+void
+main(void)
+{
+ int dig;
+ unsigned long i, lo, *dec;
+ struct ucnumber num;
+
+ ucdata_setup(".");
+
+ if (ucisweak(0x30))
+ printf("WEAK\n");
+ else
+ printf("NOT WEAK\n");
+
+ printf("LOWER 0x%04lX\n", uctolower(0xff3a));
+ printf("UPPER 0x%04lX\n", uctoupper(0xff5a));
+
+ if (ucisalpha(0x1d5))
+ printf("ALPHA\n");
+ else
+ printf("NOT ALPHA\n");
+
+ if (ucisupper(0x1d5)) {
+ printf("UPPER\n");
+ lo = uctolower(0x1d5);
+ printf("0x%04lx\n", lo);
+ lo = uctotitle(0x1d5);
+ printf("0x%04lx\n", lo);
+ } else
+ printf("NOT UPPER\n");
+
+ if (ucistitle(0x1d5))
+ printf("TITLE\n");
+ else
+ printf("NOT TITLE\n");
+
+ if (uciscomposite(0x1d5))
+ printf("COMPOSITE\n");
+ else
+ printf("NOT COMPOSITE\n");
+
+ if (ucdecomp(0x1d5, &lo, &dec)) {
+ for (i = 0; i < lo; i++)
+ printf("0x%04lx ", dec[i]);
+ putchar('\n');
+ }
+
+ if ((lo = uccombining_class(0x41)) != 0)
+ printf("0x41 CCL %ld\n", lo);
+
+ if (ucisxdigit(0xfeff))
+ printf("0xFEFF HEX DIGIT\n");
+ else
+ printf("0xFEFF NOT HEX DIGIT\n");
+
+ if (ucisdefined(0x10000))
+ printf("0x10000 DEFINED\n");
+ else
+ printf("0x10000 NOT DEFINED\n");
+
+ if (ucnumber_lookup(0x30, &num)) {
+ if (num.numerator != num.denominator)
+ printf("UCNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCNUMBER: 0x30 = %d\n", num.numerator);
+ } else
+ printf("UCNUMBER: 0x30 NOT A NUMBER\n");
+
+ if (ucnumber_lookup(0xbc, &num)) {
+ if (num.numerator != num.denominator)
+ printf("UCNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCNUMBER: 0xbc = %d\n", num.numerator);
+ } else
+ printf("UCNUMBER: 0xbc NOT A NUMBER\n");
+
+
+ if (ucnumber_lookup(0xff19, &num)) {
+ if (num.numerator != num.denominator)
+ printf("UCNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCNUMBER: 0xff19 = %d\n", num.numerator);
+ } else
+ printf("UCNUMBER: 0xff19 NOT A NUMBER\n");
+
+ if (ucnumber_lookup(0x4e00, &num)) {
+ if (num.numerator != num.denominator)
+ printf("UCNUMBER: 0x4e00 = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCNUMBER: 0x4e00 = %d\n", num.numerator);
+ } else
+ printf("UCNUMBER: 0x4e00 NOT A NUMBER\n");
+
+ if (ucdigit_lookup(0x06f9, &dig))
+ printf("UCDIGIT: 0x6f9 = %d\n", dig);
+ else
+ printf("UCDIGIT: 0x6f9 NOT A NUMBER\n");
+
+ dig = ucgetdigit(0x0969);
+ printf("UCGETDIGIT: 0x969 = %d\n", dig);
+
+ num = ucgetnumber(0x30);
+ if (num.numerator != num.denominator)
+ printf("UCGETNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCGETNUMBER: 0x30 = %d\n", num.numerator);
+
+ num = ucgetnumber(0xbc);
+ if (num.numerator != num.denominator)
+ printf("UCGETNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCGETNUMBER: 0xbc = %d\n", num.numerator);
+
+ num = ucgetnumber(0xff19);
+ if (num.numerator != num.denominator)
+ printf("UCGETNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
+ else
+ printf("UCGETNUMBER: 0xff19 = %d\n", num.numerator);
+
+ ucdata_cleanup();
+ exit(0);
+}
+
+#endif /* TEST */
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/*
+ * Copyright 2001 Computing Research Labs, New Mexico State University
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* $Id: ucgendat.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */
+
+#include "portable.h"
+#include "ldap_config.h"
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#undef ishdigit
+#define ishdigit(cc) (((cc) >= '0' && (cc) <= '9') ||\
+ ((cc) >= 'A' && (cc) <= 'F') ||\
+ ((cc) >= 'a' && (cc) <= 'f'))
+
+/*
+ * A header written to the output file with the byte-order-mark and the number
+ * of property nodes.
+ */
+static unsigned short hdr[2] = {0xfeff, 0};
+
+#define NUMPROPS 50
+#define NEEDPROPS (NUMPROPS + (4 - (NUMPROPS & 3)))
+
+typedef struct {
+ char *name;
+ int len;
+} _prop_t;
+
+/*
+ * List of properties expected to be found in the Unicode Character Database
+ * including some implementation specific properties.
+ *
+ * The implementation specific properties are:
+ * Cm = Composed (can be decomposed)
+ * Nb = Non-breaking
+ * Sy = Symmetric (has left and right forms)
+ * Hd = Hex digit
+ * Qm = Quote marks
+ * Mr = Mirroring
+ * Ss = Space, other
+ * Cp = Defined character
+ */
+static _prop_t props[NUMPROPS] = {
+ {"Mn", 2}, {"Mc", 2}, {"Me", 2}, {"Nd", 2}, {"Nl", 2}, {"No", 2},
+ {"Zs", 2}, {"Zl", 2}, {"Zp", 2}, {"Cc", 2}, {"Cf", 2}, {"Cs", 2},
+ {"Co", 2}, {"Cn", 2}, {"Lu", 2}, {"Ll", 2}, {"Lt", 2}, {"Lm", 2},
+ {"Lo", 2}, {"Pc", 2}, {"Pd", 2}, {"Ps", 2}, {"Pe", 2}, {"Po", 2},
+ {"Sm", 2}, {"Sc", 2}, {"Sk", 2}, {"So", 2}, {"L", 1}, {"R", 1},
+ {"EN", 2}, {"ES", 2}, {"ET", 2}, {"AN", 2}, {"CS", 2}, {"B", 1},
+ {"S", 1}, {"WS", 2}, {"ON", 2},
+ {"Cm", 2}, {"Nb", 2}, {"Sy", 2}, {"Hd", 2}, {"Qm", 2}, {"Mr", 2},
+ {"Ss", 2}, {"Cp", 2}, {"Pi", 2}, {"Pf", 2}, {"AL", 2}
+};
+
+typedef struct {
+ unsigned long *ranges;
+ unsigned short used;
+ unsigned short size;
+} _ranges_t;
+
+static _ranges_t proptbl[NUMPROPS];
+
+/*
+ * Make sure this array is sized to be on a 4-byte boundary at compile time.
+ */
+static unsigned short propcnt[NEEDPROPS];
+
+/*
+ * Array used to collect a decomposition before adding it to the decomposition
+ * table.
+ */
+static unsigned long dectmp[64];
+static unsigned long dectmp_size;
+
+typedef struct {
+ unsigned long code;
+ unsigned short size;
+ unsigned short used;
+ unsigned long *decomp;
+} _decomp_t;
+
+/*
+ * List of decomposition. Created and expanded in order as the characters are
+ * encountered.
+ */
+static _decomp_t *decomps;
+static unsigned long decomps_used;
+static unsigned long decomps_size;
+
+/*
+ * Composition exclusion table stuff.
+ */
+#define COMPEX_SET(c) (compexs[(c) >> 5] |= (1 << ((c) & 31)))
+#define COMPEX_TEST(c) (compexs[(c) >> 5] & (1 << ((c) & 31)))
+static unsigned long compexs[2048];
+
+/*
+ * Struct for holding a composition pair, and array of composition pairs
+ */
+typedef struct {
+ unsigned long comp;
+ unsigned long count;
+ unsigned long code1;
+ unsigned long code2;
+} _comp_t;
+
+static _comp_t *comps;
+static unsigned long comps_used;
+
+/*
+ * Types and lists for handling lists of case mappings.
+ */
+typedef struct {
+ unsigned long key;
+ unsigned long other1;
+ unsigned long other2;
+} _case_t;
+
+static _case_t *upper;
+static _case_t *lower;
+static _case_t *title;
+static unsigned long upper_used;
+static unsigned long upper_size;
+static unsigned long lower_used;
+static unsigned long lower_size;
+static unsigned long title_used;
+static unsigned long title_size;
+
+/*
+ * Array used to collect case mappings before adding them to a list.
+ */
+static unsigned long cases[3];
+
+/*
+ * An array to hold ranges for combining classes.
+ */
+static unsigned long *ccl;
+static unsigned long ccl_used;
+static unsigned long ccl_size;
+
+/*
+ * Structures for handling numbers.
+ */
+typedef struct {
+ unsigned long code;
+ unsigned long idx;
+} _codeidx_t;
+
+typedef struct {
+ short numerator;
+ short denominator;
+} _num_t;
+
+/*
+ * Arrays to hold the mapping of codes to numbers.
+ */
+static _codeidx_t *ncodes;
+static unsigned long ncodes_used;
+static unsigned long ncodes_size;
+
+static _num_t *nums;
+static unsigned long nums_used;
+static unsigned long nums_size;
+
+/*
+ * Array for holding numbers.
+ */
+static _num_t *nums;
+static unsigned long nums_used;
+static unsigned long nums_size;
+
+static void
+add_range(unsigned long start, unsigned long end, char *p1, char *p2)
+{
+ int i, j, k, len;
+ _ranges_t *rlp;
+ char *name;
+
+ for (k = 0; k < 2; k++) {
+ if (k == 0) {
+ name = p1;
+ len = 2;
+ } else {
+ if (p2 == 0)
+ break;
+
+ name = p2;
+ len = 1;
+ }
+
+ for (i = 0; i < NUMPROPS; i++) {
+ if (props[i].len == len && memcmp(props[i].name, name, len) == 0)
+ break;
+ }
+
+ if (i == NUMPROPS)
+ continue;
+
+ rlp = &proptbl[i];
+
+ /*
+ * Resize the range list if necessary.
+ */
+ if (rlp->used == rlp->size) {
+ if (rlp->size == 0)
+ rlp->ranges = (unsigned long *)
+ malloc(sizeof(unsigned long) << 3);
+ else
+ rlp->ranges = (unsigned long *)
+ realloc((char *) rlp->ranges,
+ sizeof(unsigned long) * (rlp->size + 8));
+ rlp->size += 8;
+ }
+
+ /*
+ * If this is the first code for this property list, just add it
+ * and return.
+ */
+ if (rlp->used == 0) {
+ rlp->ranges[0] = start;
+ rlp->ranges[1] = end;
+ rlp->used += 2;
+ continue;
+ }
+
+ /*
+ * Optimize the case of adding the range to the end.
+ */
+ j = rlp->used - 1;
+ if (start > rlp->ranges[j]) {
+ j = rlp->used;
+ rlp->ranges[j++] = start;
+ rlp->ranges[j++] = end;
+ rlp->used = j;
+ continue;
+ }
+
+ /*
+ * Need to locate the insertion point.
+ */
+ for (i = 0;
+ i < rlp->used && start > rlp->ranges[i + 1] + 1; i += 2) ;
+
+ /*
+ * If the start value lies in the current range, then simply set the
+ * new end point of the range to the end value passed as a parameter.
+ */
+ if (rlp->ranges[i] <= start && start <= rlp->ranges[i + 1] + 1) {
+ rlp->ranges[i + 1] = end;
+ return;
+ }
+
+ /*
+ * Shift following values up by two.
+ */
+ for (j = rlp->used; j > i; j -= 2) {
+ rlp->ranges[j] = rlp->ranges[j - 2];
+ rlp->ranges[j + 1] = rlp->ranges[j - 1];
+ }
+
+ /*
+ * Add the new range at the insertion point.
+ */
+ rlp->ranges[i] = start;
+ rlp->ranges[i + 1] = end;
+ rlp->used += 2;
+ }
+}
+
+static void
+ordered_range_insert(unsigned long c, char *name, int len)
+{
+ int i, j;
+ unsigned long s, e;
+ _ranges_t *rlp;
+
+ if (len == 0)
+ return;
+
+ /*
+ * Deal with directionality codes introduced in Unicode 3.0.
+ */
+ if ((len == 2 && memcmp(name, "BN", 2) == 0) ||
+ (len == 3 &&
+ (memcmp(name, "NSM", 3) == 0 || memcmp(name, "PDF", 3) == 0 ||
+ memcmp(name, "LRE", 3) == 0 || memcmp(name, "LRO", 3) == 0 ||
+ memcmp(name, "RLE", 3) == 0 || memcmp(name, "RLO", 3) == 0))) {
+ /*
+ * Mark all of these as Other Neutral to preserve compatibility with
+ * older versions.
+ */
+ len = 2;
+ name = "ON";
+ }
+
+ for (i = 0; i < NUMPROPS; i++) {
+ if (props[i].len == len && memcmp(props[i].name, name, len) == 0)
+ break;
+ }
+
+ if (i == NUMPROPS)
+ return;
+
+ /*
+ * Have a match, so insert the code in order.
+ */
+ rlp = &proptbl[i];
+
+ /*
+ * Resize the range list if necessary.
+ */
+ if (rlp->used == rlp->size) {
+ if (rlp->size == 0)
+ rlp->ranges = (unsigned long *)
+ malloc(sizeof(unsigned long) << 3);
+ else
+ rlp->ranges = (unsigned long *)
+ realloc((char *) rlp->ranges,
+ sizeof(unsigned long) * (rlp->size + 8));
+ rlp->size += 8;
+ }
+
+ /*
+ * If this is the first code for this property list, just add it
+ * and return.
+ */
+ if (rlp->used == 0) {
+ rlp->ranges[0] = rlp->ranges[1] = c;
+ rlp->used += 2;
+ return;
+ }
+
+ /*
+ * Optimize the cases of extending the last range and adding new ranges to
+ * the end.
+ */
+ j = rlp->used - 1;
+ e = rlp->ranges[j];
+ s = rlp->ranges[j - 1];
+
+ if (c == e + 1) {
+ /*
+ * Extend the last range.
+ */
+ rlp->ranges[j] = c;
+ return;
+ }
+
+ if (c > e + 1) {
+ /*
+ * Start another range on the end.
+ */
+ j = rlp->used;
+ rlp->ranges[j] = rlp->ranges[j + 1] = c;
+ rlp->used += 2;
+ return;
+ }
+
+ if (c >= s)
+ /*
+ * The code is a duplicate of a code in the last range, so just return.
+ */
+ return;
+
+ /*
+ * The code should be inserted somewhere before the last range in the
+ * list. Locate the insertion point.
+ */
+ for (i = 0;
+ i < rlp->used && c > rlp->ranges[i + 1] + 1; i += 2) ;
+
+ s = rlp->ranges[i];
+ e = rlp->ranges[i + 1];
+
+ if (c == e + 1)
+ /*
+ * Simply extend the current range.
+ */
+ rlp->ranges[i + 1] = c;
+ else if (c < s) {
+ /*
+ * Add a new entry before the current location. Shift all entries
+ * before the current one up by one to make room.
+ */
+ for (j = rlp->used; j > i; j -= 2) {
+ rlp->ranges[j] = rlp->ranges[j - 2];
+ rlp->ranges[j + 1] = rlp->ranges[j - 1];
+ }
+ rlp->ranges[i] = rlp->ranges[i + 1] = c;
+
+ rlp->used += 2;
+ }
+}
+
+static void
+add_decomp(unsigned long code)
+{
+ unsigned long i, j, size;
+
+ /*
+ * Add the code to the composite property.
+ */
+ ordered_range_insert(code, "Cm", 2);
+
+ /*
+ * Locate the insertion point for the code.
+ */
+ for (i = 0; i < decomps_used && code > decomps[i].code; i++) ;
+
+ /*
+ * Allocate space for a new decomposition.
+ */
+ if (decomps_used == decomps_size) {
+ if (decomps_size == 0)
+ decomps = (_decomp_t *) malloc(sizeof(_decomp_t) << 3);
+ else
+ decomps = (_decomp_t *)
+ realloc((char *) decomps,
+ sizeof(_decomp_t) * (decomps_size + 8));
+ (void) memset((char *) (decomps + decomps_size), '\0',
+ sizeof(_decomp_t) << 3);
+ decomps_size += 8;
+ }
+
+ if (i < decomps_used && code != decomps[i].code) {
+ /*
+ * Shift the decomps up by one if the codes don't match.
+ */
+ for (j = decomps_used; j > i; j--)
+ (void) AC_MEMCPY((char *) &decomps[j], (char *) &decomps[j - 1],
+ sizeof(_decomp_t));
+ }
+
+ /*
+ * Insert or replace a decomposition.
+ */
+ size = dectmp_size + (4 - (dectmp_size & 3));
+ if (decomps[i].size < size) {
+ if (decomps[i].size == 0)
+ decomps[i].decomp = (unsigned long *)
+ malloc(sizeof(unsigned long) * size);
+ else
+ decomps[i].decomp = (unsigned long *)
+ realloc((char *) decomps[i].decomp,
+ sizeof(unsigned long) * size);
+ decomps[i].size = size;
+ }
+
+ if (decomps[i].code != code)
+ decomps_used++;
+
+ decomps[i].code = code;
+ decomps[i].used = dectmp_size;
+ (void) AC_MEMCPY((char *) decomps[i].decomp, (char *) dectmp,
+ sizeof(unsigned long) * dectmp_size);
+
+ /*
+ * NOTICE: This needs changing later so it is more general than simply
+ * pairs. This calculation is done here to simplify allocation elsewhere.
+ */
+ if (dectmp_size == 2)
+ comps_used++;
+}
+
+static void
+add_title(unsigned long code)
+{
+ unsigned long i, j;
+
+ /*
+ * Always map the code to itself.
+ */
+ cases[2] = code;
+
+ if (title_used == title_size) {
+ if (title_size == 0)
+ title = (_case_t *) malloc(sizeof(_case_t) << 3);
+ else
+ title = (_case_t *) realloc((char *) title,
+ sizeof(_case_t) * (title_size + 8));
+ title_size += 8;
+ }
+
+ /*
+ * Locate the insertion point.
+ */
+ for (i = 0; i < title_used && code > title[i].key; i++) ;
+
+ if (i < title_used) {
+ /*
+ * Shift the array up by one.
+ */
+ for (j = title_used; j > i; j--)
+ (void) AC_MEMCPY((char *) &title[j], (char *) &title[j - 1],
+ sizeof(_case_t));
+ }
+
+ title[i].key = cases[2]; /* Title */
+ title[i].other1 = cases[0]; /* Upper */
+ title[i].other2 = cases[1]; /* Lower */
+
+ title_used++;
+}
+
+static void
+add_upper(unsigned long code)
+{
+ unsigned long i, j;
+
+ /*
+ * Always map the code to itself.
+ */
+ cases[0] = code;
+
+ /*
+ * If the title case character is not present, then make it the same as
+ * the upper case.
+ */
+ if (cases[2] == 0)
+ cases[2] = code;
+
+ if (upper_used == upper_size) {
+ if (upper_size == 0)
+ upper = (_case_t *) malloc(sizeof(_case_t) << 3);
+ else
+ upper = (_case_t *) realloc((char *) upper,
+ sizeof(_case_t) * (upper_size + 8));
+ upper_size += 8;
+ }
+
+ /*
+ * Locate the insertion point.
+ */
+ for (i = 0; i < upper_used && code > upper[i].key; i++) ;
+
+ if (i < upper_used) {
+ /*
+ * Shift the array up by one.
+ */
+ for (j = upper_used; j > i; j--)
+ (void) AC_MEMCPY((char *) &upper[j], (char *) &upper[j - 1],
+ sizeof(_case_t));
+ }
+
+ upper[i].key = cases[0]; /* Upper */
+ upper[i].other1 = cases[1]; /* Lower */
+ upper[i].other2 = cases[2]; /* Title */
+
+ upper_used++;
+}
+
+static void
+add_lower(unsigned long code)
+{
+ unsigned long i, j;
+
+ /*
+ * Always map the code to itself.
+ */
+ cases[1] = code;
+
+ /*
+ * If the title case character is empty, then make it the same as the
+ * upper case.
+ */
+ if (cases[2] == 0)
+ cases[2] = cases[0];
+
+ if (lower_used == lower_size) {
+ if (lower_size == 0)
+ lower = (_case_t *) malloc(sizeof(_case_t) << 3);
+ else
+ lower = (_case_t *) realloc((char *) lower,
+ sizeof(_case_t) * (lower_size + 8));
+ lower_size += 8;
+ }
+
+ /*
+ * Locate the insertion point.
+ */
+ for (i = 0; i < lower_used && code > lower[i].key; i++) ;
+
+ if (i < lower_used) {
+ /*
+ * Shift the array up by one.
+ */
+ for (j = lower_used; j > i; j--)
+ (void) AC_MEMCPY((char *) &lower[j], (char *) &lower[j - 1],
+ sizeof(_case_t));
+ }
+
+ lower[i].key = cases[1]; /* Lower */
+ lower[i].other1 = cases[0]; /* Upper */
+ lower[i].other2 = cases[2]; /* Title */
+
+ lower_used++;
+}
+
+static void
+ordered_ccl_insert(unsigned long c, unsigned long ccl_code)
+{
+ unsigned long i, j;
+
+ if (ccl_used == ccl_size) {
+ if (ccl_size == 0)
+ ccl = (unsigned long *) malloc(sizeof(unsigned long) * 24);
+ else
+ ccl = (unsigned long *)
+ realloc((char *) ccl, sizeof(unsigned long) * (ccl_size + 24));
+ ccl_size += 24;
+ }
+
+ /*
+ * Optimize adding the first item.
+ */
+ if (ccl_used == 0) {
+ ccl[0] = ccl[1] = c;
+ ccl[2] = ccl_code;
+ ccl_used += 3;
+ return;
+ }
+
+ /*
+ * Handle the special case of extending the range on the end. This
+ * requires that the combining class codes are the same.
+ */
+ if (ccl_code == ccl[ccl_used - 1] && c == ccl[ccl_used - 2] + 1) {
+ ccl[ccl_used - 2] = c;
+ return;
+ }
+
+ /*
+ * Handle the special case of adding another range on the end.
+ */
+ if (c > ccl[ccl_used - 2] + 1 ||
+ (c == ccl[ccl_used - 2] + 1 && ccl_code != ccl[ccl_used - 1])) {
+ ccl[ccl_used++] = c;
+ ccl[ccl_used++] = c;
+ ccl[ccl_used++] = ccl_code;
+ return;
+ }
+
+ /*
+ * Locate either the insertion point or range for the code.
+ */
+ for (i = 0; i < ccl_used && c > ccl[i + 1] + 1; i += 3) ;
+
+ if (ccl_code == ccl[i + 2] && c == ccl[i + 1] + 1) {
+ /*
+ * Extend an existing range.
+ */
+ ccl[i + 1] = c;
+ return;
+ } else if (c < ccl[i]) {
+ /*
+ * Start a new range before the current location.
+ */
+ for (j = ccl_used; j > i; j -= 3) {
+ ccl[j] = ccl[j - 3];
+ ccl[j - 1] = ccl[j - 4];
+ ccl[j - 2] = ccl[j - 5];
+ }
+ ccl[i] = ccl[i + 1] = c;
+ ccl[i + 2] = ccl_code;
+ }
+}
+
+/*
+ * Adds a number if it does not already exist and returns an index value
+ * multiplied by 2.
+ */
+static unsigned long
+make_number(short num, short denom)
+{
+ unsigned long n;
+
+ /*
+ * Determine if the number already exists.
+ */
+ for (n = 0; n < nums_used; n++) {
+ if (nums[n].numerator == num && nums[n].denominator == denom)
+ return n << 1;
+ }
+
+ if (nums_used == nums_size) {
+ if (nums_size == 0)
+ nums = (_num_t *) malloc(sizeof(_num_t) << 3);
+ else
+ nums = (_num_t *) realloc((char *) nums,
+ sizeof(_num_t) * (nums_size + 8));
+ nums_size += 8;
+ }
+
+ n = nums_used++;
+ nums[n].numerator = num;
+ nums[n].denominator = denom;
+
+ return n << 1;
+}
+
+static void
+add_number(unsigned long code, short num, short denom)
+{
+ unsigned long i, j;
+
+ /*
+ * Insert the code in order.
+ */
+ for (i = 0; i < ncodes_used && code > ncodes[i].code; i++) ;
+
+ /*
+ * Handle the case of the codes matching and simply replace the number
+ * that was there before.
+ */
+ if (i < ncodes_used && code == ncodes[i].code) {
+ ncodes[i].idx = make_number(num, denom);
+ return;
+ }
+
+ /*
+ * Resize the array if necessary.
+ */
+ if (ncodes_used == ncodes_size) {
+ if (ncodes_size == 0)
+ ncodes = (_codeidx_t *) malloc(sizeof(_codeidx_t) << 3);
+ else
+ ncodes = (_codeidx_t *)
+ realloc((char *) ncodes, sizeof(_codeidx_t) * (ncodes_size + 8));
+
+ ncodes_size += 8;
+ }
+
+ /*
+ * Shift things around to insert the code if necessary.
+ */
+ if (i < ncodes_used) {
+ for (j = ncodes_used; j > i; j--) {
+ ncodes[j].code = ncodes[j - 1].code;
+ ncodes[j].idx = ncodes[j - 1].idx;
+ }
+ }
+ ncodes[i].code = code;
+ ncodes[i].idx = make_number(num, denom);
+
+ ncodes_used++;
+}
+
+/*
+ * This routine assumes that the line is a valid Unicode Character Database
+ * entry.
+ */
+static void
+read_cdata(FILE *in)
+{
+ unsigned long i, lineno, skip, code, ccl_code;
+ short wnum, neg, number[2];
+ char line[512], *s, *e;
+
+ lineno = skip = 0;
+ while (fscanf(in, "%[^\n]\n", line) != EOF) {
+ lineno++;
+
+ /*
+ * Skip blank lines and lines that start with a '#'.
+ */
+ if (line[0] == 0 || line[0] == '#')
+ continue;
+
+ /*
+ * If lines need to be skipped, do it here.
+ */
+ if (skip) {
+ skip--;
+ continue;
+ }
+
+ /*
+ * Collect the code. The code can be up to 6 hex digits in length to
+ * allow surrogates to be specified.
+ */
+ for (s = line, i = code = 0; *s != ';' && i < 6; i++, s++) {
+ code <<= 4;
+ if (*s >= '0' && *s <= '9')
+ code += *s - '0';
+ else if (*s >= 'A' && *s <= 'F')
+ code += (*s - 'A') + 10;
+ else if (*s >= 'a' && *s <= 'f')
+ code += (*s - 'a') + 10;
+ }
+
+ /*
+ * Handle the following special cases:
+ * 1. 4E00-9FA5 CJK Ideographs.
+ * 2. AC00-D7A3 Hangul Syllables.
+ * 3. D800-DFFF Surrogates.
+ * 4. E000-F8FF Private Use Area.
+ * 5. F900-FA2D Han compatibility.
+ */
+ switch (code) {
+ case 0x4e00:
+ /*
+ * The Han ideographs.
+ */
+ add_range(0x4e00, 0x9fff, "Lo", "L");
+
+ /*
+ * Add the characters to the defined category.
+ */
+ add_range(0x4e00, 0x9fa5, "Cp", 0);
+
+ skip = 1;
+ break;
+ case 0xac00:
+ /*
+ * The Hangul syllables.
+ */
+ add_range(0xac00, 0xd7a3, "Lo", "L");
+
+ /*
+ * Add the characters to the defined category.
+ */
+ add_range(0xac00, 0xd7a3, "Cp", 0);
+
+ skip = 1;
+ break;
+ case 0xd800:
+ /*
+ * Make a range of all surrogates and assume some default
+ * properties.
+ */
+ add_range(0x010000, 0x10ffff, "Cs", "L");
+ skip = 5;
+ break;
+ case 0xe000:
+ /*
+ * The Private Use area. Add with a default set of properties.
+ */
+ add_range(0xe000, 0xf8ff, "Co", "L");
+ skip = 1;
+ break;
+ case 0xf900:
+ /*
+ * The CJK compatibility area.
+ */
+ add_range(0xf900, 0xfaff, "Lo", "L");
+
+ /*
+ * Add the characters to the defined category.
+ */
+ add_range(0xf900, 0xfaff, "Cp", 0);
+
+ skip = 1;
+ }
+
+ if (skip)
+ continue;
+
+ /*
+ * Add the code to the defined category.
+ */
+ ordered_range_insert(code, "Cp", 2);
+
+ /*
+ * Locate the first character property field.
+ */
+ for (i = 0; *s != 0 && i < 2; s++) {
+ if (*s == ';')
+ i++;
+ }
+ for (e = s; *e && *e != ';'; e++) ;
+
+ ordered_range_insert(code, s, e - s);
+
+ /*
+ * Locate the combining class code.
+ */
+ for (s = e; *s != 0 && i < 3; s++) {
+ if (*s == ';')
+ i++;
+ }
+
+ /*
+ * Convert the combining class code from decimal.
+ */
+ for (ccl_code = 0, e = s; *e && *e != ';'; e++)
+ ccl_code = (ccl_code * 10) + (*e - '0');
+
+ /*
+ * Add the code if it not 0.
+ */
+ if (ccl_code != 0)
+ ordered_ccl_insert(code, ccl_code);
+
+ /*
+ * Locate the second character property field.
+ */
+ for (s = e; *s != 0 && i < 4; s++) {
+ if (*s == ';')
+ i++;
+ }
+ for (e = s; *e && *e != ';'; e++) ;
+
+ ordered_range_insert(code, s, e - s);
+
+ /*
+ * Check for a decomposition.
+ */
+ s = ++e;
+ if (*s != ';' && *s != '<') {
+ /*
+ * Collect the codes of the decomposition.
+ */
+ for (dectmp_size = 0; *s != ';'; ) {
+ /*
+ * Skip all leading non-hex digits.
+ */
+ while (!ishdigit(*s))
+ s++;
+
+ for (dectmp[dectmp_size] = 0; ishdigit(*s); s++) {
+ dectmp[dectmp_size] <<= 4;
+ if (*s >= '0' && *s <= '9')
+ dectmp[dectmp_size] += *s - '0';
+ else if (*s >= 'A' && *s <= 'F')
+ dectmp[dectmp_size] += (*s - 'A') + 10;
+ else if (*s >= 'a' && *s <= 'f')
+ dectmp[dectmp_size] += (*s - 'a') + 10;
+ }
+ dectmp_size++;
+ }
+
+ /*
+ * If there are any codes in the temporary decomposition array,
+ * then add the character with its decomposition.
+ */
+ if (dectmp_size > 0)
+ add_decomp(code);
+ }
+
+ /*
+ * Skip to the number field.
+ */
+ for (i = 0; i < 3 && *s; s++) {
+ if (*s == ';')
+ i++;
+ }
+
+ /*
+ * Scan the number in.
+ */
+ number[0] = number[1] = 0;
+ for (e = s, neg = wnum = 0; *e && *e != ';'; e++) {
+ if (*e == '-') {
+ neg = 1;
+ continue;
+ }
+
+ if (*e == '/') {
+ /*
+ * Move the the denominator of the fraction.
+ */
+ if (neg)
+ number[wnum] *= -1;
+ neg = 0;
+ e++;
+ wnum++;
+ }
+ number[wnum] = (number[wnum] * 10) + (*e - '0');
+ }
+
+ if (e > s) {
+ /*
+ * Adjust the denominator in case of integers and add the number.
+ */
+ if (wnum == 0)
+ number[1] = number[0];
+
+ add_number(code, number[0], number[1]);
+ }
+
+ /*
+ * Skip to the start of the possible case mappings.
+ */
+ for (s = e, i = 0; i < 4 && *s; s++) {
+ if (*s == ';')
+ i++;
+ }
+
+ /*
+ * Collect the case mappings.
+ */
+ cases[0] = cases[1] = cases[2] = 0;
+ for (i = 0; i < 3; i++) {
+ while (ishdigit(*s)) {
+ cases[i] <<= 4;
+ if (*s >= '0' && *s <= '9')
+ cases[i] += *s - '0';
+ else if (*s >= 'A' && *s <= 'F')
+ cases[i] += (*s - 'A') + 10;
+ else if (*s >= 'a' && *s <= 'f')
+ cases[i] += (*s - 'a') + 10;
+ s++;
+ }
+ if (*s == ';')
+ s++;
+ }
+ if (cases[0] && cases[1])
+ /*
+ * Add the upper and lower mappings for a title case character.
+ */
+ add_title(code);
+ else if (cases[1])
+ /*
+ * Add the lower and title case mappings for the upper case
+ * character.
+ */
+ add_upper(code);
+ else if (cases[0])
+ /*
+ * Add the upper and title case mappings for the lower case
+ * character.
+ */
+ add_lower(code);
+ }
+}
+
+static _decomp_t *
+find_decomp(unsigned long code)
+{
+ long l, r, m;
+
+ l = 0;
+ r = decomps_used - 1;
+ while (l <= r) {
+ m = (l + r) >> 1;
+ if (code > decomps[m].code)
+ l = m + 1;
+ else if (code < decomps[m].code)
+ r = m - 1;
+ else
+ return &decomps[m];
+ }
+ return 0;
+}
+
+static void
+decomp_it(_decomp_t *d)
+{
+ unsigned long i;
+ _decomp_t *dp;
+
+ for (i = 0; i < d->used; i++) {
+ if ((dp = find_decomp(d->decomp[i])) != 0)
+ decomp_it(dp);
+ else
+ dectmp[dectmp_size++] = d->decomp[i];
+ }
+}
+
+/*
+ * Expand all decompositions by recursively decomposing each character
+ * in the decomposition.
+ */
+static void
+expand_decomp(void)
+{
+ unsigned long i;
+
+ for (i = 0; i < decomps_used; i++) {
+ dectmp_size = 0;
+ decomp_it(&decomps[i]);
+ if (dectmp_size > 0)
+ add_decomp(decomps[i].code);
+ }
+}
+
+static int
+cmpcomps(_comp_t *comp1, _comp_t *comp2)
+{
+ long diff = comp1->code1 - comp2->code1;
+
+ if (!diff)
+ diff = comp1->code2 - comp2->code2;
+ return (int) diff;
+}
+
+/*
+ * Load composition exclusion data
+ */
+static void
+read_compexdata(FILE *in)
+{
+ unsigned short i, code;
+ char line[512], *s;
+
+ (void) memset((char *) compexs, 0, sizeof(unsigned long) << 11);
+
+ while (fscanf(in, "%[^\n]\n", line) != EOF) {
+ /*
+ * Skip blank lines and lines that start with a '#'.
+ */
+ if (line[0] == 0 || line[0] == '#')
+ continue;
+
+ /*
+ * Collect the code. Assume max 4 digits
+ */
+
+ for (s = line, i = code = 0; *s != '#' && i < 4; i++, s++) {
+ code <<= 4;
+ if (*s >= '0' && *s <= '9')
+ code += *s - '0';
+ else if (*s >= 'A' && *s <= 'F')
+ code += (*s - 'A') + 10;
+ else if (*s >= 'a' && *s <= 'f')
+ code += (*s - 'a') + 10;
+ }
+ COMPEX_SET(code);
+ }
+}
+
+/*
+ * Creates array of compositions from decomposition array
+ */
+static void
+create_comps(void)
+{
+ unsigned long i, cu;
+
+ comps = (_comp_t *) malloc(comps_used * sizeof(_comp_t));
+
+ for (i = cu = 0; i < decomps_used; i++) {
+ if (decomps[i].used != 2 || COMPEX_TEST(decomps[i].code))
+ continue;
+ comps[cu].comp = decomps[i].code;
+ comps[cu].count = 2;
+ comps[cu].code1 = decomps[i].decomp[0];
+ comps[cu].code2 = decomps[i].decomp[1];
+ cu++;
+ }
+ comps_used = cu;
+ qsort(comps, comps_used, sizeof(_comp_t),
+ (int (*)(const void *, const void *)) cmpcomps);
+}
+
+static void
+write_cdata(char *opath)
+{
+ FILE *out;
+ unsigned long i, idx, bytes, nprops;
+ unsigned short casecnt[2];
+ char path[BUFSIZ];
+
+ /*****************************************************************
+ *
+ * Generate the ctype data.
+ *
+ *****************************************************************/
+
+ /*
+ * Open the ctype.dat file.
+ */
+ sprintf(path, "%s%sctype.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ /*
+ * Collect the offsets for the properties. The offsets array is
+ * on a 4-byte boundary to keep things efficient for architectures
+ * that need such a thing.
+ */
+ for (i = idx = 0; i < NUMPROPS; i++) {
+ propcnt[i] = (proptbl[i].used != 0) ? idx : 0xffff;
+ idx += proptbl[i].used;
+ }
+
+ /*
+ * Add the sentinel index which is used by the binary search as the upper
+ * bound for a search.
+ */
+ propcnt[i] = idx;
+
+ /*
+ * Record the actual number of property lists. This may be different than
+ * the number of offsets actually written because of aligning on a 4-byte
+ * boundary.
+ */
+ hdr[1] = NUMPROPS;
+
+ /*
+ * Calculate the byte count needed and pad the property counts array to a
+ * 4-byte boundary.
+ */
+ if ((bytes = sizeof(unsigned short) * (NUMPROPS + 1)) & 3)
+ bytes += 4 - (bytes & 3);
+ nprops = bytes / sizeof(unsigned short);
+ bytes += sizeof(unsigned long) * idx;
+
+ /*
+ * Write the header.
+ */
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write the byte count.
+ */
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ /*
+ * Write the property list counts.
+ */
+ fwrite((char *) propcnt, sizeof(unsigned short), nprops, out);
+
+ /*
+ * Write the property lists.
+ */
+ for (i = 0; i < NUMPROPS; i++) {
+ if (proptbl[i].used > 0)
+ fwrite((char *) proptbl[i].ranges, sizeof(unsigned long),
+ proptbl[i].used, out);
+ }
+
+ fclose(out);
+
+ /*****************************************************************
+ *
+ * Generate the case mapping data.
+ *
+ *****************************************************************/
+
+ /*
+ * Open the case.dat file.
+ */
+ sprintf(path, "%s%scase.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ /*
+ * Write the case mapping tables.
+ */
+ hdr[1] = upper_used + lower_used + title_used;
+ casecnt[0] = upper_used;
+ casecnt[1] = lower_used;
+
+ /*
+ * Write the header.
+ */
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write the upper and lower case table sizes.
+ */
+ fwrite((char *) casecnt, sizeof(unsigned short), 2, out);
+
+ if (upper_used > 0)
+ /*
+ * Write the upper case table.
+ */
+ fwrite((char *) upper, sizeof(_case_t), upper_used, out);
+
+ if (lower_used > 0)
+ /*
+ * Write the lower case table.
+ */
+ fwrite((char *) lower, sizeof(_case_t), lower_used, out);
+
+ if (title_used > 0)
+ /*
+ * Write the title case table.
+ */
+ fwrite((char *) title, sizeof(_case_t), title_used, out);
+
+ fclose(out);
+
+ /*****************************************************************
+ *
+ * Generate the composition data.
+ *
+ *****************************************************************/
+
+ /*
+ * Create compositions from decomposition data
+ */
+ create_comps();
+
+ /*
+ * Open the comp.dat file.
+ */
+ sprintf(path, "%s%scomp.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ /*
+ * Write the header.
+ */
+ hdr[1] = (unsigned short) comps_used * 4;
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write out the byte count to maintain header size.
+ */
+ bytes = comps_used * sizeof(_comp_t);
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ /*
+ * Now, if comps exist, write them out.
+ */
+ if (comps_used > 0)
+ fwrite((char *) comps, sizeof(_comp_t), comps_used, out);
+
+ fclose(out);
+
+ /*****************************************************************
+ *
+ * Generate the decomposition data.
+ *
+ *****************************************************************/
+
+ /*
+ * Fully expand all decompositions before generating the output file.
+ */
+ expand_decomp();
+
+ /*
+ * Open the decomp.dat file.
+ */
+ sprintf(path, "%s%sdecomp.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ hdr[1] = decomps_used;
+
+ /*
+ * Write the header.
+ */
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write a temporary byte count which will be calculated as the
+ * decompositions are written out.
+ */
+ bytes = 0;
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ if (decomps_used) {
+ /*
+ * Write the list of decomp nodes.
+ */
+ for (i = idx = 0; i < decomps_used; i++) {
+ fwrite((char *) &decomps[i].code, sizeof(unsigned long), 1, out);
+ fwrite((char *) &idx, sizeof(unsigned long), 1, out);
+ idx += decomps[i].used;
+ }
+
+ /*
+ * Write the sentinel index as the last decomp node.
+ */
+ fwrite((char *) &idx, sizeof(unsigned long), 1, out);
+
+ /*
+ * Write the decompositions themselves.
+ */
+ for (i = 0; i < decomps_used; i++)
+ fwrite((char *) decomps[i].decomp, sizeof(unsigned long),
+ decomps[i].used, out);
+
+ /*
+ * Seek back to the beginning and write the byte count.
+ */
+ bytes = (sizeof(unsigned long) * idx) +
+ (sizeof(unsigned long) * ((hdr[1] << 1) + 1));
+ fseek(out, sizeof(unsigned short) << 1, 0L);
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ fclose(out);
+ }
+
+ /*****************************************************************
+ *
+ * Generate the combining class data.
+ *
+ *****************************************************************/
+
+ /*
+ * Open the cmbcl.dat file.
+ */
+ sprintf(path, "%s%scmbcl.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ /*
+ * Set the number of ranges used. Each range has a combining class which
+ * means each entry is a 3-tuple.
+ */
+ hdr[1] = ccl_used / 3;
+
+ /*
+ * Write the header.
+ */
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write out the byte count to maintain header size.
+ */
+ bytes = ccl_used * sizeof(unsigned long);
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ if (ccl_used > 0)
+ /*
+ * Write the combining class ranges out.
+ */
+ fwrite((char *) ccl, sizeof(unsigned long), ccl_used, out);
+
+ fclose(out);
+
+ /*****************************************************************
+ *
+ * Generate the number data.
+ *
+ *****************************************************************/
+
+ /*
+ * Open the num.dat file.
+ */
+ sprintf(path, "%s%snum.dat", opath, LDAP_DIRSEP);
+ if ((out = fopen(path, "wb")) == 0)
+ return;
+
+ /*
+ * The count part of the header will be the total number of codes that
+ * have numbers.
+ */
+ hdr[1] = (unsigned short) (ncodes_used << 1);
+ bytes = (ncodes_used * sizeof(_codeidx_t)) + (nums_used * sizeof(_num_t));
+
+ /*
+ * Write the header.
+ */
+ fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+
+ /*
+ * Write out the byte count to maintain header size.
+ */
+ fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
+
+ /*
+ * Now, if number mappings exist, write them out.
+ */
+ if (ncodes_used > 0) {
+ fwrite((char *) ncodes, sizeof(_codeidx_t), ncodes_used, out);
+ fwrite((char *) nums, sizeof(_num_t), nums_used, out);
+ }
+
+ fclose(out);
+}
+
+static void
+usage(char *prog)
+{
+ fprintf(stderr,
+ "Usage: %s [-o output-directory|-x composition-exclusions]", prog);
+ fprintf(stderr, " datafile1 datafile2 ...\n\n");
+ fprintf(stderr,
+ "-o output-directory\n\t\tWrite the output files to a different");
+ fprintf(stderr, " directory (default: .).\n");
+ fprintf(stderr,
+ "-x composition-exclusion\n\t\tFile of composition codes");
+ fprintf(stderr, " that should be excluded.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *in;
+ char *prog, *opath;
+
+ if ((prog = strrchr(argv[0], *LDAP_DIRSEP)) != 0)
+ prog++;
+ else
+ prog = argv[0];
+
+ opath = 0;
+ in = stdin;
+
+ argc--;
+ argv++;
+
+ while (argc > 0) {
+ if (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'o':
+ argc--;
+ argv++;
+ opath = argv[0];
+ break;
+ case 'x':
+ argc--;
+ argv++;
+ if ((in = fopen(argv[0], "rb")) == 0)
+ fprintf(stderr,
+ "%s: unable to open composition exclusion file %s\n",
+ prog, argv[0]);
+ else {
+ read_compexdata(in);
+ fclose(in);
+ in = 0;
+ }
+ break;
+ default:
+ usage(prog);
+ }
+ } else {
+ if (in != stdin && in != NULL)
+ fclose(in);
+ if ((in = fopen(argv[0], "rb")) == 0)
+ fprintf(stderr, "%s: unable to open ctype file %s\n",
+ prog, argv[0]);
+ else {
+ read_cdata(in);
+ fclose(in);
+ in = 0;
+ }
+ }
+ argc--;
+ argv++;
+ }
+
+ if (opath == 0)
+ opath = ".";
+ write_cdata(opath);
+
+ return 0;
+}
i = 0;
}
- p = ucs = (long *) malloc( len * sizeof(*ucs) );
+ p = ucs = malloc( len * sizeof(*ucs) );
if ( ucs == NULL ) {
free(out);
return NULL;
* proper normalized form.
*/
- ucs = (long *) malloc( ( ( norm1 || l1 > l2 ) ? l1 : l2 ) * sizeof(*ucs) );
+ ucs = malloc( ( ( norm1 || l1 > l2 ) ? l1 : l2 ) * sizeof(*ucs) );
if ( ucs == NULL ) {
return l1 > l2 ? 1 : -1; /* what to do??? */
}
if ( norm1 ) {
ucsout1 = ucs;
l1 = ulen;
- ucs = (long *) malloc( l2 * sizeof(*ucs) );
+ ucs = malloc( l2 * sizeof(*ucs) );
if ( ucs == NULL ) {
return l1 > l2 ? 1 : -1; /* what to do??? */
}
#endif /* SLAPD_LMHASH */
#ifdef SLAPD_SPASSWD
-# include <sasl.h>
+# ifdef HAVE_SASL_SASL_H
+# include <sasl/sasl.h>
+# else
+# include <sasl.h>
+# endif
#endif
#ifdef SLAPD_KPASSWD
#ifdef HAVE_CYRUS_SASL
if( lutil_passwd_sasl_conn != NULL ) {
- const char *errstr = NULL;
int sc;
-
+# if SASL_VERSION_MAJOR < 2
+ const char *errstr = NULL;
sc = sasl_checkpass( lutil_passwd_sasl_conn,
passwd->bv_val, passwd->bv_len,
cred->bv_val, cred->bv_len,
&errstr );
-
+# else
+ sc = sasl_checkpass( lutil_passwd_sasl_conn,
+ passwd->bv_val, passwd->bv_len,
+ cred->bv_val, cred->bv_len );
+# endif
rtn = ( sc != SASL_OK );
}
#endif
for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) {
if ( p[ 0 ] == REWRITE_SUBMATCH_ESCAPE ) {
/*
- * '\' marks the beginning of a new map
+ * '%' marks the beginning of a new map
*/
if ( p[ 1 ] == '{' ) {
cnt++;
/*
- * '\' followed by a digit may mark the beginning
+ * '%' followed by a digit may mark the beginning
* of an old map
*/
} else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) {
cnt++;
p++;
}
- p++;
+ if ( p[ 1 ] != '\0' )
+ p++;
} else if ( p[ 0 ] == '}' ) {
cnt--;
}
}
for ( begin = p; p[ 0 ] != '\0'; p++ ) {
- if ( p[ 0 ] == '\\' ) {
+ if ( p[ 0 ] == '\\' && p[ 1 ] != '\0' ) {
p++;
} else if ( p[ 0 ] == '\'' || p[ 0 ] == '\"') {
if ( in_quoted_field && p[ 0 ] == quote ) {
for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
/*
- * Keep only single escapes '\'
+ * Keep only single escapes '%'
*/
if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) {
continue;
static void access_append(Access **l, Access *a);
static void acl_usage(void) LDAP_GCCATTR((noreturn));
-static void acl_regex_normalized_dn(struct berval *pattern);
+static void acl_regex_normalized_dn(const char *src, struct berval *pat);
#ifdef LDAP_DEBUG
static void print_acl(Backend *be, AccessControl *a);
static void print_access(Access *b);
#endif
-static int
+static void
regtest(const char *fname, int lineno, char *pat) {
int e;
regex_t re;
"%s: line %d: regular expression \"%s\" bad because of %s\n",
fname, lineno, pat, error );
acl_usage();
- return(0);
}
regfree(&re);
- return(1);
}
void
|| strcmp(right, ".*") == 0
|| strcmp(right, ".*$") == 0
|| strcmp(right, "^.*") == 0
- || strcmp(right, "^.*$$") == 0
+ || strcmp(right, "^.*$") == 0
|| strcmp(right, ".*$$") == 0
|| strcmp(right, "^.*$$") == 0 )
{
a->acl_dn_pat.bv_len = sizeof("*")-1;
} else {
- a->acl_dn_pat.bv_val = right;
- acl_regex_normalized_dn( &a->acl_dn_pat );
+ acl_regex_normalized_dn( right, &a->acl_dn_pat );
}
} else if ( strcasecmp( style, "base" ) == 0 ) {
a->acl_dn_style = ACL_STYLE_BASE;
if( a->acl_dn_pat.bv_len != 0 ) {
if ( a->acl_dn_style != ACL_STYLE_REGEX ) {
struct berval bv;
- dnNormalize2( NULL, &a->acl_dn_pat, &bv);
+ rc = dnNormalize2( NULL, &a->acl_dn_pat, &bv);
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr,
+ "%s: line %d: bad DN \"%s\"\n",
+ fname, lineno, a->acl_dn_pat.bv_val );
+ acl_usage();
+ }
free( a->acl_dn_pat.bv_val );
a->acl_dn_pat = bv;
} else {
1, &bv);
} else {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
}
if ( sty != ACL_STYLE_REGEX && expand == 0 ) {
- dnNormalize2(NULL, &bv, &b->a_dn_pat);
+ rc = dnNormalize2(NULL, &bv, &b->a_dn_pat);
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr,
+ "%s: line %d: bad DN \"%s\"\n",
+ fname, lineno, bv.bv_val );
+ acl_usage();
+ }
free(bv.bv_val);
} else {
b->a_dn_pat = bv;
b->a_group_style = sty;
if (sty == ACL_STYLE_REGEX) {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
b->a_group_pat = bv;
} else {
ber_str2bv( right, 0, 0, &bv );
- dnNormalize2( NULL, &bv, &b->a_group_pat );
+ rc = dnNormalize2( NULL, &bv, &b->a_group_pat );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr,
+ "%s: line %d: bad DN \"%s\"\n",
+ fname, lineno, right );
+ acl_usage();
+ }
}
if (value && *value) {
b->a_peername_style = sty;
if (sty == ACL_STYLE_REGEX) {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
b->a_sockname_style = sty;
if (sty == ACL_STYLE_REGEX) {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
b->a_domain_style = sty;
b->a_domain_expand = expand;
if (sty == ACL_STYLE_REGEX) {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
b->a_sockurl_style = sty;
if (sty == ACL_STYLE_REGEX) {
- bv.bv_val = right;
- acl_regex_normalized_dn( &bv );
+ acl_regex_normalized_dn( right, &bv );
if ( !ber_bvccmp( &bv, '*' ) ) {
regtest(fname, lineno, bv.bv_val);
}
}
for( i=1; str[i] != '\0'; i++ ) {
- if( TOLOWER(str[i]) == 'w' ) {
+ if( TOLOWER((unsigned char) str[i]) == 'w' ) {
ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
- } else if( TOLOWER(str[i]) == 'r' ) {
+ } else if( TOLOWER((unsigned char) str[i]) == 'r' ) {
ACL_PRIV_SET(mask, ACL_PRIV_READ);
- } else if( TOLOWER(str[i]) == 's' ) {
+ } else if( TOLOWER((unsigned char) str[i]) == 's' ) {
ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
- } else if( TOLOWER(str[i]) == 'c' ) {
+ } else if( TOLOWER((unsigned char) str[i]) == 'c' ) {
ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
- } else if( TOLOWER(str[i]) == 'x' ) {
+ } else if( TOLOWER((unsigned char) str[i]) == 'x' ) {
ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
} else if( str[i] != '0' ) {
}
/*
+ * Set pattern to a "normalized" DN from src.
* At present it simply eats the (optional) space after
* a RDN separator (,)
* Eventually will evolve in a more complete normalization
- *
- * Note that the input berval only needs bv_val, it ignores
- * the input bv_len and sets it on return.
*/
static void
acl_regex_normalized_dn(
+ const char *src,
struct berval *pattern
)
{
char *str, *p;
+ ber_len_t len;
- str = ch_strdup( pattern->bv_val );
+ str = ch_strdup( src );
+ len = strlen( src );
for ( p = str; p && p[ 0 ]; p++ ) {
/* escape */
- if ( p[ 0 ] == '\\' ) {
+ if ( p[ 0 ] == '\\' && p[ 1 ] ) {
/*
* if escaping a hex pair we should
* increment p twice; however, in that
for ( q = &p[ 2 ]; q[ 0 ] == ' '; q++ ) {
/* DO NOTHING */ ;
}
- AC_MEMCPY( p+1, q, pattern->bv_len-(q-str)+1);
+ AC_MEMCPY( p+1, q, len-(q-str)+1);
}
}
}
ID id;
int refcnt, freeit = 1;
- /* set cache mutex */
+ /* set cache write lock */
ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
assert( e->e_private );
* for instance)
*/
if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
bdb_cache_delete_entry_internal( cache, e );
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
freeit = 0;
/* now the entry is in DELETED state */
if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
BEI(e)->bei_state = CACHE_ENTRY_READY;
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
} else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
if( refcnt > 0 ) {
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
bdb_entry_return( e );
}
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
}
} else {
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
"bdb_cache_add_entry_rw: add (%s):%s to cache\n",
e->e_dn, rw ? "w" : "r" ));
#endif
- /* set cache mutex */
+ /* set cache write lock */
ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
assert( e->e_private == NULL );
if( bdb_cache_entry_private_init(e) != 0 ) {
- /* free cache mutex */
- ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
+ /* free cache write lock */
+ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
if ( avl_insert( &cache->c_dntree, (caddr_t) e,
(AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
{
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
bdb_cache_entry_private_destroy(e);
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( -1 );
}
BEI(e)->bei_state = CACHE_ENTRY_CREATING;
BEI(e)->bei_refcnt = 1;
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
/* lru */
LRU_ADD( cache, e );
}
}
- /* free cache mutex */
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( 0 );
}
int i, rc;
Entry *ee;
- /* set cache mutex */
+ /* set cache write lock */
ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
assert( e->e_private );
e->e_id, e->e_dn, 0 );
#endif
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( 1 );
}
#endif
}
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( -1 );
}
/* will be marked after when entry is returned */
BEI(e)->bei_state = CACHE_ENTRY_CREATING;
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
/* lru */
LRU_ADD( cache, e );
}
}
- /* free cache mutex */
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( 0 );
}
e.e_nname = *ndn;
try_again:
- /* set cache mutex */
+ /* set cache read lock */
ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
if ( state != CACHE_ENTRY_READY ) {
assert(state != CACHE_ENTRY_UNDEFINED);
- /* free cache mutex */
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
goto try_again;
}
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
- /* free cache mutex */
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
#ifdef NEW_LOGGING
#endif
} else {
- /* free cache mutex */
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
id = NOID;
e.e_id = id;
try_again:
- /* set cache mutex */
+ /* set cache read lock */
ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
assert(state != CACHE_ENTRY_UNDEFINED);
- /* free cache mutex */
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
* so, unlock the cache, yield, and try again.
*/
- /* free cache mutex */
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
#ifdef NEW_LOGGING
goto try_again;
}
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
/* lru */
LRU_DELETE( cache, ep );
BEI(ep)->bei_refcnt++;
- /* free cache mutex */
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
#ifdef NEW_LOGGING
return( ep );
}
- /* free cache mutex */
+ /* free cache read lock */
ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
return( NULL );
{
int rc;
- /* set cache mutex */
+ /* set cache write lock */
ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
assert( e->e_private );
e->e_id, 0, 0 );
#endif
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
rc = bdb_cache_delete_entry_internal( cache, e );
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
- /* free cache mutex */
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
return( rc );
}
Entry *e;
int rc;
- /* set cache mutex */
+ /* set cache write lock */
ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
+ /* set lru mutex */
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
#ifdef NEW_LOGGING
}
- /* free cache mutex */
+ /* free lru mutex */
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
+ /* free cache write lock */
ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
}
}
}
+#ifdef BDB_HIER
+ ldap_pvt_thread_rdwr_destroy( &bdb->bi_tree_rdwr );
+#endif
+ ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock );
+ ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.lru_mutex );
+ ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex );
+ ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex );
+
return 0;
}
--- /dev/null
+/* suffixmassage.c - massages ldap backend dns */
+/* $OpenLDAP$ */
+
+/*
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * Module back-ldap, originally developed by Howard Chu
+ *
+ * has been modified by Pierangelo Masarati. The original copyright
+ * notice has been maintained.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "portable.h"
+
+#ifndef ENABLE_REWRITE
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-ldap.h"
+
+/*
+ * ldap_back_dn_massage
+ *
+ * Aliases the suffix; based on suffix_alias (servers/slapd/suffixalias.c).
+ */
+void
+ldap_back_dn_massage(
+ struct ldapinfo *li,
+ struct berval *dn,
+ struct berval *res,
+ int normalized,
+ int tofrom
+)
+{
+ int i, src, dst;
+
+ if ( dn == NULL ) {
+ res->bv_val = NULL;
+ res->bv_len = 0;
+ return;
+ }
+ if ( li == NULL || li->suffix_massage == NULL ) {
+ *res = *dn;
+ return;
+ }
+
+ if ( tofrom ) {
+ src = 0 + normalized;
+ dst = 2 + normalized;
+ } else {
+ src = 2 + normalized;
+ dst = 0 + normalized;
+ }
+
+ for ( i = 0;
+ li->suffix_massage[i] != NULL;
+ i += 4 ) {
+ int aliasLength = li->suffix_massage[i+src]->bv_len;
+ int diff = dn->bv_len - aliasLength;
+
+ if ( diff < 0 ) {
+ /* alias is longer than dn */
+ continue;
+ } else if ( diff > 0 ) {
+ if ( normalized && ( ! DN_SEPARATOR(dn->bv_val[diff-1]) ) ) {
+ /* boundary is not at a DN separator */
+ continue;
+ }
+ /* At a DN Separator */
+ /* XXX or an escaped separator... oh well */
+ }
+
+ if ( !strcmp( li->suffix_massage[i+src]->bv_val, &dn->bv_val[diff] ) ) {
+ res->bv_len = diff + li->suffix_massage[i+dst]->bv_len;
+ res->bv_val = ch_malloc( res->bv_len + 1 );
+ strncpy( res->bv_val, dn->bv_val, diff );
+ strcpy( &res->bv_val[diff], li->suffix_massage[i+dst]->bv_val );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "suffixmassage", LDAP_LEVEL_ARGS,
+ "ldap_back_dn_massage: converted \"%s\" to \"%s\"\n",
+ dn->bv_val, res->bv_val ));
+#else
+ Debug( LDAP_DEBUG_ARGS,
+ "ldap_back_dn_massage:"
+ " converted \"%s\" to \"%s\"\n",
+ dn->bv_val, res->bv_val, 0 );
+#endif
+ break;
+ }
+ }
+
+ return;
+}
+#endif /* !ENABLE_REWRITE */
--- /dev/null
+/* unbind.c - ldap backend unbind function */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* This is an altered version */
+/*
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits should appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ *
+ *
+ * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
+ *
+ * This software is being modified by Pierangelo Masarati.
+ * The previously reported conditions apply to the modified code as well.
+ * Changes in the original code are highlighted where required.
+ * Credits for the original code go to the author, Howard Chu.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-ldap.h"
+
+int
+ldap_back_conn_destroy(
+ Backend *be,
+ Connection *conn
+)
+{
+ struct ldapinfo *li = (struct ldapinfo *) be->be_private;
+ struct ldapconn *lc, lc_curr;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+ "ldap_back_conn_destroy: fetching conn %ld\n",
+ conn->c_connid ));
+#else /* !NEW_LOGGING */
+ Debug( LDAP_DEBUG_TRACE,
+ "=>ldap_back_conn_destroy: fetching conn %ld\n",
+ conn->c_connid, 0, 0 );
+#endif /* !NEW_LOGGING */
+
+ lc_curr.conn = conn;
+
+ ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+ lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, ldap_back_conn_cmp );
+ ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+
+ if (lc) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
+ "ldap_back_conn_destroy: destroying conn %ld\n",
+ conn->c_connid ));
+#else /* !NEW_LOGGING */
+ Debug( LDAP_DEBUG_TRACE,
+ "=>ldap_back_conn_destroy: destroying conn %ld\n",
+ lc->conn->c_connid, 0, 0 );
+#endif
+
+#ifdef ENABLE_REWRITE
+ /*
+ * Cleanup rewrite session
+ */
+ rewrite_session_delete( li->rwinfo, conn );
+#endif /* ENABLE_REWRITE */
+
+ /*
+ * Needs a test because the handler may be corrupted,
+ * and calling ldap_unbind on a corrupted header results
+ * in a segmentation fault
+ */
+ ldap_unbind(lc->ld);
+ if ( lc->bound_dn.bv_val ) {
+ ch_free( lc->bound_dn.bv_val );
+ }
+ ch_free( lc );
+ }
+
+ /* no response to unbind */
+
+ return 0;
+}
#else
#ifdef NEW_LOGGING
- LDAP_LOG (( "config",LDAP_LEVEL_ERR, "ldbm_back_db_config: "\"dbsync\""
+ LDAP_LOG (( "config", LDAP_LEVEL_ERR, "ldbm_back_db_config: \"dbsync\""
" policies not supported in non-threaded environments\n" ));
#else
Debug( LDAP_DEBUG_ANY,
strncpy(buf, vals[0].bv_val, i);
s = buf+i;
strcpy(s, pw->pw_name);
- *s = TOUPPER(*s);
+ *s = TOUPPER((unsigned char)*s);
strcat(s, vals[0].bv_val+i+1);
vals[0].bv_val = buf;
}
--- /dev/null
+
+=head1 Introduction
+
+This is a sample Perl module for the OpenLDAP server slapd.
+It also contains the documentation that you will need to
+get up and going.
+
+WARNING: the interfaces of this backen to the perl module
+MAY change. Any suggestions would greatly be appreciated.
+
+
+=head1 Overview
+
+The Perl back end works by embedding a Perl interpreter into
+the slapd backend. Then when the configuration file indicates
+that we are going to be using a Perl backend it will get an
+option that tells it what module to use. It then creates a
+new Perl object that handles all the request for that particular
+instance of the back end.
+
+
+=head1 Interface
+
+You will need to create a method for each one of the
+following actions that you wish to handle.
+
+ * new # Creates a new object.
+ * search # Performs the ldap search
+ * compare # does a compare
+ * modify # modify's and entry
+ * add # adds an entry to back end
+ * modrdn # modifies a an entries rdn
+ * delete # deletes an ldap entry
+ * config # process unknown config file lines
+ * init # called after backend is initialized
+
+=head2 new
+
+This method is called when the config file encounters a
+B<perlmod> line. The module in that line is then effectively
+used into the perl interpreter, then the new method is called
+to create a new object. Note that multiple instances of that
+object may be instantiated, as with any perl object.
+
+The new method doesn't receive any arguments other than the
+class name.
+
+RETURN:
+
+=head2 search
+
+This method is called when a search request comes from a client.
+It arguments are as follow.
+
+ * obj reference
+ * base DN
+ * scope
+ * alias deferencing policy
+ * size limit
+ * time limit
+ * filter string
+ * attributes only flag ( 1 for yes )
+ * list of attributes that are to be returned. (could be empty)
+
+RETURN:
+
+=head2 compare
+
+This method is called when a compare request comes from a client.
+Its arguments are as follows.
+
+ * obj reference
+ * dn
+ * attribute assertion string
+
+RETURN:
+
+=head2 modify
+
+This method is called when a modify request comes from a client.
+Its arguments are as follows.
+
+ * obj reference
+ * dn
+ * lists formatted as follows
+ { ADD | DELETE | REPLACE }, key, value
+
+RETURN:
+
+=head2 add
+
+This method is called when a add request comes from a client.
+Its arguments are as follows.
+
+ * obj reference
+ * entry in string format.
+
+RETURN:
+
+=head2 modrdn
+
+This method is called when a modrdn request comes from a client.
+Its arguments are as follows.
+
+ * obj reference
+ * dn
+ * new rdn
+ * delete old dn flage ( 1 means yes )
+
+RETURN:
+
+=head2 delete
+
+This method is called when a delete request comes from a client.
+Its arguments are as follows.
+
+ * obj reference
+ * dn
+
+RETURN:
+
+=head2 config
+
+ * obj reference
+ * arrray of arguments on line
+
+RETURN: non zero value if this is not a valid option.
+
+=head2 init
+
+ * obj reference
+
+RETURN: non zero value if initialization failed.
+
+=head1 Configuration
+
+The perl section of the config file recognizes the following
+options. It should also be noted that any option not recoginized
+will be sent to the B<config> method of the perl module as noted
+above.
+
+ database perl # startn section for the perl database
+
+ suffix "o=AnyOrg, c=US"
+
+ perlModulePath /path/to/libs # addes the path to @INC variable same
+ # as "use lib '/path/to/libs'"
+
+ perlModule ModName # use the module name ModName from ModName.pm
+
+ filterSearchResults # search results are candidates that need to be
+ # filtered, rather than search results to be
+ # returned directly to the client
+
+=cut
+
+package SampleLDAP;
+
+use POSIX;
+
+sub new
+{
+ my $class = shift;
+
+ my $this = {};
+ bless $this, $class;
+ print STDERR "Here in new\n";
+ print STDERR "Posix Var " . BUFSIZ . " and " . FILENAME_MAX . "\n";
+ return $this;
+}
+
+sub search
+{
+ my $this = shift;
+ my($base, $scope, $deref, $sizeLim, $timeLim, $filterStr, $attrOnly, @attrs ) = @_;
+ print STDERR "====$filterStr====\n";
+ $filterStr =~ s/\(|\)//g;
+ $filterStr =~ s/=/: /;
+
+ my @match_dn = ();
+ foreach my $dn ( keys %$this ) {
+ if ( $this->{ $dn } =~ /$filterStr/im ) {
+ push @match_dn, $dn;
+ last if ( scalar @match_dn == $sizeLim );
+
+ }
+ }
+
+ my @match_entries = ();
+
+ foreach my $dn ( @match_dn ) {
+ push @match_entries, $this->{ $dn };
+ }
+
+ return ( 0 , @match_entries );
+
+}
+
+sub compare
+{
+ my $this = shift;
+ my ( $dn, $avaStr ) = @_;
+ my $rc = 5; # LDAP_COMPARE_FALSE
+
+ $avaStr =~ s/=/: /;
+
+ if ( $this->{ $dn } =~ /$avaStr/im ) {
+ $rc = 6; # LDAP_COMPARE_TRUE
+ }
+
+ return $rc;
+}
+
+sub modify
+{
+ my $this = shift;
+
+ my ( $dn, @list ) = @_;
+
+ while ( @list > 0 ) {
+ my $action = shift @list;
+ my $key = shift @list;
+ my $value = shift @list;
+
+ if( $action eq "ADD" ) {
+ $this->{ $dn } .= "$key: $value\n";
+
+ }
+ elsif( $action eq "DELETE" ) {
+ $this->{ $dn } =~ s/^$key:\s*$value\n//mi ;
+
+ }
+ elsif( $action eq "REPLACE" ) {
+ $this->{ $dn } =~ s/$key: .*$/$key: $value/im ;
+ }
+ }
+
+ return 0;
+}
+
+sub add
+{
+ my $this = shift;
+
+ my ( $entryStr ) = @_;
+
+ my ( $dn ) = ( $entryStr =~ /dn:\s(.*)$/m );
+
+ #
+ # This needs to be here untill a normalize dn is
+ # passed to this routine.
+ #
+ $dn = uc( $dn );
+ $dn =~ s/\s*//g;
+
+
+ $this->{$dn} = $entryStr;
+
+ return 0;
+}
+
+sub modrdn
+{
+ my $this = shift;
+
+ my ( $dn, $newdn, $delFlag ) = @_;
+
+ $this->{ $newdn } = $this->{ $dn };
+
+ if( $delFlag ) {
+ delete $this->{ $dn };
+ }
+ return 0;
+
+}
+
+sub delete
+{
+ my $this = shift;
+
+ my ( $dn ) = @_;
+
+ print STDERR "XXXXXX $dn XXXXXXX\n";
+ delete $this->{$dn};
+}
+
+sub config
+{
+ my $this = shift;
+
+ my ( @args ) = @_;
+ local $, = " - ";
+ print STDERR @args;
+ print STDERR "\n";
+ return 0;
+}
+
+1;
+
+
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+int
+perl_back_add(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e
+)
+{
+ int len;
+ int count;
+ int return_code;
+
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+ ldap_pvt_thread_mutex_lock( &entry2str_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( entry2str( e, &len ), 0 )));
+
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("add", G_SCALAR);
+#else
+ count = perl_call_method("add", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in back_add\n");
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ Debug( LDAP_DEBUG_ANY, "Perl ADD\n", 0, 0, 0 );
+ return( 0 );
+}
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+/* init.c - initialize Perl backend */
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <XSUB.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+
+/**********************************************************
+ *
+ * Bind
+ *
+ **********************************************************/
+int
+perl_back_bind(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *dn,
+ struct berval *ndn,
+ int method,
+ struct berval *cred,
+ struct berval *edn
+)
+{
+ int return_code;
+ int count;
+
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+
+#ifdef HAVE_WIN32_ASPERL
+ PERL_SET_CONTEXT( PERL_INTERPRETER );
+#endif
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( dn->bv_val , 0)));
+ XPUSHs(sv_2mortal(newSVpv( cred->bv_val , cred->bv_len)));
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("bind", G_SCALAR);
+#else
+ count = perl_call_method("bind", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in back_bind\n");
+ }
+
+ return_code = POPi;
+
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ Debug( LDAP_DEBUG_ANY, "Perl BIND returned 0x%04x\n", return_code, 0, 0 );
+
+ send_ldap_result( conn, op, return_code, NULL, NULL, NULL, NULL );
+
+ return ( return_code );
+}
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+/* init.c - initialize shell backend */
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+/**********************************************************
+ *
+ * Close
+ *
+ **********************************************************/
+
+int
+perl_back_close(
+ BackendInfo *bd
+)
+{
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ perl_destruct(PERL_INTERPRETER);
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ return 0;
+}
+
+int
+perl_back_destroy(
+ BackendInfo *bd
+)
+{
+ perl_free(PERL_INTERPRETER);
+ PERL_INTERPRETER = NULL;
+
+ ldap_pvt_thread_mutex_destroy( &perl_interpreter_mutex );
+
+ return 0;
+}
+
+int
+perl_back_db_destroy(
+ BackendDB *be
+)
+{
+ free( be->be_private );
+ be->be_private = NULL;
+
+ return 0;
+}
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+/**********************************************************
+ *
+ * Compare
+ *
+ **********************************************************/
+
+int
+perl_back_compare(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *dn,
+ struct berval *ndn,
+ AttributeAssertion *ava
+)
+{
+ int return_code;
+ int count;
+ char *avastr, *ptr;
+
+ PerlBackend *perl_back = (PerlBackend *)be->be_private;
+
+ avastr = ch_malloc( ava->aa_desc->ad_cname.bv_len + 1 +
+ ava->aa_value.bv_len + 1 );
+
+ slap_strcopy( slap_strcopy( slap_strcopy( avastr,
+ ava->aa_desc->ad_cname.bv_val ), "=" ),
+ ava->aa_value.bv_val );
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( dn->bv_val , 0)));
+ XPUSHs(sv_2mortal(newSVpv( avastr , 0)));
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("compare", G_SCALAR);
+#else
+ count = perl_call_method("compare", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in back_compare\n");
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ ch_free( avastr );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ Debug( LDAP_DEBUG_ANY, "Perl COMPARE\n", 0, 0, 0 );
+
+ return (0);
+}
+
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+
+/**********************************************************
+ *
+ * Config
+ *
+ **********************************************************/
+int
+perl_back_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ SV* loc_sv;
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+ char eval_str[EVAL_BUF_SIZE];
+ int count ;
+ int args;
+ int return_code;
+
+
+ if ( strcasecmp( argv[0], "perlModule" ) == 0 ) {
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s.pm: line %d: missing module in \"perlModule <module>\" line\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+#ifdef PERL_IS_5_6
+ snprintf( eval_str, EVAL_BUF_SIZE, "use %s;", argv[1] );
+ eval_pv( eval_str, 0 );
+
+ if (SvTRUE(ERRSV)) {
+ STRLEN n_a;
+
+ fprintf(stderr , "Error %s\n", SvPV(ERRSV, n_a)) ;
+ }
+#else
+ snprintf( eval_str, EVAL_BUF_SIZE, "%s.pm", argv[1] );
+ perl_require_pv( eval_str );
+
+ if (SvTRUE(GvSV(errgv))) {
+ fprintf(stderr , "Error %s\n", SvPV(GvSV(errgv), na)) ;
+ }
+#endif /* PERL_IS_5_6 */
+ else {
+ dSP; ENTER; SAVETMPS;
+ PUSHMARK(sp);
+ XPUSHs(sv_2mortal(newSVpv(argv[1], 0)));
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("new", G_SCALAR);
+#else
+ count = perl_call_method("new", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in config\n") ;
+ }
+
+ perl_back->pb_obj_ref = newSVsv(POPs);
+
+ PUTBACK; FREETMPS; LEAVE ;
+ }
+
+ } else if ( strcasecmp( argv[0], "perlModulePath" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing module in \"PerlModulePath <module>\" line\n",
+ fname, lineno );
+ return( 1 );
+ }
+
+ snprintf( eval_str, EVAL_BUF_SIZE, "push @INC, '%s';", argv[1] );
+#ifdef PERL_IS_5_6
+ loc_sv = eval_pv( eval_str, 0 );
+#else
+ loc_sv = perl_eval_pv( eval_str, 0 );
+#endif
+
+ /* XXX loc_sv return value is ignored. */
+
+ } else if ( strcasecmp( argv[0], "filterSearchResults" ) == 0 ) {
+ perl_back->pb_filter_search_results = 1;
+ } else {
+ /*
+ * Pass it to Perl module if defined
+ */
+
+ {
+ dSP ; ENTER ; SAVETMPS;
+
+ PUSHMARK(sp) ;
+ XPUSHs( perl_back->pb_obj_ref );
+
+ /* Put all arguments on the perl stack */
+ for( args = 0; args < argc; args++ ) {
+ XPUSHs(sv_2mortal(newSVpv(argv[args], 0)));
+ }
+
+ PUTBACK ;
+
+#ifdef PERL_IS_5_6
+ count = call_method("config", G_SCALAR);
+#else
+ count = perl_call_method("config", G_SCALAR);
+#endif
+
+ SPAGAIN ;
+
+ if (count != 1) {
+ croak("Big trouble in config\n") ;
+ }
+
+ return_code = POPi;
+
+ PUTBACK ; FREETMPS ; LEAVE ;
+
+ }
+
+ /* if the module rejected it then we should reject it */
+ if ( return_code != 0 ) {
+ fprintf( stderr,
+ "Unknown perl backend config: %s\n", argv[0]);
+ exit( EXIT_FAILURE );
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+int
+perl_back_delete(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *dn,
+ struct berval *ndn
+)
+{
+ int len;
+ int count;
+ int return_code;
+
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( dn->bv_val , 0 )));
+
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("delete", G_SCALAR);
+#else
+ count = perl_call_method("delete", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in perl-back_delete\n");
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ Debug( LDAP_DEBUG_ANY, "Perl DELETE\n", 0, 0, 0 );
+ return( 0 );
+}
--- /dev/null
+/* $OpenLDAP$ */
+#ifndef _PERL_EXTERNAL_H
+#define _PERL_EXTERNAL_H
+
+LDAP_BEGIN_DECL
+
+extern BI_init perl_back_initialize;
+extern BI_open perl_back_open;
+extern BI_close perl_back_close;
+extern BI_destroy perl_back_destroy;
+
+extern BI_db_init perl_back_db_init;
+extern BI_db_open perl_back_db_open;
+extern BI_db_destroy perl_back_db_destroy;
+
+extern BI_db_config perl_back_db_config;
+
+extern BI_op_bind perl_back_bind;
+
+extern BI_op_search perl_back_search;
+
+extern BI_op_compare perl_back_compare;
+
+extern BI_op_modify perl_back_modify;
+
+extern BI_op_modrdn perl_back_modrdn;
+
+extern BI_op_add perl_back_add;
+
+extern BI_op_delete perl_back_delete;
+
+LDAP_END_DECL
+
+#endif /* _PERL_EXTERNAL_H */
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+ /* init.c - initialize shell backend */
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <XSUB.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+
+static void perl_back_xs_init LDAP_P((PERL_BACK_XS_INIT_PARAMS));
+EXT void boot_DynaLoader LDAP_P((PERL_BACK_BOOT_DYNALOADER_PARAMS));
+
+PerlInterpreter *PERL_INTERPRETER = NULL;
+ldap_pvt_thread_mutex_t perl_interpreter_mutex;
+
+#ifdef SLAPD_PERL_DYNAMIC
+
+int back_perl_LTX_init_module(int argc, char *argv[])
+{
+ BackendInfo bi;
+
+ memset( &bi, '\0', sizeof(bi) );
+ bi.bi_type = "perl";
+ bi.bi_init = perl_back_initialize;
+
+ backend_add(&bi);
+ return 0;
+}
+
+#endif /* SLAPD_PERL_DYNAMIC */
+
+
+/**********************************************************
+ *
+ * Init
+ *
+ **********************************************************/
+
+int
+perl_back_initialize(
+ BackendInfo *bi
+)
+{
+ char *embedding[] = { "", "-e", "0" };
+
+ Debug( LDAP_DEBUG_TRACE, "perl backend open\n", 0, 0, 0 );
+
+ if( PERL_INTERPRETER != NULL ) {
+ Debug( LDAP_DEBUG_ANY, "perl backend open: already opened\n",
+ 0, 0, 0 );
+ return 1;
+ }
+
+ PERL_INTERPRETER = perl_alloc();
+ perl_construct(PERL_INTERPRETER);
+ perl_parse(PERL_INTERPRETER, perl_back_xs_init, 3, embedding, (char **)NULL);
+ perl_run(PERL_INTERPRETER);
+
+ bi->bi_open = perl_back_open;
+ bi->bi_config = 0;
+ bi->bi_close = perl_back_close;
+ bi->bi_destroy = perl_back_destroy;
+
+ bi->bi_db_init = perl_back_db_init;
+ bi->bi_db_config = perl_back_db_config;
+ bi->bi_db_open = perl_back_db_open;
+ bi->bi_db_close = 0;
+ bi->bi_db_destroy = perl_back_db_destroy;
+
+ bi->bi_op_bind = perl_back_bind;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = perl_back_search;
+ bi->bi_op_compare = perl_back_compare;
+ bi->bi_op_modify = perl_back_modify;
+ bi->bi_op_modrdn = perl_back_modrdn;
+ bi->bi_op_add = perl_back_add;
+ bi->bi_op_delete = perl_back_delete;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_acl_group = 0;
+ bi->bi_acl_attribute = 0;
+ bi->bi_chk_referrals = 0;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = 0;
+
+ return 0;
+}
+
+int
+perl_back_open(
+ BackendInfo *bi
+)
+{
+ ldap_pvt_thread_mutex_init( &perl_interpreter_mutex );
+ return 0;
+}
+
+int
+perl_back_db_init(
+ BackendDB *be
+)
+{
+ be->be_private = (PerlBackend *) ch_malloc( sizeof(PerlBackend) );
+ memset( be->be_private, '\0', sizeof(PerlBackend));
+
+ ((PerlBackend *)be->be_private)->pb_filter_search_results = 0;
+
+ Debug( LDAP_DEBUG_TRACE, "perl backend db init\n", 0, 0, 0 );
+
+ return 0;
+}
+
+int
+perl_back_db_open(
+ BackendDB *be
+)
+{
+ int count;
+ int return_code;
+
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs( perl_back->pb_obj_ref );
+
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("init", G_SCALAR);
+#else
+ count = perl_call_method("init", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in perl_back_db_open\n");
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ return return_code;
+}
+
+
+static void
+perl_back_xs_init()
+{
+ char *file = __FILE__;
+ dXSUB_SYS;
+ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+}
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+int
+perl_back_modify(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *dn,
+ struct berval *ndn,
+ Modifications *modlist
+)
+{
+ char test[500];
+ int return_code;
+ int count;
+ int i;
+ int err = 0;
+ char *matched = NULL, *info = NULL;
+
+ PerlBackend *perl_back = (PerlBackend *)be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( dn->bv_val , 0)));
+
+ for (; modlist != NULL; modlist = modlist->sml_next ) {
+ Modification *mods = &modlist->sml_mod;
+
+ switch ( mods->sm_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ XPUSHs(sv_2mortal(newSVpv("ADD", 0 )));
+ break;
+
+ case LDAP_MOD_DELETE:
+ XPUSHs(sv_2mortal(newSVpv("DELETE", 0 )));
+ break;
+
+ case LDAP_MOD_REPLACE:
+ XPUSHs(sv_2mortal(newSVpv("REPLACE", 0 )));
+ break;
+ }
+
+
+ XPUSHs(sv_2mortal(newSVpv( mods->sm_type.bv_val, 0 )));
+
+ for ( i = 0;
+ mods->sm_bvalues != NULL && mods->sm_bvalues[i].bv_val != NULL;
+ i++ )
+ {
+ XPUSHs(sv_2mortal(newSVpv( mods->sm_bvalues[i].bv_val, 0 )));
+ }
+ }
+
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("modify", G_SCALAR);
+#else
+ count = perl_call_method("modify", G_SCALAR);
+#endif
+
+ SPAGAIN;
+
+ if (count != 1) {
+ croak("Big trouble in back_modify\n");
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ Debug( LDAP_DEBUG_ANY, "Perl MODIFY\n", 0, 0, 0 );
+ return( 0 );
+}
+
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+/*
+ * LDAP v3 newSuperior support.
+ *
+ * Copyright 1999, Juan C. Gomez, All rights reserved.
+ * This software is not subject to any license of Silicon Graphics
+ * Inc. or Purdue University.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * without restriction or fee of any kind as long as this notice
+ * is preserved.
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+int
+perl_back_modrdn(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *dn,
+ struct berval *ndn,
+ struct berval *newrdn,
+ struct berval *nnewrdn,
+ int deleteoldrdn,
+ struct berval *newSuperior,
+ struct berval *nnewSuperior
+)
+{
+ int len;
+ int count;
+ int return_code;
+
+ PerlBackend *perl_back = (PerlBackend *) be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp) ;
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( dn->bv_val , 0 )));
+ XPUSHs(sv_2mortal(newSVpv( newrdn->bv_val , 0 )));
+ XPUSHs(sv_2mortal(newSViv( deleteoldrdn )));
+ if ( newSuperior != NULL ) {
+ XPUSHs(sv_2mortal(newSVpv( newSuperior->bv_val , 0 )));
+ }
+ PUTBACK ;
+
+#ifdef PERL_IS_5_6
+ count = call_method("modrdn", G_SCALAR);
+#else
+ count = perl_call_method("modrdn", G_SCALAR);
+#endif
+
+ SPAGAIN ;
+
+ if (count != 1) {
+ croak("Big trouble in back_modrdn\n") ;
+ }
+
+ return_code = POPi;
+
+ PUTBACK; FREETMPS; LEAVE ;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ Debug( LDAP_DEBUG_ANY, "Perl MODRDN\n", 0, 0, 0 );
+ return( 0 );
+}
--- /dev/null
+/* $OpenLDAP$ */
+#ifndef PERL_BACK_H
+#define PERL_BACK_H 1
+
+LDAP_BEGIN_DECL
+
+/*
+ * From Apache mod_perl: test for Perl version.[ja
+ */
+#ifdef pTHX_
+#define PERL_IS_5_6
+#endif
+
+#define EVAL_BUF_SIZE 500
+
+#ifdef pTHX_
+#define PERL_IS_5_6
+#endif
+
+extern ldap_pvt_thread_mutex_t perl_interpreter_mutex;
+
+#ifdef HAVE_WIN32_ASPERL
+/* We should be using the PL_errgv, I think */
+/* All the old style variables are prefixed with PL_ now */
+# define errgv PL_errgv
+# define na PL_na
+#endif
+
+#ifdef HAVE_WIN32_ASPERL
+/* pTHX is needed often now */
+# define PERL_INTERPRETER my_perl
+# define PERL_BACK_XS_INIT_PARAMS pTHX
+# define PERL_BACK_BOOT_DYNALOADER_PARAMS pTHX, CV *cv
+#else
+# define PERL_INTERPRETER perl_interpreter
+# define PERL_BACK_XS_INIT_PARAMS void
+# define PERL_BACK_BOOT_DYNALOADER_PARAMS CV *cv
+#endif
+
+extern PerlInterpreter *PERL_INTERPRETER;
+
+
+typedef struct perl_backend_instance {
+ char *pb_module_name;
+ SV *pb_obj_ref;
+ int pb_filter_search_results;
+} PerlBackend;
+
+LDAP_END_DECL
+
+#include "external.h"
+
+#endif
--- /dev/null
+/* $OpenLDAP$ */
+/*
+ * Copyright 1999, John C. Quillan, All rights reserved.
+ * Portions Copyright 2002, myinternet Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#ifdef HAVE_WIN32_ASPERL
+#include "asperl_undefs.h"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+
+#include "perl_back.h"
+
+/**********************************************************
+ *
+ * Search
+ *
+ **********************************************************/
+int
+perl_back_search(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ struct berval *base,
+ struct berval *nbase,
+ int scope,
+ int deref,
+ int sizelimit,
+ int timelimit,
+ Filter *filter,
+ struct berval *filterstr,
+ AttributeName *attrs,
+ int attrsonly
+ )
+{
+ char test[500];
+ int count ;
+ int err = 0;
+ char *matched = NULL, *info = NULL;
+ PerlBackend *perl_back = (PerlBackend *)be->be_private;
+ AttributeName *an;
+ Entry *e;
+ char *buf;
+ int i;
+ int return_code;
+
+ ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex );
+
+ {
+ dSP; ENTER; SAVETMPS;
+
+ PUSHMARK(sp) ;
+ XPUSHs( perl_back->pb_obj_ref );
+ XPUSHs(sv_2mortal(newSVpv( nbase->bv_val , 0)));
+ XPUSHs(sv_2mortal(newSViv( scope )));
+ XPUSHs(sv_2mortal(newSViv( deref )));
+ XPUSHs(sv_2mortal(newSViv( sizelimit )));
+ XPUSHs(sv_2mortal(newSViv( timelimit )));
+ XPUSHs(sv_2mortal(newSVpv( filterstr->bv_val , 0)));
+ XPUSHs(sv_2mortal(newSViv( attrsonly )));
+
+ for ( an = attrs; an && an->an_name.bv_val; an++ ) {
+ XPUSHs(sv_2mortal(newSVpv( an->an_name.bv_val , 0)));
+ }
+ PUTBACK;
+
+#ifdef PERL_IS_5_6
+ count = call_method("search", G_ARRAY );
+#else
+ count = perl_call_method("search", G_ARRAY );
+#endif
+
+ SPAGAIN;
+
+ if (count < 1) {
+ croak("Big trouble in back_search\n") ;
+ }
+
+ if ( count > 1 ) {
+
+ for ( i = 1; i < count; i++ ) {
+
+ buf = POPp;
+
+ if ( (e = str2entry( buf )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "str2entry(%s) failed\n", buf, 0, 0 );
+
+ } else {
+ int send_entry;
+
+ if (perl_back->pb_filter_search_results)
+ send_entry = (test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE);
+ else
+ send_entry = 1;
+
+ if (send_entry) {
+ send_search_entry( be, conn, op,
+ e, attrs, attrsonly, NULL );
+ }
+
+ entry_free( e );
+ }
+ }
+ }
+
+ /*
+ * We grab the return code last because the stack comes
+ * from perl in reverse order.
+ *
+ * ex perl: return ( 0, $res_1, $res_2 );
+ *
+ * ex stack: <$res_2> <$res_1> <0>
+ */
+
+ return_code = POPi;
+
+
+
+ PUTBACK; FREETMPS; LEAVE;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex );
+
+ send_ldap_result( conn, op, return_code,
+ NULL, NULL, NULL, NULL );
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License. A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_SQL
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdarg.h>
+#include "slap.h"
+#include "back-sql.h"
+#include "schema-map.h"
+#include "util.h"
+
+
+char backsql_def_oc_query[]="SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return FROM ldap_oc_mappings";
+char backsql_def_at_query[]="SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return,sel_expr_u FROM ldap_attr_mappings WHERE oc_map_id=?";
+char backsql_def_delentry_query[]="DELETE FROM ldap_entries WHERE id=?";
+char backsql_def_insentry_query[]="INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) VALUES (?,?,?,?)";
+char backsql_def_subtree_cond[]="ldap_entries.dn LIKE CONCAT('%',?)";
+char backsql_id_query[]="SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
+
+/* TimesTen*/
+char backsql_check_dn_ru_query[] = "SELECT dn_ru from ldap_entries";
+
+char* backsql_strcat(char* dest,int *buflen, ...)
+{
+ va_list strs;
+ int cdlen,cslen,grow;
+ char *cstr;
+
+ /*Debug(LDAP_DEBUG_TRACE,"==>my_strcat()\n");*/
+ va_start(strs,buflen);
+ if (dest==NULL || *buflen<=0)
+ {
+ dest=(char*)ch_calloc(BACKSQL_STR_GROW,sizeof(char));
+ *buflen=BACKSQL_STR_GROW;
+ }
+ cdlen=strlen(dest)+1;
+ while ((cstr=va_arg(strs,char*)) != NULL)
+ {
+ cslen=strlen(cstr);
+ grow=BACKSQL_MAX(BACKSQL_STR_GROW,cslen);
+ if (*buflen-cdlen < cslen)
+ {
+ /*Debug(LDAP_DEBUG_TRACE,"my_strcat(): buflen=%d, cdlen=%d, cslen=%d -- reallocating dest\n",
+ *buflen,cdlen,cslen); */
+ dest=(char*)ch_realloc(dest,(*buflen)+grow*sizeof(char));
+ if (dest == NULL)
+ {
+ Debug(LDAP_DEBUG_ANY,"my_strcat(): could not reallocate string buffer.\n",0,0,0);
+ }
+ *buflen+=grow;
+ /*Debug(LDAP_DEBUG_TRACE,"my_strcat(): new buflen=%d, dest=%p\n",*buflen,dest,0);*/
+ }
+ strcat(dest,cstr);
+ cdlen+=cslen;
+ }
+ va_end(strs);
+ /*Debug(LDAP_DEBUG_TRACE,"<==my_strcat() (dest='%s')\n",dest,0,0);*/
+ return dest;
+}
+
+int backsql_entry_addattr(Entry *e,char *at_name,char *at_val,unsigned int at_val_len)
+{
+ Attribute *c_at=e->e_attrs;
+ struct berval* add_val[2];
+ struct berval cval;
+ AttributeDescription *ad;
+ int rc;
+ const char *text;
+
+ Debug(LDAP_DEBUG_TRACE,"backsql_entry_addattr(): at_name='%s', at_val='%s'\n",at_name,at_val,0);
+ cval.bv_val=at_val;
+ cval.bv_len=at_val_len;
+ add_val[0]=&cval;
+ add_val[1]=NULL;
+
+ ad=NULL;
+ rc = slap_str2ad( at_name, &ad, &text );
+ if( rc != LDAP_SUCCESS )
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_entry_addattr(): failed to find AttributeDescription for '%s'\n",at_name,0,0);
+ return 0;
+ }
+
+ rc = attr_merge(e,ad,add_val);
+
+ if( rc != 0 )
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_entry_addattr(): failed to merge value '%s' for attribute '%s'\n",at_val,at_name,0);
+ return 0;
+ }
+
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_query_addattr()\n",0,0,0);
+ return 1;
+}
+
+char* backsql_get_table_spec(char **p)
+{
+ char *s,*q;
+ char *res=NULL;
+ int res_len=0;
+
+ s=*p;
+ while(**p && **p!=',') (*p)++;
+ if (**p)
+ *(*p)++='\0';
+
+#define BACKSQL_NEXT_WORD { \
+ while (*s && isspace((unsigned char)*s)) s++; \
+ if (!*s) return res; \
+ q=s; \
+ while (*q && !isspace((unsigned char)*q)) q++; \
+ if (*q) *q++='\0'; \
+ }
+
+ BACKSQL_NEXT_WORD;
+ res=backsql_strcat(res,&res_len,s,NULL);/*table name*/
+ s=q;
+
+ BACKSQL_NEXT_WORD;
+ if (!strcasecmp(s,"as"))
+ {
+ s=q;
+ BACKSQL_NEXT_WORD;
+ }
+ /*res=backsql_strcat(res,&res_len," AS ",s,NULL);
+ *oracle doesn't understand AS :(
+ */
+ res=backsql_strcat(res,&res_len," ",s,NULL);/*table alias*/
+ return res;
+}
+
+int backsql_merge_from_clause(char **dest_from,int *dest_len,char *src_from)
+{
+ char *s,*p,*srcc,*pos,e;
+
+ /*Debug(LDAP_DEBUG_TRACE,"==>backsql_merge_from_clause(): dest_from='%s',src_from='%s'\n",
+ dest_from,src_from,0); */
+ srcc=ch_strdup(src_from);
+ p=srcc;
+ while(*p)
+ {
+ s=backsql_get_table_spec(&p);
+ /* Debug(LDAP_DEBUG_TRACE,"backsql_merge_from_clause(): p='%s' s='%s'\n",p,s,0); */
+ if (*dest_from==NULL)
+ *dest_from=backsql_strcat(*dest_from,dest_len,s,NULL);
+ else
+ if((pos=strstr(*dest_from,s))==NULL)
+ *dest_from=backsql_strcat(*dest_from,dest_len,",",s,NULL);
+ else if((e=pos[strlen(s)])!='\0' && e!=',')
+ *dest_from=backsql_strcat(*dest_from,dest_len,",",s,NULL);
+ if (s)
+ ch_free(s);
+ }
+/* Debug(LDAP_DEBUG_TRACE,"<==backsql_merge_from_clause()\n",0,0,0);*/
+ free(srcc);
+ return 1;
+}
+
+#endif /* SLAPD_SQL */
if ( rc )
return rc;
} else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) {
- if ( isdigit( cargv[1][0] ) ) {
+ if ( isdigit( (unsigned char) cargv[1][0] ) ) {
i = atoi(cargv[1]);
rc = ldap_pvt_tls_set_option( NULL,
LDAP_OPT_X_TLS_REQUIRE_CERT,
/* compare */
return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
}
+
+/*
+ * Convert a DN from X.500 format into a normalized DN
+ */
+int
+dnDCEnormalize( char *dce, struct berval *out )
+{
+ int rc;
+ LDAPDN *dn = NULL;
+
+ out->bv_val = NULL;
+ out->bv_len = 0;
+
+ rc = ldap_str2dn( dce, &dn, LDAP_DN_FORMAT_DCE );
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+
+ /*
+ * Schema-aware rewrite
+ */
+ if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /*
+ * Back to string representation
+ */
+ rc = ldap_dn2bv( dn, out, LDAP_DN_FORMAT_LDAPV3 );
+
+ ldap_dnfree( dn );
+
+ if ( rc != LDAP_SUCCESS ) {
+ rc = LDAP_INVALID_SYNTAX;
+ }
+ return rc;
+}
#endif /* LOG_LOCAL4 */
+static int check_config = 0;
static void
usage( char *name )
fprintf( stderr,
"usage: %s options\n", name );
fprintf( stderr,
- "\t-d level\tDebug Level" "\n"
- "\t-f filename\tConfiguration File\n"
+ "\t-d level\tDebug level" "\n"
+ "\t-f filename\tConfiguration file\n"
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
"\t-g group\tGroup (id or name) to run as\n"
#endif
- "\t-h URLs\tList of URLs to serve\n"
+ "\t-h URLs\t\tList of URLs to serve\n"
#ifdef LOG_LOCAL4
- "\t-l sysloguser\tSyslog User (default: LOCAL4)\n"
+ "\t-l facility\tSyslog facility (default: LOCAL4)\n"
#endif
- "\t-n serverName\tservice name\n"
+ "\t-n serverName\tService name\n"
#ifdef HAVE_CHROOT
- "\t-r directory\n"
+ "\t-r directory\tSandbox directory to chroot to\n"
#endif
- "\t-s level\tSyslog Level\n"
+ "\t-s level\tSyslog level\n"
+ "\t-t\t\tCheck configuration file and exit\n"
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
- "\t-u user\tUser (id or name) to run as\n"
+ "\t-u user\t\tUser (id or name) to run as\n"
#endif
);
}
#endif
while ( (i = getopt( argc, argv,
- "d:f:h:s:n:"
+ "d:f:h:s:n:t"
#ifdef HAVE_CHROOT
"r:"
#endif
serverName = ch_strdup( optarg );
break;
+ case 't':
+ check_config++;
+ break;
+
default:
usage( argv[0] );
rc = 1;
openlog( serverName, OPENLOG_OPTIONS );
#endif
- if( slapd_daemon_init( urls ) != 0 ) {
+ if( !check_config && slapd_daemon_init( urls ) != 0 ) {
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
goto stop;
if ( read_config( configfile ) != 0 ) {
rc = 1;
SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
+
+ if ( check_config ) {
+ fprintf( stderr, "config check failed\n" );
+ }
+
+ goto destroy;
+ }
+
+ if ( check_config ) {
+ rc = 0;
+ fprintf( stderr, "config check succeeded\n" );
goto destroy;
}
LDAP_SLAPD_F (void) dnParent LDAP_P(( struct berval *dn, struct berval *pdn ));
+LDAP_SLAPD_F (int) dnDCEnormalize LDAP_P(( char *dce, struct berval *out ));
+
/*
* entry.c
*/
/* trim the label */
for( k=0; k<jv->bv_len; k++ ) {
- if( isspace(jv->bv_val[k]) ) {
+ if( isspace( (unsigned char) jv->bv_val[k] ) ) {
jv->bv_val[k] = '\0';
jv->bv_len = k;
break;
err, matched, text, refs,
NULL, NULL, NULL, ctrls );
+ {
+ char nbuf[64];
+ sprintf( nbuf, "%ld nentries=%d", (long) err, nentries );
+
Statslog( LDAP_DEBUG_STATS,
- "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
+ "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%s text=%s\n",
(long) op->o_connid, (long) op->o_opid,
- (unsigned long) tag, (long) err, text ? text : "" );
+ (unsigned long) tag, nbuf, text ? text : "" );
+ }
if (tmp != NULL) {
ch_free(tmp);
#endif
/* Flags for telling slap_sasl_getdn() what type of identity is being passed */
-#define FLAG_GETDN_FINAL 1
#define FLAG_GETDN_AUTHCID 2
#define FLAG_GETDN_AUTHZID 4
string returned in *dn is in its own allocated memory, and must be free'd
by the calling process.
-Mark Adamson, Carnegie Mellon
+
+ The "dn:" prefix is no longer used anywhere inside slapd. It is only used
+ on strings passed in directly from SASL.
+ -Howard Chu, Symas Corp.
*/
#define SET_DN 1
static struct berval ext_bv = { sizeof("EXTERNAL")-1, "EXTERNAL" };
-int slap_sasl_getdn( Connection *conn, char *id,
+int slap_sasl_getdn( Connection *conn, char *id, int len,
char *user_realm, struct berval *dn, int flags )
{
char *c1;
- int rc, len, is_dn = 0;
+ int rc, is_dn = 0, do_norm = 1;
sasl_conn_t *ctx;
struct berval dn2;
return( LDAP_SUCCESS );
}
ctx = conn->c_sasl_context;
- len = strlen( id );
+ if ( len == 0 ) len = strlen( id );
/* An authcID needs to be converted to authzID form */
if( flags & FLAG_GETDN_AUTHCID ) {
&& id[0] == '/' )
{
/* check SASL external for X.509 style DN and */
- /* convert to dn:<dn> form */
- dn->bv_val = ldap_dcedn2dn( id );
- dn->bv_len = strlen(dn->bv_val);
+ /* convert to dn:<dn> form, result is normalized */
+ dnDCEnormalize( id, dn );
+ do_norm = 0;
is_dn = SET_DN;
} else {
}
/* DN strings that are a cn=auth identity to run through regexp */
- if( is_dn == SET_DN && ( ( flags & FLAG_GETDN_FINAL ) == 0 ) )
+ if( is_dn == SET_DN )
{
slap_sasl2dn( dn, &dn2 );
if( dn2.bv_val ) {
ch_free( dn->bv_val );
*dn = dn2;
+ do_norm = 0; /* slap_sasl2dn normalizes */
#ifdef NEW_LOGGING
LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
"slap_sasl_getdn: dn:id converted to %s.\n", dn->bv_val ));
}
}
- if( flags & FLAG_GETDN_FINAL ) {
- /* omit "dn:" prefix */
- is_dn = 0;
- } else {
+ if ( do_norm ) {
rc = dnNormalize2( NULL, dn, &dn2 );
free(dn->bv_val);
if ( rc != LDAP_SUCCESS ) {
*dn = dn2;
}
- /* Attach the "dn:" prefix if needed */
- if ( is_dn == SET_DN ) {
- c1 = ch_malloc( dn->bv_len + sizeof("dn:") );
- strcpy( c1, "dn:" );
- strcpy( c1 + 3, dn->bv_val );
- free( dn->bv_val );
- dn->bv_val = c1;
- dn->bv_len += 3;
- }
-
return( LDAP_SUCCESS );
}
cred.bv_val = (char *)pass;
cred.bv_len = passlen;
- /* XXX do we need to check sasldb as well? */
+ /* SASL will fallback to its own mechanisms if we don't
+ * find an answer here.
+ */
- /* XXX can we do both steps at once? */
- rc = slap_sasl_getdn( conn, (char *)username, NULL, &dn,
- FLAG_GETDN_AUTHCID | FLAG_GETDN_FINAL );
+ rc = slap_sasl_getdn( conn, (char *)username, 0, NULL, &dn,
+ FLAG_GETDN_AUTHCID );
if ( rc != LDAP_SUCCESS ) {
sasl_seterror( sconn, 0, ldap_err2string( rc ) );
return SASL_NOUSER;
in ? in : "<empty>" );
#endif
- rc = slap_sasl_getdn( conn, (char *)in, (char *)user_realm, &dn,
+ rc = slap_sasl_getdn( conn, (char *)in, inlen, (char *)user_realm, &dn,
(flags == SASL_CU_AUTHID) ? FLAG_GETDN_AUTHCID : FLAG_GETDN_AUTHZID );
if ( rc != LDAP_SUCCESS ) {
sasl_seterror( sconn, 0, ldap_err2string( rc ) );
Connection *conn = (Connection *)context;
struct berval authcDN, authzDN;
char *realm;
- int rc, equal = 1;
+ int rc, equal = 1, ext = 0;
#ifdef NEW_LOGGING
LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
if ( requested_user )
equal = !strcmp( auth_identity, requested_user );
- realm = strchr( auth_identity, '@' );
- if ( realm )
- *realm++ = '\0';
+ /* If using SASL-EXTERNAL, don't modify the ID in any way */
+ if ( conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len
+ && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 )
+ && auth_identity[0] == '/' ) {
+ ext = 1;
+ realm = NULL;
+ } else {
+ /* Else look for an embedded realm in the name */
+ realm = strchr( auth_identity, '@' );
+ if ( realm ) *realm++ = '\0';
+ }
- rc = slap_sasl_getdn( conn, auth_identity, realm ? realm : (char *)def_realm,
+ rc = slap_sasl_getdn( conn, auth_identity, alen, realm ? realm : (char *)def_realm,
&authcDN, FLAG_GETDN_AUTHCID );
if ( realm )
realm[-1] = '@';
return SASL_OK;
}
- realm = strchr( requested_user, '@' );
- if ( realm )
- *realm++ = '\0';
+ if ( ext ) {
+ realm = NULL;
+ } else {
+ realm = strchr( requested_user, '@' );
+ if ( realm ) *realm++ = '\0';
+ }
- rc = slap_sasl_getdn( conn, requested_user, realm ? realm : (char *)def_realm,
+ rc = slap_sasl_getdn( conn, requested_user, rlen, realm ? realm : (char *)def_realm,
&authzDN, FLAG_GETDN_AUTHZID );
if ( realm )
realm[-1] = '@';
static int
slap_sasl_authorize(
void *context,
- const char *authcid,
- const char *authzid,
+ char *authcid,
+ char *authzid,
const char **user,
const char **errstr)
{
struct berval authcDN, authzDN;
- int rc;
+ int rc, ext = 0;
Connection *conn = context;
- char *realm;
+ char *realm, *xrealm;
*user = NULL;
/* Convert the identities to DN's. If no authzid was given, client will
be bound as the DN matching their username */
- rc = slap_sasl_getdn( conn, (char *)authcid, realm, &authcDN, FLAG_GETDN_AUTHCID );
+ if ( conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len
+ && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 )
+ && authcid[0] == '/' ) {
+ ext = 1;
+ xrealm = NULL;
+ } else {
+ xrealm = strchr( authcid, '@' );
+ if ( xrealm ) *xrealm++ = '\0';
+ }
+ rc = slap_sasl_getdn( conn, (char *)authcid, 0, xrealm ? xrealm : realm, &authcDN, FLAG_GETDN_AUTHCID );
+ if ( xrealm ) xrealm[-1] = '@';
if( rc != LDAP_SUCCESS ) {
*errstr = ldap_err2string( rc );
return SASL_NOAUTHZ;
*errstr = NULL;
return SASL_OK;
}
- rc = slap_sasl_getdn( conn, (char *)authzid, realm, &authzDN, FLAG_GETDN_AUTHZID );
+ if ( ext ) {
+ xrealm = NULL;
+ } else {
+ xrealm = strchr( authzid, '@' );
+ if ( xrealm ) *xrealm++ = '\0';
+ }
+ rc = slap_sasl_getdn( conn, (char *)authzid, 0, xrealm ? xrealm : realm, &authzDN, FLAG_GETDN_AUTHZID );
+ if ( xrealm ) xrealm[-1] = '@';
if( rc != LDAP_SUCCESS ) {
ch_free( authcDN.bv_val );
*errstr = ldap_err2string( rc );
NULL, "no SASL username", NULL, NULL );
} else {
- rc = slap_sasl_getdn( conn, username, realm, edn, FLAG_GETDN_FINAL );
-
- if( rc == LDAP_SUCCESS ) {
- sasl_ssf_t *ssf = NULL;
- (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf );
- *ssfp = ssf ? *ssf : 0;
+ sasl_ssf_t *ssf = NULL;
- if( *ssfp ) {
- ldap_pvt_thread_mutex_lock( &conn->c_mutex );
- conn->c_sasl_layers++;
- ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
- }
+ rc = LDAP_SUCCESS;
+ ber_str2bv( username, 0, 1, edn );
- send_ldap_sasl( conn, op, rc,
- NULL, NULL, NULL, NULL,
- response.bv_len ? &response : NULL );
+ (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf );
+ *ssfp = ssf ? *ssf : 0;
- } else {
-#if SASL_VERSION_MAJOR >= 2
- errstr = sasl_errdetail( ctx );
-#endif
- send_ldap_result( conn, op, rc,
- NULL, errstr, NULL, NULL );
+ if( *ssfp ) {
+ ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+ conn->c_sasl_layers++;
+ ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
}
+
+ send_ldap_sasl( conn, op, rc,
+ NULL, NULL, NULL, NULL,
+ response.bv_len ? &response : NULL );
}
} else if ( sc == SASL_CONTINUE ) {
reg->sr_offset[0] = -2;
n = 1;
for ( c = reg->sr_replace; *c; c++ ) {
- if ( *c == '\\' ) {
+ if ( *c == '\\' && c[1] ) {
c++;
continue;
}
* attribute named by *attr. If any of those rules map to the *assertDN, the
* authorization is approved.
*
- * DN's passed in should have a dn: prefix
+ * The DNs should not have the dn: prefix
*/
static int
slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct berval *attr, struct berval *authc)
int i, rc;
BerVarray vals=NULL;
AttributeDescription *ad=NULL;
- struct berval bv;
#ifdef NEW_LOGGING
LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
if( rc != LDAP_SUCCESS )
goto COMPLETE;
- bv.bv_val = searchDN->bv_val + 3;
- bv.bv_len = searchDN->bv_len - 3;
- rc = backend_attribute( NULL, NULL, NULL, NULL, &bv, ad, &vals );
+ rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
if( rc != LDAP_SUCCESS )
goto COMPLETE;
- bv.bv_val = assertDN->bv_val + 3;
- bv.bv_len = assertDN->bv_len - 3;
/* Check if the *assertDN matches any **vals */
for( i=0; vals[i].bv_val != NULL; i++ ) {
- rc = slap_sasl_match( &vals[i], &bv, authc );
+ rc = slap_sasl_match( &vals[i], assertDN, authc );
if ( rc == LDAP_SUCCESS )
goto COMPLETE;
}
/* Check if a bind can SASL authorize to another identity.
- Accepts authorization DN's with "dn:" prefix */
+ * The DNs should not have the dn: prefix
+ */
static struct berval sasl_authz_src = {
sizeof(SASL_AUTHZ_SOURCE_ATTR)-1, SASL_AUTHZ_SOURCE_ATTR };
};
-static char *bvcasechr( struct berval *bv, int c, ber_len_t *len )
+static char *bvcasechr( struct berval *bv, unsigned char c, ber_len_t *len )
{
ber_len_t i;
- int lower = TOLOWER( c );
- int upper = TOUPPER( c );
+ char lower = TOLOWER( c );
+ char upper = TOUPPER( c );
if( c == 0 ) return NULL;
*/
static struct berval *
-asn1_integer2str(ASN1_INTEGER *a)
+asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
{
char buf[256];
char *p;
*--p = '-';
}
- return ber_bvstrdup(p);
+ return ber_str2bv( p, 0, 1, bv );
}
/* Get a DN in RFC2253 format from a X509_NAME internal struct */
-static struct berval *
-dn_openssl2ldap(X509_NAME *name)
+int
+dn_openssl2ldap(X509_NAME *name, struct berval *out)
{
- char issuer_dn[1024];
- BIO *bio;
-
- bio = BIO_new(BIO_s_mem());
- if ( !bio ) {
-#ifdef NEW_LOGGING
- LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
- "dn_openssl2ldap: error creating BIO_s_mem: %s\n",
- ERR_error_string(ERR_get_error(),NULL)));
-#else
- Debug( LDAP_DEBUG_ARGS, "dn_openssl2ldap: "
- "error creating BIO: %s\n",
- ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
-#endif
- return NULL;
- }
- X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
-
- BIO_gets(bio, issuer_dn, 1024);
+ char buf[2048], *p;
- BIO_free(bio);
- return ber_bvstrdup(issuer_dn);
+ p = X509_NAME_oneline( name, buf, sizeof( buf ) );
+ return dnDCEnormalize( p, out );
}
/*
{
X509 *xcert;
unsigned char *p = in->bv_val;
- struct berval *serial;
- struct berval *issuer_dn;
- struct berval *bv_tmp;
+ struct berval serial;
+ struct berval issuer_dn;
xcert = d2i_X509(NULL, &p, in->bv_len);
if ( !xcert ) {
return LDAP_INVALID_SYNTAX;
}
- serial = asn1_integer2str(xcert->cert_info->serialNumber);
- if ( !serial ) {
+ if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
X509_free(xcert);
return LDAP_INVALID_SYNTAX;
}
- issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
- if ( !issuer_dn ) {
+ if ( dn_openssl2ldap(X509_get_issuer_name(xcert), &issuer_dn ) != LDAP_SUCCESS ) {
X509_free(xcert);
- ber_bvfree(serial);
+ ber_memfree(serial.bv_val);
return LDAP_INVALID_SYNTAX;
}
- /* Actually, dn_openssl2ldap returns in a normalized format, but
- it is different from our normalized format */
- bv_tmp = issuer_dn;
- if ( dnNormalize(NULL, bv_tmp, &issuer_dn) != LDAP_SUCCESS ) {
- X509_free(xcert);
- ber_bvfree(serial);
- ber_bvfree(bv_tmp);
- return LDAP_INVALID_SYNTAX;
- }
- ber_bvfree(bv_tmp);
X509_free(xcert);
- out->bv_len = serial->bv_len + issuer_dn->bv_len + sizeof(" $ ");
+ out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
out->bv_val = ch_malloc(out->bv_len);
p = out->bv_val;
- AC_MEMCPY(p, serial->bv_val, serial->bv_len);
- p += serial->bv_len;
+ AC_MEMCPY(p, serial.bv_val, serial.bv_len);
+ p += serial.bv_len;
AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
p += 3;
- AC_MEMCPY(p, issuer_dn->bv_val, issuer_dn->bv_len);
- p += issuer_dn->bv_len;
+ AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
+ p += issuer_dn.bv_len;
*p++ = '\0';
#ifdef NEW_LOGGING
out->bv_val, NULL, NULL );
#endif
- ber_bvfree(serial);
- ber_bvfree(issuer_dn);
+ ber_memfree(serial.bv_val);
+ ber_memfree(issuer_dn.bv_val);
return LDAP_SUCCESS;
}
static int
serial_and_issuer_parse(
struct berval *assertion,
- struct berval **serial,
- struct berval **issuer_dn
+ struct berval *serial,
+ struct berval *issuer_dn
)
{
char *begin;
bv.bv_len = end-begin+1;
bv.bv_val = begin;
- *serial = ber_dupbv(NULL, &bv);
+ ber_dupbv(serial, &bv);
/* now extract the issuer, remember p was at the dollar sign */
- begin = p+1;
- end = assertion->bv_val+assertion->bv_len-1;
- while (ASCII_SPACE(*begin))
- begin++;
- /* should we trim spaces at the end too? is it safe always? */
+ if ( issuer_dn ) {
+ begin = p+1;
+ end = assertion->bv_val+assertion->bv_len-1;
+ while (ASCII_SPACE(*begin))
+ begin++;
+ /* should we trim spaces at the end too? is it safe always? */
- bv.bv_len = end-begin+1;
- bv.bv_val = begin;
- dnNormalize( NULL, &bv, issuer_dn );
+ bv.bv_len = end-begin+1;
+ bv.bv_val = begin;
+ dnNormalize2( NULL, &bv, issuer_dn );
+ }
return LDAP_SUCCESS;
}
{
X509 *xcert;
unsigned char *p = value->bv_val;
- struct berval *serial;
- struct berval *issuer_dn;
- struct berval *asserted_serial;
- struct berval *asserted_issuer_dn;
+ struct berval serial;
+ struct berval issuer_dn;
+ struct berval asserted_serial;
+ struct berval asserted_issuer_dn;
int ret;
xcert = d2i_X509(NULL, &p, value->bv_len);
return LDAP_INVALID_SYNTAX;
}
- serial = asn1_integer2str(xcert->cert_info->serialNumber);
- issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
+ asn1_integer2str(xcert->cert_info->serialNumber, &serial);
+ dn_openssl2ldap(X509_get_issuer_name(xcert), &issuer_dn);
X509_free(xcert);
flags,
slap_schema.si_syn_integer,
slap_schema.si_mr_integerMatch,
- serial,
- asserted_serial);
+ &serial,
+ &asserted_serial);
if ( ret == LDAP_SUCCESS ) {
if ( *matchp == 0 ) {
/* We need to normalize everything for dnMatch */
flags,
slap_schema.si_syn_distinguishedName,
slap_schema.si_mr_distinguishedNameMatch,
- issuer_dn,
- asserted_issuer_dn);
+ &issuer_dn,
+ &asserted_issuer_dn);
}
}
#ifdef NEW_LOGGING
LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
"certificateExactMatch: %d\n %s $ %s\n %s $ %s\n",
- *matchp, serial->bv_val, issuer_dn->bv_val,
- asserted_serial->bv_val, asserted_issuer_dn->bv_val));
+ *matchp, serial.bv_val, issuer_dn.bv_val,
+ asserted_serial.bv_val, asserted_issuer_dn.bv_val));
#else
Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
"%d\n\t\"%s $ %s\"\n",
- *matchp, serial->bv_val, issuer_dn->bv_val );
+ *matchp, serial.bv_val, issuer_dn.bv_val );
Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
- asserted_serial->bv_val, asserted_issuer_dn->bv_val,
+ asserted_serial.bv_val, asserted_issuer_dn.bv_val,
NULL );
#endif
- ber_bvfree(serial);
- ber_bvfree(issuer_dn);
- ber_bvfree(asserted_serial);
- ber_bvfree(asserted_issuer_dn);
+ ber_memfree(serial.bv_val);
+ ber_memfree(issuer_dn.bv_val);
+ ber_memfree(asserted_serial.bv_val);
+ ber_memfree(asserted_issuer_dn.bv_val);
return ret;
}
BerVarray keys;
X509 *xcert;
unsigned char *p;
- struct berval * serial;
+ struct berval serial;
/* we should have at least one value at this point */
assert( values != NULL && values[0].bv_val != NULL );
return LDAP_INVALID_SYNTAX;
}
- serial = asn1_integer2str(xcert->cert_info->serialNumber);
+ asn1_integer2str(xcert->cert_info->serialNumber, &serial);
X509_free(xcert);
integerNormalize( slap_schema.si_syn_integer,
- serial,
+ &serial,
&keys[i] );
- ber_bvfree(serial);
+ ber_memfree(serial.bv_val);
#ifdef NEW_LOGGING
LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
"certificateExactIndexer: returning: %s\n",
BerVarray *keysp )
{
BerVarray keys;
- struct berval *asserted_serial;
- struct berval *asserted_issuer_dn;
+ struct berval asserted_serial;
serial_and_issuer_parse(assertValue,
&asserted_serial,
- &asserted_issuer_dn);
+ NULL);
keys = ch_malloc( sizeof( struct berval ) * 2 );
- integerNormalize( syntax, asserted_serial, &keys[0] );
+ integerNormalize( syntax, &asserted_serial, &keys[0] );
keys[1].bv_val = NULL;
*keysp = keys;
- ber_bvfree(asserted_serial);
- ber_bvfree(asserted_issuer_dn);
+ ber_memfree(asserted_serial.bv_val);
return LDAP_SUCCESS;
}
#endif
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* config.c - configuration file handling routines
*/
+#include "portable.h"
+
#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <lber.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+#include <ac/ctype.h>
+
#include <ldap.h>
#include "slurp.h"
#include "globals.h"
-#define MAXARGS 100
+#define MAXARGS 500
/* Forward declarations */
-#ifdef NEEDPROTOS
-static void add_replica( char **, int );
-static int parse_replica_line( char **, int, Ri *);
-static void parse_line( char *, int *, char ** );
-static char *getline( FILE * );
-static char *strtok_quote( char *, char * );
-#else /* NEEDPROTOS */
-static void add_replica();
-static int parse_replica_line();
-static void parse_line();
-static char *getline();
-static char *strtok_quote();
-#endif /* NEEDPROTOS */
+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 *, int *, char ** ));
+static char *getline LDAP_P(( FILE * ));
+static char *strtok_quote LDAP_P(( char *, char * ));
/* current config file line # */
static int lineno;
)
{
FILE *fp;
- char buf[BUFSIZ];
- char *line, *p;
+ char *line;
int cargc;
char *cargv[MAXARGS];
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "config", LDAP_LEVEL_ARGS,
+ "slurpd_read_config: Config: opening config file \"%s\"\n", fname ));
+#else
Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
fname, 0, 0 );
+#endif
if ( (fp = fopen( fname, "r" )) == NULL ) {
perror( fname );
- exit( 1 );
+ exit( EXIT_FAILURE );
}
lineno = 0;
continue;
}
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "config", LDAP_LEVEL_DETAIL1,
+ "slurpd_read_config: Config: (%s)\n", line ));
+#else
Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
+#endif
parse_line( line, &cargc, cargv );
"line %d: missing filename in \"replogfile ",
lineno );
fprintf( stderr, "<filename>\" line\n" );
- exit( 1 );
+ 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" );
}
- sprintf( sglob->slapd_replogfile, cargv[1] );
+ strcpy( sglob->slapd_replogfile, cargv[1] );
}
} 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 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
+ "%s: line %d: missing filename in \"include "
+ "<filename>\" line.\n", fname, lineno ));
+#else
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing filename in \"include <filename>\" line\n",
+ fname, lineno, 0 );
+#endif
+
+ return( 1 );
+ }
+ savefname = strdup( cargv[1] );
+ savelineno = lineno;
+
+ if ( slurpd_read_config( savefname ) != 0 ) {
+ return( 1 );
+ }
+
+ free( savefname );
+ lineno = savelineno - 1;
}
}
fclose( fp );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "config", LDAP_LEVEL_RESULTS,
+ "slurpd_read_config: Config: "
+ "** configuration file successfully read and parsed\n" ));
+#else
Debug( LDAP_DEBUG_CONFIG,
"Config: ** configuration file successfully read and parsed\n",
0, 0, 0 );
+#endif
return 0;
}
} else {
inquote = 1;
}
- strcpy( next, next + 1 );
+ AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
break;
case '\\':
- strcpy( next, next + 1 );
+ if ( next[1] )
+ AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
+ next++; /* dont parse the escaped character */
break;
default:
CATLINE( buf );
while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
if ( (p = strchr( buf, '\n' )) != NULL ) {
- *p = '\0';
+ if( p > buf && p[-1] == '\r' ) --p;
+ *p = '\0';
}
lineno++;
- if ( ! isspace( buf[0] ) ) {
+ if ( ! isspace( (unsigned char) buf[0] ) ) {
return( line );
}
+ /* change leading whitespace to space */
+ buf[0] = ' ';
+
CATLINE( buf );
}
buf[0] = '\0';
( nr + 1 ) * sizeof( Re * ));
if ( sglob->replicas == NULL ) {
fprintf( stderr, "out of memory, add_replica\n" );
- exit( 1 );
+ exit( EXIT_FAILURE );
}
sglob->replicas[ nr ] = NULL;
if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
fprintf( stderr, "out of memory, Ri_init\n" );
- exit( 1 );
+ exit( EXIT_FAILURE );
}
if ( parse_replica_line( cargv, cargc,
sglob->replicas[ nr - 1] ) < 0 ) {
sglob->replicas[ nr - 1] = NULL;
sglob->num_replicas--;
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "config", LDAP_LEVEL_RESULTS,
+ "add_replica: 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 ));
+#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 );
+#endif
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( 1 );
+ 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|kerberos" credentials=<creds>
+ * bindmethod="simple" credentials=<creds>
*
* where:
* <hostname:portnumber> describes the host name and port number where the
*
* <binddn> is the DN to bind to the replica slapd as,
*
- * bindmethod is either "simple" or "kerberos", and
+ * bindmethod is "simple", and
*
* <creds> are the credentials (e.g. password) for binddn. <creds> are
- * only used for bindmethod=simple. For bindmethod=kerberos, the
- * credentials= option should be omitted. Credentials for kerberos
- * authentication are in the system srvtab file.
+ * 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
#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,
char *hp, *val;
for ( i = 1; i < cargc; i++ ) {
- if ( !strncasecmp( cargv[ i ], HOSTSTR, strlen( HOSTSTR ))) {
- val = cargv[ i ] + strlen( HOSTSTR ) + 1;
+ if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */
if (( hp = strchr( val, ':' )) != NULL ) {
*hp = '\0';
hp++;
ri->ri_port = atoi( hp );
}
if ( ri->ri_port <= 0 ) {
- ri->ri_port = LDAP_PORT;
+ ri->ri_port = 0;
}
ri->ri_hostname = strdup( val );
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 ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( TLSSTR );
+ if( !strcasecmp( val, TLSCRITICALSTR ) ) {
+ ri->ri_tls = TLS_CRITICAL;
+ } else {
+ ri->ri_tls = TLS_ON;
+ }
} else if ( !strncasecmp( cargv[ i ],
- BINDDNSTR, strlen( BINDDNSTR ))) {
- val = cargv[ i ] + strlen( BINDDNSTR ) + 1;
+ BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( BINDDNSTR );
ri->ri_bind_dn = strdup( val );
gots |= GOT_DN;
} else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
- strlen( BINDMETHSTR ))) {
- val = cargv[ i ] + strlen( BINDMETHSTR ) + 1;
+ sizeof( BINDMETHSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( BINDMETHSTR );
if ( !strcasecmp( val, KERBEROSSTR )) {
-#ifdef KERBEROS
- ri->ri_bind_method = AUTH_KERBEROS;
- if ( ri->ri_srvtab == NULL ) {
- ri->ri_srvtab = strdup( sglob->default_srvtab );
- }
- gots |= GOT_METHOD;
-#else /* KERBEROS */
fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
- fprintf( stderr, "specified in the slapd configuration file,\n" );
- fprintf( stderr, "but slurpd was not built with kerberos.\n" );
- fprintf( stderr, "You must rebuild the LDAP release with\n" );
- fprintf( stderr, "kerberos support if you wish to use\n" );
- fprintf( stderr, "bindmethod=kerberos\n" );
- exit( 1 );
-#endif /* KERBEROS */
+ fprintf( stderr, "specified in the slapd configuration file.\n" );
+ fprintf( stderr, "slurpd no longer supports Kerberos.\n" );
+ exit( EXIT_FAILURE );
} else if ( !strcasecmp( val, SIMPLESTR )) {
ri->ri_bind_method = AUTH_SIMPLE;
gots |= GOT_METHOD;
+ } else if ( !strcasecmp( val, SASLSTR )) {
+ ri->ri_bind_method = AUTH_SASL;
+ gots |= GOT_METHOD;
} else {
ri->ri_bind_method = -1;
}
- } else if ( !strncasecmp( cargv[ i ], CREDSTR, strlen( CREDSTR ))) {
- val = cargv[ i ] + strlen( CREDSTR ) + 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 ], BINDPSTR, strlen( BINDPSTR ))) {
- val = cargv[ i ] + strlen( BINDPSTR ) + 1;
- ri->ri_principal = strdup( val );
- } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, strlen( SRVTABSTR ))) {
- val = cargv[ i ] + strlen( SRVTABSTR ) + 1;
+ } 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 if ( !strncasecmp( cargv[ i ],
+ SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) {
+ val = cargv[ i ] + sizeof( SRVTABSTR );
if ( ri->ri_srvtab != NULL ) {
free( ri->ri_srvtab );
}
cargv[ i ] );
}
}
- if ( gots != GOT_ALL ) {
- fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
- fprintf( stderr, "config file, line %d\n", lineno );
- return -1;
- }
+
+ if ( ri->ri_bind_method == 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;
}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* fm.c - file management routines.
*/
+#include "portable.h"
+
#include <stdio.h>
-#include <string.h>
-#include <signal.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/signal.h>
#include "slurp.h"
#include "globals.h"
-extern void do_admin();
-
-static void set_shutdown();
-void do_nothing();
-
-/*
- * Externs
- */
-#ifdef NEEDPROTOS
-extern int file_nonempty( char * );
-extern int acquire_lock(char *, FILE **, FILE ** );
-extern int relinquish_lock(char *, FILE *, FILE * );
-#else /* NEEDPROTOS */
-extern int file_nonempty();
-extern int acquire_lock();
-extern int relinquish_lock();
-#endif /* NEEDPROTOS */
/*
* Forward references
*/
-#ifdef NEEDPROTOS
-static char *get_record( FILE * );
-static void populate_queue( char *f );
-static void set_shutdown();
-void do_nothing();
-#else /* NEEDPROTOS */
-static char *get_record();
-static void populate_queue();
-static void set_shutdown();
-void do_nothing();
-#endif /* NEEDPROTOS */
-
-#ifndef SYSERRLIST_IN_STDIO
-extern char *sys_errlist[];
-#endif /* SYSERRLIST_IN_STDIO */
-
+static char *get_record LDAP_P(( FILE * ));
+static void populate_queue LDAP_P(( char *f ));
+static RETSIGTYPE set_shutdown LDAP_P((int));
/*
* - adds items to the internal queue of replication work to do
* - signals the replication threads to let them know new work has arrived.
*/
-void
+void *
fm(
void *arg
)
/* Set up our signal handlers:
* SIG{TERM,INT,HUP} causes a shutdown
- * SIGUSR1 - does nothing, used to wake up sleeping threads.
- * SIGUSR2 - causes slurpd to read its administrative interface file.
- * (not yet implemented).
+ * LDAP_SIGUSR1 - does nothing, used to wake up sleeping threads.
+ * LDAP_SIGUSR2 - causes a shutdown
*/
- (void) SIGNAL( SIGUSR1, (void *) do_nothing );
- (void) SIGNAL( SIGUSR2, (void *) do_admin );
- (void) SIGNAL( SIGTERM, (void *) set_shutdown );
- (void) SIGNAL( SIGINT, (void *) set_shutdown );
- (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+ (void) SIGNAL( LDAP_SIGUSR1, do_nothing );
+ (void) SIGNAL( LDAP_SIGUSR2, set_shutdown );
+ (void) SIGNAL( SIGTERM, set_shutdown );
+ (void) SIGNAL( SIGINT, set_shutdown );
+#ifdef SIGHUP
+ (void) SIGNAL( SIGHUP, set_shutdown );
+#endif
if ( sglob->one_shot_mode ) {
if ( file_nonempty( sglob->slapd_replogfile )) {
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;
+ return NULL;
}
/*
* There may be some leftover replication records in our own
while ( !sglob->slurpd_shutdown ) {
if ( file_nonempty( sglob->slapd_replogfile )) {
/* New work found - copy to slurpd replog file */
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_ARGS,
+ "fm: new work in %s\n", sglob->slapd_replogfile ));
+#else
Debug( LDAP_DEBUG_ARGS, "new work in %s\n",
sglob->slapd_replogfile, 0, 0 );
+#endif
if (( rc = copy_replog( sglob->slapd_replogfile,
sglob->slurpd_replogfile )) == 0 ) {
populate_queue( sglob->slurpd_replogfile );
} else {
if ( rc < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_CRIT,
+ "fm: Fatal error while copying replication log\n" ));
+#else
Debug( LDAP_DEBUG_ANY,
"Fatal error while copying replication log\n",
0, 0, 0 );
+#endif
sglob->slurpd_shutdown = 1;
}
}
} else {
- tsleep( sglob->no_work_interval );
+ ldap_pvt_thread_sleep( sglob->no_work_interval );
}
/* Garbage-collect queue */
FILE *fp, *lfp;
if (( rc = acquire_lock( sglob->slurpd_replogfile, &fp,
&lfp )) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_ERR,
+ "fm: Error: cannot acquire lock on \"%s\" for trimming\n",
+ sglob->slurpd_replogfile ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: cannot acquire lock on \"%s\" for trimming\n",
sglob->slurpd_replogfile, 0, 0 );
+#endif
} else {
sglob->rq->rq_write( sglob->rq, fp );
(void) relinquish_lock( sglob->slurpd_replogfile, fp, lfp );
}
}
}
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_RESULTS, "fm: exiting\n" ));
+#else
Debug( LDAP_DEBUG_ARGS, "fm: exiting\n", 0, 0, 0 );
+#endif
+ return NULL;
}
/*
* Set a global flag which signals that we're shutting down.
*/
-static void
-set_shutdown()
+static RETSIGTYPE
+set_shutdown(int sig)
{
int i;
sglob->slurpd_shutdown = 1; /* set flag */
- pthread_kill( sglob->fm_tid, SIGUSR1 ); /* wake up file mgr */
+ ldap_pvt_thread_kill( sglob->fm_tid, LDAP_SIGUSR1 ); /* wake up file mgr */
sglob->rq->rq_lock( sglob->rq ); /* lock queue */
- pthread_cond_broadcast( &(sglob->rq->rq_more) ); /* wake repl threads */
+ 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 */
- (void) SIGNAL( SIGTERM, (void *) set_shutdown ); /* reinstall handlers */
- (void) SIGNAL( SIGINT, (void *) set_shutdown );
- (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+ (void) SIGNAL_REINSTALL( sig, set_shutdown ); /* reinstall handlers */
}
/*
* A do-nothing signal handler.
*/
-void
-do_nothing()
+RETSIGTYPE
+do_nothing(int sig)
{
- (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+ (void) SIGNAL_REINSTALL( sig, do_nothing );
}
)
{
FILE *fp, *lfp;
- Rq *rq = sglob->rq;
char *p;
if ( acquire_lock( f, &fp, &lfp ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_ERR,
+ "populate_queue: error: can't lock file \"%s\": %s\n",
+ f, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY,
"error: can't lock file \"%s\": %s\n",
f, sys_errlist[ errno ], 0 );
+#endif
return;
}
* the queue.
*/
if ( fseek( fp, sglob->srpos, 0 ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_ERR,
+ "populate_queue: error: can't seek to offset %ld in file \"%s\"\n",
+ sglob->srpos, f ));
+#else
Debug( LDAP_DEBUG_ANY,
"error: can't seek to offset %ld in file \"%s\"\n",
sglob->srpos, f, 0 );
- return;
- }
+#endif
+ } else {
while (( p = get_record( fp )) != NULL ) {
if ( sglob->rq->rq_add( sglob->rq, p ) < 0 ) {
char *t;
if (( t = strchr( p, '\n' )) != NULL ) {
*t = '\0';
}
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "fm", LDAP_LEVEL_ERR,
+ "populate_queue: error: malformed replog entry "
+ "(begins with \"%s\")\n", p ));
+#else
Debug( LDAP_DEBUG_ANY,
"error: malformed replog entry (begins with \"%s\")\n",
p, 0, 0 );
+#endif
}
free( p );
- pthread_yield();
+ ldap_pvt_thread_yield();
}
sglob->srpos = ftell( fp );
+ }
(void) relinquish_lock( f, fp, lfp );
}
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;
+
+ while ( lcur + len + 1 > lmax ) {
+ lmax += BUFSIZ;
+ buf = (char *) ch_realloc( buf, lmax );
+ }
+ strcpy( buf + lcur, line );
+ lcur += len;
}
return( buf );
}
-
case T_ADDCT:
lderr = op_ldap_add( ri, re, errmsg );
if ( lderr != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( " ldap_op", LDAP_LEVEL_ERR, "do_ldap: "
+ "Error: ldap_add_s failed adding \"%s\": %s\n",
+ *errmsg ? *errmsg : ldap_err2string( lderr ), re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_add_s failed adding \"%s\": %s\n",
*errmsg ? *errmsg : ldap_err2string( lderr ),
re->re_dn, 0 );
+#endif
}
break;
case T_MODIFYCT:
lderr = op_ldap_modify( ri, re, errmsg );
if ( lderr != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( " ldap_op", LDAP_LEVEL_ERR, "do_ldap: "
+ "Error: ldap_modify_s failed modifying \"%s\": %s\n",
+ *errmsg ? *errmsg : ldap_err2string( lderr ), re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_modify_s failed modifying \"%s\": %s\n",
*errmsg ? *errmsg : ldap_err2string( lderr ),
re->re_dn, 0 );
+#endif
}
break;
case T_DELETECT:
lderr = op_ldap_delete( ri, re, errmsg );
if ( lderr != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( " ldap_op", LDAP_LEVEL_ERR, "do_ldap: "
+ "Error: ldap_delete_s failed deleting \"%s\": %s\n",
+ *errmsg ? *errmsg : ldap_err2string( lderr ), re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_delete_s failed deleting \"%s\": %s\n",
*errmsg ? *errmsg : ldap_err2string( lderr ),
re->re_dn, 0 );
+#endif
}
break;
case T_MODRDNCT:
lderr = op_ldap_modrdn( ri, re, errmsg );
if ( lderr != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( " ldap_op", LDAP_LEVEL_ERR, "do_ldap: "
+ "Error: ldap_modrdn_s failed modifying %s: %s\n",
+ *errmsg ? *errmsg : ldap_err2string( lderr ), re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_modrdn_s failed modifying %s: %s\n",
*errmsg ? *errmsg : ldap_err2string( lderr ),
re->re_dn, 0 );
+#endif
}
break;
default:
+#ifdef NEW_LOGGING
+ LDAP_LOG (( " ldap_op", LDAP_LEVEL_ERR, "do_ldap: "
+ "Error: bad op \"%d\", dn = \"%s\"\n",
+ re->re_changetype, re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: do_ldap: bad op \"%d\", dn = \"%s\"\n",
re->re_changetype, re->re_dn, 0 );
+#endif
return DO_LDAP_ERR_FATAL;
}
ldmarr[ nattrs ] = NULL;
/* Perform the operation */
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "op_ldap_add: replica %s:%d - add dn \"%s\"\n",
+ ri->ri_hostname, ri->ri_port, re->re_dn ));
+#else
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n",
ri->ri_hostname, ri->ri_port, re->re_dn );
+#endif
rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr );
ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
} else {
*errmsg = "No modifications to do";
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_add: Error: no mods to do (%s)!\n", re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_add: no mods to do (%s)!\n", re->re_dn, 0, 0 );
+#endif
}
free_ldmarr( ldmarr );
return( lderr );
if ( re->re_mods == NULL ) {
*errmsg = "No arguments given";
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modify: Error: no arguments\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modify: no arguments\n",
0, 0, 0 );
+#endif
return -1;
}
break;
default:
if ( state == AWAITING_OP ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modify: Error: unknown mod type \"%s\"\n", type ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_modify: unknown mod type \"%s\"\n",
type, 0, 0 );
+#endif
continue;
}
* Construct the mod_bvalues part of the ldapmod struct.
*/
if ( strcasecmp( type, ldm->mod_type )) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modify: Error: "
+ "malformed modify op, %s: %s (expecting \"%s\")\n",
+ type, value, ldm->mod_type ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: malformed modify op, %s: %s (expecting %s:)\n",
type, value, ldm->mod_type );
+#endif
continue;
}
ldm->mod_bvalues = ( struct berval ** )
if ( nops > 0 ) {
/* Actually perform the LDAP operation */
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_DETAIL1,
+ "op_ldap_modify: replica %s:%d - modify dn \"%s\"\n",
+ ri->ri_hostname, ri->ri_port, re->re_dn ));
+#else
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
ri->ri_hostname, ri->ri_port, re->re_dn );
+#endif
rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
}
free_ldmarr( ldmarr );
{
int rc;
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "op_ldap_delete: replica %s:%d - delete dn \"%s\"\n",
+ ri->ri_hostname, ri->ri_port, re->re_dn ));
+#else
Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
ri->ri_hostname, ri->ri_port, re->re_dn );
+#endif
rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
return( rc );
if ( re->re_mods == NULL ) {
*errmsg = "No arguments given";
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: no arguments\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
0, 0, 0 );
+#endif
return -1;
}
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 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: multiple newrdn arg \"%s\"\n",
+ mi[ i ].mi_val ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
mi[ i ].mi_val, 0, 0 );
+#endif
*errmsg = "Multiple newrdn argument";
return -1;
}
} else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
if( state & GOT_DELOLDRDN ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: multiple deleteoldrdn arg \"%s\"\n",
+ mi[ i ].mi_val ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
mi[ i ].mi_val, 0, 0 );
+#endif
*errmsg = "Multiple newrdn argument";
return -1;
}
} else if ( !strcmp( mi[ i ].mi_val, "1" )) {
drdnflag = 1;
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: bad deleteoldrdn arg \"%s\"\n",
+ mi[ i ].mi_val ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
mi[ i ].mi_val, 0, 0 );
+#endif
*errmsg = "Incorrect argument to deleteoldrdn";
return -1;
}
} else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
if( state & GOT_NEWSUP ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: multiple newsuperior arg \"%s\"\n",
+ mi[ i ].mi_val ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
mi[ i ].mi_val, 0, 0 );
+#endif
*errmsg = "Multiple newsuperior argument";
return -1;
}
state |= GOT_NEWSUP;
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: bad type \"%s\"\n",
+ mi[ i ].mi_type ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
mi[ i ].mi_type, 0, 0 );
+#endif
*errmsg = "Bad value in replication log entry";
return -1;
}
* Punt if we don't have all the args.
*/
if ( !GOT_ALL_MODDN(state) ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "op_ldap_modrdn: Error: missing arguments\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
0, 0, 0 );
+#endif
*errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
return -1;
}
buf2 = (char *) ch_malloc( strlen( re->re_dn ) + strlen( mi->mi_val )
+ 10 );
sprintf( buf2, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "op_ldap_modrdn: replica %s - modify rdn %s (flag: %d)\n",
+ buf, buf2, drdnflag ));
+#else
Debug( LDAP_DEBUG_ARGS,
"replica %s - modify rdn %s (flag: %d)\n",
buf, buf2, drdnflag );
+#endif
free( buf2 );
}
#endif /* LDAP_DEBUG */
if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
rc = ldap_unbind( ri->ri_ldp );
if ( rc != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "do_unbind: ldap_unbind failed for %s:%d: %s\n",
+ ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
+#endif
}
ri->ri_ldp = NULL;
}
*lderr = 0;
if ( ri == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: null ri ptr\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
+#endif
return( BIND_ERR_BADRI );
}
if ( ri->ri_ldp != NULL ) {
ldrc = ldap_unbind( ri->ri_ldp );
if ( ldrc != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "do_bind: ldap_unbind failed: %s\n", ldap_err2string( ldrc ) ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: do_bind: ldap_unbind failed: %s\n",
ldap_err2string( ldrc ), 0, 0 );
+#endif
}
ri->ri_ldp = NULL;
}
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "do_bind: Initializing session to %s:%d\n",
+ ri->ri_hostname, ri->ri_port ));
+#else
Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
ri->ri_hostname, ri->ri_port, 0 );
+#endif
ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
if ( ri->ri_ldp == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR,
+ "do_bind: ldap_init (%s, %d) failed: %s\n",
+ ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
+#endif
return( BIND_ERR_OPEN );
}
LDAP_OPT_PROTOCOL_VERSION, &version);
if( err != LDAP_OPT_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: ",
+ "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
+ ri->ri_hostname ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
ri->ri_hostname, NULL, NULL );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
if( err != LDAP_OPT_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: ",
+ "Error: ldap_set_option(%s, REFERRALS, OFF) failed!\n",
+ ri->ri_hostname ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
ri->ri_hostname, NULL, NULL );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
return BIND_ERR_REFERRALS;
err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
if( err != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: ",
+ "%s: ldap_start_tls failed: %s (%d)\n",
+ ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
+ ldap_err2string( err ), err ));
+#else
Debug( LDAP_DEBUG_ANY,
"%s: ldap_start_tls failed: %s (%d)\n",
ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
ldap_err2string( err ), err );
+#endif
if( ri->ri_tls == TLS_CRITICAL ) {
ldap_unbind( ri->ri_ldp );
/*
* Bind with a plaintext password.
*/
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "do_bind: bind to %s:%d as %s (simple)\n",
+ ri->ri_hostname, ri->ri_port, ri->ri_bind_dn ));
+#else
Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
+#endif
ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
ri->ri_password );
if ( ldrc != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
+ ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_simple_bind_s for %s:%d failed: %s\n",
ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
+#endif
*lderr = ldrc;
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
break;
case AUTH_SASL:
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ARGS,
+ "do_bind: bind to %s as %s via %s (SASL)\n",
+ ri->ri_hostname, ri->ri_authcId, ri->ri_saslmech ));
+#else
Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
ri->ri_hostname, ri->ri_authcId, ri->ri_saslmech );
+#endif
#ifdef HAVE_CYRUS_SASL
if( ri->ri_secprops != NULL ) {
ri->ri_secprops);
if( err != LDAP_OPT_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
+ ri->ri_hostname, ri->ri_secprops ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
ri->ri_hostname, ri->ri_secprops, NULL );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
return BIND_ERR_SASL_FAILED;
ri->ri_saslmech, NULL, NULL,
LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
if ( ldrc != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "Error: LDAP SASL for %s:%d failed: %s\n",
+ ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
+#endif
*lderr = ldrc;
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
ber_memfree( defaults );
}
break;
+#else
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "Error: do_bind: SASL not supported %s:%d\n",
+ ri->ri_hostname, ri->ri_port ));
#else
Debug( LDAP_DEBUG_ANY,
"Error: do_bind: SASL not supported %s:%d\n",
ri->ri_hostname, ri->ri_port, NULL );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
return( BIND_ERR_BAD_ATYPE );
#endif
default:
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
+ ri->ri_bind_method, ri->ri_hostname, ri->ri_port ));
+#else
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 );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
return( BIND_ERR_BAD_ATYPE );
err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
if( err != LDAP_OPT_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_ERR, "do_bind: "
+ "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
+ ri->ri_hostname ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: "
"ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
ri->ri_hostname, NULL, NULL );
+#endif
ldap_unbind( ri->ri_ldp );
ri->ri_ldp = NULL;
return BIND_ERR_MANAGEDSAIT;
for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
ldm = ldmarr[ i ];
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_INFO, "dump_ldm_array: "
+ "Trace (%ld): *** ldmarr[ %d ] contents:\n",
+ (long) getpid(), i ));
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_INFO, "dump_ldm_array: "
+ "Trace (%ld): *** ldm->mod_op: %d\n",
+ (long) getpid(), ldm->mod_op ));
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_INFO, "dump_ldm_array: "
+ "Trace (%ld): *** ldm->mod_type: %s\n",
+ (long) getpid(), ldm->mod_type ));
+#else
Debug( LDAP_DEBUG_TRACE,
"Trace (%ld): *** ldmarr[ %d ] contents:\n",
(long) getpid(), i, 0 );
Debug( LDAP_DEBUG_TRACE,
"Trace (%ld): *** ldm->mod_type: %s\n",
(long) getpid(), ldm->mod_type, 0 );
+#endif
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 );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ldap_op", LDAP_LEVEL_INFO, "dump_ldm_array: "
+ "Trace (%ld):%s\n", (long) getpid(), msgbuf ));
+#else
Debug( LDAP_DEBUG_TRACE,
"Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
+#endif
free( msgbuf );
}
}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* lock.c - routines to open and apply an advisory lock to a file
*/
+#include "portable.h"
+
#include <stdio.h>
-#include <sys/time.h>
-#include <sys/types.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>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include "portable.h"
-#ifdef USE_LOCKF
-#include <unistd.h>
#endif
-#include "../slapd/slap.h"
+#include "slurp.h"
FILE *
lock_fopen(
- char *fname,
- char *type,
+ const char *fname,
+ const char *type,
FILE **lfp
)
{
strcpy( buf, fname );
strcat( buf, ".lock" );
if ( (*lfp = fopen( buf, "w" )) == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "lock", LDAP_LEVEL_ERR, "lock_fopen: "
+ "Error: could not open \"%s\"\n", buf ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: could not open \"%s\"\n", buf, 0, 0 );
+#endif
return( NULL );
}
/* acquire the lock */
-#ifdef USE_LOCKF
- while ( lockf( fileno( *lfp ), F_LOCK, 0 ) != 0 ) {
-#else
- while ( flock( fileno( *lfp ), LOCK_EX ) != 0 ) {
-#endif
- ; /* NULL */
- }
+ ldap_lockf( fileno(*lfp) );
/* open the log file */
if ( (fp = fopen( fname, type )) == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "lock", LDAP_LEVEL_ERR, "lock_fopen: "
+ "Error: could not open \"%s\"\n", fname ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: could not open \"%s\"\n", fname, 0, 0 );
-#ifdef USE_LOCKF
- lockf( fileno( *lfp ), F_ULOCK, 0 );
-#else
- flock( fileno( *lfp ), LOCK_UN );
#endif
+ ldap_unlockf( fileno(*lfp) );
+ fclose( *lfp );
+ *lfp = NULL;
return( NULL );
}
)
{
/* unlock */
-#ifdef USE_LOCKF
- lockf( fileno( lfp ), F_ULOCK, 0 );
-#else
- flock( fileno( lfp ), LOCK_UN );
-#endif
+ ldap_unlockf( fileno(lfp) );
fclose( lfp );
return( fclose( fp ) );
*/
int
acquire_lock(
- char *file,
+ const char *file,
FILE **rfp,
FILE **lfp
)
{
if (( *rfp = lock_fopen( file, "r+", lfp )) == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "lock", LDAP_LEVEL_ERR, "acquire_lock: "
+ "Error: acquire_lock(%ld): Could not acquire lock on \"%s\"\n",
+ (long) getpid(), file ));
+#else
Debug( LDAP_DEBUG_ANY,
- "Error: acquire_lock(%d): Could not acquire lock on \"%s\"\n",
- getpid(), file, 0);
+ "Error: acquire_lock(%ld): Could not acquire lock on \"%s\"\n",
+ (long) getpid(), file, 0);
+#endif
return( -1 );
}
return( 0 );
*/
int
relinquish_lock(
- char *file,
+ const char *file,
FILE *rfp,
FILE *lfp
)
{
if ( lock_fclose( rfp, lfp ) == EOF ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "lock", LDAP_LEVEL_ERR, "relinguish_lock: "
+ "Error: relinquish_lock (%ld): Error closing \"%s\"\n",
+ (long) getpid(), file ));
+#else
Debug( LDAP_DEBUG_ANY,
- "Error: relinquish_lock (%d): Error closing \"%s\"\n",
- getpid(), file, 0 );
+ "Error: relinquish_lock (%ld): Error closing \"%s\"\n",
+ (long) getpid(), file, 0 );
+#endif
return( -1 );
}
return( 0 );
if ( ldap_pvt_thread_create( &(sglob->fm_tid),
0, fm, (void *) NULL ) != 0 )
{
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "main", LDAP_LEVEL_ERR,
+ "main: file manager ldap_pvt_thread_create failed\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "file manager ldap_pvt_thread_create failed\n",
0, 0, 0 );
+#endif
exit( EXIT_FAILURE );
}
/* destroy the thread package */
ldap_pvt_thread_destroy();
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "main", LDAP_LEVEL_RESULTS,
+ "main: slurpd terminated\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "slurpd: terminated.\n", 0, 0, 0 );
+#endif
return 0;
#endif /* !NO_THREADS */
}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
*/
+#include "portable.h"
+
#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "../slapd/slap.h"
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/ctype.h>
+
#include "slurp.h"
#include "globals.h"
-/* externs */
-extern char *str_getline( char **next );
-extern void ch_free( char *p );
-
-extern char *sys_errlist[];
+#include "../slapd/slap.h"
/* Forward references */
-static Rh *get_repl_hosts( char *, int *, char ** );
-static int gettype( char * );
-static int getchangetype( char *);
-static int Re_parse( Re *re, char *replbuf );
-static void Re_dump( Re *re, FILE *fp );
-static void warn_unknown_replica( char *, int port );
+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 */
/*
* Free an Re
+ * ??? Something should apparently return nonzero here, but I dont know what.
*/
static int
Re_free(
return 0;
}
if ( re->re_refcnt > 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_WARNING, "Re_free: "
+ "Warning: freeing re (dn: %s) with nonzero refcnt\n", re->re_dn ));
+#else
Debug( LDAP_DEBUG_ANY,
"Warning: freeing re (dn: %s) with nonzero refcnt\n",
re->re_dn, 0, 0 );
+#endif
}
-#if !defined( THREAD_SUNOS4_LWP )
- /* This seems to have problems under SunOS lwp */
- pthread_mutex_destroy( &re->re_mutex );
-#endif /* THREAD_SUNOS4_LWP */
- ch_free( re->re_timestamp );
+
+ 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( mi );
}
free( re );
+ return 0;
}
int state;
int nml;
char *buf, *rp, *p;
- long buflen;
+ size_t buflen;
char *type, *value;
- int len;
+ ber_len_t len;
int nreplicas;
if ( re == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR, "Re_parse: Error: re is NULL\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Re_parse: error: re is NULL\n", 0, 0, 0 );
+#endif
return -1;
}
if ( replbuf == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR, "Re_parse: Error: replbuf is NULL\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Re_parse: error: replbuf is NULL\n", 0, 0, 0 );
+#endif
return -1;
}
re->re_refcnt = sglob->num_replicas;
for (;;) {
- if (( state == GOT_ALL ) || ( buf = str_getline( &rp )) == NULL ) {
+ if (( state == GOT_ALL ) || ( buf = ldif_getline( &rp )) == NULL ) {
break;
}
/*
if ( strncmp( buf, ERROR_STR, strlen( ERROR_STR )) == 0 ) {
continue;
}
- buflen = ( long ) strlen( buf );
- if ( str_parse_line( buf, &type, &value, &len ) < 0 ) {
+ buflen = strlen( buf );
+ if ( ldif_parse_line( buf, &type, &value, &len ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_parse: Error: malformed replog file\n" ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: Re_parse: malformed replog file\n",
0, 0, 0 );
+#endif
return -1;
}
switch ( gettype( type )) {
/* there was a sequence number */
*p++ = '\0';
}
- re->re_timestamp = strdup( value );
- if ( p != NULL && isdigit( *p )) {
+ re->re_timestamp = atol( value );
+ if ( p != NULL && isdigit( (unsigned char) *p )) {
re->re_seq = atoi( p );
}
state |= GOT_TIME;
break;
case T_DN:
- re->re_dn = strdup( value );
+ 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 )) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_parse: Error: bad type <%s>\n", type ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: Re_parse: bad type <%s>\n",
type, 0, 0 );
+#endif
+ free( type );
+ if ( value != NULL )
+ free( value );
return -1;
}
}
+ free( type );
+ if ( value != NULL )
+ free( value );
}
if ( state != GOT_ALL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_parse: Error: malformed replog file\n" ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: Re_parse: malformed replog file\n",
0, 0, 0 );
+#endif
return -1;
}
for (;;) {
- if (( buf = str_getline( &rp )) == NULL ) {
+ char *const dash = "-";
+
+ if (( buf = ldif_getline( &rp )) == NULL ) {
break;
}
- buflen = ( long ) strlen( buf );
+ buflen = strlen( buf );
if (( buflen == 1 ) && ( buf[ 0 ] == '-' )) {
- type = "-";
+ type = dash;
value = NULL;
} else {
- if ( str_parse_line( buf, &type, &value, &len ) < 0 ) {
+ if ( ldif_parse_line( buf, &type, &value, &len ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_parse: Error: malformed replog line \"%s\"\n", buf ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: malformed replog line \"%s\"\n",
buf, 0, 0 );
+#endif
return -1;
}
}
sizeof( Mi ) * ( nml + 2 ));
re->re_mods[ nml ].mi_type = strdup( type );
if ( value != NULL ) {
- re->re_mods[ nml ].mi_val = strdup( value );
+ 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 + 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;
}
char **r_rp
)
{
- char buf[ LINE_WIDTH + 1 ];
char *type, *value, *line, *p;
Rh *rh = NULL;
- int nreplicas, len;
+ int nreplicas;
+ ber_len_t len;
int port;
int repl_ok;
int i;
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 = str_getline( r_rp );
+ line = ldif_getline( r_rp );
if ( line == NULL ) {
break;
}
if ( strncasecmp( *r_rp, "replica:", 7 )) {
break;
}
- line = str_getline( r_rp );
+ line = ldif_getline( r_rp );
if ( line == NULL ) {
break;
}
- if ( str_parse_line( line, &type, &value, &len ) < 0 ) {
+ if ( ldif_parse_line( line, &type, &value, &len ) < 0 ) {
return( NULL );
}
- port = LDAP_PORT;
+ port = 0;
if (( p = strchr( value, ':' )) != NULL ) {
*p = '\0';
p++;
break;
}
}
+ free( type );
if ( !repl_ok ) {
warn_unknown_replica( value, port );
+ if ( value != NULL )
+ free( value );
continue;
}
rh = (Rh *) ch_realloc((char *) rh, ( nreplicas + 2 ) * sizeof( Rh ));
if ( rh == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "get_repl_hosts: Out of memory\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Out of memory in get_repl_hosts\n",
0, 0, 0 );
+#endif
return NULL;
}
rh[ nreplicas ].rh_hostname = strdup( value );
rh[ nreplicas ].rh_port = port;
nreplicas++;
+
+ if ( value != NULL )
+ free( value );
}
if ( nreplicas == 0 ) {
Mi *mi;
if ( re == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR, "Re_dump: re is NULL\n" ));
+#else
Debug( LDAP_DEBUG_TRACE, "Re_dump: re is NULL\n", 0, 0, 0 );
+#endif
return;
}
fprintf( fp, "Re_dump: ******\n" );
fprintf( fp, "re_refcnt: %d\n", re->re_refcnt );
- fprintf( fp, "re_timestamp: %s\n", re->re_timestamp );
+ 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++ ) {
int i;
char *s;
int rc = 0;
- Rh *rh;
if ( re == NULL || fp == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_write: Internal error: NULL argument\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Internal error: Re_write: NULL argument\n",
0, 0, 0 );
+#endif
return -1;
}
}
}
}
- if ( fprintf( fp, "time: %s.%d\n", re->re_timestamp, re->re_seq ) < 0 ) {
+ if ( fprintf( fp, "time: %ld.%d\n", (long) re->re_timestamp, re->re_seq ) < 0 ) {
rc = -1;
goto bad;
}
}
} else {
char *obuf;
- obuf = ldif_type_and_value( re->re_mods[ i ].mi_type,
+ 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 ) {
free( obuf );
goto bad;
} else {
- free( obuf );
+ ber_memfree( obuf );
}
}
}
}
bad:
if ( rc != 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_ERR,
+ "Re_write: Error while writing: %s\n", sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY, "Error while writing: %s\n",
sys_errlist[ errno ], 0, 0 );
+#endif
}
return rc;
}
Re *re
)
{
- return( pthread_mutex_lock( &re->re_mutex ));
+ return( ldap_pvt_thread_mutex_lock( &re->re_mutex ));
}
Re *re
)
{
- return( pthread_mutex_unlock( &re->re_mutex ));
+ return( ldap_pvt_thread_mutex_unlock( &re->re_mutex ));
}
/* Initialize private data */
(*re)->re_refcnt = sglob->num_replicas;
- (*re)->re_timestamp = NULL;
+ (*re)->re_timestamp = (time_t) 0L;
(*re)->re_replicas = NULL;
(*re)->re_dn = NULL;
(*re)->re_changetype = 0;
(*re)->re_mods = NULL;
(*re)->re_next = NULL;
- pthread_mutex_init( &((*re)->re_mutex), pthread_mutexattr_default );
+ ldap_pvt_thread_mutex_init( &((*re)->re_mutex) );
return 0;
}
}
}
if ( !found ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "re", LDAP_LEVEL_WARNING, "warn_unknown_replica: "
+ "Warning: unknown replica %s:%d found in replication log\n",
+ host, port ));
+#else
Debug( LDAP_DEBUG_ANY,
"Warning: unknown replica %s:%d found in replication log\n",
host, port, 0 );
+#endif
nur++;
ur = (Rh *) ch_realloc( (char *) ur, ( nur * sizeof( Rh )));
ur[ nur - 1 ].rh_hostname = strdup( host );
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* to a replica LDAP server.
*/
+#include "portable.h"
#include <stdio.h>
-#include <sys/types.h>
+
+#include <ac/errno.h>
+#include <ac/unistd.h>
+
#include <sys/stat.h>
#include <fcntl.h>
-#include <unistd.h>
#include "slurp.h"
#include "globals.h"
-#ifndef SYSERRLIST_IN_STDIO
-extern char *sys_errlist[];
-#endif /* SYSERRLIST_IN_STDIO */
-
-
/*
* 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"
FILE *rfp, *lfp;
int rc;
- pthread_mutex_lock( &sglob->rej_mutex );
+ ldap_pvt_thread_mutex_lock( &sglob->rej_mutex );
sprintf( rejfile, "%s/%s:%d.rej", sglob->slurpd_rdir,
ri->ri_hostname, ri->ri_port );
int rjfd;
if (( rjfd = open( rejfile, O_RDWR | O_APPEND | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP )) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "reject", LDAP_LEVEL_ERR, "write_reject: "
+ "Error: Cannot create \"%s\":%s\n",
+ rejfile, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: write_reject: Cannot create \"%s\": %s\n",
rejfile, sys_errlist[ errno ], 0 );
- pthread_mutex_unlock( &sglob->rej_mutex );
+#endif
+ ldap_pvt_thread_mutex_unlock( &sglob->rej_mutex );
return;
} else {
close( rjfd );
}
}
if (( rc = acquire_lock( rejfile, &rfp, &lfp )) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "reject", LDAP_LEVEL_ERR, "write_reject: "
+ "Error: Cannot open reject file \"%s\"\n", rejfile ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: cannot open reject file \"%s\"\n",
rejfile, 0, 0 );
+#endif
} else {
fseek( rfp, 0, 2 );
if ( errmsg != NULL ) {
fprintf( rfp, "%s: %s\n", ERROR_STR, ldap_err2string( lderr ));
}
if ((rc = re->re_write( ri, re, rfp )) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "reject", LDAP_LEVEL_ERR, "write_reject: "
+ "Error: Cannot write reject file \"%s\"\n", rejfile ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: cannot write reject file \"%s\"\n",
rejfile, 0, 0 );
+#endif
}
(void) relinquish_lock( rejfile, rfp, lfp );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "reject", LDAP_LEVEL_ERR, "write_reject: "
+ "Error: ldap operation failed, data written to \"%s\"\n", rejfile ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: ldap operation failed, data written to \"%s\"\n",
rejfile, 0, 0 );
+#endif
}
- pthread_mutex_unlock( &sglob->rej_mutex );
+ ldap_pvt_thread_mutex_unlock( &sglob->rej_mutex );
return;
}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* replica.c - code to start up replica threads.
*/
+#include "portable.h"
#include <stdio.h>
* Just invoke the Ri's process() member function, and log the start and
* finish.
*/
-void
+static void *
replicate(
- Ri *ri
+ void *ri_arg
)
{
- int i;
- unsigned long seq;
+ Ri *ri = (Ri *) ri_arg;
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replica", LDAP_LEVEL_ARGS, "replicate: "
+ "begin replication thread for %s:%d\n",
+ ((Ri *)ri)->ri_hostname, ((Ri *)ri)->ri_port ));
+#else
Debug( LDAP_DEBUG_ARGS, "begin replication thread for %s:%d\n",
- ri->ri_hostname, ri->ri_port, 0 );
+ ((Ri *)ri)->ri_hostname, ((Ri *)ri)->ri_port, 0 );
+#endif
ri->ri_process( ri );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replica", LDAP_LEVEL_ARGS, "replicate: "
+ "begin replication thread for %s:%d\n",
+ ri->ri_hostname, ri->ri_port ));
+#else
Debug( LDAP_DEBUG_ARGS, "end replication thread for %s:%d\n",
ri->ri_hostname, ri->ri_port, 0 );
- return;
+#endif
+ return NULL;
}
Ri *ri
)
{
- pthread_attr_t attr;
-
- pthread_attr_init( &attr );
- pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
-
- if ( pthread_create( &(ri->ri_tid), attr, (void *) replicate,
+ /* POSIX_THREADS or compatible */
+ if ( ldap_pvt_thread_create( &(ri->ri_tid), 0, replicate,
(void *) ri ) != 0 ) {
- Debug( LDAP_DEBUG_ANY, "replica \"%s:%d\" pthread_create failed\n",
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replica", LDAP_LEVEL_ERR, "start_replica_thread: "
+ "replica %s:%d ldap_pvt_thread_create failed\n",
+ ri->ri_hostname, ri->ri_port ));
+#else
+ Debug( LDAP_DEBUG_ANY, "replica \"%s:%d\" ldap_pvt_thread_create failed\n",
ri->ri_hostname, ri->ri_port, 0 );
- pthread_attr_destroy( &attr );
+#endif
return -1;
}
- pthread_attr_destroy( &attr );
+
return 0;
}
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* replog.c - routines which read and write replication log files.
*/
+#include "portable.h"
-#include <errno.h>
#include <stdio.h>
-#include <syslog.h>
-#include <sys/time.h>
-#include <sys/types.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 <sys/param.h>
+
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include "portable.h"
#include "slurp.h"
#include "globals.h"
-/*
- * Externs
- */
-#ifdef NEEDPROTOS
-extern FILE *lock_fopen( char *, char *, FILE ** );
-extern char *ch_malloc( unsigned long );
-#else /* NEEDPROTOS */
-extern FILE *lock_fopen();
-extern char *ch_malloc();
-#endif /* NEEDPROTOS */
-
-/*
- * Forward declarations
- */
-#ifdef NEEDPROTOS
-int file_nonempty( char * );
-#else /* NEEDPROTOS */
-int file_nonempty();
-#endif /* NEEDPROTOS */
-
-
-#ifndef SYSERRLIST_IN_STDIO
-extern char *sys_errlist[];
-#endif
-
-/*
- * Forward declarations
- */
-static int duplicate_replog( char *, char * );
-
-
-
-
/*
* Copy the replication log. Returns 0 on success, 1 if a temporary
* error occurs, and -1 if a fatal error occurs.
static char rbuf[ 1024 ];
char *p;
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ARGS, "copy_replog: "
+ "copy replog \"%s\" to \"%s\"\n", src, dst ));
+#else
Debug( LDAP_DEBUG_ARGS,
"copy replog \"%s\" to \"%s\"\n",
src, dst, 0 );
+#endif
/*
* Make sure the destination directory is writable. If not, exit
*p = '\0';
}
if ( access( buf, W_OK ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: (%ld): Directory %s is not writable\n",
+ (long) getpid(), buf ));
+#else
Debug( LDAP_DEBUG_ANY,
- "Error: copy_replog (%d): Directory %s is not writable\n",
- getpid(), buf, 0 );
+ "Error: copy_replog (%ld): Directory %s is not writable\n",
+ (long) getpid(), buf, 0 );
+#endif
return( -1 );
}
strcpy( buf, dst );
*p = '\0';
}
if ( access( buf, W_OK ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: (%ld): Directory %s is not writable\n",
+ (long) getpid(), buf ));
+#else
Debug( LDAP_DEBUG_ANY,
- "Error: copy_replog (%d): Directory %s is not writable\n",
- getpid(), buf, 0 );
+ "Error: copy_replog (%ld): Directory %s is not writable\n",
+ (long) getpid(), buf, 0 );
+#endif
return( -1 );
}
/* lock src */
rfp = lock_fopen( src, "r", &lfp );
if ( rfp == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: Can't lock replog \"%s\" for read: %s\n",
+ src, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: copy_replog: Can't lock replog \"%s\" for read: %s\n",
src, sys_errlist[ errno ], 0 );
+#endif
return( 1 );
}
/* lock dst */
dfp = lock_fopen( dst, "a", &dlfp );
if ( dfp == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: Can't lock replog \"%s\" for write: %s\n",
+ src, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: copy_replog: Can't lock replog \"%s\" for write: %s\n",
src, sys_errlist[ errno ], 0 );
- lock_fclose( rfp );
+#endif
+ lock_fclose( rfp, lfp );
return( 1 );
}
truncate( src, (off_t) 0 );
}
- if ( lock_fclose( rfp, lfp ) == EOF ) {
+ if ( lock_fclose( dfp, dlfp ) == EOF ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: Error closing \"%s\"\n", src ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: copy_replog: Error closing \"%s\"\n",
src, 0, 0 );
+#endif
}
- if ( lock_fclose( dfp, dlfp ) == EOF ) {
+ if ( lock_fclose( rfp, lfp ) == EOF ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "replog", LDAP_LEVEL_ERR, "copy_replog: "
+ "Error: Error closing \"%s\"\n", src ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: copy_replog: Error closing \"%s\"\n",
src, 0, 0 );
+#endif
}
return( rc );
}
(void) SIGNAL( LDAP_SIGUSR1, do_nothing );
(void) SIGNAL( SIGPIPE, SIG_IGN );
if ( ri == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ri", LDAP_LEVEL_ERR, "Ri_process: "
+ "Error: ri == NULL!\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: Ri_process: ri == NULL!\n", 0, 0, 0 );
+#endif
return -1;
}
if ( re != NULL ) {
if ( !ismine( ri, re )) {
/* The Re doesn't list my host:port */
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ri", LDAP_LEVEL_DETAIL1, "Ri_process: "
+ "Replica %s:%d, skip repl record for %s (not mine)\n",
+ ri->ri_hostname, ri->ri_port, re->re_dn ));
+#else
Debug( LDAP_DEBUG_TRACE,
"Replica %s:%d, skip repl record for %s (not mine)\n",
ri->ri_hostname, ri->ri_port, re->re_dn );
+#endif
} else if ( !isnew( ri, re )) {
/* This Re is older than my saved status information */
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ri", LDAP_LEVEL_DETAIL1, "Ri_process: "
+ "Replica %s:%d, skip repl record for %s (old)\n",
+ ri->ri_hostname, ri->ri_port, re->re_dn ));
+#else
Debug( LDAP_DEBUG_TRACE,
"Replica %s:%d, skip repl record for %s (old)\n",
ri->ri_hostname, ri->ri_port, re->re_dn );
+#endif
} else {
rc = do_ldap( ri, re, &errmsg );
switch ( rc ) {
case DO_LDAP_ERR_RETRYABLE:
ldap_pvt_thread_sleep( RETRY_SLEEP_TIME );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ri", LDAP_LEVEL_DETAIL1, "Ri_process: "
+ "Retrying operation for DN %s on replica %s:%d\n",
+ re->re_dn, ri->ri_hostname, ri->ri_port ));
+#else
Debug( LDAP_DEBUG_ANY,
"Retrying operation for DN %s on replica %s:%d\n",
re->re_dn, ri->ri_hostname, ri->ri_port );
+#endif
continue;
break;
case DO_LDAP_ERR_FATAL: {
}
}
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "ri", LDAP_LEVEL_ERR, "Ri_process: "
+ "Error: re is null in Ri_process\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: re is null in Ri_process\n",
0, 0, 0 );
+#endif
}
rq->rq_lock( rq );
while ( !sglob->slurpd_shutdown &&
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
*
*/
-#include <stdio.h>
-
-#include "slurp.h"
-#include "globals.h"
+#include "portable.h"
+#include <stdio.h>
+#include <sys/stat.h>
-/* externs */
-#ifdef NEEDPROTOS
-extern void Re_dump( Re *re );
-#else /* NEEDPROTOS */
-extern void Re_dump();
-#endif /* NEEDPROTOS */
+#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
-extern char *sys_errlist[];
+#include "slurp.h"
+#include "globals.h"
/*
Rq *rq
)
{
- return( pthread_mutex_lock( &rq->rq_mutex ));
+ return( ldap_pvt_thread_mutex_lock( &rq->rq_mutex ));
}
-
-
-
/*
* Unlock the replication queue.
*/
Rq *rq
)
{
- return( pthread_mutex_unlock( &rq->rq_mutex ));
+ return( ldap_pvt_thread_mutex_unlock( &rq->rq_mutex ));
}
}
-
-
/*
* Return the next item in the queue. Callers should lock the queue before
* calling this routine.
}
-
-
/*
* Delete the item at the head of the list. The queue should be locked
* by the caller before calling this routine.
}
if ( savedhead->re_getrefcnt( savedhead ) != 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_WARNING, "Rq_delhead: "
+ "Warning: attempt to delete when refcnt != 0\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Warning: attempt to delete when refcnt != 0\n",
0, 0, 0 );
+#endif
return( -1 );
}
}
-
-
/*
* Add an entry to the tail of the replication queue. Locking is handled
* internally. When items are added to the queue, this routine wakes
/* set the sequence number */
re->re_seq = 0;
- if ( !wasempty && !strcmp(rq->rq_tail->re_timestamp, re->re_timestamp )) {
+ 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.
/* Increment count of items in queue */
rq->rq_nre++;
/* wake up any threads waiting for more work */
- pthread_cond_broadcast( &rq->rq_more );
+ ldap_pvt_thread_cond_broadcast( &rq->rq_more );
/* ... and unlock the queue */
rq->rq_unlock( rq );
}
-
-
/*
* Garbage-collect the replication queue. Locking is handled internally.
*/
)
{
if ( rq == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_DETAIL1, "Rq_gc: rq is NULL!\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Rq_gc: rq is NULL!\n", 0, 0, 0 );
+#endif
return;
}
rq->rq_lock( rq );
}
-
/*
* For debugging: dump the contents of the replication queue to a file.
* Locking is handled internally.
{
Re *re;
FILE *fp;
+ int tmpfd;
if ( rq == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ARGS, "Rq_dump: rq is NULL!\n" ));
+#else
Debug( LDAP_DEBUG_ANY, "Rq_dump: rq is NULL!\n", 0, 0, 0 );
+#endif
return;
}
- if (( fp = fopen( SLURPD_DUMPFILE, "w" )) == NULL ) {
+ if (unlink(SLURPD_DUMPFILE) == -1 && errno != ENOENT) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ERR, "Rq_dump: "
+ "\"%s\" exists, cannot unlink\n", SLURPD_DUMPFILE ));
+#else
+ Debug( LDAP_DEBUG_ANY, "Rq_dump: \"%s\" exists, and cannot unlink\n",
+ SLURPD_DUMPFILE, 0, 0 );
+#endif
+ return;
+ }
+ if (( tmpfd = open(SLURPD_DUMPFILE, O_CREAT|O_RDWR|O_EXCL, 0600)) == -1) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ERR, "Rq_dump: "
+ "cannot open \"%s\" for write\n", SLURPD_DUMPFILE ));
+#else
Debug( LDAP_DEBUG_ANY, "Rq_dump: cannot open \"%s\" for write\n",
SLURPD_DUMPFILE, 0, 0 );
+#endif
+ return;
+ }
+ if (( fp = fdopen( tmpfd, "w" )) == NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ERR, "Rq_dump: "
+ "cannot fdopen \"%s\" for write\n", SLURPD_DUMPFILE ));
+#else
+ Debug( LDAP_DEBUG_ANY, "Rq_dump: cannot fdopen \"%s\" for write\n",
+ SLURPD_DUMPFILE, 0, 0 );
+#endif
return;
}
}
-
/*
* Write the contents of a replication queue to a file. Returns zero if
* successful, -1 if not. Handles queue locking internally. Callers should
return -1;
}
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ENTRY, "Rq_write: "
+ "re-write on-disk replication log\n" ));
+#else
Debug( LDAP_DEBUG_ARGS, "re-write on-disk replication log\n",
0, 0, 0 );
+#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
sglob->srpos = ftell( fp ); /* update replog file position */
/* and truncate to correct len */
if ( ftruncate( fileno( fp ), sglob->srpos ) < 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "rq", LDAP_LEVEL_ERR, "Rq_write: "
+ "Error truncating replication log: %s\n", sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY, "Error truncating replication log: %s\n",
sys_errlist[ errno ], 0, 0 );
+#endif
}
rq->rq_ndel = 0; /* reset count of deleted re's */
time( &now );
}
-
-
/*
* Check to see if the private slurpd replication log needs trimming.
* The current criteria are:
)
{
int rc = 0;
- Re *re;
- int nzrc = 0; /* nzrc is count of entries with refcnt == 0 */
time_t now;
if ( rq == NULL ) {
for ( re = rq->rq_gethead( rq ); re != NULL;
re = rq->rq_getnext( re )) {
if ( type == RQ_COUNT_NZRC ) {
- if ( re->re_getrefcnt( re ) > 1 ) {
+ if ( re->re_getrefcnt( re ) > 0 ) {
count++;
}
}
}
-
-
/*
* Allocate and initialize an Rq object.
*/
(*rq)->rq_getcount = Rq_getcount;
/* Initialize private data */
- pthread_mutex_init( &((*rq)->rq_mutex), pthread_mutexattr_default );
- pthread_cond_init( &((*rq)->rq_more), pthread_condattr_default );
+ 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;
return 0;
}
-
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
* writing status information to disk.
*/
-
+#include "portable.h"
#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
#include "slurp.h"
#include "globals.h"
-#ifndef SYSERRLIST_IN_STDIO
-extern char *sys_errlist[];
-#endif /* SYSERRLIST_IN_STDIO */
-
/*
* Add information about replica host specified by Ri to list
* of hosts.
}
/* Serialize access to the St struct */
- pthread_mutex_lock( &(st->st_mutex ));
+ 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 ) {
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return NULL;
}
- st->st_data[ ind ] = ( Stel * ) ch_malloc( st->st_data,
- sizeof( Stel ));
+ st->st_data[ ind ] = ( Stel * ) ch_malloc( sizeof( Stel ) );
if ( st->st_data[ ind ] == NULL ) {
- pthread_mutex_unlock( &(st->st_mutex ));
+ 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;
- memset( st->st_data[ ind ]->last, 0, sizeof( st->st_data[ ind ]->last ));
+ st->st_data[ ind ]->last = 0;
st->st_data[ ind ]->seq = 0;
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return st->st_data[ ind ];
}
if ( st == NULL ) {
return -1;
}
- pthread_mutex_lock( &(st->st_mutex ));
+ 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 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "st", LDAP_LEVEL_ERR, "St_write: "
+ "Error: cannot open status file \"%s\":%s\n",
+ sglob->slurpd_status_file, sys_errlist[ errno ] ));
+#else
Debug( LDAP_DEBUG_ANY,
"Error: cannot open status file \"%s\": %s\n",
sglob->slurpd_status_file, sys_errlist[ errno ], 0 );
+#endif
st->st_err_logged = 1;
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return -1;
}
} else {
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:%s:%d\n", stel->hostname, stel->port,
- stel->last, stel->seq );
+ fprintf( st->st_fp, "%s:%d:%ld:%d\n",
+ stel->hostname, stel->port,
+ (long) stel->last, stel->seq );
}
fflush( st->st_fp );
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return 0;
}
return -1;
}
- pthread_mutex_lock( &(st->st_mutex ));
- strcpy( stel->last, re->re_timestamp );
+ ldap_pvt_thread_mutex_lock( &(st->st_mutex ));
+ stel->last = re->re_timestamp;
stel->seq = re->re_seq;
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return 0;
}
if ( st == NULL ) {
return -1;
}
- pthread_mutex_lock( &(st->st_mutex ));
+ 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 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "st", LDAP_LEVEL_ERR, "St_write: "
+ "Error: cannot create status file \"%s\"\n",
+ sglob->slurpd_status_file ));
+#else
Debug( LDAP_DEBUG_ANY, "Error: cannot create status file \"%s\"\n",
sglob->slurpd_status_file, 0, 0 );
- pthread_mutex_unlock( &(st->st_mutex ));
+#endif
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return -1;
}
(void) fclose( fp );
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "st", LDAP_LEVEL_DETAIL1, "St_write: "
+ "No status file found, defaulting values\n" ));
+#else
Debug( LDAP_DEBUG_ARGS, "No status file found, defaulting values\n",
0, 0, 0 );
+#endif
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 ) {
if ( !strcmp( hostname, sglob->st->st_data[ i ]->hostname ) &&
atoi( port ) == sglob->st->st_data[ i ]->port ) {
found = 1;
- strcpy( sglob->st->st_data[ i ]->last, timestamp );
+ sglob->st->st_data[ i ]->last = atol( timestamp );
sglob->st->st_data[ i ]->seq = atoi( seq );
break;
}
char tbuf[ 255 ];
sprintf( tbuf, "%s:%s (timestamp %s.%s)", hostname, port,
timestamp, seq );
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "st", LDAP_LEVEL_DETAIL1, "St_write: "
+ "Retrieved state information for %s\n", tbuf ));
+#else
Debug( LDAP_DEBUG_ARGS,
"Retrieved state information for %s\n", tbuf, 0, 0 );
+#endif
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "st", LDAP_LEVEL_WARNING, "St_write: "
+ "Warning: saved state for %s:%s, not a known replica\n",
+ hostname, port ));
+#else
Debug( LDAP_DEBUG_ANY,
"Warning: saved state for %s:%s, not a known replica\n",
hostname, port, 0 );
+#endif
}
}
(void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return 0;
bad:
(void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
- pthread_mutex_unlock( &(st->st_mutex ));
+ ldap_pvt_thread_mutex_unlock( &(st->st_mutex ));
return -1;
}
St *st
)
{
- return( pthread_mutex_lock( &st->st_mutex ));
+ return( ldap_pvt_thread_mutex_lock( &st->st_mutex ));
}
St *st
)
{
- return( pthread_mutex_unlock( &st->st_mutex ));
+ return( ldap_pvt_thread_mutex_unlock( &st->st_mutex ));
}
return -1;
}
- pthread_mutex_init( &((*st)->st_mutex), pthread_mutexattr_default );
+ ldap_pvt_thread_mutex_init( &((*st)->st_mutex) );
(*st)->st_data = NULL;
(*st)->st_fp = NULL;
(*st)->st_lfp = NULL;