]> git.sur5r.net Git - openldap/commitdiff
Resync with HEAD
authorKurt Zeilenga <kurt@openldap.org>
Thu, 18 Apr 2002 17:19:55 +0000 (17:19 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Thu, 18 Apr 2002 17:19:55 +0000 (17:19 +0000)
56 files changed:
clients/maildap/main.c [new file with mode: 0644]
clients/tools/ldapmodify.c
doc/man/man3/ldap_schema.3 [new file with mode: 0644]
doc/man/man8/slapd.8
libraries/liblber/bprint.c
libraries/libldap/cyrus.c
libraries/libldap/result.c
libraries/liblunicode/ucdata/ucdata.c [new file with mode: 0644]
libraries/liblunicode/ucdata/ucgendat.c [new file with mode: 0644]
libraries/liblunicode/ucstr.c
libraries/liblutil/passwd.c
libraries/librewrite/map.c
libraries/librewrite/parse.c
libraries/librewrite/subst.c
servers/slapd/aclparse.c
servers/slapd/back-bdb/cache.c
servers/slapd/back-bdb/init.c
servers/slapd/back-ldap/suffixmassage.c [new file with mode: 0644]
servers/slapd/back-ldap/unbind.c [new file with mode: 0644]
servers/slapd/back-ldbm/config.c
servers/slapd/back-passwd/search.c
servers/slapd/back-perl/SampleLDAP.pm [new file with mode: 0644]
servers/slapd/back-perl/add.c [new file with mode: 0644]
servers/slapd/back-perl/bind.c [new file with mode: 0644]
servers/slapd/back-perl/close.c [new file with mode: 0644]
servers/slapd/back-perl/compare.c [new file with mode: 0644]
servers/slapd/back-perl/config.c [new file with mode: 0644]
servers/slapd/back-perl/delete.c [new file with mode: 0644]
servers/slapd/back-perl/external.h [new file with mode: 0644]
servers/slapd/back-perl/init.c [new file with mode: 0644]
servers/slapd/back-perl/modify.c [new file with mode: 0644]
servers/slapd/back-perl/modrdn.c [new file with mode: 0644]
servers/slapd/back-perl/perl_back.h [new file with mode: 0644]
servers/slapd/back-perl/search.c [new file with mode: 0644]
servers/slapd/back-sql/util.c [new file with mode: 0644]
servers/slapd/config.c
servers/slapd/dn.c
servers/slapd/main.c
servers/slapd/proto-slap.h
servers/slapd/referral.c
servers/slapd/result.c
servers/slapd/sasl.c
servers/slapd/saslauthz.c
servers/slapd/schema_init.c
servers/slurpd/config.c
servers/slurpd/fm.c
servers/slurpd/ldap_op.c
servers/slurpd/lock.c
servers/slurpd/main.c
servers/slurpd/re.c
servers/slurpd/reject.c
servers/slurpd/replica.c
servers/slurpd/replog.c
servers/slurpd/ri.c
servers/slurpd/rq.c
servers/slurpd/st.c

diff --git a/clients/maildap/main.c b/clients/maildap/main.c
new file mode 100644 (file)
index 0000000..345c8f4
--- /dev/null
@@ -0,0 +1,2074 @@
+/* $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 = &current_group->g_members;
+                               current_nto = &current_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 );
+}
index d09b9ad8398b4ece77746f25347a9f5b25db4f40..f55cb80aa15d2bc2bf83bfc057d768979e58e4b8 100644 (file)
@@ -1,40 +1,61 @@
+/* $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"
@@ -42,228 +63,700 @@ extern int ldap_debug, lber_debug;
 #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;
@@ -272,53 +765,85 @@ process_ldif_rec( char *rbuf )
        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 {
@@ -327,60 +852,104 @@ process_ldif_rec( char *rbuf )
        }
 
        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 );
        }
@@ -397,209 +966,110 @@ process_ldif_rec( char *rbuf )
        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 ) {
@@ -612,7 +1082,7 @@ domodify( char *dn, LDAPMod **pmods, int newentry )
                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;
@@ -629,9 +1099,9 @@ domodify( char *dn, LDAPMod **pmods, int newentry )
     }
 
     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 ) {
@@ -641,7 +1111,9 @@ domodify( char *dn, LDAPMod **pmods, int newentry )
            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" );
        }
@@ -656,14 +1128,16 @@ domodify( char *dn, LDAPMod **pmods, int newentry )
 
 
 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" );
        }
@@ -678,20 +1152,26 @@ dodelete( char *dn )
 
 
 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" );
        }
@@ -705,93 +1185,38 @@ domodrdn( char *dn, char *newrdn, int deleteoldrdn )
 }
 
 
-
-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 );
diff --git a/doc/man/man3/ldap_schema.3 b/doc/man/man3/ldap_schema.3
new file mode 100644 (file)
index 0000000..11a7bfc
--- /dev/null
@@ -0,0 +1,329 @@
+.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.  
+
index 949f866e68e8176f92f3843e0057aa77df310fe6..4a92d7aad4c324feb46f136c7ca0dd7fdd54b09a 100644 (file)
@@ -6,12 +6,12 @@
 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
@@ -144,6 +144,12 @@ will run with the specified group name or id.
 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
@@ -167,6 +173,14 @@ on voluminous debugging which will be printed on standard error, type:
 .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),
index a6ae8ce7ed68337196edc622c1382071d440ba36..23ebf88853e05261216084530eb2f2a0e4ebdffd 100644 (file)
@@ -285,7 +285,7 @@ int ber_output_dump(
         
         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 ] = '.';
index 5f128098d353f079f95da282ee06beb5c46ecb95..d14e893c058357e21e0bffac8a99350001a696cc 100644 (file)
@@ -846,7 +846,7 @@ int ldap_pvt_sasl_secprops(
                } 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 {
@@ -856,7 +856,7 @@ int ldap_pvt_sasl_secprops(
                } 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 {
@@ -866,7 +866,7 @@ int ldap_pvt_sasl_secprops(
                } 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 {
index c99e2a84ff93a43036a1e537d1d7b30116392ca9..5905f43afa1417870e1c8397fd238b1fb052599e 100644 (file)
@@ -647,7 +647,8 @@ try_read1msg(
                {
                        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 ) {
diff --git a/libraries/liblunicode/ucdata/ucdata.c b/libraries/liblunicode/ucdata/ucdata.c
new file mode 100644 (file)
index 0000000..e4ded22
--- /dev/null
@@ -0,0 +1,1325 @@
+/* $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 */
diff --git a/libraries/liblunicode/ucdata/ucgendat.c b/libraries/liblunicode/ucdata/ucgendat.c
new file mode 100644 (file)
index 0000000..2b67122
--- /dev/null
@@ -0,0 +1,1561 @@
+/* $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;
+}
index f0cc6033221fdedb51faf08ce53657652c9f0abf..18a882111d7506ce6be17d181ad5b0a6bfb09713 100644 (file)
@@ -167,7 +167,7 @@ struct berval * UTF8bvnormalize(
                i = 0;
        }
 
-       p = ucs = (long *) malloc( len * sizeof(*ucs) );
+       p = ucs = malloc( len * sizeof(*ucs) );
        if ( ucs == NULL ) {
                free(out);
                return NULL;
@@ -342,7 +342,7 @@ int UTF8bvnormcmp(
         * 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??? */
        }
