diff --git a/clients/maildap/main.c b/clients/maildap/main.c new file mode 100644 index 0000000000000000000000000000000000000000..345c8f4256853b9cc02df766d1e89b3cd15ea8d8 --- /dev/null +++ b/clients/maildap/main.c @@ -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 = ¤t_group->g_members; + current_nto = ¤t_group->g_nmembers; + split_address( address, + &localpart, &domainpart ); + if ( domainpart ) { + sprintf( buf, "%s-%s@%s", + localpart, ERRORS, + domainpart ); + free( localpart ); + free( domainpart ); + } else { + sprintf( buf, "%s-%s@%s", + localpart, ERRORS, + host ); + free( localpart ); + } + current_group->g_errorsto = strdup( buf ); + } + break; + + case AS_KIND_REQUEST: + cur_priority = as->as_priority; + /* This is a group with special processing */ + if ( type & GROUP_REQUEST ) { + add_to( current_to, current_nto, vals ); + resolved = 1; + } + break; + + case AS_KIND_OWNER: + cur_priority = as->as_priority; + /* This is a group with special processing */ + if ( type & GROUP_REQUEST ) { + add_to( current_to, current_nto, vals ); + resolved = 1; + } + break; + + case AS_KIND_ROUTE_TO_HOST: + if ( !is_my_host( vals[0] ) ) { + cur_priority = as->as_priority; + if ( as->as_syntax == AS_SYNTAX_PRESENT ) { + needs_mta_routing = 1; + } else { + route_to_host = strdup( vals[0] ); + } + } + break; + + case AS_KIND_ROUTE_TO_ADDR: + for ( j=0; j<own_addresses_total; j++ ) { + if ( strcasecmp( vals[0], own_addresses[j] ) ) { + cur_priority = as->as_priority; + if ( as->as_syntax == AS_SYNTAX_PRESENT ) { + needs_mta_routing = 1; + } else { + route_to_address = strdup( vals[0] ); + } + } + break; + } + + case AS_KIND_OWN_ADDR: + add_to( &own_addresses, &own_addresses_total, vals ); + cur_priority = as->as_priority; + break; + + case AS_KIND_DELIVERY_TYPE: + add_to( &delivery_types, &delivery_types_total, vals ); + cur_priority = as->as_priority; + break; + + default: + syslog( LOG_ALERT, + "Invalid kind %d", as->as_kind ); + /* Error, TBC */ + } + ldap_value_free( vals ); + } + /* + * Now check if we are dealing with mail routing. We support + * two modes. + * + * The first mode and by far the most robust method is doing + * routing at the MTA. In this case, we just checked if the + * routing attributes were present and did not seem like + * pointing to ourselves. The only thing we have to do here + * is adding to the recipient list any of the RFC822 addresses + * of this entry. That means we needed to retrieve them from + * the entry itself because we might have arrived here through + * some directory search. The address received as argument is + * not the address of the entry we are processing, but rather + * the RFC822 address we are expanding now. Unfortunately, + * this requires an MTA that understands LDAP routing. + * Sendmail 8.10.0 does, if compiled properly. + * + * The second method, that is most emphatically not recommended + * is routing in maildap. This is going to require using the + * percent hack. Moreover, this may occasionally loop. + */ + if ( needs_mta_routing ) { + if ( !own_addresses ) { + add_error( err, nerr, E_NOOWNADDRESS, address, e ); + return( 0 ); + } + nvals[0] = own_addresses[0]; /* Anyone will do */ + nvals[1] = NULL; + add_to( current_to, current_nto, nvals ); + resolved = 1; + } else if ( route_to_host ) { + char *p; + if ( !route_to_address ) { + if ( !own_addresses ) { + add_error( err, nerr, E_NOOWNADDRESS, address, e ); + return( 0 ); + } + route_to_address = strdup( own_addresses[0] ); + } + /* This makes use of the percent hack, but there's no choice */ + p = strchr( route_to_address, '@' ); + if ( p ) { + *p = '%'; + } + sprintf( buf, "%s@%s", route_to_address, route_to_host ); + nvals[0] = buf; + nvals[1] = NULL; + add_to( current_to, current_nto, nvals ); + resolved = 1; + free( route_to_host ); + free( route_to_address ); + } else if ( route_to_address ) { + nvals[0] = route_to_address; + nvals[1] = NULL; + add_to( current_to, current_nto, nvals ); + resolved = 1; + free( route_to_address ); + } + if ( own_addresses ) { + ldap_value_free( own_addresses ); + } + if ( delivery_types ) { + ldap_value_free( delivery_types ); + } + + return( resolved ); +} + +static int +search_bases( + char *filter, + Subst *substs, + char *name, + char ***to, + int *nto, + Group ***togroups, + int *ngroups, + Error **err, + int *nerr, + int type +) +{ + int b, resolved = 0; + + for ( b = 0; base[b] != NULL; b++ ) { + + if ( ! (base[b]->b_search & type) ) { + continue; + } + + resolved = search_ldap_url( base[b]->b_url, substs, name, + base[b]->b_rdnpref, + base[b]->b_m_entries, + to, nto, togroups, ngroups, + err, nerr, type ); + if ( resolved ) + break; + } + return( resolved ); +} + +static void +do_address( + char *name, + char ***to, + int *nto, + Group ***togroups, + int *ngroups, + Error **err, + int *nerr, + int type +) +{ + char *localpart = NULL, *domainpart = NULL; + char *synthname = NULL; + int resolved; + int i; + Subst substs[6]; + + /* + * Look up the name in X.500, add the appropriate addresses found + * to the to list, or to the err list in case of error. Groups are + * handled by the do_group routine, individuals are handled here. + * When looking up name, we follow the bases hierarchy, looking + * in base[0] first, then base[1], etc. For each base, there is + * a set of search filters to try, in order. If something goes + * wrong here trying to contact X.500, we exit with EX_TEMPFAIL. + * If the b_rdnpref flag is set, then we give preference to entries + * that matched name because it's their rdn, otherwise not. + */ + + split_address( name, &localpart, &domainpart ); + synthname = strdup( localpart ); + for ( i = 0; synthname[i] != '\0'; i++ ) { + if ( synthname[i] == '.' || synthname[i] == '_' ) + synthname[i] = ' '; + } + substs[0].sub_char = 'm'; + substs[0].sub_value = name; + substs[1].sub_char = 'h'; + substs[1].sub_value = host; + substs[2].sub_char = 'l'; + substs[2].sub_value = localpart; + substs[3].sub_char = 'd'; + substs[3].sub_value = domainpart; + substs[4].sub_char = 's'; + substs[4].sub_value = synthname; + substs[5].sub_char = '\0'; + substs[5].sub_value = NULL; + + resolved = search_bases( NULL, substs, name, + to, nto, togroups, ngroups, + err, nerr, type ); + + if ( localpart ) { + free( localpart ); + } + if ( domainpart ) { + free( domainpart ); + } + if ( synthname ) { + free( synthname ); + } + + if ( !resolved ) { + /* not resolved - bounce with user unknown */ + if ( type == USER ) { + add_error( err, nerr, E_USERUNKNOWN, name, NULL ); + } else { + add_error( err, nerr, E_GROUPUNKNOWN, name, NULL ); + } + } +} + +static void +send_message( char **to ) +{ + int pid; +#ifndef HAVE_WAITPID + WAITSTATUSTYPE status; +#endif + + if ( debug ) { + char buf[1024]; + int i; + + strcpy( buf, to[0] ); + for ( i = 1; to[i] != NULL; i++ ) { + strcat( buf, " " ); + strcat( buf, to[i] ); + } + + syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf ); + } + + /* parent */ + if ( (pid = fork()) != 0 ) { +#ifdef HAVE_WAITPID + waitpid( pid, (int *) NULL, 0 ); +#else + wait4( pid, &status, WAIT_FLAGS, 0 ); +#endif + /* child */ + } else { + /* to includes sendmailargs */ + execv( MAIL500_SENDMAIL, to ); + + syslog( LOG_ALERT, "execv failed" ); + + exit( EX_TEMPFAIL ); + } +} + +static void +send_group( Group **group, int ngroup ) +{ + int i, pid; + char **argv; + int argc; + char *iargv[7]; +#ifndef HAVE_WAITPID + WAITSTATUSTYPE status; +#endif + + for ( i = 0; i < ngroup; i++ ) { + (void) rewind( stdin ); + + iargv[0] = MAIL500_SENDMAIL; + iargv[1] = "-f"; + iargv[2] = group[i]->g_errorsto; + iargv[3] = "-oMrX.500"; + iargv[4] = "-odi"; + iargv[5] = "-oi"; + iargv[6] = NULL; + + argv = NULL; + argc = 0; + add_to( &argv, &argc, iargv ); + add_to( &argv, &argc, group[i]->g_members ); + + if ( debug ) { + char buf[1024]; + int i; + + strcpy( buf, argv[0] ); + for ( i = 1; i < argc; i++ ) { + strcat( buf, " " ); + strcat( buf, argv[i] ); + } + + syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); + } + + /* parent */ + if ( (pid = fork()) != 0 ) { +#ifdef HAVE_WAITPID + waitpid( pid, (int *) NULL, 0 ); +#else + wait4( pid, &status, WAIT_FLAGS, 0 ); +#endif + /* child */ + } else { + execv( MAIL500_SENDMAIL, argv ); + + syslog( LOG_ALERT, "execv failed" ); + + exit( EX_TEMPFAIL ); + } + } +} + +static void +send_errors( Error *err, int nerr ) +{ + int pid, i, namelen; + FILE *fp; + int fd[2]; + char *argv[8]; + char buf[1024]; +#ifndef HAVE_WAITPID + WAITSTATUSTYPE status; +#endif + + if ( strcmp( MAIL500_BOUNCEFROM, mailfrom ) == 0 ) { + mailfrom = errorsfrom; + } + + argv[0] = MAIL500_SENDMAIL; + argv[1] = "-oMrX.500"; + argv[2] = "-odi"; + argv[3] = "-oi"; + argv[4] = "-f"; + argv[5] = MAIL500_BOUNCEFROM; + argv[6] = mailfrom; + argv[7] = NULL; + + if ( debug ) { + int i; + + strcpy( buf, argv[0] ); + for ( i = 1; argv[i] != NULL; i++ ) { + strcat( buf, " " ); + strcat( buf, argv[i] ); + } + + syslog( LOG_ALERT, "execing sendmail: (%s)", buf ); + } + + if ( pipe( fd ) == -1 ) { + syslog( LOG_ALERT, "cannot create pipe" ); + exit( EX_TEMPFAIL ); + } + + if ( (pid = fork()) != 0 ) { + if ( (fp = fdopen( fd[1], "w" )) == NULL ) { + syslog( LOG_ALERT, "cannot fdopen pipe" ); + exit( EX_TEMPFAIL ); + } + + fprintf( fp, "To: %s\n", mailfrom ); + fprintf( fp, "From: %s\n", errorsfrom ); + fprintf( fp, "Subject: undeliverable mail\n" ); + fprintf( fp, "\n" ); + fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" ); + for ( i = 0; i < nerr; i++ ) { + namelen = strlen( err[i].e_addr ); + fprintf( fp, "\n" ); + + switch ( err[i].e_code ) { + case E_USERUNKNOWN: + fprintf( fp, "%s: User unknown\n", err[i].e_addr ); + break; + + case E_GROUPUNKNOWN: + fprintf( fp, "%s: Group unknown\n", err[i].e_addr ); + break; + + case E_BADMEMBER: + fprintf( fp, "%s: Group member does not exist\n", + err[i].e_addr ); + fprintf( fp, "This could be because the distinguished name of the person has changed\n" ); + fprintf( fp, "If this is the case, the problem can be solved by removing and\n" ); + fprintf( fp, "then re-adding the person to the group.\n" ); + break; + + case E_NOREQUEST: + fprintf( fp, "%s: Group exists but has no request address\n", + err[i].e_addr ); + break; + + case E_NOERRORS: + fprintf( fp, "%s: Group exists but has no errors-to address\n", + err[i].e_addr ); + break; + + case E_NOOWNER: + fprintf( fp, "%s: Group exists but has no owner\n", + err[i].e_addr ); + break; + + case E_AMBIGUOUS: + do_ambiguous( fp, &err[i], namelen ); + break; + + case E_NOEMAIL: + do_noemail( fp, &err[i], namelen ); + break; + + case E_MEMBERNOEMAIL: + fprintf( fp, "%s: Group member exists but does not have an email address\n", + err[i].e_addr ); + break; + + case E_JOINMEMBERNOEMAIL: + fprintf( fp, "%s: User has joined group but does not have an email address\n", + err[i].e_addr ); + break; + + case E_LOOP: + fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n", + err[i].e_addr, err[i].e_loop ); + break; + + case E_NOMEMBERS: + fprintf( fp, "%s: Group has no members\n", + err[i].e_addr ); + break; + + case E_NOOWNADDRESS: + fprintf( fp, "%s: Not enough information to perform required routing\n", + err[i].e_addr ); + break; + + default: + syslog( LOG_ALERT, "unknown error %d", err[i].e_code ); + unbind_and_exit( EX_TEMPFAIL ); + break; + } + } + + fprintf( fp, "\n------- The original message sent:\n\n" ); + + while ( fgets( buf, sizeof(buf), stdin ) != NULL ) { + fputs( buf, fp ); + } + fclose( fp ); + +#ifdef HAVE_WAITPID + waitpid( pid, (int *) NULL, 0 ); +#else + wait4( pid, &status, WAIT_FLAGS, 0 ); +#endif + } else { + dup2( fd[0], 0 ); + + execv( MAIL500_SENDMAIL, argv ); + + syslog( LOG_ALERT, "execv failed" ); + + exit( EX_TEMPFAIL ); + } +} + +static void +do_noemail( FILE *fp, Error *err, int namelen ) +{ + int i, last; + char *dn, *rdn; + char **ufn, **vals; + + fprintf(fp, "%s: User has no email address registered.\n", + err->e_addr ); + fprintf( fp, "%*s Name, title, postal address and phone for '%s':\n\n", + namelen, " ", err->e_addr ); + + /* name */ + dn = ldap_get_dn( ld, err->e_msg ); + ufn = ldap_explode_dn( dn, 1 ); + rdn = strdup( ufn[0] ); + if ( strcasecmp( rdn, err->e_addr ) == 0 ) { + if ( (vals = ldap_get_values( ld, err->e_msg, "cn" )) + != NULL ) { + for ( i = 0; vals[i]; i++ ) { + last = strlen( vals[i] ) - 1; + if ( isdigit((unsigned char) vals[i][last]) ) { + rdn = strdup( vals[i] ); + break; + } + } + + ldap_value_free( vals ); + } + } + fprintf( fp, "%*s %s\n", namelen, " ", rdn ); + free( dn ); + free( rdn ); + ldap_value_free( ufn ); + + /* titles or descriptions */ + if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL && + (vals = ldap_get_values( ld, err->e_msg, "description" )) + == NULL ) { + fprintf( fp, "%*s No title or description registered\n", + namelen, " " ); + } else { + for ( i = 0; vals[i] != NULL; i++ ) { + fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); + } + + ldap_value_free( vals ); + } + + /* postal address */ + if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" )) + == NULL ) { + fprintf( fp, "%*s No postal address registered\n", namelen, + " " ); + } else { + fprintf( fp, "%*s ", namelen, " " ); + for ( i = 0; vals[0][i] != '\0'; i++ ) { + if ( vals[0][i] == '$' ) { + fprintf( fp, "\n%*s ", namelen, " " ); + while ( isspace((unsigned char) vals[0][i+1]) ) + i++; + } else { + fprintf( fp, "%c", vals[0][i] ); + } + } + fprintf( fp, "\n" ); + + ldap_value_free( vals ); + } + + /* telephone number */ + if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" )) + == NULL ) { + fprintf( fp, "%*s No phone number registered\n", namelen, + " " ); + } else { + for ( i = 0; vals[i] != NULL; i++ ) { + fprintf( fp, "%*s %s\n", namelen, " ", vals[i] ); + } + + ldap_value_free( vals ); + } +} + +/* ARGSUSED */ +static void +do_ambiguous( FILE *fp, Error *err, int namelen ) +{ + int i, last; + char *dn, *rdn; + char **ufn, **vals; + LDAPMessage *e; + + i = ldap_result2error( ld, err->e_msg, 0 ); + + fprintf( fp, "%s: Ambiguous user. %s%d matches found:\n\n", + err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "", + ldap_count_entries( ld, err->e_msg ) ); + + for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL; + e = ldap_next_entry( ld, e ) ) { + dn = ldap_get_dn( ld, e ); + ufn = ldap_explode_dn( dn, 1 ); + rdn = strdup( ufn[0] ); + if ( strcasecmp( rdn, err->e_addr ) == 0 ) { + if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) { + for ( i = 0; vals[i]; i++ ) { + last = strlen( vals[i] ) - 1; + if (isdigit((unsigned char) vals[i][last])) { + rdn = strdup( vals[i] ); + break; + } + } + + ldap_value_free( vals ); + } + } + + /* + if ( isgroup( e ) ) { + vals = ldap_get_values( ld, e, "description" ); + } else { + vals = ldap_get_values( ld, e, "title" ); + } + */ + vals = ldap_get_values( ld, e, "description" ); + + fprintf( fp, " %-20s %s\n", rdn, vals ? vals[0] : "" ); + for ( i = 1; vals && vals[i] != NULL; i++ ) { + fprintf( fp, " %s\n", vals[i] ); + } + + free( dn ); + free( rdn ); + ldap_value_free( ufn ); + if ( vals != NULL ) + ldap_value_free( vals ); + } +} + +static int +count_values( char **list ) +{ + int i; + + for ( i = 0; list && list[i] != NULL; i++ ) + ; /* NULL */ + + return( i ); +} + +static void +add_to( char ***list, int *nlist, char **new ) +{ + int i, nnew, oldnlist; + + nnew = count_values( new ); + + oldnlist = *nlist; + if ( *list == NULL || *nlist == 0 ) { + *list = (char **) malloc( (nnew + 1) * sizeof(char *) ); + *nlist = nnew; + } else { + *list = (char **) realloc( *list, *nlist * sizeof(char *) + + nnew * sizeof(char *) + sizeof(char *) ); + *nlist += nnew; + } + + for ( i = 0; i < nnew; i++ ) + (*list)[i + oldnlist] = strdup( new[i] ); + (*list)[*nlist] = NULL; +} + +static void +add_single_to( char ***list, char *new ) +{ + int nlist; + + if ( *list == NULL ) { + nlist = 0; + *list = (char **) malloc( 2 * sizeof(char *) ); + } else { + nlist = count_values( *list ); + *list = (char **) realloc( *list, + ( nlist + 2 ) * sizeof(char *) ); + } + + (*list)[nlist] = strdup( new ); + (*list)[nlist+1] = NULL; +} + +static int +isgroup( LDAPMessage *e ) +{ + int i, j; + char **oclist; + + if ( !groupclasses ) { + return( 0 ); + } + + oclist = ldap_get_values( ld, e, "objectClass" ); + + for ( i = 0; oclist[i] != NULL; i++ ) { + for ( j = 0; groupclasses[j] != NULL; j++ ) { + if ( strcasecmp( oclist[i], groupclasses[j] ) == 0 ) { + ldap_value_free( oclist ); + return( 1 ); + } + } + } + ldap_value_free( oclist ); + + return( 0 ); +} + +static void +add_error( Error **err, int *nerr, int code, char *addr, LDAPMessage *msg ) +{ + if ( *nerr == 0 ) { + *err = (Error *) malloc( sizeof(Error) ); + } else { + *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) ); + } + + (*err)[*nerr].e_code = code; + (*err)[*nerr].e_addr = strdup( addr ); + (*err)[*nerr].e_msg = msg; + (*nerr)++; +} + +static void +unbind_and_exit( int rc ) +{ + int i; + + if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS ) + syslog( LOG_ALERT, "ldap_unbind failed %d\n", i ); + + exit( rc ); +} diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c index d09b9ad8398b4ece77746f25347a9f5b25db4f40..f55cb80aa15d2bc2bf83bfc057d768979e58e4b8 100644 --- a/clients/tools/ldapmodify.c +++ b/clients/tools/ldapmodify.c @@ -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 index 0000000000000000000000000000000000000000..11a7bfc739e3d7ee2e7ef9b67bf431bf949068a9 --- /dev/null +++ b/doc/man/man3/ldap_schema.3 @@ -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. + diff --git a/doc/man/man8/slapd.8 b/doc/man/man8/slapd.8 index 949f866e68e8176f92f3843e0057aa77df310fe6..4a92d7aad4c324feb46f136c7ca0dd7fdd54b09a 100644 --- a/doc/man/man8/slapd.8 +++ b/doc/man/man8/slapd.8 @@ -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), diff --git a/libraries/liblber/bprint.c b/libraries/liblber/bprint.c index a6ae8ce7ed68337196edc622c1382071d440ba36..23ebf88853e05261216084530eb2f2a0e4ebdffd 100644 --- a/libraries/liblber/bprint.c +++ b/libraries/liblber/bprint.c @@ -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 ] = '.'; diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c index 5f128098d353f079f95da282ee06beb5c46ecb95..d14e893c058357e21e0bffac8a99350001a696cc 100644 --- a/libraries/libldap/cyrus.c +++ b/libraries/libldap/cyrus.c @@ -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 { diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index c99e2a84ff93a43036a1e537d1d7b30116392ca9..5905f43afa1417870e1c8397fd238b1fb052599e 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -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 index 0000000000000000000000000000000000000000..e4ded225fae9c60db866aa19c14febb81e6f7c62 --- /dev/null +++ b/libraries/liblunicode/ucdata/ucdata.c @@ -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 index 0000000000000000000000000000000000000000..2b6712231621c7510099f1acb072212f8cccc7a9 --- /dev/null +++ b/libraries/liblunicode/ucdata/ucgendat.c @@ -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; +} diff --git a/libraries/liblunicode/ucstr.c b/libraries/liblunicode/ucstr.c index f0cc6033221fdedb51faf08ce53657652c9f0abf..18a882111d7506ce6be17d181ad5b0a6bfb09713 100644 --- a/libraries/liblunicode/ucstr.c +++ b/libraries/liblunicode/ucstr.c @@ -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??? */ } diff --git a/libraries/liblutil/passwd.c b/libraries/liblutil/passwd.c index ee9282310cb85f6302e15753d021a00776fdd159..dba06c9b2b1d8e5901726477d4a9755de7e5c901 100644 --- a/libraries/liblutil/passwd.c +++ b/libraries/liblutil/passwd.c @@ -28,7 +28,11 @@ #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 diff --git a/libraries/librewrite/map.c b/libraries/librewrite/map.c index 2180d8907757164816ad4c23e19b8babe54a5fe2..8db54af13711b89701804bb6fdcf5a214cf20012 100644 --- a/libraries/librewrite/map.c +++ b/libraries/librewrite/map.c @@ -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--; } diff --git a/libraries/librewrite/parse.c b/libraries/librewrite/parse.c index a8129c41aed5ecfd83b2bce50d2961282eff3beb..bc83e0594e575a6a0cc61c4ce12ec07ef05e0452 100644 --- a/libraries/librewrite/parse.c +++ b/libraries/librewrite/parse.c @@ -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 ) { diff --git a/libraries/librewrite/subst.c b/libraries/librewrite/subst.c index 1024517463519212239e7985e28a8f1b6cd81b61..4c0bc411e0fa627c0d77084e2a116da33c635f06 100644 --- a/libraries/librewrite/subst.c +++ b/libraries/librewrite/subst.c @@ -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; diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index 95397c2668eb71b7d04639b4e679df4f75d082bc..f53d273aa6373e5edbb946b996a252555962bea1 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -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); } } } diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index 1dd74f1cd8e873509b565e0b7f21a135aeee19a0..5038db4bc799bacf7dbe6f7982e621f379a1a0db 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -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 ); } diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index d0c27ba340abb03ddcbce38eb1d1d22cf8948d6a..0283e3170bbb1debb74491ca8df931ab5e6ec59b 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -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 index 0000000000000000000000000000000000000000..0847740f02fbcc1c09008ca63a45d733134f55c9 --- /dev/null +++ b/servers/slapd/back-ldap/suffixmassage.c @@ -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 index 0000000000000000000000000000000000000000..f3f5617d5d49d614d81e51470d855d4bed0075b0 --- /dev/null +++ b/servers/slapd/back-ldap/unbind.c @@ -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; +} diff --git a/servers/slapd/back-ldbm/config.c b/servers/slapd/back-ldbm/config.c index 3c8475024e5621e81739513579404b4ef4e2c1ca..2cb64aa675aa263749c569475003c23ccc26427c 100644 --- a/servers/slapd/back-ldbm/config.c +++ b/servers/slapd/back-ldbm/config.c @@ -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, diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c index 2cdeb4c9cf1671c2b1566d3a70f98805ebee3e1f..83db8ae5fea8d83d801f597dda78ab2e0aa9b024 100644 --- a/servers/slapd/back-passwd/search.c +++ b/servers/slapd/back-passwd/search.c @@ -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 index 0000000000000000000000000000000000000000..6bbcd0e5a375709548aa5d74b91a2a43f4c13de1 --- /dev/null +++ b/servers/slapd/back-perl/SampleLDAP.pm @@ -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 index 0000000000000000000000000000000000000000..c4a54ef5fcd8c26a0f13d269fa6987fff54456a4 --- /dev/null +++ b/servers/slapd/back-perl/add.c @@ -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 index 0000000000000000000000000000000000000000..a286224563303ee2cc860d91f867fd3a52bebac9 --- /dev/null +++ b/servers/slapd/back-perl/bind.c @@ -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 index 0000000000000000000000000000000000000000..f16478b3f361ff1bbab898f38102eaaa245abca1 --- /dev/null +++ b/servers/slapd/back-perl/close.c @@ -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 index 0000000000000000000000000000000000000000..cf167b3b31273130fbcee2e01acb0002128f5e99 --- /dev/null +++ b/servers/slapd/back-perl/compare.c @@ -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 index 0000000000000000000000000000000000000000..da4d839d3e3bf1cad7e805b0a7561db3d26757ce --- /dev/null +++ b/servers/slapd/back-perl/config.c @@ -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 index 0000000000000000000000000000000000000000..e07d3abf18368a932dec48537ef713f49a341f52 --- /dev/null +++ b/servers/slapd/back-perl/delete.c @@ -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 index 0000000000000000000000000000000000000000..f95fe171e43a0735994a5768a904b0c10ae43d10 --- /dev/null +++ b/servers/slapd/back-perl/external.h @@ -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 index 0000000000000000000000000000000000000000..ec105f95430f8318d87c1eebd82fa7edd9433a69 --- /dev/null +++ b/servers/slapd/back-perl/init.c @@ -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 index 0000000000000000000000000000000000000000..2d0fb9817cbe432ecc264b5859abbe138c2ab108 --- /dev/null +++ b/servers/slapd/back-perl/modify.c @@ -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 index 0000000000000000000000000000000000000000..32db575665b898aab01540d95a1e1b870dcd77b8 --- /dev/null +++ b/servers/slapd/back-perl/modrdn.c @@ -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 index 0000000000000000000000000000000000000000..232364492a425d445bb36329287f595ddfa69660 --- /dev/null +++ b/servers/slapd/back-perl/perl_back.h @@ -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 index 0000000000000000000000000000000000000000..dea77e5b089f849fefd425f5819db52438fe1d60 --- /dev/null +++ b/servers/slapd/back-perl/search.c @@ -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 index 0000000000000000000000000000000000000000..00e1d33889e6ffce2c509c180d20e50216abfcba --- /dev/null +++ b/servers/slapd/back-sql/util.c @@ -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 */ diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 06016c0a7692d8d1ef159192d59cd77bb6d1acdf..286531681413c5b69ba5a3756f1fe10b90dfa8ef 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -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, diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 450691d326a5c076b48dfc116a07b0e8f5f409b5..40064a47fa3af42d25058f4d0d76ba65e3371d52 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -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; +} diff --git a/servers/slapd/main.c b/servers/slapd/main.c index fa1bb4916d5b4800840461b1dd2c214628f4278b..62249eeaf2ab5a3f63e9e3e2b98d9d10fe1111c9 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -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; } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index f3d6a8b0b346478505805e4e893fbcae63879699..0e0939eac9ee01c53b1621f1fae45e5139ca1fc0 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -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 */ diff --git a/servers/slapd/referral.c b/servers/slapd/referral.c index d3caa3ffd4a0c39c767160ae4fc48ea1f04d1a92..53edf251fba585d36abccdac5f419b604b499240 100644 --- a/servers/slapd/referral.c +++ b/servers/slapd/referral.c @@ -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; diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 8c96ff0239683f6f1b0d69de9297b65ec2e695af..4343f90794cec7729ff25b0d62fa4b9bfbc0f9c8 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -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); diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index 4876c076f8dada7137043cdefa924744fa580e7d..87f29735aa7394ed3eb00b9b33cc563f2d3d0a3d 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -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 ) { diff --git a/servers/slapd/saslauthz.c b/servers/slapd/saslauthz.c index 2f9ee9b74a12e514870cf7f731254c7ce675bb96..c13726b0b1a4613f805d84eea7e6c1546c372408 100644 --- a/servers/slapd/saslauthz.c +++ b/servers/slapd/saslauthz.c @@ -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 }; diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 8695cd8fe63855189fc1f100c9bf0ab59143a48e..85e9f2526fc379d8fc47d5b49dcf0c8cad9152e7 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -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 diff --git a/servers/slurpd/config.c b/servers/slurpd/config.c index 7a8261e8492b7cfe799ddf915243dc2d62352450..db08952915a0d66188748d17a490132927c1725f 100644 --- a/servers/slurpd/config.c +++ b/servers/slurpd/config.c @@ -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,33 +20,28 @@ * 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; } diff --git a/servers/slurpd/fm.c b/servers/slurpd/fm.c index 2d36838bb549dc4ed3086f44bcf955af03d370a6..36fab6540e346a8588ca56e9adb4f3c1fcfeffea 100644 --- a/servers/slurpd/fm.c +++ b/servers/slurpd/fm.c @@ -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. @@ -14,50 +19,24 @@ * 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 ); } - diff --git a/servers/slurpd/ldap_op.c b/servers/slurpd/ldap_op.c index 4d676fe4523cacbdba673d9998b28a5eb780f328..2d63daefaff57867eb8b3a75a60f4079e6856724 100644 --- a/servers/slurpd/ldap_op.c +++ b/servers/slurpd/ldap_op.c @@ -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 ); } } diff --git a/servers/slurpd/lock.c b/servers/slurpd/lock.c index 62aab06784b37f5acd99621aa00da0c789b69a70..d457cdfc21ae62aa655692e0bef074e06d05c21f 100644 --- a/servers/slurpd/lock.c +++ b/servers/slurpd/lock.c @@ -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. @@ -14,24 +19,27 @@ * 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 ); diff --git a/servers/slurpd/main.c b/servers/slurpd/main.c index 19949128d31d294996029b9619ad24eadaa91e8a..7a391221b50530b28aecb430a00223010e47df59 100644 --- a/servers/slurpd/main.c +++ b/servers/slurpd/main.c @@ -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 */ } diff --git a/servers/slurpd/re.c b/servers/slurpd/re.c index 4a6dc382377247c1da34ff330d9170a69c274e01..7fd254893cf6b7ba015ca22ae2a2e17909f3d441 100644 --- a/servers/slurpd/re.c +++ b/servers/slurpd/re.c @@ -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. @@ -18,28 +23,27 @@ */ +#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 ); diff --git a/servers/slurpd/reject.c b/servers/slurpd/reject.c index 8ae0dc63635728ca298566a8cced943f1ff4d134..d3346cf50902bd53205307c82ea02e22b170ee93 100644 --- a/servers/slurpd/reject.c +++ b/servers/slurpd/reject.c @@ -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. @@ -17,21 +22,19 @@ * 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; } diff --git a/servers/slurpd/replica.c b/servers/slurpd/replica.c index ed25a629077031feed19d6dee387adaea5b66f1b..9bb77ca8ef7dfcc190dec778c33aca82d8c4120f 100644 --- a/servers/slurpd/replica.c +++ b/servers/slurpd/replica.c @@ -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> @@ -26,22 +32,33 @@ * 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; } diff --git a/servers/slurpd/replog.c b/servers/slurpd/replog.c index c3a855cffecbc626a00d2c67b443c74213c40e73..a93f9040d50b194570c85bcc2e8d16e59a3265eb 100644 --- a/servers/slurpd/replog.c +++ b/servers/slurpd/replog.c @@ -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,55 +20,24 @@ * 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 ); } diff --git a/servers/slurpd/ri.c b/servers/slurpd/ri.c index a805060a98f0672683e25c0127854154cd7d09a5..5dbdaf855d6e53f3d233407c21202ed89f2e6e5a 100644 --- a/servers/slurpd/ri.c +++ b/servers/slurpd/ri.c @@ -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 && diff --git a/servers/slurpd/rq.c b/servers/slurpd/rq.c index 54adb4da1af77e4fd26db6da62d375ea781e94c6..37098c9f3649e23aa29a1a943c8d63350d922039 100644 --- a/servers/slurpd/rq.c +++ b/servers/slurpd/rq.c @@ -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. @@ -31,21 +36,24 @@ * */ -#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; } - diff --git a/servers/slurpd/st.c b/servers/slurpd/st.c index 610b29585342e2b4205d82ed080288b4448f2934..ffe150ea241b505aa705b89e42a3e39f5a164e49 100644 --- a/servers/slurpd/st.c +++ b/servers/slurpd/st.c @@ -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. @@ -16,19 +21,17 @@ * 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;