@@ -365,7 +365,7 @@ int UTF8bvnormcmp(
        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??? */
                }
index ee9282310cb85f6302e15753d021a00776fdd159..dba06c9b2b1d8e5901726477d4a9755de7e5c901 100644 (file)
 #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
@@ -659,14 +663,18 @@ static int chk_sasl(
 
 #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
index 2180d8907757164816ad4c23e19b8babe54a5fe2..8db54af13711b89701804bb6fdcf5a214cf20012 100644 (file)
@@ -245,19 +245,20 @@ rewrite_map_parse(
        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--;
                }
index a8129c41aed5ecfd83b2bce50d2961282eff3beb..bc83e0594e575a6a0cc61c4ce12ec07ef05e0452 100644 (file)
@@ -45,7 +45,7 @@ parse_line(
        }
        
        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 ) {
index 1024517463519212239e7985e28a8f1b6cd81b61..4c0bc411e0fa627c0d77084e2a116da33c635f06 100644 (file)
@@ -53,7 +53,7 @@ rewrite_subst_compile(
        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;
index 95397c2668eb71b7d04639b4e679df4f75d082bc..f53d273aa6373e5edbb946b996a252555962bea1 100644 (file)
@@ -22,14 +22,14 @@ static void         split(char *line, int splitchar, char **left, char **right);
 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;
@@ -79,10 +79,8 @@ regtest(const char *fname, int lineno, char *pat) {
                        "%s: line %d: regular expression \"%s\" bad because of %s\n",
                        fname, lineno, pat, error );
                acl_usage();
-               return(0);
        }
        regfree(&re);
-       return(1);
 }
 
 void
@@ -166,7 +164,7 @@ parse_acl(
                                                        || strcmp(right, ".*") == 0 
                                                        || strcmp(right, ".*$") == 0 
                                                        || strcmp(right, "^.*") == 0 
-                                                       || strcmp(right, "^.*$$") == 0
+                                                       || strcmp(right, "^.*$") == 0
                                                        || strcmp(right, ".*$$") == 0 
                                                        || strcmp(right, "^.*$$") == 0 )
                                                {
@@ -174,8 +172,7 @@ parse_acl(
                                                        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;
@@ -236,7 +233,13 @@ parse_acl(
                        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 {
@@ -373,8 +376,7 @@ parse_acl(
                                                                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);
                                                        }
@@ -402,7 +404,13 @@ parse_acl(
                                        }
 
                                        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;
@@ -490,15 +498,20 @@ parse_acl(
 
                                        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) {
@@ -625,8 +638,7 @@ parse_acl(
 
                                        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);
                                                }
@@ -661,8 +673,7 @@ parse_acl(
 
                                        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);
                                                }
@@ -704,8 +715,7 @@ parse_acl(
                                        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);
                                                }
@@ -740,8 +750,7 @@ parse_acl(
 
                                        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);
                                                }
@@ -1191,19 +1200,19 @@ str2accessmask( const char *str )
                }
 
                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' ) {
@@ -1270,25 +1279,26 @@ acl_usage( void )
 }
 
 /*
+ * 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 
@@ -1309,7 +1319,7 @@ acl_regex_normalized_dn(
                                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);
                        }
                }
        }
index 1dd74f1cd8e873509b565e0b7f21a135aeee19a0..5038db4bc799bacf7dbe6f7982e621f379a1a0db 100644 (file)
@@ -167,7 +167,7 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
        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 );
@@ -183,8 +183,10 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
         * 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 */
@@ -193,7 +195,7 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
        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
@@ -209,7 +211,7 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
 
        } 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
@@ -228,7 +230,7 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
                                bdb_entry_return( e );
                        }
 
-                       /* free cache mutex */
+                       /* free cache write lock */
                        ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
 
 #ifdef NEW_LOGGING
@@ -243,7 +245,7 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
                }
 
        } else {
-               /* free cache mutex */
+               /* free cache write lock */
                ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
 
 #ifdef NEW_LOGGING
@@ -304,14 +306,14 @@ bdb_cache_add_entry_rw(
                   "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,
@@ -330,7 +332,7 @@ bdb_cache_add_entry_rw(
        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
@@ -378,7 +380,7 @@ bdb_cache_add_entry_rw(
 
                bdb_cache_entry_private_destroy(e);
 
-               /* free cache mutex */
+               /* free cache write lock */
                ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
                return( -1 );
        }
@@ -390,6 +392,7 @@ bdb_cache_add_entry_rw(
        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 );
@@ -429,8 +432,9 @@ bdb_cache_add_entry_rw(
                }
        }
 
-       /* 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 );
 }
@@ -450,7 +454,7 @@ bdb_cache_update_entry(
        int     i, rc;
        Entry   *ee;
 
-       /* set cache mutex */
+       /* set cache write lock */
        ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
 
        assert( e->e_private );
@@ -468,7 +472,7 @@ bdb_cache_update_entry(
                    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 );
        }
@@ -501,7 +505,7 @@ bdb_cache_update_entry(
 #endif
                }
 
-               /* free cache mutex */
+               /* free cache write lock */
                ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
                return( -1 );
        }
@@ -511,6 +515,7 @@ bdb_cache_update_entry(
        /* 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 );
@@ -550,8 +555,9 @@ bdb_cache_update_entry(
                }
        }
 
-       /* 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 );
 }
@@ -571,7 +577,7 @@ bdb_cache_find_entry_ndn2id(
        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,
@@ -598,7 +604,7 @@ try_again:
                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
@@ -616,15 +622,17 @@ try_again:
                        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
@@ -638,7 +646,7 @@ try_again:
 #endif
 
        } else {
-               /* free cache mutex */
+               /* free cache read lock */
                ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
 
                id = NOID;
@@ -665,7 +673,7 @@ bdb_cache_find_entry_id(
        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,
@@ -688,7 +696,7 @@ try_again:
 
                        assert(state != CACHE_ENTRY_UNDEFINED);
 
-                       /* free cache mutex */
+                       /* free cache read lock */
                        ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
 
 #ifdef NEW_LOGGING
@@ -713,7 +721,7 @@ try_again:
                         * 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
@@ -730,7 +738,9 @@ try_again:
                        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 );
@@ -738,7 +748,7 @@ try_again:
                
                BEI(ep)->bei_refcnt++;
 
-               /* free cache mutex */
+               /* free lru mutex */
                ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
 
 #ifdef NEW_LOGGING
@@ -755,7 +765,7 @@ try_again:
                return( ep );
        }
 
-       /* free cache mutex */
+       /* free cache read lock */
        ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
 
        return( NULL );
@@ -780,7 +790,7 @@ bdb_cache_delete_entry(
 {
        int     rc;
 
-       /* set cache mutex */
+       /* set cache write lock */
        ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
 
        assert( e->e_private );
@@ -793,11 +803,13 @@ bdb_cache_delete_entry(
                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 );
 }
@@ -846,8 +858,9 @@ bdb_cache_release_all( Cache *cache )
        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
@@ -879,8 +892,9 @@ bdb_cache_release_all( Cache *cache )
 
        }
 
-       /* 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 );
 }
 
index d0c27ba340abb03ddcbce38eb1d1d22cf8948d6a..0283e3170bbb1debb74491ca8df931ab5e6ec59b 100644 (file)
@@ -443,6 +443,14 @@ bdb_db_destroy( BackendDB *be )
                }
        }
 
+#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;
 }
 
diff --git a/servers/slapd/back-ldap/suffixmassage.c b/servers/slapd/back-ldap/suffixmassage.c
new file mode 100644 (file)
index 0000000..0847740
--- /dev/null
@@ -0,0 +1,115 @@
+/* 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 */
diff --git a/servers/slapd/back-ldap/unbind.c b/servers/slapd/back-ldap/unbind.c
new file mode 100644 (file)
index 0000000..f3f5617
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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;
+}
index 3c8475024e5621e81739513579404b4ef4e2c1ca..2cb64aa675aa263749c569475003c23ccc26427c 100644 (file)
@@ -177,7 +177,7 @@ ldbm_back_db_config(
 
 #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,
index 2cdeb4c9cf1671c2b1566d3a70f98805ebee3e1f..83db8ae5fea8d83d801f597dda78ab2e0aa9b024 100644 (file)
@@ -325,7 +325,7 @@ pw2entry( Backend *be, struct passwd *pw, const char **text )
                        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;
                }
diff --git a/servers/slapd/back-perl/SampleLDAP.pm b/servers/slapd/back-perl/SampleLDAP.pm
new file mode 100644 (file)
index 0000000..6bbcd0e
--- /dev/null
@@ -0,0 +1,300 @@
+
+=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;
+
+
diff --git a/servers/slapd/back-perl/add.c b/servers/slapd/back-perl/add.c
new file mode 100644 (file)
index 0000000..c4a54ef
--- /dev/null
@@ -0,0 +1,77 @@
+/* $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 );
+}
diff --git a/servers/slapd/back-perl/bind.c b/servers/slapd/back-perl/bind.c
new file mode 100644 (file)
index 0000000..a286224
--- /dev/null
@@ -0,0 +1,91 @@
+/* $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 );
+}
diff --git a/servers/slapd/back-perl/close.c b/servers/slapd/back-perl/close.c
new file mode 100644 (file)
index 0000000..f16478b
--- /dev/null
@@ -0,0 +1,69 @@
+/* $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;
+}
diff --git a/servers/slapd/back-perl/compare.c b/servers/slapd/back-perl/compare.c
new file mode 100644 (file)
index 0000000..cf167b3
--- /dev/null
@@ -0,0 +1,94 @@
+/* $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);
+}
+
diff --git a/servers/slapd/back-perl/config.c b/servers/slapd/back-perl/config.c
new file mode 100644 (file)
index 0000000..da4d839
--- /dev/null
@@ -0,0 +1,161 @@
+/* $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;
+}
diff --git a/servers/slapd/back-perl/delete.c b/servers/slapd/back-perl/delete.c
new file mode 100644 (file)
index 0000000..e07d3ab
--- /dev/null
@@ -0,0 +1,76 @@
+/* $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 );
+}
diff --git a/servers/slapd/back-perl/external.h b/servers/slapd/back-perl/external.h
new file mode 100644 (file)
index 0000000..f95fe17
--- /dev/null
@@ -0,0 +1,34 @@
+/* $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 */
diff --git a/servers/slapd/back-perl/init.c b/servers/slapd/back-perl/init.c
new file mode 100644 (file)
index 0000000..ec105f9
--- /dev/null
@@ -0,0 +1,184 @@
+/* $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);
+}
diff --git a/servers/slapd/back-perl/modify.c b/servers/slapd/back-perl/modify.c
new file mode 100644 (file)
index 0000000..2d0fb98
--- /dev/null
@@ -0,0 +1,109 @@
+/* $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 );
+}
+
diff --git a/servers/slapd/back-perl/modrdn.c b/servers/slapd/back-perl/modrdn.c
new file mode 100644 (file)
index 0000000..32db575
--- /dev/null
@@ -0,0 +1,98 @@
+/* $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 );
+}
diff --git a/servers/slapd/back-perl/perl_back.h b/servers/slapd/back-perl/perl_back.h
new file mode 100644 (file)
index 0000000..2323644
--- /dev/null
@@ -0,0 +1,53 @@
+/* $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
diff --git a/servers/slapd/back-perl/search.c b/servers/slapd/back-perl/search.c
new file mode 100644 (file)
index 0000000..dea77e5
--- /dev/null
@@ -0,0 +1,141 @@
+/* $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;
+}
+
diff --git a/servers/slapd/back-sql/util.c b/servers/slapd/back-sql/util.c
new file mode 100644 (file)
index 0000000..00e1d33
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *      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 */
index 06016c0a7692d8d1ef159192d59cd77bb6d1acdf..286531681413c5b69ba5a3756f1fe10b90dfa8ef 100644 (file)
@@ -2222,7 +2222,7 @@ read_config( const char *fname )
                        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,
index 450691d326a5c076b48dfc116a07b0e8f5f409b5..40064a47fa3af42d25058f4d0d76ba65e3371d52 100644 (file)
@@ -829,3 +829,40 @@ dnIsSuffix(
        /* 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;
+}
index fa1bb4916d5b4800840461b1dd2c214628f4278b..62249eeaf2ab5a3f63e9e3e2b98d9d10fe1111c9 100644 (file)
@@ -88,6 +88,7 @@ static int   cnvt_str2int( char *, STRDISP_P, int );
 
 #endif /* LOG_LOCAL4 */
 
+static int check_config = 0;
 
 static void
 usage( char *name )
@@ -95,22 +96,23 @@ 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
     );
 }
@@ -213,7 +215,7 @@ int main( int argc, char **argv )
 #endif
 
        while ( (i = getopt( argc, argv,
-                            "d:f:h:s:n:"
+                            "d:f:h:s:n:t"
 #ifdef HAVE_CHROOT
                                "r:"
 #endif
@@ -280,6 +282,10 @@ int main( int argc, char **argv )
                        serverName = ch_strdup( optarg );
                        break;
 
+               case 't':
+                       check_config++;
+                       break;
+
                default:
                        usage( argv[0] );
                        rc = 1;
@@ -319,7 +325,7 @@ int main( int argc, char **argv )
        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;
@@ -378,6 +384,17 @@ int main( int argc, char **argv )
        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;
        }
 
index f3d6a8b0b346478505805e4e893fbcae63879699..0e0939eac9ee01c53b1621f1fae45e5139ca1fc0 100644 (file)
@@ -404,6 +404,8 @@ LDAP_SLAPD_F (void) build_new_dn LDAP_P((
 
 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
  */
index d3caa3ffd4a0c39c767160ae4fc48ea1f04d1a92..53edf251fba585d36abccdac5f419b604b499240 100644 (file)
@@ -314,7 +314,7 @@ BerVarray get_entry_referrals(
 
                /* 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;
index 8c96ff0239683f6f1b0d69de9297b65ec2e695af..4343f90794cec7729ff25b0d62fa4b9bfbc0f9c8 100644 (file)
@@ -594,10 +594,15 @@ send_search_result(
                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);
index 4876c076f8dada7137043cdefa924744fa580e7d..87f29735aa7394ed3eb00b9b33cc563f2d3d0a3d 100644 (file)
@@ -38,7 +38,6 @@
 #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
 
@@ -130,6 +129,10 @@ slap_sasl_log(
    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
@@ -137,11 +140,11 @@ slap_sasl_log(
 
 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;
 
@@ -166,7 +169,7 @@ int slap_sasl_getdn( Connection *conn, char *id,
                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 ) {
@@ -176,9 +179,9 @@ int slap_sasl_getdn( Connection *conn, char *id,
                        && 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 {
@@ -246,12 +249,13 @@ int slap_sasl_getdn( Connection *conn, char *id,
        }
 
        /* 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 ));
@@ -262,10 +266,7 @@ int slap_sasl_getdn( Connection *conn, char *id,
                }
        }
 
-       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 ) {
@@ -275,16 +276,6 @@ int slap_sasl_getdn( Connection *conn, char *id,
                *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 );
 }
 
@@ -306,11 +297,12 @@ slap_sasl_checkpass(
        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;
@@ -388,7 +380,7 @@ slap_sasl_canonicalize(
                        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 ) );
@@ -441,7 +433,7 @@ slap_sasl_authorize(
        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,
@@ -456,11 +448,19 @@ slap_sasl_authorize(
        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] = '@';
@@ -480,11 +480,14 @@ slap_sasl_authorize(
                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] = '@';
@@ -537,15 +540,15 @@ slap_sasl_authorize(
 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;
 
@@ -579,7 +582,17 @@ slap_sasl_authorize(
 
        /* 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;
@@ -598,7 +611,14 @@ slap_sasl_authorize(
                *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 );
@@ -1088,30 +1108,23 @@ int slap_sasl_bind(
                                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 ) {
index 2f9ee9b74a12e514870cf7f731254c7ce675bb96..c13726b0b1a4613f805d84eea7e6c1546c372408 100644 (file)
@@ -164,7 +164,7 @@ int slap_sasl_regexp_config( const char *match, const char *replace )
        reg->sr_offset[0] = -2;
        n = 1;
        for ( c = reg->sr_replace;       *c;  c++ ) {
-               if ( *c == '\\' ) {
+               if ( *c == '\\' && c[1] ) {
                        c++;
                        continue;
                }
@@ -546,7 +546,7 @@ CONCLUDED:
  * 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)
@@ -555,7 +555,6 @@ slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct b
        int i, rc;
        BerVarray vals=NULL;
        AttributeDescription *ad=NULL;
-       struct berval bv;
 
 #ifdef NEW_LOGGING
        LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
@@ -571,17 +570,13 @@ slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct b
        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;
        }
@@ -604,7 +599,8 @@ 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 };
index 8695cd8fe63855189fc1f100c9bf0ab59143a48e..85e9f2526fc379d8fc47d5b49dcf0c8cad9152e7 100644 (file)
@@ -98,11 +98,11 @@ static const struct MatchingRulePtr {
 };
 
 
-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;
        
@@ -3421,7 +3421,7 @@ char digit[] = "0123456789";
  */
 
 static struct berval *
-asn1_integer2str(ASN1_INTEGER *a)
+asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
 {
        char buf[256];
        char *p;
@@ -3477,35 +3477,17 @@ asn1_integer2str(ASN1_INTEGER *a)
                *--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 );
 }
 
 /*
@@ -3519,9 +3501,8 @@ certificateExactConvert(
 {
        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 ) {
@@ -3537,39 +3518,27 @@ certificateExactConvert(
                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
@@ -3582,8 +3551,8 @@ certificateExactConvert(
                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;
 }
@@ -3591,8 +3560,8 @@ certificateExactConvert(
 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;
@@ -3617,18 +3586,20 @@ serial_and_issuer_parse(
 
        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;
 }
@@ -3644,10 +3615,10 @@ certificateExactMatch(
 {
        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);
@@ -3664,8 +3635,8 @@ certificateExactMatch(
                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);
 
@@ -3678,8 +3649,8 @@ certificateExactMatch(
                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 */
@@ -3688,29 +3659,29 @@ certificateExactMatch(
                                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;
 }
@@ -3733,7 +3704,7 @@ static int certificateExactIndexer(
        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 );
@@ -3762,12 +3733,12 @@ static int certificateExactIndexer(
                        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",
@@ -3797,20 +3768,18 @@ static int certificateExactFilter(
        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
index 7a8261e8492b7cfe799ddf915243dc2d62352450..db08952915a0d66188748d17a490132927c1725f 100644 (file)
@@ -1,3 +1,8 @@
+/* $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;
@@ -59,17 +59,21 @@ slurpd_read_config(
 )
 {
     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;
@@ -79,7 +83,12 @@ slurpd_read_config(
            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 );
 
@@ -101,23 +110,57 @@ slurpd_read_config(
                        "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;
 }
 
@@ -178,11 +221,13 @@ strtok_quote(
            } 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:
@@ -230,13 +275,17 @@ getline(
     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';
@@ -261,13 +310,13 @@ add_replica(
            ( 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 ) {
@@ -280,17 +329,25 @@ add_replica(
        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 );
        }
     }
 }
@@ -301,7 +358,7 @@ add_replica(
  * 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
@@ -309,12 +366,10 @@ add_replica(
  *
  * <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
@@ -324,6 +379,8 @@ add_replica(
 #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,
@@ -336,56 +393,86 @@ parse_replica_line(
     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 );
            }
@@ -396,11 +483,19 @@ parse_replica_line(
                    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;
 }
 
index 2d36838bb549dc4ed3086f44bcf955af03d370a6..36fab6540e346a8588ca56e9adb4f3c1fcfeffea 100644 (file)
@@ -1,3 +1,8 @@
+/* $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));
 
 
 /*
@@ -68,7 +47,7 @@ extern char *sys_errlist[];
  *  - 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
 )
@@ -77,15 +56,16 @@ fm(
 
     /* 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 )) {
@@ -96,7 +76,7 @@ fm(
                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
@@ -111,21 +91,31 @@ fm(
     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 */
@@ -136,16 +126,27 @@ fm(
            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;
 }
 
 
@@ -154,22 +155,20 @@ fm(
 /*
  * 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 */
 }
 
 
@@ -178,10 +177,10 @@ set_shutdown()
 /*
  * 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 );
 }
 
 
@@ -197,13 +196,18 @@ populate_queue(
 )
 {
     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;
     }
 
@@ -212,11 +216,16 @@ populate_queue(
      * 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;
@@ -224,14 +233,21 @@ populate_queue(
            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 );
 }
     
@@ -256,13 +272,13 @@ get_record(
 
     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 );
 }
-
index 4d676fe4523cacbdba673d9998b28a5eb780f328..2d63daefaff57867eb8b3a75a60f4079e6856724 100644 (file)
@@ -84,47 +84,77 @@ do_ldap(
                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;
                }
 
@@ -190,16 +220,27 @@ op_ldap_add(
        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 ); 
@@ -235,8 +276,13 @@ op_ldap_modify(
 
     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;
     }
 
@@ -283,9 +329,14 @@ op_ldap_modify(
            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;
            }
 
@@ -296,9 +347,16 @@ op_ldap_modify(
             * 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 ** )
@@ -316,8 +374,14 @@ op_ldap_modify(
 
     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 );
@@ -339,8 +403,14 @@ op_ldap_delete(
 {
     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 );
@@ -376,8 +446,13 @@ op_ldap_modrdn(
 
     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;
     }
 
@@ -387,9 +462,15 @@ op_ldap_modrdn(
     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;
                }
@@ -399,9 +480,15 @@ op_ldap_modrdn(
 
        } 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;
                }
@@ -412,18 +499,30 @@ op_ldap_modrdn(
            } 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;
                }
@@ -432,8 +531,14 @@ op_ldap_modrdn(
            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;
        }
@@ -443,8 +548,13 @@ op_ldap_modrdn(
      * 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;
     }
@@ -457,9 +567,15 @@ op_ldap_modrdn(
        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 */
@@ -592,9 +708,15 @@ do_unbind(
     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;
     }
@@ -625,27 +747,48 @@ do_bind(
     *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 );
     }
 
@@ -655,9 +798,15 @@ do_bind(
                        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;
@@ -674,9 +823,15 @@ do_bind(
                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;
@@ -689,10 +844,17 @@ do_bind(
                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 );
@@ -707,14 +869,26 @@ do_bind(
        /*
         * 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;
@@ -723,8 +897,14 @@ do_bind(
        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 ) {
@@ -733,9 +913,15 @@ do_bind(
                        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;
@@ -751,8 +937,14 @@ do_bind(
                    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;
@@ -763,19 +955,31 @@ do_bind(
                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 );
@@ -796,9 +1000,15 @@ do_bind(
                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;
@@ -827,6 +1037,17 @@ dump_ldm_array(
 
     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 );
@@ -836,13 +1057,19 @@ dump_ldm_array(
        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 );
            }
        }
index 62aab06784b37f5acd99621aa00da0c789b69a70..d457cdfc21ae62aa655692e0bef074e06d05c21f 100644 (file)
@@ -1,3 +1,8 @@
+/* $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
 )
 {
@@ -42,29 +50,31 @@ lock_fopen(
        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 );
        }
 
@@ -80,11 +90,7 @@ lock_fclose(
 )
 {
        /* 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 ) );
@@ -97,15 +103,21 @@ lock_fclose(
  */
 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 );
@@ -119,15 +131,21 @@ acquire_lock(
  */
 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 );
index 19949128d31d294996029b9619ad24eadaa91e8a..7a391221b50530b28aecb430a00223010e47df59 100644 (file)
@@ -120,8 +120,13 @@ main(
     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 );
 
     }
@@ -157,7 +162,12 @@ main(
     /* 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 */
 }
index 4a6dc382377247c1da34ff330d9170a69c274e01..7fd254893cf6b7ba015ca22ae2a2e17909f3d441 100644 (file)
@@ -1,3 +1,8 @@
+/* $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 */
@@ -62,6 +66,7 @@ Re_getnext(
 
 /*
  * Free an Re
+ * ??? Something should apparently return nonzero here, but I dont know what.
  */
 static int
 Re_free(
@@ -76,15 +81,18 @@ 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 );
@@ -100,6 +108,7 @@ Re_free(
        free( mi );
     }
     free( re );
+    return 0;
 }
 
 
@@ -125,17 +134,25 @@ Re_parse(
     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;
     }
 
@@ -147,7 +164,7 @@ Re_parse(
     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;
        }
        /*
@@ -158,11 +175,16 @@ Re_parse(
        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 )) {
@@ -175,46 +197,71 @@ Re_parse(
                /* 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;
            }
        }
@@ -222,7 +269,9 @@ Re_parse(
            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;
@@ -231,6 +280,11 @@ Re_parse(
        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;
 }
@@ -252,10 +306,10 @@ get_repl_hosts(
     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;
@@ -274,7 +328,7 @@ get_repl_hosts(
     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;
            }
@@ -282,14 +336,14 @@ get_repl_hosts(
        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++;
@@ -309,20 +363,31 @@ get_repl_hosts(
                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 ) {
@@ -430,12 +495,16 @@ Re_dump(
     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++ ) {
@@ -494,11 +563,15 @@ Re_write(
     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;
     }
 
@@ -522,7 +595,7 @@ Re_write(
            }
        }
     }
-    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;
     }
@@ -563,7 +636,8 @@ Re_write(
            }
        } 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 ) {
@@ -571,7 +645,7 @@ Re_write(
                free( obuf );
                goto bad;
            } else {
-               free( obuf );
+               ber_memfree( obuf );
            }
        }
     }
@@ -585,8 +659,13 @@ Re_write(
     }
 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;
 }
@@ -638,7 +717,7 @@ Re_lock(
     Re *re
 )
 {
-    return( pthread_mutex_lock( &re->re_mutex ));
+    return( ldap_pvt_thread_mutex_lock( &re->re_mutex ));
 }
 
 
@@ -652,7 +731,7 @@ Re_unlock(
     Re *re
 )
 {
-    return( pthread_mutex_unlock( &re->re_mutex ));
+    return( ldap_pvt_thread_mutex_unlock( &re->re_mutex ));
 }
 
 
@@ -685,7 +764,7 @@ Re_init(
 
     /* 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;
@@ -693,7 +772,7 @@ Re_init(
    (*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;
 }
 
@@ -723,9 +802,15 @@ warn_unknown_replica(
        }
     }
     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 );
index 8ae0dc63635728ca298566a8cced943f1ff4d134..d3346cf50902bd53205307c82ea02e22b170ee93 100644 (file)
@@ -1,3 +1,8 @@
+/* $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"
@@ -52,7 +55,7 @@ write_reject(
     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 );
 
@@ -61,18 +64,29 @@ write_reject(
        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 ) {
@@ -81,16 +95,26 @@ write_reject(
            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;
 }
 
index ed25a629077031feed19d6dee387adaea5b66f1b..9bb77ca8ef7dfcc190dec778c33aca82d8c4120f 100644 (file)
@@ -1,3 +1,8 @@
+/* $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.
@@ -15,6 +20,7 @@
  * 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;
 }
 
 
@@ -54,18 +71,19 @@ start_replica_thread(
     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;
 }
index c3a855cffecbc626a00d2c67b443c74213c40e73..a93f9040d50b194570c85bcc2e8d16e59a3265eb 100644 (file)
@@ -1,3 +1,8 @@
+/* $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.
@@ -83,9 +57,14 @@ copy_replog(
     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
@@ -98,9 +77,15 @@ copy_replog(
        *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 );
@@ -110,28 +95,46 @@ copy_replog(
        *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 );
     }
 
@@ -147,15 +150,25 @@ copy_replog(
        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 );
 }
index a805060a98f0672683e25c0127854154cd7d09a5..5dbdaf855d6e53f3d233407c21202ed89f2e6e5a 100644 (file)
@@ -55,7 +55,12 @@ Ri_process(
     (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;
     }
 
@@ -85,22 +90,40 @@ Ri_process(
        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: {
@@ -122,8 +145,13 @@ Ri_process(
                }
            }
        } 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 &&
index 54adb4da1af77e4fd26db6da62d375ea781e94c6..37098c9f3649e23aa29a1a943c8d63350d922039 100644 (file)
@@ -1,3 +1,8 @@
+/* $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"
 
 
 /*
@@ -56,13 +64,10 @@ Rq_lock(
     Rq *rq
 )
 {
-    return( pthread_mutex_lock( &rq->rq_mutex ));
+    return( ldap_pvt_thread_mutex_lock( &rq->rq_mutex ));
 }
 
 
-
-
-
 /*
  * Unlock the replication queue.
  */
@@ -71,7 +76,7 @@ Rq_unlock(
     Rq *rq
 )
 {
-    return( pthread_mutex_unlock( &rq->rq_mutex ));
+    return( ldap_pvt_thread_mutex_unlock( &rq->rq_mutex ));
 }
 
 
@@ -89,8 +94,6 @@ Rq_gethead(
 }
 
 
-
-
 /*
  * Return the next item in the queue.  Callers should lock the queue before
  * calling this routine.
@@ -108,8 +111,6 @@ Rq_getnext(
 }
 
 
-
-
 /*
  * Delete the item at the head of the list.  The queue should be locked
  * by the caller before calling this routine.
@@ -132,8 +133,13 @@ Rq_delhead(
     }
 
     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 );
     }
 
@@ -144,8 +150,6 @@ Rq_delhead(
 }
 
 
-
-
 /* 
  * Add an entry to the tail of the replication queue.  Locking is handled
  * internally.  When items are added to the queue, this routine wakes
@@ -188,7 +192,7 @@ Rq_add(
 
     /* 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.
@@ -200,7 +204,7 @@ Rq_add(
     /* 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 );
@@ -209,8 +213,6 @@ Rq_add(
 }
 
 
-
-
 /*
  * Garbage-collect the replication queue.  Locking is handled internally.
  */
@@ -220,7 +222,11 @@ Rq_gc(
 )
 {
     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 ); 
@@ -234,7 +240,6 @@ Rq_gc(
 }
 
 
-
 /*
  * For debugging: dump the contents of the replication queue to a file.
  * Locking is handled internally.
@@ -246,15 +251,45 @@ Rq_dump(
 {
     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;
     }
 
@@ -268,7 +303,6 @@ Rq_dump(
 }
 
 
-
 /*
  * Write the contents of a replication queue to a file.  Returns zero if
  * successful, -1 if not.  Handles queue locking internally.  Callers should
@@ -287,8 +321,13 @@ Rq_write(
        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
@@ -306,8 +345,13 @@ Rq_write(
     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 );
@@ -317,8 +361,6 @@ Rq_write(
 }
 
 
-
-
 /*
  * Check to see if the private slurpd replication log needs trimming.
  * The current criteria are:
@@ -335,8 +377,6 @@ Rq_needtrim(
 )
 {
     int                rc = 0;
-    Re         *re;
-    int                nzrc = 0;       /* nzrc is count of entries with refcnt == 0 */
     time_t     now;
 
     if ( rq == NULL ) {
@@ -380,7 +420,7 @@ Rq_getcount(
        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++;
                }
            }
@@ -391,8 +431,6 @@ Rq_getcount(
 }
 
 
-
-
 /* 
  * Allocate and initialize an Rq object.
  */
@@ -421,8 +459,8 @@ Rq_init(
     (*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;
@@ -431,4 +469,3 @@ Rq_init(
 
     return 0;
 }
-
index 610b29585342e2b4205d82ed080288b4448f2934..ffe150ea241b505aa705b89e42a3e39f5a164e49 100644 (file)
@@ -1,3 +1,8 @@
+/* $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.
@@ -46,29 +49,28 @@ St_add(
     }
 
     /* 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 ];
 }
 
@@ -89,17 +91,23 @@ St_write (
     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 {
@@ -112,12 +120,13 @@ St_write (
     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;
 }
@@ -139,10 +148,10 @@ St_update(
        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;
 }
 
@@ -168,24 +177,36 @@ St_read(
     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 ) {
@@ -217,7 +238,7 @@ St_read(
            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;
            }
@@ -226,21 +247,32 @@ St_read(
            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;
 }
     
@@ -255,7 +287,7 @@ St_lock(
     St *st
 )
 {
-    return( pthread_mutex_lock( &st->st_mutex ));
+    return( ldap_pvt_thread_mutex_lock( &st->st_mutex ));
 }
 
 
@@ -269,7 +301,7 @@ St_unlock(
     St *st
 )
 {
-    return( pthread_mutex_unlock( &st->st_mutex ));
+    return( ldap_pvt_thread_mutex_unlock( &st->st_mutex ));
 }
 
 
@@ -292,7 +324,7 @@ St_init(
        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;