diff --git a/README b/README index 78a7df4d4a354e2b899a75b39ce9827c95dce72b..7757b21620338756f7535e93d0bfaa63c22a07c3 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ -OpenLDAP 2.1 ALPHA README +OpenLDAP 2.1 BETA README For a description of what this distribution contains, see the ANNOUNCEMENT file in this directory. - This is a 2.1 alpha release. + This is a 2.1 beta release. It is NOT intended for general use. @@ -61,7 +61,7 @@ SUPPORT / FEEDBACK / PROBLEM REPORTS / DISCUSSIONS the answer, please enquire on the OpenLDAP-software list. Issues, such as bug reports, should be reported using our - our Issue Tracking System <http://www.OpenLDAP.com/its/> or + our Issue Tracking System <http://www.OpenLDAP.org/its/> or by sending mail to OpenLDAP-its@OpenLDAP.org. Do not use this system for software enquiries. Please direct these to an appropriate mailing list. diff --git a/build/main.dsw b/build/main.dsw new file mode 100644 index 0000000000000000000000000000000000000000..f198bf3c05e979c4aae55079885084db4c7e5538 --- /dev/null +++ b/build/main.dsw @@ -0,0 +1,812 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "apitest"=..\libraries\libldap\apitest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "apitest_r"=..\libraries\libldap_r\apitest_r.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "backbdb"="..\servers\slapd\back-bdb\backbdb.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "backldbm"="..\servers\slapd\back-ldbm\backldbm.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "backmon"="..\servers\slapd\back-monitor\backmon.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "build"=.\build.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apitest + End Project Dependency + Begin Project Dependency + Project_Dep_Name apitest_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name dtest + End Project Dependency + Begin Project Dependency + Project_Dep_Name etest + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldapdelete + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldapmodify + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldapmodrdn + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldappasswd + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldapsearch + End Project Dependency + Begin Project Dependency + Project_Dep_Name ldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name testavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name ud + End Project Dependency + Begin Project Dependency + Project_Dep_Name slapcat + End Project Dependency + Begin Project Dependency + Project_Dep_Name slapadd + End Project Dependency + Begin Project Dependency + Project_Dep_Name slapindex + End Project Dependency + Begin Project Dependency + Project_Dep_Name slapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name ltest + End Project Dependency + Begin Project Dependency + Project_Dep_Name ltest_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name passwd + End Project Dependency + Begin Project Dependency + Project_Dep_Name ucgendat + End Project Dependency + Begin Project Dependency + Project_Dep_Name dntest + End Project Dependency + Begin Project Dependency + Project_Dep_Name ftest + End Project Dependency +}}} + +############################################################################### + +Project: "dntest"=..\libraries\libldap\dntest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency +}}} + +############################################################################### + +Project: "dtest"=..\libraries\liblber\dtest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "etest"=..\libraries\liblber\etest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ftest"=..\libraries\libldap\ftest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency +}}} + +############################################################################### + +Project: "ldapcompare"=..\clients\tools\ldapcompare.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ldapdelete"=..\clients\tools\ldapdelete.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ldapmodify"=..\clients\tools\ldapmodify.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ldapmodrdn"=..\clients\tools\ldapmodrdn.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ldappasswd"=..\clients\tools\ldappasswd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ldapsearch"=..\clients\tools\ldapsearch.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "libavl"=..\libraries\libavl\libavl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "liblber"=..\libraries\liblber\liblber.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "libldap"=..\libraries\libldap\libldap.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "libldap_r"=..\libraries\libldap_r\libldap_r.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "libldbm"=..\libraries\libldbm\libldbm.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "libldif"=..\libraries\libldif\libldif.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "liblunicode"=..\libraries\liblunicode\liblunicode.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "liblutil"=..\libraries\liblutil\liblutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "libslapd"=..\servers\slapd\libslapd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "ltest"=..\libraries\libldap\ltest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ltest_r"=..\libraries\libldap_r\ltest_r.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "passwd"=..\libraries\liblutil\passwd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency +}}} + +############################################################################### + +Project: "setup"=..\include\setup.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "slapadd"=..\servers\slapd\tools\slapadd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name backldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblunicode + End Project Dependency + Begin Project Dependency + Project_Dep_Name backbdb + End Project Dependency + Begin Project Dependency + Project_Dep_Name backmon + End Project Dependency +}}} + +############################################################################### + +Project: "slapcat"=..\servers\slapd\tools\slapcat.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name backldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblunicode + End Project Dependency + Begin Project Dependency + Project_Dep_Name backbdb + End Project Dependency + Begin Project Dependency + Project_Dep_Name backmon + End Project Dependency +}}} + +############################################################################### + +Project: "slapd"=..\servers\slapd\slapd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name backldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblunicode + End Project Dependency + Begin Project Dependency + Project_Dep_Name backbdb + End Project Dependency + Begin Project Dependency + Project_Dep_Name backmon + End Project Dependency +}}} + +############################################################################### + +Project: "slapindex"=..\servers\slapd\tools\slapindex.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name backldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldap_r + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblunicode + End Project Dependency + Begin Project Dependency + Project_Dep_Name backbdb + End Project Dependency + Begin Project Dependency + Project_Dep_Name backmon + End Project Dependency +}}} + +############################################################################### + +Project: "testavl"=..\libraries\libavl\testavl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency +}}} + +############################################################################### + +Project: "ucgendat"=..\libraries\liblunicode\ucgendat.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency +}}} + +############################################################################### + +Project: "ud"=..\clients\ud\ud.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblber + End Project Dependency + Begin Project Dependency + Project_Dep_Name liblutil + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/build/mkrelease b/build/mkrelease new file mode 100755 index 0000000000000000000000000000000000000000..f0e7a1f5d70d1ad5a99cbb16671cbe8ddb94dfb8 --- /dev/null +++ b/build/mkrelease @@ -0,0 +1,54 @@ +#! /bin/sh +# $OpenLDAP$ +## Copyright 1998-2002 The OpenLDAP Foundation +## COPYING RESTRICTIONS APPLY. See COPYRIGHT File in top level directory +## of this package for details. +# +# Make a release +# mkrelease RELNAME CVSTAG CVSMODULES +# where CVSTAG is the tag to export from the current CVSROOT +# + +set -e # exit immediately if any errors occur + +if test $# != 3 ; then + echo 'usage: mkrelease RELNAME CVSTAG CVSMODULES ...' + exit 1 +fi + +RELNAME=openldap-$1 +shift +CVSTAG=$1 +shift + +if test -e $RELNAME ; then + echo "error: $RELNAME exists" + exit 1 +fi + +echo Release: $RELNAME +echo CVS Tag: $CVSTAG +echo Modules: $* + +cvs -q export -r $CVSTAG -d $RELNAME $* + +if test ! -d $RELNAME ; then + echo "error: $RELNAME doesn't exists" + exit 1 +fi + +if test ! -e $RELNAME/build/version.sh ; then + echo "No build version" + exit 1 +fi + +. $RELNAME/build/version.sh + +tar cf $RELNAME.tar $RELNAME +gzip -9 -c $RELNAME.tar > $RELNAME.tgz +md5 $RELNAME.tgz > $RELNAME.md5 +rm -f $RELNAME.tar + +ls -l $RELNAME.* + +echo "Made $OL_STRING as $RELNAME.tgz" diff --git a/clients/tools/ldappasswd.c b/clients/tools/ldappasswd.c new file mode 100644 index 0000000000000000000000000000000000000000..838eb0288e107756904a13be78a19003b170adfb --- /dev/null +++ b/clients/tools/ldappasswd.c @@ -0,0 +1,785 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/signal.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include <ldap.h> + +#include "lutil_ldap.h" +#include "ldap_defaults.h" + +static int verbose = 0; + +static void +usage(const char *s) +{ + fprintf(stderr, +"Change password of an LDAP user\n\n" +"usage: %s [options] [user]\n" +" user: the autentication identity, commonly a DN\n" +"Password change options:\n" +" -a secret old password\n" +" -A prompt for old password\n" +" -s secret new password\n" +" -S prompt for new password\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(s)\n" +" -H URI LDAP Uniform Resource Indentifier(s)\n" +" -I use SASL Interactive mode\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" +" -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" + , s ); + + exit( EXIT_FAILURE ); +} + +int +main( int argc, char *argv[] ) +{ + int rc; + char *prog = NULL; + char *ldaphost = NULL; + char *ldapuri = NULL; + + char *user = NULL; + char *binddn = NULL; + + struct berval passwd = { 0, NULL }; + char *newpw = NULL; + char *oldpw = NULL; + + int want_bindpw = 0; + int want_newpw = 0; + int want_oldpw = 0; + + int not = 0; + int i; + int ldapport = 0; + int debug = 0; + int version = -1; + int authmethod = -1; + int manageDSAit = 0; +#ifdef HAVE_CYRUS_SASL + unsigned sasl_flags = LDAP_SASL_AUTOMATIC; + char *sasl_realm = NULL; + char *sasl_authc_id = NULL; + char *sasl_authz_id = NULL; + char *sasl_mech = NULL; + char *sasl_secprops = NULL; +#endif + int use_tls = 0; + int referrals = 0; + LDAP *ld = NULL; + struct berval *bv = NULL; + + int id, code = LDAP_OTHER; + LDAPMessage *res; + char *matcheddn = NULL, *text = NULL, **refs = NULL; + char *retoid = NULL; + struct berval *retdata = NULL; + + prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1; + + while( (i = getopt( argc, argv, "Aa:Ss:" + "Cd:D:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF ) + { + switch (i) { + /* Password Options */ + case 'A': /* prompt for old password */ + want_oldpw++; + break; + + case 'a': /* old password (secret) */ + oldpw = strdup (optarg); + + { + char* p; + + for( p = optarg; *p != '\0'; p++ ) { + *p = '\0'; + } + } + break; + + case 'S': /* prompt for user password */ + want_newpw++; + break; + + case 's': /* new password (secret) */ + newpw = strdup (optarg); + { + char* p; + + for( p = optarg; *p != '\0'; p++ ) { + *p = '\0'; + } + } + break; + + /* Common Options (including options we don't use) */ + 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 '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 '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 '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 '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 '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': +#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, "%s: unrecognized option -%c\n", + prog, optopt ); + usage (prog); + } + } + + if (authmethod == -1) { +#ifdef HAVE_CYRUS_SASL + authmethod = LDAP_AUTH_SASL; +#else + authmethod = LDAP_AUTH_SIMPLE; +#endif + } + + if( argc - optind > 1 ) { + usage( prog ); + } else if ( argc - optind == 1 ) { + user = strdup( argv[optind] ); + } else { + user = NULL; + } + + if( want_oldpw && oldpw == NULL ) { + /* prompt for old password */ + char *ckoldpw; + oldpw = strdup(getpassphrase("Old password: ")); + ckoldpw = getpassphrase("Re-enter old password: "); + + if( oldpw== NULL || ckoldpw == NULL || + strcmp( oldpw, ckoldpw )) + { + fprintf( stderr, "passwords do not match\n" ); + return EXIT_FAILURE; + } + } + + if( want_newpw && newpw == NULL ) { + /* prompt for new password */ + char *cknewpw; + newpw = strdup(getpassphrase("New password: ")); + cknewpw = getpassphrase("Re-enter new password: "); + + if( newpw== NULL || cknewpw == NULL || + strcmp( newpw, cknewpw )) + { + fprintf( stderr, "passwords do not match\n" ); + return EXIT_FAILURE; + } + } + + if (want_bindpw && passwd.bv_val == NULL ) { + /* handle bind password */ + passwd.bv_val = strdup( getpassphrase("Enter bind password: ")); + passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0; + } + + 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 ); + } + } + +#ifdef SIGPIPE + (void) SIGNAL( SIGPIPE, SIG_IGN ); +#endif + + /* connect to server */ + if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) { + if ( verbose ) { + fprintf( stderr, "ldap_init( %s, %d )\n", + ldaphost != NULL ? ldaphost : "<DEFAULT>", + ldapport ); + } + + ld = ldap_init( ldaphost, ldapport ); + if( ld == NULL ) { + perror("ldapsearch: ldap_init"); + return EXIT_FAILURE; + } + + } else { + 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; + } + + /* LDAPv3 only */ + version = LDAP_VERSION3; + rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + + if(rc != LDAP_OPT_SUCCESS ) { + fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version ); + return EXIT_FAILURE; + } + + 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 ( 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 ); + } + } + + if( user != NULL || oldpw != NULL || newpw != NULL ) { + /* build change password control */ + BerElement *ber = ber_alloc_t( LBER_USE_DER ); + + if( ber == NULL ) { + perror( "ber_alloc_t" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + ber_printf( ber, "{" /*}*/ ); + + if( user != NULL ) { + ber_printf( ber, "ts", + LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user ); + free(user); + } + + if( oldpw != NULL ) { + ber_printf( ber, "ts", + LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, oldpw ); + free(oldpw); + } + + if( newpw != NULL ) { + ber_printf( ber, "ts", + LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, newpw ); + free(newpw); + } + + ber_printf( ber, /*{*/ "N}" ); + + rc = ber_flatten( ber, &bv ); + + if( rc < 0 ) { + perror( "ber_flatten" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + ber_free( ber, 1 ); + } + + if ( not ) { + rc = LDAP_SUCCESS; + goto skip; + } + + rc = ldap_extended_operation( ld, + LDAP_EXOP_MODIFY_PASSWD, bv, + NULL, NULL, &id ); + + ber_bvfree( bv ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_extended_operation" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res ); + if ( rc < 0 ) { + ldap_perror( ld, "ldappasswd: ldap_result" ); + return rc; + } + + rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_parse_result" ); + return rc; + } + + rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_parse_result" ); + return rc; + } + + if( retdata != NULL ) { + ber_tag_t tag; + char *s; + BerElement *ber = ber_init( retdata ); + + if( ber == NULL ) { + perror( "ber_init" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + /* we should check the tag */ + tag = ber_scanf( ber, "{a}", &s); + + if( tag == LBER_ERROR ) { + perror( "ber_scanf" ); + } else { + printf("New password: %s\n", s); + free( s ); + } + + ber_free( ber, 1 ); + } + + if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) { + printf( "Result: %s (%d)\n", ldap_err2string( code ), code ); + + if( text && *text ) { + printf( "Additional info: %s\n", text ); + } + + if( matcheddn && *matcheddn ) { + printf( "Matched DN: %s\n", matcheddn ); + } + + if( refs ) { + int i; + for( i=0; refs[i]; i++ ) { + printf("Referral: %s\n", refs[i] ); + } + } + } + + ber_memfree( text ); + ber_memfree( matcheddn ); + ber_memvfree( (void **) refs ); + ber_memfree( retoid ); + ber_bvfree( retdata ); + +skip: + /* disconnect from server */ + ldap_unbind (ld); + + return code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index d96aff131711ea7bc85bde1ed6194a246c2d7afc..bf76dbdfdd0f608898474a955752c99381e4f938 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -1,475 +1,1413 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <lber.h> -#include <ldap.h> -#include <ldif.h> -#include "ldapconfig.h" +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/signal.h> +#include <ac/string.h> +#include <ac/unistd.h> +#include <ac/errno.h> +#include <sys/stat.h> + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_IO_H +#include <io.h> +#endif -#define DEFSEP "=" +#include <ldap.h> -#ifdef LDAP_DEBUG -extern int ldap_debug, lber_debug; -#endif /* LDAP_DEBUG */ +#include "ldif.h" +#include "lutil.h" +#include "lutil_ldap.h" +#include "ldap_defaults.h" +#include "ldap_log.h" +static char *def_tmpdir; +static char *def_urlpre; -usage( s ) -char *s; +static void +usage( const char *s ) { - fprintf( stderr, "usage: %s [options] filter [attributes...]\nwhere:\n", s ); - fprintf( stderr, " filter\tRFC-1558 compliant LDAP search filter\n" ); - fprintf( stderr, " attributes\twhitespace-separated list of attributes to retrieve\n" ); - fprintf( stderr, "\t\t(if no attribute list is given, all are retrieved)\n" ); - fprintf( stderr, "options:\n" ); - fprintf( stderr, " -n\t\tshow what would be done but don't actually search\n" ); - fprintf( stderr, " -v\t\trun in verbose mode (diagnostics to standard output)\n" ); - fprintf( stderr, " -t\t\twrite values to files in /tmp\n" ); - fprintf( stderr, " -u\t\tinclude User Friendly entry names in the output\n" ); - fprintf( stderr, " -A\t\tretrieve attribute names only (no values)\n" ); - fprintf( stderr, " -B\t\tdo not suppress printing of non-ASCII values\n" ); - fprintf( stderr, " -L\t\tprint entries in LDIF format (-B is implied)\n" ); -#ifdef LDAP_REFERRALS - fprintf( stderr, " -R\t\tdo not automatically follow referrals\n" ); -#endif /* LDAP_REFERRALS */ - fprintf( stderr, " -d level\tset LDAP debugging level to `level'\n" ); - fprintf( stderr, " -F sep\tprint `sep' instead of `=' between attribute names and values\n" ); - fprintf( stderr, " -S attr\tsort the results by attribute `attr'\n" ); - fprintf( stderr, " -f file\tperform sequence of searches listed in `file'\n" ); - fprintf( stderr, " -b basedn\tbase dn for search\n" ); - fprintf( stderr, " -s scope\tone of base, one, or sub (search scope)\n" ); - fprintf( stderr, " -a deref\tone of never, always, search, or find (alias dereferencing)\n" ); - fprintf( stderr, " -l time lim\ttime limit (in seconds) for search\n" ); - fprintf( stderr, " -z size lim\tsize limit (in entries) for search\n" ); - fprintf( stderr, " -D binddn\tbind dn\n" ); - fprintf( stderr, " -w passwd\tbind passwd (for simple authentication)\n" ); -#ifdef KERBEROS - fprintf( stderr, " -k\t\tuse Kerberos instead of Simple Password authentication\n" ); -#endif - fprintf( stderr, " -h host\tldap server\n" ); - fprintf( stderr, " -p port\tport on ldap server\n" ); - exit( 1 ); + fprintf( stderr, +"usage: %s [options] [filter [attributes...]]\nwhere:\n" +" filter\tRFC-2254 compliant LDAP search filter\n" +" attributes\twhitespace-separated list of attribute descriptions\n" +" which may include:\n" +" 1.1 no attributes\n" +" * all user attributes\n" +" + all operational attributes\n" + +"Search options:\n" +" -a deref one of never (default), always, search, or find\n" +" -A retrieve attribute names only (no values)\n" +" -b basedn base dn for search\n" +" -F prefix URL prefix for files (default: %s)\n" +" -l limit time limit (in seconds) for search\n" +" -L print responses in LDIFv1 format\n" +" -LL print responses in LDIF format without comments\n" +" -LLL print responses in LDIF format without comments\n" +" and version\n" +" -s scope one of base, one, or sub (search scope)\n" +" -S attr sort the results by attribute `attr'\n" +" -t write binary values to files in temporary directory\n" +" -tt write all values to files in temporary directory\n" +" -T path write files to directory specified by path (default: %s)\n" +" -u include User Friendly entry names in the output\n" +" -z limit size limit (in entries) for search\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 search\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" +, s, def_urlpre, def_tmpdir ); + + exit( EXIT_FAILURE ); } -static char *binddn = LDAPSEARCH_BINDDN; -static char *passwd = NULL; -static char *base = LDAPSEARCH_BASE; -static char *ldaphost = LDAPHOST; -static int ldapport = LDAP_PORT; -static char *sep = DEFSEP; +static void print_entry LDAP_P(( + LDAP *ld, + LDAPMessage *entry, + int attrsonly)); + +static void print_reference( + LDAP *ld, + LDAPMessage *reference ); + +static void print_extended( + LDAP *ld, + LDAPMessage *extended ); + +static void print_partial( + LDAP *ld, + LDAPMessage *partial ); + +static int print_result( + LDAP *ld, + LDAPMessage *result, + int search ); + +static void print_ctrls( + LDAPControl **ctrls ); + +static int write_ldif LDAP_P(( + int type, + char *name, + char *value, + ber_len_t vallen )); + +static int dosearch LDAP_P(( + LDAP *ld, + char *base, + int scope, + char *filtpatt, + char *value, + char **attrs, + int attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + struct timeval *timeout, + int sizelimit )); + +static char *tmpdir = NULL; +static char *urlpre = NULL; +static char *prog = NULL; +static char *binddn = NULL; +static struct berval passwd = { 0, NULL }; +static char *base = NULL; +static char *ldaphost = NULL; +static char *ldapuri = 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 char *sortattr = NULL; -static int skipsortattr = 0; -static int verbose, not, includeufn, allow_binary, vals2tmp, ldif; +static int verbose, not, includeufn, vals2tmp, ldif; -main( argc, argv ) -int argc; -char **argv; +static void +urlize(char *url) { - char *infile, *filtpattern, **attrs, line[ BUFSIZ ]; - FILE *fp; - int rc, i, first, scope, kerberos, deref, attrsonly; - int ldap_options, timelimit, sizelimit, authmethod; - LDAP *ld; - extern char *optarg; - extern int optind; - - infile = NULL; - deref = verbose = allow_binary = not = kerberos = vals2tmp = - attrsonly = ldif = 0; -#ifdef LDAP_REFERRALS - ldap_options = LDAP_OPT_REFERRALS; -#else /* LDAP_REFERRALS */ - ldap_options = 0; -#endif /* LDAP_REFERRALS */ - sizelimit = timelimit = 0; - scope = LDAP_SCOPE_SUBTREE; - - while (( i = getopt( argc, argv, -#ifdef KERBEROS - "KknuvtRABLD:s:f:h:b:d:p:F:a:w:l:z:S:" -#else - "nuvtRABLD:s:f:h:b:d:p:F:a:w:l:z:S:" -#endif - )) != EOF ) { + char *p; + + if (*LDAP_DIRSEP != '/') + { + for (p = url; *p; p++) + { + if (*p == *LDAP_DIRSEP) + *p = '/'; + } + } +} + +int +main( int argc, char **argv ) +{ + char *infile, *filtpattern, **attrs = NULL, line[BUFSIZ]; + FILE *fp = NULL; + int rc, i, first, scope, deref, attrsonly, manageDSAit; + int referrals, timelimit, sizelimit, debug; + int authmethod, version, want_bindpw; + LDAP *ld = NULL; + + infile = NULL; + debug = verbose = not = vals2tmp = referrals = + attrsonly = manageDSAit = ldif = want_bindpw = 0; + + lutil_log_initialize(argc, argv); + + deref = sizelimit = timelimit = version = -1; + + scope = LDAP_SCOPE_SUBTREE; + authmethod = -1; + + if((def_tmpdir = getenv("TMPDIR")) == NULL && + (def_tmpdir = getenv("TMP")) == NULL && + (def_tmpdir = getenv("TEMP")) == NULL ) + { + def_tmpdir = LDAP_TMPDIR; + } + + if ( !*def_tmpdir ) + def_tmpdir = LDAP_TMPDIR; + + def_urlpre = malloc( sizeof("file:////") + strlen(def_tmpdir) ); + + if( def_urlpre == NULL ) { + perror( "malloc" ); + return EXIT_FAILURE; + } + + sprintf( def_urlpre, "file:///%s/", + def_tmpdir[0] == *LDAP_DIRSEP ? &def_tmpdir[1] : def_tmpdir ); + + urlize( def_urlpre ); + + prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1; + + while (( i = getopt( argc, argv, "Aa:b:F:f:Ll:S:s:T:tuz:" + "Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z")) != EOF ) + { switch( i ) { - case 'n': /* do Not do any searches */ - ++not; - break; - case 'v': /* verbose mode */ - ++verbose; - break; - case 'd': -#ifdef LDAP_DEBUG - ldap_debug = lber_debug = atoi( optarg ); /* */ -#else /* LDAP_DEBUG */ - fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" ); -#endif /* LDAP_DEBUG */ - break; -#ifdef KERBEROS - case 'k': /* use kerberos bind */ - kerberos = 2; - break; - case 'K': /* use kerberos bind, 1st part only */ - kerberos = 1; - break; -#endif - case 'u': /* include UFN */ - ++includeufn; - break; - case 't': /* write attribute values to /tmp files */ - ++vals2tmp; - break; - case 'R': /* don't automatically chase referrals */ -#ifdef LDAP_REFERRALS - ldap_options &= ~LDAP_OPT_REFERRALS; -#else /* LDAP_REFERRALS */ - fprintf( stderr, - "compile with -DLDAP_REFERRALS for referral support\n" ); -#endif /* LDAP_REFERRALS */ - break; + /* Search Options */ + case 'a': /* set alias deref option */ + if ( strcasecmp( optarg, "never" ) == 0 ) { + deref = LDAP_DEREF_NEVER; + } else if ( strncasecmp( optarg, "search", sizeof("search")-1 ) == 0 ) { + deref = LDAP_DEREF_SEARCHING; + } else if ( strncasecmp( optarg, "find", sizeof("find")-1 ) == 0 ) { + deref = LDAP_DEREF_FINDING; + } else if ( strcasecmp( optarg, "always" ) == 0 ) { + deref = LDAP_DEREF_ALWAYS; + } else { + fprintf( stderr, "alias deref should be never, search, find, or always\n" ); + usage(prog); + } + break; case 'A': /* retrieve attribute names only -- no values */ - ++attrsonly; - break; + ++attrsonly; + break; + case 'b': /* search base */ + base = strdup( optarg ); + break; + case 'f': /* input file */ + if( infile != NULL ) { + fprintf( stderr, "%s: -f previously specified\n", prog ); + return EXIT_FAILURE; + } + infile = strdup( optarg ); + break; + case 'F': /* uri prefix */ + if( urlpre ) free( urlpre ); + urlpre = strdup( optarg ); + break; + case 'l': /* time limit */ + timelimit = atoi( optarg ); + if( timelimit < 0 ) { + fprintf( stderr, "%s: invalid timelimit (%d) specified\n", + prog, timelimit ); + return EXIT_FAILURE; + } + break; case 'L': /* print entries in LDIF format */ - ++ldif; - /* fall through -- always allow binary when outputting LDIF */ - case 'B': /* allow binary values to be printed */ - ++allow_binary; - break; + ++ldif; + break; case 's': /* search scope */ - if ( strncasecmp( optarg, "base", 4 ) == 0 ) { + if ( strcasecmp( optarg, "base" ) == 0 ) { scope = LDAP_SCOPE_BASE; - } else if ( strncasecmp( optarg, "one", 3 ) == 0 ) { + } else if ( strncasecmp( optarg, "one", sizeof("one")-1 ) == 0 ) { scope = LDAP_SCOPE_ONELEVEL; - } else if ( strncasecmp( optarg, "sub", 3 ) == 0 ) { + } else if ( strncasecmp( optarg, "sub", sizeof("sub")-1 ) == 0 ) { scope = LDAP_SCOPE_SUBTREE; - } else { + } else { fprintf( stderr, "scope should be base, one, or sub\n" ); - usage( argv[ 0 ] ); - } - break; + usage(prog); + } + break; + case 'S': /* sort attribute */ + sortattr = strdup( optarg ); + break; + case 'u': /* include UFN */ + ++includeufn; + break; + case 't': /* write attribute values to TMPDIR files */ + ++vals2tmp; + break; + case 'T': /* tmpdir */ + if( tmpdir ) free( tmpdir ); + tmpdir = strdup( optarg ); + break; + case 'z': /* size limit */ + sizelimit = atoi( optarg ); + break; - case 'a': /* set alias deref option */ - if ( strncasecmp( optarg, "never", 5 ) == 0 ) { - deref = LDAP_DEREF_NEVER; - } else if ( strncasecmp( optarg, "search", 5 ) == 0 ) { - deref = LDAP_DEREF_SEARCHING; - } else if ( strncasecmp( optarg, "find", 4 ) == 0 ) { - deref = LDAP_DEREF_FINDING; - } else if ( strncasecmp( optarg, "always", 6 ) == 0 ) { - deref = LDAP_DEREF_ALWAYS; - } else { - fprintf( stderr, "alias deref should be never, search, find, or always\n" ); - usage( argv[ 0 ] ); - } - break; - - case 'F': /* field separator */ - sep = strdup( optarg ); + /* Common Options */ + case 'C': + referrals++; + break; + case 'd': + debug |= atoi( optarg ); break; - case 'f': /* input file */ - infile = strdup( optarg ); + case 'D': /* bind DN */ + if( binddn != NULL ) { + fprintf( stderr, "%s: -D previously specified\n", prog ); + return EXIT_FAILURE; + } + binddn = strdup( optarg ); break; 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 'b': /* searchbase */ - base = strdup( optarg ); + 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 'D': /* bind DN */ - binddn = 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': /* ldap port */ - 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 'w': /* bind password */ - passwd = strdup( optarg ); + 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 'l': /* time limit */ - timelimit = atoi( optarg ); + 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 'z': /* size limit */ - sizelimit = atoi( optarg ); + 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': +#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 'S': /* sort attribute */ - sortattr = strdup( optarg ); + 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; - default: - usage( argv[0] ); - } - } - - if ( argc - optind < 1 ) { - usage( argv[ 0 ] ); - } - filtpattern = strdup( argv[ optind ] ); - if ( argv[ optind + 1 ] == NULL ) { - attrs = NULL; - } else if ( sortattr == NULL || *sortattr == '\0' ) { - attrs = &argv[ optind + 1 ]; - } else { - for ( i = optind + 1; i < argc; i++ ) { - if ( strcasecmp( argv[ i ], sortattr ) == 0 ) { + 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, "%s: unrecognized option -%c\n", + prog, optopt ); + usage(prog); + } + } + + 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 ( i == argc ) { - skipsortattr = 1; - argv[ optind ] = sortattr; + + if (( argc - optind < 1 ) || + ( *argv[optind] != '(' /*')'*/ && + ( strchr( argv[optind], '=' ) == NULL ) ) ) + { + filtpattern = "(objectclass=*)"; } else { - optind++; - } - attrs = &argv[ optind ]; - } - - if ( infile != NULL ) { - if ( infile[0] == '-' && infile[1] == '\0' ) { - fp = stdin; - } else if (( fp = fopen( infile, "r" )) == NULL ) { - perror( infile ); - exit( 1 ); - } - } - - if ( verbose ) { - printf( "ldap_open( %s, %d )\n", ldaphost, ldapport ); - } - - if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) { - perror( ldaphost ); - exit( 1 ); - } - - ld->ld_deref = deref; - ld->ld_timelimit = timelimit; - ld->ld_sizelimit = sizelimit; - ld->ld_options = ldap_options; - - if ( !kerberos ) { - authmethod = LDAP_AUTH_SIMPLE; - } else if ( kerberos == 1 ) { - authmethod = LDAP_AUTH_KRBV41; - } else { - authmethod = LDAP_AUTH_KRBV4; - } - if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) { - ldap_perror( ld, "ldap_bind" ); - exit( 1 ); - } - - if ( verbose ) { - printf( "filter pattern: %s\nreturning: ", filtpattern ); - if ( attrs == NULL ) { - printf( "ALL" ); + filtpattern = strdup( argv[optind++] ); + } + + if ( argv[optind] != NULL ) { + attrs = &argv[optind]; + } + + if ( infile != NULL ) { + if ( infile[0] == '-' && infile[1] == '\0' ) { + fp = stdin; + } else if (( fp = fopen( infile, "r" )) == NULL ) { + perror( infile ); + return EXIT_FAILURE; + } + } + + if ( tmpdir == NULL ) { + tmpdir = def_tmpdir; + + if ( urlpre == NULL ) + urlpre = def_urlpre; + } + + if( urlpre == NULL ) { + urlpre = malloc( sizeof("file:////") + strlen(tmpdir) ); + + if( urlpre == NULL ) { + perror( "malloc" ); + return EXIT_FAILURE; + } + + sprintf( urlpre, "file:///%s/", + tmpdir[0] == *LDAP_DIRSEP ? &tmpdir[1] : tmpdir ); + + urlize( urlpre ); + } + + 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 + + if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) { + if ( verbose ) { + fprintf( stderr, "ldap_init( %s, %d )\n", + ldaphost != NULL ? ldaphost : "<DEFAULT>", + ldapport ); + } + + ld = ldap_init( ldaphost, ldapport ); + if( ld == NULL ) { + perror("ldapsearch: ldap_init"); + return EXIT_FAILURE; + } + } else { - for ( i = 0; attrs[ i ] != NULL; ++i ) { - printf( "%s ", attrs[ i ] ); - } - } - putchar( '\n' ); - } - - if ( infile == NULL ) { - rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern, "" ); - } else { - rc = 0; - first = 1; - while ( rc == 0 && fgets( line, sizeof( line ), fp ) != NULL ) { - line[ strlen( line ) - 1 ] = '\0'; - if ( !first ) { - putchar( '\n' ); - } else { - first = 0; - } - rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern, - line ); - } - if ( fp != stdin ) { - fclose( fp ); - } - } - - ldap_unbind( ld ); - exit( rc ); -} + 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; + } + } -dosearch( ld, base, scope, attrs, attrsonly, filtpatt, value ) - LDAP *ld; - char *base; - int scope; - char **attrs; - int attrsonly; - char *filtpatt; - char *value; -{ - char filter[ BUFSIZ ], **val; - int rc, first, matches; - LDAPMessage *res, *e; - - sprintf( filter, filtpatt, value ); - - if ( verbose ) { - printf( "filter is: (%s)\n", filter ); - } - - if ( not ) { - return( LDAP_SUCCESS ); - } - - if ( ldap_search( ld, base, scope, filter, attrs, attrsonly ) == -1 ) { - ldap_perror( ld, "ldap_search" ); - return( ld->ld_errno ); - } - - matches = 0; - first = 1; - while ( (rc = ldap_result( ld, LDAP_RES_ANY, sortattr ? 1 : 0, NULL, &res )) - == LDAP_RES_SEARCH_ENTRY ) { - matches++; - e = ldap_first_entry( ld, res ); - if ( !first ) { - putchar( '\n' ); + if (deref != -1 && + ldap_set_option( ld, LDAP_OPT_DEREF, (void *) &deref ) != LDAP_OPT_SUCCESS ) + { + fprintf( stderr, "Could not set LDAP_OPT_DEREF %d\n", deref ); + return EXIT_FAILURE; + } + if (timelimit != -1 && + ldap_set_option( ld, LDAP_OPT_TIMELIMIT, (void *) &timelimit ) != LDAP_OPT_SUCCESS ) + { + fprintf( stderr, "Could not set LDAP_OPT_TIMELIMIT %d\n", timelimit ); + return EXIT_FAILURE; + } + if (sizelimit != -1 && + ldap_set_option( ld, LDAP_OPT_SIZELIMIT, (void *) &sizelimit ) != LDAP_OPT_SUCCESS ) + { + fprintf( stderr, "Could not set LDAP_OPT_SIZELIMIT %d\n", sizelimit ); + 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 ( 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 { - first = 0; + if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod ) + != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_bind" ); + return( EXIT_FAILURE ); + } } - print_entry( ld, e, attrsonly ); - ldap_msgfree( res ); - } - if ( rc == -1 ) { - ldap_perror( ld, "ldap_result" ); - return( rc ); - } - if (( rc = ldap_result2error( ld, res, 0 )) != LDAP_SUCCESS ) { - ldap_perror( ld, "ldap_search" ); - } - if ( sortattr != NULL ) { - extern int strcasecmp(); - - (void) ldap_sort_entries( ld, &res, - ( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp ); - matches = 0; - first = 1; - for ( e = ldap_first_entry( ld, res ); e != NULLMSG; - e = ldap_next_entry( ld, e ) ) { - matches++; - if ( !first ) { - putchar( '\n' ); + + 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 ); + } + } + } + + if ( verbose ) { + fprintf( stderr, "filter%s: %s\nrequesting: ", + infile != NULL ? " pattern" : "", + filtpattern ); + + if ( attrs == NULL ) { + fprintf( stderr, "ALL" ); } else { - first = 0; + for ( i = 0; attrs[ i ] != NULL; ++i ) { + fprintf( stderr, "%s ", attrs[ i ] ); + } } - print_entry( ld, e, attrsonly ); - } - } + fprintf( stderr, "\n" ); + } + + if ( ldif == 0 ) { + printf( "# extended LDIF\n" ); + } else if ( ldif < 3 ) { + printf( "version: %d\n\n", 1 ); + } + + if (ldif < 2 ) { + printf( "#\n# LDAPv%d\n# filter%s: %s\n# requesting: ", + version, + infile != NULL ? " pattern" : "", + filtpattern ); + + if ( attrs == NULL ) { + printf( "ALL" ); + } else { + for ( i = 0; attrs[ i ] != NULL; ++i ) { + printf( "%s ", attrs[ i ] ); + } + } + + if ( manageDSAit ) { + printf("\n# with manageDSAit %scontrol", + manageDSAit > 1 ? "critical " : "" ); + } + + printf( "\n#\n\n" ); + } + + if ( infile == NULL ) { + rc = dosearch( ld, base, scope, NULL, filtpattern, + attrs, attrsonly, NULL, NULL, NULL, -1 ); - if ( verbose ) { - printf( "%d matches\n", matches ); - } + } else { + rc = 0; + first = 1; + while ( rc == 0 && fgets( line, sizeof( line ), fp ) != NULL ) { + line[ strlen( line ) - 1 ] = '\0'; + if ( !first ) { + putchar( '\n' ); + } else { + first = 0; + } + rc = dosearch( ld, base, scope, filtpattern, line, + attrs, attrsonly, NULL, NULL, NULL, -1 ); + } + if ( fp != stdin ) { + fclose( fp ); + } + } - ldap_msgfree( res ); - return( rc ); + ldap_unbind( ld ); + return( rc ); } -print_entry( ld, entry, attrsonly ) - LDAP *ld; - LDAPMessage *entry; - int attrsonly; +static int dosearch( + LDAP *ld, + char *base, + int scope, + char *filtpatt, + char *value, + char **attrs, + int attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + struct timeval *timeout, + int sizelimit ) { - char *a, *dn, *ufn, tmpfname[ 64 ]; - int i, j, notascii; - BerElement *ber; - struct berval **bvals; - FILE *tmpfp; - extern char *mktemp(); - - dn = ldap_get_dn( ld, entry ); - if ( ldif ) { - write_ldif_value( "dn", dn, strlen( dn )); - } else { - printf( "%s\n", dn ); - } - if ( includeufn ) { - ufn = ldap_dn2ufn( dn ); - if ( ldif ) { - write_ldif_value( "ufn", ufn, strlen( ufn )); + char *filter; + int rc; + int nresponses; + int nentries; + int nreferences; + int nextended; + int npartial; + LDAPMessage *res, *msg; + ber_int_t msgid; + + if( filtpatt != NULL ) { + filter = malloc( strlen( filtpatt ) + strlen( value ) ); + if( filter == NULL ) { + perror( "malloc" ); + return EXIT_FAILURE; + } + + sprintf( filter, filtpatt, value ); + + if ( verbose ) { + fprintf( stderr, "filter: %s\n", filter ); + } + + if( ldif < 2 ) { + printf( "#\n# filter: %s\n#\n", filter ); + } + } else { - printf( "%s\n", ufn ); - } - free( ufn ); - } - free( dn ); - - for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL; - a = ldap_next_attribute( ld, entry, ber ) ) { - if ( skipsortattr && strcasecmp( a, sortattr ) == 0 ) { - continue; - } - if ( attrsonly ) { - if ( ldif ) { - write_ldif_value( a, "", 0 ); - } else { - printf( "%s\n", a ); - } - } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) { - for ( i = 0; bvals[i] != NULL; i++ ) { - if ( vals2tmp ) { - sprintf( tmpfname, "/tmp/ldapsearch-%s-XXXXXX", a ); - tmpfp = NULL; - - if ( mktemp( tmpfname ) == NULL ) { - perror( tmpfname ); - } else if (( tmpfp = fopen( tmpfname, "w")) == NULL ) { - perror( tmpfname ); - } else if ( fwrite( bvals[ i ]->bv_val, - bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) { - perror( tmpfname ); - } else if ( ldif ) { - write_ldif_value( a, tmpfname, strlen( tmpfname )); - } else { - printf( "%s%s%s\n", a, sep, tmpfname ); - } - - if ( tmpfp != NULL ) { - fclose( tmpfp ); - } - } else { - notascii = 0; - if ( !allow_binary ) { - for ( j = 0; j < bvals[ i ]->bv_len; ++j ) { - if ( !isascii( bvals[ i ]->bv_val[ j ] )) { - notascii = 1; + filter = value; + } + + if ( not ) { + return LDAP_SUCCESS; + } + + rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, + sctrls, cctrls, timeout, sizelimit, &msgid ); + + if ( filtpatt != NULL ) { + free( filter ); + } + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: ldap_search_ext: %s (%d)\n", + prog, ldap_err2string( rc ), rc ); + return( rc ); + } + + nresponses = nentries = nreferences = nextended = npartial = 0; + + res = NULL; + + while ((rc = ldap_result( ld, LDAP_RES_ANY, + sortattr ? LDAP_MSG_ALL : LDAP_MSG_ONE, + NULL, &res )) > 0 ) + { + if( sortattr ) { + (void) ldap_sort_entries( ld, &res, + ( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp ); + } + + for ( msg = ldap_first_message( ld, res ); + msg != NULL; + msg = ldap_next_message( ld, msg ) ) + { + if( nresponses++ ) putchar('\n'); + + switch( ldap_msgtype( msg ) ) { + case LDAP_RES_SEARCH_ENTRY: + nentries++; + print_entry( ld, msg, attrsonly ); + break; + + case LDAP_RES_SEARCH_REFERENCE: + nreferences++; + print_reference( ld, msg ); + break; + + case LDAP_RES_EXTENDED: + nextended++; + print_extended( ld, msg ); + + if( ldap_msgid( msg ) == 0 ) { + /* unsolicited extended operation */ + goto done; + } break; - } + + case LDAP_RES_EXTENDED_PARTIAL: + npartial++; + print_partial( ld, msg ); + break; + + case LDAP_RES_SEARCH_RESULT: + rc = print_result( ld, msg, 1 ); + goto done; } - } + } - if ( ldif ) { - write_ldif_value( a, bvals[ i ]->bv_val, - bvals[ i ]->bv_len ); - } else { - printf( "%s%s%s\n", a, sep, - notascii ? "NOT ASCII" : bvals[ i ]->bv_val ); - } + ldap_msgfree( res ); + } + + if ( rc == -1 ) { + ldap_perror( ld, "ldap_result" ); + return( rc ); + } + +done: + if ( ldif < 2 ) { + printf( "\n# numResponses: %d\n", nresponses ); + if( nentries ) printf( "# numEntries: %d\n", nentries ); + if( nextended ) printf( "# numExtended: %d\n", nextended ); + if( npartial ) printf( "# numPartial: %d\n", npartial ); + if( nreferences ) printf( "# numReferences: %d\n", nreferences ); + } + + return( rc ); +} + +static void +print_entry( + LDAP *ld, + LDAPMessage *entry, + int attrsonly) +{ + char *a, *dn, *ufn; + char tmpfname[ 256 ]; + char url[ 256 ]; + int i, rc; + BerElement *ber = NULL; + struct berval **bvals; + LDAPControl **ctrls = NULL; + FILE *tmpfp; + + dn = ldap_get_dn( ld, entry ); + ufn = NULL; + + if ( ldif < 2 ) { + ufn = ldap_dn2ufn( dn ); + write_ldif( LDIF_PUT_COMMENT, NULL, ufn, ufn ? strlen( ufn ) : 0 ); + } + write_ldif( LDIF_PUT_VALUE, "dn", dn, dn ? strlen( dn ) : 0); + + rc = ldap_get_entry_controls( ld, entry, &ctrls ); + + if( rc != LDAP_SUCCESS ) { + fprintf(stderr, "print_entry: %d\n", rc ); + ldap_perror( ld, "ldap_get_entry_controls" ); + exit( EXIT_FAILURE ); + } + + if( ctrls ) { + print_ctrls( ctrls ); + ldap_controls_free( ctrls ); + } + + if ( includeufn ) { + if( ufn == NULL ) { + ufn = ldap_dn2ufn( dn ); } - } - ber_bvecfree( bvals ); + write_ldif( LDIF_PUT_VALUE, "ufn", ufn, ufn ? strlen( ufn ) : 0 ); + } + + if( ufn != NULL ) ldap_memfree( ufn ); + ldap_memfree( dn ); + + for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL; + a = ldap_next_attribute( ld, entry, ber ) ) + { + if ( attrsonly ) { + write_ldif( LDIF_PUT_NOVALUE, a, NULL, 0 ); + + } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) { + for ( i = 0; bvals[i] != NULL; i++ ) { + if ( vals2tmp > 1 || ( vals2tmp + && ldif_is_not_printable( bvals[i]->bv_val, bvals[i]->bv_len ) )) + { + int tmpfd; + /* write value to file */ + sprintf( tmpfname, "%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX", + tmpdir, a ); + tmpfp = NULL; + + tmpfd = mkstemp( tmpfname ); + + if ( tmpfd < 0 ) { + perror( tmpfname ); + continue; + } + + if (( tmpfp = fdopen( tmpfd, "w")) == NULL ) { + perror( tmpfname ); + continue; + } + + if ( fwrite( bvals[ i ]->bv_val, + bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) + { + perror( tmpfname ); + fclose( tmpfp ); + continue; + } + + fclose( tmpfp ); + + sprintf( url, "%s%s", urlpre, + &tmpfname[strlen(tmpdir) + sizeof(LDAP_DIRSEP) - 1] ); + + urlize( url ); + write_ldif( LDIF_PUT_URL, a, url, strlen( url )); + + } else { + write_ldif( LDIF_PUT_VALUE, a, + bvals[ i ]->bv_val, bvals[ i ]->bv_len ); + } + } + ber_bvecfree( bvals ); + } + } + + if( ber != NULL ) { + ber_free( ber, 0 ); } - } } +static void print_reference( + LDAP *ld, + LDAPMessage *reference ) +{ + int rc; + char **refs = NULL; + LDAPControl **ctrls; -int -write_ldif_value( char *type, char *value, unsigned long vallen ) + if( ldif < 2 ) { + printf("# search reference\n"); + } + + rc = ldap_parse_reference( ld, reference, &refs, &ctrls, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror(ld, "ldap_parse_reference"); + exit( EXIT_FAILURE ); + } + + if( refs ) { + int i; + for( i=0; refs[i] != NULL; i++ ) { + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE, + "ref", refs[i], strlen(refs[i]) ); + } + ber_memvfree( (void **) refs ); + } + + if( ctrls ) { + print_ctrls( ctrls ); + ldap_controls_free( ctrls ); + } +} + +static void print_extended( + LDAP *ld, + LDAPMessage *extended ) { - char *ldif; + int rc; + char *retoid = NULL; + struct berval *retdata = NULL; + + if( ldif < 2 ) { + printf("# extended result response\n"); + } + + rc = ldap_parse_extended_result( ld, extended, + &retoid, &retdata, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror(ld, "ldap_parse_extended_result"); + exit( EXIT_FAILURE ); + } + + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE, + "extended", retoid, retoid ? strlen(retoid) : 0 ); + ber_memfree( retoid ); + + if(retdata) { + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY, + "data", retdata->bv_val, retdata->bv_len ); + ber_bvfree( retdata ); + } + + print_result( ld, extended, 0 ); +} + +static void print_partial( + LDAP *ld, + LDAPMessage *partial ) +{ + int rc; + char *retoid = NULL; + struct berval *retdata = NULL; + LDAPControl **ctrls = NULL; + + if( ldif < 2 ) { + printf("# extended partial response\n"); + } + + rc = ldap_parse_extended_partial( ld, partial, + &retoid, &retdata, &ctrls, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror(ld, "ldap_parse_extended_partial"); + exit( EXIT_FAILURE ); + } + + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE, + "partial", retoid, retoid ? strlen(retoid) : 0 ); + + ber_memfree( retoid ); + + if( retdata ) { + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY, + "data", + retdata->bv_val, retdata->bv_len ); + + ber_bvfree( retdata ); + } - if (( ldif = ldif_type_and_value( type, value, (int)vallen )) == NULL ) { - return( -1 ); - } + if( ctrls ) { + print_ctrls( ctrls ); + ldap_controls_free( ctrls ); + } +} + +static int print_result( + LDAP *ld, + LDAPMessage *result, int search ) +{ + int rc; + int err; + char *matcheddn = NULL; + char *text = NULL; + char **refs = NULL; + LDAPControl **ctrls = NULL; + + if( search ) { + if ( ldif < 2 ) { + printf("# search result\n"); + } + if ( ldif < 1 ) { + printf("%s: %d\n", "search", ldap_msgid(result) ); + } + } + + rc = ldap_parse_result( ld, result, + &err, &matcheddn, &text, &refs, &ctrls, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror(ld, "ldap_parse_result"); + exit( EXIT_FAILURE ); + } + + + if( !ldif ) { + printf( "result: %d %s\n", err, ldap_err2string(err) ); + + } else if ( err != LDAP_SUCCESS ) { + fprintf( stderr, "%s (%d)\n", ldap_err2string(err), err ); + } + + if( matcheddn && *matcheddn ) { + if( !ldif ) { + write_ldif( LDIF_PUT_VALUE, + "matchedDN", matcheddn, strlen(matcheddn) ); + } else { + fprintf( stderr, "Matched DN: %s\n", matcheddn ); + } + + ber_memfree( matcheddn ); + } + + if( text && *text ) { + if( !ldif ) { + write_ldif( LDIF_PUT_TEXT, "text", + text, strlen(text) ); + } else { + fprintf( stderr, "Additional information: %s\n", text ); + } + + ber_memfree( text ); + } + + if( refs ) { + int i; + for( i=0; refs[i] != NULL; i++ ) { + if( !ldif ) { + write_ldif( LDIF_PUT_VALUE, "ref", refs[i], strlen(refs[i]) ); + } else { + fprintf( stderr, "Referral: %s\n", refs[i] ); + } + } + + ber_memvfree( (void **) refs ); + } + + if( ctrls ) { + print_ctrls( ctrls ); + ldap_controls_free( ctrls ); + } + + return err; +} + +static void print_ctrls( + LDAPControl **ctrls ) +{ + int i; + for(i=0; ctrls[i] != NULL; i++ ) { + /* control: OID criticality base64value */ + struct berval *b64 = NULL; + ber_len_t len; + char *str; + + len = strlen( ctrls[i]->ldctl_oid ); + + /* add enough for space after OID and the critical value itself */ + len += ctrls[i]->ldctl_iscritical + ? sizeof("true") : sizeof("false"); + + /* convert to base64 */ + if( ctrls[i]->ldctl_value.bv_len ) { + b64 = ber_memalloc( sizeof(struct berval) ); + + b64->bv_len = LUTIL_BASE64_ENCODE_LEN( + ctrls[i]->ldctl_value.bv_len ) + 1; + b64->bv_val = ber_memalloc( b64->bv_len + 1 ); + + b64->bv_len = lutil_b64_ntop( + ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len, + b64->bv_val, b64->bv_len ); + } + + if( b64 ) { + len += 1 + b64->bv_len; + } + + str = malloc( len + 1 ); + strcpy( str, ctrls[i]->ldctl_oid ); + strcat( str, ctrls[i]->ldctl_iscritical + ? " true" : " false" ); + + if( b64 ) { + strcat(str, " "); + strcat(str, b64->bv_val ); + } + + write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE, + "control", str, len ); + + free( str ); + ber_bvfree( b64 ); + } +} + +static int +write_ldif( int type, char *name, char *value, ber_len_t vallen ) +{ + char *ldif; + + if (( ldif = ldif_put( type, name, value, vallen )) == NULL ) { + return( -1 ); + } - fputs( ldif, stdout ); - free( ldif ); + fputs( ldif, stdout ); + ber_memfree( ldif ); - return( 0 ); + return( 0 ); } diff --git a/clients/tools/ldapwhoami.c b/clients/tools/ldapwhoami.c new file mode 100644 index 0000000000000000000000000000000000000000..d69e35faa4607c9f3347b8dc985d7f3aa7287264 --- /dev/null +++ b/clients/tools/ldapwhoami.c @@ -0,0 +1,717 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/signal.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include <ldap.h> + +#include "lutil_ldap.h" +#include "ldap_defaults.h" + +static int verbose = 0; + +static void +usage(const char *s) +{ + fprintf(stderr, +"Issue LDAP Who am I? operation to request user's authzid\n\n" +"usage: %s [options]\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(s)\n" +" -H URI LDAP Uniform Resource Indentifier(s)\n" +" -I use SASL Interactive mode\n" +" -n show what would be done but don't actually do it\n" +" -O props SASL security properties\n" +" -p port port on LDAP server\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" + , s ); + + exit( EXIT_FAILURE ); +} + +int +main( int argc, char *argv[] ) +{ + int rc; + char *prog = NULL; + char *ldaphost = NULL; + char *ldapuri = NULL; + + char *user = NULL; + char *binddn = NULL; + + struct berval passwd = { 0, NULL }; + char *newpw = NULL; + char *oldpw = NULL; + + int want_bindpw = 0; + int want_newpw = 0; + int want_oldpw = 0; + + int not = 0; + int i; + int ldapport = 0; + int debug = 0; + int version = -1; + int authmethod = -1; + int manageDSAit = 0; +#ifdef HAVE_CYRUS_SASL + unsigned sasl_flags = LDAP_SASL_AUTOMATIC; + char *sasl_realm = NULL; + char *sasl_authc_id = NULL; + char *sasl_authz_id = NULL; + char *sasl_mech = NULL; + char *sasl_secprops = NULL; +#endif + int use_tls = 0; + int referrals = 0; + LDAP *ld = NULL; + + int id, code = LDAP_OTHER; + LDAPMessage *res; + char *matcheddn = NULL, *text = NULL, **refs = NULL; + char *retoid = NULL; + struct berval *retdata = NULL; + + prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1; + + while( (i = getopt( argc, argv, "Aa:Ss:" + "Cd:D:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF ) + { + switch (i) { + /* Password Options */ + case 'A': /* prompt for old password */ + want_oldpw++; + break; + + case 'a': /* old password (secret) */ + oldpw = strdup (optarg); + + { + char* p; + + for( p = optarg; *p != '\0'; p++ ) { + *p = '\0'; + } + } + break; + + case 'S': /* prompt for user password */ + want_newpw++; + break; + + case 's': /* new password (secret) */ + newpw = strdup (optarg); + { + char* p; + + for( p = optarg; *p != '\0'; p++ ) { + *p = '\0'; + } + } + break; + + /* Common Options (including options we don't use) */ + 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 '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 '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 '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 '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 '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': +#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, "%s: unrecognized option -%c\n", + prog, optopt ); + usage (prog); + } + } + + if (authmethod == -1) { +#ifdef HAVE_CYRUS_SASL + authmethod = LDAP_AUTH_SASL; +#else + authmethod = LDAP_AUTH_SIMPLE; +#endif + } + + if( argc - optind > 1 ) { + usage( prog ); + } else if ( argc - optind == 1 ) { + user = strdup( argv[optind] ); + } else { + user = NULL; + } + + if( want_oldpw && oldpw == NULL ) { + /* prompt for old password */ + char *ckoldpw; + oldpw = strdup(getpassphrase("Old password: ")); + ckoldpw = getpassphrase("Re-enter old password: "); + + if( oldpw== NULL || ckoldpw == NULL || + strcmp( oldpw, ckoldpw )) + { + fprintf( stderr, "passwords do not match\n" ); + return EXIT_FAILURE; + } + } + + if( want_newpw && newpw == NULL ) { + /* prompt for new password */ + char *cknewpw; + newpw = strdup(getpassphrase("New password: ")); + cknewpw = getpassphrase("Re-enter new password: "); + + if( newpw== NULL || cknewpw == NULL || + strcmp( newpw, cknewpw )) + { + fprintf( stderr, "passwords do not match\n" ); + return EXIT_FAILURE; + } + } + + if (want_bindpw && passwd.bv_val == NULL ) { + /* handle bind password */ + passwd.bv_val = strdup( getpassphrase("Enter bind password: ")); + passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0; + } + + 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 ); + } + } + +#ifdef SIGPIPE + (void) SIGNAL( SIGPIPE, SIG_IGN ); +#endif + + /* connect to server */ + if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) { + if ( verbose ) { + fprintf( stderr, "ldap_init( %s, %d )\n", + ldaphost != NULL ? ldaphost : "<DEFAULT>", + ldapport ); + } + + ld = ldap_init( ldaphost, ldapport ); + if( ld == NULL ) { + perror("ldapwhoami: ldap_init"); + return EXIT_FAILURE; + } + + } else { + 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; + } + + /* LDAPv3 only */ + version = LDAP_VERSION3; + rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + + if(rc != LDAP_OPT_SUCCESS ) { + fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version ); + return EXIT_FAILURE; + } + + 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 ( 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 ); + } + } + + if ( not ) { + rc = LDAP_SUCCESS; + goto skip; + } + + rc = ldap_extended_operation( ld, + LDAP_EXOP_X_WHO_AM_I, NULL, + NULL, NULL, &id ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_extended_operation" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res ); + if ( rc < 0 ) { + ldap_perror( ld, "ldappasswd: ldap_result" ); + return rc; + } + + rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_parse_result" ); + return rc; + } + + rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 ); + + if( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_parse_result" ); + return rc; + } + + if( retdata != NULL ) { + if( retdata->bv_len == 0 ) { + printf("anonymous\n" ); + } else { + printf("%s\n", retdata->bv_val ); + } + } + + if( verbose || ( code != LDAP_SUCCESS ) || matcheddn || text || refs ) { + printf( "Result: %s (%d)\n", ldap_err2string( code ), code ); + + if( text && *text ) { + printf( "Additional info: %s\n", text ); + } + + if( matcheddn && *matcheddn ) { + printf( "Matched DN: %s\n", matcheddn ); + } + + if( refs ) { + int i; + for( i=0; refs[i]; i++ ) { + printf("Referral: %s\n", refs[i] ); + } + } + } + + ber_memfree( text ); + ber_memfree( matcheddn ); + ber_memvfree( (void **) refs ); + ber_memfree( retoid ); + ber_bvfree( retdata ); + +skip: + /* disconnect from server */ + ldap_unbind (ld); + + return code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/configure b/configure index 4a86644c1b4f62a3b8b9a2bdd339a1c848b16dcb..ed6818afff9ac1898aff40d6fb5c6fd7190cf426 100755 --- a/configure +++ b/configure @@ -118,6 +118,10 @@ ac_help="$ac_help --enable-monitor enable monitor backend [no]" ac_help="$ac_help --with-monitor-module module type [static]" +ac_help="$ac_help + --enable-null enable null backend [no]" +ac_help="$ac_help + --with-null-module module type [static]" ac_help="$ac_help --enable-passwd enable passwd backend [no]" ac_help="$ac_help @@ -871,7 +875,7 @@ echo "Configuring $TB$OL_STRING$TN ..." echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:875: checking host system type" >&5 +echo "configure:879: checking host system type" >&5 if test "x$ac_cv_host" = "x" || (test "x$host" != "xNONE" && test "x$host" != "x$ac_cv_host_alias"); then # Make sure we can run config.sub. @@ -912,7 +916,7 @@ host_os=$ac_cv_host_os echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:916: checking target system type" >&5 +echo "configure:920: checking target system type" >&5 if test "x$ac_cv_target" = "x" || (test "x$target" != "xNONE" && test "x$target" != "x$ac_cv_target_alias"); then # Make sure we can run config.sub. @@ -952,7 +956,7 @@ target_os=$ac_cv_target_os echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:956: checking build system type" >&5 +echo "configure:960: checking build system type" >&5 if test "x$ac_cv_build" = "x" || (test "x$build" != "xNONE" && test "x$build" != "x$ac_cv_build_alias"); then # Make sure we can run config.sub. @@ -1029,7 +1033,7 @@ test "$host_alias" != "$target_alias" && # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1033: checking for a BSD compatible install" >&5 +echo "configure:1037: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"\${ac_cv_path_install+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1086,7 +1090,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 -echo "configure:1090: checking whether build environment is sane" >&5 +echo "configure:1094: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile @@ -1147,7 +1151,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1151: checking for $ac_word" >&5 +echo "configure:1155: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AWK+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1177,7 +1181,7 @@ test -n "$AWK" && break done echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:1181: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:1185: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1217,7 +1221,7 @@ fi missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:1221: checking for working aclocal" >&5 +echo "configure:1225: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1230,7 +1234,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:1234: checking for working autoconf" >&5 +echo "configure:1238: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1243,7 +1247,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:1247: checking for working automake" >&5 +echo "configure:1251: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1256,7 +1260,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:1260: checking for working autoheader" >&5 +echo "configure:1264: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1269,7 +1273,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:1273: checking for working makeinfo" >&5 +echo "configure:1277: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1289,7 +1293,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1293: checking for $ac_word" >&5 +echo "configure:1297: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AMTAR+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1357,7 +1361,7 @@ OPENLDAP_LIBVERSION=$OL_API_LIB echo $ac_n "checking configure arguments""... $ac_c" 1>&6 -echo "configure:1361: checking configure arguments" >&5 +echo "configure:1365: checking configure arguments" >&5 top_builddir=`pwd` @@ -2289,6 +2293,47 @@ else fi # end --with-monitor_module +# OpenLDAP --enable-null + # Check whether --enable-null or --disable-null was given. +if test "${enable_null+set}" = set; then + enableval="$enable_null" + + ol_arg=invalid + for ol_val in auto yes no ; do + if test "$enableval" = "$ol_val" ; then + ol_arg="$ol_val" + fi + done + if test "$ol_arg" = "invalid" ; then + { echo "configure: error: bad value $enableval for --enable-null" 1>&2; exit 1; } + fi + ol_enable_null="$ol_arg" + +else + ol_enable_null="no" +fi +# end --enable-null +# OpenLDAP --with-null_module + # Check whether --with-null_module or --without-null_module was given. +if test "${with_null_module+set}" = set; then + withval="$with_null_module" + + ol_arg=invalid + for ol_val in static dynamic ; do + if test "$withval" = "$ol_val" ; then + ol_arg="$ol_val" + fi + done + if test "$ol_arg" = "invalid" ; then + { echo "configure: error: bad value $withval for --with-null_module" 1>&2; exit 1; } + fi + ol_with_null_module="$ol_arg" + +else + ol_with_null_module="static" +fi +# end --with-null_module + # OpenLDAP --enable-passwd # Check whether --enable-passwd or --disable-passwd was given. if test "${enable_passwd+set}" = set; then @@ -2555,6 +2600,9 @@ if test $ol_enable_slapd = no ; then if test $ol_enable_monitor = yes ; then echo "configure: warning: slapd disabled, ignoring --enable-monitor argument" 1>&2 fi + if test $ol_enable_null = yes ; then + echo "configure: warning: slapd disabled, ignoring --enable-null argument" 1>&2 + fi if test $ol_enable_passwd = yes ; then echo "configure: warning: slapd disabled, ignoring --enable-passwd argument" 1>&2 fi @@ -2606,6 +2654,9 @@ if test $ol_enable_slapd = no ; then if test $ol_with_monitor_module != static ; then echo "configure: warning: slapd disabled, ignoring --with-monitor-module argument" 1>&2 fi + if test $ol_with_null_module != static ; then + echo "configure: warning: slapd disabled, ignoring --with-null-module argument" 1>&2 + fi if test $ol_with_passwd_module != static ; then echo "configure: warning: slapd disabled, ignoring --with-passwd-module argument" 1>&2 fi @@ -2632,6 +2683,7 @@ if test $ol_enable_slapd = no ; then ol_enable_ldbm=no ol_enable_meta=no ol_enable_monitor=no + ol_enable_null=no ol_enable_passwd=no ol_enable_perl=no ol_enable_shell=no @@ -2653,6 +2705,7 @@ if test $ol_enable_slapd = no ; then ol_with_ldbm_module=static ol_with_meta_module=static ol_with_monitor_module=static + ol_with_null_module=static ol_with_passwd_module=static ol_with_perl_module=static ol_with_shell_module=static @@ -2682,6 +2735,7 @@ elif test $ol_enable_ldbm = no ; then $ol_enable_ldap = no -a \ $ol_enable_meta = no -a \ $ol_enable_monitor = no -a \ + $ol_enable_null = no -a \ $ol_enable_passwd = no -a \ $ol_enable_perl = no -a \ $ol_enable_shell = no -a \ @@ -2791,6 +2845,7 @@ BUILD_LDAP=no BUILD_LDBM=no BUILD_META=no BUILD_MONITOR=no +BUILD_NULL=no BUILD_PASSWD=no BUILD_PERL=no BUILD_SHELL=no @@ -2802,6 +2857,7 @@ BUILD_LDAP_DYNAMIC=static BUILD_LDBM_DYNAMIC=static BUILD_META_DYNAMIC=static BUILD_MONITOR_DYNAMIC=static +BUILD_NULL_DYNAMIC=static BUILD_PASSWD_DYNAMIC=static BUILD_PERL_DYNAMIC=static BUILD_SHELL_DYNAMIC=static @@ -2846,7 +2902,7 @@ SLAPD_SLP_LIBS= # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:2850: checking for a BSD compatible install" >&5 +echo "configure:2906: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"\${ac_cv_path_install+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2927,7 +2983,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2931: checking for $ac_word" >&5 +echo "configure:2987: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2979,7 +3035,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2983: checking for $ac_word" >&5 +echo "configure:3039: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3016,7 +3072,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3020: checking for $ac_word" >&5 +echo "configure:3076: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AR+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3061,12 +3117,12 @@ if test "X${PATH_SEPARATOR+set}" != Xset; then fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:3065: checking for Cygwin environment" >&5 +echo "configure:3121: checking for Cygwin environment" >&5 if eval "test \"\${ac_cv_cygwin+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3070 "configure" +#line 3126 "configure" #include "confdefs.h" int main() { @@ -3077,7 +3133,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:3081: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3137: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -3093,19 +3149,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:3097: checking for mingw32 environment" >&5 +echo "configure:3153: checking for mingw32 environment" >&5 if eval "test \"\${ac_cv_mingw32+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3102 "configure" +#line 3158 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:3109: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3165: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -3121,19 +3177,19 @@ echo "$ac_t""$ac_cv_mingw32" 1>&6 MINGW32= test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for EMX OS/2 environment""... $ac_c" 1>&6 -echo "configure:3125: checking for EMX OS/2 environment" >&5 +echo "configure:3181: checking for EMX OS/2 environment" >&5 if eval "test \"\${ac_cv_emxos2+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3130 "configure" +#line 3186 "configure" #include "confdefs.h" int main() { return __EMX__; ; return 0; } EOF -if { (eval echo configure:3137: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3193: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_emxos2=yes else @@ -3149,7 +3205,7 @@ echo "$ac_t""$ac_cv_emxos2" 1>&6 EMXOS2= test "$ac_cv_emxos2" = yes && EMXOS2=yes echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:3153: checking how to run the C preprocessor" >&5 +echo "configure:3209: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -3164,13 +3220,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 3168 "configure" +#line 3224 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3174: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3230: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -3181,13 +3237,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 3185 "configure" +#line 3241 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3191: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3247: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -3198,13 +3254,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 3202 "configure" +#line 3258 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3208: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3264: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -3254,7 +3310,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3258: checking for $ac_word" >&5 +echo "configure:3314: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3284,7 +3340,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3288: checking for $ac_word" >&5 +echo "configure:3344: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3335,7 +3391,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3339: checking for $ac_word" >&5 +echo "configure:3395: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3367,7 +3423,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:3371: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works" >&5 +echo "configure:3427: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -3378,12 +3434,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 3382 "configure" +#line 3438 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:3387: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3443: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -3409,12 +3465,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:3413: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:3469: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:3418: checking whether we are using GNU C" >&5 +echo "configure:3474: checking whether we are using GNU C" >&5 if eval "test \"\${ac_cv_prog_gcc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3423,7 +3479,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:3427: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:3483: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -3442,7 +3498,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:3446: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:3502: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"\${ac_cv_prog_cc_g+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3485,7 +3541,7 @@ ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 -echo "configure:3489: checking for ld used by GCC" >&5 +echo "configure:3545: checking for ld used by GCC" >&5 case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw @@ -3515,10 +3571,10 @@ echo "configure:3489: checking for ld used by GCC" >&5 esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 -echo "configure:3519: checking for GNU ld" >&5 +echo "configure:3575: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 -echo "configure:3522: checking for non-GNU ld" >&5 +echo "configure:3578: checking for non-GNU ld" >&5 fi if eval "test \"\${lt_cv_path_LD+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3553,7 +3609,7 @@ else fi test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 -echo "configure:3557: checking if the linker ($LD) is GNU ld" >&5 +echo "configure:3613: checking if the linker ($LD) is GNU ld" >&5 if eval "test \"\${lt_cv_prog_gnu_ld+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3570,7 +3626,7 @@ with_gnu_ld=$lt_cv_prog_gnu_ld echo $ac_n "checking for $LD option to reload object files""... $ac_c" 1>&6 -echo "configure:3574: checking for $LD option to reload object files" >&5 +echo "configure:3630: checking for $LD option to reload object files" >&5 if eval "test \"\${lt_cv_ld_reload_flag+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3582,7 +3638,7 @@ reload_flag=$lt_cv_ld_reload_flag test -n "$reload_flag" && reload_flag=" $reload_flag" echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 -echo "configure:3586: checking for BSD-compatible nm" >&5 +echo "configure:3642: checking for BSD-compatible nm" >&5 if eval "test \"\${lt_cv_path_NM+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3620,7 +3676,7 @@ NM="$lt_cv_path_NM" echo "$ac_t""$NM" 1>&6 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:3624: checking whether ln -s works" >&5 +echo "configure:3680: checking whether ln -s works" >&5 if eval "test \"\${ac_cv_prog_LN_S+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3641,7 +3697,7 @@ else fi echo $ac_n "checking how to recognise dependant libraries""... $ac_c" 1>&6 -echo "configure:3645: checking how to recognise dependant libraries" >&5 +echo "configure:3701: checking how to recognise dependant libraries" >&5 if eval "test \"\${lt_cv_deplibs_check_method+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3824,13 +3880,13 @@ file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method echo $ac_n "checking for object suffix""... $ac_c" 1>&6 -echo "configure:3828: checking for object suffix" >&5 +echo "configure:3884: checking for object suffix" >&5 if eval "test \"\${ac_cv_objext+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftest* echo 'int i = 1;' > conftest.$ac_ext -if { (eval echo configure:3834: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3890: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then for ac_file in conftest.*; do case $ac_file in *.c) ;; @@ -3851,7 +3907,7 @@ ac_objext=$ac_cv_objext echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:3855: checking for executable suffix" >&5 +echo "configure:3911: checking for executable suffix" >&5 if eval "test \"\${ac_cv_exeext+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3861,7 +3917,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:3865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:3921: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.C | *.o | *.obj | *.xcoff) ;; @@ -3892,7 +3948,7 @@ fi # Check for command to grab the raw symbol name followed by C symbol from nm. echo $ac_n "checking command to parse $NM output""... $ac_c" 1>&6 -echo "configure:3896: checking command to parse $NM output" >&5 +echo "configure:3952: checking command to parse $NM output" >&5 if eval "test \"\${lt_cv_sys_global_symbol_pipe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3972,10 +4028,10 @@ void nm_test_func(){} int main(){nm_test_var='a';nm_test_func();return(0);} EOF - if { (eval echo configure:3976: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + if { (eval echo configure:4032: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then # Now try to grab the symbols. nlist=conftest.nm - if { (eval echo configure:3979: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5; } && test -s "$nlist"; then + if { (eval echo configure:4035: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" @@ -4026,7 +4082,7 @@ EOF save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$no_builtin_flag" - if { (eval echo configure:4030: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + if { (eval echo configure:4086: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then pipe_works=yes fi LIBS="$save_LIBS" @@ -4075,17 +4131,17 @@ for ac_hdr in dlfcn.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:4079: checking for $ac_hdr" >&5 +echo "configure:4135: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4084 "configure" +#line 4140 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:4089: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:4145: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -4120,7 +4176,7 @@ case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then echo $ac_n "checking for ${ac_tool_prefix}file""... $ac_c" 1>&6 -echo "configure:4124: checking for ${ac_tool_prefix}file" >&5 +echo "configure:4180: checking for ${ac_tool_prefix}file" >&5 if eval "test \"\${lt_cv_path_MAGIC_CMD+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4182,7 +4238,7 @@ fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then echo $ac_n "checking for file""... $ac_c" 1>&6 -echo "configure:4186: checking for file" >&5 +echo "configure:4242: checking for file" >&5 if eval "test \"\${lt_cv_path_MAGIC_CMD+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4253,7 +4309,7 @@ esac # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4257: checking for $ac_word" >&5 +echo "configure:4313: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_RANLIB+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4285,7 +4341,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4289: checking for $ac_word" >&5 +echo "configure:4345: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_RANLIB+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4320,7 +4376,7 @@ fi # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4324: checking for $ac_word" >&5 +echo "configure:4380: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_STRIP+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4352,7 +4408,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4356: checking for $ac_word" >&5 +echo "configure:4412: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_STRIP+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4401,8 +4457,8 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 4405 "configure"' > conftest.$ac_ext - if { (eval echo configure:4406: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + echo '#line 4461 "configure"' > conftest.$ac_ext + if { (eval echo configure:4462: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" @@ -4423,7 +4479,7 @@ case $host in SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 -echo "configure:4427: checking whether the C compiler needs -belf" >&5 +echo "configure:4483: checking whether the C compiler needs -belf" >&5 if eval "test \"\${lt_cv_cc_needs_belf+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4436,14 +4492,14 @@ ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$a cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <<EOF -#line 4440 "configure" +#line 4496 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:4447: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_needs_belf=yes else @@ -4473,7 +4529,7 @@ echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4477: checking for $ac_word" >&5 +echo "configure:4533: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_DLLTOOL+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4505,7 +4561,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4509: checking for $ac_word" >&5 +echo "configure:4565: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_DLLTOOL+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4540,7 +4596,7 @@ fi # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4544: checking for $ac_word" >&5 +echo "configure:4600: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AS+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4572,7 +4628,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4576: checking for $ac_word" >&5 +echo "configure:4632: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AS+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4607,7 +4663,7 @@ fi # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4611: checking for $ac_word" >&5 +echo "configure:4667: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_OBJDUMP+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4639,7 +4695,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4643: checking for $ac_word" >&5 +echo "configure:4699: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_OBJDUMP+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4675,12 +4731,12 @@ fi # recent cygwin and mingw systems supply a stub DllMain which the user # can override, but on older systems we have to supply one echo $ac_n "checking if libtool should supply DllMain function""... $ac_c" 1>&6 -echo "configure:4679: checking if libtool should supply DllMain function" >&5 +echo "configure:4735: checking if libtool should supply DllMain function" >&5 if eval "test \"\${lt_cv_need_dllmain+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4684 "configure" +#line 4740 "configure" #include "confdefs.h" int main() { @@ -4688,7 +4744,7 @@ extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); DllMain (0, 0, 0); ; return 0; } EOF -if { (eval echo configure:4692: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4748: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_need_dllmain=no else @@ -4709,19 +4765,19 @@ echo "$ac_t""$lt_cv_need_dllmain" 1>&6 SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -mdll" echo $ac_n "checking how to link DLLs""... $ac_c" 1>&6 -echo "configure:4713: checking how to link DLLs" >&5 +echo "configure:4769: checking how to link DLLs" >&5 if eval "test \"\${lt_cv_cc_dll_switch+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4718 "configure" +#line 4774 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:4725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_dll_switch=-mdll else @@ -4835,7 +4891,7 @@ set dummy $CC compiler="$2" echo $ac_n "checking for objdir""... $ac_c" 1>&6 -echo "configure:4839: checking for objdir" >&5 +echo "configure:4895: checking for objdir" >&5 rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then @@ -4862,7 +4918,7 @@ test -z "$pic_mode" && pic_mode=default # in isolation, and that seeing it set (from the cache) indicates that # the associated values are set (in the cache) correctly too. echo $ac_n "checking for $compiler option to produce PIC""... $ac_c" 1>&6 -echo "configure:4866: checking for $compiler option to produce PIC" >&5 +echo "configure:4922: checking for $compiler option to produce PIC" >&5 if eval "test \"\${lt_cv_prog_cc_pic+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -5014,21 +5070,21 @@ else # Check to make sure the pic_flag actually works. echo $ac_n "checking if $compiler PIC flag $lt_cv_prog_cc_pic works""... $ac_c" 1>&6 -echo "configure:5018: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5 +echo "configure:5074: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5 if eval "test \"\${lt_cv_prog_cc_pic_works+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" cat > conftest.$ac_ext <<EOF -#line 5025 "configure" +#line 5081 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:5032: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5088: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* case $host_os in hpux9* | hpux10* | hpux11*) @@ -5080,7 +5136,7 @@ if test -n "$lt_cv_prog_cc_shlib"; then fi echo $ac_n "checking if $compiler static flag $lt_cv_prog_cc_static works""... $ac_c" 1>&6 -echo "configure:5084: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5 +echo "configure:5140: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5 if eval "test \"\${lt_cv_prog_cc_static_works+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -5088,14 +5144,14 @@ else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" cat > conftest.$ac_ext <<EOF -#line 5092 "configure" +#line 5148 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:5099: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_prog_cc_static_works=yes else @@ -5122,7 +5178,7 @@ can_build_shared="$lt_cv_prog_cc_can_build_shared" # Check to see if options -o and -c are simultaneously supported by compiler echo $ac_n "checking if $compiler supports -c -o file.$ac_objext""... $ac_c" 1>&6 -echo "configure:5126: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo "configure:5182: checking if $compiler supports -c -o file.$ac_objext" >&5 if eval "test \"\${lt_cv_compiler_c_o+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -5141,7 +5197,7 @@ chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" compiler_c_o=no -if { (eval echo configure:5145: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then +if { (eval echo configure:5201: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then @@ -5170,7 +5226,7 @@ echo "$ac_t""$compiler_c_o" 1>&6 if test x"$compiler_c_o" = x"yes"; then # Check to see if we can write to a .lo echo $ac_n "checking if $compiler supports -c -o file.lo""... $ac_c" 1>&6 -echo "configure:5174: checking if $compiler supports -c -o file.lo" >&5 +echo "configure:5230: checking if $compiler supports -c -o file.lo" >&5 if eval "test \"\${lt_cv_compiler_o_lo+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -5181,14 +5237,14 @@ else save_objext="$ac_objext" ac_objext=lo cat > conftest.$ac_ext <<EOF -#line 5185 "configure" +#line 5241 "configure" #include "confdefs.h" int main() { int some_variable = 0; ; return 0; } EOF -if { (eval echo configure:5192: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5248: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -5219,7 +5275,7 @@ hard_links="nottested" if test "$compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo $ac_n "checking if we can lock with hard links""... $ac_c" 1>&6 -echo "configure:5223: checking if we can lock with hard links" >&5 +echo "configure:5279: checking if we can lock with hard links" >&5 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no @@ -5238,20 +5294,20 @@ fi if test "$GCC" = yes; then # Check to see if options -fno-rtti -fno-exceptions are supported by compiler echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions""... $ac_c" 1>&6 -echo "configure:5242: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo "configure:5298: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 echo "int some_variable = 0;" > conftest.$ac_ext save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" compiler_rtti_exceptions=no cat > conftest.$ac_ext <<EOF -#line 5248 "configure" +#line 5304 "configure" #include "confdefs.h" int main() { int some_variable = 0; ; return 0; } EOF -if { (eval echo configure:5255: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5311: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -5278,7 +5334,7 @@ fi # See if the linker supports building shared libraries. echo $ac_n "checking whether the linker ($LD) supports shared libraries""... $ac_c" 1>&6 -echo "configure:5282: checking whether the linker ($LD) supports shared libraries" >&5 +echo "configure:5338: checking whether the linker ($LD) supports shared libraries" >&5 allow_undefined_flag= no_undefined_flag= @@ -5962,7 +6018,7 @@ test "$ld_shlibs" = no && can_build_shared=no # Check hardcoding attributes. echo $ac_n "checking how to hardcode library paths into programs""... $ac_c" 1>&6 -echo "configure:5966: checking how to hardcode library paths into programs" >&5 +echo "configure:6022: checking how to hardcode library paths into programs" >&5 hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var"; then @@ -5990,7 +6046,7 @@ echo "$ac_t""$hardcode_action" 1>&6 striplib= old_striplib= echo $ac_n "checking whether stripping libraries is possible""... $ac_c" 1>&6 -echo "configure:5994: checking whether stripping libraries is possible" >&5 +echo "configure:6050: checking whether stripping libraries is possible" >&5 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" @@ -6004,7 +6060,7 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown # PORTME Fill in your ld.so characteristics echo $ac_n "checking dynamic linker characteristics""... $ac_c" 1>&6 -echo "configure:6008: checking dynamic linker characteristics" >&5 +echo "configure:6064: checking dynamic linker characteristics" >&5 library_names_spec= libname_spec='lib$name' soname_spec= @@ -6401,11 +6457,11 @@ test "$dynamic_linker" = no && can_build_shared=no # Report the final consequences. echo $ac_n "checking if libtool supports shared libraries""... $ac_c" 1>&6 -echo "configure:6405: checking if libtool supports shared libraries" >&5 +echo "configure:6461: checking if libtool supports shared libraries" >&5 echo "$ac_t""$can_build_shared" 1>&6 echo $ac_n "checking whether to build shared libraries""... $ac_c" 1>&6 -echo "configure:6409: checking whether to build shared libraries" >&5 +echo "configure:6465: checking whether to build shared libraries" >&5 test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and @@ -6428,7 +6484,7 @@ esac echo "$ac_t""$enable_shared" 1>&6 echo $ac_n "checking whether to build static libraries""... $ac_c" 1>&6 -echo "configure:6432: checking whether to build static libraries" >&5 +echo "configure:6488: checking whether to build static libraries" >&5 # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes echo "$ac_t""$enable_static" 1>&6 @@ -6469,12 +6525,12 @@ else *) echo $ac_n "checking for shl_load""... $ac_c" 1>&6 -echo "configure:6473: checking for shl_load" >&5 +echo "configure:6529: checking for shl_load" >&5 if eval "test \"\${ac_cv_func_shl_load+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 6478 "configure" +#line 6534 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char shl_load(); below. */ @@ -6498,7 +6554,7 @@ f = shl_load; ; return 0; } EOF -if { (eval echo configure:6502: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_shl_load=yes" else @@ -6516,7 +6572,7 @@ if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 -echo "configure:6520: checking for shl_load in -ldld" >&5 +echo "configure:6576: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6524,7 +6580,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <<EOF -#line 6528 "configure" +#line 6584 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -6535,7 +6591,7 @@ int main() { shl_load() ; return 0; } EOF -if { (eval echo configure:6539: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6595: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6554,12 +6610,12 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen""... $ac_c" 1>&6 -echo "configure:6558: checking for dlopen" >&5 +echo "configure:6614: checking for dlopen" >&5 if eval "test \"\${ac_cv_func_dlopen+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 6563 "configure" +#line 6619 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dlopen(); below. */ @@ -6583,7 +6639,7 @@ f = dlopen; ; return 0; } EOF -if { (eval echo configure:6587: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6643: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else @@ -6601,7 +6657,7 @@ if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:6605: checking for dlopen in -ldl" >&5 +echo "configure:6661: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6609,7 +6665,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <<EOF -#line 6613 "configure" +#line 6669 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -6620,7 +6676,7 @@ int main() { dlopen() ; return 0; } EOF -if { (eval echo configure:6624: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6639,7 +6695,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen in -lsvld""... $ac_c" 1>&6 -echo "configure:6643: checking for dlopen in -lsvld" >&5 +echo "configure:6699: checking for dlopen in -lsvld" >&5 ac_lib_var=`echo svld'_'dlopen | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6647,7 +6703,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsvld $LIBS" cat > conftest.$ac_ext <<EOF -#line 6651 "configure" +#line 6707 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -6658,7 +6714,7 @@ int main() { dlopen() ; return 0; } EOF -if { (eval echo configure:6662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6718: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6677,7 +6733,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 -echo "configure:6681: checking for dld_link in -ldld" >&5 +echo "configure:6737: checking for dld_link in -ldld" >&5 ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6685,7 +6741,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <<EOF -#line 6689 "configure" +#line 6745 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -6696,7 +6752,7 @@ int main() { dld_link() ; return 0; } EOF -if { (eval echo configure:6700: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6756: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6752,7 +6808,7 @@ fi LIBS="$lt_cv_dlopen_libs $LIBS" echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 -echo "configure:6756: checking whether a program can dlopen itself" >&5 +echo "configure:6812: checking whether a program can dlopen itself" >&5 if eval "test \"\${lt_cv_dlopen_self+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -6762,7 +6818,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 6766 "configure" +#line 6822 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -6823,7 +6879,7 @@ int main () exit (status); } EOF - if { (eval echo configure:6827: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} 2>/dev/null; then + if { (eval echo configure:6883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in @@ -6846,7 +6902,7 @@ echo "$ac_t""$lt_cv_dlopen_self" 1>&6 if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 -echo "configure:6850: checking whether a statically linked program can dlopen itself" >&5 +echo "configure:6906: checking whether a statically linked program can dlopen itself" >&5 if eval "test \"\${lt_cv_dlopen_self_static+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -6856,7 +6912,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 6860 "configure" +#line 6916 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -6917,7 +6973,7 @@ int main () exit (status); } EOF - if { (eval echo configure:6921: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} 2>/dev/null; then + if { (eval echo configure:6977: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in @@ -6966,14 +7022,14 @@ if test "$enable_shared" = yes && test "$GCC" = yes; then # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. echo $ac_n "checking whether -lc should be explicitly linked in""... $ac_c" 1>&6 -echo "configure:6970: checking whether -lc should be explicitly linked in" >&5 +echo "configure:7026: checking whether -lc should be explicitly linked in" >&5 if eval "test \"\${lt_cv_archive_cmds_need_lc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else $rm conftest* echo 'static int dummy;' > conftest.$ac_ext - if { (eval echo configure:6977: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + if { (eval echo configure:7033: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then soname=conftest lib=conftest libobjs=conftest.$ac_objext @@ -6986,7 +7042,7 @@ else libname=conftest save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= - if { (eval echo configure:6990: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\") 1>&5; (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5; } + if { (eval echo configure:7046: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\") 1>&5; (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5; } then lt_cv_archive_cmds_need_lc=no else @@ -7573,7 +7629,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7577: checking for $ac_word" >&5 +echo "configure:7633: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AWK+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7604,7 +7660,7 @@ done # test for ln hardlink support echo $ac_n "checking whether ln works""... $ac_c" 1>&6 -echo "configure:7608: checking whether ln works" >&5 +echo "configure:7664: checking whether ln works" >&5 if eval "test \"\${ol_cv_prog_LN_H+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7627,7 +7683,7 @@ else fi echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:7631: checking whether ln -s works" >&5 +echo "configure:7687: checking whether ln -s works" >&5 if eval "test \"\${ac_cv_prog_LN_S+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7651,7 +7707,7 @@ fi # Extract the first word of "sendmail", so it can be a program name with args. set dummy sendmail; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7655: checking for $ac_word" >&5 +echo "configure:7711: checking for $ac_word" >&5 if eval "test \"\${ac_cv_path_SENDMAIL+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7687,7 +7743,7 @@ fi # Extract the first word of "vi", so it can be a program name with args. set dummy vi; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7691: checking for $ac_word" >&5 +echo "configure:7747: checking for $ac_word" >&5 if eval "test \"\${ac_cv_path_EDITOR+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7723,7 +7779,7 @@ fi # Extract the first word of "finger", so it can be a program name with args. set dummy finger; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7727: checking for $ac_word" >&5 +echo "configure:7783: checking for $ac_word" >&5 if eval "test \"\${ac_cv_path_FINGER+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7762,7 +7818,7 @@ if test $ol_enable_perl != no ; then # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7766: checking for $ac_word" >&5 +echo "configure:7822: checking for $ac_word" >&5 if eval "test \"\${ac_cv_path_PERLBIN+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7813,7 +7869,7 @@ fi fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:7817: checking how to run the C preprocessor" >&5 +echo "configure:7873: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -7828,13 +7884,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 7832 "configure" +#line 7888 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7838: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7894: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -7845,13 +7901,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 7849 "configure" +#line 7905 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7855: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7911: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -7862,13 +7918,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 7866 "configure" +#line 7922 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7872: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7928: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -7907,12 +7963,12 @@ fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:7911: checking for Cygwin environment" >&5 +echo "configure:7967: checking for Cygwin environment" >&5 if eval "test \"\${ac_cv_cygwin+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 7916 "configure" +#line 7972 "configure" #include "confdefs.h" int main() { @@ -7923,7 +7979,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:7927: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:7983: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -7939,19 +7995,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:7943: checking for mingw32 environment" >&5 +echo "configure:7999: checking for mingw32 environment" >&5 if eval "test \"\${ac_cv_mingw32+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 7948 "configure" +#line 8004 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:7955: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:8011: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -7970,7 +8026,7 @@ test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:7974: checking for executable suffix" >&5 +echo "configure:8030: checking for executable suffix" >&5 if eval "test \"\${ac_cv_exeext+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7980,7 +8036,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:7984: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:8040: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.C | *.o | *.obj | *.xcoff) ;; @@ -8001,13 +8057,13 @@ echo "$ac_t""${ac_cv_exeext}" 1>&6 ac_exeext=$EXEEXT echo $ac_n "checking for object suffix""... $ac_c" 1>&6 -echo "configure:8005: checking for object suffix" >&5 +echo "configure:8061: checking for object suffix" >&5 if eval "test \"\${ac_cv_objext+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftest* echo 'int i = 1;' > conftest.$ac_ext -if { (eval echo configure:8011: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:8067: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then for ac_file in conftest.*; do case $ac_file in *.c) ;; @@ -8031,7 +8087,7 @@ EOF echo $ac_n "checking for be_app in -lbe""... $ac_c" 1>&6 -echo "configure:8035: checking for be_app in -lbe" >&5 +echo "configure:8091: checking for be_app in -lbe" >&5 ac_lib_var=`echo be'_'be_app | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8039,7 +8095,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lbe -lroot -lnet $LIBS" cat > conftest.$ac_ext <<EOF -#line 8043 "configure" +#line 8099 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8050,7 +8106,7 @@ int main() { be_app() ; return 0; } EOF -if { (eval echo configure:8054: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8110: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8076,7 +8132,7 @@ fi echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6 -echo "configure:8080: checking for ${CC-cc} option to accept ANSI C" >&5 +echo "configure:8136: checking for ${CC-cc} option to accept ANSI C" >&5 if eval "test \"\${am_cv_prog_cc_stdc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8093,7 +8149,7 @@ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIO do CC="$ac_save_CC $ac_arg" cat > conftest.$ac_ext <<EOF -#line 8097 "configure" +#line 8153 "configure" #include "confdefs.h" #include <stdarg.h> #include <stdio.h> @@ -8130,7 +8186,7 @@ return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } EOF -if { (eval echo configure:8134: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:8190: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* am_cv_prog_cc_stdc="$ac_arg"; break else @@ -8164,7 +8220,7 @@ if test -z "${MKDEP}"; then OL_MKDEP="${CC-cc}" if test -z "${MKDEP_FLAGS}"; then echo $ac_n "checking for ${OL_MKDEP} depend flag""... $ac_c" 1>&6 -echo "configure:8168: checking for ${OL_MKDEP} depend flag" >&5 +echo "configure:8224: checking for ${OL_MKDEP} depend flag" >&5 if eval "test \"\${ol_cv_mkdep+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8174,7 +8230,7 @@ else cat > conftest.c <<EOF noCode; EOF - if { ac_try='$OL_MKDEP $flag conftest.c'; { (eval echo configure:8178: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } \ + if { ac_try='$OL_MKDEP $flag conftest.c'; { (eval echo configure:8234: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } \ | egrep '^conftest\.'"${ac_objext}" >/dev/null 2>&1 then if test ! -f conftest."${ac_object}" ; then @@ -8207,7 +8263,7 @@ if test "${ol_cv_mkdep}" = no ; then fi echo $ac_n "checking for afopen in -ls""... $ac_c" 1>&6 -echo "configure:8211: checking for afopen in -ls" >&5 +echo "configure:8267: checking for afopen in -ls" >&5 ac_lib_var=`echo s'_'afopen | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8215,7 +8271,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ls $LIBS" cat > conftest.$ac_ext <<EOF -#line 8219 "configure" +#line 8275 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8226,7 +8282,7 @@ int main() { afopen() ; return 0; } EOF -if { (eval echo configure:8230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8260,17 +8316,17 @@ if test $ol_enable_modules != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8264: checking for $ac_hdr" >&5 +echo "configure:8320: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8269 "configure" +#line 8325 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8274: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8330: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8302,7 +8358,7 @@ done fi echo $ac_n "checking for lt_dlinit in -lltdl""... $ac_c" 1>&6 -echo "configure:8306: checking for lt_dlinit in -lltdl" >&5 +echo "configure:8362: checking for lt_dlinit in -lltdl" >&5 ac_lib_var=`echo ltdl'_'lt_dlinit | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8310,7 +8366,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lltdl $LIBS" cat > conftest.$ac_ext <<EOF -#line 8314 "configure" +#line 8370 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8321,7 +8377,7 @@ int main() { lt_dlinit() ; return 0; } EOF -if { (eval echo configure:8325: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8381: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8359,6 +8415,7 @@ else ol_with_ldbm_module=static ol_with_meta_module=static ol_with_monitor_module=static + ol_with_null_module=static ol_with_passwd_module=static ol_with_perl_module=static ol_with_shell_module=static @@ -8367,13 +8424,13 @@ fi # test for EBCDIC echo $ac_n "checking for EBCDIC""... $ac_c" 1>&6 -echo "configure:8371: checking for EBCDIC" >&5 +echo "configure:8428: checking for EBCDIC" >&5 if eval "test \"\${ol_cv_cpp_ebcdic+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8377 "configure" +#line 8434 "configure" #include "confdefs.h" #if !('M' == 0xd4) @@ -8382,7 +8439,7 @@ else EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8386: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8443: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8406,12 +8463,12 @@ EOF fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:8410: checking for ANSI C header files" >&5 +echo "configure:8467: checking for ANSI C header files" >&5 if eval "test \"\${ol_cv_header_stdc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8415 "configure" +#line 8472 "configure" #include "confdefs.h" #include <stdlib.h> #include <stdarg.h> @@ -8419,7 +8476,7 @@ else #include <float.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8423: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8480: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8436,7 +8493,7 @@ rm -f conftest* if test $ol_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 8440 "configure" +#line 8497 "configure" #include "confdefs.h" #include <string.h> EOF @@ -8454,7 +8511,7 @@ fi if test $ol_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 8458 "configure" +#line 8515 "configure" #include "confdefs.h" #include <stdlib.h> EOF @@ -8475,7 +8532,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext <<EOF -#line 8479 "configure" +#line 8536 "configure" #include "confdefs.h" #include <ctype.h> #ifndef HAVE_EBCDIC @@ -8493,7 +8550,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:8497: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:8554: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -8527,12 +8584,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 -echo "configure:8531: checking for $ac_hdr that defines DIR" >&5 +echo "configure:8588: checking for $ac_hdr that defines DIR" >&5 if eval "test \"\${ac_cv_header_dirent_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8536 "configure" +#line 8593 "configure" #include "confdefs.h" #include <sys/types.h> #include <$ac_hdr> @@ -8540,7 +8597,7 @@ int main() { DIR *dirp = 0; ; return 0; } EOF -if { (eval echo configure:8544: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:8601: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else @@ -8565,7 +8622,7 @@ done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 -echo "configure:8569: checking for opendir in -ldir" >&5 +echo "configure:8626: checking for opendir in -ldir" >&5 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8573,7 +8630,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext <<EOF -#line 8577 "configure" +#line 8634 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8584,7 +8641,7 @@ int main() { opendir() ; return 0; } EOF -if { (eval echo configure:8588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8645: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8606,7 +8663,7 @@ fi else echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 -echo "configure:8610: checking for opendir in -lx" >&5 +echo "configure:8667: checking for opendir in -lx" >&5 ac_lib_var=`echo x'_'opendir | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8614,7 +8671,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext <<EOF -#line 8618 "configure" +#line 8675 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8625,7 +8682,7 @@ int main() { opendir() ; return 0; } EOF -if { (eval echo configure:8629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8686: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8648,12 +8705,12 @@ fi fi echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 -echo "configure:8652: checking for sys/wait.h that is POSIX.1 compatible" >&5 +echo "configure:8709: checking for sys/wait.h that is POSIX.1 compatible" >&5 if eval "test \"\${ac_cv_header_sys_wait_h+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8657 "configure" +#line 8714 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/wait.h> @@ -8669,7 +8726,7 @@ wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } EOF -if { (eval echo configure:8673: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:8730: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_sys_wait_h=yes else @@ -8690,12 +8747,12 @@ EOF fi echo $ac_n "checking POSIX termios""... $ac_c" 1>&6 -echo "configure:8694: checking POSIX termios" >&5 +echo "configure:8751: checking POSIX termios" >&5 if eval "test \"\${am_cv_sys_posix_termios+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8699 "configure" +#line 8756 "configure" #include "confdefs.h" #include <sys/types.h> #include <unistd.h> @@ -8705,7 +8762,7 @@ int main() { tcgetattr(0, 0); ; return 0; } EOF -if { (eval echo configure:8709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8766: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_sys_posix_termios=yes else @@ -8721,7 +8778,7 @@ echo "$ac_t""$am_cv_sys_posix_termios" 1>&6 echo $ac_n "checking whether use of TIOCGWINSZ requires sys/ioctl.h""... $ac_c" 1>&6 -echo "configure:8725: checking whether use of TIOCGWINSZ requires sys/ioctl.h" >&5 +echo "configure:8782: checking whether use of TIOCGWINSZ requires sys/ioctl.h" >&5 if eval "test \"\${am_cv_sys_tiocgwinsz_needs_sys_ioctl_h+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8730,7 +8787,7 @@ else gwinsz_in_termios_h=no if test $am_cv_sys_posix_termios = yes; then cat > conftest.$ac_ext <<EOF -#line 8734 "configure" +#line 8791 "configure" #include "confdefs.h" #include <sys/types.h> # include <termios.h> @@ -8750,7 +8807,7 @@ rm -f conftest* if test $gwinsz_in_termios_h = no; then cat > conftest.$ac_ext <<EOF -#line 8754 "configure" +#line 8811 "configure" #include "confdefs.h" #include <sys/types.h> # include <sys/ioctl.h> @@ -8834,17 +8891,17 @@ for ac_hdr in \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8838: checking for $ac_hdr" >&5 +echo "configure:8895: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8843 "configure" +#line 8900 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8848: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8905: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8874,12 +8931,12 @@ done echo $ac_n "checking for dlopen""... $ac_c" 1>&6 -echo "configure:8878: checking for dlopen" >&5 +echo "configure:8935: checking for dlopen" >&5 if eval "test \"\${ac_cv_func_dlopen+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 8883 "configure" +#line 8940 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dlopen(); below. */ @@ -8903,7 +8960,7 @@ f = dlopen; ; return 0; } EOF -if { (eval echo configure:8907: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8964: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else @@ -8921,7 +8978,7 @@ if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:8925: checking for dlopen in -ldl" >&5 +echo "configure:8982: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8929,7 +8986,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <<EOF -#line 8933 "configure" +#line 8990 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8940,7 +8997,7 @@ int main() { dlopen() ; return 0; } EOF -if { (eval echo configure:8944: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9001: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8971,7 +9028,7 @@ fi echo $ac_n "checking for sigset in -lV3""... $ac_c" 1>&6 -echo "configure:8975: checking for sigset in -lV3" >&5 +echo "configure:9032: checking for sigset in -lV3" >&5 ac_lib_var=`echo V3'_'sigset | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8979,7 +9036,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lV3 $LIBS" cat > conftest.$ac_ext <<EOF -#line 8983 "configure" +#line 9040 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -8990,7 +9047,7 @@ int main() { sigset() ; return 0; } EOF -if { (eval echo configure:8994: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9051: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9019,12 +9076,12 @@ fi echo $ac_n "checking for winsock""... $ac_c" 1>&6 -echo "configure:9023: checking for winsock" >&5 +echo "configure:9080: checking for winsock" >&5 save_LIBS="$LIBS" for curlib in ws2_32 wsock32; do LIBS="$LIBS -l$curlib" cat > conftest.$ac_ext <<EOF -#line 9028 "configure" +#line 9085 "configure" #include "confdefs.h" char socket@12(); @@ -9041,7 +9098,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:9045: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9102: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* have_winsock=yes else @@ -9076,12 +9133,12 @@ echo "$ac_t""$have_winsock" 1>&6 echo $ac_n "checking for socket""... $ac_c" 1>&6 -echo "configure:9080: checking for socket" >&5 +echo "configure:9137: checking for socket" >&5 if eval "test \"\${ac_cv_func_socket+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9085 "configure" +#line 9142 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char socket(); below. */ @@ -9105,7 +9162,7 @@ f = socket; ; return 0; } EOF -if { (eval echo configure:9109: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9166: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_socket=yes" else @@ -9124,7 +9181,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 -echo "configure:9128: checking for main in -lsocket" >&5 +echo "configure:9185: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9132,14 +9189,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <<EOF -#line 9136 "configure" +#line 9193 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:9143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9200: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9167,7 +9224,7 @@ else fi echo $ac_n "checking for main in -lnet""... $ac_c" 1>&6 -echo "configure:9171: checking for main in -lnet" >&5 +echo "configure:9228: checking for main in -lnet" >&5 ac_lib_var=`echo net'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9175,14 +9232,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lnet $LIBS" cat > conftest.$ac_ext <<EOF -#line 9179 "configure" +#line 9236 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:9186: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9210,7 +9267,7 @@ else fi echo $ac_n "checking for main in -lnsl_s""... $ac_c" 1>&6 -echo "configure:9214: checking for main in -lnsl_s" >&5 +echo "configure:9271: checking for main in -lnsl_s" >&5 ac_lib_var=`echo nsl_s'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9218,14 +9275,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl_s $LIBS" cat > conftest.$ac_ext <<EOF -#line 9222 "configure" +#line 9279 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:9229: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9253,7 +9310,7 @@ else fi echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 -echo "configure:9257: checking for main in -lnsl" >&5 +echo "configure:9314: checking for main in -lnsl" >&5 ac_lib_var=`echo nsl'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9261,14 +9318,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <<EOF -#line 9265 "configure" +#line 9322 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:9272: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9329: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9296,7 +9353,7 @@ else fi echo $ac_n "checking for socket in -linet""... $ac_c" 1>&6 -echo "configure:9300: checking for socket in -linet" >&5 +echo "configure:9357: checking for socket in -linet" >&5 ac_lib_var=`echo inet'_'socket | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9304,7 +9361,7 @@ else ac_save_LIBS="$LIBS" LIBS="-linet $LIBS" cat > conftest.$ac_ext <<EOF -#line 9308 "configure" +#line 9365 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9315,7 +9372,7 @@ int main() { socket() ; return 0; } EOF -if { (eval echo configure:9319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9376: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9343,7 +9400,7 @@ else fi echo $ac_n "checking for main in -lgen""... $ac_c" 1>&6 -echo "configure:9347: checking for main in -lgen" >&5 +echo "configure:9404: checking for main in -lgen" >&5 ac_lib_var=`echo gen'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9351,14 +9408,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lgen $LIBS" cat > conftest.$ac_ext <<EOF -#line 9355 "configure" +#line 9412 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:9362: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9419: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9390,12 +9447,12 @@ fi echo $ac_n "checking for select""... $ac_c" 1>&6 -echo "configure:9394: checking for select" >&5 +echo "configure:9451: checking for select" >&5 if eval "test \"\${ac_cv_func_select+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9399 "configure" +#line 9456 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char select(); below. */ @@ -9419,7 +9476,7 @@ f = select; ; return 0; } EOF -if { (eval echo configure:9423: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9480: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_select=yes" else @@ -9442,7 +9499,7 @@ fi if test "${ac_cv_header_winsock_h}" != yes; then echo $ac_n "checking types of arguments for select()""... $ac_c" 1>&6 -echo "configure:9446: checking types of arguments for select()" >&5 +echo "configure:9503: checking types of arguments for select()" >&5 if eval "test \"\${ac_cv_func_select_arg234+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -9456,7 +9513,7 @@ else for ac_cv_func_select_arg1 in 'int' 'size_t' 'unsigned long' 'unsigned'; do for ac_cv_func_select_arg5 in 'struct timeval *' 'const struct timeval *'; do cat > conftest.$ac_ext <<EOF -#line 9460 "configure" +#line 9517 "configure" #include "confdefs.h" #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -9475,7 +9532,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:9479: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:9536: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_not_found=no ; break 3 else @@ -9520,17 +9577,17 @@ for ac_hdr in regex.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:9524: checking for $ac_hdr" >&5 +echo "configure:9581: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9529 "configure" +#line 9586 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:9534: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:9591: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -9561,14 +9618,14 @@ if test "$ac_cv_header_regex_h" != yes ; then fi echo $ac_n "checking for library containing regfree""... $ac_c" 1>&6 -echo "configure:9565: checking for library containing regfree" >&5 +echo "configure:9622: checking for library containing regfree" >&5 if eval "test \"\${ac_cv_search_regfree+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_func_search_save_LIBS="$LIBS" ac_cv_search_regfree="no" cat > conftest.$ac_ext <<EOF -#line 9572 "configure" +#line 9629 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9579,7 +9636,7 @@ int main() { regfree() ; return 0; } EOF -if { (eval echo configure:9583: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9640: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_regfree="none required" else @@ -9590,7 +9647,7 @@ rm -f conftest* test "$ac_cv_search_regfree" = "no" && for ac_lib in regex gnuregex; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat > conftest.$ac_ext <<EOF -#line 9594 "configure" +#line 9651 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9601,7 +9658,7 @@ int main() { regfree() ; return 0; } EOF -if { (eval echo configure:9605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_regfree="-l$ac_lib" break @@ -9624,7 +9681,7 @@ fi echo $ac_n "checking for compatible POSIX regex""... $ac_c" 1>&6 -echo "configure:9628: checking for compatible POSIX regex" >&5 +echo "configure:9685: checking for compatible POSIX regex" >&5 if eval "test \"\${ol_cv_c_posix_regex+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -9633,7 +9690,7 @@ else ol_cv_c_posix_regex=cross else cat > conftest.$ac_ext <<EOF -#line 9637 "configure" +#line 9694 "configure" #include "confdefs.h" #include <sys/types.h> @@ -9659,7 +9716,7 @@ main() return rc; } EOF -if { (eval echo configure:9663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:9720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_c_posix_regex=yes else @@ -9685,17 +9742,17 @@ for ac_hdr in sys/uuid.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:9689: checking for $ac_hdr" >&5 +echo "configure:9746: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9694 "configure" +#line 9751 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:9699: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:9756: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -9725,14 +9782,14 @@ if test $ac_cv_header_sys_uuid_h = yes ; then save_LIBS="$LIBS" echo $ac_n "checking for library containing uuid_to_str""... $ac_c" 1>&6 -echo "configure:9729: checking for library containing uuid_to_str" >&5 +echo "configure:9786: checking for library containing uuid_to_str" >&5 if eval "test \"\${ac_cv_search_uuid_to_str+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_func_search_save_LIBS="$LIBS" ac_cv_search_uuid_to_str="no" cat > conftest.$ac_ext <<EOF -#line 9736 "configure" +#line 9793 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9743,7 +9800,7 @@ int main() { uuid_to_str() ; return 0; } EOF -if { (eval echo configure:9747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9804: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_uuid_to_str="none required" else @@ -9754,7 +9811,7 @@ rm -f conftest* test "$ac_cv_search_uuid_to_str" = "no" && for ac_lib in uuid; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat > conftest.$ac_ext <<EOF -#line 9758 "configure" +#line 9815 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9765,7 +9822,7 @@ int main() { uuid_to_str() ; return 0; } EOF -if { (eval echo configure:9769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9826: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_uuid_to_str="-l$ac_lib" break @@ -9800,11 +9857,11 @@ fi if test $have_uuid = no ; then echo $ac_n "checking to see if -lrpcrt4 is needed for win32 UUID support""... $ac_c" 1>&6 -echo "configure:9804: checking to see if -lrpcrt4 is needed for win32 UUID support" >&5 +echo "configure:9861: checking to see if -lrpcrt4 is needed for win32 UUID support" >&5 save_LIBS="$LIBS" LIBS="$LIBS -lrpcrt4" cat > conftest.$ac_ext <<EOF -#line 9808 "configure" +#line 9865 "configure" #include "confdefs.h" char UuidCreate@4(); @@ -9817,7 +9874,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:9821: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9878: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* need_rpcrt=yes else @@ -9836,12 +9893,12 @@ fi ol_link_dnssrv=no echo $ac_n "checking for res_query""... $ac_c" 1>&6 -echo "configure:9840: checking for res_query" >&5 +echo "configure:9897: checking for res_query" >&5 if eval "test \"\${ac_cv_func_res_query+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9845 "configure" +#line 9902 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char res_query(); below. */ @@ -9865,7 +9922,7 @@ f = res_query; ; return 0; } EOF -if { (eval echo configure:9869: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9926: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_res_query=yes" else @@ -9886,12 +9943,12 @@ fi if test $ac_cv_func_res_query = no ; then echo $ac_n "checking for __res_query""... $ac_c" 1>&6 -echo "configure:9890: checking for __res_query" >&5 +echo "configure:9947: checking for __res_query" >&5 if eval "test \"\${ac_cv_func___res_query+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 9895 "configure" +#line 9952 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char __res_query(); below. */ @@ -9915,7 +9972,7 @@ f = __res_query; ; return 0; } EOF -if { (eval echo configure:9919: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9976: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func___res_query=yes" else @@ -9939,7 +9996,7 @@ fi if test $ac_cv_func_res_query = no ; then echo $ac_n "checking for res_query in -lbind""... $ac_c" 1>&6 -echo "configure:9943: checking for res_query in -lbind" >&5 +echo "configure:10000: checking for res_query in -lbind" >&5 ac_lib_var=`echo bind'_'res_query | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9947,7 +10004,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lbind $LIBS" cat > conftest.$ac_ext <<EOF -#line 9951 "configure" +#line 10008 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -9958,7 +10015,7 @@ int main() { res_query() ; return 0; } EOF -if { (eval echo configure:9962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9990,7 +10047,7 @@ fi if test $ac_cv_func_res_query = no ; then echo $ac_n "checking for __res_query in -lbind""... $ac_c" 1>&6 -echo "configure:9994: checking for __res_query in -lbind" >&5 +echo "configure:10051: checking for __res_query in -lbind" >&5 ac_lib_var=`echo bind'_'__res_query | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9998,7 +10055,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lbind $LIBS" cat > conftest.$ac_ext <<EOF -#line 10002 "configure" +#line 10059 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -10009,7 +10066,7 @@ int main() { __res_query() ; return 0; } EOF -if { (eval echo configure:10013: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10041,7 +10098,7 @@ fi if test $ac_cv_func_res_query = no ; then echo $ac_n "checking for res_query in -lresolv""... $ac_c" 1>&6 -echo "configure:10045: checking for res_query in -lresolv" >&5 +echo "configure:10102: checking for res_query in -lresolv" >&5 ac_lib_var=`echo resolv'_'res_query | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10049,7 +10106,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lresolv $LIBS" cat > conftest.$ac_ext <<EOF -#line 10053 "configure" +#line 10110 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -10060,7 +10117,7 @@ int main() { res_query() ; return 0; } EOF -if { (eval echo configure:10064: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10092,7 +10149,7 @@ fi if test $ac_cv_func_res_query = no ; then echo $ac_n "checking for __res_query in -lresolv""... $ac_c" 1>&6 -echo "configure:10096: checking for __res_query in -lresolv" >&5 +echo "configure:10153: checking for __res_query in -lresolv" >&5 ac_lib_var=`echo resolv'_'__res_query | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10100,7 +10157,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lresolv $LIBS" cat > conftest.$ac_ext <<EOF -#line 10104 "configure" +#line 10161 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -10111,7 +10168,7 @@ int main() { __res_query() ; return 0; } EOF -if { (eval echo configure:10115: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10172: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10159,12 +10216,12 @@ fi for ac_func in getaddrinfo gai_strerror inet_ntop do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:10163: checking for $ac_func" >&5 +echo "configure:10220: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10168 "configure" +#line 10225 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -10188,7 +10245,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:10192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10249: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -10220,13 +10277,13 @@ if test $ac_cv_func_getaddrinfo = no -o $ac_cv_func_inet_ntop = no ; then fi elif test $ol_enable_ipv6 != no ; then echo $ac_n "checking INET6_ADDRSTRLEN""... $ac_c" 1>&6 -echo "configure:10224: checking INET6_ADDRSTRLEN" >&5 +echo "configure:10281: checking INET6_ADDRSTRLEN" >&5 if eval "test \"\${ol_cv_inet6_addrstrlen+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10230 "configure" +#line 10287 "configure" #include "confdefs.h" # include <netinet/in.h> @@ -10261,17 +10318,17 @@ if test $ol_enable_local != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10265: checking for $ac_hdr" >&5 +echo "configure:10322: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10270 "configure" +#line 10327 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10275: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10332: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10318,17 +10375,17 @@ if test $ol_with_kerberos = yes -o $ol_with_kerberos = auto \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10322: checking for $ac_hdr" >&5 +echo "configure:10379: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10327 "configure" +#line 10384 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10332: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10389: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10360,17 +10417,17 @@ done do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10364: checking for $ac_hdr" >&5 +echo "configure:10421: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10369 "configure" +#line 10426 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10374: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10431: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10404,7 +10461,7 @@ done if test $krb5_impl = mit; then echo $ac_n "checking for main in -lk5crypto""... $ac_c" 1>&6 -echo "configure:10408: checking for main in -lk5crypto" >&5 +echo "configure:10465: checking for main in -lk5crypto" >&5 ac_lib_var=`echo k5crypto'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10412,14 +10469,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lk5crypto $LIBS" cat > conftest.$ac_ext <<EOF -#line 10416 "configure" +#line 10473 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10423: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10480: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10442,7 +10499,7 @@ fi echo $ac_n "checking for main in -lkrb5""... $ac_c" 1>&6 -echo "configure:10446: checking for main in -lkrb5" >&5 +echo "configure:10503: checking for main in -lkrb5" >&5 ac_lib_var=`echo krb5'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10450,14 +10507,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lkrb5 -l$krb5crypto -lcom_err $LIBS" cat > conftest.$ac_ext <<EOF -#line 10454 "configure" +#line 10511 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10461: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10518: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10481,23 +10538,61 @@ fi elif test $krb5_impl = heimdal; then + echo $ac_n "checking for main in -ldes""... $ac_c" 1>&6 +echo "configure:10543: checking for main in -ldes" >&5 +ac_lib_var=`echo des'_'main | sed 'y%./+-:%__p__%'` +if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldes $LIBS" +cat > conftest.$ac_ext <<EOF +#line 10551 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:10558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + krb5crypto=des +else + echo "$ac_t""no" 1>&6 +krb5crypto=crypto +fi + + echo $ac_n "checking for main in -lkrb5""... $ac_c" 1>&6 -echo "configure:10486: checking for main in -lkrb5" >&5 +echo "configure:10581: checking for main in -lkrb5" >&5 ac_lib_var=`echo krb5'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" -LIBS="-lkrb5 -ldes -lasn1 -lroken -lcom_err $LIBS" +LIBS="-lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err $LIBS" cat > conftest.$ac_ext <<EOF -#line 10494 "configure" +#line 10589 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10501: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10596: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10513,7 +10608,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 have_krb5=yes - KRB5_LIBS="-lkrb5 -ldes -lasn1 -lroken -lcom_err" + KRB5_LIBS="-lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err" else echo "$ac_t""no" 1>&6 have_krb5=no @@ -10560,17 +10655,17 @@ if test $ol_link_krb5 = yes -a \( $ol_with_kerberos = yes -o \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10564: checking for $ac_hdr" >&5 +echo "configure:10659: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10569 "configure" +#line 10664 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10574: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10669: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10600,7 +10695,7 @@ done if test $ac_cv_header_kerberosIV_krb_h = yes ; then if test $krb5_impl = mit; then echo $ac_n "checking for main in -lkrb4""... $ac_c" 1>&6 -echo "configure:10604: checking for main in -lkrb4" >&5 +echo "configure:10699: checking for main in -lkrb4" >&5 ac_lib_var=`echo krb4'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10608,14 +10703,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lkrb4 -ldes425 -lkrb5 -l$krb5crypto -lcom_err $LIBS" cat > conftest.$ac_ext <<EOF -#line 10612 "configure" +#line 10707 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10619: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10640,22 +10735,22 @@ fi elif test $krb5_impl = heimdal; then echo $ac_n "checking for main in -lkrb4""... $ac_c" 1>&6 -echo "configure:10644: checking for main in -lkrb4" >&5 +echo "configure:10739: checking for main in -lkrb4" >&5 ac_lib_var=`echo krb4'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" -LIBS="-lkrb4 -lkrb5 -ldes -lasn1 -lroken -lcom_err $LIBS" +LIBS="-lkrb4 -lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err $LIBS" cat > conftest.$ac_ext <<EOF -#line 10652 "configure" +#line 10747 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10754: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10697,7 +10792,7 @@ EOF echo $ac_n "checking for des_debug in Kerberos libraries""... $ac_c" 1>&6 -echo "configure:10701: checking for des_debug in Kerberos libraries" >&5 +echo "configure:10796: checking for des_debug in Kerberos libraries" >&5 if eval "test \"\${ol_cv_var_des_debug+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -10705,7 +10800,7 @@ else save_LIBS="$LIBS" LIBS="$KRB4_LIBS $KRB5_LIBS $LIBS" cat > conftest.$ac_ext <<EOF -#line 10709 "configure" +#line 10804 "configure" #include "confdefs.h" #include <kerberosIV/krb.h> @@ -10718,7 +10813,7 @@ des_debug = 1; ; return 0; } EOF -if { (eval echo configure:10722: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10817: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_var_des_debug=yes else @@ -10757,17 +10852,17 @@ if test $ol_with_kerberos = yes -o $ol_with_kerberos = auto \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10761: checking for $ac_hdr" >&5 +echo "configure:10856: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10766 "configure" +#line 10861 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10771: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10866: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10796,7 +10891,7 @@ done if test $ac_cv_header_krb_h = yes ; then echo $ac_n "checking for main in -lkrb""... $ac_c" 1>&6 -echo "configure:10800: checking for main in -lkrb" >&5 +echo "configure:10895: checking for main in -lkrb" >&5 ac_lib_var=`echo krb'_'main | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10804,14 +10899,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lkrb -ldes $LIBS" cat > conftest.$ac_ext <<EOF -#line 10808 "configure" +#line 10903 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:10815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10881,17 +10976,17 @@ if test $ol_with_tls != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10885: checking for $ac_hdr" >&5 +echo "configure:10980: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 10890 "configure" +#line 10985 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10895: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10920,7 +11015,7 @@ done if test $ac_cv_header_openssl_ssl_h = yes -o $ac_cv_header_ssl_h = yes ; then echo $ac_n "checking for SSLeay_add_ssl_algorithms in -lssl""... $ac_c" 1>&6 -echo "configure:10924: checking for SSLeay_add_ssl_algorithms in -lssl" >&5 +echo "configure:11019: checking for SSLeay_add_ssl_algorithms in -lssl" >&5 ac_lib_var=`echo ssl'_'SSLeay_add_ssl_algorithms | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10928,7 +11023,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lssl -lcrypto $LIBS" cat > conftest.$ac_ext <<EOF -#line 10932 "configure" +#line 11027 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -10939,7 +11034,7 @@ int main() { SSLeay_add_ssl_algorithms() ; return 0; } EOF -if { (eval echo configure:10943: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11038: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10964,7 +11059,7 @@ fi if test $have_ssleay = no ; then echo $ac_n "checking for SSL_library_init in -lssl""... $ac_c" 1>&6 -echo "configure:10968: checking for SSL_library_init in -lssl" >&5 +echo "configure:11063: checking for SSL_library_init in -lssl" >&5 ac_lib_var=`echo ssl'_'SSL_library_init | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -10972,7 +11067,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lssl -lcrypto $LIBS" cat > conftest.$ac_ext <<EOF -#line 10976 "configure" +#line 11071 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -10983,7 +11078,7 @@ int main() { SSL_library_init() ; return 0; } EOF -if { (eval echo configure:10987: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11082: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11009,7 +11104,7 @@ fi if test $have_ssleay = no ; then echo $ac_n "checking for ssl3_accept in -lssl""... $ac_c" 1>&6 -echo "configure:11013: checking for ssl3_accept in -lssl" >&5 +echo "configure:11108: checking for ssl3_accept in -lssl" >&5 ac_lib_var=`echo ssl'_'ssl3_accept | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -11017,7 +11112,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lssl -lcrypto -lRSAglue -lrsaref $LIBS" cat > conftest.$ac_ext <<EOF -#line 11021 "configure" +#line 11116 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -11028,7 +11123,7 @@ int main() { ssl3_accept() ; return 0; } EOF -if { (eval echo configure:11032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11127: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11075,7 +11170,7 @@ EOF fi else - echo "configure: warning: TLS privacy protection not supported!" 1>&2 + echo "configure: warning: TLS data protection not supported!" 1>&2 fi if test $ol_link_tls = yes ; then @@ -11086,7 +11181,7 @@ EOF elif test $ol_with_tls = auto ; then echo "configure: warning: Could not locate TLS/SSL package" 1>&2 - echo "configure: warning: TLS privacy protection not supported!" 1>&2 + echo "configure: warning: TLS data protection not supported!" 1>&2 elif test $ol_with_tls != no ; then { echo "configure: error: Could not locate TLS/SSL package" 1>&2; exit 1; } @@ -11109,12 +11204,12 @@ for ac_func in \ do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:11113: checking for $ac_func" >&5 +echo "configure:11208: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11118 "configure" +#line 11213 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -11138,7 +11233,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:11142: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11237: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -11167,19 +11262,19 @@ if test "$ac_cv_func_ctime_r" = no ; then ol_cv_func_ctime_r_nargs=0 else echo $ac_n "checking number of arguments of ctime_r""... $ac_c" 1>&6 -echo "configure:11171: checking number of arguments of ctime_r" >&5 +echo "configure:11266: checking number of arguments of ctime_r" >&5 if eval "test \"\${ol_cv_func_ctime_r_nargs+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11176 "configure" +#line 11271 "configure" #include "confdefs.h" #include <time.h> int main() { time_t ti; char *buffer; ctime_r(&ti,buffer,32); ; return 0; } EOF -if { (eval echo configure:11183: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11278: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_ctime_r_nargs3=yes else @@ -11191,14 +11286,14 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 11195 "configure" +#line 11290 "configure" #include "confdefs.h" #include <time.h> int main() { time_t ti; char *buffer; ctime_r(&ti,buffer); ; return 0; } EOF -if { (eval echo configure:11202: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11297: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_ctime_r_nargs2=yes else @@ -11238,12 +11333,12 @@ fi if test "$ac_cv_func_gethostbyname_r" = yes ; then echo $ac_n "checking number of arguments of gethostbyname_r""... $ac_c" 1>&6 -echo "configure:11242: checking number of arguments of gethostbyname_r" >&5 +echo "configure:11337: checking number of arguments of gethostbyname_r" >&5 if eval "test \"\${ol_cv_func_gethostbyname_r_nargs+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11247 "configure" +#line 11342 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/socket.h> @@ -11257,7 +11352,7 @@ struct hostent hent; char buffer[BUFSIZE]; buffer, bufsize, &h_errno); ; return 0; } EOF -if { (eval echo configure:11261: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11356: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_gethostbyname_r_nargs5=yes else @@ -11269,7 +11364,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 11273 "configure" +#line 11368 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/socket.h> @@ -11284,7 +11379,7 @@ struct hostent hent;struct hostent *rhent; &rhent, &h_errno); ; return 0; } EOF -if { (eval echo configure:11288: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11383: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_gethostbyname_r_nargs6=yes else @@ -11325,12 +11420,12 @@ fi if test "$ac_cv_func_gethostbyaddr_r" = yes ; then echo $ac_n "checking number of arguments of gethostbyaddr_r""... $ac_c" 1>&6 -echo "configure:11329: checking number of arguments of gethostbyaddr_r" >&5 +echo "configure:11424: checking number of arguments of gethostbyaddr_r" >&5 if eval "test \"\${ol_cv_func_gethostbyaddr_r_nargs+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11334 "configure" +#line 11429 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/socket.h> @@ -11346,7 +11441,7 @@ struct hostent hent; char buffer[BUFSIZE]; alen, AF_INET, &hent, buffer, bufsize, &h_errno); ; return 0; } EOF -if { (eval echo configure:11350: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11445: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_gethostbyaddr_r_nargs7=yes else @@ -11358,7 +11453,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 11362 "configure" +#line 11457 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/socket.h> @@ -11376,7 +11471,7 @@ struct hostent hent; &rhent, &h_errno); ; return 0; } EOF -if { (eval echo configure:11380: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:11475: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_func_gethostbyaddr_r_nargs8=yes else @@ -11439,12 +11534,12 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \ echo $ac_n "checking for _beginthread""... $ac_c" 1>&6 -echo "configure:11443: checking for _beginthread" >&5 +echo "configure:11538: checking for _beginthread" >&5 if eval "test \"\${ac_cv_func__beginthread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11448 "configure" +#line 11543 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _beginthread(); below. */ @@ -11468,7 +11563,7 @@ f = _beginthread; ; return 0; } EOF -if { (eval echo configure:11472: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11567: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__beginthread=yes" else @@ -11524,17 +11619,17 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:11528: checking for $ac_hdr" >&5 +echo "configure:11623: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11533 "configure" +#line 11628 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:11538: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:11633: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -11563,13 +11658,13 @@ done if test $ac_cv_header_pthread_h = yes ; then echo $ac_n "checking POSIX thread version""... $ac_c" 1>&6 -echo "configure:11567: checking POSIX thread version" >&5 +echo "configure:11662: checking POSIX thread version" >&5 if eval "test \"\${ol_cv_pthread_version+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11573 "configure" +#line 11668 "configure" #include "confdefs.h" # include <pthread.h> @@ -11591,7 +11686,7 @@ rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 11595 "configure" +#line 11690 "configure" #include "confdefs.h" # include <pthread.h> @@ -11644,12 +11739,12 @@ EOF echo $ac_n "checking for LinuxThreads pthread.h""... $ac_c" 1>&6 -echo "configure:11648: checking for LinuxThreads pthread.h" >&5 +echo "configure:11743: checking for LinuxThreads pthread.h" >&5 if eval "test \"\${ol_cv_header_linux_threads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11653 "configure" +#line 11748 "configure" #include "confdefs.h" #include <pthread.h> EOF @@ -11676,12 +11771,12 @@ EOF echo $ac_n "checking for GNU Pth pthread.h""... $ac_c" 1>&6 -echo "configure:11680: checking for GNU Pth pthread.h" >&5 +echo "configure:11775: checking for GNU Pth pthread.h" >&5 if eval "test \"\${ol_cv_header_gnu_pth_pthread_h+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11685 "configure" +#line 11780 "configure" #include "confdefs.h" #include <pthread.h> #ifdef _POSIX_THREAD_IS_GNU_PTH @@ -11710,17 +11805,17 @@ echo "$ac_t""$ol_cv_header_gnu_pth_pthread_h" 1>&6 do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:11714: checking for $ac_hdr" >&5 +echo "configure:11809: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 11719 "configure" +#line 11814 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:11724: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:11819: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -11750,14 +11845,14 @@ done echo $ac_n "checking for pthread_create in default libraries""... $ac_c" 1>&6 -echo "configure:11754: checking for pthread_create in default libraries" >&5 +echo "configure:11849: checking for pthread_create in default libraries" >&5 if eval "test \"\${ol_cv_pthread_create+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 11761 "configure" +#line 11856 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -11838,7 +11933,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:11842: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11937: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_create=yes else @@ -11850,7 +11945,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 11854 "configure" +#line 11949 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -11936,7 +12031,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:11940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:12035: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_create=yes else @@ -11961,7 +12056,7 @@ echo "$ac_t""$ol_cv_pthread_create" 1>&6 if test "$ol_link_threads" = no ; then # try -kthread echo $ac_n "checking for pthread link with -kthread""... $ac_c" 1>&6 -echo "configure:11965: checking for pthread link with -kthread" >&5 +echo "configure:12060: checking for pthread link with -kthread" >&5 if eval "test \"\${ol_cv_pthread_kthread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -11972,7 +12067,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 11976 "configure" +#line 12071 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12053,7 +12148,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:12057: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12152: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_kthread=yes else @@ -12065,7 +12160,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 12069 "configure" +#line 12164 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12151,7 +12246,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:12155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:12250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_kthread=yes else @@ -12181,7 +12276,7 @@ fi if test "$ol_link_threads" = no ; then # try -pthread echo $ac_n "checking for pthread link with -pthread""... $ac_c" 1>&6 -echo "configure:12185: checking for pthread link with -pthread" >&5 +echo "configure:12280: checking for pthread link with -pthread" >&5 if eval "test \"\${ol_cv_pthread_pthread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -12192,7 +12287,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 12196 "configure" +#line 12291 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12273,7 +12368,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:12277: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12372: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_pthread=yes else @@ -12285,7 +12380,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 12289 "configure" +#line 12384 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12371,7 +12466,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:12375: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:12470: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_pthread=yes else @@ -12401,7 +12496,7 @@ fi if test "$ol_link_threads" = no ; then # try -pthreads echo $ac_n "checking for pthread link with -pthreads""... $ac_c" 1>&6 -echo "configure:12405: checking for pthread link with -pthreads" >&5 +echo "configure:12500: checking for pthread link with -pthreads" >&5 if eval "test \"\${ol_cv_pthread_pthreads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -12412,7 +12507,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 12416 "configure" +#line 12511 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12493,7 +12588,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:12497: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_pthreads=yes else @@ -12505,7 +12600,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 12509 "configure" +#line 12604 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12591,7 +12686,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:12595: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:12690: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_pthreads=yes else @@ -12621,7 +12716,7 @@ fi if test "$ol_link_threads" = no ; then # try -mthreads echo $ac_n "checking for pthread link with -mthreads""... $ac_c" 1>&6 -echo "configure:12625: checking for pthread link with -mthreads" >&5 +echo "configure:12720: checking for pthread link with -mthreads" >&5 if eval "test \"\${ol_cv_pthread_mthreads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -12632,7 +12727,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 12636 "configure" +#line 12731 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12713,7 +12808,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:12717: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_mthreads=yes else @@ -12725,7 +12820,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 12729 "configure" +#line 12824 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12811,7 +12906,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:12815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:12910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_mthreads=yes else @@ -12841,7 +12936,7 @@ fi if test "$ol_link_threads" = no ; then # try -thread echo $ac_n "checking for pthread link with -thread""... $ac_c" 1>&6 -echo "configure:12845: checking for pthread link with -thread" >&5 +echo "configure:12940: checking for pthread link with -thread" >&5 if eval "test \"\${ol_cv_pthread_thread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -12852,7 +12947,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 12856 "configure" +#line 12951 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -12933,7 +13028,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:12937: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_thread=yes else @@ -12945,7 +13040,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 12949 "configure" +#line 13044 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13031,7 +13126,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:13035: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:13130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_thread=yes else @@ -13062,7 +13157,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthread -lmach -lexc -lc_r echo $ac_n "checking for pthread link with -lpthread -lmach -lexc -lc_r""... $ac_c" 1>&6 -echo "configure:13066: checking for pthread link with -lpthread -lmach -lexc -lc_r" >&5 +echo "configure:13161: checking for pthread link with -lpthread -lmach -lexc -lc_r" >&5 if eval "test \"\${ol_cv_pthread_lpthread_lmach_lexc_lc_r+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -13073,7 +13168,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 13077 "configure" +#line 13172 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13154,7 +13249,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13158: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13253: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthread_lmach_lexc_lc_r=yes else @@ -13166,7 +13261,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 13170 "configure" +#line 13265 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13252,7 +13347,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:13256: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:13351: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthread_lmach_lexc_lc_r=yes else @@ -13282,7 +13377,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthread -lmach -lexc echo $ac_n "checking for pthread link with -lpthread -lmach -lexc""... $ac_c" 1>&6 -echo "configure:13286: checking for pthread link with -lpthread -lmach -lexc" >&5 +echo "configure:13381: checking for pthread link with -lpthread -lmach -lexc" >&5 if eval "test \"\${ol_cv_pthread_lpthread_lmach_lexc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -13293,7 +13388,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 13297 "configure" +#line 13392 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13374,7 +13469,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13378: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13473: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthread_lmach_lexc=yes else @@ -13386,7 +13481,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 13390 "configure" +#line 13485 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13472,7 +13567,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:13476: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:13571: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthread_lmach_lexc=yes else @@ -13503,7 +13598,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthread -Wl,-woff,85 echo $ac_n "checking for pthread link with -lpthread -Wl,-woff,85""... $ac_c" 1>&6 -echo "configure:13507: checking for pthread link with -lpthread -Wl,-woff,85" >&5 +echo "configure:13602: checking for pthread link with -lpthread -Wl,-woff,85" >&5 if eval "test \"\${ol_cv_pthread_lib_lpthread_woff+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -13514,7 +13609,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 13518 "configure" +#line 13613 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13595,7 +13690,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13599: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13694: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lib_lpthread_woff=yes else @@ -13607,7 +13702,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 13611 "configure" +#line 13706 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13693,7 +13788,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:13697: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:13792: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lib_lpthread_woff=yes else @@ -13724,7 +13819,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthread echo $ac_n "checking for pthread link with -lpthread""... $ac_c" 1>&6 -echo "configure:13728: checking for pthread link with -lpthread" >&5 +echo "configure:13823: checking for pthread link with -lpthread" >&5 if eval "test \"\${ol_cv_pthread_lpthread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -13735,7 +13830,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 13739 "configure" +#line 13834 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13816,7 +13911,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13820: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthread=yes else @@ -13828,7 +13923,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 13832 "configure" +#line 13927 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -13914,7 +14009,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:13918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:14013: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthread=yes else @@ -13944,7 +14039,7 @@ fi if test "$ol_link_threads" = no ; then # try -lc_r echo $ac_n "checking for pthread link with -lc_r""... $ac_c" 1>&6 -echo "configure:13948: checking for pthread link with -lc_r" >&5 +echo "configure:14043: checking for pthread link with -lc_r" >&5 if eval "test \"\${ol_cv_pthread_lc_r+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -13955,7 +14050,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 13959 "configure" +#line 14054 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14036,7 +14131,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:14040: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:14135: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lc_r=yes else @@ -14048,7 +14143,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 14052 "configure" +#line 14147 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14134,7 +14229,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:14138: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:14233: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lc_r=yes else @@ -14165,7 +14260,7 @@ fi if test "$ol_link_threads" = no ; then # try -threads echo $ac_n "checking for pthread link with -threads""... $ac_c" 1>&6 -echo "configure:14169: checking for pthread link with -threads" >&5 +echo "configure:14264: checking for pthread link with -threads" >&5 if eval "test \"\${ol_cv_pthread_threads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -14176,7 +14271,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 14180 "configure" +#line 14275 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14257,7 +14352,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:14261: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:14356: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_threads=yes else @@ -14269,7 +14364,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 14273 "configure" +#line 14368 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14355,7 +14450,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:14359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:14454: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_threads=yes else @@ -14386,7 +14481,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthreads -lmach -lexc -lc_r echo $ac_n "checking for pthread link with -lpthreads -lmach -lexc -lc_r""... $ac_c" 1>&6 -echo "configure:14390: checking for pthread link with -lpthreads -lmach -lexc -lc_r" >&5 +echo "configure:14485: checking for pthread link with -lpthreads -lmach -lexc -lc_r" >&5 if eval "test \"\${ol_cv_pthread_lpthreads_lmach_lexc_lc_r+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -14397,7 +14492,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 14401 "configure" +#line 14496 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14478,7 +14573,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:14482: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:14577: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthreads_lmach_lexc_lc_r=yes else @@ -14490,7 +14585,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 14494 "configure" +#line 14589 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14576,7 +14671,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:14580: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:14675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthreads_lmach_lexc_lc_r=yes else @@ -14606,7 +14701,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthreads -lmach -lexc echo $ac_n "checking for pthread link with -lpthreads -lmach -lexc""... $ac_c" 1>&6 -echo "configure:14610: checking for pthread link with -lpthreads -lmach -lexc" >&5 +echo "configure:14705: checking for pthread link with -lpthreads -lmach -lexc" >&5 if eval "test \"\${ol_cv_pthread_lpthreads_lmach_lexc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -14617,7 +14712,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 14621 "configure" +#line 14716 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14698,7 +14793,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:14702: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:14797: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthreads_lmach_lexc=yes else @@ -14710,7 +14805,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 14714 "configure" +#line 14809 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14796,7 +14891,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:14800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:14895: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthreads_lmach_lexc=yes else @@ -14826,7 +14921,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthreads -lexc echo $ac_n "checking for pthread link with -lpthreads -lexc""... $ac_c" 1>&6 -echo "configure:14830: checking for pthread link with -lpthreads -lexc" >&5 +echo "configure:14925: checking for pthread link with -lpthreads -lexc" >&5 if eval "test \"\${ol_cv_pthread_lpthreads_lexc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -14837,7 +14932,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 14841 "configure" +#line 14936 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -14918,7 +15013,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:14922: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lpthreads_lexc=yes else @@ -14930,7 +15025,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 14934 "configure" +#line 15029 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -15016,7 +15111,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:15020: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:15115: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lpthreads_lexc=yes else @@ -15047,7 +15142,7 @@ fi if test "$ol_link_threads" = no ; then # try -lpthreads echo $ac_n "checking for pthread link with -lpthreads""... $ac_c" 1>&6 -echo "configure:15051: checking for pthread link with -lpthreads" >&5 +echo "configure:15146: checking for pthread link with -lpthreads" >&5 if eval "test \"\${ol_cv_pthread_lib_lpthreads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -15058,7 +15153,7 @@ else if test "$cross_compiling" = yes; then cat > conftest.$ac_ext <<EOF -#line 15062 "configure" +#line 15157 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -15139,7 +15234,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:15143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15238: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_pthread_lib_lpthreads=yes else @@ -15151,7 +15246,7 @@ fi rm -f conftest* else cat > conftest.$ac_ext <<EOF -#line 15155 "configure" +#line 15250 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -15237,7 +15332,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:15241: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:15336: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_lib_lpthreads=yes else @@ -15279,12 +15374,12 @@ EOF for ac_func in sched_yield pthread_yield do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:15283: checking for $ac_func" >&5 +echo "configure:15378: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15288 "configure" +#line 15383 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -15308,7 +15403,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:15312: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15407: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -15336,7 +15431,7 @@ done if test $ac_cv_func_sched_yield = no -a \ $ac_cv_func_pthread_yield = no ; then echo $ac_n "checking for sched_yield in -lrt""... $ac_c" 1>&6 -echo "configure:15340: checking for sched_yield in -lrt" >&5 +echo "configure:15435: checking for sched_yield in -lrt" >&5 ac_lib_var=`echo rt'_'sched_yield | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -15344,7 +15439,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lrt $LIBS" cat > conftest.$ac_ext <<EOF -#line 15348 "configure" +#line 15443 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -15355,7 +15450,7 @@ int main() { sched_yield() ; return 0; } EOF -if { (eval echo configure:15359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15454: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -15387,12 +15482,12 @@ fi for ac_func in thr_yield do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:15391: checking for $ac_func" >&5 +echo "configure:15486: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15396 "configure" +#line 15491 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -15416,7 +15511,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:15420: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -15450,12 +15545,12 @@ done for ac_func in pthread_kill pthread_rwlock_destroy do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:15454: checking for $ac_func" >&5 +echo "configure:15549: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15459 "configure" +#line 15554 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -15479,7 +15574,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:15483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15578: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -15505,13 +15600,13 @@ done echo $ac_n "checking for pthread_detach with <pthread.h>""... $ac_c" 1>&6 -echo "configure:15509: checking for pthread_detach with <pthread.h>" >&5 +echo "configure:15604: checking for pthread_detach with <pthread.h>" >&5 if eval "test \"\${ol_cv_func_pthread_detach+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15515 "configure" +#line 15610 "configure" #include "confdefs.h" #include <pthread.h> @@ -15523,7 +15618,7 @@ int main() { pthread_detach(NULL); ; return 0; } EOF -if { (eval echo configure:15527: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15622: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_func_pthread_detach=yes else @@ -15555,12 +15650,12 @@ EOF do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:15559: checking for $ac_func" >&5 +echo "configure:15654: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15564 "configure" +#line 15659 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -15584,7 +15679,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:15588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15683: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -15613,12 +15708,12 @@ done for ac_func in pthread_kill_other_threads_np do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:15617: checking for $ac_func" >&5 +echo "configure:15712: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15622 "configure" +#line 15717 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -15642,7 +15737,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:15646: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:15741: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -15667,7 +15762,7 @@ fi done echo $ac_n "checking for LinuxThreads implementation""... $ac_c" 1>&6 -echo "configure:15671: checking for LinuxThreads implementation" >&5 +echo "configure:15766: checking for LinuxThreads implementation" >&5 if eval "test \"\${ol_cv_sys_linux_threads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -15680,7 +15775,7 @@ echo "$ac_t""$ol_cv_sys_linux_threads" 1>&6 echo $ac_n "checking for LinuxThreads consistency""... $ac_c" 1>&6 -echo "configure:15684: checking for LinuxThreads consistency" >&5 +echo "configure:15779: checking for LinuxThreads consistency" >&5 if eval "test \"\${ol_cv_linux_threads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -15705,7 +15800,7 @@ echo "$ac_t""$ol_cv_linux_threads" 1>&6 fi echo $ac_n "checking if pthread_create() works""... $ac_c" 1>&6 -echo "configure:15709: checking if pthread_create() works" >&5 +echo "configure:15804: checking if pthread_create() works" >&5 if eval "test \"\${ol_cv_pthread_create_works+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -15714,7 +15809,7 @@ else ol_cv_pthread_create_works=yes else cat > conftest.$ac_ext <<EOF -#line 15718 "configure" +#line 15813 "configure" #include "confdefs.h" /* pthread test headers */ #include <pthread.h> @@ -15800,7 +15895,7 @@ int main(argc, argv) } EOF -if { (eval echo configure:15804: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:15899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_create_works=yes else @@ -15822,7 +15917,7 @@ echo "$ac_t""$ol_cv_pthread_create_works" 1>&6 if test $ol_with_yielding_select = auto ; then echo $ac_n "checking if select yields when using pthreads""... $ac_c" 1>&6 -echo "configure:15826: checking if select yields when using pthreads" >&5 +echo "configure:15921: checking if select yields when using pthreads" >&5 if eval "test \"\${ol_cv_pthread_select_yields+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -15831,7 +15926,7 @@ else ol_cv_pthread_select_yields=cross else cat > conftest.$ac_ext <<EOF -#line 15835 "configure" +#line 15930 "configure" #include "confdefs.h" #include <sys/types.h> @@ -15907,7 +16002,7 @@ int main(argc, argv) exit(2); } EOF -if { (eval echo configure:15911: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:16006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_pthread_select_yields=no else @@ -15951,17 +16046,17 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:15955: checking for $ac_hdr" >&5 +echo "configure:16050: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 15960 "configure" +#line 16055 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:15965: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16060: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -15991,12 +16086,12 @@ done ol_with_threads=found echo $ac_n "checking for cthread_fork""... $ac_c" 1>&6 -echo "configure:15995: checking for cthread_fork" >&5 +echo "configure:16090: checking for cthread_fork" >&5 if eval "test \"\${ac_cv_func_cthread_fork+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16000 "configure" +#line 16095 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char cthread_fork(); below. */ @@ -16020,7 +16115,7 @@ f = cthread_fork; ; return 0; } EOF -if { (eval echo configure:16024: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16119: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_cthread_fork=yes" else @@ -16042,7 +16137,7 @@ fi if test $ol_link_threads = no ; then echo $ac_n "checking for cthread_fork with -all_load""... $ac_c" 1>&6 -echo "configure:16046: checking for cthread_fork with -all_load" >&5 +echo "configure:16141: checking for cthread_fork with -all_load" >&5 if eval "test \"\${ol_cv_cthread_all_load+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -16050,7 +16145,7 @@ else save_LIBS="$LIBS" LIBS="-all_load $LIBS" cat > conftest.$ac_ext <<EOF -#line 16054 "configure" +#line 16149 "configure" #include "confdefs.h" #include <mach/cthreads.h> int main() { @@ -16059,7 +16154,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:16063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16158: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_cthread_all_load=yes else @@ -16089,12 +16184,12 @@ echo "$ac_t""$ol_cv_cthread_all_load" 1>&6 save_LIBS="$LIBS" LIBS="$LIBS -lthreads" echo $ac_n "checking for cthread_fork""... $ac_c" 1>&6 -echo "configure:16093: checking for cthread_fork" >&5 +echo "configure:16188: checking for cthread_fork" >&5 if eval "test \"\${ac_cv_func_cthread_fork+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16098 "configure" +#line 16193 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char cthread_fork(); below. */ @@ -16118,7 +16213,7 @@ f = cthread_fork; ; return 0; } EOF -if { (eval echo configure:16122: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16217: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_cthread_fork=yes" else @@ -16168,17 +16263,17 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16172: checking for $ac_hdr" >&5 +echo "configure:16267: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16177 "configure" +#line 16272 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16182: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16277: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16207,7 +16302,7 @@ done if test $ac_cv_header_pth_h = yes ; then echo $ac_n "checking for pth_version in -lpth""... $ac_c" 1>&6 -echo "configure:16211: checking for pth_version in -lpth" >&5 +echo "configure:16306: checking for pth_version in -lpth" >&5 ac_lib_var=`echo pth'_'pth_version | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -16215,7 +16310,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lpth $LIBS" cat > conftest.$ac_ext <<EOF -#line 16219 "configure" +#line 16314 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -16226,7 +16321,7 @@ int main() { pth_version() ; return 0; } EOF -if { (eval echo configure:16230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16325: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -16271,17 +16366,17 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16275: checking for $ac_hdr" >&5 +echo "configure:16370: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16280 "configure" +#line 16375 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16285: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16380: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16309,7 +16404,7 @@ done if test $ac_cv_header_thread_h = yes -a $ac_cv_header_synch_h = yes ; then echo $ac_n "checking for thr_create in -lthread""... $ac_c" 1>&6 -echo "configure:16313: checking for thr_create in -lthread" >&5 +echo "configure:16408: checking for thr_create in -lthread" >&5 ac_lib_var=`echo thread'_'thr_create | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -16317,7 +16412,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lthread $LIBS" cat > conftest.$ac_ext <<EOF -#line 16321 "configure" +#line 16416 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -16328,7 +16423,7 @@ int main() { thr_create() ; return 0; } EOF -if { (eval echo configure:16332: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16427: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -16368,12 +16463,12 @@ EOF do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:16372: checking for $ac_func" >&5 +echo "configure:16467: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16377 "configure" +#line 16472 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -16397,7 +16492,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:16401: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16496: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -16428,17 +16523,17 @@ done do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16432: checking for $ac_hdr" >&5 +echo "configure:16527: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16437 "configure" +#line 16532 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16442: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16537: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16466,7 +16561,7 @@ done if test $ac_cv_header_lwp_lwp_h = yes ; then echo $ac_n "checking for lwp_create in -llwp""... $ac_c" 1>&6 -echo "configure:16470: checking for lwp_create in -llwp" >&5 +echo "configure:16565: checking for lwp_create in -llwp" >&5 ac_lib_var=`echo lwp'_'lwp_create | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -16474,7 +16569,7 @@ else ac_save_LIBS="$LIBS" LIBS="-llwp $LIBS" cat > conftest.$ac_ext <<EOF -#line 16478 "configure" +#line 16573 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -16485,7 +16580,7 @@ int main() { lwp_create() ; return 0; } EOF -if { (eval echo configure:16489: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16584: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -16538,17 +16633,17 @@ if test $ol_with_threads = manual ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16542: checking for $ac_hdr" >&5 +echo "configure:16637: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16547 "configure" +#line 16642 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16552: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16647: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16577,12 +16672,12 @@ done for ac_func in sched_yield pthread_yield do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:16581: checking for $ac_func" >&5 +echo "configure:16676: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16586 "configure" +#line 16681 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -16606,7 +16701,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:16610: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16705: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -16632,12 +16727,12 @@ done echo $ac_n "checking for LinuxThreads pthread.h""... $ac_c" 1>&6 -echo "configure:16636: checking for LinuxThreads pthread.h" >&5 +echo "configure:16731: checking for LinuxThreads pthread.h" >&5 if eval "test \"\${ol_cv_header_linux_threads+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16641 "configure" +#line 16736 "configure" #include "confdefs.h" #include <pthread.h> EOF @@ -16667,17 +16762,17 @@ EOF do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16671: checking for $ac_hdr" >&5 +echo "configure:16766: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16676 "configure" +#line 16771 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16681: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16776: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16707,17 +16802,17 @@ done do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16711: checking for $ac_hdr" >&5 +echo "configure:16806: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16716 "configure" +#line 16811 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16721: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16816: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16747,17 +16842,17 @@ done do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16751: checking for $ac_hdr" >&5 +echo "configure:16846: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16756 "configure" +#line 16851 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16761: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:16856: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16816,20 +16911,20 @@ EOF echo $ac_n "checking for thread specific errno""... $ac_c" 1>&6 -echo "configure:16820: checking for thread specific errno" >&5 +echo "configure:16915: checking for thread specific errno" >&5 if eval "test \"\${ol_cv_errno_thread_specific+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16826 "configure" +#line 16921 "configure" #include "confdefs.h" #include <errno.h> int main() { errno = 0; ; return 0; } EOF -if { (eval echo configure:16833: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16928: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_errno_thread_specific=yes else @@ -16845,20 +16940,20 @@ fi echo "$ac_t""$ol_cv_errno_thread_specific" 1>&6 echo $ac_n "checking for thread specific h_errno""... $ac_c" 1>&6 -echo "configure:16849: checking for thread specific h_errno" >&5 +echo "configure:16944: checking for thread specific h_errno" >&5 if eval "test \"\${ol_cv_h_errno_thread_specific+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16855 "configure" +#line 16950 "configure" #include "confdefs.h" #include <netdb.h> int main() { h_errno = 0; ; return 0; } EOF -if { (eval echo configure:16862: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:16957: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_h_errno_thread_specific=yes else @@ -16916,17 +17011,17 @@ if test $ol_with_ldbm_api = auto \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:16920: checking for $ac_hdr" >&5 +echo "configure:17015: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16925 "configure" +#line 17020 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:16930: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:17025: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -16954,13 +17049,13 @@ done if test $ac_cv_header_db_185_h = yes -o $ac_cv_header_db_h = yes; then echo $ac_n "checking if Berkeley DB header compatibility""... $ac_c" 1>&6 -echo "configure:16958: checking if Berkeley DB header compatibility" >&5 +echo "configure:17053: checking if Berkeley DB header compatibility" >&5 if eval "test \"\${ol_cv_header_db1+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 16964 "configure" +#line 17059 "configure" #include "confdefs.h" #if HAVE_DB_185_H @@ -16997,7 +17092,7 @@ echo "$ac_t""$ol_cv_header_db1" 1>&6 ol_cv_lib_db=no if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (default)""... $ac_c" 1>&6 -echo "configure:17001: checking for Berkeley DB link (default)" >&5 +echo "configure:17096: checking for Berkeley DB link (default)" >&5 if eval "test \"\${ol_cv_db_none+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17007,7 +17102,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17011 "configure" +#line 17106 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17054,7 +17149,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17058: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17153: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_none=yes else @@ -17078,7 +17173,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb4)""... $ac_c" 1>&6 -echo "configure:17082: checking for Berkeley DB link (-ldb4)" >&5 +echo "configure:17177: checking for Berkeley DB link (-ldb4)" >&5 if eval "test \"\${ol_cv_db_db4+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17088,7 +17183,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17092 "configure" +#line 17187 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17135,7 +17230,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17139: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db4=yes else @@ -17159,7 +17254,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb)""... $ac_c" 1>&6 -echo "configure:17163: checking for Berkeley DB link (-ldb)" >&5 +echo "configure:17258: checking for Berkeley DB link (-ldb)" >&5 if eval "test \"\${ol_cv_db_db+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17169,7 +17264,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17173 "configure" +#line 17268 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17216,7 +17311,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17220: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db=yes else @@ -17240,7 +17335,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb3)""... $ac_c" 1>&6 -echo "configure:17244: checking for Berkeley DB link (-ldb3)" >&5 +echo "configure:17339: checking for Berkeley DB link (-ldb3)" >&5 if eval "test \"\${ol_cv_db_db3+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17250,7 +17345,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17254 "configure" +#line 17349 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17297,7 +17392,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17396: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db3=yes else @@ -17321,7 +17416,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb2)""... $ac_c" 1>&6 -echo "configure:17325: checking for Berkeley DB link (-ldb2)" >&5 +echo "configure:17420: checking for Berkeley DB link (-ldb2)" >&5 if eval "test \"\${ol_cv_db_db2+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17331,7 +17426,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17335 "configure" +#line 17430 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17378,7 +17473,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17382: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17477: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db2=yes else @@ -17402,7 +17497,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb1)""... $ac_c" 1>&6 -echo "configure:17406: checking for Berkeley DB link (-ldb1)" >&5 +echo "configure:17501: checking for Berkeley DB link (-ldb1)" >&5 if eval "test \"\${ol_cv_db_db1+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17412,7 +17507,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17416 "configure" +#line 17511 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17459,7 +17554,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17463: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db1=yes else @@ -17494,17 +17589,17 @@ for ac_hdr in db.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:17498: checking for $ac_hdr" >&5 +echo "configure:17593: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 17503 "configure" +#line 17598 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:17508: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:17603: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -17534,7 +17629,7 @@ if test $ac_cv_header_db_h = yes; then ol_cv_lib_db=no if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (default)""... $ac_c" 1>&6 -echo "configure:17538: checking for Berkeley DB link (default)" >&5 +echo "configure:17633: checking for Berkeley DB link (default)" >&5 if eval "test \"\${ol_cv_db_none+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17544,7 +17639,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17548 "configure" +#line 17643 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17591,7 +17686,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17595: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17690: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_none=yes else @@ -17615,7 +17710,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb4)""... $ac_c" 1>&6 -echo "configure:17619: checking for Berkeley DB link (-ldb4)" >&5 +echo "configure:17714: checking for Berkeley DB link (-ldb4)" >&5 if eval "test \"\${ol_cv_db_db4+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17625,7 +17720,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17629 "configure" +#line 17724 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17672,7 +17767,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17676: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17771: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db4=yes else @@ -17696,7 +17791,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb)""... $ac_c" 1>&6 -echo "configure:17700: checking for Berkeley DB link (-ldb)" >&5 +echo "configure:17795: checking for Berkeley DB link (-ldb)" >&5 if eval "test \"\${ol_cv_db_db+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17706,7 +17801,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17710 "configure" +#line 17805 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17753,7 +17848,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17757: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db=yes else @@ -17777,7 +17872,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb3)""... $ac_c" 1>&6 -echo "configure:17781: checking for Berkeley DB link (-ldb3)" >&5 +echo "configure:17876: checking for Berkeley DB link (-ldb3)" >&5 if eval "test \"\${ol_cv_db_db3+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17787,7 +17882,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17791 "configure" +#line 17886 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17834,7 +17929,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:17933: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db3=yes else @@ -17858,7 +17953,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb2)""... $ac_c" 1>&6 -echo "configure:17862: checking for Berkeley DB link (-ldb2)" >&5 +echo "configure:17957: checking for Berkeley DB link (-ldb2)" >&5 if eval "test \"\${ol_cv_db_db2+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17868,7 +17963,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17872 "configure" +#line 17967 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17915,7 +18010,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:17919: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18014: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db2=yes else @@ -17939,7 +18034,7 @@ fi if test $ol_cv_lib_db = no ; then echo $ac_n "checking for Berkeley DB link (-ldb1)""... $ac_c" 1>&6 -echo "configure:17943: checking for Berkeley DB link (-ldb1)" >&5 +echo "configure:18038: checking for Berkeley DB link (-ldb1)" >&5 if eval "test \"\${ol_cv_db_db1+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -17949,7 +18044,7 @@ else LIBS="$ol_DB_LIB $LIBS" cat > conftest.$ac_ext <<EOF -#line 17953 "configure" +#line 18048 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -17996,7 +18091,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:18000: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18095: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_db_db1=yes else @@ -18022,7 +18117,7 @@ fi if test "$ol_cv_lib_db" != no ; then ol_cv_berkeley_db=yes echo $ac_n "checking for Berkeley DB thread support""... $ac_c" 1>&6 -echo "configure:18026: checking for Berkeley DB thread support" >&5 +echo "configure:18121: checking for Berkeley DB thread support" >&5 if eval "test \"\${ol_cv_berkeley_db_thread+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -18036,7 +18131,7 @@ else ol_cv_berkeley_db_thread=cross else cat > conftest.$ac_ext <<EOF -#line 18040 "configure" +#line 18135 "configure" #include "confdefs.h" #ifdef HAVE_DB_185_H @@ -18103,7 +18198,7 @@ main() return rc; } EOF -if { (eval echo configure:18107: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:18202: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_berkeley_db_thread=yes else @@ -18164,13 +18259,13 @@ if test $ol_enable_bdb = yes -a $ol_link_ldbm != berkeley ; then { echo "configure: error: BDB: BerkeleyDB not available" 1>&2; exit 1; } elif test $ol_enable_bdb != no -a $ol_link_ldbm = berkeley ; then echo $ac_n "checking Berkeley DB version for BDB backend""... $ac_c" 1>&6 -echo "configure:18168: checking Berkeley DB version for BDB backend" >&5 +echo "configure:18263: checking Berkeley DB version for BDB backend" >&5 if eval "test \"\${ol_cv_bdb_compat+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18174 "configure" +#line 18269 "configure" #include "confdefs.h" #include <db.h> @@ -18217,18 +18312,18 @@ fi if test $ol_with_ldbm_api = auto -o $ol_with_ldbm_api = mdbm ; then echo $ac_n "checking for MDBM library""... $ac_c" 1>&6 -echo "configure:18221: checking for MDBM library" >&5 +echo "configure:18316: checking for MDBM library" >&5 if eval "test \"\${ol_cv_lib_mdbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ol_LIBS="$LIBS" echo $ac_n "checking for mdbm_set_chain""... $ac_c" 1>&6 -echo "configure:18227: checking for mdbm_set_chain" >&5 +echo "configure:18322: checking for mdbm_set_chain" >&5 if eval "test \"\${ac_cv_func_mdbm_set_chain+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18232 "configure" +#line 18327 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char mdbm_set_chain(); below. */ @@ -18252,7 +18347,7 @@ f = mdbm_set_chain; ; return 0; } EOF -if { (eval echo configure:18256: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18351: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_mdbm_set_chain=yes" else @@ -18271,7 +18366,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mdbm_set_chain in -lmdbm""... $ac_c" 1>&6 -echo "configure:18275: checking for mdbm_set_chain in -lmdbm" >&5 +echo "configure:18370: checking for mdbm_set_chain in -lmdbm" >&5 ac_lib_var=`echo mdbm'_'mdbm_set_chain | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -18279,7 +18374,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lmdbm $LIBS" cat > conftest.$ac_ext <<EOF -#line 18283 "configure" +#line 18378 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -18290,7 +18385,7 @@ int main() { mdbm_set_chain() ; return 0; } EOF -if { (eval echo configure:18294: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18389: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -18325,17 +18420,17 @@ echo "$ac_t""$ol_cv_lib_mdbm" 1>&6 do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:18329: checking for $ac_hdr" >&5 +echo "configure:18424: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18334 "configure" +#line 18429 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:18339: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:18434: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -18362,7 +18457,7 @@ fi done echo $ac_n "checking for db""... $ac_c" 1>&6 -echo "configure:18366: checking for db" >&5 +echo "configure:18461: checking for db" >&5 if eval "test \"\${ol_cv_mdbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -18395,18 +18490,18 @@ fi if test $ol_with_ldbm_api = auto -o $ol_with_ldbm_api = gdbm ; then echo $ac_n "checking for GDBM library""... $ac_c" 1>&6 -echo "configure:18399: checking for GDBM library" >&5 +echo "configure:18494: checking for GDBM library" >&5 if eval "test \"\${ol_cv_lib_gdbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ol_LIBS="$LIBS" echo $ac_n "checking for gdbm_open""... $ac_c" 1>&6 -echo "configure:18405: checking for gdbm_open" >&5 +echo "configure:18500: checking for gdbm_open" >&5 if eval "test \"\${ac_cv_func_gdbm_open+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18410 "configure" +#line 18505 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char gdbm_open(); below. */ @@ -18430,7 +18525,7 @@ f = gdbm_open; ; return 0; } EOF -if { (eval echo configure:18434: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18529: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gdbm_open=yes" else @@ -18449,7 +18544,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gdbm_open in -lgdbm""... $ac_c" 1>&6 -echo "configure:18453: checking for gdbm_open in -lgdbm" >&5 +echo "configure:18548: checking for gdbm_open in -lgdbm" >&5 ac_lib_var=`echo gdbm'_'gdbm_open | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -18457,7 +18552,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lgdbm $LIBS" cat > conftest.$ac_ext <<EOF -#line 18461 "configure" +#line 18556 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -18468,7 +18563,7 @@ int main() { gdbm_open() ; return 0; } EOF -if { (eval echo configure:18472: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18567: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -18503,17 +18598,17 @@ echo "$ac_t""$ol_cv_lib_gdbm" 1>&6 do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:18507: checking for $ac_hdr" >&5 +echo "configure:18602: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18512 "configure" +#line 18607 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:18517: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:18612: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -18540,7 +18635,7 @@ fi done echo $ac_n "checking for db""... $ac_c" 1>&6 -echo "configure:18544: checking for db" >&5 +echo "configure:18639: checking for db" >&5 if eval "test \"\${ol_cv_gdbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -18574,18 +18669,18 @@ fi if test $ol_with_ldbm_api = ndbm ; then echo $ac_n "checking for NDBM library""... $ac_c" 1>&6 -echo "configure:18578: checking for NDBM library" >&5 +echo "configure:18673: checking for NDBM library" >&5 if eval "test \"\${ol_cv_lib_ndbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ol_LIBS="$LIBS" echo $ac_n "checking for dbm_open""... $ac_c" 1>&6 -echo "configure:18584: checking for dbm_open" >&5 +echo "configure:18679: checking for dbm_open" >&5 if eval "test \"\${ac_cv_func_dbm_open+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18589 "configure" +#line 18684 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dbm_open(); below. */ @@ -18609,7 +18704,7 @@ f = dbm_open; ; return 0; } EOF -if { (eval echo configure:18613: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18708: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dbm_open=yes" else @@ -18628,7 +18723,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dbm_open in -lndbm""... $ac_c" 1>&6 -echo "configure:18632: checking for dbm_open in -lndbm" >&5 +echo "configure:18727: checking for dbm_open in -lndbm" >&5 ac_lib_var=`echo ndbm'_'dbm_open | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -18636,7 +18731,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lndbm $LIBS" cat > conftest.$ac_ext <<EOF -#line 18640 "configure" +#line 18735 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -18647,7 +18742,7 @@ int main() { dbm_open() ; return 0; } EOF -if { (eval echo configure:18651: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18746: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -18667,7 +18762,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dbm_open in -ldbm""... $ac_c" 1>&6 -echo "configure:18671: checking for dbm_open in -ldbm" >&5 +echo "configure:18766: checking for dbm_open in -ldbm" >&5 ac_lib_var=`echo dbm'_'dbm_open | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -18675,7 +18770,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldbm $LIBS" cat > conftest.$ac_ext <<EOF -#line 18679 "configure" +#line 18774 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -18686,7 +18781,7 @@ int main() { dbm_open() ; return 0; } EOF -if { (eval echo configure:18690: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -18723,17 +18818,17 @@ echo "$ac_t""$ol_cv_lib_ndbm" 1>&6 do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:18727: checking for $ac_hdr" >&5 +echo "configure:18822: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18732 "configure" +#line 18827 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:18737: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:18832: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -18760,7 +18855,7 @@ fi done echo $ac_n "checking for db""... $ac_c" 1>&6 -echo "configure:18764: checking for db" >&5 +echo "configure:18859: checking for db" >&5 if eval "test \"\${ol_cv_ndbm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -18817,17 +18912,17 @@ if test $ol_enable_wrappers != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:18821: checking for $ac_hdr" >&5 +echo "configure:18916: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18826 "configure" +#line 18921 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:18831: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:18926: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -18849,11 +18944,11 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then EOF echo $ac_n "checking for TCP wrappers library""... $ac_c" 1>&6 -echo "configure:18853: checking for TCP wrappers library" >&5 +echo "configure:18948: checking for TCP wrappers library" >&5 save_LIBS="$LIBS" LIBS="$LIBS -lwrap" cat > conftest.$ac_ext <<EOF -#line 18857 "configure" +#line 18952 "configure" #include "confdefs.h" #include <tcpd.h> @@ -18868,7 +18963,7 @@ hosts_access(req) ; return 0; } EOF -if { (eval echo configure:18872: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18967: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "$ac_t""-lwrap" 1>&6 have_wrappers=yes @@ -18880,7 +18975,7 @@ else LIBS="$LIBS -lnsl" cat > conftest.$ac_ext <<EOF -#line 18884 "configure" +#line 18979 "configure" #include "confdefs.h" #include <tcpd.h> @@ -18895,7 +18990,7 @@ hosts_access(req) ; return 0; } EOF -if { (eval echo configure:18899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:18994: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "$ac_t""-lwrap -lnsl" 1>&6 have_wrappers=yes @@ -18935,12 +19030,12 @@ fi if test $ol_enable_syslog != no ; then echo $ac_n "checking for openlog""... $ac_c" 1>&6 -echo "configure:18939: checking for openlog" >&5 +echo "configure:19034: checking for openlog" >&5 if eval "test \"\${ac_cv_func_openlog+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 18944 "configure" +#line 19039 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char openlog(); below. */ @@ -18964,7 +19059,7 @@ f = openlog; ; return 0; } EOF -if { (eval echo configure:18968: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_openlog=yes" else @@ -18993,7 +19088,7 @@ fi ol_link_sql=no if test $ol_enable_sql != no ; then echo $ac_n "checking for SQLDriverConnect in -liodbc""... $ac_c" 1>&6 -echo "configure:18997: checking for SQLDriverConnect in -liodbc" >&5 +echo "configure:19092: checking for SQLDriverConnect in -liodbc" >&5 ac_lib_var=`echo iodbc'_'SQLDriverConnect | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19001,7 +19096,7 @@ else ac_save_LIBS="$LIBS" LIBS="-liodbc $LIBS" cat > conftest.$ac_ext <<EOF -#line 19005 "configure" +#line 19100 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19012,7 +19107,7 @@ int main() { SQLDriverConnect() ; return 0; } EOF -if { (eval echo configure:19016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19111: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19037,7 +19132,7 @@ fi ol_link_sql="-liodbc" else echo $ac_n "checking for SQLDriverConnect in -lodbc""... $ac_c" 1>&6 -echo "configure:19041: checking for SQLDriverConnect in -lodbc" >&5 +echo "configure:19136: checking for SQLDriverConnect in -lodbc" >&5 ac_lib_var=`echo odbc'_'SQLDriverConnect | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19045,7 +19140,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lodbc $LIBS" cat > conftest.$ac_ext <<EOF -#line 19049 "configure" +#line 19144 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19056,7 +19151,7 @@ int main() { SQLDriverConnect() ; return 0; } EOF -if { (eval echo configure:19060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19095,17 +19190,17 @@ for ac_hdr in termcap.h ncurses.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:19099: checking for $ac_hdr" >&5 +echo "configure:19194: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19104 "configure" +#line 19199 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:19109: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:19204: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -19134,7 +19229,7 @@ done if test $ol_link_termcap = no ; then echo $ac_n "checking for tputs in -ltermcap""... $ac_c" 1>&6 -echo "configure:19138: checking for tputs in -ltermcap" >&5 +echo "configure:19233: checking for tputs in -ltermcap" >&5 ac_lib_var=`echo termcap'_'tputs | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19142,7 +19237,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ltermcap $LIBS" cat > conftest.$ac_ext <<EOF -#line 19146 "configure" +#line 19241 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19153,7 +19248,7 @@ int main() { tputs() ; return 0; } EOF -if { (eval echo configure:19157: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19252: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19186,7 +19281,7 @@ fi if test $ol_link_termcap = no ; then echo $ac_n "checking for initscr in -lncurses""... $ac_c" 1>&6 -echo "configure:19190: checking for initscr in -lncurses" >&5 +echo "configure:19285: checking for initscr in -lncurses" >&5 ac_lib_var=`echo ncurses'_'initscr | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19194,7 +19289,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext <<EOF -#line 19198 "configure" +#line 19293 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19205,7 +19300,7 @@ int main() { initscr() ; return 0; } EOF -if { (eval echo configure:19209: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19304: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19251,17 +19346,17 @@ if test $ol_with_cyrus_sasl != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:19255: checking for $ac_hdr" >&5 +echo "configure:19350: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19260 "configure" +#line 19355 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:19265: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:19360: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -19290,7 +19385,7 @@ done if test $ac_cv_header_sasl_sasl_h = yes -o $ac_cv_header_sasl_h = yes; then echo $ac_n "checking for sasl_client_init in -lsasl2""... $ac_c" 1>&6 -echo "configure:19294: checking for sasl_client_init in -lsasl2" >&5 +echo "configure:19389: checking for sasl_client_init in -lsasl2" >&5 ac_lib_var=`echo sasl2'_'sasl_client_init | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19298,7 +19393,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsasl2 $LIBS" cat > conftest.$ac_ext <<EOF -#line 19302 "configure" +#line 19397 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19309,7 +19404,7 @@ int main() { sasl_client_init() ; return 0; } EOF -if { (eval echo configure:19313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19408: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19328,7 +19423,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sasl_client_init in -lsasl""... $ac_c" 1>&6 -echo "configure:19332: checking for sasl_client_init in -lsasl" >&5 +echo "configure:19427: checking for sasl_client_init in -lsasl" >&5 ac_lib_var=`echo sasl'_'sasl_client_init | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19336,7 +19431,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsasl $LIBS" cat > conftest.$ac_ext <<EOF -#line 19340 "configure" +#line 19435 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19347,7 +19442,7 @@ int main() { sasl_client_init() ; return 0; } EOF -if { (eval echo configure:19351: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19426,13 +19521,13 @@ if test $ol_with_fetch != no ; then ol_LIBS=$LIBS LIBS="-lfetch -lcom_err $LIBS" echo $ac_n "checking fetch(3) library""... $ac_c" 1>&6 -echo "configure:19430: checking fetch(3) library" >&5 +echo "configure:19525: checking fetch(3) library" >&5 if eval "test \"\${ol_cv_lib_fetch+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19436 "configure" +#line 19531 "configure" #include "confdefs.h" #include <sys/param.h> @@ -19442,7 +19537,7 @@ int main() { struct url *u = fetchParseURL("file:///"); ; return 0; } EOF -if { (eval echo configure:19446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19541: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_lib_fetch=yes else @@ -19480,17 +19575,17 @@ if test $ol_with_readline != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:19484: checking for $ac_hdr" >&5 +echo "configure:19579: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19489 "configure" +#line 19584 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:19494: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:19589: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -19521,7 +19616,7 @@ done save_LIBS="$LIBS" LIBS="$TERMCAP_LIBS $LIBS" echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 -echo "configure:19525: checking for readline in -lreadline" >&5 +echo "configure:19620: checking for readline in -lreadline" >&5 ac_lib_var=`echo readline'_'readline | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19529,7 +19624,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lreadline $LIBS" cat > conftest.$ac_ext <<EOF -#line 19533 "configure" +#line 19628 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19540,7 +19635,7 @@ int main() { readline() ; return 0; } EOF -if { (eval echo configure:19544: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19639: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19582,12 +19677,12 @@ fi if test $ol_enable_crypt != no ; then echo $ac_n "checking for crypt""... $ac_c" 1>&6 -echo "configure:19586: checking for crypt" >&5 +echo "configure:19681: checking for crypt" >&5 if eval "test \"\${ac_cv_func_crypt+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19591 "configure" +#line 19686 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char crypt(); below. */ @@ -19611,7 +19706,7 @@ f = crypt; ; return 0; } EOF -if { (eval echo configure:19615: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19710: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_crypt=yes" else @@ -19630,7 +19725,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 -echo "configure:19634: checking for crypt in -lcrypt" >&5 +echo "configure:19729: checking for crypt in -lcrypt" >&5 ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19638,7 +19733,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcrypt $LIBS" cat > conftest.$ac_ext <<EOF -#line 19642 "configure" +#line 19737 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19649,7 +19744,7 @@ int main() { crypt() ; return 0; } EOF -if { (eval echo configure:19653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19748: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19692,12 +19787,12 @@ fi if test $ol_enable_proctitle != no ; then echo $ac_n "checking for setproctitle""... $ac_c" 1>&6 -echo "configure:19696: checking for setproctitle" >&5 +echo "configure:19791: checking for setproctitle" >&5 if eval "test \"\${ac_cv_func_setproctitle+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19701 "configure" +#line 19796 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char setproctitle(); below. */ @@ -19721,7 +19816,7 @@ f = setproctitle; ; return 0; } EOF -if { (eval echo configure:19725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19820: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setproctitle=yes" else @@ -19740,7 +19835,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setproctitle in -lutil""... $ac_c" 1>&6 -echo "configure:19744: checking for setproctitle in -lutil" >&5 +echo "configure:19839: checking for setproctitle in -lutil" >&5 ac_lib_var=`echo util'_'setproctitle | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19748,7 +19843,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lutil $LIBS" cat > conftest.$ac_ext <<EOF -#line 19752 "configure" +#line 19847 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19759,7 +19854,7 @@ int main() { setproctitle() ; return 0; } EOF -if { (eval echo configure:19763: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19858: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19799,17 +19894,17 @@ if test $ol_enable_slp != no ; then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:19803: checking for $ac_hdr" >&5 +echo "configure:19898: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19808 "configure" +#line 19903 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:19813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:19908: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -19838,7 +19933,7 @@ done if test $ac_cv_header_slp_h = yes ; then echo $ac_n "checking for SLPOpen in -lslp""... $ac_c" 1>&6 -echo "configure:19842: checking for SLPOpen in -lslp" >&5 +echo "configure:19937: checking for SLPOpen in -lslp" >&5 ac_lib_var=`echo slp'_'SLPOpen | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -19846,7 +19941,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lslp $LIBS" cat > conftest.$ac_ext <<EOF -#line 19850 "configure" +#line 19945 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -19857,7 +19952,7 @@ int main() { SLPOpen() ; return 0; } EOF -if { (eval echo configure:19861: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:19956: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -19892,12 +19987,12 @@ EOF fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:19896: checking for ANSI C header files" >&5 +echo "configure:19991: checking for ANSI C header files" >&5 if eval "test \"\${ac_cv_header_stdc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 19901 "configure" +#line 19996 "configure" #include "confdefs.h" #include <stdlib.h> #include <stdarg.h> @@ -19905,7 +20000,7 @@ else #include <float.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:19909: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:20004: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -19922,7 +20017,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 19926 "configure" +#line 20021 "configure" #include "confdefs.h" #include <string.h> EOF @@ -19940,7 +20035,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 19944 "configure" +#line 20039 "configure" #include "confdefs.h" #include <stdlib.h> EOF @@ -19961,7 +20056,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext <<EOF -#line 19965 "configure" +#line 20060 "configure" #include "confdefs.h" #include <ctype.h> #if ((' ' & 0x0FF) == 0x020) @@ -19979,7 +20074,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:19983: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:20078: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -20003,12 +20098,12 @@ EOF fi echo $ac_n "checking for mode_t""... $ac_c" 1>&6 -echo "configure:20007: checking for mode_t" >&5 +echo "configure:20102: checking for mode_t" >&5 if eval "test \"\${ac_cv_type_mode_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20012 "configure" +#line 20107 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20039,12 +20134,12 @@ EOF fi echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:20043: checking for off_t" >&5 +echo "configure:20138: checking for off_t" >&5 if eval "test \"\${ac_cv_type_off_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20048 "configure" +#line 20143 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20075,12 +20170,12 @@ EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 -echo "configure:20079: checking for pid_t" >&5 +echo "configure:20174: checking for pid_t" >&5 if eval "test \"\${ac_cv_type_pid_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20084 "configure" +#line 20179 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20111,19 +20206,19 @@ EOF fi echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6 -echo "configure:20115: checking for ptrdiff_t" >&5 +echo "configure:20210: checking for ptrdiff_t" >&5 if eval "test \"\${am_cv_type_ptrdiff_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20120 "configure" +#line 20215 "configure" #include "confdefs.h" #include <stddef.h> int main() { ptrdiff_t p ; return 0; } EOF -if { (eval echo configure:20127: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20222: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* am_cv_type_ptrdiff_t=yes else @@ -20144,12 +20239,12 @@ EOF fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 -echo "configure:20148: checking return type of signal handlers" >&5 +echo "configure:20243: checking return type of signal handlers" >&5 if eval "test \"\${ac_cv_type_signal+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20153 "configure" +#line 20248 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -20166,7 +20261,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:20170: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20265: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -20185,12 +20280,12 @@ EOF echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:20189: checking for size_t" >&5 +echo "configure:20284: checking for size_t" >&5 if eval "test \"\${ac_cv_type_size_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20194 "configure" +#line 20289 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20222,12 +20317,12 @@ fi echo $ac_n "checking for ssize_t""... $ac_c" 1>&6 -echo "configure:20226: checking for ssize_t" >&5 +echo "configure:20321: checking for ssize_t" >&5 if eval "test \"\${ac_cv_type_ssize_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20231 "configure" +#line 20326 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20258,12 +20353,12 @@ EOF fi echo $ac_n "checking for caddr_t""... $ac_c" 1>&6 -echo "configure:20262: checking for caddr_t" >&5 +echo "configure:20357: checking for caddr_t" >&5 if eval "test \"\${ac_cv_type_caddr_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20267 "configure" +#line 20362 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -20295,12 +20390,12 @@ fi echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 -echo "configure:20299: checking for socklen_t" >&5 +echo "configure:20394: checking for socklen_t" >&5 if eval "test \"\${ol_cv_type_socklen_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20304 "configure" +#line 20399 "configure" #include "confdefs.h" #ifdef HAVE_SYS_TYPES_H @@ -20314,7 +20409,7 @@ int main() { socklen_t len; ; return 0; } EOF -if { (eval echo configure:20318: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20413: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_type_socklen_t=yes else @@ -20335,12 +20430,12 @@ EOF fi echo $ac_n "checking for member st_blksize in aggregate type struct stat""... $ac_c" 1>&6 -echo "configure:20339: checking for member st_blksize in aggregate type struct stat" >&5 +echo "configure:20434: checking for member st_blksize in aggregate type struct stat" >&5 if eval "test \"\${ac_cv_c_struct_member_st_blksize+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20344 "configure" +#line 20439 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/stat.h> @@ -20348,7 +20443,7 @@ int main() { struct stat foo; foo.st_blksize; ; return 0; } EOF -if { (eval echo configure:20352: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20447: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_struct_member_st_blksize=yes else @@ -20370,12 +20465,12 @@ EOF fi echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 -echo "configure:20374: checking whether time.h and sys/time.h may both be included" >&5 +echo "configure:20469: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"\${ac_cv_header_time+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20379 "configure" +#line 20474 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/time.h> @@ -20384,7 +20479,7 @@ int main() { struct tm *tp; ; return 0; } EOF -if { (eval echo configure:20388: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20483: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else @@ -20405,12 +20500,12 @@ EOF fi echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 -echo "configure:20409: checking whether struct tm is in sys/time.h or time.h" >&5 +echo "configure:20504: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"\${ac_cv_struct_tm+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20414 "configure" +#line 20509 "configure" #include "confdefs.h" #include <sys/types.h> #include <time.h> @@ -20418,7 +20513,7 @@ int main() { struct tm *tp; tp->tm_sec; ; return 0; } EOF -if { (eval echo configure:20422: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20517: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else @@ -20439,12 +20534,12 @@ EOF fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:20443: checking for uid_t in sys/types.h" >&5 +echo "configure:20538: checking for uid_t in sys/types.h" >&5 if eval "test \"\${ac_cv_type_uid_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20448 "configure" +#line 20543 "configure" #include "confdefs.h" #include <sys/types.h> EOF @@ -20473,19 +20568,19 @@ EOF fi echo $ac_n "checking for sig_atomic_t""... $ac_c" 1>&6 -echo "configure:20477: checking for sig_atomic_t" >&5 +echo "configure:20572: checking for sig_atomic_t" >&5 if eval "test \"\${ol_cv_type_sig_atomic_t+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20482 "configure" +#line 20577 "configure" #include "confdefs.h" #include <signal.h> int main() { sig_atomic_t atomic; ; return 0; } EOF -if { (eval echo configure:20489: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20584: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_type_sig_atomic_t=yes else @@ -20509,13 +20604,13 @@ EOF # test for pw_gecos in struct passwd echo $ac_n "checking struct passwd for pw_gecos""... $ac_c" 1>&6 -echo "configure:20513: checking struct passwd for pw_gecos" >&5 +echo "configure:20608: checking struct passwd for pw_gecos" >&5 if eval "test \"\${ol_cv_struct_passwd_pw_gecos+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20519 "configure" +#line 20614 "configure" #include "confdefs.h" #include <pwd.h> int main() { @@ -20525,7 +20620,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:20529: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20624: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_struct_passwd_pw_gecos=yes else @@ -20547,13 +20642,13 @@ fi # test for pw_passwd in struct passwd echo $ac_n "checking struct passwd for pw_passwd""... $ac_c" 1>&6 -echo "configure:20551: checking struct passwd for pw_passwd" >&5 +echo "configure:20646: checking struct passwd for pw_passwd" >&5 if eval "test \"\${ol_cv_struct_passwd_pw_passwd+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20557 "configure" +#line 20652 "configure" #include "confdefs.h" #include <pwd.h> int main() { @@ -20563,7 +20658,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:20567: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20662: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_struct_passwd_pw_passwd=yes else @@ -20585,7 +20680,7 @@ fi echo $ac_n "checking if toupper() requires islower()""... $ac_c" 1>&6 -echo "configure:20589: checking if toupper() requires islower()" >&5 +echo "configure:20684: checking if toupper() requires islower()" >&5 if eval "test \"\${ol_cv_c_upper_lower+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -20594,7 +20689,7 @@ else ol_cv_c_upper_lower=safe else cat > conftest.$ac_ext <<EOF -#line 20598 "configure" +#line 20693 "configure" #include "confdefs.h" #include <ctype.h> @@ -20606,7 +20701,7 @@ main() exit(1); } EOF -if { (eval echo configure:20610: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:20705: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ol_cv_c_upper_lower=no else @@ -20629,12 +20724,12 @@ EOF fi echo $ac_n "checking for working const""... $ac_c" 1>&6 -echo "configure:20633: checking for working const" >&5 +echo "configure:20728: checking for working const" >&5 if eval "test \"\${ac_cv_c_const+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20638 "configure" +#line 20733 "configure" #include "confdefs.h" int main() { @@ -20683,7 +20778,7 @@ ccp = (char const *const *) p; ; return 0; } EOF -if { (eval echo configure:20687: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20782: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else @@ -20704,12 +20799,12 @@ EOF fi echo $ac_n "checking if compiler understands volatile""... $ac_c" 1>&6 -echo "configure:20708: checking if compiler understands volatile" >&5 +echo "configure:20803: checking if compiler understands volatile" >&5 if eval "test \"\${ol_cv_c_volatile+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 20713 "configure" +#line 20808 "configure" #include "confdefs.h" int x, y, z; int main() { @@ -20718,7 +20813,7 @@ volatile int a; int * volatile b = x ? &y : &z; *b = 0; ; return 0; } EOF -if { (eval echo configure:20722: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20817: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_c_volatile=yes else @@ -20748,14 +20843,14 @@ EOF else echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:20752: checking whether byte ordering is bigendian" >&5 +echo "configure:20847: checking whether byte ordering is bigendian" >&5 if eval "test \"\${ac_cv_c_bigendian+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext <<EOF -#line 20759 "configure" +#line 20854 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -20766,11 +20861,11 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:20770: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20865: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext <<EOF -#line 20774 "configure" +#line 20869 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -20781,7 +20876,7 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:20785: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20880: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -20801,7 +20896,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 20805 "configure" +#line 20900 "configure" #include "confdefs.h" main () { /* Are we little or big endian? From Harbison&Steele. */ @@ -20814,7 +20909,7 @@ main () { exit (u.c[sizeof (long) - 1] == 1); } EOF -if { (eval echo configure:20818: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:20913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else @@ -20840,13 +20935,13 @@ fi fi echo $ac_n "checking size of short""... $ac_c" 1>&6 -echo "configure:20844: checking size of short" >&5 +echo "configure:20939: checking size of short" >&5 if eval "test \"\${ac_cv_sizeof_short+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 20850 "configure" +#line 20945 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -20856,7 +20951,7 @@ int main() { switch (0) case 0: case (sizeof (short) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:20860: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20955: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_short=$ac_size else @@ -20879,13 +20974,13 @@ EOF echo $ac_n "checking size of int""... $ac_c" 1>&6 -echo "configure:20883: checking size of int" >&5 +echo "configure:20978: checking size of int" >&5 if eval "test \"\${ac_cv_sizeof_int+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 20889 "configure" +#line 20984 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -20895,7 +20990,7 @@ int main() { switch (0) case 0: case (sizeof (int) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:20899: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:20994: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_int=$ac_size else @@ -20918,13 +21013,13 @@ EOF echo $ac_n "checking size of long""... $ac_c" 1>&6 -echo "configure:20922: checking size of long" >&5 +echo "configure:21017: checking size of long" >&5 if eval "test \"\${ac_cv_sizeof_long+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 20928 "configure" +#line 21023 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -20934,7 +21029,7 @@ int main() { switch (0) case 0: case (sizeof (long) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:20938: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:21033: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_long=$ac_size else @@ -20985,7 +21080,7 @@ EOF echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 -echo "configure:20989: checking for 8-bit clean memcmp" >&5 +echo "configure:21084: checking for 8-bit clean memcmp" >&5 if eval "test \"\${ac_cv_func_memcmp_clean+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -20993,7 +21088,7 @@ else ac_cv_func_memcmp_clean=no else cat > conftest.$ac_ext <<EOF -#line 20997 "configure" +#line 21092 "configure" #include "confdefs.h" main() @@ -21003,7 +21098,7 @@ main() } EOF -if { (eval echo configure:21007: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:21102: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_memcmp_clean=yes else @@ -21021,12 +21116,12 @@ echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" echo $ac_n "checking for strftime""... $ac_c" 1>&6 -echo "configure:21025: checking for strftime" >&5 +echo "configure:21120: checking for strftime" >&5 if eval "test \"\${ac_cv_func_strftime+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21030 "configure" +#line 21125 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char strftime(); below. */ @@ -21050,7 +21145,7 @@ f = strftime; ; return 0; } EOF -if { (eval echo configure:21054: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21149: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strftime=yes" else @@ -21072,7 +21167,7 @@ else echo "$ac_t""no" 1>&6 # strftime is in -lintl on SCO UNIX. echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 -echo "configure:21076: checking for strftime in -lintl" >&5 +echo "configure:21171: checking for strftime in -lintl" >&5 ac_lib_var=`echo intl'_'strftime | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -21080,7 +21175,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <<EOF -#line 21084 "configure" +#line 21179 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -21091,7 +21186,7 @@ int main() { strftime() ; return 0; } EOF -if { (eval echo configure:21095: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21190: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -21119,12 +21214,12 @@ fi echo $ac_n "checking for inet_aton()""... $ac_c" 1>&6 -echo "configure:21123: checking for inet_aton()" >&5 +echo "configure:21218: checking for inet_aton()" >&5 if eval "test \"\${ol_cv_func_inet_aton+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21128 "configure" +#line 21223 "configure" #include "confdefs.h" #ifdef HAVE_SYS_TYPES_H @@ -21146,7 +21241,7 @@ struct in_addr in; int rc = inet_aton( "255.255.255.255", &in ); ; return 0; } EOF -if { (eval echo configure:21150: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_func_inet_aton=yes else @@ -21168,12 +21263,12 @@ EOF echo $ac_n "checking for _spawnlp""... $ac_c" 1>&6 -echo "configure:21172: checking for _spawnlp" >&5 +echo "configure:21267: checking for _spawnlp" >&5 if eval "test \"\${ac_cv_func__spawnlp+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21177 "configure" +#line 21272 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _spawnlp(); below. */ @@ -21197,7 +21292,7 @@ f = _spawnlp; ; return 0; } EOF -if { (eval echo configure:21201: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21296: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__spawnlp=yes" else @@ -21221,12 +21316,12 @@ fi echo $ac_n "checking for _snprintf""... $ac_c" 1>&6 -echo "configure:21225: checking for _snprintf" >&5 +echo "configure:21320: checking for _snprintf" >&5 if eval "test \"\${ac_cv_func__snprintf+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21230 "configure" +#line 21325 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _snprintf(); below. */ @@ -21250,7 +21345,7 @@ f = _snprintf; ; return 0; } EOF -if { (eval echo configure:21254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21349: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__snprintf=yes" else @@ -21276,12 +21371,12 @@ fi echo $ac_n "checking for _vsnprintf""... $ac_c" 1>&6 -echo "configure:21280: checking for _vsnprintf" >&5 +echo "configure:21375: checking for _vsnprintf" >&5 if eval "test \"\${ac_cv_func__vsnprintf+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21285 "configure" +#line 21380 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _vsnprintf(); below. */ @@ -21305,7 +21400,7 @@ f = _vsnprintf; ; return 0; } EOF -if { (eval echo configure:21309: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21404: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__vsnprintf=yes" else @@ -21331,12 +21426,12 @@ fi echo $ac_n "checking for vprintf""... $ac_c" 1>&6 -echo "configure:21335: checking for vprintf" >&5 +echo "configure:21430: checking for vprintf" >&5 if eval "test \"\${ac_cv_func_vprintf+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21340 "configure" +#line 21435 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char vprintf(); below. */ @@ -21360,7 +21455,7 @@ f = vprintf; ; return 0; } EOF -if { (eval echo configure:21364: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else @@ -21384,12 +21479,12 @@ fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 -echo "configure:21388: checking for _doprnt" >&5 +echo "configure:21483: checking for _doprnt" >&5 if eval "test \"\${ac_cv_func__doprnt+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21393 "configure" +#line 21488 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt(); below. */ @@ -21413,7 +21508,7 @@ f = _doprnt; ; return 0; } EOF -if { (eval echo configure:21417: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21512: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else @@ -21442,12 +21537,12 @@ if test $ac_cv_func_vprintf = yes ; then for ac_func in vsnprintf vsprintf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:21446: checking for $ac_func" >&5 +echo "configure:21541: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21451 "configure" +#line 21546 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -21471,7 +21566,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:21475: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21570: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -21552,12 +21647,12 @@ for ac_func in \ do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:21556: checking for $ac_func" >&5 +echo "configure:21651: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21561 "configure" +#line 21656 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -21581,7 +21676,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:21585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -21609,12 +21704,12 @@ done for ac_func in getopt do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:21613: checking for $ac_func" >&5 +echo "configure:21708: checking for $ac_func" >&5 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21618 "configure" +#line 21713 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -21638,7 +21733,7 @@ f = $ac_func; ; return 0; } EOF -if { (eval echo configure:21642: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21737: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -21671,13 +21766,13 @@ fi # Check Configuration echo $ac_n "checking declaration of sys_errlist""... $ac_c" 1>&6 -echo "configure:21675: checking declaration of sys_errlist" >&5 +echo "configure:21770: checking declaration of sys_errlist" >&5 if eval "test \"\${ol_cv_dcl_sys_errlist+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21681 "configure" +#line 21776 "configure" #include "confdefs.h" #include <stdio.h> @@ -21690,7 +21785,7 @@ int main() { char *c = (char *) *sys_errlist ; return 0; } EOF -if { (eval echo configure:21694: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:21789: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ol_cv_dcl_sys_errlist=yes ol_cv_have_sys_errlist=yes @@ -21713,20 +21808,20 @@ EOF echo $ac_n "checking existence of sys_errlist""... $ac_c" 1>&6 -echo "configure:21717: checking existence of sys_errlist" >&5 +echo "configure:21812: checking existence of sys_errlist" >&5 if eval "test \"\${ol_cv_have_sys_errlist+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 21723 "configure" +#line 21818 "configure" #include "confdefs.h" #include <errno.h> int main() { char *c = (char *) *sys_errlist ; return 0; } EOF -if { (eval echo configure:21730: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:21825: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ol_cv_have_sys_errlist=yes else @@ -21982,6 +22077,27 @@ EOF fi fi +if test "$ol_enable_null" != no ; then + cat >> confdefs.h <<\EOF +#define SLAPD_NULL 1 +EOF + + BUILD_SLAPD=yes + BUILD_NULL=yes + if test "$ol_with_null_module" != static ; then + cat >> confdefs.h <<\EOF +#define SLAPD_NULL_DYNAMIC 1 +EOF + + BUILD_NULL=mod + BUILD_NULL_DYNAMIC=shared + SLAPD_MODULES_LIST="$SLAPD_MODULES_LIST -dlopen \$(SLAP_DIR)back-null/back_null.la" + SLAPD_DYNAMIC_BACKENDS="$SLAPD_DYNAMIC_BACKENDS back-null" + else + SLAPD_STATIC_BACKENDS="$SLAPD_STATIC_BACKENDS back-null" + fi +fi + if test "$ol_enable_passwd" != no ; then cat >> confdefs.h <<\EOF #define SLAPD_PASSWD 1 @@ -22114,6 +22230,8 @@ fi + + @@ -22249,6 +22367,7 @@ servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.i servers/slapd/back-ldbm/Makefile:build/top.mk:servers/slapd/back-ldbm/Makefile.in:build/mod.mk \ servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk \ servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk \ +servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk \ servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk \ servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk \ servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk \ @@ -22354,6 +22473,7 @@ s%@BUILD_LDAP@%$BUILD_LDAP%g s%@BUILD_LDBM@%$BUILD_LDBM%g s%@BUILD_META@%$BUILD_META%g s%@BUILD_MONITOR@%$BUILD_MONITOR%g +s%@BUILD_NULL@%$BUILD_NULL%g s%@BUILD_PASSWD@%$BUILD_PASSWD%g s%@BUILD_PERL@%$BUILD_PERL%g s%@BUILD_SHELL@%$BUILD_SHELL%g @@ -22364,6 +22484,7 @@ s%@BUILD_LDAP_DYNAMIC@%$BUILD_LDAP_DYNAMIC%g s%@BUILD_LDBM_DYNAMIC@%$BUILD_LDBM_DYNAMIC%g s%@BUILD_META_DYNAMIC@%$BUILD_META_DYNAMIC%g s%@BUILD_MONITOR_DYNAMIC@%$BUILD_MONITOR_DYNAMIC%g +s%@BUILD_NULL_DYNAMIC@%$BUILD_NULL_DYNAMIC%g s%@BUILD_PASSWD_DYNAMIC@%$BUILD_PASSWD_DYNAMIC%g s%@BUILD_PERL_DYNAMIC@%$BUILD_PERL_DYNAMIC%g s%@BUILD_SHELL_DYNAMIC@%$BUILD_SHELL_DYNAMIC%g @@ -22472,6 +22593,7 @@ servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.i servers/slapd/back-ldbm/Makefile:build/top.mk:servers/slapd/back-ldbm/Makefile.in:build/mod.mk \ servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk \ servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk \ +servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk \ servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk \ servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk \ servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk \ diff --git a/configure.in b/configure.in index a5766d6ea10643a99d3ab583a0b1ad69a0d8591f..1ad5c1a5d9445a8ffa09d4155a118cf726131396 100644 --- a/configure.in +++ b/configure.in @@ -199,6 +199,9 @@ OL_ARG_WITH(meta_module,[ --with-meta-module module type], static, OL_ARG_ENABLE(monitor,[ --enable-monitor enable monitor backend], no)dnl OL_ARG_WITH(monitor_module,[ --with-monitor-module module type], static, [static dynamic]) +OL_ARG_ENABLE(null,[ --enable-null enable null backend], no)dnl +OL_ARG_WITH(null_module,[ --with-null-module module type], static, + [static dynamic]) OL_ARG_ENABLE(passwd,[ --enable-passwd enable passwd backend], no)dnl OL_ARG_WITH(passwd_module,[ --with-passwd-module module type], static, [static dynamic]) @@ -249,6 +252,9 @@ if test $ol_enable_slapd = no ; then if test $ol_enable_monitor = yes ; then AC_MSG_WARN([slapd disabled, ignoring --enable-monitor argument]) fi + if test $ol_enable_null = yes ; then + AC_MSG_WARN([slapd disabled, ignoring --enable-null argument]) + fi if test $ol_enable_passwd = yes ; then AC_MSG_WARN([slapd disabled, ignoring --enable-passwd argument]) fi @@ -303,6 +309,9 @@ dnl fi if test $ol_with_monitor_module != static ; then AC_MSG_WARN([slapd disabled, ignoring --with-monitor-module argument]) fi + if test $ol_with_null_module != static ; then + AC_MSG_WARN([slapd disabled, ignoring --with-null-module argument]) + fi if test $ol_with_passwd_module != static ; then AC_MSG_WARN([slapd disabled, ignoring --with-passwd-module argument]) fi @@ -329,6 +338,7 @@ dnl fi ol_enable_ldbm=no ol_enable_meta=no ol_enable_monitor=no + ol_enable_null=no ol_enable_passwd=no ol_enable_perl=no ol_enable_shell=no @@ -351,6 +361,7 @@ dnl ol_enable_multimaster=no ol_with_ldbm_module=static ol_with_meta_module=static ol_with_monitor_module=static + ol_with_null_module=static ol_with_passwd_module=static ol_with_perl_module=static ol_with_shell_module=static @@ -381,6 +392,7 @@ elif test $ol_enable_ldbm = no ; then $ol_enable_ldap = no -a \ $ol_enable_meta = no -a \ $ol_enable_monitor = no -a \ + $ol_enable_null = no -a \ $ol_enable_passwd = no -a \ $ol_enable_perl = no -a \ $ol_enable_shell = no -a \ @@ -494,6 +506,7 @@ BUILD_LDAP=no BUILD_LDBM=no BUILD_META=no BUILD_MONITOR=no +BUILD_NULL=no BUILD_PASSWD=no BUILD_PERL=no BUILD_SHELL=no @@ -505,6 +518,7 @@ BUILD_LDAP_DYNAMIC=static BUILD_LDBM_DYNAMIC=static BUILD_META_DYNAMIC=static BUILD_MONITOR_DYNAMIC=static +BUILD_NULL_DYNAMIC=static BUILD_PASSWD_DYNAMIC=static BUILD_PERL_DYNAMIC=static BUILD_SHELL_DYNAMIC=static @@ -719,6 +733,7 @@ else ol_with_ldbm_module=static ol_with_meta_module=static ol_with_monitor_module=static + ol_with_null_module=static ol_with_passwd_module=static ol_with_perl_module=static ol_with_shell_module=static @@ -1032,11 +1047,15 @@ if test $ol_with_kerberos = yes -o $ol_with_kerberos = auto \ [-l$krb5crypto -lcom_err]) elif test $krb5_impl = heimdal; then + AC_CHECK_LIB(des, main, + [krb5crypto=des], + [krb5crypto=crypto]) + AC_CHECK_LIB(krb5, main, [have_krb5=yes - KRB5_LIBS="-lkrb5 -ldes -lasn1 -lroken -lcom_err"], + KRB5_LIBS="-lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err"], [have_krb5=no], - [-ldes -lasn1 -lroken -lcom_err]) + [-l$krb5crypto -lasn1 -lroken -lcom_err]) AC_DEFINE(HAVE_HEIMDAL_KERBEROS, 1, [define if you have HEIMDAL Kerberos]) @@ -1081,7 +1100,7 @@ if test $ol_link_krb5 = yes -a \( $ol_with_kerberos = yes -o \ elif test $krb5_impl = heimdal; then AC_CHECK_LIB(krb4, main, [have_k425=yes KRB4_LIBS="-lkrb4"], [have_k425=no], - [-lkrb5 -ldes -lasn1 -lroken -lcom_err]) + [-lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err]) else have_425=no @@ -1216,7 +1235,7 @@ if test $ol_with_tls != no ; then fi else - AC_WARN([TLS privacy protection not supported!]) + AC_WARN([TLS data protection not supported!]) fi if test $ol_link_tls = yes ; then @@ -1224,7 +1243,7 @@ if test $ol_link_tls = yes ; then elif test $ol_with_tls = auto ; then AC_WARN([Could not locate TLS/SSL package]) - AC_WARN([TLS privacy protection not supported!]) + AC_WARN([TLS data protection not supported!]) elif test $ol_with_tls != no ; then AC_ERROR([Could not locate TLS/SSL package]) @@ -2554,6 +2573,22 @@ if test "$ol_enable_monitor" != no ; then fi fi +if test "$ol_enable_null" != no ; then + AC_DEFINE(SLAPD_NULL,1,[define to support NULL backend]) + BUILD_SLAPD=yes + BUILD_NULL=yes + if test "$ol_with_null_module" != static ; then + AC_DEFINE(SLAPD_NULL_DYNAMIC,1, + [define to support dynamic NULL backend]) + BUILD_NULL=mod + BUILD_NULL_DYNAMIC=shared + SLAPD_MODULES_LIST="$SLAPD_MODULES_LIST -dlopen \$(SLAP_DIR)back-null/back_null.la" + SLAPD_DYNAMIC_BACKENDS="$SLAPD_DYNAMIC_BACKENDS back-null" + else + SLAPD_STATIC_BACKENDS="$SLAPD_STATIC_BACKENDS back-null" + fi +fi + if test "$ol_enable_passwd" != no ; then AC_DEFINE(SLAPD_PASSWD,1,[define to support PASSWD backend]) BUILD_SLAPD=yes @@ -2654,6 +2689,7 @@ AC_SUBST(BUILD_SLAPD) AC_SUBST(BUILD_LDBM) AC_SUBST(BUILD_META) AC_SUBST(BUILD_MONITOR) + AC_SUBST(BUILD_NULL) AC_SUBST(BUILD_PASSWD) AC_SUBST(BUILD_PERL) AC_SUBST(BUILD_SHELL) @@ -2664,6 +2700,7 @@ AC_SUBST(BUILD_SLAPD) AC_SUBST(BUILD_LDBM_DYNAMIC) AC_SUBST(BUILD_META_DYNAMIC) AC_SUBST(BUILD_MONITOR_DYNAMIC) + AC_SUBST(BUILD_NULL_DYNAMIC) AC_SUBST(BUILD_PASSWD_DYNAMIC) AC_SUBST(BUILD_PERL_DYNAMIC) AC_SUBST(BUILD_SHELL_DYNAMIC) @@ -2749,6 +2786,7 @@ servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.i servers/slapd/back-ldbm/Makefile:build/top.mk:servers/slapd/back-ldbm/Makefile.in:build/mod.mk \ servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk \ servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk \ +servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk \ servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk \ servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk \ servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk \ diff --git a/contrib/ldapc++/Makefile.in b/contrib/ldapc++/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..36a4d2160e5e39eb6cf8408661ea994cd8dd1a3a --- /dev/null +++ b/contrib/ldapc++/Makefile.in @@ -0,0 +1,367 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Copyright 2000, OpenLDAP Foundation, All Rights Reserved. +# COPYING RESTRICTIONS APPLY, see COPYRIGHT file + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +CC = @CC@ +CXX = @CXX@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +EXEEXT = @EXEEXT@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ + +EXTRA_DIST = BUGS +SUBDIRS = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ./src/config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README AUTHORS Makefile.am Makefile.in TODO acconfig.h \ +aclocal.m4 config.guess config.sub configure configure.in install-sh \ +ltmain.sh missing mkinstalldirs src/config.h.in src/stamp-h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +src/config.h: src/stamp-h + @if test ! -f $@; then \ + rm -f src/stamp-h; \ + $(MAKE) src/stamp-h; \ + else :; fi +src/stamp-h: $(srcdir)/src/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=src/config.h \ + $(SHELL) ./config.status + @echo timestamp > src/stamp-h 2> /dev/null +$(srcdir)/src/config.h.in: $(srcdir)/src/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/src/stamp-h.in; \ + $(MAKE) $(srcdir)/src/stamp-h.in; \ + else :; fi +$(srcdir)/src/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/src/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f src/config.h + +maintainer-clean-hdr: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" != "." || dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + -rm -f libtool + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ldapc++/aclocal.m4 b/contrib/ldapc++/aclocal.m4 new file mode 100644 index 0000000000000000000000000000000000000000..4c2b77a5435494d89c4218df5ab4d87c5641e515 --- /dev/null +++ b/contrib/ldapc++/aclocal.m4 @@ -0,0 +1,3563 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4-p5 + +dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN([AM_MISSING_PROG], +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + +# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*- + +# serial 46 AC_PROG_LIBTOOL + +builtin([undefine],[symbols]) + +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +]) + +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +_LT_AC_PROG_ECHO_BACKSLASH +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_SAVE + AC_LANG_C + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_RESTORE]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac + +_LT_AC_LTCONFIG_HACK + +]) + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN(_LT_AC_CHECK_DLFCN, +[AC_CHECK_HEADERS(dlfcn.h) +])# _LT_AC_CHECK_DLFCN + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +[symcode='[BCDEGRST]'] + +# Regexp to match symbols that can be accessed directly from C. +[sympat='\([_A-Za-z][_A-Za-z0-9]*\)'] + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + [symcode='[BCDT]'] + ;; +cygwin* | mingw* | pw32*) + [symcode='[ABCDGISTW]'] + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix*) + [symcode='[BCDEGRST]'] + ;; +solaris* | sysv5*) + [symcode='[BDT]'] + ;; +sysv4) + [symcode='[DFNSTU]'] + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + [symcode='[ABCDGISTW]'] +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. +[lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"] + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext <<EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat <<EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <<EOF >> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +[lt_preloaded_symbols[] =] +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if AC_TRY_EVAL(ac_link) && test -s conftest; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AC_FD_CC + fi + else + echo "cannot find nm_test_var in $nlist" >&AC_FD_CC + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "$progname: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= + global_symbol_to_c_name_address= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" + global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address"; +then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + +# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR +# --------------------------------- +AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], +[# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac +fi +])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn;t interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +AC_DIVERT_POP +])# _LT_AC_PROG_ECHO_BACKSLASH + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN(_LT_AC_TRY_DLOPEN_SELF, +[if test "$cross_compiling" = yes; then : + [$4] +else + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN(AC_LIBTOOL_DLOPEN_SELF, +[if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + +AC_DEFUN([_LT_AC_LTCONFIG_HACK], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="[$]2" + +AC_MSG_CHECKING([for objdir]) +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +AC_MSG_RESULT($objdir) + + +AC_ARG_WITH(pic, +[ --with-pic try to use only PIC/non-PIC objects [default=use both]], +pic_mode="$withval", pic_mode=default) +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +AC_MSG_CHECKING([for $compiler option to produce PIC]) +AC_CACHE_VAL(lt_cv_prog_cc_pic, +[ lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + lt_cv_prog_cc_wl='-Wl,' + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + if test "x$host_vendor" = xsni; then + lt_cv_prog_cc_wl='-LD' + else + lt_cv_prog_cc_wl='-Wl,' + fi + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi +]) +if test -z "$lt_cv_prog_cc_pic"; then + AC_MSG_RESULT([none]) +else + AC_MSG_RESULT([$lt_cv_prog_cc_pic]) + + # Check to make sure the pic_flag actually works. + AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works]) + AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + AC_TRY_COMPILE([], [], [dnl + case $host_os in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then + # they create non-PIC objects. So, if there were any warnings, we + # assume that PIC is not supported. + if test -s conftest.err; then + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + ], [dnl + lt_cv_prog_cc_pic_works=no + ]) + CFLAGS="$save_CFLAGS" + ]) + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + AC_MSG_RESULT([$lt_cv_prog_cc_pic_works]) +fi + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | [egrep -e "[ ]$lt_cv_prog_cc_shlib[ ]"] >/dev/null; then : + else + AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure]) + lt_cv_prog_cc_can_build_shared=no + fi +fi + +AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works]) +AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes]) + LDFLAGS="$save_LDFLAGS" +]) + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +AC_MSG_RESULT([$lt_cv_prog_cc_static_works]) + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" + + +# Check to see if options -o and -c are simultaneously supported by compiler +AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext]) +AC_CACHE_VAL([lt_cv_compiler_c_o], [ +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" +compiler_c_o=no +if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&AC_FD_CC + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null +]) +compiler_c_o=$lt_cv_compiler_c_o +AC_MSG_RESULT([$compiler_c_o]) + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + AC_MSG_CHECKING([if $compiler supports -c -o file.lo]) + AC_CACHE_VAL([lt_cv_compiler_o_lo], [ + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + save_objext="$ac_objext" + ac_objext=lo + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + ]) + ac_objext="$save_objext" + CFLAGS="$save_CFLAGS" + ]) + compiler_o_lo=$lt_cv_compiler_o_lo + AC_MSG_RESULT([$compiler_o_lo]) +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi + +if test "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions]) + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + ]) + CFLAGS="$save_CFLAGS" + AC_MSG_RESULT([$compiler_rtti_exceptions]) + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi + +# See if the linker supports building shared libraries. +AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries]) + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; +openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + ld_shlibs=no + cat <<EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < [$]0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + [sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//"] < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \[$]# in + 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + hardcode_direct=yes + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + esac + + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + shared_flag='${wl}-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok' + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case "$host_os" in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + export_dynamic_flag_spec='${wl}-Bexport' + ;; + + solaris*) + no_undefined_flag=' -z defs' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + [solaris2.[0-5] | solaris2.[0-5].*]) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsno; then + archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +AC_MSG_RESULT([$ld_shlibs]) +test "$ld_shlibs" = no && can_build_shared=no + +# Check hardcoding attributes. +AC_MSG_CHECKING([how to hardcode library paths into programs]) +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +AC_MSG_RESULT([$hardcode_action]) + +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +# PORTME Fill in your ld.so characteristics +AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + [ aix4 | aix4.[01] | aix4.[01].*)] + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can + # not hardcode correct soname into executable. Probably we can + # add versioning support to collect2, so additional links can + # be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | [$Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\'']`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | [sed -e 's/[.]/-/g']`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | [sed -e 's/[.]/-/g']`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | [sed -e 's/[.]/-/g']`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case "$host_os" in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +AC_LIBTOOL_DLOPEN_SELF + +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + AC_CACHE_VAL([lt_cv_archive_cmds_need_lc], + [$rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile); then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi]) + AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc]) + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} + +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \ + postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib file_magic_cmd export_symbols_cmds \ + deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + global_symbol_to_c_name_address \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case $var in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996-2000 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include <windows.h> +# #undef WIN32_LEAN_AND_MEAN +# #include <stdio.h> +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include <cygwin/cygwin_dll.h> +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999-2000 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include <stdio.h> /* for printf() */ +# #include <unistd.h> /* for open(), lseek(), read() */ +# #include <fcntl.h> /* for O_RDONLY, O_BINARY */ +# #include <string.h> /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i<nexp; i++) +# { +# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4); +# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i); +# } +# +# return 0; +# } +# /* impgen.c ends here */ + +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi + +])# _LT_AC_LTCONFIG_HACK + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_LIBTOOL_PICMODE - implement the --with-pic flag +# Usage: AC_LIBTOOL_PICMODE[(MODE)] +# Where MODE is either `yes' or `no'. If omitted, it defaults to +# `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default)]) + + +# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <<EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +]) + + +# AC_PATH_MAGIC - find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH) + else + MAGIC_CMD=: + fi +fi +]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +# AC_PROG_LD_GNU - +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +]) + +# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, +[lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" +]) + +# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_CACHE_CHECK([how to recognise dependant libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# ['file_magic [regex]'] -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'] + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[[012]]) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + [lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + [lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"] + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* | m68* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;;] + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$'] + else + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$'] + fi + ;; + +newos6*) + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +[sysv5uw[78]* | sysv4*uw2*)] + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'] + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'] + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + [lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"] + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +]) + + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and INCLTDL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and INCLTDL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= + fi +]) + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + diff --git a/contrib/ldapc++/config.guess b/contrib/ldapc++/config.guess new file mode 100755 index 0000000000000000000000000000000000000000..b9766334c2195ca788ab1f1c7a13a5a106d9ac06 --- /dev/null +++ b/contrib/ldapc++/config.guess @@ -0,0 +1,1308 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-07-12' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner <bothner@cygnus.com>. +# Please send patches to <config-patches@gnu.org>. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int dummy(){}" > $dummy.c ; + for c in cc gcc c89 ; do + ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; + if test $? = 0 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + rm -f $dummy.c $dummy.o $dummy.rel ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_MACHINE}" in + i?86) + test -z "$VENDOR" && VENDOR=pc + ;; + *) + test -z "$VENDOR" && VENDOR=unknown + ;; +esac +test -e /etc/SuSE-release && VENDOR=suse + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE}" in + i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <<EOF >$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + case "${HPUX_REV}" in + 11.[0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + esac ;; + esac + fi ;; + esac + if [ "${HP_ARCH}" = "" ]; then + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + eval $set_cc_for_build + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy + fi ;; + esac + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3D:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + mips:Linux:*:*) + case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in + big) echo mips-${VENDOR}-linux && exit 0 ;; + little) echo mipsel-${VENDOR}-linux && exit 0 ;; + esac + ;; + ppc:Linux:*:*|ppc64:Linux:*:*) + echo powerpc-${VENDOR}-linux + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev67 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-${VENDOR}-linux${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-${VENDOR}-linux ;; + PA8*) echo hppa2.0-${VENDOR}-linux ;; + *) echo hppa-${VENDOR}-linux ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-${VENDOR}-linux + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-${VENDOR}-linux + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_supported_targets=`cd /; ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-${VENDOR}-linux" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-${VENDOR}-linuxaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-${VENDOR}-linuxcoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linuxoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-${VENDOR}-linuxoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c <<EOF +#include <features.h> +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux\n", argv[1]); +# else + printf ("%s-${VENDOR}-linuxlibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linuxlibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linuxaout\n", argv[1]); +#endif + return 0; +} +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +eval $set_cc_for_build +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + ftp://ftp.gnu.org/pub/gnu/config/ + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ldapc++/config.sub b/contrib/ldapc++/config.sub new file mode 100755 index 0000000000000000000000000000000000000000..4334d1209af900a0720574ed7c50cfa97cea78e3 --- /dev/null +++ b/contrib/ldapc++/config.sub @@ -0,0 +1,1375 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-06-08' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to <config-patches@gnu.org>. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \ + | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \ + | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp10 | pdp11 \ + | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | mips64vr5000el | mcore | s390 | s390x \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \ + | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \ + | pj | pjl | h8500 | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \ + | arm-* | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp10-* | pdp11-* | sh-* | sh[34]-* | sh[34]eb-* \ + | powerpc-* | powerpcle-* | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \ + | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \ + | [cjt]90-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [cjt]90) + basic_machine=${basic_machine}-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + ;; + mips*-linux*) + basic_machine=mips-unknown + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc64) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + windows32) + basic_machine=i386-pc + os=-windows32-msvcrt + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + case $os in + linux*) + basic_machine=mips-unknown + ;; + *) + basic_machine=mips-mips + ;; + esac + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + basic_machine=sh-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ldapc++/configure b/contrib/ldapc++/configure new file mode 100755 index 0000000000000000000000000000000000000000..efd26184f93b2029fe9cf132451a682c8f5eff78 --- /dev/null +++ b/contrib/ldapc++/configure @@ -0,0 +1,7950 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by Autoconf 2.52. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac +fi + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF + +EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +cross_compiling=no +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +ac_unique_file="src/main.cpp" + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: should be removed in autoconf 3.0. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<EOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +EOF + + cat <<EOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +EOF + + cat <<\EOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST build programs to run on HOST [BUILD] +EOF +fi + +if test -n "$ac_init_help"; then + + cat <<\EOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-shared=PKGS build shared libraries default=yes + --enable-static=PKGS build static libraries default=yes + --enable-fast-install=PKGS optimize for fast installation default=yes + --disable-libtool-lock avoid locking (might break parallel builds) +--enable-debug + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-pic try to use only PIC/non-PIC objects default=use both + --with-libldap=DIR Path to the libldap library /usr/local/lib + --with-ldap-includes=DIR Path to the libldap include files /usr/local/include + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CC C compiler command + CFLAGS C compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +EOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue + cd $ac_subdir + # A "../" for each directory in /$ac_subdir. + ac_dots=`echo $ac_subdir | + sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'` + + case $srcdir in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_subdir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure.gnu; then + echo + $SHELL $ac_sub_srcdir/configure.gnu --help=recursive + elif test -f $ac_sub_srcdir/configure; then + echo + $SHELL $ac_sub_srcdir/configure --help=recursive + elif test -f $ac_sub_srcdir/configure.ac || + test -f $ac_sub_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\EOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +EOF + exit 0 +fi +exec 5>config.log +cat >&5 <<EOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.52. Invocation command line was + + $ $0 $@ + +EOF +{ +cat <<_ASUNAME +## ---------- ## +## Platform. ## +## ---------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +PATH = $PATH + +_ASUNAME +} >&5 + +cat >&5 <<EOF +## ------------ ## +## Core tests. ## +## ------------ ## + +EOF + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell meta-characters. +ac_configure_args= +ac_sep= +for ac_arg +do + case $ac_arg in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + ac_sep=" " ;; + *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg" + ac_sep=" " ;; + esac + # Get rid of the leading space. +done + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + echo >&5 + echo "## ----------------- ##" >&5 + echo "## Cache variables. ##" >&5 + echo "## ----------------- ##" >&5 + echo >&5 + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} >&5 + sed "/^$/d" confdefs.h >conftest.log + if test -s conftest.log; then + echo >&5 + echo "## ------------ ##" >&5 + echo "## confdefs.h. ##" >&5 + echo "## ------------ ##" >&5 + echo >&5 + cat conftest.log >&5 + fi + (echo; echo) >&5 + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" >&5 + echo "$as_me: exit $exit_status" >&5 + rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:1010: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + cat "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:1021: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:1029: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:1045: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:1049: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:1055: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:1057: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:1059: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. It doesn't matter if + # we pass some twice (in addition to the command line arguments). + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val" + ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:1078: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:1080: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac +echo "#! $SHELL" >conftest.sh +echo "exit 0" >>conftest.sh +chmod +x conftest.sh +if { (echo "$as_me:1100: PATH=\".;.\"; conftest.sh") >&5 + (PATH=".;."; conftest.sh) 2>&5 + ac_status=$? + echo "$as_me:1103: \$? = $ac_status" >&5 + (exit $ac_status); }; then + ac_path_separator=';' +else + ac_path_separator=: +fi +PATH_SEPARATOR="$ac_path_separator" +rm -f conftest.sh + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:1129: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:1149: checking for a BSD compatible install" >&5 +echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_IFS=$IFS; IFS=$ac_path_separator + for ac_dir in $PATH; do + IFS=$ac_save_IFS + # Account for people who put trailing slashes in PATH elements. + case $ac_dir/ in + / | ./ | .// | /cC/* \ + | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \ + | /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if $as_executable_p "$ac_dir/$ac_prog"; then + if test $ac_prog = install && + grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:1198: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:1209: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:1232: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { { echo "$as_me:1245: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +rm -f conftest* +echo "$as_me:1252: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +echo "$as_me:1267: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:1287: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:1291: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +PACKAGE=main + +VERSION=0.0.1 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { { echo "$as_me:1301: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +cat >>confdefs.h <<EOF +#define PACKAGE "$PACKAGE" +EOF + +cat >>confdefs.h <<EOF +#define VERSION "$VERSION" +EOF + +missing_dir=`cd $ac_aux_dir && pwd` +echo "$as_me:1315: checking for working aclocal" >&5 +echo $ECHO_N "checking for working aclocal... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$as_me:1322: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$as_me:1326: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:1330: checking for working autoconf" >&5 +echo $ECHO_N "checking for working autoconf... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$as_me:1337: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$as_me:1341: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:1345: checking for working automake" >&5 +echo $ECHO_N "checking for working automake... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$as_me:1352: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$as_me:1356: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:1360: checking for working autoheader" >&5 +echo $ECHO_N "checking for working autoheader... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$as_me:1367: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$as_me:1371: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:1375: checking for working makeinfo" >&5 +echo $ECHO_N "checking for working makeinfo... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$as_me:1382: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$as_me:1386: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +ac_config_headers="$ac_config_headers src/config.h" + +ac_config_commands="$ac_config_commands default-1" + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:1406: checking for a BSD compatible install" >&5 +echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_IFS=$IFS; IFS=$ac_path_separator + for ac_dir in $PATH; do + IFS=$ac_save_IFS + # Account for people who put trailing slashes in PATH elements. + case $ac_dir/ in + / | ./ | .// | /cC/* \ + | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \ + | /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if $as_executable_p "$ac_dir/$ac_prog"; then + if test $ac_prog = install && + grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:1455: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:1476: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" +echo "$as_me:1491: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:1499: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:1502: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:1515: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CXX="$ac_prog" +echo "$as_me:1530: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:1538: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:1541: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + +# Provide some information about the compiler. +echo "$as_me:1553:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:1556: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:1559: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1561: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:1564: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1566: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:1569: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line 1573 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:1589: checking for C++ compiler default output" >&5 +echo $ECHO_N "checking for C++ compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:1592: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:1595: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. +for ac_file in `ls a.exe conftest.exe 2>/dev/null; + ls a.out conftest 2>/dev/null; + ls a.* conftest.* 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + a.out ) # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool --akim. + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1618: error: C++ compiler cannot create executables" >&5 +echo "$as_me: error: C++ compiler cannot create executables" >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:1624: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:1629: checking whether the C++ compiler works" >&5 +echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:1635: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1638: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:1645: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'." >&5 +echo "$as_me: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:1653: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:1660: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:1662: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:1665: checking for executable suffix" >&5 +echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6 +if { (eval echo "$as_me:1667: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:1670: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:1686: error: cannot compute EXEEXT: cannot compile and link" >&5 +echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:1692: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:1698: checking for object suffix" >&5 +echo $ECHO_N "checking for object suffix... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1704 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:1716: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1719: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1731: error: cannot compute OBJEXT: cannot compile" >&5 +echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:1738: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:1742: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1748 "configure" +#include "confdefs.h" + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1763: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1766: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1769: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1772: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:1784: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:1790: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1796 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1808: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1811: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1814: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1817: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cxx_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:1827: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + ''\ + '#include <stdlib.h>' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line 1854 "configure" +#include "confdefs.h" +#include <stdlib.h> +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1867: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1870: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1873: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1876: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line 1886 "configure" +#include "confdefs.h" +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1898: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1901: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1904: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1907: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi; +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi; +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi; +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:1997: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:2001: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:2010: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:2014: error: $ac_config_sub $ac_cv_build_alias failed." >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed." >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:2019: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +test -z "$build_alias" && + build_alias=$ac_cv_build + +echo "$as_me:2029: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:2038: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:2043: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +test -z "$host_alias" && + host_alias=$ac_cv_host + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:2061: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}gcc" +echo "$as_me:2076: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:2084: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:2087: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:2096: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="gcc" +echo "$as_me:2111: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:2119: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:2122: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:2135: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}cc" +echo "$as_me:2150: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:2158: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:2161: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:2170: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="cc" +echo "$as_me:2185: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:2193: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:2196: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:2209: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue +fi +ac_cv_prog_CC="cc" +echo "$as_me:2229: found $ac_dir/$ac_word" >&5 +break +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" ${1+"$@"} + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:2251: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:2254: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:2265: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +echo "$as_me:2280: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:2288: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:2291: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:2304: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="$ac_prog" +echo "$as_me:2319: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:2327: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:2330: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + +test -z "$CC" && { { echo "$as_me:2342: error: no acceptable cc found in \$PATH" >&5 +echo "$as_me: error: no acceptable cc found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:2347:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:2350: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:2353: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:2355: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:2358: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:2360: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:2363: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:2366: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2372 "configure" +#include "confdefs.h" + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2387: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2390: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2393: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2396: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:2408: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:2414: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2420 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2432: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2435: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2438: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2441: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:2451: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2478: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2481: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2484: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2487: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include <stdlib.h>' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line 2499 "configure" +#include "confdefs.h" +#include <stdlib.h> +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2512: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2515: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2518: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2521: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line 2531 "configure" +#include "confdefs.h" +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2543: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2546: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2549: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2552: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:2589: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:2619: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:2622: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + echo "$as_me:2652: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:2655: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:2658: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:2661: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:2673: result: $lt_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + +echo "$as_me:2677: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:2684: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" + +echo "$as_me:2689: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi + +NM="$lt_cv_path_NM" +echo "$as_me:2725: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:2728: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:2732: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:2735: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:2739: checking how to recognise dependant libraries" >&5 +echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# ['file_magic [regex]'] -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[012]) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* | m68* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[78]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; +esac + +fi +echo "$as_me:2917: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:2923: checking command to parse $NM output" >&5 +echo $ECHO_N "checking command to parse $NM output... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix*) + symcode='[BCDEGRST]' + ;; +solaris* | sysv5*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. +lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext <<EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +EOF + + if { (eval echo "$as_me:3004: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:3007: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:3011: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:3014: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat <<EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <<EOF >> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo "$as_me:3066: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:3069: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= + global_symbol_to_c_name_address= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" + global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address"; +then + echo "$as_me:3110: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:3113: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:3122: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line 3143 "configure" +#include "confdefs.h" +#include <assert.h> + Syntax error +_ACEOF +if { (eval echo "$as_me:3148: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3154: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line 3177 "configure" +#include "confdefs.h" +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:3181: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3187: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:3224: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line 3234 "configure" +#include "confdefs.h" +#include <assert.h> + Syntax error +_ACEOF +if { (eval echo "$as_me:3239: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3245: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line 3268 "configure" +#include "confdefs.h" +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:3272: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3278: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:3306: error: C preprocessor \"$CPP\" fails sanity check" >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:3320: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 3326 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:3330: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3336: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:3355: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<EOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +EOF + +fi +done + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:3369: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <<EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:3424: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:3427: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:3433: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <<EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:3488: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:3491: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:3507: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" +echo "$as_me:3522: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:3530: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:3533: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:3542: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_RANLIB="ranlib" +echo "$as_me:3557: found $ac_dir/$ac_word" >&5 +break +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:3566: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:3569: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:3581: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_STRIP="${ac_tool_prefix}strip" +echo "$as_me:3596: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:3604: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:3607: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:3616: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_STRIP="strip" +echo "$as_me:3631: found $ac_dir/$ac_word" >&5 +break +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:3640: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:3643: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +enable_dlopen=no +enable_win32_dll=no + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 3667 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:3668: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:3671: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:3692: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +#line 3705 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:3717: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:3720: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:3723: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:3726: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +lt_cv_cc_needs_belf=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +echo "$as_me:3742: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo "$as_me:3836: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$as_me:3847: result: $objdir" >&5 +echo "${ECHO_T}$objdir" >&6 + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +echo "$as_me:3862: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_pic+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + lt_cv_prog_cc_wl='-Wl,' + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + if test "x$host_vendor" = xsni; then + lt_cv_prog_cc_wl='-LD' + else + lt_cv_prog_cc_wl='-Wl,' + fi + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi + +fi + +if test -z "$lt_cv_prog_cc_pic"; then + echo "$as_me:4009: result: none" >&5 +echo "${ECHO_T}none" >&6 +else + echo "$as_me:4012: result: $lt_cv_prog_cc_pic" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic" >&6 + + # Check to make sure the pic_flag actually works. + echo "$as_me:4016: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_cv_prog_cc_pic works... $ECHO_C" >&6 + if test "${lt_cv_prog_cc_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + cat >conftest.$ac_ext <<_ACEOF +#line 4024 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:4036: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:4039: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:4042: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:4045: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + case $host_os in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then + # they create non-PIC objects. So, if there were any warnings, we + # assume that PIC is not supported. + if test -s conftest.err; then + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 + lt_cv_prog_cc_pic_works=no + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + +fi + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + echo "$as_me:4081: result: $lt_cv_prog_cc_pic_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic_works" >&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + { echo "$as_me:4087: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&5 +echo "$as_me: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&2;} + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$lt_cv_prog_cc_shlib[ ]" >/dev/null; then : + else + { echo "$as_me:4091: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 +echo "$as_me: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} + lt_cv_prog_cc_can_build_shared=no + fi +fi + +echo "$as_me:4097: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_cv_prog_cc_static works... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + cat >conftest.$ac_ext <<_ACEOF +#line 4106 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:4118: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:4121: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:4124: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:4127: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_prog_cc_static_works=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +echo "$as_me:4141: result: $lt_cv_prog_cc_static_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_static_works" >&6 + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" + +# Check to see if options -o and -c are simultaneously supported by compiler +echo "$as_me:4152: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" +compiler_c_o=no +if { (eval echo configure:4172: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +fi + +compiler_c_o=$lt_cv_compiler_c_o +echo "$as_me:4196: result: $compiler_c_o" >&5 +echo "${ECHO_T}$compiler_c_o" >&6 + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo "$as_me:4201: checking if $compiler supports -c -o file.lo" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.lo... $ECHO_C" >&6 + if test "${lt_cv_compiler_o_lo+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + save_objext="$ac_objext" + ac_objext=lo + cat >conftest.$ac_ext <<_ACEOF +#line 4213 "configure" +#include "confdefs.h" + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:4225: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:4228: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:4231: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:4234: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + ac_objext="$save_objext" + CFLAGS="$save_CFLAGS" + +fi + + compiler_o_lo=$lt_cv_compiler_o_lo + echo "$as_me:4255: result: $compiler_o_lo" >&5 +echo "${ECHO_T}$compiler_o_lo" >&6 +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:4265: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:4273: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:4276: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +if test "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo "$as_me:4286: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + cat >conftest.$ac_ext <<_ACEOF +#line 4293 "configure" +#include "confdefs.h" + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:4305: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:4308: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:4311: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:4314: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + echo "$as_me:4330: result: $compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$compiler_rtti_exceptions" >&6 + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi + +# See if the linker supports building shared libraries. +echo "$as_me:4341: checking whether the linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the linker ($LD) supports shared libraries... $ECHO_C" >&6 + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; +openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + ld_shlibs=no + cat <<EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < [$]0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \$# in + 2) echo " \$2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \$2 @ \$_lt_hint \$3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + hardcode_direct=yes + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + esac + + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + shared_flag='${wl}-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok' + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + export_dynamic_flag_spec='${wl}-Bexport' + ;; + + solaris*) + no_undefined_flag=' -z defs' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsno; then + archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$as_me:4993: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no + +# Check hardcoding attributes. +echo "$as_me:4998: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$as_me:5022: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 + +striplib= +old_striplib= +echo "$as_me:5027: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:5032: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:5035: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +# PORTME Fill in your ld.so characteristics +echo "$as_me:5043: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can + # not hardcode correct soname into executable. Probably we can + # add versioning support to collect2, so additional links can + # be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/./-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case "$host_os" in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:5436: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "$as_me:5441: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:5443: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:5446: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:5467: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:5470: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:5474: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + echo "$as_me:5512: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 5518 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +char (*f) (); + +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +f = shl_load; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5549: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5552: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5555: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5558: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_func_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:5568: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:5573: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 5581 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5600: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5603: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5606: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5609: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:5620: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:5625: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 5631 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +char (*f) (); + +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +f = dlopen; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5662: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5665: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5668: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5671: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_func_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:5681: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:5686: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 5694 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5713: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5716: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5719: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5722: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:5733: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:5738: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 5746 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5765: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5768: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5771: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5774: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:5785: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:5790: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 5798 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5817: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5820: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5823: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5826: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:5837: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + +fi + +fi + +fi + +fi + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:5873: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<EOF +#line 5884 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:5945: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5948: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + +fi +echo "$as_me:5965: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:5970: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<EOF +#line 5981 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + if { (eval echo "$as_me:6042: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:6045: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + +fi +echo "$as_me:6062: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:6092: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + if test "${lt_cv_archive_cmds_need_lc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + $rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + if { (eval echo "$as_me:6100: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:6103: \$? = $ac_status" >&5 + (exit $ac_status); }; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:6117: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:6120: \$? = $ac_status" >&5 + (exit $ac_status); } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi +fi + + echo "$as_me:6133: result: $lt_cv_archive_cmds_need_lc" >&5 +echo "${ECHO_T}$lt_cv_archive_cmds_need_lc" >&6 + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} + +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \ + postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib file_magic_cmd export_symbols_cmds \ + deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + global_symbol_to_c_name_address \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case $var in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996-2000 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include <windows.h> +# #undef WIN32_LEAN_AND_MEAN +# #include <stdio.h> +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include <cygwin/cygwin_dll.h> +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999-2000 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include <stdio.h> /* for printf() */ +# #include <unistd.h> /* for open(), lseek(), read() */ +# #include <fcntl.h> /* for O_RDONLY, O_BINARY */ +# #include <string.h> /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i<nexp; i++) +# { +# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4); +# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i); +# } +# +# return 0; +# } +# /* impgen.c ends here */ + +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + + CXXFLAGS="-g -O0 -Wall" + cat >>confdefs.h <<\EOF +#define WITH_DEBUG 1 +EOF + +else + + CXXFLAGS="-O0" + +fi; + +# Check whether --with-libldap or --without-libldap was given. +if test "${with_libldap+set}" = set; then + withval="$with_libldap" + + LIBS="-L$with_libldap $LIBS " + +else + + LIBS="-L/usr/local/lib $LIBS " + +fi; + +# Check whether --with-ldap-includes or --without-ldap-includes was given. +if test "${with_ldap_includes+set}" = set; then + withval="$with_ldap_includes" + + CPPFLAGS="-I$with_ldap_includes $CPPFLAGS " + +else + + CPPFLAGS="-I/usr/local/include $CPPFLAGS " + +fi; + +echo "$as_me:6737: checking for main in -lresolv" >&5 +echo $ECHO_N "checking for main in -lresolv... $ECHO_C" >&6 +if test "${ac_cv_lib_resolv_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 6745 "configure" +#include "confdefs.h" + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:6757: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:6760: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:6763: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:6766: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_resolv_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_resolv_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:6777: result: $ac_cv_lib_resolv_main" >&5 +echo "${ECHO_T}$ac_cv_lib_resolv_main" >&6 +if test $ac_cv_lib_resolv_main = yes; then + cat >>confdefs.h <<EOF +#define HAVE_LIBRESOLV 1 +EOF + + LIBS="-lresolv $LIBS" + +fi + +echo "$as_me:6788: checking for ber_strdup in -llber" >&5 +echo $ECHO_N "checking for ber_strdup in -llber... $ECHO_C" >&6 +if test "${ac_cv_lib_lber_ber_strdup+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-llber $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 6796 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ber_strdup (); +int +main () +{ +ber_strdup (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:6815: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:6818: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:6821: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:6824: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_lber_ber_strdup=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_lber_ber_strdup=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:6835: result: $ac_cv_lib_lber_ber_strdup" >&5 +echo "${ECHO_T}$ac_cv_lib_lber_ber_strdup" >&6 +if test $ac_cv_lib_lber_ber_strdup = yes; then + + : + +else + + echo " didn't find ber_strdup in liblber !"; + echo " Check for the right version (>= 2.0) of the OpenLDAP libraries"; + echo " or try the --with-libldap option."; + exit + +fi + +echo "$as_me:6850: checking for ldap_add_ext in -lldap" >&5 +echo $ECHO_N "checking for ldap_add_ext in -lldap... $ECHO_C" >&6 +if test "${ac_cv_lib_ldap_ldap_add_ext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lldap + -llber + $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 6860 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ldap_add_ext (); +int +main () +{ +ldap_add_ext (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:6879: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:6882: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:6885: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:6888: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ldap_ldap_add_ext=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_ldap_ldap_add_ext=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:6899: result: $ac_cv_lib_ldap_ldap_add_ext" >&5 +echo "${ECHO_T}$ac_cv_lib_ldap_ldap_add_ext" >&6 +if test $ac_cv_lib_ldap_ldap_add_ext = yes; then + + : + +else + + echo " didn't find ldap_add_ext in libldap !"; + echo " Check for the right version (>= 2.0) of the OpenLDAP libraries"; + echo " or try the --with-libldap option."; + exit + +fi + +echo "$as_me:6914: checking whether time.h and sys/time.h may both be included" >&5 +echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6 +if test "${ac_cv_header_time+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 6920 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:6936: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:6939: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:6942: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:6945: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_time=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_header_time=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:6955: result: $ac_cv_header_time" >&5 +echo "${ECHO_T}$ac_cv_header_time" >&6 +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo "$as_me:6965: checking for ldap.h" >&5 +echo $ECHO_N "checking for ldap.h... $ECHO_C" >&6 +if test "${ac_cv_header_ldap_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 6971 "configure" +#include "confdefs.h" +#include <ldap.h> +_ACEOF +if { (eval echo "$as_me:6975: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:6981: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_cv_header_ldap_h=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_header_ldap_h=no +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:7000: result: $ac_cv_header_ldap_h" >&5 +echo "${ECHO_T}$ac_cv_header_ldap_h" >&6 + +cat >conftest.$ac_ext <<_ACEOF +#line 7004 "configure" +#include "confdefs.h" +#include <ldap.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ldap_add_ext" >/dev/null 2>&1; then + + : + +else + + echo " didn't find ldap_add_ext in ldap.h!"; + echo " Check for the right version (>= 2.0) of the OpenLDAP includes"; + echo " or try --with-ldap-includes option."; + exit + +fi +rm -f conftest* + +echo "$as_me:7024: checking for lber.h" >&5 +echo $ECHO_N "checking for lber.h... $ECHO_C" >&6 +if test "${ac_cv_header_lber_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 7030 "configure" +#include "confdefs.h" +#include <lber.h> +_ACEOF +if { (eval echo "$as_me:7034: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:7040: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_cv_header_lber_h=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_header_lber_h=no +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:7059: result: $ac_cv_header_lber_h" >&5 +echo "${ECHO_T}$ac_cv_header_lber_h" >&6 + +cat >conftest.$ac_ext <<_ACEOF +#line 7063 "configure" +#include "confdefs.h" +#include <lber.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ber_strdup" >/dev/null 2>&1; then + + : + +else + + echo " didn't find ber_strdup in lber.h!"; + echo " Check for the right version (>= 2.0) of the OpenLDAP includes"; + echo " or try --with-ldap-includes option."; + exit + +fi +rm -f conftest* + +ac_config_files="$ac_config_files Makefile src/Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overriden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if cmp -s $cache_file confcache; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:7163: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +SHELL=\${CONFIG_SHELL-$SHELL} +ac_cs_invocation="\$0 \$@" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } + +exec 6>&1 + +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\EOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to <bug-autoconf@gnu.org>." +EOF + +cat >>$CONFIG_STATUS <<EOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.52, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +EOF + +cat >>$CONFIG_STATUS <<\EOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + shift + set dummy "$ac_option" "$ac_optarg" ${1+"$@"} + shift + ;; + -*);; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_need_defaults=false;; + esac + + case $1 in + # Handling of the options. +EOF +cat >>$CONFIG_STATUS <<EOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion" + exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;; +EOF +cat >>$CONFIG_STATUS <<\EOF + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:7339: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + shift + CONFIG_FILES="$CONFIG_FILES $1" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + shift + CONFIG_HEADERS="$CONFIG_HEADERS $1" + ac_need_defaults=false;; + + # This is an error. + -*) { { echo "$as_me:7358: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +exec 5>>config.log +cat >&5 << _ACEOF + +## ----------------------- ## +## Running config.status. ## +## ----------------------- ## + +This file was extended by $as_me 2.52, executed with + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + > $ac_cs_invocation +on `(hostname || uname -n) 2>/dev/null | sed 1q` + +_ACEOF +EOF + +cat >>$CONFIG_STATUS <<EOF +# +# INIT-COMMANDS section. +# + +EOF + +cat >>$CONFIG_STATUS <<\EOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "src/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + *) { { echo "$as_me:7404: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/cs$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + +EOF + +cat >>$CONFIG_STATUS <<EOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@DEFS@,$DEFS,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@CPP@,$CPP,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +CEOF + +EOF + + cat >>$CONFIG_STATUS <<\EOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +EOF +cat >>$CONFIG_STATUS <<\EOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || mkdir "$as_incr_dir" + ;; + esac +done; } + + ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'` + else + ac_dir_suffix= ac_dots= + fi + + case $srcdir in + .) ac_srcdir=. + if test -z "$ac_dots"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_dots$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_dots$srcdir ;; + esac + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_dots$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:7637: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated automatically by config.status. */ + configure_input="Generated automatically from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:7655: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:7668: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +EOF +cat >>$CONFIG_STATUS <<EOF + sed "$ac_vpsub +$extrasub +EOF +cat >>$CONFIG_STATUS <<\EOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +EOF +cat >>$CONFIG_STATUS <<\EOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:7729: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:7740: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:7753: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +EOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\EOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\(\([^ (][^ (]*\)([^)]*)\)[ ]*\(.*\)$,${ac_dA}\2${ac_dB}\1${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +EOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\EOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +EOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # egrep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\EOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated automatically by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated automatically by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated automatically by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:7870: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || mkdir "$as_incr_dir" + ;; + esac +done; } + + fi + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +EOF +cat >>$CONFIG_STATUS <<\EOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + + case $ac_dest in + default-1 ) test -z "$CONFIG_HEADERS" || echo timestamp > src/stamp-h ;; + esac +done +EOF + +cat >>$CONFIG_STATUS <<\EOF + +{ (exit 0); exit 0; } +EOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + exec 5>/dev/null + $SHELL $CONFIG_STATUS || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/contrib/ldapc++/configure.in b/contrib/ldapc++/configure.in new file mode 100644 index 0000000000000000000000000000000000000000..a622bf759e620333eb713be7c47c96329a06df89 --- /dev/null +++ b/contrib/ldapc++/configure.in @@ -0,0 +1,94 @@ +dnl Copyright 2000, OpenLDAP Foundation, All Rights Reserved. +dnl COPYING RESTRICTIONS APPLY, see COPYRIGHT file + + +dnl Process this file with autoconf to produce a configure script. + +dnl disable config.cache +dnl define([AC_CACHE_LOAD], ) +dnl define([AC_CACHE_SAVE], ) + +AC_INIT(src/main.cpp) +AM_INIT_AUTOMAKE(main, 0.0.1) +AM_CONFIG_HEADER(src/config.h) + + +dnl Checks for programs. +AC_PROG_INSTALL +dnl AC_PROG_CC +AC_PROG_CXX +dnl AC_PROG_RANLIB +dnl AM_DISABLE_SHARED +AC_PROG_LIBTOOL +dnl AC_PROG_MAKE_SET +AC_ARG_ENABLE(debug,--enable-debug,[ + CXXFLAGS="-g -O0 -Wall" + AC_DEFINE(WITH_DEBUG) + ],[ + CXXFLAGS="-O0" + ] +) + +AC_ARG_WITH(libldap,[ --with-libldap=DIR Path to the libldap library [/usr/local/lib]],[ + LIBS="-L$with_libldap $LIBS " + ],[ + LIBS="-L/usr/local/lib $LIBS " + ] +) + +AC_ARG_WITH(ldap-includes,[ --with-ldap-includes=DIR Path to the libldap include files [/usr/local/include]],[ + CPPFLAGS="-I$with_ldap_includes $CPPFLAGS " + ],[ + CPPFLAGS="-I/usr/local/include $CPPFLAGS " + ] +) +dnl Checks for libraries. +AC_CHECK_LIB(resolv,main) +AC_CHECK_LIB(lber,ber_strdup,[ +dnl NOOP + : + ],[ + echo " didn't find ber_strdup in liblber !"; + echo " Check for the right version (>= 2.0) of the OpenLDAP libraries"; + echo " or try the --with-libldap option."; + exit + ]) +AC_CHECK_LIB(ldap,ldap_add_ext,[ +dnl NOOP + : + ],[ + echo " didn't find ldap_add_ext in libldap !"; + echo " Check for the right version (>= 2.0) of the OpenLDAP libraries"; + echo " or try the --with-libldap option."; + exit + ],[ + -llber + ]) +dnl Checks for header files. +AC_HEADER_TIME +AC_CHECK_HEADER(ldap.h) +AC_EGREP_HEADER(ldap_add_ext,ldap.h,[ +dnl NOOP + : + ],[ + echo " didn't find ldap_add_ext in ldap.h!"; + echo " Check for the right version (>= 2.0) of the OpenLDAP includes"; + echo " or try --with-ldap-includes option."; + exit + ]) +AC_CHECK_HEADER(lber.h) +AC_EGREP_HEADER(ber_strdup,lber.h,[ +dnl NOOP + : + ],[ + echo " didn't find ber_strdup in lber.h!"; + echo " Check for the right version (>= 2.0) of the OpenLDAP includes"; + echo " or try --with-ldap-includes option."; + exit + ]) + +dnl Checks for typedefs, structures, and compiler characteristics. + +dnl Checks for library functions. + +AC_OUTPUT(Makefile src/Makefile) diff --git a/contrib/ldapc++/ltmain.sh b/contrib/ldapc++/ltmain.sh new file mode 100644 index 0000000000000000000000000000000000000000..47f816f2a90322b7a6a9ef02b8eca1fcfd108a45 --- /dev/null +++ b/contrib/ldapc++/ltmain.sh @@ -0,0 +1,4982 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit 0 +fi + +# The name of this program. +progname=`$echo "$0" | sed 's%^.*/%%'` +modename="$progname" + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.4.1 +TIMESTAMP=" (1.922.2.34 2001/09/03 01:22:13)" + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' +SP2NL='tr \040 \012' +NL2SP='tr \015\012 \040\040' + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +# We save the old values to restore during execute mode. +if test "${LC_ALL+set}" = set; then + save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL +fi +if test "${LANG+set}" = set; then + save_LANG="$LANG"; LANG=C; export LANG +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + echo "$modename: not configured to build any kind of library" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + sed -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case $nonopt in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + prev= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + case $prev in + "") ;; + xcompiler) + # Aesthetically quote the previous argument. + prev= + lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + + case $arg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + # Accept any command-line options. + case $arg in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + case $user_target in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $lastarg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case $user_target in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + else + # Don't build PIC code + command="$base_compile $srcfile" + fi + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if (test -z "$pic_flag" || test "$pic_mode" != default) && + test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $srcfile" + else + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n $prev + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + esac + fi + if test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.lo | *.$objext) + # A library or standard object. + if test "$prev" = dlfiles; then + # This file was specified with -dlopen. + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $arg" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + else + case $arg in + *.lo) libobjs="$libobjs $arg" ;; + *) objs="$objs $arg" ;; + esac + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + libs="$libs $deplib" + done + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit 1 + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test $linkmode = prog; then + # Determine which files to process + case $pass in + dlopen) + libs="$dlfiles" + save_deplibs="$deplibs" # Collect dlpreopened libraries + deplibs= + ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -l*) + if test $linkmode = oldlib && test $linkmode = obj; then + $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2 + continue + fi + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + # Search the libtool library + lib="$searchdir/lib${name}.la" + if test -f "$lib"; then + found=yes + break + fi + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test $pass = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test $pass = scan; then + deplibs="$deplib $deplibs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test $pass = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + echo + echo "*** Warning: This library needs some functionality provided by $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + else + echo + echo "*** Warning: Linking the shared library $output against the" + echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test $pass != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test $found = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit 1 + fi + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test $linkmode = oldlib && test $linkmode = obj; }; then + # Add dl[pre]opened files of deplib + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test $pass = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + elif test $linkmode != prog && test $linkmode != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit 1 + fi + continue + fi # $pass = conv + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + + # This library was specified with -dlopen. + if test $pass = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. + dlprefiles="$dlprefiles $lib" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test $pass = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test $linkmode = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" + fi + continue + fi + + if test $linkmode = prog && test $pass != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test $linkalldeplibs = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # Link against this shared library + + if test "$linkmode,$pass" = "prog,link" || + { test $linkmode = lib && test $hardcode_into_libs = yes; }; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + if test $linkmode = prog; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + fi + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`echo $soroot | sed -e 's/^.*\///'` + newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$extract_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$old_archive_from_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n $old_archive_from_expsyms_cmds + + if test $linkmode = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test $linkmode = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test $linkmode = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + add="-l$name" + fi + + if test $linkmode = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test $linkmode = prog; then + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + # Try to link the static library + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + echo "*** Warning: This library needs some functionality provided by $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** Therefore, libtool will create a static module, that should work " + echo "*** as long as the dlopening application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test $linkmode = lib; then + if test -n "$dependency_libs" && + { test $hardcode_into_libs != yes || test $build_old_libs = yes || + test $link_static = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + + if test $link_all_deplibs != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="-L$absdir/$objdir" + else + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="-L$absdir" + fi + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test $pass = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test $pass != dlopen; then + test $pass != scan && dependency_libs="$newdependency_libs" + if test $pass != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + *) + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + if test "$pass" = "conv" && + { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then + libs="$deplibs" # reset libs + deplibs= + fi + done # for pass + if test $linkmode = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit 1 + else + echo + echo "*** Warning: Linking the shared library $output against the non-libtool" + echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case $current in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $revision in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $age in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix) + major=`expr $current - $age + 1` + verstring="sgi$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="sgi$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring="" + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs. + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'` + deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'` + dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test $hardcode_into_libs != yes || test $build_old_libs = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd*) + # Do not include libc due to us having libc/libc_r. + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test $build_libtool_need_lc = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $rm conftest + $CC -o conftest conftest.c $deplibs + if test $? -eq 0 ; then + ldd_output=`ldd conftest` + for i in $deplibs; do + name="`expr $i : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $i." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + newdeplibs="$newdeplibs $i" + fi + done + else + # Error occured in the first compile. Let's try to salvage the situation: + # Compile a seperate program for each library. + for i in $deplibs; do + name="`expr $i : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + $rm conftest + $CC -o conftest conftest.c $i + # Did it work? + if test $? -eq 0 ; then + ldd_output=`ldd conftest` + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $i." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + droppeddeps=yes + echo + echo "*** Warning! Library $i is needed by this library but I was not able to" + echo "*** make it link in! You will probably need to install it or some" + echo "*** library that it depends on before this library will be fully" + echo "*** functional. Installing it before continuing would be even better." + fi + else + newdeplibs="$newdeplibs $i" + fi + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method + file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | sed 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | sed 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + if eval echo \"$potent_lib\" 2>/dev/null \ + | sed 10q \ + | egrep "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test $allow_undefined = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test $hardcode_into_libs = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + test -z "$dlname" && dlname=$soname + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + eval cmds=\"$archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit 0 + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + prog) + case $host in + *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | sed -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test $need_relink = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit 0 + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="cd `pwd`; $relink_command" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case $0 in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|sed 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) exeext=.exe ;; + *) exeext= ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin* | *-*-pw32*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="cd `pwd`; $SHELL $0 --mode=relink $libtool_args" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test $need_relink = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + /usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`echo $destfile | sed -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $0 --finish$current_libdirs' + else + exit 0 + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = ":" && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd='"$cmd"$args' + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + rmdirs= + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$objdir" + else + objdir="$dir/$objdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test $mode = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test $mode = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test $mode = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + + *) + # Do a test to see if this is a libtool program. + if test $mode = clean && + (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$file + + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit 1 +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/contrib/ldapc++/src/LDAPAttribute.h b/contrib/ldapc++/src/LDAPAttribute.h new file mode 100644 index 0000000000000000000000000000000000000000..82972caa0628a52b09dcc979afa17c18bf8b199d --- /dev/null +++ b/contrib/ldapc++/src/LDAPAttribute.h @@ -0,0 +1,180 @@ +/* + * Copyright 2000-2002, OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + + +#ifndef LDAP_ATTRIBUTE_H +#define LDAP_ATTRIBUTE_H + +#include<iostream> +#include<string> +#include<ldap.h> +#include<lber.h> + +#include <StringList.h> + +/** + * Represents the name an value(s) of an Attribute + */ +class LDAPAttribute{ + public : + /** + * Default constructor. + * initializes an empty object. + */ + LDAPAttribute(); + + /** + * Copy constructor. + * Copies all values of an Attribute to a new one + * @param attr The Attribute that should be copied + */ + LDAPAttribute(const LDAPAttribute& attr); + + /** + * Construct an Attribute with a single string value + * @param name The attribute's name (type) + * @param value The string value of the attribute, if "" the + * attribute will have no values, for LDAPv3 + * this values must be UTF-8 encoded + */ + LDAPAttribute(const std::string& name, const std::string& value=""); + + /** + * Construct an attribute with multiple string values + * @param name The attribute's name (type) + * @param values A 0-terminated array of char*. Each char* specifies + * one value of the attribute (UTF-8 encoded) + */ + LDAPAttribute(const char* name, char **values); + + /** + * Construct an attribute with multiple string values + * @param name The attribute's name (type) + * @param values A list of strings. Each element specifies + * one value of the attribute (UTF-8 or binary + * encoded) + */ + LDAPAttribute(const std::string& name, const StringList& values); + + /** + * Construct an attribute with multiple binary coded values + * @param name The attribute's name (type) + * @param values 0-terminated array of binary attribute values + * The BerValue struct is declared as:<BR> + * struct berval{ + * unsigned long bv_len; + * char *bv_val; + * } BerValue; + */ + LDAPAttribute(const char* name, BerValue **values); + + /** + * Destructor + */ + ~LDAPAttribute(); + + /** + * Add a single string value(bin/char) to the Attribute + * @param value Value that should be added, it is copied inside the + * object + */ + void addValue(const std::string& value); + + /** + * Add a single binary value to the Attribute + * @param value The binary coded value that should be added to the + * Attribute. + * @return 0 no problem <BR> + * -1 failure (mem. allocation problem) + */ + int addValue(const BerValue *value); + + /** + * Set the values of the attribute. If the object contains some values + * already, they are deleted + * @param values 0-terminated array of char*, each char* + * representing a string value to add to the entry + * + * @return 0 no problem <BR> + * -1 failure (mem. allocation problem) + */ + int setValues(char** values); + + /** + * Set the values of the attribute. If the object does already contain + * some values, they will be deleted + * @param values 0-terminated array of BerValue*, each BerValue + * representing a binary value to add to the entry + * + * @return 0 no problem <BR> + * -1 failure (mem. allocation problem) + */ + int setValues(BerValue** values); + + /** + * Set the values of the attribute. If the object does already contain + * some values, they will be deleted + * @param values A list of string-Objects. Each string is + * representing a string or binary value to add to + * the entry + */ + void setValues(const StringList& values); + + /** + * For interal use only. + * This method is used to translate the values of the Attribute to + * 0-terminated Array of BerValue-structs as used by the C-API + * @return The Values of the Attribute as an 0-terminated Array of + * BerValue* (is dynamically allocated, delete it after usage) + * <BR> + * 0-pointer in case of error + */ + BerValue** getBerValues() const; + + /** + * @return The values of the array as a list of strings + */ + const StringList& getValues() const; + + /** + * @return The number of values of the attribute + */ + int getNumValues() const; + + /** + * @return The name(type) of the attribute + */ + const std::string& getName() const ; + + /** + * Sets the Attribute's name (type) + * @param the new name of the object + */ + void setName(const std::string& name); + + /** + * For internal use only. + * + * This method translate the attribute of the object into a + * LDAPMod-Structure as used by the C-API + */ + LDAPMod* toLDAPMod() const ; + + /** + * @return true If the attribute contains non-printable attributes + */ + bool isNotPrintable() const ; + + private : + std::string m_name; + StringList m_values; + + /** + * This method can be used to dump the data of a LDAPResult-Object. + * It is only useful for debugging purposes at the moment + */ + friend std::ostream& operator << (std::ostream& s, const LDAPAttribute& attr); +}; +#endif //#ifndef LDAP_ATTRIBUTE_H diff --git a/contrib/ldapc++/src/LDAPAttributeList.cpp b/contrib/ldapc++/src/LDAPAttributeList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d3b467748cc9657229aa0d81e0066dde92cd6cb --- /dev/null +++ b/contrib/ldapc++/src/LDAPAttributeList.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2000-2002, OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + + +#include "debug.h" + +#include "LDAPAttributeList.h" + +#include "LDAPException.h" +#include "LDAPAttribute.h" +#include "LDAPAsynConnection.h" +#include "LDAPMessage.h" + +using namespace std; + +// little helper function for doing case insensitve string comparison +bool nocase_compare(char c1, char c2); + +LDAPAttributeList::LDAPAttributeList(){ + DEBUG(LDAP_DEBUG_CONSTRUCT, + "LDAPAttributeList::LDAPAttributList( )" << endl); +} + +LDAPAttributeList::LDAPAttributeList(const LDAPAttributeList& al){ + DEBUG(LDAP_DEBUG_CONSTRUCT, + "LDAPAttributeList::LDAPAttributList(&)" << endl); + m_attrs=al.m_attrs; +} + +LDAPAttributeList::LDAPAttributeList(const LDAPAsynConnection *ld, + LDAPMessage *msg){ + DEBUG(LDAP_DEBUG_CONSTRUCT, + "LDAPAttributeList::LDAPAttributList()" << endl); + BerElement *ptr=0; + char *name=ldap_first_attribute(ld->getSessionHandle(), msg, &ptr); +/* + This code was making problems if no attribute were returned + How am I supposed to find decoding errors? ldap_first/next_attribute + return 0 in case of error or if there are no more attributes. In either + case they set the LDAP* error code to 0x54 (Decoding error) ??? Strange.. + + There will be some changes in the new version of the C-API so that this + code should work in the future. + if(name == 0){ + ber_free(ptr,0); + ldap_memfree(name); + throw LDAPException(ld); + }else{ +*/ BerValue **values; + for (;name !=0; + name=ldap_next_attribute(ld->getSessionHandle(),msg,ptr) ){ + values=ldap_get_values_len(ld->getSessionHandle(), + msg, name); + this->addAttribute(LDAPAttribute(name, values)); + ldap_memfree(name); + ldap_value_free_len(values); + } + ber_free(ptr,0); +// } +} + +LDAPAttributeList::~LDAPAttributeList(){ + DEBUG(LDAP_DEBUG_DESTROY,"LDAPAttributeList::~LDAPAttributList()" << endl); +} + +size_t LDAPAttributeList::size() const{ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::size()" << endl); + return m_attrs.size(); +} + +bool LDAPAttributeList::empty() const{ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::empty()" << endl); + return m_attrs.empty(); +} + +LDAPAttributeList::const_iterator LDAPAttributeList::begin() const{ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::begin()" << endl); + return m_attrs.begin(); +} + +LDAPAttributeList::const_iterator LDAPAttributeList::end() const{ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::end()" << endl); + return m_attrs.end(); +} + +const LDAPAttribute* LDAPAttributeList::getAttributeByName( + const string& name) const { + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::getAttributeByName()" << endl); + DEBUG(LDAP_DEBUG_TRACE | LDAP_DEBUG_PARAMETER, + " name:" << name << endl); + AttrList::const_iterator i; + for( i = m_attrs.begin(); i != m_attrs.end(); i++){ + const std::string& tmpType = i->getName(); + if(name.size() == tmpType.size()){ + if(equal(name.begin(), name.end(), tmpType.begin(), + nocase_compare)){ + return &(*i); + DEBUG(LDAP_DEBUG_TRACE," found:" << name << endl); + } + } + } + return 0; +} + +void LDAPAttributeList::addAttribute(const LDAPAttribute& attr){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::addAttribute()" << endl); + DEBUG(LDAP_DEBUG_TRACE | LDAP_DEBUG_PARAMETER, + " attr:" << attr << endl); + const std::string attrType = attr.getName(); + const std::string::size_type attrLen = attrType.size(); + std::string::size_type tmpAttrLen = 0; + bool done=false; + AttrList::iterator i; + for( i=m_attrs.begin(); i != m_attrs.end(); i++ ){ + const std::string tmpAttrType = i->getName(); + tmpAttrLen = tmpAttrType.size(); + if(tmpAttrLen == attrLen){ + if(equal(tmpAttrType.begin(), tmpAttrType.end(), attrType.begin(), + nocase_compare)){ + const StringList& values = attr.getValues(); + StringList::const_iterator j; + for(j = values.begin(); j != values.end(); j++){ + i->addValue(*j); + } + DEBUG(LDAP_DEBUG_TRACE,"Attribute" << i->getName() + << "already present" << endl); + done=true; + break; // The AttributeType was already present, + // we are done here + } + } + } + if(! done){ + m_attrs.push_back(attr); + } +} + + +LDAPMod** LDAPAttributeList::toLDAPModArray() const{ + DEBUG(LDAP_DEBUG_TRACE,"LDAPAttribute::toLDAPModArray()" << endl); + LDAPMod **ret = (LDAPMod**) malloc((m_attrs.size()+1) * sizeof(LDAPMod*)); + AttrList::const_iterator i; + int j=0; + for (i=m_attrs.begin(); i!= m_attrs.end(); i++, j++){ + ret[j]=i->toLDAPMod(); + } + ret[m_attrs.size()]=0; + return ret; +} + +ostream& operator << (ostream& s, const LDAPAttributeList& al){ + AttrList::const_iterator i; + for(i=al.m_attrs.begin(); i!=al.m_attrs.end(); i++){ + s << *i << "; "; + } + return s; +} + +bool nocase_compare( char c1, char c2){ + return toupper(c1) == toupper(c2); +} + diff --git a/contrib/ldapc++/src/LDAPAttributeList.h b/contrib/ldapc++/src/LDAPAttributeList.h new file mode 100644 index 0000000000000000000000000000000000000000..990a6d8c850931e05e473a5f90472040a139afc8 --- /dev/null +++ b/contrib/ldapc++/src/LDAPAttributeList.h @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2002, OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + + +#ifndef LDAP_ATTRIBUTE_LIST_H +#define LDAP_ATTRIBUTE_LIST_H + +#include <ldap.h> +#include <list> +#include <string> + +class LDAPAttribute; +class LDAPAsynConnection; +class LDAPMsg; + +typedef std::list<LDAPAttribute> AttrList; + +/** + * This container class is used to store multiple LDAPAttribute-objects. + */ +class LDAPAttributeList{ + private : + AttrList m_attrs; + + public : + typedef AttrList::const_iterator const_iterator; + typedef AttrList::iterator iterator; + + + /** + * Copy-constructor + */ + LDAPAttributeList(const LDAPAttributeList& al); + + /** + * For internal use only + * + * This constructor is used by the library internally to create a + * list of attributes from a LDAPMessage-struct that was return by + * the C-API + */ + LDAPAttributeList(const LDAPAsynConnection *ld, LDAPMessage *msg); + + /** + * Constructs an empty list. + */ + LDAPAttributeList(); + + /** + * Destructor + */ + virtual ~LDAPAttributeList(); + + /** + * @return The number of LDAPAttribute-objects that are currently + * stored in this list. + */ + size_t size() const; + + /** + * @return true if there are zero LDAPAttribute-objects currently + * stored in this list. + */ + bool empty() const; + + /** + * @return A iterator that points to the first element of the list. + */ + const_iterator begin() const; + + /** + * @return A iterator that points to the element after the last + * element of the list. + */ + const_iterator end() const; + + /** + * Get an Attribute by its AttributeType + * @param name The name of the Attribute to look for + * @return a pointer to the LDAPAttribute with the AttributeType + * "name" or 0, if there is no Attribute of that Type + */ + const LDAPAttribute* getAttributeByName(const std::string& name) const; + + + /** + * Adds one element to the end of the list. + * @param attr The attribute to add to the list. + */ + void addAttribute(const LDAPAttribute& attr); + + /** + * Translates the list of Attributes to a 0-terminated array of + * LDAPMod-structures as needed by the C-API + */ + LDAPMod** toLDAPModArray() const; + + /** + * This method can be used to dump the data of a LDAPResult-Object. + * It is only useful for debugging purposes at the moment + */ + friend std::ostream& operator << (std::ostream& s, + const LDAPAttributeList& al); +}; + +#endif // LDAP_ATTRIBUTE_LIST_H + diff --git a/contrib/ldapc++/src/LDAPBindRequest.cpp b/contrib/ldapc++/src/LDAPBindRequest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eae3983b318f9ca250f387d499f5e332a6f81237 --- /dev/null +++ b/contrib/ldapc++/src/LDAPBindRequest.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2000, OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include <ldap.h> + +#include "debug.h" + +#include "LDAPBindRequest.h" +#include "LDAPException.h" + +using namespace std; + +LDAPBindRequest::LDAPBindRequest(const LDAPBindRequest& req) : + LDAPRequest(req){ + DEBUG(LDAP_DEBUG_CONSTRUCT, "LDAPBindRequest::LDAPBindRequest(&)" << endl); + m_dn=req.m_dn; + m_cred=req.m_cred; + m_mech=req.m_mech; +} + +LDAPBindRequest::LDAPBindRequest(const string& dn,const string& passwd, + LDAPAsynConnection *connect, const LDAPConstraints *cons, + bool isReferral) : LDAPRequest(connect, cons, isReferral){ + DEBUG(LDAP_DEBUG_CONSTRUCT,"LDAPBindRequest::LDAPBindRequest()" << endl); + DEBUG(LDAP_DEBUG_CONSTRUCT | LDAP_DEBUG_PARAMETER, " dn:" << dn << endl + << " passwd:" << passwd << endl); + m_dn = dn; + m_cred = passwd; + m_mech = ""; +} + +LDAPBindRequest::~LDAPBindRequest(){ + DEBUG(LDAP_DEBUG_DESTROY,"LDAPBindRequest::~LDAPBindRequest()" << endl); +} + +LDAPMessageQueue* LDAPBindRequest::sendRequest(){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPBindRequest::sendRequest()" << endl); + int msgID=0; + + const char* mech = (m_mech == "" ? 0 : m_mech.c_str()); + BerValue* tmpcred=0; + if(m_cred != ""){ + char* tmppwd = (char*) malloc( (m_cred.size()+1) * sizeof(char)); + m_cred.copy(tmppwd,string::npos); + tmppwd[m_cred.size()]=0; + tmpcred=ber_bvstr(tmppwd); + }else{ + tmpcred=(BerValue*) malloc(sizeof(BerValue)); + tmpcred->bv_len=0; + tmpcred->bv_val=0; + } + const char* dn = 0; + if(m_dn != ""){ + dn = m_dn.c_str(); + } + LDAPControl** tmpSrvCtrls=m_cons->getSrvCtrlsArray(); + LDAPControl** tmpClCtrls=m_cons->getClCtrlsArray(); + int err=ldap_sasl_bind(m_connection->getSessionHandle(),dn, + mech, tmpcred, tmpSrvCtrls, tmpClCtrls, &msgID); + LDAPControlSet::freeLDAPControlArray(tmpSrvCtrls); + LDAPControlSet::freeLDAPControlArray(tmpClCtrls); + ber_bvfree(tmpcred); + + if(err != LDAP_SUCCESS){ + throw LDAPException(err); + }else{ + m_msgID=msgID; + return new LDAPMessageQueue(this); + } +} + +LDAPRequest* LDAPBindRequest::followReferral(LDAPMsg* /*urls*/){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPBindRequest::followReferral()" << endl); + DEBUG(LDAP_DEBUG_TRACE, + "ReferralChasing for bind-operation not implemented yet" << endl); + return 0; +} + diff --git a/contrib/ldapc++/src/LDAPConnection.cpp b/contrib/ldapc++/src/LDAPConnection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71165ea8529232f0a8619952cd2db75bfb226511 --- /dev/null +++ b/contrib/ldapc++/src/LDAPConnection.cpp @@ -0,0 +1,359 @@ +/* + * Copyright 2000, OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "debug.h" + +#include "LDAPResult.h" +#include "LDAPException.h" +#include "LDAPReferralException.h" +#include "LDAPUrlList.h" + +#include "LDAPConnection.h" +const int LDAPConnection::SEARCH_BASE = LDAPAsynConnection::SEARCH_BASE; +const int LDAPConnection::SEARCH_ONE = LDAPAsynConnection::SEARCH_ONE; +const int LDAPConnection::SEARCH_SUB = LDAPAsynConnection::SEARCH_SUB; + +using namespace std; + +LDAPConnection::LDAPConnection(const string& hostname, int port, + LDAPConstraints* cons) : + LDAPAsynConnection(hostname, port, cons){ +} + +LDAPConnection::~LDAPConnection(){ +} + +int LDAPConnection::start_tls(){ + return LDAPAsynConnection::start_tls(); +} + +void LDAPConnection::bind(const string& dn, const string& passwd, + LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::bind" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::bind(dn,passwd,cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + if(resCode != LDAPResult::SUCCESS) { + if(resCode == LDAPResult::REFERRAL){ + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + }else{ + delete res; + delete msg; + throw LDAPException(resCode); + } + } + delete res; + delete msg; // memcheck +} + +void LDAPConnection::unbind(){ + LDAPAsynConnection::unbind(); +} + +bool LDAPConnection::compare(const string& dn, const LDAPAttribute& attr, + LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::compare" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::compare(dn,attr,cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::COMPARE_TRUE : + delete res; + delete msg; + return true; + break; + case LDAPResult::COMPARE_FALSE : + delete res; + delete msg; + return false; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } +} + +void LDAPConnection::del(const string& dn, const LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::del" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::del(dn,cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete res; + delete msg; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } + +} + +void LDAPConnection::add(const LDAPEntry* le, const LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::add" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::add(le,cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete res; + delete msg; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } +} + +void LDAPConnection::modify(const string& dn, const LDAPModList* mods, + const LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::modify" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::modify(dn,mods,cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete res; + delete msg; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } + +} + +void LDAPConnection::rename(const string& dn, const string& newRDN, + bool delOldRDN, const string& newParentDN, + const LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::rename" << endl); + LDAPMessageQueue* msg=0; + LDAPResult* res=0; + try{ + msg = LDAPAsynConnection::rename(dn,newRDN,delOldRDN, newParentDN, + cons); + res = (LDAPResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete res; + delete msg; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } +} + +LDAPSearchResults* LDAPConnection::search(const string& base, int scope, + const string& filter, const StringList& attrs, bool attrsOnly, + const LDAPConstraints* cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::search" << endl); + LDAPMessageQueue* msgq=0; + LDAPResult* res=0; + LDAPSearchResults* results= 0; + + try{ + results = new LDAPSearchResults(); + msgq = LDAPAsynConnection::search(base,scope, filter, attrs, attrsOnly, + cons); + res = results->readMessageQueue(msgq); + }catch(LDAPException e){ + delete results; // memcheck + delete msgq; + throw; + } + if(res != 0){ + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete res; + delete msgq; + return results; + break; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete results; // memcheck + delete res; + delete msgq; + throw LDAPReferralException(urls); + } + break; + default : + delete results; // memcheck + delete res; + delete msgq; + throw LDAPException(resCode); + } + } + return 0; +} + +LDAPExtResult* LDAPConnection::extOperation(const string& oid, + const string& value, const LDAPConstraints *cons){ + DEBUG(LDAP_DEBUG_TRACE,"LDAPConnection::extOperation" << endl); + LDAPMessageQueue* msg=0; + LDAPExtResult* res=0; + try{ + msg = LDAPAsynConnection::extOperation(oid,value,cons); + res = (LDAPExtResult*)msg->getNext(); + }catch(LDAPException e){ + delete msg; + delete res; + throw; + } + int resCode=res->getResultCode(); + switch (resCode){ + case LDAPResult::SUCCESS : + delete msg; + return res; + case LDAPResult::REFERRAL : + { + LDAPUrlList urls = res->getReferralUrls(); + delete res; + delete msg; + throw LDAPReferralException(urls); + } + break; + default : + delete res; + delete msg; + throw LDAPException(resCode); + } +} + +const string& LDAPConnection::getHost() const{ + return LDAPAsynConnection::getHost(); +} + +int LDAPConnection::getPort() const{ + return LDAPAsynConnection::getPort(); +} + +void LDAPConnection::setConstraints(LDAPConstraints* cons){ + LDAPAsynConnection::setConstraints(cons); +} + +const LDAPConstraints* LDAPConnection::getConstraints() const{ + return LDAPAsynConnection::getConstraints(); +} + +int LDAPConnection::enableCache(long timeout, long maxmem) { + return LDAPAsynConnection::enableCache(timeout, maxmem); +} + + +void LDAPConnection::disableCache() { + LDAPAsynConnection::disableCache(); +} + +bool LDAPConnection::getCacheEnabled() { + return LDAPAsynConnection::getCacheEnabled(); +} + +void LDAPConnection::uncache_entry(string &dn) { + LDAPAsynConnection::uncache_entry(dn); +} + +void LDAPConnection::flush_cache() +{ + LDAPAsynConnection::flush_cache(); +} + diff --git a/contrib/ldapc++/src/LDAPUrlList.cpp b/contrib/ldapc++/src/LDAPUrlList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..037349a382ffc88fcb87dca3080317a476285d65 --- /dev/null +++ b/contrib/ldapc++/src/LDAPUrlList.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2002 OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "LDAPUrlList.h" +#include <assert.h> +#include "debug.h" + +using namespace std; + +LDAPUrlList::LDAPUrlList(){ + DEBUG(LDAP_DEBUG_CONSTRUCT," LDAPUrlList::LDAPUrlList()" << endl); + m_urls=UrlList(); +} + +LDAPUrlList::LDAPUrlList(const LDAPUrlList& urls){ + DEBUG(LDAP_DEBUG_CONSTRUCT," LDAPUrlList::LDAPUrlList(&)" << endl); + m_urls = urls.m_urls; +} + + +LDAPUrlList::LDAPUrlList(char** url){ + DEBUG(LDAP_DEBUG_CONSTRUCT," LDAPUrlList::LDAPUrlList()" << endl); + char** i; + assert(url); + for(i = url; *i != 0; i++){ + add(LDAPUrl(*i)); + } +} + +LDAPUrlList::~LDAPUrlList(){ + DEBUG(LDAP_DEBUG_DESTROY," LDAPUrlList::~LDAPUrlList()" << endl); + m_urls.clear(); +} + +size_t LDAPUrlList::size() const{ + return m_urls.size(); +} + +bool LDAPUrlList::empty() const{ + return m_urls.empty(); +} + +LDAPUrlList::const_iterator LDAPUrlList::begin() const{ + return m_urls.begin(); +} + +LDAPUrlList::const_iterator LDAPUrlList::end() const{ + return m_urls.end(); +} + +void LDAPUrlList::add(const LDAPUrl& url){ + m_urls.push_back(url); +} + diff --git a/contrib/ldapc++/src/Makefile.in b/contrib/ldapc++/src/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..98b5e1aaa1a4993e44cd4dd550a465a65db06d03 --- /dev/null +++ b/contrib/ldapc++/src/Makefile.in @@ -0,0 +1,488 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Copyright 2000, OpenLDAP Foundation, All Rights Reserved. +# COPYING RESTRICTIONS APPLY, see COPYRIGHT file + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +CC = @CC@ +CXX = @CXX@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +EXEEXT = @EXEEXT@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ + +lib_LTLIBRARIES = libldapcpp.la + +libldapcpp_la_SOURCES = LDAPAddRequest.cpp LDAPAsynConnection.cpp LDAPAttribute.cpp LDAPAttributeList.cpp LDAPBindRequest.cpp LDAPCompareRequest.cpp LDAPConnection.cpp LDAPConstraints.cpp LDAPControl.cpp LDAPControlSet.cpp LDAPDeleteRequest.cpp LDAPEntry.cpp LDAPEntryList.cpp LDAPException.cpp LDAPExtRequest.cpp LDAPExtResult.cpp LDAPMessage.cpp LDAPMessageQueue.cpp LDAPModDNRequest.cpp LDAPModification.cpp LDAPModifyRequest.cpp LDAPModList.cpp LDAPRebind.cpp LDAPRebindAuth.cpp LDAPReferralException.cpp LDAPReferenceList.cpp LDAPRequest.cpp LDAPResult.cpp LDAPSearchReference.cpp LDAPSearchRequest.cpp LDAPSearchResult.cpp LDAPSearchResults.cpp LDAPUrl.cpp LDAPUrlList.cpp StringList.cpp + + +include_HEADERS = LDAPAsynConnection.h LDAPAttribute.h LDAPAttributeList.h LDAPConnection.h LDAPConstraints.h LDAPControl.h LDAPControlSet.h LDAPEntry.h LDAPEntryList.h LDAPException.h LDAPExtResult.h LDAPMessage.h LDAPMessageQueue.h LDAPModification.h LDAPModList.h LDAPRebind.h LDAPRebindAuth.h LDAPReferralException.h LDAPReferenceList.h LDAPResult.h LDAPSearchReference.h LDAPSearchResult.h LDAPSearchResults.h LDAPUrl.h LDAPUrlList.h StringList.h + + +noinst_HEADERS = LDAPAddRequest.h LDAPBindRequest.h LDAPCompareRequest.h LDAPDeleteRequest.h LDAPExtRequest.h LDAPModDNRequest.h LDAPModifyRequest.h LDAPRequest.h LDAPSearchRequest.h + + +libldapcpp_la_LIBADD = -lldap -llber +libldapcpp_la_LDFLAGS = -version-info 0:1:0 + +noinst_PROGRAMS = main + +main_SOURCES = main.cpp +main_LDADD = ./libldapcpp.la +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libldapcpp_la_DEPENDENCIES = +libldapcpp_la_OBJECTS = LDAPAddRequest.lo LDAPAsynConnection.lo \ +LDAPAttribute.lo LDAPAttributeList.lo LDAPBindRequest.lo \ +LDAPCompareRequest.lo LDAPConnection.lo LDAPConstraints.lo \ +LDAPControl.lo LDAPControlSet.lo LDAPDeleteRequest.lo LDAPEntry.lo \ +LDAPEntryList.lo LDAPException.lo LDAPExtRequest.lo LDAPExtResult.lo \ +LDAPMessage.lo LDAPMessageQueue.lo LDAPModDNRequest.lo \ +LDAPModification.lo LDAPModifyRequest.lo LDAPModList.lo LDAPRebind.lo \ +LDAPRebindAuth.lo LDAPReferralException.lo LDAPReferenceList.lo \ +LDAPRequest.lo LDAPResult.lo LDAPSearchReference.lo \ +LDAPSearchRequest.lo LDAPSearchResult.lo LDAPSearchResults.lo \ +LDAPUrl.lo LDAPUrlList.lo StringList.lo +noinst_PROGRAMS = main$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) + +main_OBJECTS = main.$(OBJEXT) +main_DEPENDENCIES = ./libldapcpp.la +main_LDFLAGS = +CXXFLAGS = @CXXFLAGS@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(include_HEADERS) $(noinst_HEADERS) + +DIST_COMMON = ./stamp-h.in Makefile.am Makefile.in config.h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +DEP_FILES = .deps/LDAPAddRequest.P .deps/LDAPAsynConnection.P \ +.deps/LDAPAttribute.P .deps/LDAPAttributeList.P .deps/LDAPBindRequest.P \ +.deps/LDAPCompareRequest.P .deps/LDAPConnection.P \ +.deps/LDAPConstraints.P .deps/LDAPControl.P .deps/LDAPControlSet.P \ +.deps/LDAPDeleteRequest.P .deps/LDAPEntry.P .deps/LDAPEntryList.P \ +.deps/LDAPException.P .deps/LDAPExtRequest.P .deps/LDAPExtResult.P \ +.deps/LDAPMessage.P .deps/LDAPMessageQueue.P .deps/LDAPModDNRequest.P \ +.deps/LDAPModList.P .deps/LDAPModification.P .deps/LDAPModifyRequest.P \ +.deps/LDAPRebind.P .deps/LDAPRebindAuth.P .deps/LDAPReferenceList.P \ +.deps/LDAPReferralException.P .deps/LDAPRequest.P .deps/LDAPResult.P \ +.deps/LDAPSearchReference.P .deps/LDAPSearchRequest.P \ +.deps/LDAPSearchResult.P .deps/LDAPSearchResults.P .deps/LDAPUrl.P \ +.deps/LDAPUrlList.P .deps/StringList.P .deps/main.P +SOURCES = $(libldapcpp_la_SOURCES) $(main_SOURCES) +OBJECTS = $(libldapcpp_la_OBJECTS) $(main_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .cpp .lo .o .obj .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=src/config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libldapcpp.la: $(libldapcpp_la_OBJECTS) $(libldapcpp_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libldapcpp_la_LDFLAGS) $(libldapcpp_la_OBJECTS) $(libldapcpp_la_LIBADD) $(LIBS) + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +main$(EXEEXT): $(main_OBJECTS) $(main_DEPENDENCIES) + @rm -f main$(EXEEXT) + $(CXXLINK) $(main_LDFLAGS) $(main_OBJECTS) $(main_LDADD) $(LIBS) +.cpp.o: + $(CXXCOMPILE) -c $< +.cpp.obj: + $(CXXCOMPILE) -c `cygpath -w $<` +.cpp.lo: + $(LTCXXCOMPILE) -c $< + +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir) + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(include_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(includedir)/$$p; \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign src/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp + +%.o: %.cpp + @echo '$(CXXCOMPILE) -c $<'; \ + $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.cpp + @echo '$(LTCXXCOMPILE) -c $<'; \ + $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: install-libLTLIBRARIES +install-exec: install-exec-am + +install-data-am: install-includeHEADERS +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-libLTLIBRARIES uninstall-includeHEADERS +uninstall: uninstall-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) config.h +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-libLTLIBRARIES \ + mostlyclean-compile mostlyclean-libtool \ + mostlyclean-noinstPROGRAMS mostlyclean-tags \ + mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-hdr clean-libLTLIBRARIES clean-compile clean-libtool \ + clean-noinstPROGRAMS clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-hdr distclean-libLTLIBRARIES distclean-compile \ + distclean-libtool distclean-noinstPROGRAMS \ + distclean-tags distclean-depend distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-hdr \ + maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-noinstPROGRAMS maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool mostlyclean-noinstPROGRAMS \ +distclean-noinstPROGRAMS clean-noinstPROGRAMS \ +maintainer-clean-noinstPROGRAMS uninstall-includeHEADERS \ +install-includeHEADERS tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir mostlyclean-depend distclean-depend \ +clean-depend maintainer-clean-depend info-am info dvi-am dvi check \ +check-am installcheck-am installcheck all-recursive-am install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ldapc++/src/config.h.in b/contrib/ldapc++/src/config.h.in new file mode 100644 index 0000000000000000000000000000000000000000..d2c1714044d6b452ac49d9d5fcb8dada053b18a7 --- /dev/null +++ b/contrib/ldapc++/src/config.h.in @@ -0,0 +1,18 @@ +/* src/config.h.in. Generated automatically from configure.in by autoheader. */ +#undef WITH_DEBUG + + +/* Define if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Name of package */ +#undef PACKAGE + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION diff --git a/doc/devel/todo b/doc/devel/todo new file mode 100644 index 0000000000000000000000000000000000000000..a051b7b0ae081d3a3ebccbb3903370d2c0b7da56 --- /dev/null +++ b/doc/devel/todo @@ -0,0 +1,68 @@ +OpenLDAP To Do List +------------------- + +This is a list of projects that need getting done. They are defined +by scale of the effort as opposed to priority. Contribute to +projects based upon your personal priorities. + +If you would like to work on any of these projects, please coordinate +by posting to OpenLDAP-devel mailing list: + http://www.OpenLDAP.org/lists + +If you have a project you'd like added to the list, talk it up on +Developer's list or just do it. + +Please read: + http://www.OpenLDAP.org/devel/programming.html + http://www.OpenLDAP.org/devel/contributing.html + + +OpenLDAP 2.x Projects +--------------------- + SLAPD + Complete Unicode Support (ACLs, etc.) + client API update + Implement per referral/continuation callback + clients + Implement referral chasing options w/ referral callback + Update manual pages + + +Large projects +-------------- +Redesign slapd memory allocation fault handling +Perform a security audit (and fix any hole found) + + +Medium projects +--------------- +Implement LDAP Transactions +Implement authPassword (RFC 3112) +Implement localization +Implement Proxy Authorization Group extension +Implement LCUP +Add LDIFv1 control support +Update to latest autoconf and friends + + +Small projects +-------------- +Populate matchingRuleUse attribute in the subschema +Implement -E/-e extensions options +Implement -V version options +Implement Proxy Authorization Control extension +Complete Simple Paged Results Control +Add No-Op Control support to ldap client tools +Add tests to test suite (ACI, moddn, manageDSAit, etc.) +Add support for Cyrus pwcheckd/saslauthd +Create ldapbind (from ldapcompare?) to support bind operations +Convert utfconv.txt into man page(s). +Update any manual page + + +For additional TODO items, see: + http://www.openldap.org/its/index.cgi/Software%20Enhancements + + +--- +$OpenLDAP$ diff --git a/doc/man/man3/ldap_url.3 b/doc/man/man3/ldap_url.3 index 7e04bcc3370026dd2121cad9d234aae011f2b2cf..60e07c0362c14f8b1f28805ca17d0205a24f7ac5 100644 --- a/doc/man/man3/ldap_url.3 +++ b/doc/man/man3/ldap_url.3 @@ -1,86 +1,62 @@ -.TH LDAP_URL 3 "28 March 1996" "U-M LDAP LDVERSION" +.TH LDAP_URL 3 "23 July 2001" "OpenLDAP LDVERSION" +.\" $OpenLDAP$ +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME ldap_is_ldap_url, ldap_url_parse, -ldap_free_urldesc, -ldap_url_search, -ldap_url_search_s, -ldap_url_search_st \- LDAP Uniform Resource Locator routines +ldap_free_urldesc \- LDAP Uniform Resource Locator routines .SH SYNOPSIS .nf .ft B -#include <lber.h> #include <ldap.h> .ft .LP .ft B -int ldap_is_ldap_url( url ) -.ft -char *url; +int ldap_is_ldap_url( const char *url ) .LP .ft B -int ldap_url_parse( url, ludpp ) -.ft -char *url; -LDAPURLDesc **ludpp; +int ldap_url_parse( const char *url, LDAPURLDesc **ludpp ) .LP typedef struct ldap_url_desc { - char *lud_host; /* LDAP host to contact */ - int lud_port; /* port on host */ - char *lud_dn; /* base for search */ - char **lud_attrs; /* NULL-terminate list of attributes */ - int lud_scope; /* a valid LDAP_SCOPE_... value */ - char *lud_filter; /* LDAP search filter */ - char *lud_string; /* for internal use only */ + char * lud_scheme; /* URI scheme */ + char lud_host; /* LDAP host to contact */ + int lud_port; /* port on host */ + char * lud_dn; /* base for search */ + char ** lud_attrs; /* list of attributes */ + int lud_scope; /* a LDAP_SCOPE_... value */ + char * lud_filter; /* LDAP search filter */ + char ** lud_exts; /* LDAP extensions */ + int lud_crit_exts; /* true if any extension is critical */ + /* may contain additional fields for internal use */ } LDAPURLDesc; .LP .ft B -ldap_free_urldesc( ludp ) -.ft -LDAPURLDesc *ludp; -.LP -.ft B -int ldap_url_search( ld, url, attrsonly ) -.ft -LDAP *ld; -char *url; -int attrsonly; -.LP -.ft B -int ldap_url_search_s( ld, url, attrsonly, res ) -.ft -LDAP *ld; -char *url; -int attrsonly; -LDAPMessage **res; -.LP -.ft B -int ldap_url_search_st( ld, url, attrsonly, timeout, res ) -.ft -LDAP *ld; -char *url; -int attrsonly; -struct timeval *timeout; -LDAPMessage **res; +ldap_free_urldesc( LDAPURLDesc *ludp ) .SH DESCRIPTION -These routines support the use of LDAP URLs (Uniform Resource Locators). -LDAP URLs look like this: +These routines support the use of LDAP URLs (Uniform Resource Locators) +as detailed in RFC 2255. LDAP URLs look like this: .nf - \fBldap://\fP\fIhostport\fP\fB/\fP\fIdn\fP[\fB?\fP\fIattributes\fP[\fB?\fP\fIscope\fP[\fB?\fP\fIfilter\fP]]] + \fBldap://\fP\fIhostport\fP\fB/\fP\fIdn\fP[\fB?\fP\fIattrs\fP[\fB?\fP\fIscope\fP[\fB?\fP\fIfilter\fP[\fB?\fP\fIexts\fP]]]] where: \fIhostport\fP is a host name with an optional ":portnumber" - \fIdn\f is the base DN to be used for an LDAP search operation - \fIattributes\fP is a comma separated list of attributes to be retrieved - \fIscope\fP is one of these three strings: base one sub (default=base) - \fIfilter\f is LDAP search filter as used in a call to ldap_search(3) + \fIdn\fP is the search base + \fIattrs\fP is a comma separated list of attributes to request + \fIscope\fP is one of these three strings: + base one sub (default=base) + \fIfilter\fP is filter + \fIexts\fP are recognized set of LDAP and/or API extensions. + +Example: + ldap://ldap.example.net/dc=example,dc=net?cn,sn?sub?(cn=*) -e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich .fi .LP URLs that are wrapped in angle-brackets and/or preceded by "URL:" are also -tolerated. +tolerated. Alternative schemes such as ldaps:// and ldapi:// may be +parsed using the below routines as well. .LP .B ldap_is_ldap_url() returns a non-zero value if \fIurl\fP looks like an LDAP URL (as @@ -93,44 +69,19 @@ routine should be used if a more thorough check is needed. breaks down an LDAP URL passed in \fIurl\fP into its component pieces. If successful, zero is returned, an LDAP URL description is allocated, filled in, and \fIludpp\fP is set to point to it. If an -error occurs, one of these values is returned: -.nf - - LDAP_URL_ERR_NOTLDAP - URL doesn't begin with "ldap://" - LDAP_URL_ERR_NODN - URL has no DN (required) - LDAP_URL_ERR_BADSCOPE - URL scope string is invalid - LDAP_URL_ERR_MEM - can't allocate memory space -.fi +error occurs, a non-zero URL error code is returned. .LP .B ldap_free_urldesc() should be called to free an LDAP URL description that was obtained from a call to .B ldap_url_parse(). -.LP -.B ldap_url_search() -initiates an asynchronous LDAP search based on the contents of the -\fIurl\fP string. This routine acts just like -.BR ldap_search (3) -except that many search parameters are pulled out of the URL. -.LP -.B ldap_url_search_s() -performs a synchronous LDAP search based on the contents of the -\fIurl\fP string. This routine acts just like -.BR ldap_search_s (3) -except that many search parameters are pulled out of the URL. -.LP -.B ldap_url_search_st() -performs a synchronous LDAP URL search with a specified \fItimeout\fP. -This routine acts just like -.BR ldap_search_st (3) -except that many search parameters are pulled out of the URL. .SH SEE ALSO -.BR ldap (3), -.BR ldap_search (3) +.BR ldap (3) .LP -.B An LDAP URL Format, -Tim Howes and Mark Smith, December 1995. Internet Draft (work in progress). -Currently available at this URL: -.nf -ftp://ds.internic.net/internet-drafts/draft-ietf-asid-ldap-format-03.txt -.fi +.B The LDAP URL Format, RFC 2255, +Tim Howes and Mark Smith, December 1997. +.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/man3/ldap_url.3.links b/doc/man/man3/ldap_url.3.links index 7ea85a4cd846f383d85a1108501b80a84640ca12..90fe023f46767d5c26f7907589dccb0842516c45 100644 --- a/doc/man/man3/ldap_url.3.links +++ b/doc/man/man3/ldap_url.3.links @@ -1,6 +1,3 @@ ldap_is_ldap_url.3 ldap_url_parse.3 ldap_free_urldesc.3 -ldap_url_search.3 -ldap_url_search_s.3 -ldap_url_search_st.3 diff --git a/doc/man/man5/slapd.access.5 b/doc/man/man5/slapd.access.5 new file mode 100644 index 0000000000000000000000000000000000000000..1e2f3964891a6014cf86644f646350790f2c9b63 --- /dev/null +++ b/doc/man/man5/slapd.access.5 @@ -0,0 +1,424 @@ +.TH SLAPD.ACCESS 5 "28 Oct 2001" "OpenLDAP LDVERSION" +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +slapd.access \- access configuration for slapd, the stand-alone LDAP daemon +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.BR slapd.conf (5) +file contains configuration information for the +.BR slapd (8) +daemon. This configuration file is also used by the +.BR slurpd (8) +replication daemon and by the SLAPD tools +.BR slapadd (8), +.BR slapcat (8), +and +.BR slapindex (8). +.LP +The +.B slapd.conf +file consists of a series of global configuration options that apply to +.B slapd +as a whole (including all backends), followed by zero or more database +backend definitions that contain information specific to a backend +instance. +.LP +The general format of +.B slapd.conf +is as follows: +.LP +.nf + # comment - these options apply to every database + <global configuration options> + # first database definition & configuration options + database <backend 1 type> + <configuration options specific to backend 1> + # subsequent database definitions & configuration options + ... +.fi +.LP +Both the global configuration and each backend-specific section can contain +access information. +Backend-specific access control directives are used for those entries +that belong to the backend, according to their naming context. +In case no access control directives are defined for a backend, +the appropriate directives from the global configuration section +are used. +.LP +Arguments that should be replaced by actual text are shown in brackets <>. +The structure of the access control directives is +.TP +.B access to <what> [ by <who> <access> [ <control> ] ]+ +Grant access (specified by +.BR <access> ) +to a set of entries and/or attributes (specified by +.BR <what> ) +by one or more requestors (specified by +.BR <who> ). +.LP +The field +.BR <what> +specifies the entity the access control directive applies to. +It can have the forms +.LP +.nf + * + [dn[.<dnstyle>]=<pattern>] + [filter=<ldapfilter>] + [attrs=<attrlist>] +.fi +.LP +The wildcard +.B * +stands for all the entries. +.LP +The statement +.B dn=<pattern> +selects the entries based on their naming context. +The optional style qualificator +.B <dnstyle> +can be +.BR regex , +which implies a regular expression pattern, as detailed in +.BR regex (7), +will be used (the default), +.B base +or +.B exact +(an alias of +.BR base ) +for an exact match of the entry, +.B one +to indicate all the entries immediately below the +.BR pattern , +.B sub +to indicate all the subentries of an entry including the entry itself, +.B children +to indicate all the subentries of an entry not including the entry itself. +Note that +.B dn=".*" +is equivalent to +.BR * . +The regex form of the pattern does not support UTF-8 (7) yet. +.LP +The statement +.B filter=<ldapfilter> +selects the entries based on a valid LDAP filter as described in RFC 2254. +.LP +The statement +.B attrs=<attrlist> +selects the attributes the access control rule applies to. +It is a comma-separated list of attribute types, plus the special names +.BR entry , +indicating access to the entry itself, and +.BR children , +indicating access to the entry's children. ObjectClass names may also +be specified in this list, which will affect all the attributes that +are required and/or allowed by that objectClass. +.LP +The last three statements are additive; they can be used in sequence +to select entities the access rule applies to based on naming context, +value and attribute type simultaneously. +.LP +The field +.B <who> +indicates whom the access rules apply to. +Multiple +.B <who> +statements can appear in an access control statement, indicating the +different access privileges to the same resource that apply to different +accessee. +It can have the forms +.LP +.nf + * + anonymous + users + self + + dn[.<dnstyle>[,<modifier>]]=<pattern> + dnattr=<attrname> + group[/<objectclass>[/<attrname>]] + [.<style>]=<pattern> + peername[.<style>]=<pattern> + sockname[.<style>]=<pattern> + domain[.<domainstyle>[,<modifier>]]=<pattern> + sockurl[.<style>]=<pattern> + set[.<style>]=<pattern> + + ssf=<n> + transport_ssf=<n> + tls_ssf=<n> + sasl_ssf=<n> + + aci=<attrname> +.fi +.LP +They may be specified in combination. +.LP +.nf +.fi +.LP +The wildcard +.B * +refers to everybody. +.LP +The keyword +.B anonymous +means access is granted to unauthenticated users; it is moslty used +to limit access to authentication resources (e.g. the +.B userPassword +attribute) to unauthenticated users for authentication purposes. +.LP +The keyword +.B users +means access is granted to authenticated users. +.LP +The keyword +.B self +means access to an entry is allowed to the entry itself (e.g. the entry +being accessed and the requesting entry must be the same). +.LP +The statement +.B dn=<pattern> +means that access is granted to the matching dn. +The optional style qualificator +.B dnstyle +allows the same choices of the dn form of the +.B <what> +field. +In detail, the +.B regex +form of +.B pattern +can exploit substring substitution of submatches in the +.B <what> +dn by using the form +.BR $<digit> , +with +.B digit +ranging from 1 to 9. +.LP +The statement +.B dnattr=<attrname> +means that access is granted to requests whose dn is listed in the +entry being accessed under the +.B attrname +attribute. +.LP +The statement +.B group=<pattern> +means that access is granted to requests whose dn is listed +in the group entry whose dn is given by +.BR pattern . +The optional parameters +.B objectclass +and +.B attrname +define the objectClass and the member attributeType of the group entry. +The optional style qualificator +.B style +can be +.BR regex , +which means that +.B pattern +will be expanded accorging to regex (7), and +.B base +or +.B exact +(an alias of +.BR base ), +which means that an exact match will be used. +.LP +The statements +.BR peername=<pattern> , +.BR sockname=<pattern> , +.BR domain=<pattern> , +and +.BR sockurl=<pattern> +mean that the contacting host IP for +.BR peername , +the named pipe file name for +.BR sockname , +the contacting host name for +.BR domain , +and the contacting URL for +.BR sockurl +are compared against +.B pattern +to determine access. +The same +.B style +rules for pattern match described for the +.B group +case apply. +The +.BR domain +clause also allows the +.B subtree +style, which succeeds when a fully qualified name exactly matches the +.BR domain +pattern, or its trailing part, after a +.BR dot , +exactly matches the +.BR domain +pattern. +.LP +The statement +.B set=<pattern> +is undocumented yet. +.LP +The statement +.B aci=<attrname> +means that the access control is determined by the values in the +.B attrname +of the entry itself. +ACIs are experimental; they must be enabled at compile time. +.LP +The statements +.BR ssf=<n> , +.BR transport_ssf=<n> , +.BR tls_ssf=<n> , +and +.BR sasl_ssf=<n> +set the required Security Strength Factor (ssf) required to grant access. +.LP +The field +.B <access> ::= [self]{<level>|<priv>} +determines the access level or the specific access privileges the +.B who +field will have. +Its component are defined as +.LP +.nf + <level> ::= none|auth|compare|search|read|write + <priv> ::= {=|+|-}{w|r|s|c|x}+ +.fi +.LP +The modifier +.B self +allows special operations like having a certain access level or privilege +only in case the operation involves the name of the user that's requesting +the access. +It implies the user that requests access is bound. +An example is the +.B selfwrite +access to the member attribute of a group, which allows one to add/delete +its own DN from the member list of a group, without affecting other members. +.LP +The +.B level +access model relies on an incremental interpretation of the access +privileges. +The possible levels are +.BR none , +.BR auth , +.BR compare , +.BR search , +.BR read , +and +.BR write . +Each access level implies all the preceding ones, thus +.B write +access will imply all accesses. +While +.B none +is trivial, +.B auth +access means that one is allowed access to an attribute to perform +authentication/authorization operations (e.g. +.BR bind ) +with no other access. +This is useful to grant unauthenticated users the least possible +access level to critical resources, like passwords. +.LP +The +.B priv +access model relies on the explicit setting of access privileges +for each clause. +The +.B = +sign resets previously defined accesses; as a consequence, the final +access privileges will be only those defined by the clause. +The +.B + +and +.B - +signs add/remove access privileges to the existing ones. +The privileges are +.B w +for write, +.B r +for read, +.B s +for search, +.B c +for compare, and +.B x +for authentication. +More than one privilege can be added in one statement. +.LP +The optional field +.B <control> +controls the flow of access rule application. +It can have the forms +.LP +.nf + stop + continue + break +.fi +.LP +where +.BR stop , +the default, means access checking stops in case of match. +The other two forms are used to keep on processing access clauses. +In detail, the +.B continue +form allows for other +.B <who> +clauses in the same +.B <access> +clause to be considered, so that they may result in incrementally altering +the privileges, while the +.B break +form allows for other +.B <access> +clauses that match the same target to be processed. +Consider the (silly) example +.LP +.nf + access to dn.subtree="dc=example,dc=com" attrs=cn + by * =cs break + + access to dn.subtree="ou=People,dc=example,dc=com" + by * +r +.fi +.LP +which allows search and compare privileges to everybody under +the "dc=example,dc=com" tree, with the second rule allowing +also read in the "ou=People" subtree, +or the (even more silly) example +.LP +.nf + access to dn.subtree="dc=example,dc=com" attrs=cn + by * =cs continue + by users +r +.fi +.LP +which grants everybody search and compare privileges, and adds read +privileges to authenticated users. +.SH FILES +ETCDIR/slapd.conf +.SH SEE ALSO +.BR slapd (8), +.LP +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) +.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/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index e0e6249d0240c2c1e4c7a257f5405728f1ecd4b7..86203c5bd3eec4ef868faeb11015d4cdb1b42c61 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1,4 +1,7 @@ -.TH SLAPD.CONF 5 "13 November 1995" "U-M LDAP LDVERSION" +.TH SLAPD.CONF 5 "26 January 2002" "OpenLDAP LDVERSION" +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ .SH NAME slapd.conf \- configuration file for slapd, the stand-alone LDAP daemon .SH SYNOPSIS @@ -10,12 +13,11 @@ contains configuration information for the .BR slapd (8) daemon. This configuration file is also used by the .BR slurpd (8) -replication daemon and by the LDBM indexing utilities -.BR ldif2ldbm (8), -.BR ldif2index (8), -.BR ldif2id2entry (8), +replication daemon and by the SLAPD tools +.BR slapadd (8), +.BR slapcat (8), and -.BR ldif2id2children (8). +.BR slapindex (8). .LP The .B slapd.conf @@ -54,9 +56,10 @@ backslash character (`\\'), the character should be preceded by a backslash character. .LP The specific configuration options available are discussed below in the -Global Configuration Options, General Backend Options, LDBM -Backend-Specific Options, Shell Backend-Specific Options, and Password -Backend-Specific Options sections. Refer to "The SLAPD and SLURPD +Global Configuration Options, General Backend Options, General Database +Options, LDBM Database-Specific Options, +Shell Database-Specific Options, and Password +Database-Specific Options sections. Refer to the "OpenLDAP Administrator's Guide" for more details on the slapd configuration file. .SH GLOBAL CONFIGURATION OPTIONS @@ -64,53 +67,218 @@ Options described in this section apply to all backends, unless specifically overridden in a backend definition. Arguments that should be replaced by actual text are shown in brackets <>. .TP -.B -access to <what> [ by <who> <accesslevel> ]+ -Grant access (specified by <accesslevel>) to a set of entries and/or +.B access to <what> [ by <who> <access> <control> ]+ +Grant access (specified by <access>) to a set of entries and/or attributes (specified by <what>) by one or more requestors (specified -by <who>). Refer to "The SLAPD and SLURPD Administrator's Guide" for -information on using the +by <who>). +See the "OpenLDAP's Administrator's Guide" for details. +.TP +.B allow <features> +Specify a set of features (separated by white space) to +allow (default none). +.B bind_v2 +allows acceptance of LDAPv2 bind requests. +.B bind_anon_cred +allows anonymous bind when credentials are not empty (e.g. +when DN is empty). +.B bind_anon_dn +allows unauthenticated (anonymous) bind when DN is not empty. +.TP +.B argsfile <filename> +The ( absolute ) name of a file that will hold the .B slapd -access-control mechanisms. -.TP -.B -attribute <name> [<name2>] { bin | ces | cis | tel | dn } -Associate a syntax with an attribute name. By default, an -attribute is assumed to have syntax -.BR cis . -An optional alternate name can be -given for an attribute. The possible syntaxes and their meanings are: +server's command line options +if started without the debugging command line option. +.HP +.hy 0 +.B attributetype (\ <oid> [NAME\ <name>] [OBSOLETE]\ + [DESC\ <description>]\ + [SUP\ <oid>] [EQUALITY\ <oid>] [ORDERING\ <oid>]\ + [SUBSTR\ <oid>] [SYNTAX\ <oidlen>] [SINGLE\-VALUE] [COLLECTIVE]\ + [NO\-USER\-MODIFICATION] [USAGE\ <attributeUsage>]\ ) +.RS +Specify an attribute type using the LDAPv3 syntax defined in RFC 2252. +The slapd parser extends the RFC 2252 definition by allowing string +forms as well as numeric OIDs to be used for the attribute OID and +attribute syntax OID. +(See the +.B objectidentifier +description.) Currently the syntax name parser is case-sensitive. +The known syntax names are: .RS .RS .PD 0 -.TP -.B bin -binary -.TP -.B ces -case exact string -.TP -.B cis -case ignore string -.TP -.B tel -telephone number string -.TP -.B dn -distinguished name +AttributeTypeDescription Audio Binary BitString Certificate CertificateList +CertificatePair DN DeliveryMethod DirectoryString DITContentRuleDescription +DITStructureRuleDescription EnhancedGuide FacsimileTelephoneNumber +GeneralizedTime Guide IA5String Integer MatchingRuleDescription +MatchingRuleUseDescription MailPreference NameAndOptionalUUID +NameFormDescription NumericString ObjectClassDescription OID +OtherMailbox OctetString PostalAddress ProtocolInformation +PresentationAddress PrintableString SupportedAlgorithm TelephoneNumber +TeletexTerminalIdentifier TelexNumber UTCTime LDAPSyntaxDescription +SubstringAssertion NISnetgrouptriple Bootparameter .PD .RE .RE +.RE .TP -.B -defaultaccess { none | compare | search | read | write | delete } -Specify the default access to grant requestors not matched by -any other access line. The default behavior is to grant read access. +.B concurrency <integer> +Specify a desired level of concurrency. Provided to the underlying +thread system as a hint. The default is not to provide any hint. +.TP +.B defaultsearchbase <dn> +Specify a default search base to use when client submits a +non-base search request with an empty base DN. +.TP +.B disallow <features> +Specify a set of features (separated by white space) to +disallow (default none). +.B bind_anon +disables acceptance of anonymous bind requests. +.B bind_simple +disables simple (bind) authentication. +.B bind_krbv4 +disables Kerberos V4 (bind) authentication. +.B tls_2_anon +disables Start TLS from forcing session to anonymous status (see also +.BR tls_authc ). +.B tls_authc +disables StartTLS if authenticated (see also +.BR tls_2_anon ). +.TP +.B idletimeout <integer> +Specify the number of seconds to wait before forcibly closing +an idle client connection. A idletimeout of 0 disables this +feature. The default is 0. .TP .B include <filename> Read additional configuration information from the given file before continuing with the next line of the current file. .TP +.B limits <who> <limit> [<limit> [...]] +Specify time and size limits based on who initiated an operation. +The argument +.B who +can be any of +.RS +.RS +.TP +anonymous | users | [dn[.<style>]=]<pattern> + +.RE +with +.RS +.TP +<style> ::= exact | base | one | subtree | children | regex | anonymous + +.RE +.B Anonymous +is hit when a search is performed without prior binding; +.B users +is hit when a search is performed by a successfully bound user; +otherwise a +.B regex +dn pattern is assumed unless otherwise specified by qualifying +the (optional) key string +.B dn +with +.B exact +or +.B base +(which are synonims), to require an exact match; with +.BR one, +to require exactly one level of depth match; with +.BR subtree, +to allow any level of depth match, including the exact match; with +.BR children, +to allow any level of depth match, not including the exact match; +.BR regex +explicitly requires the (default) match based on regular expression +pattern, as detailed in +.BR regex(7). +Finally, +.B anonymous +matches unbound operations; the +.B pattern +field is ignored. +The same behavior is obtained by using the +.B anonymous +form of the +.B who +clause. + +The currently supported limits are +.B size +and +.BR time. + +The syntax for time limits is +.BR time[.{soft|hard}]=<integer> , +where +.BR integer +is the number of seconds slapd will spend answering a search request. +If no time limit is explicitly requested by the client, the +.BR soft +limit is used; if the requested time limit exceedes the +.BR hard +limit, an "Unwilling to perform" is returned. +If the +.BR hard +limit is set to 0 or to the keyword "soft", the soft limit is used +in either case; if it is set to -1 or to the keyword "none", +no hard limit is enforced. +Explicit requests for time limits smaller or equal to the +.BR hard +limit are honored. +If no flag is set, the value is assigned to the +.BR soft +limit, and the +.BR hard +limit is set to zero, to preserve the original behavior. + +The syntax for size limits is +.BR size[.{soft|hard|unchecked}]=<integer> , +where +.BR integer +is the maximum number of entries slapd will return answering a search +request. +If no size limit is explicitly requested by the client, the +.BR soft +limit is used; if the requested size limit exceedes the +.BR hard +limit, an "Unwilling to perform" is returned. +If the +.BR hard +limit is set to 0 or to the keyword "soft", the soft limit is used +in either case; if it is set to -1 or to the keyword "none", +no hard limit is enforced. +Explicit requests for size limits smaller or equal to the +.BR hard +limit are honored. +The +.BR unchecked +flag sets a limit on the number of candidates a search request is allowed +to examine. +If the selected candidates exceed the +.BR unchecked +limit, the search will abort with "Unwilling to perform". +If it is set to -1 or to the keyword "none", no limit is applied (the default). +If no flag is set, the value is assigned to the +.BR soft +limit, and the +.BR hard +limit is set to zero, to preserve the original behavior. + +In case of no match, the global limits are used. +The default values are the same of +.BR sizelimit +and +.BR timelimit ; +no limit is set on +.BR unchecked . +.RE +.TP .B loglevel <integer> Specify the level at which debugging statements and operation statistics should be syslogged (currently logged to the @@ -159,45 +327,401 @@ entry parsing .PD .RE .RE -.TP +.HP +.B objectclass ( <oid> [NAME <name>] [DESC <description] [OBSOLETE]\ + [SUP <oids>] [{ ABSTRACT | STRUCTURAL | AUXILIARY }] [MUST <oids>]\ + [MAY <oids>] ) +.RS +Specify an objectclass using the LDAPv3 syntax defined in RFC 2252. +The slapd parser extends the RFC 2252 definition by allowing string +forms as well as numeric OIDs to be used for the object class OID. +(See the .B -objectclass <name> requires <attrs> allows <attrs> -Define the schema rules for the object class named <name>. These are -used in conjunction with the schemacheck option. +objectidentifier +description.) Object classes are "STRUCTURAL" by default. +.RE +.TP +.B objectidentifier <name> { <oid> | <name>[:<suffix>] } +Define a string name that equates to the given OID. The string can be used +in place of the numeric OID in objectclass and attribute definitions. The +name can also be used with a suffix of the form ":xx" in which case the +value "oid.xx" will be used. +.TP +.B password-hash <hash> +This option sets the hash to be used in generation of user +passwords, stored in userPassword, during processing of +LDAP Password Modify Extended Operations (RFC 3052). +The <hash> must be one of +.BR {SSHA} , +.BR {SHA} , +.BR {SMD5} , +.BR {MD5} , +and +.BR {CRYPT} . +The default is +.BR {SSHA} . + +Note that this option does not alter the normal user applications +handling of userPassword during LDAP Add, Modify, or other LDAP operations. +.TP +.B password\-crypt\-salt\-format <format> +Specify the format of the salt passed to +.BR crypt (3) +when generating {CRYPT} passwords (see +.BR password\-hash ) +during processing of LDAP Password Modify Extended Operations (RFC 3062). + +This string needs to be in +.BR sprintf (3) +format and may include one (and only one) %s conversion. +This conversion will be substituted with a string random +characters from [A\-Za\-z0\-9./]. For example, "%.2s" +provides a two character salt and "$1$%.8s" tells some +versions of crypt(3) to use an MD5 algorithm and provides +8 random characters of salt. The default is "%s", which +provides 31 characters of salt. +.TP +.B pidfile <filename> +The ( absolute ) name of a file that will hold the +.B slapd +server's process ID ( see +.BR getpid (2) +) if started without the debugging command line option. .TP .B referral <url> Specify the referral to pass back when .BR slapd (8) cannot find a local database to handle a request. +If specified multiple times, each url is provided. +.TP +.B require <conditions> +Specify a set of conditions (separated by white space) to +require (default none). +The directive may be specified globally and/or per-database. +.B bind +requires bind operation prior to directory operations. +.B LDAPv3 +requires session to be using LDAP version 3. +.B authc +requires authentication prior to directory operations. +.B SASL +requires SASL authentication prior to directory operations. +.B strong +requires strong authentication prior to directory operations. +The +.B SASL +and +.B strong +conditions are currently same. +.B none +may be used to require no conditions (useful for clearly globally +set conditions within a particular database). +.TP +.B reverse-lookup on | off +Enable/disable client name reverse lookup (default is +.BR on +if compiled with --enable-rlookups). +.TP +.B rootDSE <file> +Specify the name of an LDIF(5) file containing user defined attributes +for the root DSE. These attributes are returned in addition to the +attributes normally produced by slapd. +.TP +.B sasl-host <fqdn> +Used to specify the fully qualified domain name used for SASL processing. +.TP +.B sasl-realm <realm> +Specify SASL realm. Default is empty. +.TP +.B sasl-regexp <match> <replace> +Used by the SASL authorization mechanism to convert a SASL authenticated +username to an LDAP DN. When an authorization request is received, the SASL +.B USERNAME, REALM, +and +.B MECHANISM +are taken, when available, and combined into a SASL name of the +form +.RS +.RS +.TP +.B uid=<UID>[,cn=<REALM>][,cn=<MECH>],cn=AUTHZ + +.RE +This SASL name is then compared against the +.B match +regular expression, and if the match is successful, the SASL name is +replaced with the +.B replace +string. If there are wildcard strings in the +.B match +regular expression that are enclosed in parenthesis, e.g. +.RS +.RS +.TP +.B uid=(.*)\\\\+realm=.* + +.RE +.RE +then the portion of the SASL name that matched the wildcard will be stored +in the numbered placeholder variable $1. If there are other wildcard strings +in parenthesis, the matching strings will be in $2, $3, etc. up to $9. The +placeholders can then be used in the +.B replace +string, e.g. +.RS +.RS .TP -.B schemacheck { on | off } -Turn schema checking on or off. The default is off. +.B cn=$1,ou=Accounts,dc=$2,dc=$4. + +.RE +.RE +The replaced SASL name can be either a DN or an LDAP URI. If the latter, the slapd +server will use the URI to search its own database, and if the search returns +exactly one entry, the SASL name is replaced by the DN of that entry. +Multiple +.B sasl-regexp +options can be given in the configuration file to allow for multiple matching +and replacement patterns. The matching patterns are checked in the order they +appear in the file, stopping at the first successful match. + +.B Caution: +Because the plus sign + is a character recognized by the regular expression engine, +and it will appear in SASL names that include a REALM, be careful to escape the +plus sign with a backslash \\+ to remove the character's special meaning. +.RE .TP -.B sizelimit <integer> +.B sasl-secprops <properties> +Used to specify Cyrus SASL security properties. +The +.B none +flag (without any other properities) causes the flag properites +default, "noanonymous,noplain", to be cleared. +The +.B noplain +flag disables mechanisms susceptible to simple passive attacks. +The +.B noactive +flag disables mechanisms susceptible to active attacks. +The +.B nodict +flag disables mechanisms susceptible to passive dictionary attacks. +The +.B noanonyous +flag disables mechanisms which support anonymous login. +The +.B forwardsec +flag require forward secrecy between sessions. +The +.B passcred +require mechanisms which pass client credentials (and allow +mechanisms which can pass credentials to do so). +The +.B minssf=<factor> +property specifies the minimum acceptable +.I security strength factor +as an integer approximate to effective key length used for +encryption. 0 (zero) implies no protection, 1 implies integrity +protection only, 56 allows DES or other weak ciphers, 112 +allows triple DES and other strong ciphers, 128 allows RC4, +Blowfish and other modern strong ciphers. The default is 0. +The +.B maxssf=<factor> +property specifies the maximum acceptable +.I security strength factor +as an integer (see minssf description). The default is INT_MAX. +The +.B maxbufsize=<size> +property specifies the maximum security layer receive buffer +size allowed. 0 disables security layers. The default is 65536. +.TP +.B security <factors> +Specify a set of factors (separated by white space) to require. +An integer value is associated with each factor and is roughly +equivalent of the encryption key length to require. A value +of 112 is equivalent to 3DES, 128 to Blowfish, etc.. +The directive may be specified globally and/or per-database. +.B ssf=<n> +specifies the overall security strength factor. +.B transport=<n> +specifies the transport security strength factor. +.B tls=<n> +specifies the TLS security strength factor. +.B sasl=<n> +specifies the SASL security strength factor. +.B update_ssf=<n> +specifies the overall security strength factor to require for +directory updates. +.B update_transport=<n> +specifies the transport security strength factor to require for +directory updates. +.B update_tls=<n> +specifies the TLS security strength factor to require for +directory updates. +.B update_sasl=<n> +specifies the SASL security strength factor to require for +directory updates. +Note that the +.B transport +factor is measure of security provided by the underlying transport, +e.g. ldapi:// (and eventually IPSEC). It is not normally used. +.TP +.B sizelimit <integer> +.TP +.B sizelimit size[.{soft|hard|unchecked}]=<integer> [...] Specify the maximum number of entries to return from a search operation. The default size limit is 500. +The second format allows a fine grain setting of the size limits. +Extra args can be added on the same line. +See +.BR limits +for an explanation of the different flags. +.TP +.B sockbuf_max_incoming <integer> +Specify the maximum incoming LDAP PDU size for anonymous sessions. +The default is 262143. +.TP +.B sockbuf_max_incoming_auth <integer> +Specify the maximum incoming LDAP PDU size for authenticated sessions. +The default is 4194303. .TP .B srvtab <filename> Specify the srvtab file in which the kerberos keys necessary for authenticating clients using kerberos can be found. This option is only meaningful if you are using Kerberos authentication. .TP +.B threads <integer> +Specify the maximum size of the primary thread pool. +The default is 32. +.TP .B timelimit <integer> +.TP +.B timelimit time[.{soft|hard}]=<integer> [...] Specify the maximum number of seconds (in real time) .B slapd will spend answering a search request. The default time limit is 3600. +The second format allows a fine grain setting of the time limits. +Extra args can be added on the same line. +See +.BR limits +for an explanation of the different flags. +.SH TLS OPTIONS +If +.B slapd +is built with support for Transport Layer Security, there are more options +you can specify. +.TP +.B TLSCipherSuite <cipher-suite-spec> +Permits configuring what ciphers will be accepted and the preference order. +<cipher-suite-spec> should be a cipher specification for OpenSSL. Example: + +TLSCipherSuite HIGH:MEDIUM:+SSLv2 + +To check what ciphers a given spec selects, use: + +openssl ciphers -v <cipher-suite-spec> +.TP +.B TLSCACertificateFile <filename> +Specifies the file that contains certificates for all of the Certificate +Authorities that +.B slapd +will recognize. +.TP +.B TLSCertificateFile <filename> +Specifies the file that contains the +.B slapd +server certificate. +.TP +.B TLSCertificateKeyFile <filename> +Specifies the file that contains the +.B slapd +server private key that matches the certificate stored in the +.B TLSCertificateFile +file. Currently, the private key must not be protected with a password, so +it is of critical importance that it is protected carefully. +.TP +.B TLSRandFile <filename> +Specifies the file to obtain random bits from when /dev/[u]random +is not available. Generally set to the name of the EGD/PRNGD socket. +The environment variable RANDFILE can also be used to specify the filename. +.TP +.B TLSVerifyClient <level> +Specifies what checks to perform on client certificates in an +incoming TLS session, if any. +The +.B <level> +can be specified as one of the following keywords: +.RS +.TP +.B never +This is the default. +.B slapd +will not ask the client for a certificate. +.TP +.B allow +The client certificate is requested. If no certificate is provided, +the session proceeds normally. If a bad certificate is provided, +it will be ignored and the session proceeds normally. +.TP +.B try +The client certificate is requested. If no certificate is provided, +the session proceeds normally. If a bad certificate is provided, +the session is immediately terminated. +.TP +.B demand | hard | true +These keywords are all equivalent, for compatibility reasons. +The client certificate is requested. If no certificate is provided, +or a bad certificate is provided, the session is immediately terminated. + +Note that a valid client certificate is required in order to use the +SASL EXTERNAL authentication mechanism with a TLS session. As such, +a non-default +.B TLSVerifyClient +setting must be chosen to enable SASL EXTERNAL authentication. +.RE .SH GENERAL BACKEND OPTIONS Options in this section only apply to the configuration file section -for the backend in which they are defined. They are supported by every +for the specified backend. They are supported by every +type of backend. +.TP +.B backend <databasetype> +Mark the beginning of a backend definition. <databasetype> +should be one of +.B bdb, +.B dnssrv, +.B ldap, +.B ldbm, +.B meta, +.B monitor, +.B null, +.B passwd, +.B perl, +.B shell, +.B sql, +or +.B tcl, +depending on which backend will serve the database. + +.SH GENERAL DATABASE OPTIONS +Options in this section only apply to the configuration file section +for the database in which they are defined. They are supported by every type of backend. .TP .B database <databasetype> Mark the beginning of a new database instance definition. <databasetype> should be one of +.B bdb, +.B dnssrv, +.B ldap, .B ldbm, +.B meta, +.B monitor, +.B null, +.B passwd, +.B perl, .B shell, +.B sql, or -.B passwd +.B tcl, depending on which backend will serve the database. .TP .B lastmod on | off @@ -205,23 +729,57 @@ Controls whether .B slapd will automatically maintain the modifiersName, modifyTimestamp, creatorsName, and -createTimestamp attributes for entries. By default, lastmod is off. +createTimestamp attributes for entries. By default, lastmod is on. .TP .B readonly on | off This option puts the database into "read-only" mode. Any attempts to modify the database will return an "unwilling to perform" error. By default, readonly is off. -.TP -.B -replica host=<hostname>[:port] "binddn=<DN>" bindmethod=simple | -.B -kerberos [credentials=<password>] [srvtab=<filename>] -.br -Specify a replication site for this database. Refer to "The SLAPD and -SLURPD Administrator's Guide" for detailed information on setting up -a replicated +.HP +.B replica host=<hostname>[:port] [tls=yes|critical] +.B [suffix=<suffix> [...]] +.B bindmethod=simple|sasl [binddn=<simple DN>] [credentials=<simple password>] +.B [saslmech=<SASL mech>] [secopts=<options>] [realm=<realm>] +.B [authcId=<authentication ID>] [authcId=<authentication ID>] +.B [attr[!]=<attr list>] +.RS +Specify a replication site for this database. Refer to the "OpenLDAP +Administrator's Guide" for detailed information on setting up a replicated .B slapd -directory service. +directory service. Zero or more +.B suffix +instances can be used to select the subtrees that will be replicated +(defaults to all the database). A +.B bindmethod +of +.B simple +requires the options +.B binddn +and +.B credentials +and should only be used when adequate security services +(e.g TLS or IPSEC) are in place. A +.B bindmethod +of +.B sasl +requires the option +.B saslmech. +If the +.B mechanism +will use Kerberos, a kerberos instance should be given in +.B authcId. +An +.B attr list +can be given after the +.B attr +keyword to allow the selective replication of the listed attributes only; +if the optional +.B ! +mark is used, the list is considered exclusive, i.e. the listed attributes +are not replicated. +If an objectClass is listed, all the related attributes +are (are not) replicated. +.RE .TP .B replogfile <filename> Specify the name of the replication log file to log changes to. @@ -231,20 +789,53 @@ and read by .BR slurpd (8). See .BR slapd.replog (5) -for more information. +for more information. The specified file should be located +in a directory with limited read/write/execute access as the replication +logs may contain sensitive information. .TP .B rootdn <dn> -Specify the DN of an entry that is not subject to access control +Specify the distinguished name that is not subject to access control or administrative limit restrictions for operations on this database. +This DN may or may not be associated with an entry. An empty root +DN (the default) specifies no root access is to be granted. It is +recommended that the rootdn only be specified when needed (such as +when initially populating a database). If the rootdn is within +a namingContext (suffix) of the database, a simple bind password +may also be provided using the +.B rootpw +directive. .TP .B rootpw <password> -Specify a password for the rootdn. +Specify a password (or hash of the password) for the rootdn. If +the rootdn is not within the namingContext of the database, the +provided password is ignored. +This option accepts all RFC 2307 userPassword formats known to +the server (see +.B password-hash +desription) as well as cleartext. +.BR slappasswd (8) +may be used to generate a hash of a password. Cleartext +and \fB{CRYPT}\fP passwords are not recommended. If empty +(the default), authentication of the root DN is by other means +(e.g. SASL). Use of SASL is encouraged. .TP .B suffix <dn suffix> Specify the DN suffix of queries that will be passed to this backend database. Multiple suffix lines can be given and at least one is required for each database definition. .TP +.B subordinate +Specify that the current backend database is a subordinate of another +backend database. A subordinate database may have only one suffix. This +option may be used to glue multiple databases into a single namingContext. +If the suffix of the current database is within the namingContext of a +superior database, searches against the superior database will be +propagated to the subordinate as well. All of the databases +associated with a single namingContext should have identical rootdns. +Behavior of other LDAP operations is unaffected by this setting. In +particular, it is not possible to use moddn to move an entry from +one subordinate to another subordinate within the namingContext. +.TP .B updatedn <dn> This option is only applicable in a slave .B slapd. @@ -252,11 +843,26 @@ It specifies the DN allowed to make changes to the replica (typically, this is the DN .BR slurpd (8) binds as when making changes to the replica). -.SH LDBM BACKEND-SPECIFIC OPTIONS -Options in this category only apply to the LDBM backend database. That is, -they must follow a "database ldbm" line and come before any subsequent -"database" lines. The LDBM backend is a high-performance database that -makes extensive use of indexing and caching to speed data access. +.TP +.B updateref <url> +Specify the referral to pass back when +.BR slapd (8) +is asked to modify a replicated local database. +If specified multiple times, each url is provided. +.\" .SH LDBM BACKEND-SPECIFIC OPTIONS +.\" Options in this category only apply to the LDBM backend. That is, +.\" they must follow "backend ldbm" line and come before any subsequent +.\" "backend" or "database" lines. The LDBM backend is a high-performance +.\" database that makes extensive use of indexing and caching to speed +.\" data access. +.SH BDB DATABASE-SPECIFIC OPTIONS +Options in this category only apply to the BDB databases. That is, +they must follow "database bdb" line and come before any subsequent +"backend" or "database" lines. +.SH LDBM DATABASE-SPECIFIC OPTIONS +Options in this category only apply to the LDBM databases. That is, +they must follow "database ldbm" line and come before any subsequent +"backend" or "database" lines. .TP .B cachesize <integer> Specify the size in entries of the in-memory cache maintained @@ -267,23 +873,84 @@ Specify the size in bytes of the in-memory cache associated with each open index file. If not supported by the underlying database method, this option is ignored without comment. The default is 100000 bytes. .TP +.B dbnolocking +Specify that no database locking should be performed. +Enabling this option may improve performance at the expense of data security. +Do NOT run any slap tools while slapd is running. +.TP +.B dbnosync +Specify that on-disk database contents should not be immediately +synchronized with in memory changes. Enabling this option may improve +performance at the expense of data security. +.TP +.B dbsync <frequency> <maxdelays> <delayinterval> +Flush dirty database buffers to disk every +.B <seconds> +seconds. Implies +.B dbnosync +(ie. indvidual updates are no longer written to disk). It attempts to avoid +syncs during periods of peak activity by waiting +.B <delayinterval> +seconds if the server is busy, repeating this delay up to +.B <maxdelays> +times before proceeding. +It is an attempt to provide higher write performance with some amount of data +security. Note that it may still be possible to get an inconsistent +database if the underlying engine fills its cache and writes out individual +pages and slapd crashes or is killed before the next sync. +.B <maxdelays> +and +.B <delayinterval> +are optional and default to +.B 12 +and +.B 5 +respectively, giving a total elapsed delay of 60 seconds before a sync +will occur. +.B <maxdelays> +may be zero, and +.B <delayinterval> +must be 1 or greater. +.TP .B directory <directory> -Specify the directory where the LDBM files containing the database and -associated indexes live. The default is -.B /usr/tmp. +Specify the directory where the LDBM files containing this database and +associated indexes live. A separate directory must be specified for +each database. The default is +.BR LOCALSTATEDIR/openldap-data . .TP .B -index { <attrlist> | default } [ pres,eq,approx,sub,none ] -Specify the indexes to maintain for the given attribute. If only -an <attr> is given, all possible indexes are maintained. +index {<attrlist>|default} [pres,eq,approx,sub,<special>] +Specify the indexes to maintain for the given attribute (or +list of attributes). Some attributes only support a subset +of indexes. If only an <attr> is given, the indices specified +for \fBdefault\fR are maintained. Note that setting a default +does not imply that all attributes will be indexed. + +A number of special index parameters may be +specified. +The index type +.B sub +can be decomposed into +.BR subinitial , +.BR subany ,\ and +.B subfinal +indices. +The special type +.B nolang +may be specified to disallow use of this index by language subtypes. +The special type +.B nosubtypes +may be specified to disallow use of this index by named subtypes. +Note: changing index settings requires rebuilding indices, see +.BR slapindex (8). .TP .B mode <integer> Specify the file protection mode that newly created database index files should have. The default is 0600. -.SH SHELL BACKEND-SPECIFIC OPTIONS +.SH SHELL DATABASE-SPECIFIC OPTIONS Options in this category only apply to the SHELL backend database. That is, they must follow a "database shell" line and come before any subsequent -"database" lines. The Shell backend executes external programs to +"backend" or "database" lines. The Shell backend executes external programs to implement operations, and is designed to make it easy to tie an existing database to the .B slapd @@ -307,17 +974,15 @@ front-end. .TP .B abandon <pathname> These options specify the pathname of the command to execute in response -to the given LDAP operation. The command given should understand and -follow the input/output conventions described in Appendix B of "The SLAPD -and SLURPD Administrator's Guide." -.LP +to the given LDAP operation. + Note that you need only supply configuration lines for those commands you want the backend to handle. Operations for which a command is not supplied will be refused with an "unwilling to perform" error. -.SH PASSWORD BACKEND-SPECIFIC OPTIONS +.SH PASSWORD DATABASE-SPECIFIC OPTIONS Options in this category only apply to the PASSWD backend database. That is, they must follow a "database passwd" line and come before any -subsequent "database" lines. The PASSWD database serves up the user +subsequent "backend" or "database" lines. The PASSWD database serves up the user account information listed in the system .BR passwd (5) file. @@ -325,16 +990,31 @@ file. .B file <filename> Specifies an alternate passwd file to use. The default is .B /etc/passwd. +.SH OTHER DATABASE-SPECIFIC OPTIONS +Other databases may allow specific configuration options; they will be +documented separately since most of these databases are very specific +or experimental. .SH EXAMPLE -"The SLAPD and SLURPD Administrator's Guide" contains an annotated +"OpenLDAP Administrator's Guide" contains an annotated example of a configuration file. .SH FILES ETCDIR/slapd.conf .SH SEE ALSO .BR ldap (3), .BR slapd.replog (5), +.BR slapd.access (5), +.BR locale (5), .BR passwd (5), .BR slapd (8), +.BR slapadd (8), +.BR slapcat (8), +.BR slapindex (8), +.BR slappassword (8), .BR slurpd (8), .LP -"The SLAPD and SLURPD Administrator's Guide" +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) +.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 be0c97d3bf58f2adacc9d61c4c04517bc4a287b6..949f866e68e8176f92f3843e0057aa77df310fe6 100644 --- a/doc/man/man8/slapd.8 +++ b/doc/man/man8/slapd.8 @@ -1,16 +1,23 @@ -.TH SLAPD 8C "6 November 1995" "U-M LDAP LDVERSION" +.\" $OpenLDAP$ +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.TH SLAPD 8C "5 Novemeber 2000" "OpenLDAP LDVERSION" .SH NAME slapd \- Stand-alone LDAP Daemon .SH SYNOPSIS -.B ETCDIR/slapd [\-d debug\-level] -.B [\-f slapd\-config\-file] [\-p port\-number] -.B [\-s syslog\-level] [\-i] +.B LIBEXECDIR/slapd +.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 .SH DESCRIPTION .LP .B Slapd is the stand-alone LDAP daemon. It listens for LDAP connections on -port 389, responding +any number of ports (default 389), responding to the LDAP operations it receives over these connections. .B slapd is typically invoked at boot time, usually out of @@ -18,10 +25,22 @@ is typically invoked at boot time, usually out of Upon startup, .B slapd normally forks and disassociates itself from the invoking tty. +If configured in +.BR ETCDIR/slapd.conf , +the +.B slapd +process will print its process ID ( see +.BR getpid (2) +) to a +.B .pid +file, as well as the command line options during invocation to an +.B .args +file ( see +.BR slapd.conf (5) +). If the .B \-d -flag is given and debugging is set to some non-zero -value, +flag is given, even with a zero argument, .B slapd will not fork and disassociate from the invoking tty. .LP @@ -34,19 +53,22 @@ See .BR slurpd (8) for details. .LP -See "The SLAPD and SLURPD Administrator's Guide" for more details on +See the "OpenLDAP Administrator's Guide" for more details on .BR slapd . .SH OPTIONS .TP .BI \-d " debug\-level" Turn on debugging as defined by .I debug\-level. -If this option is specified, +If this option is specified, even with a zero argument, .B slapd will not fork or disassociate from the invoking terminal. Some general operation and status messages are printed for any value of \fIdebug\-level\fP. \fIdebug\-level\fP is taken as a bit string, with each bit corresponding to a different kind of debugging information. See <ldap.h> for details. +Remember that if you turn on packet logging, packets containing bind passwords +will be output, so if you redirect the log to a logfile, that file should +be read-protected. .TP .BI \-s " syslog\-level" This option tells @@ -55,21 +77,73 @@ at what level debugging statements should be logged to the .BR syslog (8) facility. .TP +.BI \-n " service\-name" +Specifies the service name for logging and other purposes. Defaults +to basename of argv[0], i.e.: "slapd". +.TP +.BI \-l " syslog\-local\-user" +Selects the local user of the +.BR syslog (8) +facility. Values can be +.BR LOCAL0 , +.BR LOCAL1 , +and so on, up to +.BR LOCAL7 . +The default is +.BR LOCAL4 . +However, this option is only permitted on systems that support +local users with the +.BR syslog (8) +facility. +.TP .BI \-f " slapd\-config\-file" Specifies the slapd configuration file. The default is .BR ETCDIR/slapd.conf . .TP -.BI \-p " port\-number" +.BI \-h " URLlist" .B slapd -will listen on the default LDAP port (389) unless this option is given -to override the default. +will by default serve +.B ldap:/// +(LDAP over TCP on all interfaces on default LDAP port). That is, +it will bind using INADDR_ANY and port 389. +The +.B \-h +option may be used to specify LDAP (and LDAPS) URLs to serve. +For example, if slapd is given +.B \-h " ldap://127.0.0.1:9009/ ldaps:/// ldapi:///", +It will bind 127.0.0.1:9009 for LDAP, 0.0.0.0:636 for LDAP over TLS, +and LDAP over IPC (Unix domain sockets). Host 0.0.0.0 represents +INADDR_ANY. +A space separated list of URLs is expected. The URLs should be of +LDAP (ldap://) or LDAP over TLS (ldaps://) or LDAP over IPC (ldapi://) +scheme without a DN or other optional parameters. Support for the +latter two schemes depends on selected configuration options. Hosts +may be specified by name or IPv4 and IPv6 address formats. +Ports, if specfied, must be numeric. The default ldap:// port is 389 +and the default ldaps:// port is 636. .TP -.B \-i -This option tells +.BI \-r " directory" +Specifies a chroot "jail" directory. slapd will +.BR chdir (2) +then +.BR chroot (2) +to this directory after opening listeners but before reading +any configuration file or initializing any backend. +.TP +.BI \-u " user" .B slapd -that it is being run from -.BR inetd(8) , -the Internet protocol daemon. +will run slapd with the specified user name or id, and that user's +supplementary group access list as set with initgroups(3). The group ID +is also changed to this user's gid, unless the -g option is used to +override. +.TP +.BI \-g " group" +.B slapd +will run with the specified group name or id. +.LP +Note that on some systems, running as a non-privileged user will prevent +passwd back-ends from accessing the encrypted passwords. Note also that +any shell back-ends will run as the specified non-privileged user. .SH EXAMPLES To start .I slapd @@ -78,7 +152,7 @@ the LDAP databases defined in the default config file, just type: .LP .nf .ft tt - ETCDIR/slapd + LIBEXECDIR/slapd .ft .fi .LP @@ -89,16 +163,21 @@ on voluminous debugging which will be printed on standard error, type: .LP .nf .ft tt - ETCDIR/slapd -f /usr/local/slapd/slapd.conf -d 255 + LIBEXECDIR/slapd -f ETCDIR/slapd.conf -d 255 .ft .fi .LP .SH "SEE ALSO" .BR ldap (3), .BR slapd.conf (5), +.BR slapd.access (5), .BR slurpd (8) .LP -"The SLAPD and SLURPD Administrator's Guide" +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) .SH BUGS -When using the LDBM database backend, the Modify RDN operation does not -update the attribute values in the entry that are affected by the change. +See http://www.openldap.org/its/ +.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/slapindex.8 b/doc/man/man8/slapindex.8 new file mode 100644 index 0000000000000000000000000000000000000000..d44aa1e2fefc769d65f7c9e36af68b5efafd4817 --- /dev/null +++ b/doc/man/man8/slapindex.8 @@ -0,0 +1,85 @@ +.TH SLAPINDEX 8C "20 August 2000" "OpenLDAP LDVERSION" +.\" $OpenLDAP$ +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +slapindex \- SLAPD index to LDIF utility +.SH SYNOPSIS +.B SBINDIR/slapindex +.B [\-v] +.B [\-c] +.B [\-d level] +.B [\-b suffix] +.B [\-n dbnum] +.B [\-f slapd.conf] +.B +.LP +.SH DESCRIPTION +.LP +.B Slapindex +is used to regenerate +.BR slapd (8) +indices based upon the current contents of a database. +It opens the given database determined by the database number or +suffix and updates the indices for all values of all attributes +of all entries. +.SH OPTIONS +.TP +.B \-v +enable verbose mode. +.TP +.B \-c +enable continue (ignore errors) mode. +.TP +.BI \-d " level" +enable debugging messages as defined by the specified +.IR level . +.TP +.BI \-b " suffix" +Use the specified \fIsuffix\fR to determine which database to +generate output for. The \-b cannot be used in conjunction +with the +.B \-n +option. +.TP +.BI \-n " dbnum" +Generate output for the \fIdbnum\fR\-th database listed in the +configuration file. The +.B \-n +cannot be used in conjunction with the +.B \-b +option. +.TP +.BI \-f " slapd.conf" +specify an alternative +.BR slapd.conf (5) +file. +.SH LIMITATIONS +Your +.BR slapd (8) +should not be running (at least, not in read-write +mode) when you do this to ensure consistency of the database. +.LP +This command provides ample opportunity for the user to obtain +and drink their favorite beverage. +.SH EXAMPLES +To reindex your SLAPD database, give the command: +.LP +.nf +.ft tt + SBINDIR/slapindex +.ft +.fi +.SH "SEE ALSO" +.BR ldap (3), +.BR ldif (5), +.BR slapadd (8), +.BR ldapadd (1), +.BR slapd (8) +.LP +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) +.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/include/lber_pvt.h b/include/lber_pvt.h new file mode 100644 index 0000000000000000000000000000000000000000..6fd8eb2c6bc88542a7c0348670ec2bd69e536364 --- /dev/null +++ b/include/lber_pvt.h @@ -0,0 +1,94 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. A copy of this license is available at + * http://www.OpenLDAP.org/license.html or in file LICENSE in the + * top-level directory of the distribution. + */ +/* + * lber_pvt.h - Header for ber_pvt_ functions. These are meant to be used + * by the OpenLDAP distribution only. + */ + +#ifndef _LBER_PVT_H +#define _LBER_PVT_H 1 + +#include <lber.h> + +LDAP_BEGIN_DECL + +typedef struct sockbuf_buf { + ber_len_t buf_size; + ber_len_t buf_ptr; + ber_len_t buf_end; + char *buf_base; +} Sockbuf_Buf; + +/* + * bprint.c + */ +LBER_V( BER_LOG_PRINT_FN ) ber_pvt_log_print; + +LBER_F( int ) +ber_pvt_log_printf LDAP_P(( + int errlvl, + int loglvl, + const char *fmt, + ... )) LDAP_GCCATTR((format(printf, 3, 4))); + +/* + * sockbuf.c + */ +LBER_F( ber_slen_t ) +ber_pvt_sb_do_write LDAP_P(( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )); + +LBER_F( void ) +ber_pvt_sb_buf_init LDAP_P(( Sockbuf_Buf *buf )); + +LBER_F( void ) +ber_pvt_sb_buf_destroy LDAP_P(( Sockbuf_Buf *buf )); + +LBER_F( int ) +ber_pvt_sb_grow_buffer LDAP_P(( Sockbuf_Buf *buf, ber_len_t minsize )); + +LBER_F( ber_len_t ) +ber_pvt_sb_copy_out LDAP_P(( Sockbuf_Buf *sbb, char *buf, ber_len_t len )); + +LBER_F( int ) +ber_pvt_socket_set_nonblock LDAP_P(( ber_socket_t sd, int nb )); + + +#if 0 +#define ber_bvstrcmp(v1,v2) \ + ((v1)->bv_len < (v2)->bv_len \ + ? -1 : ((v1)->bv_len > (v2)->bv_len \ + ? 1 : strncmp((v1)->bv_val, (v2)->bv_val, (v1)->bv_len) )) +#else + /* avoid strncmp() */ +#define ber_bvstrcmp(v1,v2) ber_bvcmp((v1),(v2)) +#endif + +#define ber_bvstrcasecmp(v1,v2) \ + ((v1)->bv_len < (v2)->bv_len \ + ? -1 : ((v1)->bv_len > (v2)->bv_len \ + ? 1 : strncasecmp((v1)->bv_val, (v2)->bv_val, (v1)->bv_len) )) + +#define ber_bvccmp(v1,c) \ + ( (v1)->bv_len == 1 && (v1)->bv_val[0] == (c) ) + +#define ber_strccmp(s,c) \ + ( (s)[0] == (c) && (s)[1] == '\0' ) + +#define ber_bvchr(bv,c) \ + memchr( (bv)->bv_val, (c), (bv)->bv_len ) + +#define BER_BVC(x) { sizeof( (x) ) - 1, (x) } + +LDAP_END_DECL + +#endif + diff --git a/include/ldap.h b/include/ldap.h index d64a0eb38624546548c7654a7d5e9fc5c6c7a607..302802bbc3ed316fa683e23b2bd036a0d54129ba 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -122,6 +122,7 @@ LDAP_BEGIN_DECL /* #define LDAP_OPT_X_TLS_PROTOCOL 0x6007 */ #define LDAP_OPT_X_TLS_CIPHER_SUITE 0x6008 #define LDAP_OPT_X_TLS_RANDOM_FILE 0x6009 +#define LDAP_OPT_X_TLS_SSL_CTX 0x600a #define LDAP_OPT_X_TLS_NEVER 0 #define LDAP_OPT_X_TLS_HARD 1 diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h new file mode 100644 index 0000000000000000000000000000000000000000..8a794e6f057326125f64608536d040219222dea2 --- /dev/null +++ b/include/ldap_pvt.h @@ -0,0 +1,191 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. A copy of this license is available at + * http://www.OpenLDAP.org/license.html or in file LICENSE in the + * top-level directory of the distribution. + */ +/* + * ldap-pvt.h - Header for ldap_pvt_ functions. These are meant to be used + * by the OpenLDAP distribution only. + */ + +#ifndef _LDAP_PVT_H +#define _LDAP_PVT_H 1 + +#include <lber.h> /* get ber_slen_t */ + +LDAP_BEGIN_DECL + +#define LDAP_PROTO_TCP 1 /* ldap:// */ +#define LDAP_PROTO_UDP 2 /* reserved */ +#define LDAP_PROTO_IPC 3 /* ldapi:// */ + +LDAP_F ( int ) +ldap_pvt_url_scheme2proto LDAP_P(( + const char * )); +LDAP_F ( int ) +ldap_pvt_url_scheme2tls LDAP_P(( + const char * )); + +struct ldap_url_desc; /* avoid pulling in <ldap.h> */ + +LDAP_F( int ) +ldap_url_parse_ext LDAP_P(( + LDAP_CONST char *url, + struct ldap_url_desc **ludpp )); + +LDAP_F( char * ) +ldap_pvt_ctime LDAP_P(( + const time_t *tp, + char *buf )); + +LDAP_F( char *) ldap_pvt_get_fqdn LDAP_P(( char * )); + +struct hostent; /* avoid pulling in <netdb.h> */ + +LDAP_F( int ) +ldap_pvt_gethostbyname_a LDAP_P(( + const char *name, + struct hostent *resbuf, + char **buf, + struct hostent **result, + int *herrno_ptr )); + +LDAP_F( int ) +ldap_pvt_gethostbyaddr_a LDAP_P(( + const char *addr, + int len, + int type, + struct hostent *resbuf, + char **buf, + struct hostent **result, + int *herrno_ptr )); + + +/* charray.c */ + +LDAP_F( int ) +ldap_charray_add LDAP_P(( + char ***a, + char *s )); + +LDAP_F( int ) +ldap_charray_merge LDAP_P(( + char ***a, + char **s )); + +LDAP_F( void ) +ldap_charray_free LDAP_P(( char **a )); + +LDAP_F( int ) +ldap_charray_inlist LDAP_P(( + char **a, + char *s )); + +LDAP_F( char ** ) +ldap_charray_dup LDAP_P(( char **a )); + +LDAP_F( char ** ) +ldap_str2charray LDAP_P(( + const char *str, + const char *brkstr )); + +LDAP_F( char * ) +ldap_charray2str LDAP_P(( + char **array, const char* sep )); + +/* url.c */ +LDAP_F (void) ldap_pvt_hex_unescape LDAP_P(( char *s )); + +/* + * these macros assume 'x' is an ASCII x + * and assume the "C" locale + */ +#define LDAP_ASCII(c) (!((c) & 0x80)) +#define LDAP_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define LDAP_DIGIT(c) ((c) >= '0' && (c) <= '9') +#define LDAP_LOWER(c) ((c) >= 'a' && (c) <= 'z') +#define LDAP_UPPER(c) ((c) >= 'A' && (c) <= 'Z') +#define LDAP_ALPHA(c) (LDAP_LOWER(c) || LDAP_UPPER(c)) +#define LDAP_ALNUM(c) (LDAP_ALPHA(c) || LDAP_DIGIT(c)) + +#define LDAP_LDH(c) (LDAP_ALNUM(c) || (c) == '-') + +#define LDAP_HEXLOWER(c) ((c) >= 'a' && (c) <= 'f') +#define LDAP_HEXUPPER(c) ((c) >= 'A' && (c) <= 'F') +#define LDAP_HEX(c) (LDAP_DIGIT(c) || \ + LDAP_HEXLOWER(c) || LDAP_HEXUPPER(c)) + +#ifdef HAVE_CYRUS_SASL +/* cyrus.c */ +struct sasl_security_properties; /* avoid pulling in <sasl.h> */ +LDAP_F (int) ldap_pvt_sasl_secprops LDAP_P(( + const char *in, + struct sasl_security_properties *secprops )); + +LDAP_F (void *) ldap_pvt_sasl_mutex_new LDAP_P((void)); +LDAP_F (int) ldap_pvt_sasl_mutex_lock LDAP_P((void *mutex)); +LDAP_F (int) ldap_pvt_sasl_mutex_unlock LDAP_P((void *mutex)); +LDAP_F (void) ldap_pvt_sasl_mutex_dispose LDAP_P((void *mutex)); + +struct sockbuf; /* avoid pulling in <lber.h> */ +LDAP_F (int) ldap_pvt_sasl_install LDAP_P(( struct sockbuf *, void * )); +#endif /* HAVE_CYRUS_SASL */ + +#define LDAP_PVT_SASL_LOCAL_SSF 71 /* SSF for Unix Domain Sockets */ + +struct ldap; + +LDAP_F (int) ldap_open_internal_connection LDAP_P(( + struct ldap **ldp, ber_socket_t *fdp )); + +/* search.c */ +LDAP_F( int ) ldap_pvt_put_filter LDAP_P(( + BerElement *ber, + const char *str )); + +LDAP_F( char * ) +ldap_pvt_find_wildcard LDAP_P(( const char *s )); + +LDAP_F( ber_slen_t ) +ldap_pvt_filter_value_unescape LDAP_P(( char *filter )); + +/* string.c */ +LDAP_F( char * ) +ldap_pvt_str2upper LDAP_P(( char *str )); + +LDAP_F( char * ) +ldap_pvt_str2lower LDAP_P(( char *str )); + +/* tls.c */ +LDAP_F (int) ldap_int_tls_config LDAP_P(( struct ldap *ld, + int option, const char *arg )); +LDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldap *ld, + int option, void *arg )); +LDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldap *ld, + int option, void *arg )); + +LDAP_F (void) ldap_pvt_tls_destroy LDAP_P(( void )); +LDAP_F (int) ldap_pvt_tls_init LDAP_P(( void )); +LDAP_F (int) ldap_pvt_tls_init_def_ctx LDAP_P(( void )); +LDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg )); +LDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb )); +LDAP_F (void *) ldap_pvt_tls_sb_ctx LDAP_P(( Sockbuf *sb )); + +LDAP_F (int) ldap_pvt_tls_init_default_ctx LDAP_P(( void )); + +LDAP_F (char *) ldap_pvt_tls_get_peer LDAP_P(( void *ctx )); +LDAP_F (char *) ldap_pvt_tls_get_peer_dn LDAP_P(( void *ctx )); +LDAP_F (int) ldap_pvt_tls_get_strength LDAP_P(( void *ctx )); + +LDAP_END_DECL + +#include "ldap_pvt_uc.h" + +#endif + diff --git a/include/ldap_pvt_uc.h b/include/ldap_pvt_uc.h index 6778628fa6c3a8c680ebbf9e57a46a5c8c33c7a7..6a2e4af2642a38f9075fa1fd59c3c9031d999202 100644 --- a/include/ldap_pvt_uc.h +++ b/include/ldap_pvt_uc.h @@ -84,16 +84,16 @@ LDAP_F (char*) ldap_utf8_strtok( char* sp, const char* sep, char **last); LDAP_V (const char) ldap_utf8_lentab[128]; LDAP_V (const char) ldap_utf8_mintab[32]; -#define LDAP_UTF8_ISASCII(p) ( !(*(unsigned char *)(p) & 0x80 ) ) +#define LDAP_UTF8_ISASCII(p) ( !(*(const unsigned char *)(p) & 0x80 ) ) #define LDAP_UTF8_CHARLEN(p) ( LDAP_UTF8_ISASCII(p) \ - ? 1 : ldap_utf8_lentab[*(unsigned char *)(p) ^ 0x80] ) + ? 1 : ldap_utf8_lentab[*(const unsigned char *)(p) ^ 0x80] ) /* This is like CHARLEN but additionally validates to make sure * the char used the shortest possible encoding. * 'l' is used to temporarily hold the result of CHARLEN. */ #define LDAP_UTF8_CHARLEN2(p, l) ( ( ( l = LDAP_UTF8_CHARLEN( p )) < 3 || \ - ( ldap_utf8_mintab[*(unsigned char *)(p) & 0x1f] & (p)[1] ) ) ? \ + ( ldap_utf8_mintab[*(const unsigned char *)(p) & 0x1f] & (p)[1] ) ) ? \ l : 0 ) #define LDAP_UTF8_OFFSET(p) ( LDAP_UTF8_ISASCII(p) \ @@ -137,23 +137,17 @@ LDAP_LUNICODE_F(void) ucstr2upper( ldap_unicode_t *, ber_len_t ); -#define LDAP_UTF8_CASEFOLD 0x1U #define LDAP_UTF8_NOCASEFOLD 0x0U - -LDAP_LUNICODE_F(char *) UTF8normalize( - struct berval *, - unsigned ); +#define LDAP_UTF8_CASEFOLD 0x1U +#define LDAP_UTF8_ARG1NFC 0x2U +#define LDAP_UTF8_ARG2NFC 0x4U +#define LDAP_UTF8_APPROX 0x8U LDAP_LUNICODE_F(struct berval *) UTF8bvnormalize( struct berval *, struct berval *, unsigned ); -LDAP_LUNICODE_F(int) UTF8normcmp( - const char *, - const char *, - unsigned ); - LDAP_LUNICODE_F(int) UTF8bvnormcmp( struct berval *, struct berval *, diff --git a/include/portable.h.in b/include/portable.h.in index bff4f4f7d0b8bfa6c3ca94bce7f77bfc9c08c777..f2ddab282d6a2b95ee07ded19007146593d95ea8 100644 --- a/include/portable.h.in +++ b/include/portable.h.in @@ -944,6 +944,12 @@ /* define to support dynamic cn=Monitor backend */ #undef SLAPD_MONITOR_DYNAMIC +/* define to support NULL backend */ +#undef SLAPD_NULL + +/* define to support dynamic NULL backend */ +#undef SLAPD_NULL_DYNAMIC + /* define to support PASSWD backend */ #undef SLAPD_PASSWD diff --git a/include/portable.nt b/include/portable.nt new file mode 100644 index 0000000000000000000000000000000000000000..921b3dd20e657737505a4531217c8f11b0be0765 --- /dev/null +++ b/include/portable.nt @@ -0,0 +1,1059 @@ +/* $OpenLDAP$ */ +/* include/portable.nt -- manually updated of MS NT (MS VC5) */ +/* synced with portable.h.in 1.191 */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. A copy of this license is available at + * http://www.OpenLDAP.org/license.html or in file LICENSE in the + * top-level directory of the distribution. + */ + +#ifndef _LDAP_PORTABLE_H +#define _LDAP_PORTABLE_H + +/* end of preamble */ + + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +#define gid_t int + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if your struct stat has st_blksize. */ +/* #undef HAVE_ST_BLKSIZE */ + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to the type of arg1 for select(). */ +/* #undef SELECT_TYPE_ARG1 */ + +/* Define to the type of args 2, 3 and 4 for select(). */ +/* #undef SELECT_TYPE_ARG234 */ + +/* Define to the type of arg5 for select(). */ +/* #undef SELECT_TYPE_ARG5 */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +/* #undef TIME_WITH_SYS_TIME */ + +/* Define if your <sys/time.h> declares struct tm. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +#define uid_t int + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* define this if needed to get reentrant functions */ +#ifndef REENTRANT +/* #undef REENTRANT */ +#endif +#ifndef _REENTRANT +/* #undef _REENTRANT */ +#endif + +/* define this if needed to get threadsafe functions */ +#ifndef THREADSAFE +/* #undef THREADSAFE */ +#endif +#ifndef _THREADSAFE +/* #undef _THREADSAFE */ +#endif +#ifndef THREAD_SAFE +/* #undef THREAD_SAFE */ +#endif +#ifndef _THREAD_SAFE +/* #undef _THREAD_SAFE */ +#endif + +#ifndef _SGI_MP_SOURCE +/* #undef _SGI_MP_SOURCE */ +#endif + +/* These are defined in ldap_features.h */ +/* + LDAP_API_FEATURE_X_OPENLDAP_REENTRANT + LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE + LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS +*/ + +/* These are defined in lber_types.h */ +/* + LBER_INT_T + LBER_LEN_T + LBER_SOCKET_T + LBER_TAG_T +*/ + +/* Define if you have the bcopy function. */ +/* #undef HAVE_BCOPY */ + +/* Define if you have the chroot function. */ +/* #undef HAVE_CHROOT */ + +/* Define if you have the closesocket function. */ +#define HAVE_CLOSESOCKET 1 + +/* Define if you have the ctime_r function. */ +/* #undef HAVE_CTIME_R */ + +/* Define if you have the endgrent function. */ +/* #undef HAVE_ENDGRENT */ + +/* Define if you have the endpwent function. */ +/* #undef HAVE_ENDPWENT */ + +/* Define if you have the fcntl function. */ +/* #undef HAVE_FCNTL */ + +/* Define if you have the flock function. */ +/* #undef HAVE_FLOCK */ + +/* Define if you have the gai_strerror function. */ +/* #undef HAVE_GAI_STRERROR */ + +/* Define if you have the getaddrinfo function. */ +/* #undef HAVE_GETADDRINFO */ + +/* Define if you have the getdtablesize function. */ +/* #undef HAVE_GETDTABLESIZE */ + +/* Define if you have the getgrgid function. */ +/* #undef HAVE_GETGRGID */ + +/* Define if you have the gethostbyaddr_r function. */ +/* #undef HAVE_GETHOSTBYADDR_R */ + +/* Define if you have the gethostbyname_r function. */ +/* #undef HAVE_GETHOSTBYNAME_R */ + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the getopt function. */ +/* #undef HAVE_GETOPT */ + +/* Define if you have the getpass function. */ +/* #undef HAVE_GETPASS */ + +/* Define if you have the getpassphrase function. */ +/* #undef HAVE_GETPASSPHRASE */ + +/* Define if you have the getpwnam function. */ +/* #undef HAVE_GETPWNAM */ + +/* Define if you have the getpwuid function. */ +/* #undef HAVE_GETPWUID */ + +/* Define if you have the getspnam function. */ +/* #undef HAVE_GETSPNAM */ + +/* Define if you have the gettimeofday function. */ +/* #undef HAVE_GETTIMEOFDAY */ + +/* Define if you have the inet_ntop function. */ +/* #undef HAVE_INET_NTOP */ + +/* Define if you have the initgroups function. */ +/* #undef HAVE_INITGROUPS */ + +/* Define if you have the lockf function. */ +/* #undef HAVE_LOCKF */ + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the mkstemp function. */ +/* #undef HAVE_MKSTEMP */ + +/* Define if you have the mktemp function. */ +#define HAVE_MKTEMP 1 + +/* Define if you have the pipe function. */ +/* #undef HAVE_PIPE */ + +/* Define if you have the pthread_getconcurrency function. */ +/* #undef HAVE_PTHREAD_GETCONCURRENCY */ + +/* Define if you have the pthread_kill function. */ +/* #undef HAVE_PTHREAD_KILL */ + +/* Define if you have the pthread_kill_other_threads_np function. */ +/* #undef HAVE_PTHREAD_KILL_OTHER_THREADS_NP */ + +/* Define if you have the pthread_rwlock_destroy function. */ +/* #undef HAVE_PTHREAD_RWLOCK_DESTROY */ + +/* Define if you have the pthread_setconcurrency function. */ +/* #undef HAVE_PTHREAD_SETCONCURRENCY */ + +/* Define if you have the pthread_yield function. */ +/* #undef HAVE_PTHREAD_YIELD */ + +/* Define if you have the read function. */ +#define HAVE_READ 1 + +/* Define if you have the recv function. */ +/* #undef HAVE_RECV */ + +/* Define if you have the recvfrom function. */ +/* #undef HAVE_RECVFROM */ + +/* Define if you have the sched_yield function. */ +/* #undef HAVE_SCHED_YIELD */ + +/* Define if you have the send function. */ +/* #undef HAVE_SEND */ + +/* Define if you have the sendto function. */ +/* #undef HAVE_SENDTO */ + +/* Define if you have the setegid function. */ +/* #undef HAVE_SETEGID */ + +/* Define if you have the seteuid function. */ +/* #undef HAVE_SETEUID */ + +/* Define if you have the setgid function. */ +/* #undef HAVE_SETGID */ + +/* Define if you have the setpwfile function. */ +/* #undef HAVE_SETPWFILE */ + +/* Define if you have the setsid function. */ +/* #undef HAVE_SETSID */ + +/* Define if you have the setuid function. */ +/* #undef HAVE_SETUID */ + +/* Define if you have the sigaction function. */ +/* #undef HAVE_SIGACTION */ + +/* Define if you have the signal function. */ +#define HAVE_SIGNAL 1 + +/* Define if you have the sigset function. */ +/* #undef HAVE_SIGSET */ + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strpbrk function. */ +#define HAVE_STRPBRK 1 + +/* Define if you have the strrchr function. */ +#define HAVE_STRRCHR 1 + +/* Define if you have the strsep function. */ +/* #undef HAVE_STRSEP */ + +/* Define if you have the strspn function. */ +#define HAVE_STRSPN 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the sysconf function. */ +/* #undef HAVE_SYSCONF */ + +/* Define if you have the thr_getconcurrency function. */ +/* #undef HAVE_THR_GETCONCURRENCY */ + +/* Define if you have the thr_setconcurrency function. */ +/* #undef HAVE_THR_SETCONCURRENCY */ + +/* Define if you have the thr_yield function. */ +/* #undef HAVE_THR_YIELD */ + +/* Define if you have the usleep function. */ +/* #undef HAVE_USLEEP */ + +/* Define if you have the vsnprintf function. */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have the vsprintf function. */ +#define HAVE_VSPRINTF 1 + +/* Define if you have the wait4 function. */ +/* #undef HAVE_WAIT4 */ + +/* Define if you have the waitpid function. */ +/* #undef HAVE_WAITPID */ + +/* Define if you have the write function. */ +#define HAVE_WRITE 1 + +/* Define if you have the <arpa/inet.h> header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define if you have the <arpa/nameser.h> header file. */ +/* #undef HAVE_ARPA_NAMESER_H */ + +/* Define if you have the <assert.h> header file. */ +#define HAVE_ASSERT_H 1 + +/* Define if you have the <conio.h> header file. */ +#define HAVE_CONIO_H 1 + +/* Define if you have the <crypt.h> header file. */ +/* #undef HAVE_CRYPT_H */ + +/* Define if you have the <cthread.h> header file. */ +/* #undef HAVE_CTHREAD_H */ + +/* Define if you have the <db.h> header file. */ +#define HAVE_DB_H 1 + +/* Define if you have the <db_185.h> header file. */ +/* #undef HAVE_DB_185_H */ + +/* Define if you have the <des.h> header file. */ +/* #undef HAVE_DES_H */ + +/* Define if you have the <direct.h> header file. */ +#define HAVE_DIRECT_H 1 + +/* Define if you have the <dirent.h> header file. */ +/* #undef HAVE_DIRENT_H */ + +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the <filio.h> header file. */ +/* #undef HAVE_FILIO_H */ + +/* Define if you have the <gdbm.h> header file. */ +/* #undef HAVE_GDBM_H */ + +/* Define if you have the <getopt.h> header file. */ +/* #undef HAVE_GETOPT_H */ + +/* Define if you have the <grp.h> header file. */ +/* #undef HAVE_GRP_H */ + +/* Define if you have the <heim_err.h> header file. */ +/* #undef HAVE_HEIM_ERR_H */ + +/* Define if you have the <io.h> header file. */ +#define HAVE_IO_H 1 + +/* Define if you have the <kerberosIV/des.h> header file. */ +/* #undef HAVE_KERBEROSIV_DES_H */ + +/* Define if you have the <kerberosIV/krb.h> header file. */ +/* #undef HAVE_KERBEROSIV_KRB_H */ + +/* Define if you have the <krb-archaeology.h> header file. */ +/* #undef HAVE_KRB_ARCHAEOLOGY_H */ + +/* Define if you have the <krb.h> header file. */ +/* #undef HAVE_KRB_H */ + +/* Define if you have the <krb5.h> header file. */ +/* #undef HAVE_KRB5_H */ + +/* Define if you have the <libutil.h> header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the <locale.h> header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you have the <ltdl.h> header file. */ +/* #undef HAVE_LTDL_H */ + +/* Define if you have the <lwp/lwp.h> header file. */ +/* #undef HAVE_LWP_LWP_H */ + +/* Define if you have the <mach/cthreads.h> header file. */ +/* #undef HAVE_MACH_CTHREADS_H */ + +/* Define if you have the <malloc.h> header file. */ +#define HAVE_MALLOC_H 1 + +/* Define if you have the <mdbm.h> header file. */ +/* #undef HAVE_MDBM_H */ + +/* Define if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the <minix/config.h> header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define if you have the <ncurses.h> header file. */ +/* #undef HAVE_NCURSES_H */ + +/* Define if you have the <ndbm.h> header file. */ +/* #undef HAVE_NDBM_H */ + +/* Define if you have the <ndir.h> header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the <netinet/tcp.h> header file. */ +/* #undef HAVE_NETINET_TCP_H */ + +/* Define if you have the <openssl/ssl.h> header file. */ +/* #undef HAVE_OPENSSL_SSL_H */ + +/* Define if you have the <process.h> header file. */ +#define HAVE_PROCESS_H 1 + +/* Define if you have the <psap.h> header file. */ +/* #undef HAVE_PSAP_H */ + +/* Define if you have the <pth.h> header file. */ +/* #undef HAVE_PTH_H */ + +/* Define if you have the <pthread.h> header file. */ +/* #undef HAVE_PTHREAD_H */ + +/* Define if you have the <pwd.h> header file. */ +/* #undef HAVE_PWD_H */ + +/* Define if you have the <readline/history.h> header file. */ +/* #undef HAVE_READLINE_HISTORY_H */ + +/* Define if you have the <readline/readline.h> header file. */ +/* #undef HAVE_READLINE_READLINE_H */ + +/* Define if you have the <regex.h> header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the <resolv.h> header file. */ +/* #undef HAVE_RESOLV_H */ + +/* Define if you have the <sasl.h> header file. */ +#define HAVE_SASL_H 1 + +/* Define if you have the <sched.h> header file. */ +/* #undef HAVE_SCHED_H */ + +/* Define if you have the <sgtty.h> header file. */ +/* #undef HAVE_SGTTY_H */ + +/* Define if you have the <shadow.h> header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define if you have the <slp.h> header file. */ +/* #undef HAVE_SLP_H */ + +/* Define if you have the <ssl.h> header file. */ +/* #undef HAVE_SSL_H */ + +/* Define if you have the <stddef.h> header file. */ +#define HAVE_STDDEF_H 1 + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <strings.h> header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define if you have the <synch.h> header file. */ +/* #undef HAVE_SYNCH_H */ + +/* Define if you have the <sys/dir.h> header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the <sys/errno.h> header file. */ +/* #undef HAVE_SYS_ERRNO_H */ + +/* Define if you have the <sys/file.h> header file. */ +/* #undef HAVE_SYS_FILE_H */ + +/* Define if you have the <sys/filio.h> header file. */ +/* #undef HAVE_SYS_FILIO_H */ + +/* Define if you have the <sys/ioctl.h> header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define if you have the <sys/ndir.h> header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the <sys/param.h> header file. */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Define if you have the <sys/queue.h> header file. */ +/* #undef HAVE_SYS_QUEUE_H */ + +/* Define if you have the <sys/resource.h> header file. */ +/* #undef HAVE_SYS_RESOURCE_H */ + +/* Define if you have the <sys/select.h> header file. */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define if you have the <sys/socket.h> header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define if you have the <sys/syslog.h> header file. */ +/* #undef HAVE_SYS_SYSLOG_H */ + +/* Define if you have the <sys/time.h> header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the <sys/un.h> header file. */ +/* #undef HAVE_SYS_UN_H */ + +/* Define if you have the <sysexits.h> header file. */ +/* #undef HAVE_SYSEXITS_H */ + +/* Define if you have the <syslog.h> header file. */ +/* #undef HAVE_SYSLOG_H */ + +/* Define if you have the <tcl.h> header file. */ +/* #undef HAVE_TCL_H */ + +/* Define if you have the <tcpd.h> header file. */ +/* #undef HAVE_TCPD_H */ + +/* Define if you have the <termcap.h> header file. */ +/* #undef HAVE_TERMCAP_H */ + +/* Define if you have the <termios.h> header file. */ +/* #undef HAVE_TERMIOS_H */ + +/* Define if you have the <thread.h> header file. */ +/* #undef HAVE_THREAD_H */ + +/* Define if you have the <unistd.h> header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define if you have the <winsock.h> header file. */ +#define HAVE_WINSOCK_H 1 + +/* Define if you have the <winsock2.h> header file. */ +#define HAVE_WINSOCK2_H 1 + +/* Define if you have the V3 library (-lV3). */ +/* #undef HAVE_LIBV3 */ + +/* Define if you have the bind library (-lbind). */ +/* #undef HAVE_LIBBIND */ + +/* Define if you have the dl library (-ldl). */ +/* #undef HAVE_LIBDL */ + +/* Define if you have the gen library (-lgen). */ +/* #undef HAVE_LIBGEN */ + +/* Define if you have the inet library (-linet). */ +/* #undef HAVE_LIBINET */ + +/* Define if you have the net library (-lnet). */ +/* #undef HAVE_LIBNET */ + +/* Define if you have the nsl library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define if you have the nsl_s library (-lnsl_s). */ +/* #undef HAVE_LIBNSL_S */ + +/* Define if you have the resolv library (-lresolv). */ +/* #undef HAVE_LIBRESOLV */ + +/* Define if you have the socket library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Package */ +#define OPENLDAP_PACKAGE "OpenLDAP" + +/* Version */ +#define OPENLDAP_VERSION "2.X" + +/* Version */ +/* #undef LDAP_VENDOR_VERSION */ + +/* Major */ +/* #undef LDAP_VENDOR_VERSION_MAJOR */ + +/* Minor */ +/* #undef LDAP_VENDOR_VERSION_MINOR */ + +/* Patch */ +/* #undef LDAP_VENDOR_VERSION_PATCH */ + +/* define this if you have mkversion */ +/* #undef HAVE_MKVERSION */ + +/* defined to be the EXE extension */ +#define EXEEXT ".exe" + +/* define if you have AIX security lib */ +/* #undef HAVE_AIX_SECURITY */ + +/* define if you have libtool -ltdl */ +/* #undef HAVE_LIBLTDL */ + +/* define if system uses EBCDIC instead of ASCII */ +/* #undef HAVE_EBCDIC */ + +/* Define if TIOCGWINSZ requires sys/ioctl.h */ +/* #undef GWINSZ_IN_SYS_IOCTL */ + +/* define if you have POSIX termios */ +/* #undef HAVE_POSIX_TERMIOS */ + +/* define if you have winsock */ +#define HAVE_WINSOCK 1 + +/* define if you have winsock2 */ +#define HAVE_WINSOCK2 1 + +/* define if you have res_query() */ +/* #undef HAVE_RES_QUERY */ + +/* define if you have HEIMDAL Kerberos */ +/* #undef HAVE_HEIMDAL_KERBEROS */ + +/* define if you have Kerberos V */ +/* #undef HAVE_KRB5 */ + +/* define if you have Kerberos V with IV support */ +/* #undef HAVE_KRB425 */ + +/* define if you have Kerberos IV */ +/* #undef HAVE_KRB4 */ + +/* define if you have Kerberos des_debug */ +/* #undef HAVE_DES_DEBUG */ + +/* define if you have Kerberos IV */ +/* #undef HAVE_KRB4 */ + +/* define if you have Kth Kerberos */ +/* #undef HAVE_KTH_KERBEROS */ + +/* define if you have Kerberos */ +/* #undef HAVE_KERBEROS */ + +/* define if you have SSLeay or OpenSSL */ +/* #undef HAVE_SSLEAY */ + +/* define if you have RSAref */ +/* #undef HAVE_RSAREF */ + +/* define if you have TLS */ +/* #undef HAVE_TLS */ + +/* define to support LAN Manager passwords */ +/* #undef SLAPD_LMHASH */ + +/* set to the number of arguments ctime_r() expects */ +/* #undef CTIME_R_NARGS */ + +/* set to the number of arguments gethostbyname_r() expects */ +/* #undef GETHOSTBYNAME_R_NARGS */ + +/* set to the number of arguments gethostbyaddr_r() expects */ +/* #undef GETHOSTBYADDR_R_NARGS */ + +/* if you have NT Threads */ +/* #undef HAVE_NT_THREADS */ + +/* if you have NT Service Manager */ +/* #undef HAVE_NT_SERVICE_MANAGER */ + +/* if you have NT Event Log */ +/* #undef HAVE_NT_EVENT_LOG */ + +/* define if pthreads API compatible with final spec */ +/* #undef HAVE_PTHREADS_FINAL */ + +/* define if pthreads API compatible with draft4 spec */ +/* #undef HAVE_PTHREADS_D4 */ + +/* if you have LinuxThreads */ +/* #undef HAVE_LINUX_THREADS */ + +/* define if you have POSIX Threads */ +/* #undef HAVE_PTHREADS */ + +/* Define if you have the sched_yield function. */ +/* #undef HAVE_SCHED_YIELD */ + +/* define if you have pthread_detach function */ +/* #undef HAVE_PTHREAD_DETACH */ + +/* define if you have Mach Cthreads */ +/* #undef HAVE_MACH_CTHREADS */ + +/* if you have GNU Pth */ +/* #undef HAVE_GNU_PTH */ + +/* if you have Solaris LWP (thr) package */ +/* #undef HAVE_THR */ + +/* if you have SunOS LWP package */ +/* #undef HAVE_LWP */ + +/* define if select implicitly yields */ +#define HAVE_YIELDING_SELECT 1 + +/* if you have LinuxThreads */ +/* #undef HAVE_LINUX_THREADS */ + +/* define if you have (or want) no threads */ +/* #undef NO_THREADS */ + +/* define if Berkeley DB has DB_THREAD support */ +/* #undef HAVE_BERKELEY_DB_THREAD */ + +/* define this if Berkeley DB is available */ +#define HAVE_BERKELEY_DB 1 + +/* define this to use DBHASH w/ LDBM backend */ +/* #undef LDBM_USE_DBHASH */ + +/* define this to use DBBTREE w/ LDBM backend */ +#define LDBM_USE_DBBTREE 1 + +/* define if MDBM is available */ +/* #undef HAVE_MDBM */ + +/* define if GNU DBM is available */ +/* #undef HAVE_GDBM */ + +/* define if NDBM is available */ +/* #undef HAVE_NDBM */ + +/* define if LDAP libs are dynamic */ +/* #undef LDAP_LIBS_DYNAMIC */ + +/* define if you have -lwrap */ +/* #undef HAVE_TCPD */ + +/* define if you have -ltermcap */ +/* #undef HAVE_TERMCAP */ + +/* define if you have -lncurses */ +/* #undef HAVE_NCURSES */ + +/* define if you have no termcap support */ +#define NO_TERMCAP 1 + +/* define if you have Cyrus SASL */ +#define HAVE_CYRUS_SASL 1 + +/* set to urandom device */ +/* #undef URANDOM_DEVICE */ + +/* define if you actually have FreeBSD fetch(3) */ +/* #undef HAVE_FETCH */ + +/* define if you have -lreadline */ +/* #undef HAVE_READLINE */ + +/* define if crypt(3) is available */ +/* #undef HAVE_CRYPT */ + +/* define if setproctitle(3) is available */ +/* #undef HAVE_SETPROCTITLE */ + +/* define if you have -lslp */ +/* #undef HAVE_SLP */ + +/* Define to `int' if <sys/types.h> does not define. */ +#define mode_t int + +/* Define to `long' if <sys/types.h> does not define. */ +/* #undef off_t */ + +/* Define to `int' if <sys/types.h> does not define. */ +#define pid_t int + +/* Define if system has ptrdiff_t type */ +#define HAVE_PTRDIFF_T 1 + +/* Define to `unsigned' if <sys/types.h> does not define. */ +/* #undef size_t */ + +/* Define to `signed int' if <sys/types.h> does not define. */ +/* #undef ssize_t signed int */ + +/* Define to `char *' if <sys/types.h> does not define. */ +#define caddr_t char * + +/* define to int if socklen_t is not available */ +#define socklen_t int + +/* define to atomic type if sig_atomic_t is not available */ +/* #undef sig_atomic_t */ + +/* define if struct passwd has pw_gecos */ +/* #undef HAVE_PW_GECOS */ + +/* define if struct passwd has pw_passwd */ +/* #undef HAVE_PW_PASSWD */ + +/* define if toupper() requires islower() */ +#define C_UPPER_LOWER 1 + +/* define as empty if volatile is not supported */ +/* #undef volatile */ + +/* define if cross compiling */ +/* #undef CROSS_COMPILING */ + +/* The number of bytes in type short */ +#define SIZEOF_SHORT 2 + +/* The number of bytes in type int */ +#define SIZEOF_INT 4 + +/* The number of bytes in type long */ +#define SIZEOF_LONG 4 + +/* define to you inet_aton(3) is available */ +/* #undef HAVE_INET_ATON */ + +/* if you have spawnlp() */ +#define HAVE_SPAWNLP 1 + +/* define to snprintf routine */ +#define snprintf _snprintf + +/* define to vsnprintf routine */ +#define vsnprintf _vsnprintf + +/* define if sys_errlist is not declared in stdio.h or errno.h */ +/* #undef DECL_SYS_ERRLIST */ + +/* define if you actually have sys_errlist in your libs */ +#define HAVE_SYS_ERRLIST 1 + +/* define this to add debugging code */ +/* #undef LDAP_DEBUG */ + +/* define this to add syslog code */ +/* #undef LDAP_SYSLOG */ + +/* define this to remove -lldap cache support */ +/* #undef LDAP_NOCACHE */ + +/* define this for LDAP process title support */ +/* #undef LDAP_PROCTITLE */ + +/* define to support PF_LOCAL */ +/* #undef LDAP_PF_LOCAL */ + +/* define to support PF_INET6 */ +/* #undef LDAP_PF_INET6 */ + +/* define to support cleartext passwords */ +#define SLAPD_CLEARTEXT 1 + +/* define to support crypt(3) passwords */ +/* #undef SLAPD_CRYPT */ + +/* define to support Kerberos passwords */ +/* #undef SLAPD_KPASSWD */ + +/* define to support SASL passwords */ +/* #undef SLAPD_SPASSWD */ + +/* define to support phonetic */ +/* #undef SLAPD_PHONETIC */ + +/* define to support reverse lookups */ +/* #undef SLAPD_RLOOKUPS */ + +/* define to support per-object ACIs */ +/* #undef SLAPD_ACI_ENABLED */ + +/* define to support modules */ +/* #undef SLAPD_MODULES */ + +/* define to support BDB backend */ +#define SLAPD_BDB 1 + +/* define to support dynamic BDB backend */ +/* #undef SLAPD_BDB_DYNAMIC */ + +/* define to support DNS SRV backend */ +/* #undef SLAPD_DNSSRV */ + +/* define to support dynamic DNS SRV backend */ +/* #undef SLAPD_DNSSRV_DYNAMIC */ + +/* define to support LDAP backend */ +/* #undef SLAPD_LDAP */ + +/* define to support dynamic LDAP backend */ +/* #undef SLAPD_LDAP_DYNAMIC */ + +/* define to support LDBM backend */ +/* #undef SLAPD_LDBM 1 */ + +/* define to support dynamic LDBM backend */ +/* #undef SLAPD_LDBM_DYNAMIC */ + +/* define to support LDAP Metadirectory backend */ +/* #undef SLAPD_META */ + +/* define to support dynamic LDAP Metadirectory backend */ +/* #undef SLAPD_META_DYNAMIC */ + +/* define to support cn=Monitor backend */ +#define SLAPD_MONITOR 1 + +/* define to support dynamic cn=Monitor backend */ +/* #undef SLAPD_MONITOR_DYNAMIC */ + +/* define to support NULL backend */ +/* #undef SLAPD_NULL */ + +/* define to support dynamic NULL backend */ +/* #undef SLAPD_NULL_DYNAMIC */ + +/* define to support PASSWD backend */ +/* #undef SLAPD_PASSWD */ + +/* define to support dynamic PASSWD backend */ +/* #undef SLAPD_PASSWD_DYNAMIC */ + +/* define to support PERL backend */ +/* #undef SLAPD_PERL */ + +/* define to support dynamic PERL backend */ +/* #undef SLAPD_PERL_DYNAMIC */ + +/* define to support SHELL backend */ +/* #undef SLAPD_SHELL */ + +/* define to support dynamic SHELL backend */ +/* #undef SLAPD_SHELL_DYNAMIC */ + +/* define to support TCL backend */ +/* #undef SLAPD_TCL */ + +/* define to support dynamic TCL backend */ +/* #undef SLAPD_TCL_DYNAMIC */ + +/* define to support SQL backend */ +/* #undef SLAPD_SQL */ + +/* define to support dynamic SQL backend */ +/* #undef SLAPD_SQL_DYNAMIC */ + +/* define to enable rewriting in back-ldap and back-meta */ +/* #undef ENABLE_REWRITE */ + + +/* begin of postamble */ + +#ifdef _WIN32 + /* don't suck in all of the win32 api */ +# define WIN32_LEAN_AND_MEAN 1 + +#if !defined(_WINNT) && !defined(_WIN95) +#define _WINNT +#endif + +#if defined( _MT ) && defined( _WINNT ) +#define HAVE_NT_THREADS 1 +#else +#define NO_THREADS 1 +#endif + +#ifdef HAVE_NT_THREADS +/* enable WINNT specific features only if we have NT THREADS */ +#define HAVE_NT_SERVICE_MANAGER 1 +#define HAVE_NT_EVENT_LOG 1 +#endif + +#if defined( _DEBUG ) && !defined( LDAP_DEBUG ) +/* #define LDAP_MEMORY_DEBUG 1 */ +#define LDAP_DEBUG 1 +#endif + +#define strcasecmp stricmp +#define strncasecmp strnicmp + +/* define type for ssize_t */ +typedef signed int ssize_t; + +#endif /* _WIN32 */ + +#ifndef LDAP_NEEDS_PROTOTYPES +/* force LDAP_P to always include prototypes */ +#define LDAP_NEEDS_PROTOTYPES 1 +#endif + +#ifdef HAVE_STDDEF_H +# include <stddef.h> +#endif + +#if defined(LDAP_DEVEL) && !defined(LDAP_TEST) +#define LDAP_TEST +#endif +#if defined(LDAP_TEST) && !defined(LDAP_DEBUG) +#define LDAP_DEBUG +#endif + +#include "ldap_cdefs.h" +#include "ldap_features.h" + +#include "ac/assert.h" + +#endif /* _LDAP_PORTABLE_H */ diff --git a/libraries/liblber/bprint.c b/libraries/liblber/bprint.c index e4b6fd27ea2b9ee5def85b5ab39d3c5eef286e19..a6ae8ce7ed68337196edc622c1382071d440ba36 100644 --- a/libraries/liblber/bprint.c +++ b/libraries/liblber/bprint.c @@ -1,60 +1,388 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <ctype.h> -#include "lber.h" + +#include <ac/ctype.h> +#include <ac/stdarg.h> +#include <ac/string.h> + +#include "lber-int.h" + +#define ber_log_check(errlvl, loglvl) ((errlvl) & (loglvl)) + +BER_LOG_FN ber_int_log_proc = NULL; /* - * Print arbitrary stuff, for debugging. + * We don't just set ber_pvt_err_file to stderr here, because in NT, + * stderr is a symbol imported from a DLL. As such, the compiler + * doesn't recognize the symbol as having a constant address. Thus + * we set ber_pvt_err_file to stderr later, when it first gets + * referenced. */ +FILE *ber_pvt_err_file = NULL; -#ifdef LDAP_DEBUG +/* + * ber errno + */ +BER_ERRNO_FN ber_int_errno_fn = NULL; -#ifndef NO_USERINTERFACE -#define BPLEN 48 +int * ber_errno_addr(void) +{ + static int ber_int_errno = LBER_ERROR_NONE; -void -lber_bprint( char *data, int len ) + if( ber_int_errno_fn ) { + return (*ber_int_errno_fn)(); + } + + return &ber_int_errno; +} + +/* + * Print stuff + */ +void ber_error_print( LDAP_CONST char *data ) { - static char hexdig[] = "0123456789abcdef"; - char out[ BPLEN ]; - int i = 0; + assert( data != NULL ); - memset( out, 0, BPLEN ); - for ( ;; ) { - if ( len < 1 ) { - fprintf( stderr, "\t%s\n", ( i == 0 ) ? "(end)" : out ); - break; + if (!ber_pvt_err_file) ber_pvt_err_file = stderr; + + fputs( data, ber_pvt_err_file ); + + /* Print to both streams */ + if (ber_pvt_err_file != stderr) { + fputs( data, stderr ); + fflush( stderr ); } -#ifndef HEX - if ( isgraph( (unsigned char)*data )) { - out[ i ] = ' '; - out[ i+1 ] = *data; - } else { + fflush( ber_pvt_err_file ); +} + +BER_LOG_PRINT_FN ber_pvt_log_print = ber_error_print; + +/* + * lber log + */ + +int ber_pvt_log_output( + const char *subsystem, + int level, + const char *fmt, + ... ) +{ + char buf[ 1024 ]; + va_list vl; + va_start( vl, fmt ); + + if ( ber_int_log_proc != NULL ) + { + ber_int_log_proc( ber_pvt_err_file, subsystem, level, fmt, vl ); + } + else + { + int level; + ber_get_option( NULL, LBER_OPT_BER_DEBUG, &level ); +#ifdef HAVE_VSNPRINTF + buf[sizeof(buf) - 1] = '\0'; + vsnprintf( buf, sizeof(buf)-1, fmt, vl ); +#elif HAVE_VSPRINTF + vsprintf( buf, fmt, vl ); /* hope it's not too long */ +#else + /* use doprnt() */ +#error "vsprintf() required."; +#endif + if ( ber_log_check( LDAP_DEBUG_BER, level ) ) + (*ber_pvt_log_print)( buf ); + } + va_end(vl); + + return 1; +} + +int ber_pvt_log_printf( int errlvl, int loglvl, const char *fmt, ... ) +{ + char buf[ 1024 ]; + va_list ap; + + assert( fmt != NULL ); + + if ( !ber_log_check( errlvl, loglvl )) { + return 0; + } + + va_start( ap, fmt ); + +#ifdef HAVE_VSNPRINTF + buf[sizeof(buf) - 1] = '\0'; + vsnprintf( buf, sizeof(buf)-1, fmt, ap ); +#elif HAVE_VSPRINTF + vsprintf( buf, fmt, ap ); /* hope it's not too long */ +#else + /* use doprnt() */ +#error "vsprintf() required." #endif - out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ]; - out[ i+1 ] = hexdig[ *data & 0x0f ]; -#ifndef HEX + + va_end(ap); + + (*ber_pvt_log_print)( buf ); + return 1; +} + +#if 0 +static int ber_log_puts(int errlvl, int loglvl, char *buf) +{ + assert( buf != NULL ); + + if ( !ber_log_check( errlvl, loglvl )) { + return 0; } + + (*ber_pvt_log_print)( buf ); + return 1; +} #endif - i += 2; - len--; - data++; - if ( i > BPLEN - 2 ) { - fprintf( stderr, "\t%s\n", out ); - memset( out, 0, BPLEN ); - i = 0; - continue; +/* + * Print arbitrary stuff, for debugging. + */ + +int +ber_log_bprint(int errlvl, + int loglvl, + const char *data, + ber_len_t len ) +{ + assert( data != NULL ); + + if ( !ber_log_check( errlvl, loglvl )) { + return 0; } - out[ i++ ] = ' '; - } + + ber_bprint(data, len); + return 1; } -#else /* NO_USERINTERFACE */ + void -lber_bprint( char *data, int len ) +ber_bprint( + LDAP_CONST char *data, + ber_len_t len ) { + static const char hexdig[] = "0123456789abcdef"; +#define BP_OFFSET 9 +#define BP_GRAPH 60 +#define BP_LEN 80 + char line[ BP_LEN ]; + ber_len_t i; + + assert( data != NULL ); + + /* in case len is zero */ + line[0] = '\n'; + line[1] = '\0'; + + for ( i = 0 ; i < len ; i++ ) { + int n = i % 16; + unsigned off; + + if( !n ) { + if( i ) (*ber_pvt_log_print)( line ); + memset( line, ' ', sizeof(line)-2 ); + line[sizeof(line)-2] = '\n'; + line[sizeof(line)-1] = '\0'; + + off = i % 0x0ffffU; + + line[ 2 ] = hexdig[ 0x0f & (off >> 12) ]; + line[ 3 ] = hexdig[ 0x0f & (off >> 8) ]; + line[ 4 ] = hexdig[ 0x0f & (off >> 4) ]; + line[ 5 ] = hexdig[ 0x0f & off ]; + line[ 6 ] = ':'; + } + + off = BP_OFFSET + n*3 + ((n >= 8)?1:0); + line[ off ] = hexdig[ 0x0f & ( data[i] >> 4 ) ]; + line[ off+1 ] = hexdig[ 0x0f & data[i] ]; + + off = BP_GRAPH + n + ((n >= 8)?1:0); + + if ( isprint( (unsigned char) data[i] )) { + line[ BP_GRAPH + n ] = data[i]; + } else { + line[ BP_GRAPH + n ] = '.'; + } + } + + (*ber_pvt_log_print)( line ); } -#endif /* NO_USERINTERFACE */ +#ifdef NEW_LOGGING +int ber_output_dump( + const char *subsys, + int level, + BerElement *ber, + int inout ) +{ + static const char hexdig[] = "0123456789abcdef"; + char buf[132]; + ber_len_t len; + char line[ BP_LEN ]; + ber_len_t i; + char *data = ber->ber_ptr; + + if ( inout == 1 ) { + len = ber_pvt_ber_remaining(ber); + } else { + len = ber_pvt_ber_write(ber); + } + + sprintf( buf, "ber_dump: buf=0x%08lx ptr=0x%08lx end=0x%08lx len=%ld\n", + (long) ber->ber_buf, + (long) ber->ber_ptr, + (long) ber->ber_end, + (long) len ); + + (void) ber_pvt_log_output( subsys, level, "%s", buf ); + +#define BP_OFFSET 9 +#define BP_GRAPH 60 +#define BP_LEN 80 + + assert( data != NULL ); + + /* in case len is zero */ + line[0] = '\n'; + line[1] = '\0'; + + for ( i = 0 ; i < len ; i++ ) { + int n = i % 16; + unsigned off; + + if( !n ) { + if( i ) { + (void) ber_pvt_log_output( subsys, level, "%s", line ); + } + memset( line, ' ', sizeof(line)-2 ); + line[sizeof(line)-2] = '\n'; + line[sizeof(line)-1] = '\0'; + + off = i % 0x0ffffU; + + line[ 2 ] = hexdig[ 0x0f & (off >> 12) ]; + line[ 3 ] = hexdig[ 0x0f & (off >> 8) ]; + line[ 4 ] = hexdig[ 0x0f & (off >> 4) ]; + line[ 5 ] = hexdig[ 0x0f & off ]; + line[ 6 ] = ':'; + } + + off = BP_OFFSET + n*3 + ((n >= 8)?1:0); + line[ off ] = hexdig[ 0x0f & ( data[i] >> 4 ) ]; + line[ off+1 ] = hexdig[ 0x0f & data[i] ]; + + off = BP_GRAPH + n + ((n >= 8)?1:0); + + if ( isprint( data[i] )) { + line[ BP_GRAPH + n ] = data[i]; + } else { + line[ BP_GRAPH + n ] = '.'; + } + } + + return ber_pvt_log_output( subsys, level, "%s", line ); +} #endif + +int +ber_log_dump( + int errlvl, + int loglvl, + BerElement *ber, + int inout ) +{ + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( !ber_log_check( errlvl, loglvl )) { + return 0; + } + + ber_dump(ber, inout); + return 1; +} + +void +ber_dump( + BerElement *ber, + int inout ) +{ + char buf[132]; + ber_len_t len; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( inout == 1 ) { + len = ber_pvt_ber_remaining(ber); + } else { + len = ber_pvt_ber_write(ber); + } + + sprintf( buf, "ber_dump: buf=0x%08lx ptr=0x%08lx end=0x%08lx len=%ld\n", + (long) ber->ber_buf, + (long) ber->ber_ptr, + (long) ber->ber_end, + (long) len ); + + (void) (*ber_pvt_log_print)( buf ); + + ber_bprint( ber->ber_ptr, len ); +} + +int +ber_log_sos_dump( + int errlvl, + int loglvl, + Seqorset *sos ) +{ + assert( sos != NULL ); + + if ( !ber_log_check( errlvl, loglvl )) { + return 0; + } + + ber_sos_dump( sos ); + return 1; +} + +void +ber_sos_dump( + Seqorset *sos ) +{ + char buf[132]; + + assert( sos != NULL ); + + (*ber_pvt_log_print)( "*** sos dump ***\n" ); + + while ( sos != NULL ) { + sprintf( buf, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n", + (long) sos->sos_clen, + (long) sos->sos_first, + (long) sos->sos_ptr ); + (*ber_pvt_log_print)( buf ); + + sprintf( buf, " current len %ld contents:\n", + (long) (sos->sos_ptr - sos->sos_first) ); + (*ber_pvt_log_print)( buf ); + + ber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first ); + + sos = sos->sos_next; + } + + (*ber_pvt_log_print)( "*** end dump ***\n" ); +} diff --git a/libraries/liblber/dtest.c b/libraries/liblber/dtest.c index cd63b9f89a1b95bcd340f03ecfd8554e8bf3d94a..6847e1539c590ff4ced5a382b6b987df60a289b6 100644 --- a/libraries/liblber/dtest.c +++ b/libraries/liblber/dtest.c @@ -1,5 +1,10 @@ /* dtest.c - lber decoding test program */ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * @@ -11,51 +16,88 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> + +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/socket.h> +#include <ac/unistd.h> + +#ifdef HAVE_CONSOLE_H #include <console.h> -#else /* MACOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* MACOS */ -#include "lber.h" +#endif + +#include <lber.h> -static usage( char *name ) +static void usage( const char *name ) { fprintf( stderr, "usage: %s fmt\n", name ); } +int main( int argc, char **argv ) { - long i, i2, num; - unsigned long len; - int tag; - char *str, *s1, *s2; - BerElement ber; - Sockbuf sb; - extern char *optarg; - -#ifdef MACOS + char *s; + + ber_tag_t tag; + ber_len_t len; + + BerElement *ber; + Sockbuf *sb; + int fd; + + /* enable debugging */ + int ival = -1; + ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); + + if ( argc < 2 ) { + usage( argv[0] ); + return( EXIT_FAILURE ); + } + +#ifdef HAVE_CONSOLE_H ccommand( &argv ); cshow( stdout ); -#endif /* MACOS */ +#endif + + sb = ber_sockbuf_alloc(); + fd = fileno( stdin ); + ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, + (void *)&fd ); + + ber = ber_alloc_t(LBER_USE_DER); + if( ber == NULL ) { + perror( "ber_alloc_t" ); + return( EXIT_FAILURE ); + } - bzero( &sb, sizeof(sb) ); - sb.sb_sd = 0; - sb.sb_ber.ber_buf = NULL; - if ( (tag = ber_get_next( &sb, &len, &ber )) == -1 ) { + tag = ber_get_next( sb, &len, ber); + if( tag == LBER_ERROR ) { perror( "ber_get_next" ); - exit( 1 ); + return( EXIT_FAILURE ); } - printf( "message has tag 0x%x and length %ld\n", tag, len ); - if ( ber_scanf( &ber, "i", &i ) == -1 ) { - fprintf( stderr, "ber_scanf returns -1\n" ); - exit( 1 ); + printf("decode: message tag 0x%lx and length %ld\n", + (unsigned long) tag, (long) len ); + + for( s = argv[1]; *s; s++ ) { + char buf[128]; + char fmt[2]; + fmt[0] = *s; + fmt[1] = '\0'; + + printf("decode: format %s\n", fmt ); + len = sizeof(buf); + tag = ber_scanf( ber, fmt, &buf[0], &len ); + + if( tag == LBER_ERROR ) { + perror( "ber_scanf" ); + return( EXIT_FAILURE ); + } } - printf( "got int %d\n", i ); - return( 0 ); + ber_sockbuf_free( sb ); + return( EXIT_SUCCESS ); } diff --git a/libraries/liblber/encode.c b/libraries/liblber/encode.c index cd95f8932b2633341fd0049c72f9f1a223b36378..50eb6b5f9234af5e596f6da5ab4a3c084cada359 100644 --- a/libraries/liblber/encode.c +++ b/libraries/liblber/encode.c @@ -1,5 +1,10 @@ -/* encode.c - ber output encoding routines */ +/* Encode.c - ber output encoding routines */ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * @@ -11,111 +16,116 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#ifdef MACOS -#include <stdlib.h> -#include <stdarg.h> -#include "macos.h" -#else /* MACOS */ -#if defined(NeXT) || defined(VMS) -#include <stdlib.h> -#else /* next || vms */ -#include <malloc.h> -#endif /* next || vms */ -#if defined( BC31 ) || defined( _WIN32 ) -#include <stdarg.h> -#else /* BC31 || _WIN32 */ -#include <varargs.h> -#endif /* BC31 || _WIN32 */ -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#ifdef PCNFS -#include <tklib.h> -#endif /* PCNFS */ -#endif /* MACOS */ -#ifndef VMS -#include <memory.h> -#endif -#include <string.h> -#include "lber.h" -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#endif /* DOS */ +#include <ac/stdlib.h> + +#include <ac/stdarg.h> +#include <ac/socket.h> +#include <ac/string.h> + +#include "lber-int.h" + +static int ber_put_len LDAP_P(( + BerElement *ber, + ber_len_t len, + int nosos )); + +static int ber_start_seqorset LDAP_P(( + BerElement *ber, + ber_tag_t tag )); + +static int ber_put_seqorset LDAP_P(( BerElement *ber )); -#ifdef NEEDPROTOS -static int ber_put_len( BerElement *ber, unsigned long len, int nosos ); -static int ber_start_seqorset( BerElement *ber, unsigned long tag ); -static int ber_put_seqorset( BerElement *ber ); -static int ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag ); -#endif /* NEEDPROTOS */ +static int ber_put_int_or_enum LDAP_P(( + BerElement *ber, + ber_int_t num, + ber_tag_t tag )); static int -ber_calc_taglen( unsigned long tag ) +ber_calc_taglen( ber_tag_t tag ) { int i; - long mask; + ber_tag_t mask; /* find the first non-all-zero byte in the tag */ - for ( i = sizeof(long) - 1; i > 0; i-- ) { - mask = (0xffL << (i * 8)); + for ( i = sizeof(ber_tag_t) - 1; i > 0; i-- ) { + mask = ((ber_tag_t)0xffU << (i * 8)); /* not all zero */ - if ( tag & mask ) - break; + if ( tag & mask ) break; } - return( i + 1 ); + return i + 1; } static int -ber_put_tag( BerElement *ber, unsigned long tag, int nosos ) +ber_put_tag( + BerElement *ber, + ber_tag_t tag, + int nosos ) { - int taglen; - unsigned long ntag; + int rc; + int taglen; + int i; + unsigned char nettag[sizeof(ber_tag_t)]; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); taglen = ber_calc_taglen( tag ); - ntag = LBER_HTONL( tag ); + for( i=0; i<taglen; i++ ) { + nettag[(sizeof(ber_tag_t)-1) - i] = (unsigned char)(tag & 0xffU); + tag >>= 8; + } + + rc = ber_write( ber, + &nettag[sizeof(ber_tag_t) - taglen], + taglen, nosos ); - return( ber_write( ber, ((char *) &ntag) + sizeof(long) - taglen, - taglen, nosos ) ); + return rc; } -static int -ber_calc_lenlen( unsigned long len ) +static ber_len_t +ber_calc_lenlen( ber_len_t len ) { /* * short len if it's less than 128 - one byte giving the len, * with bit 8 0. */ - if ( len <= 0x7F ) - return( 1 ); + if ( len <= (ber_len_t) 0x7FU ) + return 1; /* * long len otherwise - one byte with bit 8 set, giving the * length of the length, followed by the length itself. */ - if ( len <= 0xFF ) - return( 2 ); - if ( len <= 0xFFFFL ) - return( 3 ); - if ( len <= 0xFFFFFFL ) - return( 4 ); + if ( len <= (ber_len_t) 0xffU ) + return 2; + if ( len <= (ber_len_t) 0xffffU ) + return 3; + if ( len <= (ber_len_t) 0xffffffU ) + return 4; - return( 5 ); + return 5; } static int -ber_put_len( BerElement *ber, unsigned long len, int nosos ) +ber_put_len( BerElement *ber, ber_len_t len, int nosos ) { - int i; + int rc; + int i,j; char lenlen; - long mask; - unsigned long netlen; + ber_len_t mask; + unsigned char netlen[sizeof(ber_len_t)]; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); /* * short len if it's less than 128 - one byte giving the len, @@ -123,9 +133,8 @@ ber_put_len( BerElement *ber, unsigned long len, int nosos ) */ if ( len <= 127 ) { - netlen = LBER_HTONL( len ); - return( ber_write( ber, (char *) &netlen + sizeof(long) - 1, - 1, nosos ) ); + char length_byte = (char) len; + return ber_write( ber, &length_byte, 1, nosos ); } /* @@ -134,54 +143,65 @@ ber_put_len( BerElement *ber, unsigned long len, int nosos ) */ /* find the first non-all-zero byte */ - for ( i = sizeof(long) - 1; i > 0; i-- ) { - mask = (0xffL << (i * 8)); + for ( i = sizeof(ber_len_t) - 1; i > 0; i-- ) { + mask = ((ber_len_t)0xffU << (i * 8)); /* not all zero */ - if ( len & mask ) - break; + if ( len & mask ) break; } - lenlen = ++i; + lenlen = (unsigned char) ++i; if ( lenlen > 4 ) - return( -1 ); - lenlen |= 0x80; + return -1; + + lenlen |= 0x80UL; /* write the length of the length */ if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) - return( -1 ); + return -1; + + for( j=0; j<i; j++) { + netlen[(sizeof(ber_len_t)-1) - j] = (unsigned char)(len & 0xffU); + len >>= 8; + } /* write the length itself */ - netlen = LBER_HTONL( len ); - if ( ber_write( ber, (char *) &netlen + (sizeof(long) - i), i, nosos ) - != i ) - return( -1 ); + rc = ber_write( ber, + &netlen[sizeof(ber_len_t)-i], + i, nosos ); - return( i + 1 ); + return rc == i ? i+1 : -1; } static int -ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag ) +ber_put_int_or_enum( + BerElement *ber, + ber_int_t num, + ber_tag_t tag ) { - int i, sign, taglen; - int len, lenlen; - long netnum, mask; + int rc; + int i, j, sign, taglen, lenlen; + ber_len_t len; + ber_uint_t unum, mask; + unsigned char netnum[sizeof(ber_uint_t)]; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); sign = (num < 0); + unum = num; /* Bit fiddling should be done with unsigned values */ /* * high bit is set - look for first non-all-one byte * high bit is clear - look for first non-all-zero byte */ - for ( i = sizeof(long) - 1; i > 0; i-- ) { - mask = (0xffL << (i * 8)); + for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { + mask = ((ber_uint_t)0xffU << (i * 8)); if ( sign ) { /* not all ones */ - if ( (num & mask) != mask ) - break; + if ( (unum & mask) != mask ) break; } else { /* not all zero */ - if ( num & mask ) - break; + if ( unum & mask ) break; } } @@ -189,179 +209,251 @@ ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag ) * we now have the "leading byte". if the high bit on this * byte matches the sign bit, we need to "back up" a byte. */ - mask = (num & (0x80L << (i * 8))); - if ( (mask && !sign) || (sign && !mask) ) + mask = (unum & ((ber_uint_t)0x80U << (i * 8))); + if ( (mask && !sign) || (sign && !mask) ) { i++; + } len = i + 1; - if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) - return( -1 ); + if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { + return -1; + } if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) - return( -1 ); + return -1; i++; - netnum = LBER_HTONL( num ); - if ( ber_write( ber, (char *) &netnum + (sizeof(long) - i), i, 0 ) - != i ) - return( -1 ); + + for( j=0; j<i; j++ ) { + netnum[(sizeof(ber_int_t)-1) - j] = (unsigned char)(unum & 0xffU); + unum >>= 8; + } + + rc = ber_write( ber, + &netnum[sizeof(ber_int_t) - i], + i, 0 ); /* length of tag + length + contents */ - return( taglen + lenlen + i ); + return rc == i ? taglen + lenlen + i : -1; } int -ber_put_enum( BerElement *ber, long num, unsigned long tag ) +ber_put_enum( + BerElement *ber, + ber_int_t num, + ber_tag_t tag ) { - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_ENUMERATED; + } - return( ber_put_int_or_enum( ber, num, tag ) ); + return ber_put_int_or_enum( ber, num, tag ); } int -ber_put_int( BerElement *ber, long num, unsigned long tag ) +ber_put_int( + BerElement *ber, + ber_int_t num, + ber_tag_t tag ) { - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_INTEGER; + } - return( ber_put_int_or_enum( ber, num, tag ) ); + return ber_put_int_or_enum( ber, num, tag ); } int -ber_put_ostring( BerElement *ber, char *str, unsigned long len, - unsigned long tag ) +ber_put_ostring( + BerElement *ber, + LDAP_CONST char *str, + ber_len_t len, + ber_tag_t tag ) { - int taglen, lenlen, rc; -#ifdef STR_TRANSLATION - int free_str; -#endif /* STR_TRANSLATION */ + int taglen, lenlen, rc; - if ( tag == LBER_DEFAULT ) - tag = LBER_OCTETSTRING; + assert( ber != NULL ); + assert( str != NULL ); - if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) - return( -1 ); + assert( LBER_VALID( ber ) ); -#ifdef STR_TRANSLATION - if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 && - ber->ber_encode_translate_proc != NULL ) { - if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 ) - != 0 ) { - return( -1 ); - } - free_str = 1; - } else { - free_str = 0; + if ( tag == LBER_DEFAULT ) { + tag = LBER_OCTETSTRING; } -#endif /* STR_TRANSLATION */ + + if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) + return -1; if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 || - ber_write( ber, str, len, 0 ) != len ) { + (ber_len_t) ber_write( ber, str, len, 0 ) != len ) { rc = -1; } else { /* return length of tag + length + contents */ rc = taglen + lenlen + len; } -#ifdef STR_TRANSLATION - if ( free_str ) { - free( str ); + return rc; +} + +int +ber_put_berval( + BerElement *ber, + struct berval *bv, + ber_tag_t tag ) +{ + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if( bv == NULL || bv->bv_len == 0 ) { + return ber_put_ostring( ber, "", (ber_len_t) 0, tag ); } -#endif /* STR_TRANSLATION */ - return( rc ); + return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag ); } int -ber_put_string( BerElement *ber, char *str, unsigned long tag ) +ber_put_string( + BerElement *ber, + LDAP_CONST char *str, + ber_tag_t tag ) { - return( ber_put_ostring( ber, str, strlen( str ), tag )); + assert( ber != NULL ); + assert( str != NULL ); + + assert( LBER_VALID( ber ) ); + + return ber_put_ostring( ber, str, strlen( str ), tag ); } int -ber_put_bitstring( BerElement *ber, char *str, - unsigned long blen /* in bits */, unsigned long tag ) +ber_put_bitstring( + BerElement *ber, + LDAP_CONST char *str, + ber_len_t blen /* in bits */, + ber_tag_t tag ) { - int taglen, lenlen, len; + int taglen, lenlen; + ber_len_t len; unsigned char unusedbits; - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( str != NULL ); + + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_BITSTRING; + } - if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) - return( -1 ); + if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { + return -1; + } len = ( blen + 7 ) / 8; - unusedbits = len * 8 - blen; - if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) - return( -1 ); + unusedbits = (unsigned char) ((len * 8) - blen); + if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) { + return -1; + } - if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) - return( -1 ); + if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) { + return -1; + } - if ( ber_write( ber, str, len, 0 ) != len ) - return( -1 ); + if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len ) { + return -1; + } /* return length of tag + length + unused bit count + contents */ - return( taglen + 1 + lenlen + len ); + return taglen + 1 + lenlen + len; } int -ber_put_null( BerElement *ber, unsigned long tag ) +ber_put_null( BerElement *ber, ber_tag_t tag ) { int taglen; - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_NULL; + } - if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) - return( -1 ); + if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { + return -1; + } - if ( ber_put_len( ber, 0, 0 ) != 1 ) - return( -1 ); + if ( ber_put_len( ber, 0, 0 ) != 1 ) { + return -1; + } - return( taglen + 1 ); + return taglen + 1; } int -ber_put_boolean( BerElement *ber, int boolval, unsigned long tag ) +ber_put_boolean( + BerElement *ber, + ber_int_t boolval, + ber_tag_t tag ) { - int taglen; - unsigned char trueval = 0xff; - unsigned char falseval = 0x00; + int taglen; + unsigned char c; + + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); if ( tag == LBER_DEFAULT ) tag = LBER_BOOLEAN; - if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) - return( -1 ); + if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) { + return -1; + } + + if ( ber_put_len( ber, 1, 0 ) != 1 ) { + return -1; + } - if ( ber_put_len( ber, 1, 0 ) != 1 ) - return( -1 ); + c = boolval ? (unsigned char) ~0U : (unsigned char) 0U; - if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 ) - != 1 ) - return( -1 ); + if ( ber_write( ber, (char *) &c, 1, 0 ) + != 1 ) + { + return -1; + } - return( taglen + 2 ); + return taglen + 2; } #define FOUR_BYTE_LEN 5 static int -ber_start_seqorset( BerElement *ber, unsigned long tag ) +ber_start_seqorset( + BerElement *ber, + ber_tag_t tag ) { Seqorset *new; - if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 )) - == NULLSEQORSET ) - return( -1 ); + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + new = (Seqorset *) LBER_CALLOC( 1, sizeof(Seqorset) ); + + if ( new == NULL ) { + return -1; + } + new->sos_ber = ber; - if ( ber->ber_sos == NULLSEQORSET ) + if ( ber->ber_sos == NULL ) { new->sos_first = ber->ber_ptr; - else + } else { new->sos_first = ber->ber_sos->sos_ptr; + } /* Set aside room for a 4 byte length field */ new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN; @@ -370,64 +462,93 @@ ber_start_seqorset( BerElement *ber, unsigned long tag ) new->sos_next = ber->ber_sos; ber->ber_sos = new; - return( 0 ); + return 0; } int -ber_start_seq( BerElement *ber, unsigned long tag ) +ber_start_seq( BerElement *ber, ber_tag_t tag ) { - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_SEQUENCE; + } - return( ber_start_seqorset( ber, tag ) ); + return ber_start_seqorset( ber, tag ); } int -ber_start_set( BerElement *ber, unsigned long tag ) +ber_start_set( BerElement *ber, ber_tag_t tag ) { - if ( tag == LBER_DEFAULT ) + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( tag == LBER_DEFAULT ) { tag = LBER_SET; + } - return( ber_start_seqorset( ber, tag ) ); + return ber_start_seqorset( ber, tag ); } static int ber_put_seqorset( BerElement *ber ) { - unsigned long len, netlen; - int taglen, lenlen; - unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; + int rc; + ber_len_t len; + unsigned char netlen[sizeof(ber_len_t)]; + int taglen; + ber_len_t lenlen; + unsigned char ltag = 0x80U + FOUR_BYTE_LEN - 1; Seqorset *next; Seqorset **sos = &ber->ber_sos; + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if( *sos == NULL ) return -1; + /* * If this is the toplevel sequence or set, we need to actually - * write the stuff out. Otherwise, it's already been put in + * write the stuff out. Otherwise, it's already been put in * the appropriate buffer and will be written when the toplevel * one is written. In this case all we need to do is update the * length and tag. */ len = (*sos)->sos_clen; - netlen = LBER_HTONL( len ); - if ( sizeof(long) > 4 && len > 0xFFFFFFFFL ) - return( -1 ); + + if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL ) { + return -1; + } if ( ber->ber_options & LBER_USE_DER ) { lenlen = ber_calc_lenlen( len ); + } else { lenlen = FOUR_BYTE_LEN; } - if ( (next = (*sos)->sos_next) == NULLSEQORSET ) { + if( lenlen > 1 ) { + ber_len_t i; + for( i=0; i < lenlen-1; i++ ) { + netlen[(sizeof(ber_len_t)-1) - i] = + (unsigned char)((len >> i*8) & 0xffU); + } + } else { + netlen[sizeof(ber_len_t)-1] = (unsigned char)(len & 0x7fU); + } + + if ( (next = (*sos)->sos_next) == NULL ) { /* write the tag */ if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) return( -1 ); if ( ber->ber_options & LBER_USE_DER ) { /* Write the length in the minimum # of octets */ - if ( ber_put_len( ber, len, 1 ) == -1 ) - return( -1 ); + if ( ber_put_len( ber, len, 1 ) == -1 ) { + return -1; + } if (lenlen != FOUR_BYTE_LEN) { /* @@ -435,47 +556,76 @@ ber_put_seqorset( BerElement *ber ) * the length field. Move the data if * we don't actually need that much */ - SAFEMEMCPY( (*sos)->sos_first + taglen + + AC_MEMCPY( (*sos)->sos_first + taglen + lenlen, (*sos)->sos_first + taglen + FOUR_BYTE_LEN, len ); } } else { /* Fill FOUR_BYTE_LEN bytes for length field */ /* one byte of length length */ - if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) - return( -1 ); + if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) { + return -1; + } /* the length itself */ - if ( ber_write( ber, (char *) &netlen + sizeof(long) - - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 ) - != FOUR_BYTE_LEN - 1 ) - return( -1 ); + rc = ber_write( ber, + &netlen[sizeof(ber_len_t) - (FOUR_BYTE_LEN-1)], + FOUR_BYTE_LEN-1, 1 ); + + if( rc != FOUR_BYTE_LEN - 1 ) { + return -1; + } } /* The ber_ptr is at the set/seq start - move it to the end */ (*sos)->sos_ber->ber_ptr += len; + } else { - unsigned long ntag; + int i; + unsigned char nettag[sizeof(ber_tag_t)]; + ber_tag_t tmptag = (*sos)->sos_tag; + + if( ber->ber_sos->sos_ptr > ber->ber_end ) { + /* The sos_ptr exceeds the end of the BerElement + * this can happen, for example, when the sos_ptr + * is near the end and no data was written for the + * 'V'. We must realloc the BerElement to ensure + * we don't overwrite the buffer when writing + * the tag and length fields. + */ + ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end; + + if( ber_realloc( ber, ext ) != 0 ) { + return -1; + } + } /* the tag */ - taglen = ber_calc_taglen( (*sos)->sos_tag ); - ntag = LBER_HTONL( (*sos)->sos_tag ); - SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag + - sizeof(long) - taglen, taglen ); + taglen = ber_calc_taglen( tmptag ); + + for( i = 0; i < taglen; i++ ) { + nettag[(sizeof(ber_tag_t)-1) - i] = (unsigned char)(tmptag & 0xffU); + tmptag >>= 8; + } + + AC_FMEMCPY( (*sos)->sos_first, + &nettag[sizeof(ber_tag_t) - taglen], + taglen ); if ( ber->ber_options & LBER_USE_DER ) { - ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1); + ltag = (lenlen == 1) + ? (unsigned char) len + : (unsigned char) (0x80U + (lenlen - 1)); } /* one byte of length length */ - SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 ); + (*sos)->sos_first[1] = ltag; if ( ber->ber_options & LBER_USE_DER ) { if (lenlen > 1) { /* Write the length itself */ - SAFEMEMCPY( (*sos)->sos_first + 2, - (char *)&netlen + sizeof(unsigned long) - - (lenlen - 1), - lenlen - 1 ); + AC_FMEMCPY( (*sos)->sos_first + 2, + &netlen[sizeof(ber_len_t) - (lenlen - 1)], + lenlen - 1 ); } if (lenlen != FOUR_BYTE_LEN) { /* @@ -483,15 +633,15 @@ ber_put_seqorset( BerElement *ber ) * the length field. Move the data if * we don't actually need that much */ - SAFEMEMCPY( (*sos)->sos_first + taglen + + AC_FMEMCPY( (*sos)->sos_first + taglen + lenlen, (*sos)->sos_first + taglen + FOUR_BYTE_LEN, len ); } } else { /* the length itself */ - SAFEMEMCPY( (*sos)->sos_first + taglen + 1, - (char *) &netlen + sizeof(long) - - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 ); + AC_FMEMCPY( (*sos)->sos_first + taglen + 1, + &netlen[sizeof(ber_len_t) - (FOUR_BYTE_LEN - 1)], + FOUR_BYTE_LEN - 1 ); } next->sos_clen += (taglen + lenlen + len); @@ -499,66 +649,75 @@ ber_put_seqorset( BerElement *ber ) } /* we're done with this seqorset, so free it up */ - free( (char *) (*sos) ); + LBER_FREE( (char *) (*sos) ); *sos = next; - return( taglen + lenlen + len ); + return taglen + lenlen + len; } int ber_put_seq( BerElement *ber ) { - return( ber_put_seqorset( ber ) ); + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + return ber_put_seqorset( ber ); } int ber_put_set( BerElement *ber ) { - return( ber_put_seqorset( ber ) ); + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + return ber_put_seqorset( ber ); } +/* N tag */ +static ber_tag_t lber_int_null = 0; + /* VARARGS */ int -ber_printf( -#if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 ) - BerElement *ber, char *fmt, ... ) -#else /* MACOS || _WIN32 || BC31 */ - va_alist ) -va_dcl -#endif /* MACOS || _WIN32 || BC31 */ +ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... ) { va_list ap; -#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( BC31 ) - BerElement *ber; - char *fmt; -#endif /* !MACOS && !_WIN32 && !BC31 */ char *s, **ss; - struct berval **bv; - int rc, i; - unsigned long len; + struct berval *bv, **bvp; + int rc; + ber_int_t i; + ber_len_t len; + + assert( ber != NULL ); + assert( fmt != NULL ); + + assert( LBER_VALID( ber ) ); -#if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 ) va_start( ap, fmt ); -#else /* MACOS || _WIN32 || BC31 */ - va_start( ap ); - ber = va_arg( ap, BerElement * ); - fmt = va_arg( ap, char * ); -#endif /* MACOS || _WIN32 || BC31 */ for ( rc = 0; *fmt && rc != -1; fmt++ ) { switch ( *fmt ) { + case '!': { /* hook */ + BEREncodeCallback *f; + void *p; + + f = va_arg( ap, BEREncodeCallback * ); + p = va_arg( ap, void * ); + + rc = (*f)( ber, p ); + } break; + case 'b': /* boolean */ - i = va_arg( ap, int ); + i = va_arg( ap, ber_int_t ); rc = ber_put_boolean( ber, i, ber->ber_tag ); break; case 'i': /* int */ - i = va_arg( ap, int ); + i = va_arg( ap, ber_int_t ); rc = ber_put_int( ber, i, ber->ber_tag ); break; case 'e': /* enumeration */ - i = va_arg( ap, int ); + i = va_arg( ap, ber_int_t ); rc = ber_put_enum( ber, i, ber->ber_tag ); break; @@ -566,25 +725,41 @@ va_dcl rc = ber_put_null( ber, ber->ber_tag ); break; + case 'N': /* Debug NULL */ + if( lber_int_null != 0 ) { + /* Insert NULL to ensure peer ignores unknown tags */ + rc = ber_put_null( ber, lber_int_null ); + } else { + rc = 0; + } + break; + case 'o': /* octet string (non-null terminated) */ s = va_arg( ap, char * ); - len = va_arg( ap, int ); + len = va_arg( ap, ber_len_t ); rc = ber_put_ostring( ber, s, len, ber->ber_tag ); break; + case 'O': /* berval octet string */ + bv = va_arg( ap, struct berval * ); + if( bv == NULL ) break; + rc = ber_put_berval( ber, bv, ber->ber_tag ); + break; + case 's': /* string */ s = va_arg( ap, char * ); rc = ber_put_string( ber, s, ber->ber_tag ); break; case 'B': /* bit string */ + case 'X': /* bit string (deprecated) */ s = va_arg( ap, char * ); len = va_arg( ap, int ); /* in bits */ rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); break; case 't': /* tag for the next element */ - ber->ber_tag = va_arg( ap, unsigned long ); + ber->ber_tag = va_arg( ap, ber_tag_t ); ber->ber_usertag = 1; break; @@ -599,11 +774,21 @@ va_dcl break; case 'V': /* sequences of strings + lengths */ - if ( (bv = va_arg( ap, struct berval ** )) == NULL ) + if ( (bvp = va_arg( ap, struct berval ** )) == NULL ) break; - for ( i = 0; bv[i] != NULL; i++ ) { - if ( (rc = ber_put_ostring( ber, bv[i]->bv_val, - bv[i]->bv_len, ber->ber_tag )) == -1 ) + for ( i = 0; bvp[i] != NULL; i++ ) { + if ( (rc = ber_put_berval( ber, bvp[i], + ber->ber_tag )) == -1 ) + break; + } + break; + + case 'W': /* BerVarray */ + if ( (bv = va_arg( ap, BerVarray )) == NULL ) + break; + for ( i = 0; bv[i].bv_val != NULL; i++ ) { + if ( (rc = ber_put_berval( ber, &bv[i], + ber->ber_tag )) == -1 ) break; } break; @@ -625,9 +810,15 @@ va_dcl break; default: -#ifndef NO_USERINTERFACE - fprintf( stderr, "unknown fmt %c\n", *fmt ); -#endif /* NO_USERINTERFACE */ + if( ber->ber_debug ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, + "ber_printf: unknown fmt %c\n", *fmt )); +#else + ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, + "ber_printf: unknown fmt %c\n", *fmt ); +#endif + } rc = -1; break; } @@ -640,5 +831,5 @@ va_dcl va_end( ap ); - return( rc ); + return rc; } diff --git a/libraries/liblber/etest.c b/libraries/liblber/etest.c index 50ac00d4bfb8f46dd17559f001a62f2b8b663d8f..21d13d4a2519035e8e0fbf3a29103f2d24ef28c6 100644 --- a/libraries/liblber/etest.c +++ b/libraries/liblber/etest.c @@ -1,166 +1,159 @@ /* test.c - lber encoding test program */ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include <unix.h> -#include <fcntl.h> + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#ifdef HAVE_CONSOLE_H #include <console.h> -#else /* MACOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* MACOS */ +#endif /* HAVE_CONSOLE_H */ + #include "lber.h" -static usage( char *name ) +static void usage( const char *name ) { fprintf( stderr, "usage: %s fmtstring\n", name ); } +static char* getbuf( void ) { + char *p; + static char buf[1024]; + + if ( fgets( buf, sizeof(buf), stdin ) == NULL ) + return NULL; + + if ( (p = strchr( buf, '\n' )) != NULL ) + *p = '\0'; + + return buf; +} + +int main( int argc, char **argv ) { - int i, num, len; - char *s, *p; - Seqorset *sos = NULLSEQORSET; + char *s; + + int fd, rc; BerElement *ber; - Sockbuf sb; - extern char *optarg; + Sockbuf *sb; + + /* enable debugging */ + int ival = -1; + ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); if ( argc < 2 ) { usage( argv[0] ); - exit( 1 ); + return( EXIT_FAILURE ); } - bzero( &sb, sizeof(sb) ); - sb.sb_sd = 1; - sb.sb_ber.ber_buf = NULL; - -#ifdef MACOS +#ifdef HAVE_CONSOLE_H ccommand( &argv ); cshow( stdout ); - if (( sb.sb_sd = open( "lber-test", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY )) + if (( fd = open( "lber-test", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY )) < 0 ) { perror( "open" ); - exit( 1 ); + return( EXIT_FAILURE ); } -#endif /* MACOS */ - if ( (ber = ber_alloc()) == NULLBER ) { - perror( "ber_alloc" ); - exit( 1 ); +#else + fd = fileno(stdout); +#endif + + sb = ber_sockbuf_alloc(); + ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, + (void *)&fd ); + + if( sb == NULL ) { + perror( "ber_sockbuf_alloc_fd" ); + return( EXIT_FAILURE ); } - num = 7; - if ( ber_printf( ber, "{ti}", 0x1f44, num ) == -1 ) { - fprintf( stderr, "ber_printf returns -1" ); - exit( 1 ); + if ( (ber = ber_alloc_t( LBER_USE_DER )) == NULL ) { + perror( "ber_alloc" ); + return( EXIT_FAILURE ); } - if ( ber_flush( &sb, ber, 1 ) == -1 ) { - perror( "ber_flush" ); - exit( 1 ); + fprintf(stderr, "encode: start\n" ); + if( ber_printf( ber, "{" /*}*/ ) ) { + perror( "ber_printf {" /*}*/ ); + return( EXIT_FAILURE ); } -#ifdef notdef + for ( s = argv[1]; *s; s++ ) { - if ( fgets( buf, sizeof(buf), stdin ) == NULL ) - break; - if ( (p = strchr( buf, '\n' )) != NULL ) - *p = '\0'; + char *buf; + char fmt[2]; + fmt[0] = *s; + fmt[1] = '\0'; + + fprintf(stderr, "encode: %s\n", fmt ); switch ( *s ) { case 'i': /* int */ case 'b': /* boolean */ - i = atoi( buf ); - if ( ber_printf( ber, "i", i ) == -1 ) { - fprintf( stderr, "ber_printf i\n" ); - exit( 1 ); - } - break; - case 'e': /* enumeration */ - i = va_arg( ap, int ); - rc = ber_put_enum( ber, i, (char)ber->ber_tag ); + buf = getbuf(); + rc = ber_printf( ber, fmt, atoi(buf) ); break; case 'n': /* null */ - rc = ber_put_null( ber, (char)ber->ber_tag ); + case '{': /* begin sequence */ + case '}': /* end sequence */ + case '[': /* begin set */ + case ']': /* end set */ + rc = ber_printf( ber, fmt ); break; case 'o': /* octet string (non-null terminated) */ - s = va_arg( ap, char * ); - len = va_arg( ap, int ); - rc = ber_put_ostring( ber, s, len, (char)ber->ber_tag ); - break; - - case 's': /* string */ - s = va_arg( ap, char * ); - rc = ber_put_string( ber, s, (char)ber->ber_tag ); - break; - case 'B': /* bit string */ - s = va_arg( ap, char * ); - len = va_arg( ap, int ); /* in bits */ - rc = ber_put_bitstring( ber, s, len, (char)ber->ber_tag ); + buf = getbuf(); + rc = ber_printf( ber, fmt, buf, strlen(buf) ); break; + case 's': /* string */ case 't': /* tag for the next element */ - ber->ber_tag = va_arg( ap, int ); - ber->ber_usertag = 1; - break; - - case 'v': /* vector of strings */ - if ( (ss = va_arg( ap, char ** )) == NULL ) - break; - for ( i = 0; ss[i] != NULL; i++ ) { - if ( (rc = ber_put_string( ber, ss[i], - (char)ber->ber_tag )) == -1 ) - break; - } - break; - - case 'V': /* sequences of strings + lengths */ - if ( (bv = va_arg( ap, struct berval ** )) == NULL ) - break; - for ( i = 0; bv[i] != NULL; i++ ) { - if ( (rc = ber_put_ostring( ber, bv[i]->bv_val, - bv[i]->bv_len, (char)ber->ber_tag )) == -1 ) - break; - } - break; - - case '{': /* begin sequence */ - rc = ber_start_seq( ber, (char)ber->ber_tag ); - break; - - case '}': /* end sequence */ - rc = ber_put_seqorset( ber ); - break; - - case '[': /* begin set */ - rc = ber_start_set( ber, (char)ber->ber_tag ); - break; - - case ']': /* end set */ - rc = ber_put_seqorset( ber ); + buf = getbuf(); + rc = ber_printf( ber, fmt, buf ); break; default: -#ifndef NO_USERINTERFACE - fprintf( stderr, "unknown fmt %c\n", *fmt ); -#endif /* NO_USERINTERFACE */ + fprintf( stderr, "encode: unknown fmt %c\n", *fmt ); rc = -1; break; } + + if( rc == -1 ) { + perror( "ber_printf" ); + return( EXIT_FAILURE ); } } -#endif + fprintf(stderr, "encode: end\n" ); + if( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + perror( /*{*/ "ber_printf }" ); + return( EXIT_FAILURE ); + } + + if ( ber_flush( sb, ber, 1 ) == -1 ) { + perror( "ber_flush" ); + return( EXIT_FAILURE ); + } - return( 0 ); + ber_sockbuf_free( sb ); + return( EXIT_SUCCESS ); } diff --git a/libraries/liblber/io.c b/libraries/liblber/io.c index 081f386794a6a08b2ed5ca4225bf200556ca7a4f..95dc49b79e32dbf4a0b9c29d367f93a46233afce 100644 --- a/libraries/liblber/io.c +++ b/libraries/liblber/io.c @@ -1,5 +1,10 @@ /* io.c - ber general i/o routines */ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * @@ -11,264 +16,131 @@ * is provided ``as is'' without express or implied warranty. */ -#include <stdio.h> -#include <ctype.h> - -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#endif /* DOS || _WIN32 */ - -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#if defined(NeXT) || defined(VMS) -#include <stdlib.h> -#else /* next || vms */ -#include <malloc.h> -#endif /* next || vms */ -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#ifdef PCNFS -#include <tklib.h> -#endif /* PCNFS */ -#endif /* MACOS */ - -#ifndef VMS -#include <memory.h> -#endif -#include <string.h> -#include "lber.h" - -#ifdef _WIN32 -#include <winsock.h> -#include <io.h> -#endif /* _WIN32 */ - -#ifdef NEEDPROTOS -static int ber_realloc( BerElement *ber, unsigned long len ); -static int ber_filbuf( Sockbuf *sb, long len ); -static long BerRead( Sockbuf *sb, char *buf, long len ); -#ifdef PCNFS -static int BerWrite( Sockbuf *sb, char *buf, long len ); -#endif /* PCNFS */ -#else -int ber_filbuf(); -long BerRead(); -static int ber_realloc(); -#endif /* NEEDPROTOS */ - -#define bergetc( sb, len ) ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \ - (unsigned char)*sb->sb_ber.ber_ptr++ : \ - ber_filbuf( sb, len )) - -#ifdef MACOS -/* - * MacTCP/OpenTransport - */ -#define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL ) -#define MAX_WRITE 65535 -#define BerWrite( sb, b, l ) tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE ) -#else /* MACOS */ -#ifdef DOS -#ifdef PCNFS -/* - * PCNFS (under DOS) - */ -#define read( s, b, l ) recv( s, b, l, 0 ) -#define BerWrite( s, b, l ) send( s->sb_sd, b, (int) l, 0 ) -#endif /* PCNFS */ -#ifdef NCSA -/* - * NCSA Telnet TCP/IP stack (under DOS) - */ -#define read( s, b, l ) nread( s, b, l ) -#define BerWrite( s, b, l ) netwrite( s->sb_sd, b, l ) -#endif /* NCSA */ -#ifdef WINSOCK -/* - * Windows Socket API (under DOS/Windows 3.x) - */ -#define read( s, b, l ) recv( s, b, l, 0 ) -#define BerWrite( s, b, l ) send( s->sb_sd, b, l, 0 ) -#endif /* WINSOCK */ -#else /* DOS */ -#ifdef _WIN32 -/* - * 32-bit Windows Socket API (under Windows NT or Windows 95) - */ -#define read( s, b, l ) recv( s, b, l, 0 ) -#define BerWrite( s, b, l ) send( s->sb_sd, b, l, 0 ) -#else /* _WIN32 */ -#ifdef VMS -/* - * VMS -- each write must be 64K or smaller - */ -#define MAX_WRITE 65535 -#define BerWrite( sb, b, l ) write( sb->sb_sd, b, (l<MAX_WRITE)? l : MAX_WRITE) -#else /* VMS */ -/* - * everything else (Unix/BSD 4.3 socket API) - */ -#define BerWrite( sb, b, l ) write( sb->sb_sd, b, l ) -#endif /* VMS */ -#define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \ - (struct sockaddr *)sb->sb_fromaddr, \ - (al = sizeof(struct sockaddr), &al)) -#define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \ - (struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr)) -#endif /* _WIN32 */ -#endif /* DOS */ -#endif /* MACOS */ - -#ifndef udp_read -#define udp_read( sb, b, l, al ) CLDAP NOT SUPPORTED -#define udp_write( sb, b, l ) CLDAP NOT SUPPORTED -#endif /* udp_read */ - -#define EXBUFSIZ 1024 +#include "portable.h" -int -ber_filbuf( Sockbuf *sb, long len ) -{ - short rc; -#ifdef CLDAP - int addrlen; -#endif /* CLDAP */ - - if ( sb->sb_ber.ber_buf == NULL ) { - if ( (sb->sb_ber.ber_buf = (char *) malloc( READBUFSIZ )) == - NULL ) - return( -1 ); - sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf; - sb->sb_ber.ber_end = sb->sb_ber.ber_buf; - } +#include <stdio.h> - if ( sb->sb_naddr > 0 ) { -#ifdef CLDAP - rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen ); -#ifdef LDAP_DEBUG - if ( lber_debug ) { - fprintf( stderr, "ber_filbuf udp_read %d bytes\n", - rc ); - if ( lber_debug > 1 && rc > 0 ) - lber_bprint( sb->sb_ber.ber_buf, rc ); - } -#endif /* LDAP_DEBUG */ -#else /* CLDAP */ - rc = -1; -#endif /* CLDAP */ - } else { - rc = read( sb->sb_sd, sb->sb_ber.ber_buf, - ((sb->sb_options & LBER_NO_READ_AHEAD) && - (len < READBUFSIZ)) ? - len : READBUFSIZ ); - } +#include <ac/stdlib.h> - if ( rc > 0 ) { - sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1; - sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc; - return( (unsigned char)*sb->sb_ber.ber_buf ); - } +#include <ac/ctype.h> +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/unistd.h> - return( -1 ); -} +#ifdef HAVE_IO_H +#include <io.h> +#endif +#include "lber-int.h" -long -BerRead( Sockbuf *sb, char *buf, long len ) +ber_slen_t +ber_read( + BerElement *ber, + char *buf, + ber_len_t len ) { - int c; - long nread = 0; - - while ( len > 0 ) { - if ( (c = bergetc( sb, len )) < 0 ) { - if ( nread > 0 ) - break; - return( c ); - } - *buf++ = c; - nread++; - len--; - } - - return( nread ); -} + ber_len_t actuallen, nleft; + assert( ber != NULL ); + assert( buf != NULL ); -long -ber_read( BerElement *ber, char *buf, unsigned long len ) -{ - unsigned long actuallen, nleft; + assert( LBER_VALID( ber ) ); - nleft = ber->ber_end - ber->ber_ptr; + nleft = ber_pvt_ber_remaining( ber ); actuallen = nleft < len ? nleft : len; - SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen ); + AC_MEMCPY( buf, ber->ber_ptr, actuallen ); ber->ber_ptr += actuallen; - return( (long)actuallen ); + return( (ber_slen_t) actuallen ); } -long -ber_write( BerElement *ber, char *buf, unsigned long len, int nosos ) +ber_slen_t +ber_write( + BerElement *ber, + LDAP_CONST char *buf, + ber_len_t len, + int nosos ) { + assert( ber != NULL ); + assert( buf != NULL ); + + assert( LBER_VALID( ber ) ); + if ( nosos || ber->ber_sos == NULL ) { if ( ber->ber_ptr + len > ber->ber_end ) { if ( ber_realloc( ber, len ) != 0 ) return( -1 ); } - SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len ); + AC_MEMCPY( ber->ber_ptr, buf, (size_t)len ); ber->ber_ptr += len; - return( len ); + return( (ber_slen_t) len ); + } else { if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) { if ( ber_realloc( ber, len ) != 0 ) return( -1 ); } - SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len ); + AC_MEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len ); ber->ber_sos->sos_ptr += len; ber->ber_sos->sos_clen += len; - return( len ); + return( (ber_slen_t) len ); } } -static int -ber_realloc( BerElement *ber, unsigned long len ) +int +ber_realloc( BerElement *ber, ber_len_t len ) { - unsigned long need, have, total; + ber_len_t total; Seqorset *s; long off; char *oldbuf; - have = (ber->ber_end - ber->ber_buf) / EXBUFSIZ; - need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ); - total = have * EXBUFSIZ + need * EXBUFSIZ; + assert( ber != NULL ); + assert( len > 0 ); + assert( LBER_VALID( ber ) ); + + total = ber_pvt_ber_total( ber ); + +#define LBER_EXBUFSIZ 1000 /* a few words less than 2^N for binary buddy */ +#if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0 +# ifndef notdef + /* don't realloc by small amounts */ + total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len; +# else + { /* not sure what value this adds */ + ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ; + ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ; + total = ( have + need ) * LBER_EXBUFSIZ; + } +# endif +#else + total += len; /* realloc just what's needed */ +#endif oldbuf = ber->ber_buf; + ber->ber_buf = (char *) LBER_REALLOC( oldbuf, total ); + if ( ber->ber_buf == NULL ) { - if ( (ber->ber_buf = (char *) malloc( (size_t)total )) == NULL ) - return( -1 ); - } else if ( (ber->ber_buf = (char *) realloc( ber->ber_buf, - (size_t)total )) == NULL ) + ber->ber_buf = oldbuf; return( -1 ); + } ber->ber_end = ber->ber_buf + total; /* * If the stinking thing was moved, we need to go through and - * reset all the sos and ber pointers. Offsets would've been + * reset all the sos and ber pointers. Offsets would've been * a better idea... oh well. */ if ( ber->ber_buf != oldbuf ) { ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf); - for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) { + for ( s = ber->ber_sos; s != NULL; s = s->sos_next ) { off = s->sos_first - oldbuf; s->sos_first = ber->ber_buf + off; @@ -280,65 +152,81 @@ ber_realloc( BerElement *ber, unsigned long len ) return( 0 ); } +void +ber_free_buf( BerElement *ber ) +{ + Seqorset *s, *next; + + assert( LBER_VALID( ber ) ); + + if ( ber->ber_buf) LBER_FREE( ber->ber_buf ); + + for( s = ber->ber_sos ; s != NULL ; s = next ) { + next = s->sos_next; + LBER_FREE( s ); + } + + ber->ber_buf = NULL; + ber->ber_sos = NULL; + ber->ber_valid = LBER_UNINITIALIZED; +} + void ber_free( BerElement *ber, int freebuf ) { - if ( freebuf && ber->ber_buf != NULL ) - free( ber->ber_buf ); - free( (char *) ber ); +#ifdef LDAP_MEMORY_DEBUG + assert( ber != NULL ); +#endif + + if( ber == NULL ) { + return; + } + + if( freebuf ) + ber_free_buf( ber ); + + LBER_FREE( (char *) ber ); } int ber_flush( Sockbuf *sb, BerElement *ber, int freeit ) { - long nwritten, towrite, rc; + ber_len_t nwritten, towrite; + ber_slen_t rc; + + assert( sb != NULL ); + assert( ber != NULL ); + + assert( SOCKBUF_VALID( sb ) ); + assert( LBER_VALID( ber ) ); if ( ber->ber_rwptr == NULL ) { ber->ber_rwptr = ber->ber_buf; } towrite = ber->ber_ptr - ber->ber_rwptr; -#ifdef LDAP_DEBUG - if ( lber_debug ) { - fprintf( stderr, "ber_flush: %ld bytes to sd %ld%s\n", towrite, - sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)" - : "" ); - if ( lber_debug > 1 ) - lber_bprint( ber->ber_rwptr, towrite ); - } + if ( sb->sb_debug ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "liblber", LDAP_LEVEL_DETAIL1, + "ber_flush: %ld bytes to sd %ld%s\n", + towrite, (long)sb->sb_fd, + ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" )); + BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 )); +#else + ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug, + "ber_flush: %ld bytes to sd %ld%s\n", + towrite, (long) sb->sb_fd, + ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" ); + ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug, + ber->ber_rwptr, towrite ); #endif -#if !defined(MACOS) && !defined(DOS) - if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) { - rc = write( sb->sb_fd, ber->ber_buf, towrite ); - if ( sb->sb_options & LBER_TO_FILE_ONLY ) { - return( (int)rc ); - } } -#endif nwritten = 0; do { - if (sb->sb_naddr > 0) { -#ifdef CLDAP - rc = udp_write( sb, ber->ber_buf + nwritten, - (size_t)towrite ); -#else /* CLDAP */ - rc = -1; -#endif /* CLDAP */ - if ( rc <= 0 ) - return( -1 ); - /* fake error if write was not atomic */ - if (rc < towrite) { -#if !defined( MACOS ) && !defined( DOS ) - errno = EMSGSIZE; -#endif - return( -1 ); - } - } else { - if ( (rc = BerWrite( sb, ber->ber_rwptr, - (size_t) towrite )) <= 0 ) { - return( -1 ); - } + rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite ); + if (rc<=0) { + return -1; } towrite -= rc; nwritten += rc; @@ -356,24 +244,33 @@ ber_alloc_t( int options ) { BerElement *ber; - if ( (ber = (BerElement *) calloc( 1, sizeof(BerElement) )) == NULLBER ) - return( NULLBER ); + ber_int_options.lbo_valid = LBER_INITIALIZED; + + ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) ); + + if ( ber == NULL ) { + return NULL; + } + + ber->ber_valid = LBER_VALID_BERELEMENT; ber->ber_tag = LBER_DEFAULT; ber->ber_options = options; + ber->ber_debug = ber_int_debug; - return( ber ); + assert( LBER_VALID( ber ) ); + return ber; } BerElement * -ber_alloc() +ber_alloc( void ) /* deprecated */ { - return( ber_alloc_t( 0 ) ); + return ber_alloc_t( 0 ); } BerElement * -der_alloc() +der_alloc( void ) /* deprecated */ { - return( ber_alloc_t( LBER_USE_DER ) ); + return ber_alloc_t( LBER_USE_DER ); } BerElement * @@ -381,120 +278,175 @@ ber_dup( BerElement *ber ) { BerElement *new; - if ( (new = ber_alloc()) == NULLBER ) - return( NULLBER ); + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) { + return NULL; + } *new = *ber; + assert( LBER_VALID( new ) ); return( new ); } void -ber_init( BerElement *ber, int options ) +ber_init2( BerElement *ber, struct berval *bv, int options ) { + assert( ber != NULL ); + + ber_int_options.lbo_valid = LBER_INITIALIZED; + (void) memset( (char *)ber, '\0', sizeof( BerElement )); + ber->ber_valid = LBER_VALID_BERELEMENT; ber->ber_tag = LBER_DEFAULT; - ber->ber_options = options; -} + ber->ber_options = (char) options; + ber->ber_debug = ber_int_debug; - -void -ber_reset( BerElement *ber, int was_writing ) -{ - if ( was_writing ) { - ber->ber_end = ber->ber_ptr; + if ( bv != NULL ) { + ber->ber_buf = bv->bv_val; ber->ber_ptr = ber->ber_buf; - } else { - ber->ber_ptr = ber->ber_end; + ber->ber_end = ber->ber_buf + bv->bv_len; } - ber->ber_rwptr = NULL; + assert( LBER_VALID( ber ) ); } - -#ifdef LDAP_DEBUG - +/* OLD U-Mich ber_init() */ void -ber_dump( BerElement *ber, int inout ) +ber_init_w_nullc( BerElement *ber, int options ) { - fprintf( stderr, "ber_dump: buf 0x%lx, ptr 0x%lx, end 0x%lx\n", - ber->ber_buf, ber->ber_ptr, ber->ber_end ); - if ( inout == 1 ) { - fprintf( stderr, " current len %ld, contents:\n", - ber->ber_end - ber->ber_ptr ); - lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr ); - } else { - fprintf( stderr, " current len %ld, contents:\n", - ber->ber_ptr - ber->ber_buf ); - lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf ); - } + ber_init2( ber, NULL, options ); } -void -ber_sos_dump( Seqorset *sos ) +/* New C-API ber_init() */ +/* This function constructs a BerElement containing a copy +** of the data in the bv argument. +*/ +BerElement * +ber_init( struct berval *bv ) { - fprintf( stderr, "*** sos dump ***\n" ); - while ( sos != NULLSEQORSET ) { - fprintf( stderr, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n", - sos->sos_clen, sos->sos_first, sos->sos_ptr ); - fprintf( stderr, " current len %ld contents:\n", - sos->sos_ptr - sos->sos_first ); - lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first ); - - sos = sos->sos_next; + BerElement *ber; + + assert( bv != NULL ); + + ber_int_options.lbo_valid = LBER_INITIALIZED; + + if ( bv == NULL ) { + return NULL; } - fprintf( stderr, "*** end dump ***\n" ); -} -#endif + ber = ber_alloc_t( 0 ); + + if( ber == NULL ) { + /* allocation failed */ + return NULL; + } + + /* copy the data */ + if ( ((ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 )) + != bv->bv_len ) + { + /* write failed, so free and return NULL */ + ber_free( ber, 1 ); + return NULL; + } + + ber_reset( ber, 1 ); /* reset the pointer to the start of the buffer */ + return ber; +} -/* return the tag - LBER_DEFAULT returned means trouble */ -static unsigned long -get_tag( Sockbuf *sb ) +/* New C-API ber_flatten routine */ +/* This routine allocates a struct berval whose contents are a BER +** encoding taken from the ber argument. The bvPtr pointer pointers to +** the returned berval. +*/ +int ber_flatten( + BerElement *ber, + struct berval **bvPtr) { - unsigned char xbyte; - unsigned long tag; - char *tagp; - int i; + struct berval *bv; + + assert( bvPtr != NULL ); - if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 ) - return( LBER_DEFAULT ); + ber_int_options.lbo_valid = LBER_INITIALIZED; - if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) - return( (unsigned long) xbyte ); + if(bvPtr == NULL) { + return -1; + } - tagp = (char *) &tag; - tagp[0] = xbyte; - for ( i = 1; i < sizeof(long); i++ ) { - if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 ) - return( LBER_DEFAULT ); + bv = LBER_MALLOC( sizeof(struct berval) ); + if ( bv == NULL ) { + return -1; + } - tagp[i] = xbyte; + if ( ber == NULL ) { + /* ber is null, create an empty berval */ + bv->bv_val = NULL; + bv->bv_len = 0; - if ( ! (xbyte & LBER_MORE_TAG_MASK) ) - break; + } else { + /* copy the berval */ + ber_len_t len = ber_pvt_ber_write( ber ); + + bv->bv_val = (char *) LBER_MALLOC( len + 1 ); + if ( bv->bv_val == NULL ) { + LBER_FREE( bv ); + return -1; + } + + AC_MEMCPY( bv->bv_val, ber->ber_buf, len ); + bv->bv_val[len] = '\0'; + bv->bv_len = len; } + + *bvPtr = bv; + return 0; +} - /* tag too big! */ - if ( i == sizeof(long) ) - return( LBER_DEFAULT ); +void +ber_reset( BerElement *ber, int was_writing ) +{ + assert( ber != NULL ); + assert( LBER_VALID( ber ) ); + + if ( was_writing ) { + ber->ber_end = ber->ber_ptr; + ber->ber_ptr = ber->ber_buf; - /* want leading, not trailing 0's */ - return( tag >> (sizeof(long) - i - 1) ); + } else { + ber->ber_ptr = ber->ber_end; + } + + ber->ber_rwptr = NULL; } -unsigned long -ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber ) +/* + * A rewrite of ber_get_next that can safely be called multiple times + * for the same packet. It will simply continue where it stopped until + * a full packet is read. + */ + +ber_tag_t +ber_get_next( + Sockbuf *sb, + ber_len_t *len, + BerElement *ber ) { - unsigned long tag, netlen, toread; - unsigned char lc; - long rc; - int noctets, diff; - -#ifdef LDAP_DEBUG - if ( lber_debug ) - fprintf( stderr, "ber_get_next\n" ); + assert( sb != NULL ); + assert( len != NULL ); + assert( ber != NULL ); + + assert( SOCKBUF_VALID( sb ) ); + assert( LBER_VALID( ber ) ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "liblber", LDAP_LEVEL_ENTRY, "ber_get_next: enter\n" )); +#else + ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, + "ber_get_next\n" ); #endif /* @@ -509,93 +461,177 @@ ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber ) * 3) primitive encodings used whenever possible */ - /* - * first time through - malloc the buffer, set up ptrs, and - * read the tag and the length and as much of the rest as we can - */ - - if ( ber->ber_rwptr == NULL ) { - /* - * First, we read the tag. + if (ber->ber_rwptr == NULL) { + /* XXYYZ + * dtest does like this assert. */ + /* assert( ber->ber_buf == NULL ); */ + ber->ber_rwptr = (char *) &ber->ber_len-1; + ber->ber_ptr = ber->ber_rwptr; + ber->ber_tag = 0; + } + + while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr < + (char *)(&ber->ber_usertag + 1)) { + ber_slen_t i; + char buf[sizeof(ber->ber_len)-1]; + ber_len_t tlen = 0; - if ( (tag = get_tag( sb )) == LBER_DEFAULT ) { - return( LBER_DEFAULT ); + if ((i=ber_int_sb_read( sb, ber->ber_rwptr, + (char *)(&ber->ber_usertag+1)-ber->ber_rwptr))<=0) { + return LBER_DEFAULT; } - ber->ber_tag = tag; - - /* - * Next, read the length. The first byte contains the length - * of the length. If bit 8 is set, the length is the long - * form, otherwise it's the short form. We don't allow a - * length that's greater than what we can hold in an unsigned - * long. - */ - *len = netlen = 0; - if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) { - return( LBER_DEFAULT ); + ber->ber_rwptr += i; + + /* We got at least one byte, try to parse the tag. */ + if (ber->ber_ptr == (char *)&ber->ber_len-1) { + ber_tag_t tag; + unsigned char *p = (unsigned char *)ber->ber_ptr; + tag = *p++; + if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) { + for (i=1; (char *)p<ber->ber_rwptr; i++,p++) { + tag <<= 8; + tag |= *p; + if (!(*p & LBER_MORE_TAG_MASK)) + break; + /* Is the tag too big? */ + if (i == sizeof(ber_tag_t)-1) { + errno = ERANGE; + return LBER_DEFAULT; + } + } + /* Did we run out of bytes? */ + if ((char *)p == ber->ber_rwptr) { + return LBER_DEFAULT; + } + p++; + } + ber->ber_tag = tag; + ber->ber_ptr = (char *)p; } - if ( lc & 0x80 ) { - noctets = (lc & 0x7f); - if ( noctets > sizeof(unsigned long) ) - return( LBER_DEFAULT ); - diff = sizeof(unsigned long) - noctets; - if ( BerRead( sb, (char *) &netlen + diff, noctets ) != - noctets ) { - return( LBER_DEFAULT ); + + /* Now look for the length */ + if (*ber->ber_ptr & 0x80) { /* multi-byte */ + int llen = *(unsigned char *)ber->ber_ptr++ & 0x7f; + if (llen > (int)sizeof(ber_len_t)) { + errno = ERANGE; + return LBER_DEFAULT; + } + /* Not enough bytes? */ + if (ber->ber_rwptr - ber->ber_ptr < llen) { + return LBER_DEFAULT; + } + for (i=0; i<llen && ber->ber_ptr<ber->ber_rwptr; i++,ber->ber_ptr++) { + tlen <<=8; + tlen |= *(unsigned char *)ber->ber_ptr; } - *len = LBER_NTOHL( netlen ); } else { - *len = lc; + tlen = *(unsigned char *)ber->ber_ptr++; } - ber->ber_len = *len; - - /* - * Finally, malloc a buffer for the contents and read it in. - * It's this buffer that's passed to all the other ber decoding - * routines. - */ - -#if defined( DOS ) && !defined( _WIN32 ) - if ( *len > 65535 ) { /* DOS can't allocate > 64K */ - return( LBER_DEFAULT ); + /* Are there leftover data bytes inside ber->ber_len? */ + if (ber->ber_ptr < (char *)&ber->ber_usertag) { + if (ber->ber_rwptr < (char *)&ber->ber_usertag) + i = ber->ber_rwptr - ber->ber_ptr; + else + i = (char *)&ber->ber_usertag - ber->ber_ptr; + AC_MEMCPY(buf, ber->ber_ptr, i); + ber->ber_ptr += i; + } else { + i = 0; } -#endif /* DOS && !_WIN32 */ - - if ( ( sb->sb_options & LBER_MAX_INCOMING_SIZE ) && - *len > sb->sb_max_incoming ) { - return( LBER_DEFAULT ); + ber->ber_len = tlen; + + /* now fill the buffer. */ + + /* make sure length is reasonable */ + if ( ber->ber_len == 0 ) { + errno = ERANGE; + return LBER_DEFAULT; + } else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, + "ber_get_next: sockbuf_max_incoming limit hit " + "(%d > %d)\n", ber->ber_len, sb->sb_max_incoming )); +#else + ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug, + "ber_get_next: sockbuf_max_incoming limit hit " + "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming ); +#endif + errno = ERANGE; + return LBER_DEFAULT; } - if ( (ber->ber_buf = (char *) malloc( (size_t)*len )) == NULL ) { - return( LBER_DEFAULT ); + if (ber->ber_buf==NULL) { + ber_len_t l = ber->ber_rwptr - ber->ber_ptr; + /* ber->ber_ptr is always <= ber->ber->ber_rwptr. + * make sure ber->ber_len agrees with what we've + * already read. + */ + if ( ber->ber_len < i + l ) { + errno = ERANGE; + return LBER_DEFAULT; + } + ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len + 1 ); + if (ber->ber_buf==NULL) { + return LBER_DEFAULT; + } + ber->ber_end = ber->ber_buf + ber->ber_len; + if (i) { + AC_MEMCPY(ber->ber_buf, buf, i); + } + if (l > 0) { + AC_MEMCPY(ber->ber_buf + i, ber->ber_ptr, l); + i += l; + } + ber->ber_ptr = ber->ber_buf; + ber->ber_usertag = 0; + if ((ber_len_t)i == ber->ber_len) { + goto done; + } + ber->ber_rwptr = ber->ber_buf + i; } - ber->ber_ptr = ber->ber_buf; - ber->ber_end = ber->ber_buf + *len; - ber->ber_rwptr = ber->ber_buf; } - toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr; - do { - if ( (rc = BerRead( sb, ber->ber_rwptr, (long)toread )) <= 0 ) { - return( LBER_DEFAULT ); + if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) { + ber_slen_t res; + ber_slen_t to_go; + + to_go = ber->ber_end - ber->ber_rwptr; + assert( to_go > 0 ); + + res = ber_int_sb_read( sb, ber->ber_rwptr, to_go ); + if (res<=0) + return LBER_DEFAULT; + ber->ber_rwptr+=res; + + if (res<to_go) { +#if defined( EWOULDBLOCK ) + errno = EWOULDBLOCK; +#elif defined( EAGAIN ) + errno = EAGAIN; +#endif + return LBER_DEFAULT; } - - toread -= rc; - ber->ber_rwptr += rc; - } while ( toread > 0 ); - -#ifdef LDAP_DEBUG - if ( lber_debug ) { - fprintf( stderr, "ber_get_next: tag 0x%lx len %ld contents:\n", - tag, ber->ber_len ); - if ( lber_debug > 1 ) - ber_dump( ber, 1 ); - } +done: + ber->ber_rwptr = NULL; + *len = ber->ber_len; + if ( ber->ber_debug ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "liblber", LDAP_LEVEL_DETAIL1, + "ber_get_next: tag 0x%lx len %ld\n", + ber->ber_tag, ber->ber_len )); + BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 )); +#else + ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, + "ber_get_next: tag 0x%lx len %ld contents:\n", + ber->ber_tag, ber->ber_len ); + ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); #endif + } + return (ber->ber_tag); + } - *len = ber->ber_len; - ber->ber_rwptr = NULL; - return( ber->ber_tag ); + assert( 0 ); /* ber structure is messed up ?*/ + return LBER_DEFAULT; } diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c index 18324260bd0f06edea8dfb01814772a6c474e2d6..70c2d97e732879709e9beae901f9bc3bed22907a 100644 --- a/libraries/libldap/abandon.c +++ b/libraries/libldap/abandon.c @@ -1,43 +1,78 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * abandon.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +/* + * An abandon request looks like this: + * AbandonRequest ::= MessageID + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +static int do_abandon LDAP_P(( + LDAP *ld, + ber_int_t origid, + ber_int_t msgid, + LDAPControl **sctrls, + LDAPControl **cctrls)); + +/* + * ldap_abandon_ext - perform an ldap extended abandon operation. + * + * Parameters: + * ld LDAP descriptor + * msgid The message id of the operation to abandon + * scntrls Server Controls + * ccntrls Client Controls + * + * ldap_abandon_ext returns a LDAP error code. + * (LDAP_SUCCESS if everything went ok) + * + * Example: + * ldap_abandon_ext( ld, msgid, scntrls, ccntrls ); + */ +int +ldap_abandon_ext( + LDAP *ld, + int msgid, + LDAPControl **sctrls, + LDAPControl **cctrls ) +{ + int rc; +#ifdef NEW_LOGGING + LDAP_LOG (( "abandon", LDAP_LEVEL_ARGS, "ldap_abandon_ext %d\n", msgid )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); #endif -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#endif /* DOS */ + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#endif /* MACOS */ + return do_abandon( ld, msgid, msgid, sctrls, cctrls ); +} -#include "lber.h" -#include "ldap.h" -#include "ldap-int.h" -#ifdef NEEDPROTOS -static int do_abandon( LDAP *ld, int origid, int msgid ); -#else /* NEEDPROTOS */ -static int do_abandon(); -#endif /* NEEDPROTOS */ /* - * ldap_abandon - perform an ldap (and X.500) abandon operation. Parameters: + * ldap_abandon - perform an ldap abandon operation. Parameters: * * ld LDAP descriptor * msgid The message id of the operation to abandon @@ -50,39 +85,48 @@ static int do_abandon(); int ldap_abandon( LDAP *ld, int msgid ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "abandon", LDAP_LEVEL_ARGS, "ldap_abandon %d\n", msgid )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); - return( do_abandon( ld, msgid, msgid )); +#endif + return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS + ? 0 : -1; } static int -do_abandon( LDAP *ld, int origid, int msgid ) +do_abandon( + LDAP *ld, + ber_int_t origid, + ber_int_t msgid, + LDAPControl **sctrls, + LDAPControl **cctrls) { BerElement *ber; int i, err, sendabandon; + ber_int_t *old_abandon; Sockbuf *sb; -#ifdef LDAP_REFERRALS LDAPRequest *lr; -#endif /* LDAP_REFERRALS */ - - /* - * An abandon request looks like this: - * AbandonRequest ::= MessageID - */ +#ifdef NEW_LOGGING + LDAP_LOG (( "abandon", LDAP_LEVEL_ARGS, "do_abandon %d, msgid %d\n", + origid, msgid )); +#else Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); +#endif sendabandon = 1; -#ifdef LDAP_REFERRALS /* find the request that we are abandoning */ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { if ( lr->lr_msgid == msgid ) { /* this message */ break; } - if ( lr->lr_origid == msgid ) { /* child: abandon it */ - do_abandon( ld, msgid, lr->lr_msgid ); + if ( lr->lr_origid == msgid ) {/* child: abandon it */ + (void) do_abandon( ld, + msgid, lr->lr_msgid, sctrls, cctrls ); } } @@ -90,54 +134,86 @@ do_abandon( LDAP *ld, int origid, int msgid ) if ( origid == msgid && lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; - return( -1 ); + return( LDAP_PARAM_ERROR ); } if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } } -#endif /* LDAP_REFERRALS */ if ( ldap_msgdelete( ld, msgid ) == 0 ) { ld->ld_errno = LDAP_SUCCESS; - return( 0 ); + return LDAP_SUCCESS; } err = 0; if ( sendabandon ) { - /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { + if( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { + /* not connected */ + err = -1; + ld->ld_errno = LDAP_SERVER_DOWN; + + } else if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + /* BER element alocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; + } else { -#ifdef CLDAP - if ( ld->ld_sb.sb_naddr > 0 ) { - err = ber_printf( ber, "{isti}", - ++ld->ld_msgid, ld->ld_cldapdn, - LDAP_REQ_ABANDON, msgid ); +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { + err = ber_write( ber, ld->ld_options.ldo_peer, + sizeof(struct sockaddr), 0); + } + if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == + LDAP_VERSION2) { + char *dn = ld->ld_options.ldo_cldapdn; + if (!dn) dn = ""; + err = ber_printf( ber, "{isti", /* '}' */ + ++ld->ld_msgid, dn, + LDAP_REQ_ABANDON, msgid ); + } else +#endif + { + /* create a message to send */ + err = ber_printf( ber, "{iti", /* '}' */ + ++ld->ld_msgid, + LDAP_REQ_ABANDON, msgid ); + } + + if( err == -1 ) { + /* encoding error */ + ld->ld_errno = LDAP_ENCODING_ERROR; + } else { -#endif /* CLDAP */ - err = ber_printf( ber, "{iti}", ++ld->ld_msgid, - LDAP_REQ_ABANDON, msgid ); -#ifdef CLDAP + /* Put Server Controls */ + if ( ldap_int_put_controls( ld, sctrls, ber ) + != LDAP_SUCCESS ) + { + err = -1; + + } else { + /* close '{' */ + err = ber_printf( ber, /*{*/ "N}" ); + + if( err == -1 ) { + /* encoding error */ + ld->ld_errno = LDAP_ENCODING_ERROR; + } + } } -#endif /* CLDAP */ if ( err == -1 ) { - ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); + } else { /* send the message */ -#ifdef LDAP_REFERRALS if ( lr != NULL ) { sb = lr->lr_conn->lconn_sb; } else { - sb = &ld->ld_sb; + sb = ld->ld_sb; } -#else /* LDAP_REFERRALS */ - sb = &ld->ld_sb; -#endif /* LDAP_REFERRALS */ + if ( ber_flush( sb, ber, 1 ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; @@ -148,39 +224,38 @@ do_abandon( LDAP *ld, int origid, int msgid ) } } -#ifdef LDAP_REFERRALS if ( lr != NULL ) { if ( sendabandon ) { - free_connection( ld, lr->lr_conn, 0, 1 ); + ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } if ( origid == msgid ) { - free_request( ld, lr ); + ldap_free_request( ld, lr ); } } -#endif /* LDAP_REFERRALS */ + i = 0; + if ( ld->ld_abandoned != NULL ) { + for ( ; ld->ld_abandoned[i] != -1; i++ ) + ; /* NULL */ + } + + old_abandon = ld->ld_abandoned; + ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *) + ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) ); + if ( ld->ld_abandoned == NULL ) { - if ( (ld->ld_abandoned = (int *) malloc( 2 * sizeof(int) )) - == NULL ) { - ld->ld_errno = LDAP_NO_MEMORY; - return( -1 ); - } - i = 0; - } else { - for ( i = 0; ld->ld_abandoned[i] != -1; i++ ) - ; /* NULL */ - if ( (ld->ld_abandoned = (int *) realloc( (char *) - ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) { - ld->ld_errno = LDAP_NO_MEMORY; - return( -1 ); - } + ld->ld_abandoned = old_abandon; + ld->ld_errno = LDAP_NO_MEMORY; + return( ld->ld_errno ); } + ld->ld_abandoned[i] = msgid; ld->ld_abandoned[i + 1] = -1; if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } - return( err ); + + return( ld->ld_errno ); } diff --git a/libraries/libldap/add.c b/libraries/libldap/add.c index b79cd09b9d4a4eddf1f07cab297b3d55a6a3d797..1ce57eba7f6f95d4fa09a3796ea268aa5f8febf1 100644 --- a/libraries/libldap/add.c +++ b/libraries/libldap/add.c @@ -1,37 +1,38 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * add.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif - -#include <stdio.h> -#include <string.h> +/* + * An add request looks like this: + * AddRequest ::= SEQUENCE { + * entry DistinguishedName, + * attrs SEQUENCE OF SEQUENCE { + * type AttributeType, + * values SET OF AttributeValue + * } + * } + */ -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ +#include "portable.h" -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#endif /* DOS */ +#include <stdio.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif /* !MACOS && !DOS */ +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" /* - * ldap_add - initiate an ldap (and X.500) add operation. Parameters: + * ldap_add - initiate an ldap add operation. Parameters: * * ld LDAP descriptor * dn DN of the entry to add @@ -50,70 +51,141 @@ static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of * msgid = ldap_add( ld, dn, attrs ); */ int -ldap_add( LDAP *ld, char *dn, LDAPMod **attrs ) +ldap_add( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs ) +{ + int rc; + int msgid; + + rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid ); + + if ( rc != LDAP_SUCCESS ) + return -1; + + return msgid; +} + + +/* + * ldap_add_ext - initiate an ldap extended add operation. Parameters: + * + * ld LDAP descriptor + * dn DN of the entry to add + * mods List of attributes for the entry. This is a null- + * terminated array of pointers to LDAPMod structures. + * only the type and values in the structures need be + * filled in. + * sctrl Server Controls + * cctrl Client Controls + * msgidp Message ID pointer + * + * Example: + * LDAPMod *attrs[] = { + * { 0, "cn", { "babs jensen", "babs", 0 } }, + * { 0, "sn", { "jensen", 0 } }, + * { 0, "objectClass", { "person", 0 } }, + * 0 + * } + * rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid ); + */ +int +ldap_add_ext( + LDAP *ld, + LDAP_CONST char *dn, + LDAPMod **attrs, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) { BerElement *ber; int i, rc; - /* - * An add request looks like this: - * AddRequest ::= SEQUENCE { - * entry DistinguishedName, - * attrs SEQUENCE OF SEQUENCE { - * type AttributeType, - * values SET OF AttributeValue - * } - * } - */ +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ENTRY, "ldap_add_ext\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_add_ext\n", 0, 0, 0 ); +#endif + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( dn != NULL ); + assert( msgidp != NULL ); - Debug( LDAP_DEBUG_TRACE, "ldap_add\n", 0, 0, 0 ); + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; } - if ( ber_printf( ber, "{it{s{", ++ld->ld_msgid, LDAP_REQ_ADD, dn ) - == -1 ) { + rc = ber_printf( ber, "{it{s{", /* '}}}' */ + ++ld->ld_msgid, LDAP_REQ_ADD, dn ); + + if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return ld->ld_errno; } /* for each attribute in the entry... */ for ( i = 0; attrs[i] != NULL; i++ ) { if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) { - rc = ber_printf( ber, "{s[V]}", attrs[i]->mod_type, - attrs[i]->mod_values ); + rc = ber_printf( ber, "{s[V]N}", attrs[i]->mod_type, + attrs[i]->mod_bvalues ); } else { - rc = ber_printf( ber, "{s[v]}", attrs[i]->mod_type, + rc = ber_printf( ber, "{s[v]N}", attrs[i]->mod_type, attrs[i]->mod_values ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return ld->ld_errno; } } - if ( ber_printf( ber, "}}}" ) == -1 ) { + if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return ld->ld_errno; + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return ld->ld_errno; } /* send the message */ - return( send_initial_request( ld, LDAP_REQ_ADD, dn, ber )); + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_ADD, dn, ber ); + + if(*msgidp < 0) + return ld->ld_errno; + + return LDAP_SUCCESS; } int -ldap_add_s( LDAP *ld, char *dn, LDAPMod **attrs ) +ldap_add_ext_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAPMod **attrs, + LDAPControl **sctrls, + LDAPControl **cctrls ) { - int msgid; + int msgid, rc; LDAPMessage *res; - if ( (msgid = ldap_add( ld, dn, attrs )) == -1 ) - return( ld->ld_errno ); + rc = ldap_add_ext( ld, dn, attrs, sctrls, cctrls, &msgid ); + + if ( rc != LDAP_SUCCESS ) + return( rc ); if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) return( ld->ld_errno ); @@ -121,3 +193,9 @@ ldap_add_s( LDAP *ld, char *dn, LDAPMod **attrs ) return( ldap_result2error( ld, res, 1 ) ); } +int +ldap_add_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs ) +{ + return ldap_add_ext_s( ld, dn, attrs, NULL, NULL ); +} + diff --git a/libraries/libldap/bind.c b/libraries/libldap/bind.c index 0a0487349eac0d66780f8a90517aca6e1e685b85..076bd179768d085e85a416848986c6657c6d7c46 100644 --- a/libraries/libldap/bind.c +++ b/libraries/libldap/bind.c @@ -1,34 +1,47 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * bind.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; +/* + * BindRequest ::= SEQUENCE { + * version INTEGER, + * name DistinguishedName, -- who + * authentication CHOICE { + * simple [0] OCTET STRING -- passwd +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + * krbv42ldap [1] OCTET STRING + * krbv42dsa [2] OCTET STRING #endif + * sasl [3] SaslCredentials -- LDAPv3 + * } + * } + * + * BindResponse ::= SEQUENCE { + * COMPONENTS OF LDAPResult, + * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 + * } + * + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#ifdef DOS -#include "msdos.h" -#ifdef NCSA -#include "externs.h" -#endif /* NCSA */ -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" /* @@ -45,31 +58,19 @@ static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of */ int -ldap_bind( LDAP *ld, char *dn, char *passwd, int authmethod ) +ldap_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd, int authmethod ) { - /* - * The bind request looks like this: - * BindRequest ::= SEQUENCE { - * version INTEGER, - * name DistinguishedName, -- who - * authentication CHOICE { - * simple [0] OCTET STRING -- passwd -#ifdef KERBEROS - * krbv42ldap [1] OCTET STRING - * krbv42dsa [2] OCTET STRING -#endif - * } - * } - * all wrapped up in an LDAPMessage sequence. - */ - +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_ENTRY, "ldap_bind\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 ); +#endif switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind( ld, dn, passwd ) ); -#ifdef KERBEROS +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND case LDAP_AUTH_KRBV41: return( ldap_kerberos_bind1( ld, dn ) ); @@ -77,6 +78,10 @@ ldap_bind( LDAP *ld, char *dn, char *passwd, int authmethod ) return( ldap_kerberos_bind2( ld, dn ) ); #endif + case LDAP_AUTH_SASL: + /* user must use ldap_sasl_bind */ + /* FALL-THRU */ + default: ld->ld_errno = LDAP_AUTH_UNKNOWN; return( -1 ); @@ -98,15 +103,23 @@ ldap_bind( LDAP *ld, char *dn, char *passwd, int authmethod ) * NULL, LDAP_AUTH_KRBV4 ) */ int -ldap_bind_s( LDAP *ld, char *dn, char *passwd, int authmethod ) +ldap_bind_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *passwd, + int authmethod ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_ENTRY, "ldap_bind_s\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_bind_s\n", 0, 0, 0 ); +#endif switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind_s( ld, dn, passwd ) ); -#ifdef KERBEROS +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND case LDAP_AUTH_KRBV4: return( ldap_kerberos_bind_s( ld, dn ) ); @@ -117,17 +130,11 @@ ldap_bind_s( LDAP *ld, char *dn, char *passwd, int authmethod ) return( ldap_kerberos_bind2_s( ld, dn ) ); #endif + case LDAP_AUTH_SASL: + /* user must use ldap_sasl_bind */ + /* FALL-THRU */ + default: return( ld->ld_errno = LDAP_AUTH_UNKNOWN ); } } - - -#ifdef LDAP_REFERRALS -void -ldap_set_rebind_proc( LDAP *ld, int (*rebindproc)( LDAP *ld, char **dnp, - char **passwdp, int *authmethodp, int freeit )) -{ - ld->ld_rebindproc = rebindproc; -} -#endif /* LDAP_REFERRALS */ diff --git a/libraries/libldap/cache.c b/libraries/libldap/cache.c index 197f4fb9e38182c3b7cd36b4ed6e0d05ec828ffe..ccfc763092d3973aac0e8100edb35cceeb2ccba9 100644 --- a/libraries/libldap/cache.c +++ b/libraries/libldap/cache.c @@ -1,70 +1,50 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1993 The Regents of the University of Michigan. * All rights reserved. * * cache.c - local caching support for LDAP */ -#ifndef NO_CACHE - -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1993 The Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include <time.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#ifdef NCSA -#include "externs.h" -#endif /* NCSA */ -#ifdef WINSOCK -#include <time.h> -#endif /* WINSOCK */ -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "ldap-int.h" -#ifdef NEEDPROTOS -static int cache_hash( BerElement *ber ); -static LDAPMessage *msg_dup( LDAPMessage *msg ); -static int request_cmp( BerElement *req1, BerElement *req2 ); -static int chain_contains_dn( LDAPMessage *msg, char *dn ); -static long msg_size( LDAPMessage *msg ); -static void check_cache_memused( LDAPCache *lc ); -static void uncache_entry_or_req( LDAP *ld, char *dn, int msgid ); -#else /* NEEDPROTOS */ -static int cache_hash(); -static LDAPMessage *msg_dup(); -static int request_cmp(); -static int chain_contains_dn(); -static long msg_size(); -static void check_cache_memused(); -static void uncache_entry_or_req(); -#endif /* NEEDPROTOS */ +#ifndef LDAP_NOCACHE +static int cache_hash LDAP_P(( BerElement *ber )); +static LDAPMessage *msg_dup LDAP_P(( LDAPMessage *msg )); +static int request_cmp LDAP_P(( BerElement *req1, BerElement *req2 )); +static int chain_contains_dn LDAP_P(( LDAPMessage *msg, LDAP_CONST char *dn )); +static ber_len_t msg_size LDAP_P(( LDAPMessage *msg )); +static void check_cache_memused LDAP_P(( LDAPCache *lc )); +static void uncache_entry_or_req LDAP_P(( LDAP *ld, LDAP_CONST char *dn, ber_int_t msgid )); + +#endif int -ldap_enable_cache( LDAP *ld, long timeout, long maxmem ) +ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem ) { - if ( ld->ld_cache == NULLLDCACHE ) { - if (( ld->ld_cache = (LDAPCache *)malloc( sizeof( LDAPCache ))) - == NULLLDCACHE ) { +#ifndef LDAP_NOCACHE + if ( ld->ld_cache == NULL ) { + if (( ld->ld_cache = (LDAPCache *)LDAP_MALLOC( sizeof( LDAPCache ))) + == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } - (void) memset( ld->ld_cache, 0, sizeof( LDAPCache )); + (void) memset( ld->ld_cache, '\0', sizeof( LDAPCache )); ld->ld_cache->lc_memused = sizeof( LDAPCache ); } @@ -73,15 +53,20 @@ ldap_enable_cache( LDAP *ld, long timeout, long maxmem ) check_cache_memused( ld->ld_cache ); ld->ld_cache->lc_enabled = 1; return( 0 ); +#else + return( -1 ); +#endif } void ldap_disable_cache( LDAP *ld ) { - if ( ld->ld_cache != NULLLDCACHE ) { +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { ld->ld_cache->lc_enabled = 0; } +#endif } @@ -89,96 +74,130 @@ ldap_disable_cache( LDAP *ld ) void ldap_set_cache_options( LDAP *ld, unsigned long opts ) { - if ( ld->ld_cache != NULLLDCACHE ) { +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { ld->ld_cache->lc_options = opts; } +#endif } void ldap_destroy_cache( LDAP *ld ) { - if ( ld->ld_cache != NULLLDCACHE ) { +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { ldap_flush_cache( ld ); - free( (char *)ld->ld_cache ); - ld->ld_cache = NULLLDCACHE; + LDAP_FREE( (char *)ld->ld_cache ); + ld->ld_cache = NULL; } +#endif } void ldap_flush_cache( LDAP *ld ) { +#ifndef LDAP_NOCACHE int i; LDAPMessage *m, *next; +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_flush_cache\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_flush_cache\n", 0, 0, 0 ); +#endif - if ( ld->ld_cache != NULLLDCACHE ) { + if ( ld->ld_cache != NULL ) { /* delete all requests in the queue */ - for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { + for ( m = ld->ld_cache->lc_requests; m != NULL; m = next ) { next = m->lm_next; ldap_msgfree( m ); } - ld->ld_cache->lc_requests = NULLMSG; + ld->ld_cache->lc_requests = NULL; /* delete all messages in the cache */ for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { for ( m = ld->ld_cache->lc_buckets[ i ]; - m != NULLMSG; m = next ) { + m != NULL; m = next ) { next = m->lm_next; ldap_msgfree( m ); } - ld->ld_cache->lc_buckets[ i ] = NULLMSG; + ld->ld_cache->lc_buckets[ i ] = NULL; } ld->ld_cache->lc_memused = sizeof( LDAPCache ); } +#endif } void ldap_uncache_request( LDAP *ld, int msgid ) { - Debug( LDAP_DEBUG_TRACE, "ldap_uncache_request %d ld_cache %x\n", - msgid, ld->ld_cache, 0 ); +#ifndef LDAP_NOCACHE +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, + "ldap_uncache_request %d ld_cache %lx\n", + msgid, (long) ld->ld_cache )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_uncache_request %d ld_cache %lx\n", + msgid, (long) ld->ld_cache, 0 ); +#endif uncache_entry_or_req( ld, NULL, msgid ); +#endif } void -ldap_uncache_entry( LDAP *ld, char *dn ) +ldap_uncache_entry( LDAP *ld, LDAP_CONST char *dn ) { - Debug( LDAP_DEBUG_TRACE, "ldap_uncache_entry %s ld_cache %x\n", - dn, ld->ld_cache, 0 ); +#ifndef LDAP_NOCACHE +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, + "ldap_uncache_entry %s ld_cache %lx\n", + dn, (long) ld->ld_cache )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_uncache_entry %s ld_cache %lx\n", + dn, (long) ld->ld_cache, 0 ); +#endif uncache_entry_or_req( ld, dn, 0 ); +#endif } +#ifndef LDAP_NOCACHE + static void uncache_entry_or_req( LDAP *ld, - char *dn, /* if non-NULL, uncache entry */ - int msgid ) /* request to uncache (if dn == NULL) */ + const char *dn, /* if non-NULL, uncache entry */ + ber_int_t msgid ) /* request to uncache (if dn == NULL) */ { int i; LDAPMessage *m, *prev, *next; +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, + "uncache_entry_or_req dn %s msgid %ld ld_cache %lx\n", + dn, (long) msgid, (long) ld->ld_cache )); +#else Debug( LDAP_DEBUG_TRACE, - "ldap_uncache_entry_or_req dn %s msgid %d ld_cache %x\n", - dn, msgid, ld->ld_cache ); + "ldap_uncache_entry_or_req dn %s msgid %ld ld_cache %lx\n", + dn, (long) msgid, (long) ld->ld_cache ); +#endif - if ( ld->ld_cache == NULLLDCACHE ) { + if ( ld->ld_cache == NULL ) { return; } /* first check the request queue */ - prev = NULLMSG; - for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { + prev = NULL; + for ( m = ld->ld_cache->lc_requests; m != NULL; m = next ) { next = m->lm_next; if (( dn != NULL && chain_contains_dn( m, dn )) || ( dn == NULL && m->lm_msgid == msgid )) { - if ( prev == NULLMSG ) { + if ( prev == NULL ) { ld->ld_cache->lc_requests = next; } else { prev->lm_next = next; @@ -192,13 +211,13 @@ uncache_entry_or_req( LDAP *ld, /* now check the rest of the cache */ for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { - prev = NULLMSG; - for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULLMSG; + prev = NULL; + for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULL; m = next ) { next = m->lm_next; if (( dn != NULL && chain_contains_dn( m, dn )) || ( dn == NULL && m->lm_msgid == msgid )) { - if ( prev == NULLMSG ) { + if ( prev == NULL ) { ld->ld_cache->lc_buckets[ i ] = next; } else { prev->lm_next = next; @@ -212,36 +231,42 @@ uncache_entry_or_req( LDAP *ld, } } +#endif void -add_request_to_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) +ldap_add_request_to_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request ) { +#ifndef LDAP_NOCACHE LDAPMessage *new; - long len; + ber_len_t len; - Debug( LDAP_DEBUG_TRACE, "add_request_to_cache\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_add_request_to_cache\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_add_request_to_cache\n", 0, 0, 0 ); +#endif ld->ld_errno = LDAP_SUCCESS; - if ( ld->ld_cache == NULLLDCACHE || + if ( ld->ld_cache == NULL || ( ld->ld_cache->lc_enabled == 0 )) { return; } - if (( new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) + if (( new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) )) != NULL ) { - if (( new->lm_ber = alloc_ber_with_options( ld )) == NULLBER ) { - free( (char *)new ); + if (( new->lm_ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + LDAP_FREE( (char *)new ); return; } len = request->ber_ptr - request->ber_buf; - if (( new->lm_ber->ber_buf = (char *) malloc( (size_t)len )) + if (( new->lm_ber->ber_buf = (char *) ber_memalloc( (size_t)len )) == NULL ) { ber_free( new->lm_ber, 0 ); - free( (char *)new ); + LDAP_FREE( (char *)new ); ld->ld_errno = LDAP_NO_MEMORY; return; } - SAFEMEMCPY( new->lm_ber->ber_buf, request->ber_buf, + AC_MEMCPY( new->lm_ber->ber_buf, request->ber_buf, (size_t)len ); new->lm_ber->ber_ptr = new->lm_ber->ber_buf; new->lm_ber->ber_end = new->lm_ber->ber_buf + len; @@ -252,32 +277,52 @@ add_request_to_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) } else { ld->ld_errno = LDAP_NO_MEMORY; } +#endif } void -add_result_to_cache( LDAP *ld, LDAPMessage *result ) +ldap_add_result_to_cache( LDAP *ld, LDAPMessage *result ) { +#ifndef LDAP_NOCACHE LDAPMessage *m, **mp, *req, *new, *prev; int err, keep; - Debug( LDAP_DEBUG_TRACE, "add_result_to_cache: id %d, type %d\n", - result->lm_msgid, result->lm_msgtype, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, + "ldap_add_result_to_cache: id %ld, type %ld\n", + (long) result->lm_msgid, (long) result->lm_msgtype )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_add_result_to_cache: id %ld, type %ld\n", + (long) result->lm_msgid, (long) result->lm_msgtype, 0 ); +#endif - if ( ld->ld_cache == NULLLDCACHE || + if ( ld->ld_cache == NULL || ( ld->ld_cache->lc_enabled == 0 )) { +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "ldap_add_result_to_cache: cache disabled\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: cache disabled\n", 0, 0, 0 ); +#endif return; } if ( result->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + result->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && result->lm_msgtype != LDAP_RES_SEARCH_RESULT && result->lm_msgtype != LDAP_RES_COMPARE ) { /* * only cache search and compare operations */ +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "ldap_add_result_to_cache: " + "only caching search & compare operations\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: only caching search & compare operations\n", 0, 0, 0 ); +#endif return; } @@ -286,7 +331,7 @@ add_result_to_cache( LDAP *ld, LDAPMessage *result ) * result to it. if this result completes the results for the * request, add the request/result chain to the cache proper. */ - prev = NULLMSG; + prev = NULL; for ( m = ld->ld_cache->lc_requests; m != NULL; m = m->lm_next ) { if ( m->lm_msgid == result->lm_msgid ) { break; @@ -294,16 +339,22 @@ add_result_to_cache( LDAP *ld, LDAPMessage *result ) prev = m; } - if ( m != NULLMSG ) { /* found request; add to end of chain */ + if ( m != NULL ) { /* found request; add to end of chain */ req = m; - for ( ; m->lm_chain != NULLMSG; m = m->lm_chain ) + for ( ; m->lm_chain != NULL; m = m->lm_chain ) ; - if (( new = msg_dup( result )) != NULLMSG ) { - new->lm_chain = NULLMSG; + if (( new = msg_dup( result )) != NULL ) { + new->lm_chain = NULL; m->lm_chain = new; +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "ldap_add_result_to_cache: " + "result added to cache request chain\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: result added to cache request chain\n", 0, 0, 0 ); +#endif } if ( result->lm_msgtype == LDAP_RES_SEARCH_RESULT || result->lm_msgtype == LDAP_RES_COMPARE ) { @@ -330,16 +381,22 @@ add_result_to_cache( LDAP *ld, LDAPMessage *result ) keep = 1; } - if ( prev == NULLMSG ) { + if ( prev == NULL ) { ld->ld_cache->lc_requests = req->lm_next; } else { prev->lm_next = req->lm_next; } if ( !keep ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "ldap_add_result_to_cache: " + "not caching result with error\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: not caching result with error %d\n", err, 0, 0 ); +#endif ldap_msgfree( req ); } else { mp = &ld->ld_cache->lc_buckets[ @@ -349,15 +406,28 @@ add_result_to_cache( LDAP *ld, LDAPMessage *result ) req->lm_time = (long) time( NULL ); ld->ld_cache->lc_memused += msg_size( req ); check_cache_memused( ld->ld_cache ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "ldap_add_result_to_cache: " + "cached result with error\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: cached result with error %d\n", err, 0, 0 ); +#endif } } } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "ldap_add_result_to_cache: " + "msgid not in request list\n" )); +#else Debug( LDAP_DEBUG_TRACE, "artc: msgid not in request list\n", 0, 0, 0 ); +#endif } +#endif } @@ -369,31 +439,45 @@ add_result_to_cache( LDAP *ld, LDAPMessage *result ) * will find them. */ int -check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) +ldap_check_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request ) { +#ifndef LDAP_NOCACHE LDAPMessage *m, *new, *prev, *next; BerElement reqber; int first, hash; - unsigned long validtime; + time_t c_time; - Debug( LDAP_DEBUG_TRACE, "check_cache\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_check_cache\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_check_cache\n", 0, 0, 0 ); +#endif - if ( ld->ld_cache == NULLLDCACHE || + if ( ld->ld_cache == NULL || ( ld->ld_cache->lc_enabled == 0 )) { return( -1 ); } + memset( &reqber, '\0', sizeof(reqber) ); + reqber.ber_valid = LBER_VALID_BERELEMENT; reqber.ber_buf = reqber.ber_ptr = request->ber_buf; reqber.ber_end = request->ber_ptr; + reqber.ber_debug = ber_int_debug; - validtime = (long)time( NULL ) - ld->ld_cache->lc_timeout; + c_time = time( NULL ); - prev = NULLMSG; + prev = NULL; hash = cache_hash( &reqber ); - for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULLMSG; m = next ) { - Debug( LDAP_DEBUG_TRACE,"cc: examining id %d,type %d\n", - m->lm_msgid, m->lm_msgtype, 0 ); - if ( m->lm_time < validtime ) { + for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULL; m = next ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "ldap_check_cache: examining id %ld, type %ld\n", + (long) m->lm_msgid, (long) m->lm_msgtype )); +#else + Debug( LDAP_DEBUG_TRACE,"cc: examining id %ld,type %ld\n", + (long) m->lm_msgid, (long) m->lm_msgtype, 0 ); +#endif + if ( difftime(c_time, m->lm_time) > ld->ld_cache->lc_timeout ) { /* delete expired message */ next = m->lm_next; if ( prev == NULL ) { @@ -401,12 +485,18 @@ check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) } else { prev->lm_next = next; } +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "ldap_check_cache: expired id %ld\n", + (long) m->lm_msgid )); +#else Debug( LDAP_DEBUG_TRACE, "cc: expired id %d\n", m->lm_msgid, 0, 0 ); +#endif ld->ld_cache->lc_memused -= msg_size( m ); ldap_msgfree( m ); } else { - if ( m->lm_msgtype == (int)msgtype && + if ( m->lm_msgtype == msgtype && request_cmp( m->lm_ber, &reqber ) == 0 ) { break; } @@ -415,7 +505,7 @@ check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) } } - if ( m == NULLMSG ) { + if ( m == NULL ) { return( -1 ); } @@ -423,13 +513,13 @@ check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) * add duplicates of responses to incoming queue */ first = 1; - for ( m = m->lm_chain; m != NULLMSG; m = m->lm_chain ) { - if (( new = msg_dup( m )) == NULLMSG ) { + for ( m = m->lm_chain; m != NULL; m = m->lm_chain ) { + if (( new = msg_dup( m )) == NULL ) { return( -1 ); } new->lm_msgid = ld->ld_msgid; - new->lm_chain = NULLMSG; + new->lm_chain = NULL; if ( first ) { new->lm_next = ld->ld_responses; ld->ld_responses = new; @@ -438,20 +528,35 @@ check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ) prev->lm_chain = new; } prev = new; - Debug( LDAP_DEBUG_TRACE, "cc: added type %d\n", - new->lm_msgtype, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "ldap_check_cache: added type %ld\n", + (long) m->lm_msgtype )); +#else + Debug( LDAP_DEBUG_TRACE, "cc: added type %ld\n", + (long) new->lm_msgtype, 0, 0 ); +#endif } +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "ldap_check_cache: result returned from cache\n" )); +#else Debug( LDAP_DEBUG_TRACE, "cc: result returned from cache\n", 0, 0, 0 ); +#endif return( 0 ); +#else + return( -1 ); +#endif } +#ifndef LDAP_NOCACHE static int cache_hash( BerElement *ber ) { BerElement bercpy; - unsigned long len; + ber_len_t len; /* * just take the length of the packet and mod with # of buckets @@ -464,8 +569,14 @@ cache_hash( BerElement *ber ) len = bercpy.ber_end - bercpy.ber_ptr; } +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_RESULTS, + "cache_hash: len is %ld, returning %ld\n", + len, len % LDAP_CACHE_BUCKETS )); +#else Debug( LDAP_DEBUG_TRACE, "cache_hash: len is %ld, returning %ld\n", len, len % LDAP_CACHE_BUCKETS, 0 ); +#endif return( (int) ( len % LDAP_CACHE_BUCKETS )); } @@ -474,22 +585,22 @@ static LDAPMessage * msg_dup( LDAPMessage *msg ) { LDAPMessage *new; - long len; + ber_len_t len; - if (( new = (LDAPMessage *)malloc( sizeof(LDAPMessage))) != NULL ) { + if (( new = (LDAPMessage *)LDAP_MALLOC( sizeof(LDAPMessage))) != NULL ) { *new = *msg; /* struct copy */ - if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULLBER ) { - free( (char *)new ); - return( NULLMSG ); + if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULL ) { + LDAP_FREE( (char *)new ); + return( NULL ); } len = msg->lm_ber->ber_end - msg->lm_ber->ber_buf; - if (( new->lm_ber->ber_buf = (char *) malloc( + if (( new->lm_ber->ber_buf = (char *) ber_memalloc( (size_t)len )) == NULL ) { ber_free( new->lm_ber, 0 ); - free( (char *)new ); - return( NULLMSG ); + LDAP_FREE( (char *)new ); + return( NULL ); } - SAFEMEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf, + AC_MEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf, (size_t)len ); new->lm_ber->ber_ptr = new->lm_ber->ber_buf + ( msg->lm_ber->ber_ptr - msg->lm_ber->ber_buf ); @@ -503,7 +614,7 @@ msg_dup( LDAPMessage *msg ) static int request_cmp( BerElement *req1, BerElement *req2 ) { - unsigned long len; + ber_len_t len; BerElement r1, r2; r1 = *req1; /* struct copies */ @@ -524,7 +635,9 @@ request_cmp( BerElement *req1, BerElement *req2 ) /* * check remaining length and bytes if necessary */ - if (( len = r1.ber_end - r1.ber_ptr ) != r2.ber_end - r2.ber_ptr ) { + if (( len = r1.ber_end - r1.ber_ptr ) != + (ber_len_t) (r2.ber_end - r2.ber_ptr) ) + { return( -1 ); /* different lengths */ } return( memcmp( r1.ber_ptr, r2.ber_ptr, (size_t)len )); @@ -532,11 +645,11 @@ request_cmp( BerElement *req1, BerElement *req2 ) static int -chain_contains_dn( LDAPMessage *msg, char *dn ) +chain_contains_dn( LDAPMessage *msg, const char *dn ) { LDAPMessage *m; BerElement ber; - long msgid; + ber_int_t msgid; char *s; int rc; @@ -545,9 +658,9 @@ chain_contains_dn( LDAPMessage *msg, char *dn ) * first check the base or dn of the request */ ber = *msg->lm_ber; /* struct copy */ - if ( ber_scanf( &ber, "{i{a", &msgid, &s ) != LBER_ERROR ) { + if ( ber_scanf( &ber, "{i{a" /*}}*/, &msgid, &s ) != LBER_ERROR ) { rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; - free( s ); + LDAP_FREE( s ); if ( rc != 0 ) { return( rc ); } @@ -561,14 +674,14 @@ chain_contains_dn( LDAPMessage *msg, char *dn ) * now check the dn of each search result */ rc = 0; - for ( m = msg->lm_chain; m != NULLMSG && rc == 0 ; m = m->lm_chain ) { + for ( m = msg->lm_chain; m != NULL && rc == 0 ; m = m->lm_chain ) { if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) { continue; } ber = *m->lm_ber; /* struct copy */ - if ( ber_scanf( &ber, "{a", &s ) != LBER_ERROR ) { + if ( ber_scanf( &ber, "{a" /*}*/, &s ) != LBER_ERROR ) { rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; - free( s ); + LDAP_FREE( s ); } } @@ -576,14 +689,14 @@ chain_contains_dn( LDAPMessage *msg, char *dn ) } -static long +static ber_len_t msg_size( LDAPMessage *msg ) { LDAPMessage *m; - long size; + ber_len_t size; size = 0; - for ( m = msg; m != NULLMSG; m = m->lm_chain ) { + for ( m = msg; m != NULL; m = m->lm_chain ) { size += ( sizeof( LDAPMessage ) + m->lm_ber->ber_end - m->lm_ber->ber_buf ); } @@ -609,35 +722,48 @@ check_cache_memused( LDAPCache *lc ) * } while ( cache size is > SIZE_FACTOR * lc_maxmem ) */ int i; - unsigned long remove_threshold, validtime; + unsigned long remove_threshold; + time_t c_time; LDAPMessage *m, *prev, *next; +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "check_cache_memused: %ld bytes in use (%ld max)\n", + lc->lc_memused, lc->lc_maxmem )); +#else Debug( LDAP_DEBUG_TRACE, "check_cache_memused: %ld bytes in use (%ld max)\n", lc->lc_memused, lc->lc_maxmem, 0 ); +#endif - if ( lc->lc_maxmem <= sizeof( LDAPCache ) + if ( (unsigned) lc->lc_maxmem <= sizeof( LDAPCache ) || lc->lc_memused <= lc->lc_maxmem * SIZE_FACTOR ) { return; } remove_threshold = lc->lc_timeout; while ( lc->lc_memused > lc->lc_maxmem * SIZE_FACTOR ) { - validtime = (long)time( NULL ) - remove_threshold; + c_time = time( NULL ); for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { - prev = NULLMSG; - for ( m = lc->lc_buckets[ i ]; m != NULLMSG; + prev = NULL; + for ( m = lc->lc_buckets[ i ]; m != NULL; m = next ) { next = m->lm_next; - if ( m->lm_time < validtime ) { - if ( prev == NULLMSG ) { + if ( difftime(c_time, m->lm_time) > remove_threshold) { + if ( prev == NULL ) { lc->lc_buckets[ i ] = next; } else { prev->lm_next = next; } lc->lc_memused -= msg_size( m ); +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "check_cache_memused: removed %ld\n", + m->lm_msgid )); +#else Debug( LDAP_DEBUG_TRACE, "ccm: removed %d\n", m->lm_msgid, 0, 0 ); +#endif ldap_msgfree( m ); } else { prev = m; @@ -647,8 +773,14 @@ check_cache_memused( LDAPCache *lc ) remove_threshold *= THRESHOLD_FACTOR; } +#ifdef NEW_LOGGING + LDAP_LOG (( "cache", LDAP_LEVEL_DETAIL1, + "check_cache_memused: reduced usage to %ld bytes\n", + lc->lc_memused )); +#else Debug( LDAP_DEBUG_TRACE, "ccm: reduced usage to %ld bytes\n", lc->lc_memused, 0, 0 ); +#endif } #endif /* !NO_CACHE */ diff --git a/libraries/libldap/compare.c b/libraries/libldap/compare.c index 74388f1ceaee99faf49eb85bf54c9d81e2372958..83d7ec125e934325daa614f8e27b0f6f3b25576c 100644 --- a/libraries/libldap/compare.c +++ b/libraries/libldap/compare.c @@ -1,94 +1,178 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * compare.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +/* The compare request looks like this: + * CompareRequest ::= SEQUENCE { + * entry DistinguishedName, + * ava SEQUENCE { + * type AttributeType, + * value AttributeValue + * } + * } + */ -#include <stdio.h> -#include <string.h> +#include "portable.h" -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ +#include <stdio.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" /* - * ldap_compare - perform an ldap (and X.500) compare operation. The dn + * ldap_compare_ext - perform an ldap extended compare operation. The dn * of the entry to compare to and the attribute and value to compare (in * attr and value) are supplied. The msgid of the response is returned. * * Example: - * ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" ) + * struct berval bvalue = { "secret", sizeof("secret")-1 }; + * rc = ldap_compare( ld, "c=us@cn=bob", + * "userPassword", &bvalue, + * sctrl, cctrl, &msgid ) */ int -ldap_compare( LDAP *ld, char *dn, char *attr, char *value ) +ldap_compare_ext( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *attr, + struct berval *bvalue, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) { + int rc; BerElement *ber; - /* The compare request looks like this: - * CompareRequest ::= SEQUENCE { - * entry DistinguishedName, - * ava SEQUENCE { - * type AttributeType, - * value AttributeValue - * } - * } - * and must be wrapped in an LDAPMessage. - */ - +#ifdef NEW_LOGGING + LDAP_LOG (( "compare", LDAP_LEVEL_ENTRY, "ldap_compare\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_compare\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( dn != NULL ); + assert( attr != NULL ); + assert( msgidp != NULL ); + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + return( LDAP_NO_MEMORY ); } - if ( ber_printf( ber, "{it{s{ss}}}", ++ld->ld_msgid, LDAP_REQ_COMPARE, - dn, attr, value ) == -1 ) { + if ( ber_printf( ber, "{it{s{sON}N}", /* '}' */ + ++ld->ld_msgid, + LDAP_REQ_COMPARE, dn, attr, bvalue ) == -1 ) + { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); } -#ifndef NO_CACHE +#ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { - if ( check_cache( ld, LDAP_REQ_COMPARE, ber ) == 0 ) { + if ( ldap_check_cache( ld, LDAP_REQ_COMPARE, ber ) == 0 ) { ber_free( ber, 1 ); ld->ld_errno = LDAP_SUCCESS; - return( ld->ld_msgid ); + *msgidp = ld->ld_msgid; + return( ld->ld_errno ); } - add_request_to_cache( ld, LDAP_REQ_COMPARE, ber ); + ldap_add_request_to_cache( ld, LDAP_REQ_COMPARE, ber ); } -#endif /* NO_CACHE */ +#endif /* LDAP_NOCACHE */ /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_COMPARE, dn, ber )); + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_COMPARE, dn, ber ); + return ( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); } +/* + * ldap_compare_ext - perform an ldap extended compare operation. The dn + * of the entry to compare to and the attribute and value to compare (in + * attr and value) are supplied. The msgid of the response is returned. + * + * Example: + * msgid = ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" ) + */ int -ldap_compare_s( LDAP *ld, char *dn, char *attr, char *value ) +ldap_compare( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *attr, + LDAP_CONST char *value ) { + int msgid; + struct berval bvalue; + + bvalue.bv_val = (char *) value; + bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); + + return ldap_compare_ext( ld, dn, attr, &bvalue, NULL, NULL, &msgid ) == LDAP_SUCCESS + ? msgid : -1; +} + +int +ldap_compare_ext_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *attr, + struct berval *bvalue, + LDAPControl **sctrl, + LDAPControl **cctrl ) +{ + int rc; int msgid; LDAPMessage *res; - if ( (msgid = ldap_compare( ld, dn, attr, value )) == -1 ) - return( ld->ld_errno ); + rc = ldap_compare_ext( ld, dn, attr, bvalue, sctrl, cctrl, &msgid ); + + if ( rc != LDAP_SUCCESS ) + return( rc ); if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) return( ld->ld_errno ); return( ldap_result2error( ld, res, 1 ) ); } + +int +ldap_compare_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *attr, + LDAP_CONST char *value ) +{ + struct berval bvalue; + + bvalue.bv_val = (char *) value; + bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); + + return ldap_compare_ext_s( ld, dn, attr, &bvalue, NULL, NULL ); +} diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c new file mode 100644 index 0000000000000000000000000000000000000000..9925357b0c2065a50d6764155424bd0f5b47eea2 --- /dev/null +++ b/libraries/libldap/controls.c @@ -0,0 +1,474 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* LDAPv3 Controls (RFC2251) + * + * Controls ::= SEQUENCE OF Control + * + * Control ::= SEQUENCE { + * controlType LDAPOID, + * criticality BOOLEAN DEFAULT FALSE, + * controlValue OCTET STRING OPTIONAL + * } + */ + +#include "portable.h" + +#include <ac/stdlib.h> + +#include <ac/time.h> +#include <ac/string.h> + +#include "ldap-int.h" + + +/* + * ldap_int_put_controls + */ + +int +ldap_int_put_controls( + LDAP *ld, + LDAPControl *const *ctrls, + BerElement *ber ) +{ + LDAPControl *const *c; + + assert( ld != NULL ); + assert( ber != NULL ); + + if( ctrls == NULL ) { + /* use default server controls */ + ctrls = ld->ld_sctrls; + } + + if( ctrls == NULL || *ctrls == NULL ) { + return LDAP_SUCCESS; + } + + if ( ld->ld_version < LDAP_VERSION3 ) { + /* LDAPv2 doesn't support controls, + * error if any control is critical + */ + for( c = ctrls ; *c != NULL; c++ ) { + if( (*c)->ldctl_iscritical ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + } + + return LDAP_SUCCESS; + } + + /* Controls are encoded as a sequence of sequences */ + if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + for( c = ctrls ; *c != NULL; c++ ) { + if ( ber_printf( ber, "{s" /*}*/, + (*c)->ldctl_oid ) == -1 ) + { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + if( (*c)->ldctl_iscritical /* only if true */ + && ( ber_printf( ber, "b", + (ber_int_t) (*c)->ldctl_iscritical ) == -1 ) ) + { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + if( (*c)->ldctl_value.bv_val != NULL /* only if we have a value */ + && ( ber_printf( ber, "O", + &((*c)->ldctl_value) ) == -1 ) ) + { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + + if( ber_printf( ber, /*{*/"N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + } + + + if( ber_printf( ber, /*{*/ "}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + return LDAP_SUCCESS; +} + +int ldap_int_get_controls( + BerElement *ber, + LDAPControl ***ctrls ) +{ + int nctrls; + ber_tag_t tag; + ber_len_t len; + char *opaque; + + assert( ber != NULL ); + + if( ctrls == NULL ) { + return LDAP_SUCCESS; + } + *ctrls = NULL; + + len = ber_pvt_ber_remaining( ber ); + + if( len == 0) { + /* no controls */ + return LDAP_SUCCESS; + } + + if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { + if( tag == LBER_ERROR ) { + /* decoding error */ + return LDAP_DECODING_ERROR; + } + + /* ignore unexpected input */ + return LDAP_SUCCESS; + } + + /* set through each element */ + nctrls = 0; + *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) ); + + if( *ctrls == NULL ) { + return LDAP_NO_MEMORY; + } + + *ctrls[nctrls] = NULL; + + for( tag = ber_first_element( ber, &len, &opaque ); + tag != LBER_ERROR; + tag = ber_next_element( ber, &len, opaque ) ) + { + LDAPControl *tctrl; + LDAPControl **tctrls; + + tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) ); + + /* allocate pointer space for current controls (nctrls) + * + this control + extra NULL + */ + tctrls = (tctrl == NULL) ? NULL : + LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); + + if( tctrls == NULL ) { + /* one of the above allocation failed */ + + if( tctrl != NULL ) { + LDAP_FREE( tctrl ); + } + + ldap_controls_free(*ctrls); + *ctrls = NULL; + + return LDAP_NO_MEMORY; + } + + + tctrls[nctrls++] = tctrl; + tctrls[nctrls] = NULL; + + tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); + + if( tag != LBER_ERROR ) { + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LBER_BOOLEAN ) { + ber_int_t crit; + tag = ber_scanf( ber, "b", &crit ); + tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; + } + + if( tag != LBER_ERROR ) { + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LBER_OCTETSTRING ) { + tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); + + } else { + tctrl->ldctl_value.bv_val = NULL; + } + + if( tag == LBER_ERROR ) { + *ctrls = NULL; + ldap_controls_free( tctrls ); + return LDAP_DECODING_ERROR; + } + + *ctrls = tctrls; + } + + return LDAP_SUCCESS; +} + +/* + * Free a LDAPControl + */ +void +ldap_control_free( LDAPControl *c ) +{ +#ifdef LDAP_MEMORY_DEBUG + assert( c != NULL ); +#endif + + if ( c != NULL ) { + if( c->ldctl_oid != NULL) { + LDAP_FREE( c->ldctl_oid ); + } + + if( c->ldctl_value.bv_val != NULL ) { + LDAP_FREE( c->ldctl_value.bv_val ); + } + + LDAP_FREE( c ); + } +} + +/* + * Free an array of LDAPControl's + */ +void +ldap_controls_free( LDAPControl **controls ) +{ +#ifdef LDAP_MEMORY_DEBUG + assert( controls != NULL ); +#endif + + if ( controls != NULL ) { + int i; + + for( i=0; controls[i] != NULL; i++) { + ldap_control_free( controls[i] ); + } + + LDAP_FREE( controls ); + } +} + +/* + * Duplicate an array of LDAPControl + */ +LDAPControl ** +ldap_controls_dup( LDAPControl *const *controls ) +{ + LDAPControl **new; + int i; + + if ( controls == NULL ) { + return NULL; + } + + /* count the controls */ + for(i=0; controls[i] != NULL; i++) /* empty */ ; + + if( i < 1 ) { + /* no controls to duplicate */ + return NULL; + } + + new = (LDAPControl **) LDAP_MALLOC( i * sizeof(LDAPControl *) ); + + if( new == NULL ) { + /* memory allocation failure */ + return NULL; + } + + /* duplicate the controls */ + for(i=0; controls[i] != NULL; i++) { + new[i] = ldap_control_dup( controls[i] ); + + if( new[i] == NULL ) { + ldap_controls_free( new ); + return NULL; + } + } + + new[i] = NULL; + + return new; +} + +/* + * Duplicate a LDAPControl + */ +LDAPControl * +ldap_control_dup( const LDAPControl *c ) +{ + LDAPControl *new; + + if ( c == NULL ) { + return NULL; + } + + new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); + + if( new == NULL ) { + return NULL; + } + + if( c->ldctl_oid != NULL ) { + new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid ); + + if(new->ldctl_oid == NULL) { + LDAP_FREE( new ); + return NULL; + } + + } else { + new->ldctl_oid = NULL; + } + + if( c->ldctl_value.bv_val != NULL ) { + new->ldctl_value.bv_val = + (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 ); + + if(new->ldctl_value.bv_val == NULL) { + if(new->ldctl_oid != NULL) { + LDAP_FREE( new->ldctl_oid ); + } + LDAP_FREE( new ); + return NULL; + } + + new->ldctl_value.bv_len = c->ldctl_value.bv_len; + + AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, + c->ldctl_value.bv_len ); + + new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0'; + + } else { + new->ldctl_value.bv_len = 0; + new->ldctl_value.bv_val = NULL; + } + + new->ldctl_iscritical = c->ldctl_iscritical; + return new; +} + +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */ +/*--- + * This notice applies to changes, created by or for Novell, Inc., + * to preexisting works for which notices appear elsewhere in this file. + * + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. + * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION + * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT + * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE + * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS + * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC + * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE + * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + *--- + * Modification to OpenLDAP source by Novell, Inc. + * June 2000 sfs Added control utilities + */ +/*--- + ldap_create_control + + Internal function to create an LDAP control from the encoded BerElement. + + requestOID (IN) The OID to use in creating the control. + + ber (IN) The encoded BerElement to use in creating the control. + + iscritical (IN) 0 - Indicates the control is not critical to the operation. + non-zero - The control is critical to the operation. + + ctrlp (OUT) Returns a pointer to the LDAPControl created. This control + SHOULD be freed by calling ldap_control_free() when done. +---*/ + +int +ldap_create_control( + LDAP_CONST char *requestOID, + BerElement *ber, + int iscritical, + LDAPControl **ctrlp ) +{ + LDAPControl *ctrl; + struct berval *bvalp; + + if ( requestOID == NULL || ctrlp == NULL ) { + return LDAP_PARAM_ERROR; + } + + ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); + if ( ctrl == NULL ) { + return LDAP_NO_MEMORY; + } + + if ( ber_flatten( ber, &bvalp ) == -1 ) { + LDAP_FREE( ctrl ); + return LDAP_NO_MEMORY; + } + + ctrl->ldctl_value = *bvalp; + ber_memfree( bvalp ); + + ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); + ctrl->ldctl_iscritical = iscritical; + + if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + + *ctrlp = ctrl; + return LDAP_SUCCESS; +} + +/* + * check for critical client controls and bitch if present + * if we ever support critical controls, we'll have to + * find a means for maintaining per API call control + * information. + */ +int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls ) +{ + LDAPControl *const *c; + + assert( ld != NULL ); + + if( ctrls == NULL ) { + /* use default server controls */ + ctrls = ld->ld_cctrls; + } + + if( ctrls == NULL || *ctrls == NULL ) { + return LDAP_SUCCESS; + } + + for( c = ctrls ; *c != NULL; c++ ) { + if( (*c)->ldctl_iscritical ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + } + + return LDAP_SUCCESS; +} diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c new file mode 100644 index 0000000000000000000000000000000000000000..5f128098d353f079f95da282ee06beb5c46ecb95 --- /dev/null +++ b/libraries/libldap/cyrus.c @@ -0,0 +1,1120 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1999-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/errno.h> +#include <ac/ctype.h> + +#include "ldap-int.h" + +#ifdef HAVE_CYRUS_SASL + +#ifdef LDAP_R_COMPILE +ldap_pvt_thread_mutex_t ldap_int_sasl_mutex; +#endif + +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#else +#include <sasl.h> +#endif + +#if SASL_VERSION_MAJOR >= 2 +#define SASL_CONST const +#else +#define SASL_CONST +#endif + +/* +* Various Cyrus SASL related stuff. +*/ + +int ldap_int_sasl_init( void ) +{ + /* XXX not threadsafe */ + static int sasl_initialized = 0; + + static sasl_callback_t client_callbacks[] = { +#ifdef SASL_CB_GETREALM + { SASL_CB_GETREALM, NULL, NULL }, +#endif + { SASL_CB_USER, NULL, NULL }, + { SASL_CB_AUTHNAME, NULL, NULL }, + { SASL_CB_PASS, NULL, NULL }, + { SASL_CB_ECHOPROMPT, NULL, NULL }, + { SASL_CB_NOECHOPROMPT, NULL, NULL }, + { SASL_CB_LIST_END, NULL, NULL } + }; + + if ( sasl_initialized ) { + return 0; + } + +#ifndef CSRIMALLOC + sasl_set_alloc( + ber_memalloc, + ber_memcalloc, + ber_memrealloc, + ber_memfree ); +#endif /* CSRIMALLOC */ + +#ifdef LDAP_R_COMPILE + sasl_set_mutex( + ldap_pvt_sasl_mutex_new, + ldap_pvt_sasl_mutex_lock, + ldap_pvt_sasl_mutex_unlock, + ldap_pvt_sasl_mutex_dispose ); + + ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex ); +#endif + + if ( sasl_client_init( client_callbacks ) == SASL_OK ) { + sasl_initialized = 1; + return 0; + } + + return -1; +} + +/* + * SASL encryption support for LBER Sockbufs + */ + +struct sb_sasl_data { + sasl_conn_t *sasl_context; + Sockbuf_Buf sec_buf_in; + Sockbuf_Buf buf_in; + Sockbuf_Buf buf_out; +}; + +static int +sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + struct sb_sasl_data *p; + + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) + return -1; + p->sasl_context = (sasl_conn_t *)arg; + ber_pvt_sb_buf_init( &p->sec_buf_in ); + ber_pvt_sb_buf_init( &p->buf_in ); + ber_pvt_sb_buf_init( &p->buf_out ); + if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) { + errno = ENOMEM; + return -1; + } + + sbiod->sbiod_pvt = p; + + return 0; +} + +static int +sb_sasl_remove( Sockbuf_IO_Desc *sbiod ) +{ + struct sb_sasl_data *p; + + assert( sbiod != NULL ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; +#if SASL_VERSION_MAJOR >= 2 + /* + * SASLv2 encode/decode buffers are managed by + * libsasl2. Ensure they are not freed by liblber. + */ + p->buf_in.buf_base = NULL; + p->buf_out.buf_base = NULL; +#endif + ber_pvt_sb_buf_destroy( &p->sec_buf_in ); + ber_pvt_sb_buf_destroy( &p->buf_in ); + ber_pvt_sb_buf_destroy( &p->buf_out ); + LBER_FREE( p ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static ber_len_t +sb_sasl_pkt_length( const unsigned char *buf, int debuglevel ) +{ + ber_len_t size; + + assert( buf != NULL ); + + size = buf[0] << 24 + | buf[1] << 16 + | buf[2] << 8 + | buf[3]; + + /* we really should check against actual buffer size set + * in the secopts. + */ + if ( size > SASL_MAX_BUFF_SIZE ) { + /* somebody is trying to mess me up. */ + ber_log_printf( LDAP_DEBUG_ANY, debuglevel, + "sb_sasl_pkt_length: received illegal packet length " + "of %lu bytes\n", (unsigned long)size ); + size = 16; /* this should lead to an error. */ + } + + return size + 4; /* include the size !!! */ +} + +/* Drop a processed packet from the input buffer */ +static void +sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel ) +{ + ber_slen_t len; + + len = sec_buf_in->buf_ptr - sec_buf_in->buf_end; + if ( len > 0 ) + AC_MEMCPY( sec_buf_in->buf_base, sec_buf_in->buf_base + + sec_buf_in->buf_end, len ); + + if ( len >= 4 ) { + sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base, + debuglevel); + } + else { + sec_buf_in->buf_end = 0; + } + sec_buf_in->buf_ptr = len; +} + +static ber_slen_t +sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct sb_sasl_data *p; + ber_slen_t ret, bufptr; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + /* Are there anything left in the buffer? */ + ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len ); + bufptr = ret; + len -= ret; + + if ( len == 0 ) + return bufptr; + +#if SASL_VERSION_MAJOR >= 2 + ber_pvt_sb_buf_init( &p->buf_in ); +#else + ber_pvt_sb_buf_destroy( &p->buf_in ); +#endif + + /* Read the length of the packet */ + while ( p->sec_buf_in.buf_ptr < 4 ) { + ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base, + 4 - p->sec_buf_in.buf_ptr ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + if ( ret <= 0 ) + return ret; + + p->sec_buf_in.buf_ptr += ret; + } + + /* The new packet always starts at p->sec_buf_in.buf_base */ + ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base, + sbiod->sbiod_sb->sb_debug ); + + /* Grow the packet buffer if neccessary */ + if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) && + ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) + { + errno = ENOMEM; + return -1; + } + p->sec_buf_in.buf_end = ret; + + /* Did we read the whole encrypted packet? */ + while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) { + /* No, we have got only a part of it */ + ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr; + + ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + + p->sec_buf_in.buf_ptr, ret ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) + continue; +#endif + if ( ret <= 0 ) + return ret; + + p->sec_buf_in.buf_ptr += ret; + } + + /* Decode the packet */ + ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base, + p->sec_buf_in.buf_end, + (SASL_CONST char **)&p->buf_in.buf_base, + (unsigned *)&p->buf_in.buf_end ); + if ( ret != SASL_OK ) { + ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, + "sb_sasl_read: failed to decode packet: %s\n", + sasl_errstring( ret, NULL, NULL ) ); + sb_sasl_drop_packet( &p->sec_buf_in, + sbiod->sbiod_sb->sb_debug ); + errno = EIO; + return -1; + } + + /* Drop the packet from the input buffer */ + sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug ); + + p->buf_in.buf_size = p->buf_in.buf_end; + + bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len ); + + return bufptr; +} + +static ber_slen_t +sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct sb_sasl_data *p; + int ret; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + /* Are there anything left in the buffer? */ + if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { + ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); + if ( ret <= 0 ) + return ret; + } + + /* now encode the next packet. */ +#if SASL_VERSION_MAJOR >= 2 + ber_pvt_sb_buf_init( &p->buf_out ); +#else + ber_pvt_sb_buf_destroy( &p->buf_out ); +#endif + ret = sasl_encode( p->sasl_context, buf, len, + (SASL_CONST char **)&p->buf_out.buf_base, + (unsigned *)&p->buf_out.buf_size ); + if ( ret != SASL_OK ) { + ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, + "sb_sasl_write: failed to encode packet: %s\n", + sasl_errstring( ret, NULL, NULL ) ); + return -1; + } + p->buf_out.buf_end = p->buf_out.buf_size; + + ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); + if ( ret <= 0 ) + return ret; + return len; +} + +static int +sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + struct sb_sasl_data *p; + + p = (struct sb_sasl_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_DATA_READY ) { + if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) + return 1; + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +Sockbuf_IO ldap_pvt_sockbuf_io_sasl = { + sb_sasl_setup, /* sbi_setup */ + sb_sasl_remove, /* sbi_remove */ + sb_sasl_ctrl, /* sbi_ctrl */ + sb_sasl_read, /* sbi_read */ + sb_sasl_write, /* sbi_write */ + NULL /* sbi_close */ +}; + +int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) +{ +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_ENTRY, "ldap_pvt_sasl_install\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n", + 0, 0, 0 ); +#endif + + /* don't install the stuff unless security has been negotiated */ + + if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, + &ldap_pvt_sockbuf_io_sasl ) ) + { +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" ); +#endif + ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl, + LBER_SBIOD_LEVEL_APPLICATION, ctx_arg ); + } + + return LDAP_SUCCESS; +} + +static int +sasl_err2ldap( int saslerr ) +{ + int rc; + + switch (saslerr) { + case SASL_CONTINUE: + rc = LDAP_MORE_RESULTS_TO_RETURN; + break; + case SASL_INTERACT: + rc = LDAP_LOCAL_ERROR; + break; + case SASL_OK: + rc = LDAP_SUCCESS; + break; + case SASL_FAIL: + rc = LDAP_LOCAL_ERROR; + break; + case SASL_NOMEM: + rc = LDAP_NO_MEMORY; + break; + case SASL_NOMECH: + rc = LDAP_AUTH_UNKNOWN; + break; + case SASL_BADAUTH: + rc = LDAP_AUTH_UNKNOWN; + break; + case SASL_NOAUTHZ: + rc = LDAP_PARAM_ERROR; + break; + case SASL_TOOWEAK: + case SASL_ENCRYPT: + rc = LDAP_AUTH_UNKNOWN; + break; + default: + rc = LDAP_LOCAL_ERROR; + break; + } + + assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) ); + return rc; +} + +int +ldap_int_sasl_open( + LDAP *ld, + LDAPConn *lc, + const char * host, + ber_len_t ssf ) +{ + int rc; + sasl_conn_t *ctx; + + sasl_callback_t *session_callbacks = + LDAP_CALLOC( 2, sizeof( sasl_callback_t ) ); + + if( session_callbacks == NULL ) return LDAP_NO_MEMORY; + + session_callbacks[0].id = SASL_CB_USER; + session_callbacks[0].proc = NULL; + session_callbacks[0].context = ld; + + session_callbacks[1].id = SASL_CB_LIST_END; + session_callbacks[1].proc = NULL; + session_callbacks[1].context = NULL; + + assert( lc->lconn_sasl_ctx == NULL ); + + if ( host == NULL ) { + ld->ld_errno = LDAP_LOCAL_ERROR; + return ld->ld_errno; + } + +#if SASL_VERSION_MAJOR >= 2 + rc = sasl_client_new( "ldap", host, NULL, NULL, + session_callbacks, 0, &ctx ); +#else + rc = sasl_client_new( "ldap", host, session_callbacks, + SASL_SECURITY_LAYER, &ctx ); +#endif + LDAP_FREE( session_callbacks ); + + if ( rc != SASL_OK ) { + ld->ld_errno = sasl_err2ldap( rc ); + return ld->ld_errno; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_DETAIL1, + "ldap_int_sasl_open: host=%s\n", host )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n", + host, 0, 0 ); +#endif + + lc->lconn_sasl_ctx = ctx; + + if( ssf ) { +#if SASL_VERSION_MAJOR >= 2 + (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL, + (void *) &ssf ); +#else + sasl_external_properties_t extprops; + memset(&extprops, 0L, sizeof(extprops)); + extprops.ssf = ssf; + + (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL, + (void *) &extprops ); +#endif +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_DETAIL1, + "ldap_int_sasl_open: ssf=%ld\n", (long) ssf )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: ssf=%ld\n", + (long) ssf, 0, 0 ); +#endif + } + + return LDAP_SUCCESS; +} + +int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) +{ + sasl_conn_t *ctx = lc->lconn_sasl_ctx; + + if( ctx != NULL ) { + sasl_dispose( &ctx ); + lc->lconn_sasl_ctx = NULL; + } + + return LDAP_SUCCESS; +} + +int +ldap_int_sasl_bind( + LDAP *ld, + const char *dn, + const char *mechs, + LDAPControl **sctrls, + LDAPControl **cctrls, + unsigned flags, + LDAP_SASL_INTERACT_PROC *interact, + void * defaults ) +{ + char *data; + const char *mech = NULL; + const char *pmech = NULL; + int saslrc, rc; + sasl_ssf_t *ssf = NULL; + sasl_conn_t *ctx; + sasl_interact_t *prompts = NULL; + unsigned credlen; + struct berval ccred; + ber_socket_t sd; + +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_ARGS, + "ldap_int_sasl_bind: %s\n", mechs ? mechs : "<null>" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n", + mechs ? mechs : "<null>", 0, 0 ); +#endif + + /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ + if (ld->ld_version < LDAP_VERSION3) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); + + if ( sd == AC_SOCKET_INVALID ) { + /* not connected yet */ + int rc; + + rc = ldap_open_defconn( ld ); + if( rc < 0 ) return ld->ld_errno; + + ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); + + if( sd == AC_SOCKET_INVALID ) { + ld->ld_errno = LDAP_LOCAL_ERROR; + return ld->ld_errno; + } + } + + ctx = ld->ld_defconn->lconn_sasl_ctx; + + if( ctx == NULL ) { + ld->ld_errno = LDAP_LOCAL_ERROR; + return ld->ld_errno; + } + + /* (re)set security properties */ + sasl_setprop( ctx, SASL_SEC_PROPS, + &ld->ld_options.ldo_sasl_secprops ); + + ccred.bv_val = NULL; + ccred.bv_len = 0; + + do { + saslrc = sasl_client_start( ctx, + mechs, +#if SASL_VERSION_MAJOR < 2 + NULL, +#endif + &prompts, + (SASL_CONST char **)&ccred.bv_val, + &credlen, + &mech ); + + if( pmech == NULL && mech != NULL ) { + pmech = mech; + + if( flags != LDAP_SASL_QUIET ) { + fprintf(stderr, + "SASL/%s authentication started\n", + pmech ); + } + } + +#if SASL_VERSION_MAJOR >= 2 + /* XXX the application should free interact results. */ + if ( prompts != NULL && prompts->result != NULL ) { + LDAP_FREE( (void *)prompts->result ); + prompts->result = NULL; + } +#endif + + if( saslrc == SASL_INTERACT ) { + int res; + if( !interact ) break; + res = (interact)( ld, flags, defaults, prompts ); + if( res != LDAP_SUCCESS ) { + break; + } + } + } while ( saslrc == SASL_INTERACT ); + + ccred.bv_len = credlen; + + if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { + ld->ld_errno = sasl_err2ldap( saslrc ); + return ld->ld_errno; + } + + do { + struct berval *scred; + unsigned credlen; + + scred = NULL; + + rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred ); + + if ( ccred.bv_val != NULL ) { +#if SASL_VERSION_MAJOR < 2 + LDAP_FREE( ccred.bv_val ); +#endif + ccred.bv_val = NULL; + } + + if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { + if( scred && scred->bv_len ) { + /* and server provided us with data? */ +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_DETAIL1, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len ); +#endif + ber_bvfree( scred ); + } + return ld->ld_errno; + } + + if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) { + /* we're done, no need to step */ + if( scred && scred->bv_len ) { + /* but server provided us with data! */ +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_DETAIL1, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len ); +#endif + ber_bvfree( scred ); + return ld->ld_errno = LDAP_LOCAL_ERROR; + } + break; + } + + do { + saslrc = sasl_client_step( ctx, + (scred == NULL) ? NULL : scred->bv_val, + (scred == NULL) ? 0 : scred->bv_len, + &prompts, + (SASL_CONST char **)&ccred.bv_val, + &credlen ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "cyrus", LDAP_LEVEL_DETAIL1, + "ldap_int_sasl_bind: sasl_client_step: %d\n", saslrc )); +#else + Debug( LDAP_DEBUG_TRACE, "sasl_client_step: %d\n", + saslrc, 0, 0 ); +#endif + +#if SASL_VERSION_MAJOR >= 2 + /* XXX the application should free interact results. */ + if ( prompts != NULL && prompts->result != NULL ) { + LDAP_FREE( (void *)prompts->result ); + prompts->result = NULL; + } +#endif + + if( saslrc == SASL_INTERACT ) { + int res; + if( !interact ) break; + res = (interact)( ld, flags, defaults, prompts ); + if( res != LDAP_SUCCESS ) { + break; + } + } + } while ( saslrc == SASL_INTERACT ); + + ccred.bv_len = credlen; + ber_bvfree( scred ); + + if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { + ld->ld_errno = sasl_err2ldap( saslrc ); + return ld->ld_errno; + } + } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); + + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( saslrc != SASL_OK ) { + return ld->ld_errno = sasl_err2ldap( saslrc ); + } + + if( flags != LDAP_SASL_QUIET ) { + saslrc = sasl_getprop( ctx, SASL_USERNAME, (SASL_CONST void **) &data ); + if( saslrc == SASL_OK && data && *data ) { + fprintf( stderr, "SASL username: %s\n", data ); + } + +#if SASL_VERSION_MAJOR >= 2 + saslrc = sasl_getprop( ctx, SASL_DEFUSERREALM, (SASL_CONST void **) &data ); +#else + saslrc = sasl_getprop( ctx, SASL_REALM, (SASL_CONST void **) &data ); +#endif + if( saslrc == SASL_OK && data && *data ) { + fprintf( stderr, "SASL realm: %s\n", data ); + } + } + + saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **) &ssf ); + if( saslrc == SASL_OK ) { + if( flags != LDAP_SASL_QUIET ) { + fprintf( stderr, "SASL SSF: %lu\n", + (unsigned long) *ssf ); + } + + if( ssf && *ssf ) { + if( flags != LDAP_SASL_QUIET ) { + fprintf( stderr, "SASL installing layers\n" ); + } + ldap_pvt_sasl_install( ld->ld_conns->lconn_sb, ctx ); + } + } + + return rc; +} + +int +ldap_int_sasl_external( + LDAP *ld, + LDAPConn *conn, + const char * authid, + ber_len_t ssf ) +{ + int sc; + sasl_conn_t *ctx; +#if SASL_VERSION_MAJOR < 2 + sasl_external_properties_t extprops; +#endif + + ctx = conn->lconn_sasl_ctx; + + if ( ctx == NULL ) { + return LDAP_LOCAL_ERROR; + } + +#if SASL_VERSION_MAJOR >= 2 + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf ); +#else + memset( &extprops, '\0', sizeof(extprops) ); + extprops.ssf = ssf; + extprops.auth_id = (char *) authid; + + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, + (void *) &extprops ); +#endif + + if ( sc != SASL_OK ) { + return LDAP_LOCAL_ERROR; + } + + return LDAP_SUCCESS; +} + + +int ldap_pvt_sasl_secprops( + const char *in, + sasl_security_properties_t *secprops ) +{ + int i; + char **props = ldap_str2charray( in, "," ); + unsigned sflags = 0; + int got_sflags = 0; + sasl_ssf_t max_ssf = 0; + int got_max_ssf = 0; + sasl_ssf_t min_ssf = 0; + int got_min_ssf = 0; + unsigned maxbufsize = 0; + int got_maxbufsize = 0; + + if( props == NULL || secprops == NULL ) { + return LDAP_PARAM_ERROR; + } + + for( i=0; props[i]; i++ ) { + if( !strcasecmp(props[i], "none") ) { + got_sflags++; + + } else if( !strcasecmp(props[i], "noplain") ) { + got_sflags++; + sflags |= SASL_SEC_NOPLAINTEXT; + + } else if( !strcasecmp(props[i], "noactive") ) { + got_sflags++; + sflags |= SASL_SEC_NOACTIVE; + + } else if( !strcasecmp(props[i], "nodict") ) { + got_sflags++; + sflags |= SASL_SEC_NODICTIONARY; + + } else if( !strcasecmp(props[i], "forwardsec") ) { + got_sflags++; + sflags |= SASL_SEC_FORWARD_SECRECY; + + } else if( !strcasecmp(props[i], "noanonymous")) { + got_sflags++; + sflags |= SASL_SEC_NOANONYMOUS; + + } else if( !strcasecmp(props[i], "passcred") ) { + got_sflags++; + sflags |= SASL_SEC_PASS_CREDENTIALS; + + } else if( !strncasecmp(props[i], + "minssf=", sizeof("minssf")) ) + { + if( isdigit( props[i][sizeof("minssf")] ) ) { + got_min_ssf++; + min_ssf = atoi( &props[i][sizeof("minssf")] ); + } else { + return LDAP_NOT_SUPPORTED; + } + + } else if( !strncasecmp(props[i], + "maxssf=", sizeof("maxssf")) ) + { + if( isdigit( props[i][sizeof("maxssf")] ) ) { + got_max_ssf++; + max_ssf = atoi( &props[i][sizeof("maxssf")] ); + } else { + return LDAP_NOT_SUPPORTED; + } + + } else if( !strncasecmp(props[i], + "maxbufsize=", sizeof("maxbufsize")) ) + { + if( isdigit( props[i][sizeof("maxbufsize")] ) ) { + got_maxbufsize++; + maxbufsize = atoi( &props[i][sizeof("maxbufsize")] ); + } else { + return LDAP_NOT_SUPPORTED; + } + + if( maxbufsize && (( maxbufsize < SASL_MIN_BUFF_SIZE ) + || (maxbufsize > SASL_MAX_BUFF_SIZE ))) + { + /* bad maxbufsize */ + return LDAP_PARAM_ERROR; + } + + } else { + return LDAP_NOT_SUPPORTED; + } + } + + if(got_sflags) { + secprops->security_flags = sflags; + } + if(got_min_ssf) { + secprops->min_ssf = min_ssf; + } + if(got_max_ssf) { + secprops->max_ssf = max_ssf; + } + if(got_maxbufsize) { + secprops->maxbufsize = maxbufsize; + } + + ldap_charray_free( props ); + return LDAP_SUCCESS; +} + +int +ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg ) +{ + int rc; + + switch( option ) { + case LDAP_OPT_X_SASL_SECPROPS: + rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops ); + if( rc == LDAP_SUCCESS ) return 0; + } + + return -1; +} + +int +ldap_int_sasl_get_option( LDAP *ld, int option, void *arg ) +{ + if ( ld == NULL ) + return -1; + + switch ( option ) { + case LDAP_OPT_X_SASL_MECH: { + *(char **)arg = ld->ld_options.ldo_def_sasl_mech + ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL; + } break; + case LDAP_OPT_X_SASL_REALM: { + *(char **)arg = ld->ld_options.ldo_def_sasl_realm + ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL; + } break; + case LDAP_OPT_X_SASL_AUTHCID: { + *(char **)arg = ld->ld_options.ldo_def_sasl_authcid + ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL; + } break; + case LDAP_OPT_X_SASL_AUTHZID: { + *(char **)arg = ld->ld_options.ldo_def_sasl_authzid + ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL; + } break; + + case LDAP_OPT_X_SASL_SSF: { + int sc; + sasl_ssf_t *ssf; + sasl_conn_t *ctx; + + if( ld->ld_defconn == NULL ) { + return -1; + } + + ctx = ld->ld_defconn->lconn_sasl_ctx; + + if ( ctx == NULL ) { + return -1; + } + + sc = sasl_getprop( ctx, SASL_SSF, + (SASL_CONST void **) &ssf ); + + if ( sc != SASL_OK ) { + return -1; + } + + *(ber_len_t *)arg = *ssf; + } break; + + case LDAP_OPT_X_SASL_SSF_EXTERNAL: + /* this option is write only */ + return -1; + + case LDAP_OPT_X_SASL_SSF_MIN: + *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf; + break; + case LDAP_OPT_X_SASL_SSF_MAX: + *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf; + break; + case LDAP_OPT_X_SASL_MAXBUFSIZE: + *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize; + break; + + case LDAP_OPT_X_SASL_SECPROPS: + /* this option is write only */ + return -1; + + default: + return -1; + } + return 0; +} + +int +ldap_int_sasl_set_option( LDAP *ld, int option, void *arg ) +{ + if ( ld == NULL ) + return -1; + + switch ( option ) { + case LDAP_OPT_X_SASL_SSF: + /* This option is read-only */ + return -1; + + case LDAP_OPT_X_SASL_SSF_EXTERNAL: { + int sc; +#if SASL_VERSION_MAJOR < 2 + sasl_external_properties_t extprops; +#endif + sasl_conn_t *ctx; + + if( ld->ld_defconn == NULL ) { + return -1; + } + + ctx = ld->ld_defconn->lconn_sasl_ctx; + + if ( ctx == NULL ) { + return -1; + } + +#if SASL_VERSION_MAJOR >= 2 + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, arg); +#else + memset(&extprops, 0L, sizeof(extprops)); + + extprops.ssf = * (ber_len_t *) arg; + + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, + (void *) &extprops ); +#endif + + if ( sc != SASL_OK ) { + return -1; + } + } break; + + case LDAP_OPT_X_SASL_SSF_MIN: + ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg; + break; + case LDAP_OPT_X_SASL_SSF_MAX: + ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg; + break; + case LDAP_OPT_X_SASL_MAXBUFSIZE: + ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg; + break; + + case LDAP_OPT_X_SASL_SECPROPS: { + int sc; + sc = ldap_pvt_sasl_secprops( (char *) arg, + &ld->ld_options.ldo_sasl_secprops ); + + return sc == LDAP_SUCCESS ? 0 : -1; + } + + default: + return -1; + } + return 0; +} + +#ifdef LDAP_R_COMPILE +void *ldap_pvt_sasl_mutex_new(void) +{ + ldap_pvt_thread_mutex_t *mutex; + + mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC( + sizeof(ldap_pvt_thread_mutex_t) ); + + if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) { + return mutex; + } + return NULL; +} + +int ldap_pvt_sasl_mutex_lock(void *mutex) +{ + return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex ) + ? SASL_FAIL : SASL_OK; +} + +int ldap_pvt_sasl_mutex_unlock(void *mutex) +{ + return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex ) + ? SASL_FAIL : SASL_OK; +} + +void ldap_pvt_sasl_mutex_dispose(void *mutex) +{ + (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex ); + LDAP_FREE( mutex ); +} +#endif + +#else +int ldap_int_sasl_init( void ) +{ return LDAP_SUCCESS; } + +int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) +{ return LDAP_SUCCESS; } + +int +ldap_int_sasl_bind( + LDAP *ld, + const char *dn, + const char *mechs, + LDAPControl **sctrls, + LDAPControl **cctrls, + unsigned flags, + LDAP_SASL_INTERACT_PROC *interact, + void * defaults ) +{ return LDAP_NOT_SUPPORTED; } + +int +ldap_int_sasl_external( + LDAP *ld, + LDAPConn *conn, + const char * authid, + ber_len_t ssf ) +{ return LDAP_SUCCESS; } + +#endif /* HAVE_CYRUS_SASL */ diff --git a/libraries/libldap/delete.c b/libraries/libldap/delete.c index 47e240ea6a9bae564f909200967bd18d732217fc..c91e02e565c61c186ec99670ac8abea154c39a80 100644 --- a/libraries/libldap/delete.c +++ b/libraries/libldap/delete.c @@ -1,79 +1,117 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * delete.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif - -#include <stdio.h> -#include <string.h> +/* + * A delete request looks like this: + * DelRequet ::= DistinguishedName, + */ -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ +#include "portable.h" -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#endif /* DOS */ +#include <stdio.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" /* - * ldap_delete - initiate an ldap (and X.500) delete operation. Parameters: + * ldap_delete_ext - initiate an ldap extended delete operation. Parameters: * * ld LDAP descriptor * dn DN of the object to delete + * sctrls Server Controls + * cctrls Client Controls + * msgidp Message Id Pointer * * Example: - * msgid = ldap_delete( ld, dn ); + * rc = ldap_delete( ld, dn, sctrls, cctrls, msgidp ); */ int -ldap_delete( LDAP *ld, char *dn ) +ldap_delete_ext( + LDAP *ld, + LDAP_CONST char* dn, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) { + int rc; BerElement *ber; - /* - * A delete request looks like this: - * DelRequet ::= DistinguishedName, - */ +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ENTRY, "ldap_delete_ext\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_delete_ext\n", 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 ); + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( dn != NULL ); + assert( msgidp != NULL ); + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return( ld->ld_errno ); + } + + if ( ber_printf( ber, "{its", /* '}' */ + ++ld->ld_msgid, LDAP_REQ_DELETE, dn ) == -1 ) + { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); } - if ( ber_printf( ber, "{its}", ++ld->ld_msgid, LDAP_REQ_DELETE, dn ) - == -1 ) { + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); } /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_DELETE, dn, ber )); -} + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_DELETE, dn, ber ); + if(*msgidp < 0) + return ld->ld_errno; + + return LDAP_SUCCESS; +} int -ldap_delete_s( LDAP *ld, char *dn ) +ldap_delete_ext_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAPControl **sctrls, + LDAPControl **cctrls ) { - int msgid; + int msgid; + int rc; LDAPMessage *res; - if ( (msgid = ldap_delete( ld, dn )) == -1 ) + rc = ldap_delete_ext( ld, dn, sctrls, cctrls, &msgid ); + + if( rc != LDAP_SUCCESS ) return( ld->ld_errno ); if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) @@ -81,3 +119,38 @@ ldap_delete_s( LDAP *ld, char *dn ) return( ldap_result2error( ld, res, 1 ) ); } +/* + * ldap_delete - initiate an ldap (and X.500) delete operation. Parameters: + * + * ld LDAP descriptor + * dn DN of the object to delete + * + * Example: + * msgid = ldap_delete( ld, dn ); + */ +int +ldap_delete( LDAP *ld, LDAP_CONST char *dn ) +{ + int msgid; + + /* + * A delete request looks like this: + * DelRequet ::= DistinguishedName, + */ + +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ENTRY, "ldap_delete\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 ); +#endif + + return ldap_delete_ext( ld, dn, NULL, NULL, &msgid ) == LDAP_SUCCESS + ? msgid : -1 ; +} + + +int +ldap_delete_s( LDAP *ld, LDAP_CONST char *dn ) +{ + return ldap_delete_ext_s( ld, dn, NULL, NULL ); +} diff --git a/libraries/libldap/dntest.c b/libraries/libldap/dntest.c new file mode 100644 index 0000000000000000000000000000000000000000..72d3c52febb82f4e73f4c1564564ccfcef8a84eb --- /dev/null +++ b/libraries/libldap/dntest.c @@ -0,0 +1,277 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * OpenLDAP DN API Test + * Written by: Pierangelo Masarati <ando@OpenLDAP.org> + * + * This program is designed to test the ldap_str2dn/ldap_dn2str + * functions + */ +#include "portable.h" + +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include <stdio.h> + +#include <ldap.h> + +#include "ldap-int.h" + +#include "ldif.h" +#include "lutil.h" +#include "lutil_ldap.h" +#include "ldap_defaults.h" + +int +main( int argc, char *argv[] ) +{ + int rc, i, debug = 0, f2 = 0; + unsigned flags[ 2 ] = { 0U, 0 }; + char *strin, *str = NULL, buf[ 1024 ]; + LDAPDN *dn, *dn2 = NULL; + + while ( 1 ) { + int opt = getopt( argc, argv, "d:" ); + + if ( opt == EOF ) { + break; + } + + switch ( opt ) { + case 'd': + debug = atoi( optarg ); + break; + } + } + + optind--; + argc -= optind; + argv += optind; + + if ( argc < 2 ) { + fprintf( stderr, "usage: dntest <dn> [flags-in[,...]] [flags-out[,...]]\n\n" ); + fprintf( stderr, "\tflags-in: V3,V2,DCE,<flags>\n" ); + fprintf( stderr, "\tflags-out: V3,V2,UFN,DCE,AD,<flags>\n\n" ); + fprintf( stderr, "\t<flags>: PRETTY,PEDANTIC,NOSPACES,NOONESPACE\n\n" ); + return( 0 ); + } + + 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 ); + } + + if ( strcmp( argv[ 1 ], "-" ) == 0 ) { + size_t len; + + fgets( buf, sizeof( buf ), stdin ); + len = strlen( buf ); + if ( len > 0 && buf[ --len ] == '\n' ) { + buf[ len ] = '\0'; + } + strin = buf; + } else { + strin = argv[ 1 ]; + } + + if ( argc >= 3 ) { + for ( i = 0; i < argc - 2; i++ ) { + char *s, *e; + for ( s = argv[ 2 + i ]; s; s = e ) { + e = strchr( s, ',' ); + if ( e != NULL ) { + e[ 0 ] = '\0'; + e++; + } + + if ( !strcasecmp( s, "V3" ) ) { + flags[ i ] |= LDAP_DN_FORMAT_LDAPV3; + } else if ( !strcasecmp( s, "V2" ) ) { + flags[ i ] |= LDAP_DN_FORMAT_LDAPV2; + } else if ( !strcasecmp( s, "DCE" ) ) { + flags[ i ] |= LDAP_DN_FORMAT_DCE; + } else if ( !strcasecmp( s, "UFN" ) ) { + flags[ i ] |= LDAP_DN_FORMAT_UFN; + } else if ( !strcasecmp( s, "AD" ) ) { + flags[ i ] |= LDAP_DN_FORMAT_AD_CANONICAL; + } else if ( !strcasecmp( s, "PRETTY" ) ) { + flags[ i ] |= LDAP_DN_PRETTY; + } else if ( !strcasecmp( s, "PEDANTIC" ) ) { + flags[ i ] |= LDAP_DN_PEDANTIC; + } else if ( !strcasecmp( s, "NOSPACES" ) ) { + flags[ i ] |= LDAP_DN_P_NOLEADTRAILSPACES; + } else if ( !strcasecmp( s, "NOONESPACE" ) ) { + flags[ i ] |= LDAP_DN_P_NOSPACEAFTERRDN; + } + } + } + } + + if ( flags[ 1 ] == 0 ) + flags[ 1 ] = LDAP_DN_FORMAT_LDAPV3; + + f2 = 1; + + rc = ldap_str2dn( strin, &dn, flags[ 0 ] ); + + if ( rc == LDAP_SUCCESS ) { + int i; + if ( dn ) { + for ( i = 0; dn[ 0 ][ i ]; i++ ) { + LDAPRDN *rdn = dn[ 0 ][ i ]; + char *rstr = NULL; + + if ( ldap_rdn2str( rdn, &rstr, flags[ f2 ] ) ) { + fprintf( stdout, "\tldap_rdn2str() failed\n" ); + continue; + } + + fprintf( stdout, "\tldap_rdn2str() = \"%s\"\n", rstr ); + ldap_memfree( rstr ); + } + } else { + fprintf( stdout, "\tempty DN\n" ); + } + } + + str = NULL; + if ( rc == LDAP_SUCCESS && + ldap_dn2str( dn, &str, flags[ f2 ] ) == LDAP_SUCCESS ) + { + char **values, *tmp, *tmp2, *str2 = NULL; + int n; + + fprintf( stdout, "\nldap_dn2str(ldap_str2dn(\"%s\"))\n" + "\t= \"%s\"\n", strin, str ); + + switch ( flags[ f2 ] & LDAP_DN_FORMAT_MASK ) { + case LDAP_DN_FORMAT_UFN: + case LDAP_DN_FORMAT_AD_CANONICAL: + return( 0 ); + + case LDAP_DN_FORMAT_LDAPV3: + case LDAP_DN_FORMAT_LDAPV2: + tmp = ldap_dn2ufn( strin ); + fprintf( stdout, "\nldap_dn2ufn(\"%s\")\n" + "\t= \"%s\"\n", strin, tmp ); + ldap_memfree( tmp ); + + tmp = ldap_dn2dcedn( strin ); + fprintf( stdout, "\nldap_dn2dcedn(\"%s\")\n" + "\t= \"%s\"\n", strin, tmp ); + tmp2 = ldap_dcedn2dn( tmp ); + fprintf( stdout, "\nldap_dcedn2dn(\"%s\")\n" + "\t= \"%s\"\n", tmp, tmp2 ); + ldap_memfree( tmp ); + ldap_memfree( tmp2 ); + + tmp = ldap_dn2ad_canonical( strin ); + fprintf( stdout, "\nldap_dn2ad_canonical(\"%s\")\n" + "\t= \"%s\"\n", strin, tmp ); + ldap_memfree( tmp ); + + fprintf( stdout, "\nldap_explode_dn(\"%s\"):\n", str ); + values = ldap_explode_dn( str, 0 ); + for ( n = 0; values && values[ n ]; n++ ) { + char **vv; + int nn; + + fprintf( stdout, "\t\"%s\"\n", values[ n ] ); + + fprintf( stdout, "\tldap_explode_rdn(\"%s\")\n", + values[ n ] ); + vv = ldap_explode_rdn( values[ n ], 0 ); + for ( nn = 0; vv && vv[ nn ]; nn++ ) { + fprintf( stdout, "\t\t'%s'\n", + vv[ nn ] ); + } + LDAP_VFREE( vv ); + + fprintf( stdout, "\tldap_explode_rdn(\"%s\")" + " (no types)\n", values[ n ] ); + vv = ldap_explode_rdn( values[ n ], 1 ); + for ( nn = 0; vv && vv[ nn ]; nn++ ) { + fprintf( stdout, "\t\t\t\"%s\"\n", + vv[ nn ] ); + } + LDAP_VFREE( vv ); + + } + LDAP_VFREE( values ); + + fprintf( stdout, "\nldap_explode_dn(\"%s\")" + " (no types):\n", str ); + values = ldap_explode_dn( str, 1 ); + for ( n = 0; values && values[ n ]; n++ ) { + fprintf( stdout, "\t\"%s\"\n", values[ n ] ); + } + LDAP_VFREE( values ); + + break; + } + + dn2 = NULL; + rc = ldap_str2dn( str, &dn2, flags[ f2 ] ); + str2 = NULL; + if ( rc == LDAP_SUCCESS && + ldap_dn2str( dn2, &str2, flags[ f2 ] ) + == LDAP_SUCCESS ) { + int iRDN; + + fprintf( stdout, "\n\"%s\"\n\t == \"%s\" ? %s\n", + str, str2, + strcmp( str, str2 ) == 0 ? "yes" : "no" ); + + if( dn != NULL && dn2 == NULL ) { + fprintf( stdout, "dn mismatch\n" ); + } else if (( dn != NULL ) && (dn2 != NULL)) + for ( iRDN = 0; dn[ 0 ][ iRDN ] && dn2[ 0 ][ iRDN ]; iRDN++ ) + { + LDAPRDN *r = dn[ 0 ][ iRDN ]; + LDAPRDN *r2 = dn2[ 0 ][ iRDN ]; + int iAVA; + + for ( iAVA = 0; r[ 0 ][ iAVA ] && r2[ 0 ][ iAVA ]; iAVA++ ) { + LDAPAVA *a = r[ 0 ][ iAVA ]; + LDAPAVA *a2 = r2[ 0 ][ iAVA ]; + + if ( a->la_attr.bv_len != a2->la_attr.bv_len ) { + fprintf( stdout, "ava(%d), rdn(%d) attr len mismatch (%ld->%ld)\n", + iAVA + 1, iRDN + 1, + a->la_attr.bv_len, a2->la_attr.bv_len ); + } else if ( memcmp( a->la_attr.bv_val, a2->la_attr.bv_val, a->la_attr.bv_len ) ) { + fprintf( stdout, "ava(%d), rdn(%d) attr mismatch\n", + iAVA + 1, iRDN + 1 ); + } else if ( a->la_flags != a2->la_flags ) { + fprintf( stdout, "ava(%d), rdn(%d) flag mismatch (%x->%x)\n", + iAVA + 1, iRDN + 1, a->la_flags, a2->la_flags ); + } else if ( a->la_value.bv_len != a2->la_value.bv_len ) { + fprintf( stdout, "ava(%d), rdn(%d) value len mismatch (%ld->%ld)\n", + iAVA + 1, iRDN + 1, + a->la_value.bv_len, a2->la_value.bv_len ); + } else if ( memcmp( a->la_value.bv_val, a2->la_value.bv_val, a->la_value.bv_len ) ) { + fprintf( stdout, "ava(%d), rdn(%d) value mismatch\n", + iAVA + 1, iRDN + 1 ); + } + } + } + + ldap_dnfree( dn2 ); + ldap_memfree( str2 ); + } + ldap_memfree( str ); + } + ldap_dnfree( dn ); + + /* note: dn is not freed */ + + return( 0 ); +} + diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c index b59563ef885bc37f6871c9cca4e070bfb94e147f..8fc685b25f330ff17ba2a49e8c20590af7650334 100644 --- a/libraries/libldap/error.c +++ b/libraries/libldap/error.c @@ -1,171 +1,397 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" struct ldaperror { int e_code; - char *e_reason; + char *e_reason; }; -static struct ldaperror ldap_errlist[] = { - LDAP_SUCCESS, "Success", - LDAP_OPERATIONS_ERROR, "Operations error", - LDAP_PROTOCOL_ERROR, "Protocol error", - LDAP_TIMELIMIT_EXCEEDED, "Timelimit exceeded", - LDAP_SIZELIMIT_EXCEEDED, "Sizelimit exceeded", - LDAP_COMPARE_FALSE, "Compare false", - LDAP_COMPARE_TRUE, "Compare true", - LDAP_STRONG_AUTH_NOT_SUPPORTED, "Strong authentication not supported", - LDAP_STRONG_AUTH_REQUIRED, "Strong authentication required", - LDAP_PARTIAL_RESULTS, "Partial results and referral received", - LDAP_NO_SUCH_ATTRIBUTE, "No such attribute", - LDAP_UNDEFINED_TYPE, "Undefined attribute type", - LDAP_INAPPROPRIATE_MATCHING, "Inappropriate matching", - LDAP_CONSTRAINT_VIOLATION, "Constraint violation", - LDAP_TYPE_OR_VALUE_EXISTS, "Type or value exists", - LDAP_INVALID_SYNTAX, "Invalid syntax", - LDAP_NO_SUCH_OBJECT, "No such object", - LDAP_ALIAS_PROBLEM, "Alias problem", - LDAP_INVALID_DN_SYNTAX, "Invalid DN syntax", - LDAP_IS_LEAF, "Object is a leaf", - LDAP_ALIAS_DEREF_PROBLEM, "Alias dereferencing problem", - LDAP_INAPPROPRIATE_AUTH, "Inappropriate authentication", - LDAP_INVALID_CREDENTIALS, "Invalid credentials", - LDAP_INSUFFICIENT_ACCESS, "Insufficient access", - LDAP_BUSY, "DSA is busy", - LDAP_UNAVAILABLE, "DSA is unavailable", - LDAP_UNWILLING_TO_PERFORM, "DSA is unwilling to perform", - LDAP_LOOP_DETECT, "Loop detected", - LDAP_NAMING_VIOLATION, "Naming violation", - LDAP_OBJECT_CLASS_VIOLATION, "Object class violation", - LDAP_NOT_ALLOWED_ON_NONLEAF, "Operation not allowed on nonleaf", - LDAP_NOT_ALLOWED_ON_RDN, "Operation not allowed on RDN", - LDAP_ALREADY_EXISTS, "Already exists", - LDAP_NO_OBJECT_CLASS_MODS, "Cannot modify object class", - LDAP_RESULTS_TOO_LARGE, "Results too large", - LDAP_OTHER, "Unknown error", - LDAP_SERVER_DOWN, "Can't contact LDAP server", - LDAP_LOCAL_ERROR, "Local error", - LDAP_ENCODING_ERROR, "Encoding error", - LDAP_DECODING_ERROR, "Decoding error", - LDAP_TIMEOUT, "Timed out", - LDAP_AUTH_UNKNOWN, "Unknown authentication method", - LDAP_FILTER_ERROR, "Bad search filter", - LDAP_USER_CANCELLED, "User cancelled operation", - LDAP_PARAM_ERROR, "Bad parameter to an ldap routine", - LDAP_NO_MEMORY, "Out of memory", - -1, 0 +static struct ldaperror ldap_builtin_errlist[] = { + {LDAP_SUCCESS, "Success" }, + {LDAP_OPERATIONS_ERROR, "Operations error" }, + {LDAP_PROTOCOL_ERROR, "Protocol error" }, + {LDAP_TIMELIMIT_EXCEEDED, "Time limit exceeded" }, + {LDAP_SIZELIMIT_EXCEEDED, "Size limit exceeded" }, + {LDAP_COMPARE_FALSE, "Compare False" }, + {LDAP_COMPARE_TRUE, "Compare True" }, + {LDAP_STRONG_AUTH_NOT_SUPPORTED, "Authentication method not supported" }, + {LDAP_STRONG_AUTH_REQUIRED, "Strong authentication required" }, + {LDAP_PARTIAL_RESULTS, "Partial results and referral received" }, + + {LDAP_REFERRAL, "Referral"}, + {LDAP_ADMINLIMIT_EXCEEDED, "Administrative limit exceeded"}, + {LDAP_UNAVAILABLE_CRITICAL_EXTENSION, + "Criticial extension is unavailable"}, + {LDAP_CONFIDENTIALITY_REQUIRED, "Confidentiality required"}, + {LDAP_SASL_BIND_IN_PROGRESS, "SASL bind in progress"}, + + {LDAP_NO_SUCH_ATTRIBUTE, "No such attribute" }, + {LDAP_UNDEFINED_TYPE, "Undefined attribute type" }, + {LDAP_INAPPROPRIATE_MATCHING, "Inappropriate matching" }, + {LDAP_CONSTRAINT_VIOLATION, "Constraint violation" }, + {LDAP_TYPE_OR_VALUE_EXISTS, "Type or value exists" }, + {LDAP_INVALID_SYNTAX, "Invalid syntax" }, + + {LDAP_NO_SUCH_OBJECT, "No such object" }, + {LDAP_ALIAS_PROBLEM, "Alias problem" }, + {LDAP_INVALID_DN_SYNTAX, "Invalid DN syntax" }, + {LDAP_IS_LEAF, "Entry is a leaf" }, + {LDAP_ALIAS_DEREF_PROBLEM, "Alias dereferencing problem" }, + + {LDAP_INAPPROPRIATE_AUTH, "Inappropriate authentication" }, + {LDAP_INVALID_CREDENTIALS, "Invalid credentials" }, + {LDAP_INSUFFICIENT_ACCESS, "Insufficient access" }, + {LDAP_BUSY, "DSA is busy" }, + {LDAP_UNAVAILABLE, "DSA is unavailable" }, + {LDAP_UNWILLING_TO_PERFORM, "DSA is unwilling to perform" }, + {LDAP_LOOP_DETECT, "Loop detected" }, + + {LDAP_NAMING_VIOLATION, "Naming violation" }, + {LDAP_OBJECT_CLASS_VIOLATION, "Object class violation" }, + {LDAP_NOT_ALLOWED_ON_NONLEAF, "Operation not allowed on nonleaf" }, + {LDAP_NOT_ALLOWED_ON_RDN, "Operation not allowed on RDN" }, + {LDAP_ALREADY_EXISTS, "Already exists" }, + {LDAP_NO_OBJECT_CLASS_MODS, "Cannot modify object class" }, + {LDAP_RESULTS_TOO_LARGE, "Results too large" }, + {LDAP_AFFECTS_MULTIPLE_DSAS, "Operation affects multiple DSAs" }, + + {LDAP_OTHER, "Unknown error" }, + + /* API ResultCodes */ + {LDAP_SERVER_DOWN, "Can't contact LDAP server" }, + {LDAP_LOCAL_ERROR, "Local error" }, + {LDAP_ENCODING_ERROR, "Encoding error" }, + {LDAP_DECODING_ERROR, "Decoding error" }, + {LDAP_TIMEOUT, "Timed out" }, + {LDAP_AUTH_UNKNOWN, "Unknown authentication method" }, + {LDAP_FILTER_ERROR, "Bad search filter" }, + {LDAP_USER_CANCELLED, "User cancelled operation" }, + {LDAP_PARAM_ERROR, "Bad parameter to an ldap routine" }, + {LDAP_NO_MEMORY, "Out of memory" }, + + {LDAP_CONNECT_ERROR, "Connect error" }, + {LDAP_NOT_SUPPORTED, "Not Supported" }, + {LDAP_CONTROL_NOT_FOUND, "Control not found" }, + {LDAP_NO_RESULTS_RETURNED, "No results returned" }, + {LDAP_MORE_RESULTS_TO_RETURN, "More results to return" }, + {LDAP_CLIENT_LOOP, "Client Loop" }, + {LDAP_REFERRAL_LIMIT_EXCEEDED, "Referral Limit Exceeded" }, + + {-1, NULL} }; -char * -ldap_err2string( int err ) -{ +static struct ldaperror *ldap_errlist = ldap_builtin_errlist; + +void ldap_int_error_init( void ) { +#ifdef LDAP_NLS +#define LDAP_NLS_SDK_CAT "openldap_sdk" +#define LDAP_NLS_LIBLDAP_SET (0) + int i; + nl_catd catd = catopen( LDAP_NLS_SDK_CAT, NL_CAT_LOCALE ); - Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 ); + if( catd == -1 ) { + return; + } + + for ( i=0; ldap_errlist[i].e_reason != NULL; i++ ) { + char *msg = catgets( catd, + LDAP_NLS_LIBLDAP_SET, + ldap_errlist[i].e_code, NULL ); - for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) { - if ( err == ldap_errlist[i].e_code ) - return( ldap_errlist[i].e_reason ); + if( msg != NULL ) { + msg = LDAP_STRDUP( msg ); + + if( msg != NULL ) { + ldap_errlist[i].e_reason = msg; + } + } } - return( "Unknown error" ); + catclose( catd ); +#endif } -#ifndef NO_USERINTERFACE -void -ldap_perror( LDAP *ld, char *s ) +static const struct ldaperror * +ldap_int_error( int err ) { int i; + for ( i=0; ldap_errlist[i].e_reason != NULL; i++ ) { + if ( err == ldap_errlist[i].e_code ) { + return &ldap_errlist[i]; + } + } + + return NULL; +} + +char * +ldap_err2string( int err ) +{ + const struct ldaperror *e; + +#ifdef NEW_LOGGING + LDAP_LOG (( "error", LDAP_LEVEL_ENTRY, "ldap_err2string\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 ); +#endif + + e = ldap_int_error( err ); + + return e ? e->e_reason : "Unknown error"; +} + +/* deprecated */ +void +ldap_perror( LDAP *ld, LDAP_CONST char *str ) +{ + const struct ldaperror *e; +#ifdef NEW_LOGGING + LDAP_LOG (( "error", LDAP_LEVEL_ENTRY, "ldap_perror\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( str ); if ( ld == NULL ) { - perror( s ); + fprintf( stderr, "ldap_perror: invalid session handle\n" ); return; } - for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) { - if ( ld->ld_errno == ldap_errlist[i].e_code ) { - fprintf( stderr, "%s: %s\n", s, - ldap_errlist[i].e_reason ); - if ( ld->ld_matched != NULL && *ld->ld_matched != '\0' ) - fprintf( stderr, "%s: matched: %s\n", s, - ld->ld_matched ); - if ( ld->ld_error != NULL && *ld->ld_error != '\0' ) - fprintf( stderr, "%s: additional info: %s\n", - s, ld->ld_error ); - fflush( stderr ); - return; - } + e = ldap_int_error( ld->ld_errno ); + + fprintf( stderr, "%s: %s (%d)\n", + str ? str : "ldap_perror", + e ? e->e_reason : "unknown LDAP result code", + ld->ld_errno ); + + if ( ld->ld_matched != NULL && ld->ld_matched[0] != '\0' ) { + fprintf( stderr, "\tmatched DN: %s\n", ld->ld_matched ); + } + + if ( ld->ld_error != NULL && ld->ld_error[0] != '\0' ) { + fprintf( stderr, "\tadditional info: %s\n", ld->ld_error ); } - fprintf( stderr, "%s: Not an LDAP errno %d\n", s, ld->ld_errno ); fflush( stderr ); } -#else - -void -ldap_perror( LDAP *ld, char *s ) +/* deprecated */ +int +ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit ) { -} + int rc, err; -#endif /* NO_USERINTERFACE */ + rc = ldap_parse_result( ld, r, &err, + NULL, NULL, NULL, NULL, freeit ); + return err != LDAP_SUCCESS ? err : rc; +} +/* + * Parse LDAPResult Messages: + * + * LDAPResult ::= SEQUENCE { + * resultCode ENUMERATED, + * matchedDN LDAPDN, + * errorMessage LDAPString, + * referral [3] Referral OPTIONAL } + * + * including Bind results: + * + * BindResponse ::= [APPLICATION 1] SEQUENCE { + * COMPONENTS OF LDAPResult, + * serverSaslCreds [7] OCTET STRING OPTIONAL } + * + * and ExtendedOp results: + * + * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { + * COMPONENTS OF LDAPResult, + * responseName [10] LDAPOID OPTIONAL, + * response [11] OCTET STRING OPTIONAL } + * + */ int -ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit ) +ldap_parse_result( + LDAP *ld, + LDAPMessage *r, + int *errcodep, + char **matcheddnp, + char **errmsgp, + char ***referralsp, + LDAPControl ***serverctrls, + int freeit ) { LDAPMessage *lm; - BerElement ber; - long along; - int rc; + ber_int_t errcode = LDAP_SUCCESS; - Debug( LDAP_DEBUG_TRACE, "ldap_result2error\n", 0, 0, 0 ); + ber_tag_t tag; + BerElement *ber; - if ( r == NULLMSG ) - return( LDAP_PARAM_ERROR ); +#ifdef NEW_LOGGING + LDAP_LOG (( "error", LDAP_LEVEL_ENTRY, "ldap_parse_result\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 ); +#endif - for ( lm = r; lm->lm_chain != NULL; lm = lm->lm_chain ) - ; /* NULL */ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( r != NULL ); + + if ( ld == NULL || r == NULL ) { + return LDAP_PARAM_ERROR; + } + + if(errcodep != NULL) *errcodep = LDAP_SUCCESS; + if(matcheddnp != NULL) *matcheddnp = NULL; + if(errmsgp != NULL) *errmsgp = NULL; + if(referralsp != NULL) *referralsp = NULL; + if(serverctrls != NULL) *serverctrls = NULL; + + /* Find the next result... */ + for ( lm = r; lm != NULL; lm = lm->lm_chain ) { + /* skip over entries and references */ + if( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && + lm->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) + { + break; + } + } + + if( lm == NULL ) { + ld->ld_errno = LDAP_NO_RESULTS_RETURNED; + return ld->ld_errno; + } if ( ld->ld_error ) { - free( ld->ld_error ); + LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { - free( ld->ld_matched ); + LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } - ber = *(lm->lm_ber); - if ( ld->ld_version == LDAP_VERSION2 ) { - rc = ber_scanf( &ber, "{iaa}", &along, &ld->ld_matched, - &ld->ld_error ); + /* parse results */ + + ber = ber_dup( lm->lm_ber ); + + if ( ld->ld_version < LDAP_VERSION2 ) { + tag = ber_scanf( ber, "{ia}", + &ld->ld_errno, &ld->ld_error ); } else { - rc = ber_scanf( &ber, "{ia}", &along, &ld->ld_error ); + ber_len_t len; + tag = ber_scanf( ber, "{iaa" /*}*/, + &ld->ld_errno, &ld->ld_matched, &ld->ld_error ); + + if( tag != LBER_ERROR ) { + /* peek for referrals */ + if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) { + if( referralsp != NULL ) { + tag = ber_scanf( ber, "v", referralsp ); + + } else { + /* no place to put them so skip 'em */ + tag = ber_scanf( ber, "x" ); + } + } + } + + /* need to clean out misc items */ + if( tag != LBER_ERROR ) { + if( lm->lm_msgtype == LDAP_RES_BIND ) { + /* look for sasl result creditials */ + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) { + /* skip 'em */ + tag = ber_scanf( ber, "x" ); + } + + } else if( lm->lm_msgtype == LDAP_RES_EXTENDED ) { + /* look for exop result oid or value */ + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_OID ) { + /* skip 'em */ + tag = ber_scanf( ber, "x" ); + } + + if ( tag != LBER_ERROR && + ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) + { + /* skip 'em */ + tag = ber_scanf( ber, "x" ); + } + } + } + + if( tag != LBER_ERROR ) { + int rc = ldap_int_get_controls( ber, serverctrls ); + + if( rc != LDAP_SUCCESS ) { + tag = LBER_ERROR; + } + } + + if( tag != LBER_ERROR ) { + tag = ber_scanf( ber, /*{*/"}" ); + } } - if ( rc == LBER_ERROR ) { - ld->ld_errno = LDAP_DECODING_ERROR; - } else { - ld->ld_errno = (int) along; + + if ( tag == LBER_ERROR ) { + ld->ld_errno = errcode = LDAP_DECODING_ERROR; + } + + if( ber != NULL ) { + ber_free( ber, 0 ); } - if ( freeit ) + /* return */ + if( errcodep != NULL ) { + *errcodep = ld->ld_errno; + } + if ( errcode == LDAP_SUCCESS ) { + if( matcheddnp != NULL ) { + *matcheddnp = LDAP_STRDUP( ld->ld_matched ); + } + if( errmsgp != NULL ) { + *errmsgp = LDAP_STRDUP( ld->ld_error ); + } + + /* Find the next result... */ + for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) { + /* skip over entries and references */ + if( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && + lm->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) + { + /* more results to return */ + errcode = LDAP_MORE_RESULTS_TO_RETURN; + break; + } + } + } + + if ( freeit ) { ldap_msgfree( r ); + } - return( ld->ld_errno ); + return( errcode ); } diff --git a/libraries/libldap/extended.c b/libraries/libldap/extended.c new file mode 100644 index 0000000000000000000000000000000000000000..58bffe86205d41c491081e00c118669fbb5c5b73 --- /dev/null +++ b/libraries/libldap/extended.c @@ -0,0 +1,405 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * LDAPv3 Extended Operation Request + * ExtendedRequest ::= [APPLICATION 23] SEQUENCE { + * requestName [0] LDAPOID, + * requestValue [1] OCTET STRING OPTIONAL + * } + * + * LDAPv3 Extended Operation Response + * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { + * COMPONENTS OF LDAPResult, + * responseName [10] LDAPOID OPTIONAL, + * response [11] OCTET STRING OPTIONAL + * } + * + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +int +ldap_extended_operation( + LDAP *ld, + LDAP_CONST char *reqoid, + struct berval *reqdata, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) +{ + BerElement *ber; + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG (( "extended", LDAP_LEVEL_ENTRY, "ldap_extended_operation\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( reqoid != NULL || *reqoid == '\0' ); + assert( msgidp != NULL ); + + /* must be version 3 (or greater) */ + if ( ld->ld_version < LDAP_VERSION3 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return( ld->ld_errno ); + } + + if( reqoid == NULL || *reqoid == '\0' || msgidp == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return( ld->ld_errno ); + } + + /* create a message to send */ + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return( ld->ld_errno ); + } + + if ( reqdata != NULL ) { + rc = ber_printf( ber, "{it{tstON}", /* '}' */ + ++ld->ld_msgid, LDAP_REQ_EXTENDED, + LDAP_TAG_EXOP_REQ_OID, reqoid, + LDAP_TAG_EXOP_REQ_VALUE, reqdata ); + + } else { + rc = ber_printf( ber, "{it{tsN}", /* '}' */ + ++ld->ld_msgid, LDAP_REQ_EXTENDED, + LDAP_TAG_EXOP_REQ_OID, reqoid ); + } + + if( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); + } + + /* send the message */ + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber ); + + return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); +} + +int +ldap_extended_operation_s( + LDAP *ld, + LDAP_CONST char *reqoid, + struct berval *reqdata, + LDAPControl **sctrls, + LDAPControl **cctrls, + char **retoidp, + struct berval **retdatap ) +{ + int rc; + int msgid; + LDAPMessage *res; + +#ifdef NEW_LOGGING + LDAP_LOG (( "extended", LDAP_LEVEL_ENTRY, "ldap_extended_operation_s\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( reqoid != NULL || *reqoid == '\0' ); + assert( retoidp != NULL || retdatap != NULL ); + + if( retoidp == NULL || retdatap == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return( ld->ld_errno ); + } + + rc = ldap_extended_operation( ld, reqoid, reqdata, + sctrls, cctrls, &msgid ); + + if ( rc != LDAP_SUCCESS ) { + return( rc ); + } + + if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) { + return( ld->ld_errno ); + } + + *retoidp = NULL; + *retdatap = NULL; + + rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 ); + + if( rc != LDAP_SUCCESS ) { + ldap_msgfree( res ); + return rc; + } + + return( ldap_result2error( ld, res, 1 ) ); +} + +/* Parse an extended result */ +int +ldap_parse_extended_result ( + LDAP *ld, + LDAPMessage *res, + char **retoidp, + struct berval **retdatap, + int freeit ) +{ + BerElement *ber; + ber_tag_t rc; + ber_tag_t tag; + ber_len_t len; + struct berval *resdata; + ber_int_t errcode; + char *resoid; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( res != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "extended", LDAP_LEVEL_ENTRY, "ldap_parse_extended_result\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 ); +#endif + + if( ld->ld_version < LDAP_VERSION3 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + + if( res->lm_msgtype != LDAP_RES_EXTENDED ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + if( retoidp != NULL ) *retoidp = NULL; + if( retdatap != NULL ) *retdatap = NULL; + + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + ld->ld_error = NULL; + } + + if ( ld->ld_matched ) { + LDAP_FREE( ld->ld_matched ); + ld->ld_matched = NULL; + } + + ber = ber_dup( res->lm_ber ); + + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + rc = ber_scanf( ber, "{iaa" /*}*/, &errcode, + &ld->ld_matched, &ld->ld_error ); + + if( rc == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return ld->ld_errno; + } + + resoid = NULL; + resdata = NULL; + + tag = ber_peek_tag( ber, &len ); + + if( tag == LDAP_TAG_REFERRAL ) { + /* skip over referral */ + if( ber_scanf( ber, "x" ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return ld->ld_errno; + } + + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LDAP_TAG_EXOP_RES_OID ) { + /* we have a resoid */ + if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return ld->ld_errno; + } + + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LDAP_TAG_EXOP_RES_VALUE ) { + /* we have a resdata */ + if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + if( resoid != NULL ) LDAP_FREE( resoid ); + return ld->ld_errno; + } + } + + ber_free( ber, 0 ); + + if( retoidp != NULL ) { + *retoidp = resoid; + } else { + LDAP_FREE( resoid ); + } + + if( retdatap != NULL ) { + *retdatap = resdata; + } else { + ber_bvfree( resdata ); + } + + ld->ld_errno = errcode; + + if( freeit ) { + ldap_msgfree( res ); + } + + return LDAP_SUCCESS; +} + + +/* Parse an extended partial */ +int +ldap_parse_extended_partial ( + LDAP *ld, + LDAPMessage *res, + char **retoidp, + struct berval **retdatap, + LDAPControl ***serverctrls, + int freeit ) +{ + BerElement *ber; + ber_tag_t rc; + ber_tag_t tag; + ber_len_t len; + struct berval *resdata; + char *resoid; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( res != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "extended", LDAP_LEVEL_ENTRY, + "ldap_parse_extended_partial\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_partial\n", 0, 0, 0 ); +#endif + + if( ld->ld_version < LDAP_VERSION3 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + + if( res->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + if( retoidp != NULL ) *retoidp = NULL; + if( retdatap != NULL ) *retdatap = NULL; + + ber = ber_dup( res->lm_ber ); + + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + rc = ber_scanf( ber, "{" /*}*/ ); + + if( rc == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return ld->ld_errno; + } + + resoid = NULL; + resdata = NULL; + + tag = ber_peek_tag( ber, &len ); + + if( tag == LDAP_TAG_EXOP_RES_OID ) { + /* we have a resoid */ + if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return ld->ld_errno; + } + + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LDAP_TAG_EXOP_RES_VALUE ) { + /* we have a resdata */ + if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + if( resoid != NULL ) LDAP_FREE( resoid ); + return ld->ld_errno; + } + } + + if ( serverctrls == NULL ) { + rc = LDAP_SUCCESS; + goto free_and_return; + } + + if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) { + rc = LDAP_DECODING_ERROR; + goto free_and_return; + } + + rc = ldap_int_get_controls( ber, serverctrls ); + +free_and_return: + ber_free( ber, 0 ); + + if( retoidp != NULL ) { + *retoidp = resoid; + } else { + LDAP_FREE( resoid ); + } + + if( retdatap != NULL ) { + *retdatap = resdata; + } else { + ber_bvfree( resdata ); + } + + if( freeit ) { + ldap_msgfree( res ); + } + + return LDAP_SUCCESS; +} diff --git a/libraries/libldap/filter.c b/libraries/libldap/filter.c new file mode 100644 index 0000000000000000000000000000000000000000..fe0fab327b639245fa53e2ee977d9e2b181547d6 --- /dev/null +++ b/libraries/libldap/filter.c @@ -0,0 +1,801 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + * + * search.c + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +static char *put_complex_filter LDAP_P(( + BerElement *ber, + char *str, + ber_tag_t tag, + int not )); + +static int put_simple_filter LDAP_P(( + BerElement *ber, + char *str )); + +static int put_substring_filter LDAP_P(( + BerElement *ber, + char *type, + char *str )); + +static int put_filter_list LDAP_P(( + BerElement *ber, + char *str, + ber_tag_t tag )); + +static int ldap_is_oid ( const char *str ) +{ + int i; + + if( LDAP_ALPHA( str[0] )) { + for( i=1; str[i]; i++ ) { + if( !LDAP_LDH( str[i] )) { + return 0; + } + } + return 1; + + } else if LDAP_DIGIT( str[0] ) { + int dot=0; + for( i=1; str[i]; i++ ) { + if( LDAP_DIGIT( str[i] )) { + dot=0; + + } else if ( str[i] == '.' ) { + if( dot ) return 0; + if( ++dot > 1 ) return 0; + + } else { + return 0; + } + } + return !dot; + } + + return 0; +} + +static int ldap_is_desc ( const char *str ) +{ + int i; + + if( LDAP_ALPHA( str[0] )) { + for( i=1; str[i]; i++ ) { + if( str[i] == ';' ) { + str = &str[i+1]; + goto options; + } + + if( !LDAP_LDH( str[i] )) { + return 0; + } + } + return 1; + + } else if LDAP_DIGIT( str[0] ) { + int dot=0; + for( i=1; str[i]; i++ ) { + if( str[i] == ';' ) { + if( dot ) return 0; + str = &str[i+1]; + goto options; + } + + if( LDAP_DIGIT( str[i] )) { + dot=0; + + } else if ( str[i] == '.' ) { + if( dot ) return 0; + if( ++dot > 1 ) return 0; + + } else { + return 0; + } + } + return !dot; + } + + return 0; + +options: + if( !LDAP_LDH( str[0] )) { + return 0; + } + for( i=1; str[i]; i++ ) { + if( str[i] == ';' ) { + str = &str[i+1]; + goto options; + } + if( !LDAP_LDH( str[i] )) { + return 0; + } + } + return 1; +} + +static char * +find_right_paren( char *s ) +{ + int balance, escape; + + balance = 1; + escape = 0; + while ( *s && balance ) { + if ( !escape ) { + if ( *s == '(' ) { + balance++; + } else if ( *s == ')' ) { + balance--; + } + } + + escape = ( *s == '\\' && !escape ); + + if ( balance ) s++; + } + + return *s ? s : NULL; +} + +static int hex2value( int c ) +{ + if( c >= '0' && c <= '9' ) { + return c - '0'; + } + + if( c >= 'A' && c <= 'F' ) { + return c + (10 - (int) 'A'); + } + + if( c >= 'a' && c <= 'f' ) { + return c + (10 - (int) 'a'); + } + + return -1; +} + +char * +ldap_pvt_find_wildcard( const char *s ) +{ + for( ; *s; s++ ) { + switch( *s ) { + case '*': /* found wildcard */ + return (char *) s; + + case '(': + case ')': + return NULL; + + case '\\': + if( s[1] == '\0' ) return NULL; + + if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) { + s+=2; + + } else switch( s[1] ) { + default: + return NULL; + + /* allow RFC 1960 escapes */ + case '*': + case '(': + case ')': + case '\\': + s++; + } + } + } + + return (char *) s; +} + +/* unescape filter value */ +/* support both LDAP v2 and v3 escapes */ +/* output can include nul characters! */ +ber_slen_t +ldap_pvt_filter_value_unescape( char *fval ) +{ + ber_slen_t r, v; + int v1, v2; + + for( r=v=0; fval[v] != '\0'; v++ ) { + switch( fval[v] ) { + case '(': + case ')': + case '*': + return -1; + + case '\\': + /* escape */ + v++; + + if ( fval[v] == '\0' ) { + /* escape at end of string */ + return -1; + } + + if (( v1 = hex2value( fval[v] )) >= 0 ) { + /* LDAPv3 escape */ + if (( v2 = hex2value( fval[v+1] )) < 0 ) { + /* must be two digit code */ + return -1; + } + + fval[r++] = v1 * 16 + v2; + v++; + + } else { + /* LDAPv2 escape */ + switch( fval[v] ) { + case '(': + case ')': + case '*': + case '\\': + fval[r++] = fval[v]; + break; + default: + /* illegal escape */ + return -1; + } + } + break; + + default: + fval[r++] = fval[v]; + } + } + + fval[r] = '\0'; + return r; +} + +static char * +put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not ) +{ + char *next; + + /* + * We have (x(filter)...) with str sitting on + * the x. We have to find the paren matching + * the one before the x and put the intervening + * filters by calling put_filter_list(). + */ + + /* put explicit tag */ + if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) { + return NULL; + } + + str++; + if ( (next = find_right_paren( str )) == NULL ) { + return NULL; + } + + *next = '\0'; + if ( put_filter_list( ber, str, tag ) == -1 ) { + return NULL; + } + + /* close the '(' */ + *next++ = ')'; + + /* flush explicit tagged thang */ + if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { + return NULL; + } + + return next; +} + +int +ldap_pvt_put_filter( BerElement *ber, const char *str_in ) +{ + int rc; + char *freeme; + char *str; + char *next; + int parens, balance, escape; + + /* + * A Filter looks like this: + * Filter ::= CHOICE { + * and [0] SET OF Filter, + * or [1] SET OF Filter, + * not [2] Filter, + * equalityMatch [3] AttributeValueAssertion, + * substrings [4] SubstringFilter, + * greaterOrEqual [5] AttributeValueAssertion, + * lessOrEqual [6] AttributeValueAssertion, + * present [7] AttributeType, + * approxMatch [8] AttributeValueAssertion, + * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3 + * } + * + * SubstringFilter ::= SEQUENCE { + * type AttributeType, + * SEQUENCE OF CHOICE { + * initial [0] IA5String, + * any [1] IA5String, + * final [2] IA5String + * } + * } + * + * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3 + * matchingRule [1] MatchingRuleId OPTIONAL, + * type [2] AttributeDescription OPTIONAL, + * matchValue [3] AssertionValue, + * dnAttributes [4] BOOLEAN DEFAULT FALSE } + * + * Note: tags in a choice are always explicit + */ + +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, "ldap_pvt_put_filter: \"%s\"\n", + str_in )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 ); +#endif + + freeme = LDAP_STRDUP( str_in ); + if( freeme == NULL ) return LDAP_NO_MEMORY; + str = freeme; + + parens = 0; + while ( *str ) { + switch ( *str ) { + case '(': /*')'*/ + str++; + parens++; + + /* skip spaces */ + while( LDAP_SPACE( *str ) ) str++; + + switch ( *str ) { + case '&': +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: AND\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", + 0, 0, 0 ); +#endif + + str = put_complex_filter( ber, str, + LDAP_FILTER_AND, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } + + parens--; + break; + + case '|': +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: OR\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", + 0, 0, 0 ); +#endif + + str = put_complex_filter( ber, str, + LDAP_FILTER_OR, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } + + parens--; + break; + + case '!': +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: NOT\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", + 0, 0, 0 ); +#endif + + str = put_complex_filter( ber, str, + LDAP_FILTER_NOT, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } + + parens--; + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: simple\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", + 0, 0, 0 ); +#endif + + balance = 1; + escape = 0; + next = str; + + while ( *next && balance ) { + if ( escape == 0 ) { + if ( *next == '(' ) { + balance++; + } else if ( *next == ')' ) { + balance--; + } + } + + if ( *next == '\\' && ! escape ) { + escape = 1; + } else { + escape = 0; + } + + if ( balance ) next++; + } + + if ( balance != 0 ) { + rc = -1; + goto done; + } + + *next = '\0'; + + if ( put_simple_filter( ber, str ) == -1 ) { + rc = -1; + goto done; + } + + *next++ = /*'('*/ ')'; + + str = next; + parens--; + break; + } + break; + + case /*'('*/ ')': +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: end\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", + 0, 0, 0 ); +#endif + if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { + rc = -1; + goto done; + } + str++; + parens--; + break; + + case ' ': + str++; + break; + + default: /* assume it's a simple type=value filter */ +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1, + "ldap_pvt_put_filter: default\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", + 0, 0, 0 ); +#endif + next = strchr( str, '\0' ); + if ( put_simple_filter( ber, str ) == -1 ) { + rc = -1; + goto done; + } + str = next; + break; + } + } + + rc = parens ? -1 : 0; + +done: + LDAP_FREE( freeme ); + return rc; +} + +/* + * Put a list of filters like this "(filter1)(filter2)..." + */ + +static int +put_filter_list( BerElement *ber, char *str, ber_tag_t tag ) +{ + char *next = NULL; + char save; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, + "put_filter_list \"%s\"\n", str )); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", + str, 0, 0 ); +#endif + + while ( *str ) { + while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { + str++; + } + if ( *str == '\0' ) break; + + if ( (next = find_right_paren( str + 1 )) == NULL ) { + return -1; + } + save = *++next; + + /* now we have "(filter)" with str pointing to it */ + *next = '\0'; + if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1; + *next = save; + str = next; + + if( tag == LDAP_FILTER_NOT ) break; + } + + if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) { + return -1; + } + + return 0; +} + +static int +put_simple_filter( + BerElement *ber, + char *str ) +{ + char *s; + char *value; + ber_tag_t ftype; + int rc = -1; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, + "put_simple_filter: \"%s\"\n", str )); +#else + Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n", + str, 0, 0 ); +#endif + + str = LDAP_STRDUP( str ); + if( str == NULL ) return -1; + + if ( (s = strchr( str, '=' )) == NULL ) { + goto done; + } + + value = s + 1; + *s-- = '\0'; + + switch ( *s ) { + case '<': + ftype = LDAP_FILTER_LE; + *s = '\0'; + break; + + case '>': + ftype = LDAP_FILTER_GE; + *s = '\0'; + break; + + case '~': + ftype = LDAP_FILTER_APPROX; + *s = '\0'; + break; + + case ':': + /* RFC2254 extensible filters are off the form: + * type [:dn] [:rule] := value + * or [:dn]:rule := value + */ + ftype = LDAP_FILTER_EXT; + *s = '\0'; + + { + char *dn = strchr( str, ':' ); + char *rule = NULL; + + if( dn != NULL ) { + *dn++ = '\0'; + rule = strchr( dn, ':' ); + + if( rule == NULL ) { + /* one colon */ + if ( strcmp(dn, "dn") == 0 ) { + /* must have attribute */ + if( !ldap_is_desc( str ) ) { + goto done; + } + + rule = ""; + + } else { + rule = dn; + dn = NULL; + } + + } else { + /* two colons */ + *rule++ = '\0'; + + if ( strcmp(dn, "dn") != 0 ) { + /* must have "dn" */ + goto done; + } + } + + } + + if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { + /* must have either type or rule */ + goto done; + } + + if ( *str != '\0' && !ldap_is_desc( str ) ) { + goto done; + } + + if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { + goto done; + } + + rc = ber_printf( ber, "t{" /*"}"*/, ftype ); + + if( rc != -1 && rule && *rule != '\0' ) { + rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); + } + + if( rc != -1 && *str != '\0' ) { + rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); + } + + if( rc != -1 ) { + ber_slen_t len = ldap_pvt_filter_value_unescape( value ); + + if( len >= 0 ) { + rc = ber_printf( ber, "to", + LDAP_FILTER_EXT_VALUE, value, len ); + } else { + rc = -1; + } + } + + if( rc != -1 && dn ) { + rc = ber_printf( ber, "tb", + LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 ); + } + + if( rc != -1 ) { + rc = ber_printf( ber, /*"{"*/ "N}" ); + } + } + goto done; + + default: + if( !ldap_is_desc( str ) ) { + goto done; + + } else { + char *nextstar = ldap_pvt_find_wildcard( value ); + + if ( nextstar == NULL ) { + goto done; + + } else if ( *nextstar == '\0' ) { + ftype = LDAP_FILTER_EQUALITY; + + } else if ( strcmp( value, "*" ) == 0 ) { + ftype = LDAP_FILTER_PRESENT; + + } else { + rc = put_substring_filter( ber, str, value ); + goto done; + } + } break; + } + + if( !ldap_is_desc( str ) ) goto done; + + if ( ftype == LDAP_FILTER_PRESENT ) { + rc = ber_printf( ber, "ts", ftype, str ); + + } else { + ber_slen_t len = ldap_pvt_filter_value_unescape( value ); + + if( len >= 0 ) { + rc = ber_printf( ber, "t{soN}", + ftype, str, value, len ); + } + } + +done: + if( rc != -1 ) rc = 0; + LDAP_FREE( str ); + return rc; +} + +static int +put_substring_filter( BerElement *ber, char *type, char *val ) +{ + char *nextstar; + int gotstar = 0; + ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, + "put_substring_filter \"%s=%s\"\n", type, val )); +#else + Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", + type, val, 0 ); +#endif + + if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) { + return -1; + } + + for( ; *val; val=nextstar ) { + nextstar = ldap_pvt_find_wildcard( val ); + + if ( nextstar == NULL ) { + return -1; + } + + if ( *nextstar == '\0' ) { + ftype = LDAP_SUBSTRING_FINAL; + } else { + *nextstar++ = '\0'; + if ( gotstar++ == 0 ) { + ftype = LDAP_SUBSTRING_INITIAL; + } else { + ftype = LDAP_SUBSTRING_ANY; + } + } + + if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) { + ber_slen_t len = ldap_pvt_filter_value_unescape( val ); + + if ( len < 0 ) { + return -1; + } + + if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) { + return -1; + } + } + } + + if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) { + return -1; + } + + return 0; +} diff --git a/libraries/libldap/ftest.c b/libraries/libldap/ftest.c new file mode 100644 index 0000000000000000000000000000000000000000..f61298992ed4e7b372d38f2e0aa0ade4dc8a2e83 --- /dev/null +++ b/libraries/libldap/ftest.c @@ -0,0 +1,110 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* OpenLDAP Filter API Test */ + +#include "portable.h" + +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include <stdio.h> + +#include <ldap.h> + +#include "ldap_pvt.h" + +#include "ldif.h" +#include "lutil.h" +#include "lutil_ldap.h" +#include "ldap_defaults.h" + +static int filter2ber( char *filter ); + +int usage() +{ + fprintf( stderr, "usage:\n" + " ftest [-d n] filter\n" + " filter - RFC 2254 string representation of an " + "LDAP search filter\n" ); + return EXIT_FAILURE; +} + +int +main( int argc, char *argv[] ) +{ + int c; + int debug=0; + + while( (c = getopt( argc, argv, "d:" )) != EOF ) { + switch ( c ) { + case 'd': + debug = atoi( optarg ); + break; + default: + fprintf( stderr, "ftest: unrecognized option -%c\n", + optopt ); + return usage(); + } + } + + 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 ); + } + } + + if ( argc - optind != 1 ) { + return usage(); + } + + return filter2ber( strdup( argv[optind] ) ); +} + +static int filter2ber( char *filter ) +{ + int rc; + struct berval *bv = NULL; + BerElement *ber; + + printf( "Filter: %s\n", filter ); + + ber = ber_alloc_t( LBER_USE_DER ); + if( ber == NULL ) { + perror( "ber_alloc_t" ); + return EXIT_FAILURE; + } + + rc = ldap_pvt_put_filter( ber, filter ); + if( rc < 0 ) { + fprintf( stderr, "Filter error!\n"); + return EXIT_FAILURE; + } + + rc = ber_flatten( ber, &bv ); + if( rc < 0 ) { + perror( "ber_flatten" ); + return EXIT_FAILURE; + } + + printf( "BER encoding (len=%ld):\n", (long) bv->bv_len ); + ber_bprint( bv->bv_val, bv->bv_len ); + + ber_free( ber, 0 ); + ber_bvfree( bv ); + + return EXIT_SUCCESS; +} + diff --git a/libraries/libldap/getattr.c b/libraries/libldap/getattr.c index 50caa774c5330cf05e4d547f2c329333b43f2015..e5cd6e628d910edf1f09734f212d394b6f7f9bbc 100644 --- a/libraries/libldap/getattr.c +++ b/libraries/libldap/getattr.c @@ -1,80 +1,122 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * getattr.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <ctype.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "ldap-int.h" char * -ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber ) +ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **berout ) { - long len; + int rc; + ber_tag_t tag; + ber_len_t len = 0; + char *attr; + BerElement *ber; +#ifdef NEW_LOGGING + LDAP_LOG (( "getattr", LDAP_LEVEL_ENTRY, "ldap_first_attribute\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_first_attribute\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); + assert( berout != NULL ); - if ( (*ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( NULL ); + *berout = NULL; + + ber = ldap_alloc_ber_with_options( ld ); + if( ber == NULL ) { + return NULL; } - **ber = *entry->lm_ber; + *ber = *entry->lm_ber; /* - * Skip past the sequence, dn, sequence of sequence, snarf the - * attribute type, and skip the set of values, leaving us - * positioned right before the next attribute type/value sequence. + * Skip past the sequence, dn, sequence of sequence leaving + * us at the first attribute. */ - len = LDAP_MAX_ATTR_LEN; - if ( ber_scanf( *ber, "{x{{sx}", ld->ld_attrbuffer, &len ) - == LBER_ERROR ) { + tag = ber_scanf( ber, "{xl{" /*}}*/, &len ); + if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; - ber_free( *ber, 0 ); - return( NULL ); + ber_free( ber, 0 ); + return NULL; + } + + /* set the length to avoid overrun */ + rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len ); + if( rc != LBER_OPT_SUCCESS ) { + ld->ld_errno = LDAP_LOCAL_ERROR; + ber_free( ber, 0 ); + return NULL; } - return( ld->ld_attrbuffer ); + if ( ber_pvt_ber_remaining( ber ) == 0 ) { + assert( len == 0 ); + ber_free( ber, 0 ); + return NULL; + } + assert( len != 0 ); + + /* snatch the first attribute */ + tag = ber_scanf( ber, "{ax}", &attr ); + if( tag == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 0 ); + return NULL; + } + + *berout = ber; + return attr; } /* ARGSUSED */ char * ldap_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber ) { - long len; + ber_tag_t tag; + char *attr; +#ifdef NEW_LOGGING + LDAP_LOG (( "getattr", LDAP_LEVEL_ENTRY, "ldap_next_attribute\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_next_attribute\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); + assert( ber != NULL ); + + if ( ber_pvt_ber_remaining( ber ) == 0 ) { + return NULL; + } /* skip sequence, snarf attribute type, skip values */ - len = LDAP_MAX_ATTR_LEN; - if ( ber_scanf( ber, "{sx}", ld->ld_attrbuffer, &len ) - == LBER_ERROR ) { + tag = ber_scanf( ber, "{ax}", &attr ); + if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; - ber_free( ber, 0 ); - return( NULL ); + return NULL; } - return( ld->ld_attrbuffer ); + return attr; } diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index e0d36154a6baf8d60edc471ee2b709d0dcb2f1bf..db9fdb90836f7e3aaa18cd7452cf1594b3d8cf9b 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -84,7 +84,11 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry ) char *dn; BerElement tmp; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_get_dn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); +#endif if ( entry == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; @@ -108,7 +112,11 @@ ldap_dn2ufn( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2ufn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN ); @@ -127,7 +135,11 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) int iRDN; unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_explode_dn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 ); +#endif if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { @@ -167,7 +179,11 @@ ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) const char *p; int iAVA; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_explode_rdn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 ); +#endif /* * we only parse the first rdn @@ -248,7 +264,11 @@ ldap_dn2dcedn( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2dcedn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE ); @@ -261,7 +281,11 @@ ldap_dcedn2dn( LDAP_CONST char *dce ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dcedn2dn\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 ); @@ -273,7 +297,11 @@ ldap_dn2ad_canonical( LDAP_CONST char *dn ) { char *out = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn2ad_canonical\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 ); +#endif ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_AD_CANONICAL ); @@ -305,7 +333,11 @@ ldap_dn_normalize( LDAP_CONST char *dnin, int rc; LDAPDN *tmpDN = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ENTRY, "ldap_dn_normalize\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 ); +#endif assert( dnout ); @@ -628,7 +660,12 @@ ldap_bv2dn( struct berval *bv, LDAPDN **dn, unsigned flags ) assert( bv->bv_val ); assert( dn ); +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ARGS, "ldap_bv2dn(%s,%u)\n%s", + str, flags, "" )); +#else Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n%s", str, flags, "" ); +#endif *dn = NULL; @@ -800,7 +837,12 @@ return_result:; LDAP_FREE( tmpDN ); } +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_RESULTS, "<= ldap_bv2dn(%s,%u)=%d\n", + str, flags, rc )); +#else Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc ); +#endif *dn = newDN; return( rc ); @@ -1711,7 +1753,7 @@ quotedIA52strval( const char *str, struct berval *val, const char **next, unsign } len = endPos - startPos - escapes; - assert( len >= 0 ); + assert( endPos >= startPos + escapes ); val->bv_len = len; if ( escapes == 0 ) { val->bv_val = LDAP_STRNDUP( startPos, len ); @@ -2925,7 +2967,12 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags ) bv->bv_len = 0; bv->bv_val = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_ARGS, "=> ldap_dn2bv(%u)\n%s%s", + flags, "", "" )); +#else Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" ); +#endif /* * a null dn means an empty dn string @@ -3232,8 +3279,13 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags ) return LDAP_PARAM_ERROR; } +#ifdef NEW_LOGGING + LDAP_LOG (( "getdn", LDAP_LEVEL_RESULTS, "<= ldap_dn2bv(%s,%u)=%d\n", + bv->bv_val, flags, rc )); +#else Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", bv->bv_val, flags, rc ); +#endif return_results:; return( rc ); diff --git a/libraries/libldap/getfilter.c b/libraries/libldap/getfilter.c index e9ebc6aa294457ceed11058ff4df09140a697704..d6f62f325504289bc915c5fe5d3ad9e3d0cbf84e 100644 --- a/libraries/libldap/getfilter.c +++ b/libraries/libldap/getfilter.c @@ -1,116 +1,52 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * getfilter.c -- optional add-on to libldap */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <ctype.h> -#if defined(NeXT) -#include <regex.h> -#endif -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#ifdef DOS -#include <malloc.h> -#include "msdos.h" -#else /* DOS */ -#include <sys/types.h> -#include <sys/file.h> -#include <stdlib.h> -#include <sys/errno.h> -#ifndef VMS -#include <unistd.h> -#endif /* VMS */ -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" -#include "regex.h" - -#ifdef NEEDPROTOS -static int break_into_words( char *str, char *delims, char ***wordsp ); -int next_line_tokens( char **bufp, long *blenp, char ***toksp ); -void free_strarray( char **sap ); -#else /* NEEDPROTOS */ -static int break_into_words(); -int next_line_tokens(); -void free_strarray(); -#endif /* NEEDPROTOS */ - -#if !defined( MACOS ) && !defined( DOS ) -extern int errno; -extern char *re_comp(); -#endif -#define FILT_MAX_LINE_LEN 1024 +#include <ac/stdlib.h> -LDAPFiltDesc * -ldap_init_getfilter( char *fname ) -{ - FILE *fp; - char *buf; - long rlen, len; - int eof; - LDAPFiltDesc *lfdp; - - if (( fp = fopen( fname, "r" )) == NULL ) { - return( NULL ); - } - - if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */ - fclose( fp ); - return( NULL ); - } - - len = ftell( fp ); - - if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */ - fclose( fp ); - return( NULL ); - } - - if (( buf = malloc( (size_t)len )) == NULL ) { - fclose( fp ); - return( NULL ); - } - - rlen = fread( buf, 1, (size_t)len, fp ); - eof = feof( fp ); - fclose( fp ); - - if ( rlen != len && !eof ) { /* error: didn't get the whole file */ - free( buf ); - return( NULL ); - } +#include <ac/errno.h> +#include <ac/regex.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif - lfdp = ldap_init_getfilter_buf( buf, rlen ); - free( buf ); +#include "ldap-int.h" - return( lfdp ); -} +static int break_into_words LDAP_P(( + /* LDAP_CONST */ char *str, + LDAP_CONST char *delims, + char ***wordsp )); +#define FILT_MAX_LINE_LEN 1024 -LDAPFiltDesc * -ldap_init_getfilter_buf( char *buf, long buflen ) +static LDAPFiltDesc * +ldap_init_getfilter_buf( char *buf, ber_len_t buflen ) { LDAPFiltDesc *lfdp; LDAPFiltList *flp, *nextflp; LDAPFiltInfo *fip, *nextfip; - char *tag, **tok; - int tokcnt, i; + char *tag, **tok; + int tokcnt, i; + int rc; + regex_t re; - if (( lfdp = (LDAPFiltDesc *)calloc( 1, sizeof( LDAPFiltDesc))) == NULL ) { + if (( lfdp = (LDAPFiltDesc *)LDAP_CALLOC( 1, sizeof( LDAPFiltDesc))) == NULL ) { return( NULL ); } @@ -118,38 +54,44 @@ ldap_init_getfilter_buf( char *buf, long buflen ) fip = NULL; tag = NULL; - while ( buflen > 0 && ( tokcnt = next_line_tokens( &buf, &buflen, &tok )) + while ( buflen > 0 && ( tokcnt = ldap_int_next_line_tokens( &buf, &buflen, &tok )) > 0 ) { switch( tokcnt ) { case 1: /* tag line */ if ( tag != NULL ) { - free( tag ); + LDAP_FREE( tag ); } tag = tok[ 0 ]; - free( tok ); + LDAP_FREE( tok ); break; case 4: case 5: /* start of filter info. list */ - if (( nextflp = (LDAPFiltList *)calloc( 1, sizeof( LDAPFiltList ))) + if (( nextflp = (LDAPFiltList *)LDAP_CALLOC( 1, sizeof( LDAPFiltList ))) == NULL ) { ldap_getfilter_free( lfdp ); return( NULL ); } - nextflp->lfl_tag = strdup( tag ); + nextflp->lfl_tag = LDAP_STRDUP( tag ); nextflp->lfl_pattern = tok[ 0 ]; - if ( re_comp( nextflp->lfl_pattern ) != NULL ) { -#ifndef NO_USERINTERFACE + if ( (rc = regcomp( &re, nextflp->lfl_pattern, 0 )) != 0 ) { + char error[512]; + regerror(rc, &re, error, sizeof(error)); ldap_getfilter_free( lfdp ); - fprintf( stderr, "bad regular expresssion %s\n", - nextflp->lfl_pattern ); -#if !defined( MACOS ) && !defined( DOS ) - errno = EINVAL; +#ifdef NEW_LOGGING + LDAP_LOG (( "getfilter", LDAP_LEVEL_ERR, + "ldap_init_get_filter_buf: bad regular expression %s, %s\n", + nextflp->lfl_pattern, error )); +#else + Debug( LDAP_DEBUG_ANY, "ldap_init_get_filter_buf: " + "bad regular expression %s, %s\n", + nextflp->lfl_pattern, error, 0 ); #endif -#endif /* NO_USERINTERFACE */ - free_strarray( tok ); + errno = EINVAL; + LDAP_VFREE( tok ); return( NULL ); } + regfree(&re); nextflp->lfl_delims = tok[ 1 ]; nextflp->lfl_ilist = NULL; @@ -169,10 +111,10 @@ ldap_init_getfilter_buf( char *buf, long buflen ) case 2: case 3: /* filter, desc, and optional search scope */ if ( nextflp != NULL ) { /* add to info list */ - if (( nextfip = (LDAPFiltInfo *)calloc( 1, + if (( nextfip = (LDAPFiltInfo *)LDAP_CALLOC( 1, sizeof( LDAPFiltInfo ))) == NULL ) { ldap_getfilter_free( lfdp ); - free_strarray( tok ); + LDAP_VFREE( tok ); return( NULL ); } if ( fip == NULL ) { /* first one */ @@ -192,90 +134,138 @@ ldap_init_getfilter_buf( char *buf, long buflen ) } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) { nextfip->lfi_scope = LDAP_SCOPE_BASE; } else { - free_strarray( tok ); + LDAP_VFREE( tok ); ldap_getfilter_free( lfdp ); -#if !defined( MACOS ) && !defined( DOS ) errno = EINVAL; -#endif return( NULL ); } - free( tok[ 2 ] ); + LDAP_FREE( tok[ 2 ] ); tok[ 2 ] = NULL; } else { nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; /* default */ } nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL && strchr( tok[ 0 ], '~' ) == NULL ); - free( tok ); + LDAP_FREE( tok ); } break; default: - free_strarray( tok ); + LDAP_VFREE( tok ); ldap_getfilter_free( lfdp ); -#if !defined( MACOS ) && !defined( DOS ) errno = EINVAL; -#endif return( NULL ); } } if ( tag != NULL ) { - free( tag ); + LDAP_FREE( tag ); } return( lfdp ); } - -void -ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix ) +LDAPFiltDesc * +ldap_init_getfilter( LDAP_CONST char *fname ) { - if ( lfdp->lfd_filtprefix != NULL ) { - free( lfdp->lfd_filtprefix ); + FILE *fp; + char *buf; + long rlen, len; + int eof; + LDAPFiltDesc *lfdp; + + if (( fp = fopen( fname, "r" )) == NULL ) { + return( NULL ); } - lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : strdup( prefix ); - if ( lfdp->lfd_filtsuffix != NULL ) { - free( lfdp->lfd_filtsuffix ); + if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */ + fclose( fp ); + return( NULL ); + } + + len = ftell( fp ); + + if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */ + fclose( fp ); + return( NULL ); + } + + if (( buf = LDAP_MALLOC( (size_t)len )) == NULL ) { + fclose( fp ); + return( NULL ); + } + + rlen = fread( buf, 1, (size_t)len, fp ); + eof = feof( fp ); + fclose( fp ); + + if ( rlen != len && !eof ) { /* error: didn't get the whole file */ + LDAP_FREE( buf ); + return( NULL ); } - lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : strdup( suffix ); -} + lfdp = ldap_init_getfilter_buf( buf, rlen ); + LDAP_FREE( buf ); + + return( lfdp ); +} + LDAPFiltInfo * -ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value ) +ldap_getfirstfilter( + LDAPFiltDesc *lfdp, + /* LDAP_CONST */ char *tagpat, + /* LDAP_CONST */ char *value ) { LDAPFiltList *flp; + int rc; + regex_t re; if ( lfdp->lfd_curvalcopy != NULL ) { - free( lfdp->lfd_curvalcopy ); - free( lfdp->lfd_curvalwords ); + LDAP_FREE( lfdp->lfd_curvalcopy ); + LDAP_FREE( lfdp->lfd_curvalwords ); } lfdp->lfd_curval = value; lfdp->lfd_curfip = NULL; - for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) { - if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1 - && re_comp( flp->lfl_pattern ) == NULL - && re_exec( lfdp->lfd_curval ) == 1 ) { - lfdp->lfd_curfip = flp->lfl_ilist; - break; - } + for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) { + /* compile tagpat, continue if we fail */ + if (regcomp(&re, tagpat, REG_EXTENDED|REG_NOSUB) != 0) + continue; + + /* match tagpattern and tag, continue if we fail */ + rc = regexec(&re, flp->lfl_tag, 0, NULL, 0); + regfree(&re); + if (rc != 0) + continue; + + /* compile flp->ifl_pattern, continue if we fail */ + if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED|REG_NOSUB) != 0) + continue; + + /* match ifl_pattern and lfd_curval, continue if we fail */ + rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0); + regfree(&re); + if (rc != 0) + continue; + + /* we successfully compiled both patterns and matched both values */ + lfdp->lfd_curfip = flp->lfl_ilist; + break; } if ( lfdp->lfd_curfip == NULL ) { return( NULL ); } - if (( lfdp->lfd_curvalcopy = strdup( value )) == NULL ) { + if (( lfdp->lfd_curvalcopy = LDAP_STRDUP( value )) == NULL ) { return( NULL ); } if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims, &lfdp->lfd_curvalwords ) < 0 ) { - free( lfdp->lfd_curvalcopy ); + LDAP_FREE( lfdp->lfd_curvalcopy ); lfdp->lfd_curvalcopy = NULL; return( NULL ); } @@ -283,6 +273,16 @@ ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value ) return( ldap_getnextfilter( lfdp )); } +static void +ldap_build_filter( + char *filtbuf, + ber_len_t buflen, + LDAP_CONST char *pattern, + LDAP_CONST char *prefix, + LDAP_CONST char *suffix, + LDAP_CONST char *attr, + LDAP_CONST char *value, + char **valwords ); LDAPFiltInfo * ldap_getnextfilter( LDAPFiltDesc *lfdp ) @@ -308,12 +308,19 @@ ldap_getnextfilter( LDAPFiltDesc *lfdp ) return( &lfdp->lfd_retfi ); } - -void -ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, - char *prefix, char *suffix, char *attr, char *value, char **valwords ) +static void +ldap_build_filter( + char *filtbuf, + ber_len_t buflen, + LDAP_CONST char *pattern, + LDAP_CONST char *prefix, + LDAP_CONST char *suffix, + LDAP_CONST char *attr, + LDAP_CONST char *value, + char **valwords ) { - char *p, *f; + const char *p; + char *f; size_t slen; int i, wordcount, wordnum, endwordnum; @@ -336,12 +343,12 @@ ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, if ( *p == '%' ) { ++p; if ( *p == 'v' ) { - if ( isdigit( *(p+1))) { + if ( LDAP_DIGIT( (unsigned char) p[1] )) { ++p; wordnum = *p - '1'; if ( *(p+1) == '-' ) { ++p; - if ( isdigit( *(p+1))) { + if ( LDAP_DIGIT( (unsigned char) p[1] )) { ++p; endwordnum = *p - '1'; /* e.g., "%v2-4" */ if ( endwordnum > wordcount - 1 ) { @@ -360,7 +367,7 @@ ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, *f++ = ' '; } slen = strlen( valwords[ i ] ); - SAFEMEMCPY( f, valwords[ i ], slen ); + AC_MEMCPY( f, valwords[ i ], slen ); f += slen; } } @@ -369,17 +376,17 @@ ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, if ( wordcount > 0 ) { wordnum = wordcount - 1; slen = strlen( valwords[ wordnum ] ); - SAFEMEMCPY( f, valwords[ wordnum ], slen ); + AC_MEMCPY( f, valwords[ wordnum ], slen ); f += slen; } } else if ( value != NULL ) { slen = strlen( value ); - SAFEMEMCPY( f, value, slen ); + AC_MEMCPY( f, value, slen ); f += slen; } } else if ( *p == 'a' && attr != NULL ) { slen = strlen( attr ); - SAFEMEMCPY( f, attr, slen ); + AC_MEMCPY( f, attr, slen ); f += slen; } else { *f++ = *p; @@ -388,43 +395,44 @@ ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, *f++ = *p; } - if ( f - filtbuf > buflen ) { + if ( (size_t) (f - filtbuf) > buflen ) { /* sanity check */ --f; break; } } - if ( suffix != NULL && ( f - filtbuf ) < buflen ) { + if ( suffix != NULL && ( (size_t) (f - filtbuf) < buflen ) ) + { strcpy( f, suffix ); } else { *f = '\0'; } } - static int -break_into_words( char *str, char *delims, char ***wordsp ) +break_into_words( /* LDAP_CONST */ char *str, LDAP_CONST char *delims, char ***wordsp ) { char *word, **words; int count; - - if (( words = (char **)calloc( 1, sizeof( char * ))) == NULL ) { + char *tok_r; + + if (( words = (char **)LDAP_CALLOC( 1, sizeof( char * ))) == NULL ) { return( -1 ); } count = 0; words[ count ] = NULL; - word = strtok( str, delims ); + word = ldap_pvt_strtok( str, delims, &tok_r ); while ( word != NULL ) { - if (( words = (char **)realloc( words, + if (( words = (char **)LDAP_REALLOC( words, ( count + 2 ) * sizeof( char * ))) == NULL ) { return( -1 ); } words[ count ] = word; words[ ++count ] = NULL; - word = strtok( NULL, delims ); + word = ldap_pvt_strtok( NULL, delims, &tok_r ); } *wordsp = words; diff --git a/libraries/libldap/getvalues.c b/libraries/libldap/getvalues.c index 55102be8ab6f1c753b218fe137732169b27c69b8..bbf16d8c411c3e6b8981527cd216ea12517b8f56 100644 --- a/libraries/libldap/getvalues.c +++ b/libraries/libldap/getvalues.c @@ -1,49 +1,51 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * getvalues.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <ctype.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" char ** -ldap_get_values( LDAP *ld, LDAPMessage *entry, char *target ) +ldap_get_values( LDAP *ld, LDAPMessage *entry, LDAP_CONST char *target ) { BerElement ber; - char attr[LDAP_MAX_ATTR_LEN]; + char *attr; int found = 0; - long len; char **vals; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); + assert( target != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "getvalues", LDAP_LEVEL_ENTRY, "ldap_get_values\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 ); +#endif ber = *entry->lm_ber; /* skip sequence, dn, sequence of, and snag the first attr */ - len = sizeof(attr); - if ( ber_scanf( &ber, "{x{{s", attr, &len ) == LBER_ERROR ) { + if ( ber_scanf( &ber, "{x{{a" /*}}}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } @@ -53,16 +55,22 @@ ldap_get_values( LDAP *ld, LDAPMessage *entry, char *target ) /* break out on success, return out on error */ while ( ! found ) { - len = sizeof(attr); - if ( ber_scanf( &ber, "x}{s", attr, &len ) == LBER_ERROR ) { + LDAP_FREE(attr); + attr = NULL; + + if ( ber_scanf( &ber, /*{*/ "x}{a" /*}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } if ( strcasecmp( target, attr ) == 0 ) break; + } + LDAP_FREE(attr); + attr = NULL; + /* * if we get this far, we've found the attribute and are sitting * just before the set of values. @@ -77,21 +85,28 @@ ldap_get_values( LDAP *ld, LDAPMessage *entry, char *target ) } struct berval ** -ldap_get_values_len( LDAP *ld, LDAPMessage *entry, char *target ) +ldap_get_values_len( LDAP *ld, LDAPMessage *entry, LDAP_CONST char *target ) { BerElement ber; - char attr[LDAP_MAX_ATTR_LEN]; + char *attr; int found = 0; - long len; struct berval **vals; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); + assert( target != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "getvalues", LDAP_LEVEL_ENTRY, "ldap_get_values_len\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_get_values_len\n", 0, 0, 0 ); +#endif ber = *entry->lm_ber; /* skip sequence, dn, sequence of, and snag the first attr */ - len = sizeof(attr); - if ( ber_scanf( &ber, "{x{{s", attr, &len ) == LBER_ERROR ) { + if ( ber_scanf( &ber, "{x{{a" /* }}} */, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } @@ -101,8 +116,10 @@ ldap_get_values_len( LDAP *ld, LDAPMessage *entry, char *target ) /* break out on success, return out on error */ while ( ! found ) { - len = sizeof(attr); - if ( ber_scanf( &ber, "x}{s", attr, &len ) == LBER_ERROR ) { + LDAP_FREE( attr ); + attr = NULL; + + if ( ber_scanf( &ber, /*{*/ "x}{a" /*}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } @@ -111,6 +128,9 @@ ldap_get_values_len( LDAP *ld, LDAPMessage *entry, char *target ) break; } + LDAP_FREE( attr ); + attr = NULL; + /* * if we get this far, we've found the attribute and are sitting * just before the set of values. @@ -147,25 +167,11 @@ ldap_count_values_len( struct berval **vals ) void ldap_value_free( char **vals ) { - int i; - - if ( vals == NULL ) - return; - for ( i = 0; vals[i] != NULL; i++ ) - free( vals[i] ); - free( (char *) vals ); + LDAP_VFREE( vals ); } void ldap_value_free_len( struct berval **vals ) { - int i; - - if ( vals == NULL ) - return; - for ( i = 0; vals[i] != NULL; i++ ) { - free( vals[i]->bv_val ); - free( vals[i] ); - } - free( (char *) vals ); + ber_bvecfree( vals ); } diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c new file mode 100644 index 0000000000000000000000000000000000000000..c6b68759823304508494be73f768def571f82827 --- /dev/null +++ b/libraries/libldap/init.c @@ -0,0 +1,606 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/time.h> + +#include <limits.h> + +#include "ldap-int.h" +#include "ldap_defaults.h" + +struct ldapoptions ldap_int_global_options = + { LDAP_UNINITIALIZED, LDAP_DEBUG_NONE }; + +#define ATTR_NONE 0 +#define ATTR_BOOL 1 +#define ATTR_INT 2 +#define ATTR_KV 3 +#define ATTR_STRING 4 +#define ATTR_OPTION 5 + +#define ATTR_SASL 6 +#define ATTR_TLS 7 + +struct ol_keyvalue { + const char * key; + int value; +}; + +static const struct ol_keyvalue deref_kv[] = { + {"never", LDAP_DEREF_NEVER}, + {"searching", LDAP_DEREF_SEARCHING}, + {"finding", LDAP_DEREF_FINDING}, + {"always", LDAP_DEREF_ALWAYS}, + {NULL, 0} +}; + +static const struct ol_attribute { + int useronly; + int type; + const char * name; + const void * data; + size_t offset; +} attrs[] = { + {0, ATTR_KV, "DEREF", deref_kv, /* or &deref_kv[0] */ + offsetof(struct ldapoptions, ldo_deref)}, + {0, ATTR_INT, "SIZELIMIT", NULL, + offsetof(struct ldapoptions, ldo_sizelimit)}, + {0, ATTR_INT, "TIMELIMIT", NULL, + offsetof(struct ldapoptions, ldo_timelimit)}, + {1, ATTR_STRING, "BINDDN", NULL, + offsetof(struct ldapoptions, ldo_defbinddn)}, + {0, ATTR_STRING, "BASE", NULL, + offsetof(struct ldapoptions, ldo_defbase)}, + {0, ATTR_INT, "PORT", NULL, /* deprecated */ + offsetof(struct ldapoptions, ldo_defport)}, + {0, ATTR_OPTION, "HOST", NULL, LDAP_OPT_HOST_NAME}, /* deprecated */ + {0, ATTR_OPTION, "URI", NULL, LDAP_OPT_URI}, /* replaces HOST/PORT */ + {0, ATTR_BOOL, "REFERRALS", NULL, LDAP_BOOL_REFERRALS}, + {0, ATTR_BOOL, "RESTART", NULL, LDAP_BOOL_RESTART}, + +#ifdef HAVE_CYRUS_SASL + {1, ATTR_STRING, "SASL_MECH", NULL, + offsetof(struct ldapoptions, ldo_def_sasl_mech)}, + {1, ATTR_STRING, "SASL_REALM", NULL, + offsetof(struct ldapoptions, ldo_def_sasl_realm)}, + {1, ATTR_STRING, "SASL_AUTHCID", NULL, + offsetof(struct ldapoptions, ldo_def_sasl_authcid)}, + {1, ATTR_STRING, "SASL_AUTHZID", NULL, + offsetof(struct ldapoptions, ldo_def_sasl_authzid)}, + {0, ATTR_SASL, "SASL_SECPROPS", NULL, LDAP_OPT_X_SASL_SECPROPS}, +#endif + +#ifdef HAVE_TLS + {0, ATTR_TLS, "TLS", NULL, LDAP_OPT_X_TLS}, + {1, ATTR_TLS, "TLS_CERT", NULL, LDAP_OPT_X_TLS_CERTFILE}, + {1, ATTR_TLS, "TLS_KEY", NULL, LDAP_OPT_X_TLS_KEYFILE}, + {0, ATTR_TLS, "TLS_CACERT", NULL, LDAP_OPT_X_TLS_CACERTFILE}, + {0, ATTR_TLS, "TLS_CACERTDIR",NULL, LDAP_OPT_X_TLS_CACERTDIR}, + {0, ATTR_TLS, "TLS_REQCERT", NULL, LDAP_OPT_X_TLS_REQUIRE_CERT}, + {0, ATTR_TLS, "TLS_RANDFILE", NULL, LDAP_OPT_X_TLS_RANDOM_FILE}, +#endif + + {0, ATTR_NONE, NULL, NULL, 0} +}; + +#define MAX_LDAP_ATTR_LEN sizeof("TLS_CACERTDIR") +#define MAX_LDAP_ENV_PREFIX_LEN 8 + +static void openldap_ldap_init_w_conf( + const char *file, int userconf ) +{ + char linebuf[128]; + FILE *fp; + int i; + char *cmd, *opt; + char *start, *end; + struct ldapoptions *gopts; + + if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) { + return; /* Could not allocate mem for global options */ + } + + if (file == NULL) { + /* no file name */ + return; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_conf: trying %s\n", file )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: trying %s\n", file, 0, 0); +#endif + + fp = fopen(file, "r"); + if(fp == NULL) { + /* could not open file */ + return; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_conf: using %s\n", file )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: using %s\n", file, 0, 0); +#endif + + while((start = fgets(linebuf, sizeof(linebuf), fp)) != NULL) { + /* skip lines starting with '#' */ + if(*start == '#') continue; + + /* trim leading white space */ + while((*start != '\0') && isspace((unsigned char) *start)) + start++; + + /* anything left? */ + if(*start == '\0') continue; + + /* trim trailing white space */ + end = &start[strlen(start)-1]; + while(isspace((unsigned char)*end)) end--; + end[1] = '\0'; + + /* anything left? */ + if(*start == '\0') continue; + + + /* parse the command */ + cmd=start; + while((*start != '\0') && !isspace((unsigned char)*start)) { + start++; + } + if(*start == '\0') { + /* command has no argument */ + continue; + } + + *start++ = '\0'; + + /* we must have some whitespace to skip */ + while(isspace((unsigned char)*start)) start++; + opt = start; + + for(i=0; attrs[i].type != ATTR_NONE; i++) { + void *p; + + if( !userconf && attrs[i].useronly ) { + continue; + } + + if(strcasecmp(cmd, attrs[i].name) != 0) { + continue; + } + + switch(attrs[i].type) { + case ATTR_BOOL: + if((strcasecmp(opt, "on") == 0) + || (strcasecmp(opt, "yes") == 0) + || (strcasecmp(opt, "true") == 0)) + { + LDAP_BOOL_SET(gopts, attrs[i].offset); + + } else { + LDAP_BOOL_CLR(gopts, attrs[i].offset); + } + + break; + + case ATTR_INT: + p = &((char *) gopts)[attrs[i].offset]; + * (int*) p = atoi(opt); + break; + + case ATTR_KV: { + const struct ol_keyvalue *kv; + + for(kv = attrs[i].data; + kv->key != NULL; + kv++) { + + if(strcasecmp(opt, kv->key) == 0) { + p = &((char *) gopts)[attrs[i].offset]; + * (int*) p = kv->value; + break; + } + } + } break; + + case ATTR_STRING: + p = &((char *) gopts)[attrs[i].offset]; + if (* (char**) p != NULL) LDAP_FREE(* (char**) p); + * (char**) p = LDAP_STRDUP(opt); + break; + case ATTR_OPTION: + ldap_set_option( NULL, attrs[i].offset, opt ); + break; + case ATTR_SASL: +#ifdef HAVE_CYRUS_SASL + ldap_int_sasl_config( gopts, attrs[i].offset, opt ); +#endif + break; + case ATTR_TLS: +#ifdef HAVE_TLS + ldap_int_tls_config( NULL, attrs[i].offset, opt ); +#endif + break; + } + + break; + } + } + + fclose(fp); +} + +static void openldap_ldap_init_w_sysconf(const char *file) +{ + openldap_ldap_init_w_conf( file, 0 ); +} + +static void openldap_ldap_init_w_userconf(const char *file) +{ + char *home; + char *path = NULL; + + if (file == NULL) { + /* no file name */ + return; + } + + home = getenv("HOME"); + + if (home != NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_ARGS, + "openldap_init_w_userconf: HOME env is %s\n", home )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is %s\n", + home, 0, 0); +#endif + path = LDAP_MALLOC(strlen(home) + strlen(file) + 3); + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_ARGS, + "openldap_init_w_userconf: HOME env is NULL\n" )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is NULL\n", + 0, 0, 0); +#endif + } + + if(home != NULL && path != NULL) { + /* we assume UNIX path syntax is used... */ + + /* try ~/file */ + sprintf(path, "%s%s%s", home, LDAP_DIRSEP, file); + openldap_ldap_init_w_conf(path, 1); + + /* try ~/.file */ + sprintf(path, "%s%s.%s", home, LDAP_DIRSEP, file); + openldap_ldap_init_w_conf(path, 1); + } + + if(path != NULL) { + LDAP_FREE(path); + } + + /* try file */ + openldap_ldap_init_w_conf(file, 1); +} + +static void openldap_ldap_init_w_env( + struct ldapoptions *gopts, + const char *prefix) +{ + char buf[MAX_LDAP_ATTR_LEN+MAX_LDAP_ENV_PREFIX_LEN]; + int len; + int i; + void *p; + char *value; + + if (prefix == NULL) { + prefix = LDAP_ENV_PREFIX; + } + + strncpy(buf, prefix, MAX_LDAP_ENV_PREFIX_LEN); + buf[MAX_LDAP_ENV_PREFIX_LEN] = '\0'; + len = strlen(buf); + + for(i=0; attrs[i].type != ATTR_NONE; i++) { + strcpy(&buf[len], attrs[i].name); + value = getenv(buf); + + if(value == NULL) { + continue; + } + + switch(attrs[i].type) { + case ATTR_BOOL: + if((strcasecmp(value, "on") == 0) + || (strcasecmp(value, "yes") == 0) + || (strcasecmp(value, "true") == 0)) + { + LDAP_BOOL_SET(gopts, attrs[i].offset); + + } else { + LDAP_BOOL_CLR(gopts, attrs[i].offset); + } + break; + + case ATTR_INT: + p = &((char *) gopts)[attrs[i].offset]; + * (int*) p = atoi(value); + break; + + case ATTR_KV: { + const struct ol_keyvalue *kv; + + for(kv = attrs[i].data; + kv->key != NULL; + kv++) { + + if(strcasecmp(value, kv->key) == 0) { + p = &((char *) gopts)[attrs[i].offset]; + * (int*) p = kv->value; + break; + } + } + } break; + + case ATTR_STRING: + p = &((char *) gopts)[attrs[i].offset]; + if (* (char**) p != NULL) LDAP_FREE(* (char**) p); + if (*value == '\0') { + * (char**) p = NULL; + } else { + * (char**) p = LDAP_STRDUP(value); + } + break; + case ATTR_OPTION: + ldap_set_option( NULL, attrs[i].offset, value ); + break; + case ATTR_SASL: +#ifdef HAVE_CYRUS_SASL + ldap_int_sasl_config( gopts, attrs[i].offset, value ); +#endif + break; + case ATTR_TLS: +#ifdef HAVE_TLS + ldap_int_tls_config( NULL, attrs[i].offset, value ); +#endif + break; + } + } +} + +#if defined(__GNUC__) +/* Declare this function as a destructor so that it will automatically be + * invoked either at program exit (if libldap is a static library) or + * at unload time (if libldap is a dynamic library). + * + * Sorry, don't know how to handle this for non-GCC environments. + */ +static void ldap_int_destroy_global_options(void) + __attribute__ ((destructor)); +#endif + +static void +ldap_int_destroy_global_options(void) +{ + struct ldapoptions *gopts = LDAP_INT_GLOBAL_OPT(); + + if ( gopts->ldo_defludp ) { + ldap_free_urllist( gopts->ldo_defludp ); + gopts->ldo_defludp = NULL; + } +#if defined(HAVE_WINSOCK) || defined(HAVE_WINSOCK2) + WSACleanup( ); +#endif +} + +/* + * Initialize the global options structure with default values. + */ +void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl ) +{ + if (dbglvl) + gopts->ldo_debug = *dbglvl; + else + gopts->ldo_debug = 0; + + gopts->ldo_version = LDAP_VERSION2; + gopts->ldo_deref = LDAP_DEREF_NEVER; + gopts->ldo_timelimit = LDAP_NO_LIMIT; + gopts->ldo_sizelimit = LDAP_NO_LIMIT; + + gopts->ldo_tm_api = (struct timeval *)NULL; + gopts->ldo_tm_net = (struct timeval *)NULL; + + /* ldo_defludp will be freed by the termination handler + */ + ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/"); + gopts->ldo_defport = LDAP_PORT; +#if !defined(__GNUC__) && !defined(PIC) + /* Do this only for a static library, and only if we can't + * arrange for it to be executed as a library destructor + */ + atexit(ldap_int_destroy_global_options); +#endif + + gopts->ldo_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT; + gopts->ldo_rebind_proc = NULL; + gopts->ldo_rebind_params = NULL; + + LDAP_BOOL_ZERO(gopts); + + LDAP_BOOL_SET(gopts, LDAP_BOOL_REFERRALS); + +#ifdef LDAP_CONNECTIONLESS + gopts->ldo_peer = NULL; + gopts->ldo_cldapdn = NULL; + gopts->ldo_is_udp = 0; +#endif + +#ifdef HAVE_CYRUS_SASL + gopts->ldo_def_sasl_mech = NULL; + gopts->ldo_def_sasl_realm = NULL; + gopts->ldo_def_sasl_authcid = NULL; + gopts->ldo_def_sasl_authzid = NULL; + + memset( &gopts->ldo_sasl_secprops, + '\0', sizeof(gopts->ldo_sasl_secprops) ); + + gopts->ldo_sasl_secprops.max_ssf = INT_MAX; + gopts->ldo_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE; + gopts->ldo_sasl_secprops.security_flags = + SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS; +#endif + + gopts->ldo_valid = LDAP_INITIALIZED; + return; +} + +#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \ + || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) +char * ldap_int_hostname = NULL; +#endif + +void ldap_int_initialize( struct ldapoptions *gopts, int *dbglvl ) +{ + if ( gopts->ldo_valid == LDAP_INITIALIZED ) { + return; + } + + ldap_int_error_init(); + +#ifdef HAVE_WINSOCK2 +{ WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD( 2, 0 ); + if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + return; + } + + /* Confirm that the WinSock DLL supports 2.0.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.0 in addition to 2.0, it will still return */ + /* 2.0 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 0 ) + { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + return; + } +} /* The WinSock DLL is acceptable. Proceed. */ +#elif HAVE_WINSOCK +{ WSADATA wsaData; + if ( WSAStartup( 0x0101, &wsaData ) != 0 ) { + return; + } +} +#endif + +#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \ + || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) + ldap_int_hostname = ldap_pvt_get_fqdn( ldap_int_hostname ); +#endif + ldap_int_utils_init(); + + if ( ldap_int_tblsize == 0 ) + ldap_int_ip_init(); + + ldap_int_initialize_global_options(gopts, NULL); + + if( getenv("LDAPNOINIT") != NULL ) { + return; + } + +#ifdef HAVE_CYRUS_SASL + { + /* set authentication identity to current user name */ + char *user = getenv("USER"); + + if( user == NULL ) user = getenv("USERNAME"); + if( user == NULL ) user = getenv("LOGNAME"); + + if( user != NULL ) { + gopts->ldo_def_sasl_authcid = user; + } + } +#endif + + openldap_ldap_init_w_sysconf(LDAP_CONF_FILE); + openldap_ldap_init_w_userconf(LDAP_USERRC_FILE); + + { + char *altfile = getenv(LDAP_ENV_PREFIX "CONF"); + + if( altfile != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_userconf: %sCONF env is %s\n", + LDAP_ENV_PREFIX, altfile )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n", + LDAP_ENV_PREFIX "CONF", altfile, 0); +#endif + openldap_ldap_init_w_sysconf( altfile ); + } + else +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_userconf: %sCONF env is NULL\n", + LDAP_ENV_PREFIX )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n", + LDAP_ENV_PREFIX "CONF", 0, 0); +#endif + } + + { + char *altfile = getenv(LDAP_ENV_PREFIX "RC"); + + if( altfile != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_userconf: %sRC env is %s\n", + LDAP_ENV_PREFIX, altfile )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n", + LDAP_ENV_PREFIX "RC", altfile, 0); +#endif + openldap_ldap_init_w_userconf( altfile ); + } + else +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_DETAIL1, + "openldap_init_w_userconf: %sRC env is NULL\n", + LDAP_ENV_PREFIX )); +#else + Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n", + LDAP_ENV_PREFIX "RC", 0, 0); +#endif + } + + openldap_ldap_init_w_env(gopts, NULL); + + ldap_int_sasl_init(); +} diff --git a/libraries/libldap/kbind.c b/libraries/libldap/kbind.c index ce4a8a7f6d54bef4eba2f1bae0a96f164d7f7aaa..372eb9fa0053a98856963865a2abf9a6f1982691 100644 --- a/libraries/libldap/kbind.c +++ b/libraries/libldap/kbind.c @@ -1,39 +1,49 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * kbind.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; +/* + * BindRequest ::= SEQUENCE { + * version INTEGER, + * name DistinguishedName, -- who + * authentication CHOICE { + * simple [0] OCTET STRING -- passwd +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + * krbv42ldap [1] OCTET STRING + * krbv42dsa [2] OCTET STRING #endif + * sasl [3] SaslCredentials -- LDAPv3 + * } + * } + * + * BindResponse ::= SEQUENCE { + * COMPONENTS OF LDAPResult, + * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 + * } + * + */ + +#include "portable.h" -#ifdef KERBEROS +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND #include <stdio.h> -#include <string.h> - -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#ifdef DOS -#include "msdos.h" -#endif /* DOS */ -#include <krb.h> -#include <stdlib.h> -#if !defined(DOS) && !defined( _WIN32 ) -#include <sys/types.h> -#endif /* !DOS && !_WIN32 */ -#include <sys/time.h> -#include <sys/socket.h> -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" -#include "ldap-int.h" +#include <ac/stdlib.h> + +#include <ac/krb.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include "ldap-int.h" /* @@ -47,88 +57,72 @@ static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of * ldap_kerberos_bind1( ld, "cn=manager, o=university of michigan, c=us" ) */ int -ldap_kerberos_bind1( LDAP *ld, char *dn ) +ldap_kerberos_bind1( LDAP *ld, LDAP_CONST char *dn ) { BerElement *ber; char *cred; - int rc, credlen; - char *get_kerberosv4_credentials(); -#ifdef STR_TRANSLATION - int str_translation_on; -#endif /* STR_TRANSLATION */ - - /* - * The bind request looks like this: - * BindRequest ::= SEQUENCE { - * version INTEGER, - * name DistinguishedName, - * authentication CHOICE { - * krbv42ldap [1] OCTET STRING - * krbv42dsa [2] OCTET STRING - * } - * } - * all wrapped up in an LDAPMessage sequence. - */ + int rc; + ber_len_t credlen; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, "ldap_kerberos_bind1\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1\n", 0, 0, 0 ); +#endif + + if( ld->ld_version > LDAP_VERSION2 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return -1; + } if ( dn == NULL ) dn = ""; - if ( (cred = get_kerberosv4_credentials( ld, dn, "ldapserver", + if ( (cred = ldap_get_kerberosv4_credentials( ld, dn, "ldapserver", &credlen )) == NULL ) { return( -1 ); /* ld_errno should already be set */ } /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - free( cred ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + LDAP_FREE( cred ); return( -1 ); } -#ifdef STR_TRANSLATION - if (( str_translation_on = (( ber->ber_options & - LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */ - ber->ber_options &= ~LBER_TRANSLATE_STRINGS; - } -#endif /* STR_TRANSLATION */ - /* fill it in */ - rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND, + rc = ber_printf( ber, "{it{istoN}N}", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_KRBV41, cred, credlen ); -#ifdef STR_TRANSLATION - if ( str_translation_on ) { /* restore translation */ - ber->ber_options |= LBER_TRANSLATE_STRINGS; - } -#endif /* STR_TRANSLATION */ - if ( rc == -1 ) { - free( cred ); + LDAP_FREE( cred ); ber_free( ber, 1 ); ld->ld_errno = LDAP_ENCODING_ERROR; return( -1 ); } - free( cred ); + LDAP_FREE( cred ); -#ifndef NO_CACHE +#ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { ldap_flush_cache( ld ); } -#endif /* !NO_CACHE */ +#endif /* !LDAP_NOCACHE */ /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber )); + return ( ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber )); } int -ldap_kerberos_bind1_s( LDAP *ld, char *dn ) +ldap_kerberos_bind1_s( LDAP *ld, LDAP_CONST char *dn ) { int msgid; LDAPMessage *res; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, "ldap_kerberos_bind1_s\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1_s\n", 0, 0, 0 ); +#endif /* initiate the bind */ if ( (msgid = ldap_kerberos_bind1( ld, dn )) == -1 ) @@ -154,51 +148,44 @@ ldap_kerberos_bind1_s( LDAP *ld, char *dn ) * ldap_kerberos_bind2( ld, "cn=manager, o=university of michigan, c=us" ) */ int -ldap_kerberos_bind2( LDAP *ld, char *dn ) +ldap_kerberos_bind2( LDAP *ld, LDAP_CONST char *dn ) { BerElement *ber; char *cred; - int rc, credlen; - char *get_kerberosv4_credentials(); -#ifdef STR_TRANSLATION - int str_translation_on; -#endif /* STR_TRANSLATION */ + int rc; + ber_len_t credlen; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, "ldap_kerberos_bind2\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2\n", 0, 0, 0 ); +#endif + + if( ld->ld_version > LDAP_VERSION2 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return -1; + } if ( dn == NULL ) dn = ""; - if ( (cred = get_kerberosv4_credentials( ld, dn, "x500dsa", &credlen )) + if ( (cred = ldap_get_kerberosv4_credentials( ld, dn, "x500dsa", &credlen )) == NULL ) { return( -1 ); /* ld_errno should already be set */ } /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - free( cred ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + LDAP_FREE( cred ); return( -1 ); } -#ifdef STR_TRANSLATION - if (( str_translation_on = (( ber->ber_options & - LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */ - ber->ber_options &= ~LBER_TRANSLATE_STRINGS; - } -#endif /* STR_TRANSLATION */ - /* fill it in */ - rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND, + rc = ber_printf( ber, "{it{istoN}N}", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_KRBV42, cred, credlen ); -#ifdef STR_TRANSLATION - if ( str_translation_on ) { /* restore translation */ - ber->ber_options |= LBER_TRANSLATE_STRINGS; - } -#endif /* STR_TRANSLATION */ - - free( cred ); + LDAP_FREE( cred ); if ( rc == -1 ) { ber_free( ber, 1 ); @@ -207,17 +194,21 @@ ldap_kerberos_bind2( LDAP *ld, char *dn ) } /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber )); + return ( ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber )); } /* synchronous bind to DSA using kerberos */ int -ldap_kerberos_bind2_s( LDAP *ld, char *dn ) +ldap_kerberos_bind2_s( LDAP *ld, LDAP_CONST char *dn ) { int msgid; LDAPMessage *res; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, "ldap_kerberos_bind2_s\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2_s\n", 0, 0, 0 ); +#endif /* initiate the bind */ if ( (msgid = ldap_kerberos_bind2( ld, dn )) == -1 ) @@ -234,11 +225,15 @@ ldap_kerberos_bind2_s( LDAP *ld, char *dn ) /* synchronous bind to ldap and DSA using kerberos */ int -ldap_kerberos_bind_s( LDAP *ld, char *dn ) +ldap_kerberos_bind_s( LDAP *ld, LDAP_CONST char *dn ) { int err; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, "ldap_kerberos_bind_s\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind_s\n", 0, 0, 0 ); +#endif if ( (err = ldap_kerberos_bind1_s( ld, dn )) != LDAP_SUCCESS ) return( err ); @@ -249,54 +244,76 @@ ldap_kerberos_bind_s( LDAP *ld, char *dn ) #ifndef AUTHMAN /* - * get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap. + * ldap_get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap. * The dn of the entry to which to bind is supplied. It's assumed the * user already has a tgt. */ char * -get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len ) +ldap_get_kerberosv4_credentials( + LDAP *ld, + LDAP_CONST char *who, + LDAP_CONST char *service, + ber_len_t *len ) { KTEXT_ST ktxt; int err; char realm[REALM_SZ], *cred, *krbinstance; - Debug( LDAP_DEBUG_TRACE, "get_kerberosv4_credentials\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ENTRY, + "ldap_get_kerberosv4_credentials\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_get_kerberosv4_credentials\n", 0, 0, 0 ); +#endif if ( (err = krb_get_tf_realm( tkt_string(), realm )) != KSUCCESS ) { -#ifndef NO_USERINTERFACE - fprintf( stderr, "krb_get_tf_realm failed (%s)\n", - krb_err_txt[err] ); -#endif /* NO_USERINTERFACE */ - ld->ld_errno = LDAP_INVALID_CREDENTIALS; +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ERR, + "ldap_get_kerberosv4_credentials: krb_get_tf_realm failed: %s\n", + krb_err_txt[err] )); +#else + Debug( LDAP_DEBUG_ANY, "ldap_get_kerberosv4_credentials: " + "krb_get_tf_realm failed: %s\n", krb_err_txt[err], 0, 0 ); +#endif + ld->ld_errno = LDAP_AUTH_UNKNOWN; return( NULL ); } -#ifdef LDAP_REFERRALS + if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { + /* not connected yet */ + int rc = ldap_open_defconn( ld ); + + if( rc < 0 ) return NULL; + } + krbinstance = ld->ld_defconn->lconn_krbinstance; -#else /* LDAP_REFERRALS */ - krbinstance = ld->ld_host; -#endif /* LDAP_REFERRALS */ if ( (err = krb_mk_req( &ktxt, service, krbinstance, realm, 0 )) - != KSUCCESS ) { -#ifndef NO_USERINTERFACE - fprintf( stderr, "krb_mk_req failed (%s)\n", krb_err_txt[err] ); -#endif /* NO_USERINTERFACE */ - ld->ld_errno = LDAP_INVALID_CREDENTIALS; + != KSUCCESS ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "kbind", LDAP_LEVEL_ERR, + "ldap_get_kerberosv4_credentials: krb_mk_req failed: %s\n", + krb_err_txt[err] )); +#else + Debug( LDAP_DEBUG_ANY, "ldap_get_kerberosv4_credentials: " + "krb_mk_req failed (%s)\n", krb_err_txt[err], 0, 0 ); +#endif + ld->ld_errno = LDAP_AUTH_UNKNOWN; return( NULL ); } - if ( ( cred = malloc( ktxt.length )) == NULL ) { + if ( ( cred = LDAP_MALLOC( ktxt.length )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( NULL ); } *len = ktxt.length; - memcpy( cred, ktxt.dat, ktxt.length ); + AC_MEMCPY( cred, ktxt.dat, ktxt.length ); return( cred ); } #endif /* !AUTHMAN */ -#endif /* KERBEROS */ +#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */ diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 10adbe91ff7fdd143e69252e46e479f2790dee39..4ad20dd9f4c813a6172fbc9e940e42b441803d9d 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -1,189 +1,584 @@ +/* ldap-int.h - defines & prototypes internal to the LDAP library */ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. - * - * ldap-int.h - defines & prototypes internal to the LDAP library */ +#ifndef _LDAP_INT_H +#define _LDAP_INT_H 1 + +#ifdef LDAP_R_COMPILE +#define LDAP_THREAD_SAFE 1 +#endif + +#include "../liblber/lber-int.h" + +#ifdef LDAP_R_COMPILE +#include <ldap_pvt_thread.h> +#endif + +#ifdef HAVE_CYRUS_SASL + /* the need for this should be removed */ +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#else +#include <sasl.h> +#endif + +#define SASL_MAX_BUFF_SIZE 65536 +#define SASL_MIN_BUFF_SIZE 4096 +#endif + +/* + * Support needed if the library is running in the kernel + */ +#if LDAP_INT_IN_KERNEL + /* + * Platform specific function to return a pointer to the + * process-specific global options. + * + * This function should perform the following functions: + * Allocate and initialize a global options struct on a per process basis + * Use callers process identifier to return its global options struct + * Note: Deallocate structure when the process exits + */ +# define LDAP_INT_GLOBAL_OPT() ldap_int_global_opt() + struct ldapoptions *ldap_int_global_opt(void); +#else +# define LDAP_INT_GLOBAL_OPT() (&ldap_int_global_options) +#endif + +#define ldap_debug ((LDAP_INT_GLOBAL_OPT())->ldo_debug) + +#include "ldap_log.h" + +#undef Debug +#define Debug( level, fmt, arg1, arg2, arg3 ) \ + do { if ( ldap_debug & level ) \ + ldap_log_printf( NULL, (level), (fmt), (arg1), (arg2), (arg3) ); \ + } while ( 0 ) + +#define LDAP_Debug( subsystem, level, fmt, arg1, arg2, arg3 )\ + ldap_log_printf( NULL, (level), (fmt), (arg1), (arg2), (arg3) ) + +#include "ldap.h" + +#include "ldap_pvt.h" + +LDAP_BEGIN_DECL #define LDAP_URL_PREFIX "ldap://" -#define LDAP_URL_PREFIX_LEN 7 -#define LDAP_URL_URLCOLON "URL:" -#define LDAP_URL_URLCOLON_LEN 4 +#define LDAP_URL_PREFIX_LEN (sizeof(LDAP_URL_PREFIX)-1) +#define LDAPS_URL_PREFIX "ldaps://" +#define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1) +#define LDAPI_URL_PREFIX "ldapi://" +#define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1) +#ifdef LDAP_CONNECTIONLESS +#define LDAPC_URL_PREFIX "cldap://" +#define LDAPC_URL_PREFIX_LEN (sizeof(LDAPC_URL_PREFIX)-1) +#endif +#define LDAP_URL_URLCOLON "URL:" +#define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1) -#ifdef LDAP_REFERRALS #define LDAP_REF_STR "Referral:\n" -#define LDAP_REF_STR_LEN 10 +#define LDAP_REF_STR_LEN (sizeof(LDAP_REF_STR)-1) #define LDAP_LDAP_REF_STR LDAP_URL_PREFIX #define LDAP_LDAP_REF_STR_LEN LDAP_URL_PREFIX_LEN -#ifdef LDAP_DNS -#define LDAP_DX_REF_STR "dx://" -#define LDAP_DX_REF_STR_LEN 5 -#endif /* LDAP_DNS */ -#endif /* LDAP_REFERRALS */ +#define LDAP_DEFAULT_REFHOPLIMIT 5 + +#define LDAP_BOOL_REFERRALS 0 +#define LDAP_BOOL_RESTART 1 +#define LDAP_BOOL_TLS 3 + +#define LDAP_BOOLEANS unsigned long +#define LDAP_BOOL(n) (1 << (n)) +#define LDAP_BOOL_GET(lo, bool) \ + ((lo)->ldo_booleans & LDAP_BOOL(bool) ? -1 : 0) +#define LDAP_BOOL_SET(lo, bool) ((lo)->ldo_booleans |= LDAP_BOOL(bool)) +#define LDAP_BOOL_CLR(lo, bool) ((lo)->ldo_booleans &= ~LDAP_BOOL(bool)) +#define LDAP_BOOL_ZERO(lo) ((lo)->ldo_booleans = 0) + +/* + * This structure represents both ldap messages and ldap responses. + * These are really the same, except in the case of search responses, + * where a response has multiple messages. + */ + +struct ldapmsg { + ber_int_t lm_msgid; /* the message id */ + ber_tag_t lm_msgtype; /* the message type */ + BerElement *lm_ber; /* the ber encoded message contents */ + struct ldapmsg *lm_chain; /* for search - next msg in the resp */ + struct ldapmsg *lm_next; /* next response */ + time_t lm_time; /* used to maintain cache */ +}; + +/* + * structure representing get/set'able options + * which have global defaults. + */ +struct ldapoptions { + short ldo_valid; +#define LDAP_UNINITIALIZED 0x0 +#define LDAP_INITIALIZED 0x1 +#define LDAP_VALID_SESSION 0x2 + int ldo_debug; +#ifdef LDAP_CONNECTIONLESS +#define LDAP_IS_UDP(ld) ((ld)->ld_options.ldo_is_udp) + void* ldo_peer; /* struct sockaddr* */ + char* ldo_cldapdn; + int ldo_is_udp; +#endif + + /* per API call timeout */ + struct timeval *ldo_tm_api; + struct timeval *ldo_tm_net; + + ber_int_t ldo_version; + ber_int_t ldo_deref; + ber_int_t ldo_timelimit; + ber_int_t ldo_sizelimit; + +#ifdef HAVE_TLS + int ldo_tls_mode; +#endif + + LDAPURLDesc *ldo_defludp; + int ldo_defport; + char* ldo_defbase; + char* ldo_defbinddn; /* bind dn */ + +#ifdef HAVE_CYRUS_SASL + char* ldo_def_sasl_mech; /* SASL Mechanism(s) */ + char* ldo_def_sasl_realm; /* SASL realm */ + char* ldo_def_sasl_authcid; /* SASL authentication identity */ + char* ldo_def_sasl_authzid; /* SASL authorization identity */ + + /* SASL Security Properties */ + struct sasl_security_properties ldo_sasl_secprops; +#endif + + int ldo_refhoplimit; /* limit on referral nesting */ + + /* LDAPv3 server and client controls */ + LDAPControl **ldo_sctrls; + LDAPControl **ldo_cctrls; + + /* LDAP rebind callback function */ + LDAP_REBIND_PROC *ldo_rebind_proc; + void *ldo_rebind_params; + + LDAP_BOOLEANS ldo_booleans; /* boolean options */ +}; + + +/* + * structure for representing an LDAP server connection + */ +typedef struct ldap_conn { + Sockbuf *lconn_sb; +#ifdef HAVE_TLS + /* tls context */ + void *lconn_tls_ctx; +#endif +#ifdef HAVE_CYRUS_SASL + void *lconn_sasl_ctx; +#endif + int lconn_refcnt; + time_t lconn_lastused; /* time */ + int lconn_rebind_inprogress; /* set if rebind in progress */ + char ***lconn_rebind_queue; /* used if rebind in progress */ + int lconn_status; +#define LDAP_CONNST_NEEDSOCKET 1 +#define LDAP_CONNST_CONNECTING 2 +#define LDAP_CONNST_CONNECTED 3 + LDAPURLDesc *lconn_server; +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + char *lconn_krbinstance; +#endif + BerElement *lconn_ber; /* ber receiving on this conn. */ + + struct ldap_conn *lconn_next; +} LDAPConn; + + +/* + * structure used to track outstanding requests + */ +typedef struct ldapreq { + ber_int_t lr_msgid; /* the message id */ + int lr_status; /* status of request */ +#define LDAP_REQST_COMPLETED 0 +#define LDAP_REQST_INPROGRESS 1 +#define LDAP_REQST_CHASINGREFS 2 +#define LDAP_REQST_NOTCONNECTED 3 +#define LDAP_REQST_WRITING 4 + int lr_outrefcnt; /* count of outstanding referrals */ + ber_int_t lr_origid; /* original request's message id */ + int lr_parentcnt; /* count of parent requests */ + ber_tag_t lr_res_msgtype; /* result message type */ + ber_int_t lr_res_errno; /* result LDAP errno */ + char *lr_res_error; /* result error string */ + char *lr_res_matched;/* result matched DN string */ + BerElement *lr_ber; /* ber encoded request contents */ + LDAPConn *lr_conn; /* connection used to send request */ + struct ldapreq *lr_parent; /* request that spawned this referral */ + struct ldapreq *lr_child; /* first child request */ + struct ldapreq *lr_refnext; /* next referral spawned */ + struct ldapreq *lr_prev; /* previous request */ + struct ldapreq *lr_next; /* next request */ +} LDAPRequest; + +/* + * structure for client cache + */ +#define LDAP_CACHE_BUCKETS 31 /* cache hash table size */ +typedef struct ldapcache { + LDAPMessage *lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */ + LDAPMessage *lc_requests; /* unfulfilled reqs */ + long lc_timeout; /* request timeout */ + ber_len_t lc_maxmem; /* memory to use */ + ber_len_t lc_memused; /* memory in use */ + int lc_enabled; /* enabled? */ + unsigned long lc_options; /* options */ +#define LDAP_CACHE_OPT_CACHENOERRS 0x00000001 +#define LDAP_CACHE_OPT_CACHEALLERRS 0x00000002 +} LDAPCache; + +/* + * structure containing referral request info for rebind procedure + */ +typedef struct ldapreqinfo { + ber_len_t ri_msgid; + int ri_request; + char *ri_url; +} LDAPreqinfo; + +/* + * structure representing an ldap connection + */ + +struct ldap { + Sockbuf *ld_sb; /* socket descriptor & buffer */ + + struct ldapoptions ld_options; + +#define ld_valid ld_options.ldo_valid +#define ld_debug ld_options.ldo_debug + +#define ld_deref ld_options.ldo_deref +#define ld_timelimit ld_options.ldo_timelimit +#define ld_sizelimit ld_options.ldo_sizelimit + +#define ld_defbinddn ld_options.ldo_defbinddn +#define ld_defbase ld_options.ldo_defbase +#define ld_defhost ld_options.ldo_defhost +#define ld_defport ld_options.ldo_defport + +#define ld_refhoplimit ld_options.ldo_refhoplimit + +#define ld_sctrls ld_options.ldo_sctrls +#define ld_cctrls ld_options.ldo_cctrls +#define ld_rebind_proc ld_options.ldo_rebind_proc +#define ld_rebind_params ld_options.ldo_rebind_params + +#define ld_version ld_options.ldo_version + + unsigned short ld_lberoptions; + + ber_int_t ld_errno; + char *ld_error; + char *ld_matched; + ber_len_t ld_msgid; + + /* do not mess with these */ + LDAPRequest *ld_requests; /* list of outstanding requests */ + LDAPMessage *ld_responses; /* list of outstanding responses */ + + ber_int_t *ld_abandoned; /* array of abandoned requests */ + + LDAPCache *ld_cache; /* non-null if cache is initialized */ + + /* do not mess with the rest though */ + + LDAPConn *ld_defconn; /* default connection */ + LDAPConn *ld_conns; /* list of server connections */ + void *ld_selectinfo; /* platform specifics for select */ +}; +#define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION ) + +#ifdef LDAP_R_COMPILE +#ifdef HAVE_RES_QUERY +LDAP_V ( ldap_pvt_thread_mutex_t ) ldap_int_resolv_mutex; +#endif + +#ifdef HAVE_CYRUS_SASL +LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_sasl_mutex; +#endif +#endif + +/* + * in init.c + */ + +LDAP_V ( struct ldapoptions ) ldap_int_global_options; + +LDAP_F ( void ) ldap_int_initialize LDAP_P((struct ldapoptions *, int *)); +LDAP_F ( void ) ldap_int_initialize_global_options LDAP_P(( + struct ldapoptions *, int *)); + +/* memory.c */ + /* simple macros to realloc for now */ +#define LDAP_MALLOC(s) (LBER_MALLOC((s))) +#define LDAP_CALLOC(n,s) (LBER_CALLOC((n),(s))) +#define LDAP_REALLOC(p,s) (LBER_REALLOC((p),(s))) +#define LDAP_FREE(p) (LBER_FREE((p))) +#define LDAP_VFREE(v) (LBER_VFREE((void **)(v))) +#define LDAP_STRDUP(s) (LBER_STRDUP((s))) +#define LDAP_STRNDUP(s,l) (LBER_STRNDUP((s),(l))) + +/* + * in error.c + */ +LDAP_F (void) ldap_int_error_init( void ); + +/* + * in unit-int.c + */ +LDAP_F (void) ldap_int_utils_init LDAP_P(( void )); + + +/* + * in print.c + */ +LDAP_F (int) ldap_log_printf LDAP_P((LDAP *ld, int level, const char *fmt, ...)) LDAP_GCCATTR((format(printf, 3, 4))); /* * in cache.c */ -#ifdef NEEDPROTOS -void add_request_to_cache( LDAP *ld, unsigned long msgtype, - BerElement *request ); -void add_result_to_cache( LDAP *ld, LDAPMessage *result ); -int check_cache( LDAP *ld, unsigned long msgtype, BerElement *request ); -#else /* NEEDPROTOS */ -void add_request_to_cache(); -void add_result_to_cache(); -int check_cache(); -#endif /* NEEDPROTOS */ +LDAP_F (void) ldap_add_request_to_cache LDAP_P(( LDAP *ld, ber_tag_t msgtype, + BerElement *request )); +LDAP_F (void) ldap_add_result_to_cache LDAP_P(( LDAP *ld, LDAPMessage *result )); +LDAP_F (int) ldap_check_cache LDAP_P(( LDAP *ld, ber_tag_t msgtype, BerElement *request )); +/* + * in controls.c + */ +LDAP_F (LDAPControl *) ldap_control_dup LDAP_P(( + const LDAPControl *ctrl )); + +LDAP_F (LDAPControl **) ldap_controls_dup LDAP_P(( + LDAPControl *const *ctrls )); + +LDAP_F (int) ldap_int_get_controls LDAP_P(( + BerElement *be, + LDAPControl ***ctrlsp)); + +LDAP_F (int) ldap_int_put_controls LDAP_P(( + LDAP *ld, + LDAPControl *const *ctrls, + BerElement *ber )); + +LDAP_F (int) ldap_int_client_controls LDAP_P(( + LDAP *ld, + LDAPControl **ctrlp )); + +/* + * in dsparse.c + */ +LDAP_F (int) ldap_int_next_line_tokens LDAP_P(( char **bufp, ber_len_t *blenp, char ***toksp )); -#ifdef KERBEROS +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND /* * in kerberos.c */ -#ifdef NEEDPROTOS -char *get_kerberosv4_credentials( LDAP *ld, char *who, char *service, - int *len ); -#else /* NEEDPROTOS */ -char *get_kerberosv4_credentials(); -#endif /* NEEDPROTOS */ +LDAP_F (char *) ldap_get_kerberosv4_credentials LDAP_P(( + LDAP *ld, + LDAP_CONST char *who, + LDAP_CONST char *service, + ber_len_t *len )); -#endif /* KERBEROS */ +#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */ /* * in open.c */ -#ifdef NEEDPROTOS -int open_ldap_connection( LDAP *ld, Sockbuf *sb, char *host, int defport, - char **krbinstancep, int async ); -#else /* NEEDPROTOS */ -int open_ldap_connection(); -#endif /* NEEDPROTOS */ - +LDAP_F (int) ldap_open_defconn( LDAP *ld ); +LDAP_F (int) ldap_int_open_connection( LDAP *ld, + LDAPConn *conn, LDAPURLDesc *srvlist, int async ); /* * in os-ip.c */ -#ifdef NEEDPROTOS -int connect_to_host( Sockbuf *sb, char *host, unsigned long address, int port, +LDAP_V (int) ldap_int_tblsize; +LDAP_F (int) ldap_int_timeval_dup( struct timeval **dest, const struct timeval *tm ); +LDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, + int proto, const char *host, unsigned long address, int port, int async ); -void close_connection( Sockbuf *sb ); -#else /* NEEDPROTOS */ -int connect_to_host(); -void close_connection(); -#endif /* NEEDPROTOS */ - -#ifdef KERBEROS -#ifdef NEEDPROTOS -char *host_connected_to( Sockbuf *sb ); -#else /* NEEDPROTOS */ -char *host_connected_to(); -#endif /* NEEDPROTOS */ -#endif /* KERBEROS */ - -#ifdef LDAP_REFERRALS -#ifdef NEEDPROTOS -int do_ldap_select( LDAP *ld, struct timeval *timeout ); -void *new_select_info( void ); -void free_select_info( void *sip ); -void mark_select_write( LDAP *ld, Sockbuf *sb ); -void mark_select_read( LDAP *ld, Sockbuf *sb ); -void mark_select_clear( LDAP *ld, Sockbuf *sb ); -int is_read_ready( LDAP *ld, Sockbuf *sb ); -int is_write_ready( LDAP *ld, Sockbuf *sb ); -#else /* NEEDPROTOS */ -int do_ldap_select(); -void *new_select_info(); -void free_select_info(); -void mark_select_write(); -void mark_select_read(); -void mark_select_clear(); -int is_read_ready(); -int is_write_ready(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_REFERRALS */ +#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || \ + defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) +LDAP_V (char *) ldap_int_hostname; +LDAP_F (char *) ldap_host_connected_to( Sockbuf *sb ); +#endif + +LDAP_F (void) ldap_int_ip_init( void ); +LDAP_F (int) ldap_int_select( LDAP *ld, struct timeval *timeout ); +LDAP_F (void *) ldap_new_select_info( void ); +LDAP_F (void) ldap_free_select_info( void *sip ); +LDAP_F (void) ldap_mark_select_write( LDAP *ld, Sockbuf *sb ); +LDAP_F (void) ldap_mark_select_read( LDAP *ld, Sockbuf *sb ); +LDAP_F (void) ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ); +LDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb ); +LDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb ); + +/* + * in os-local.c + */ +#ifdef LDAP_PF_LOCAL +LDAP_F (int) ldap_connect_to_path( LDAP *ld, Sockbuf *sb, + const char *path, int async ); +#endif /* LDAP_PF_LOCAL */ /* * in request.c */ -#ifdef NEEDPROTOS -int send_initial_request( LDAP *ld, unsigned long msgtype, - char *dn, BerElement *ber ); -BerElement *alloc_ber_with_options( LDAP *ld ); -void set_ber_options( LDAP *ld, BerElement *ber ); -#else /* NEEDPROTOS */ -int send_initial_request(); -BerElement *alloc_ber_with_options(); -void set_ber_options(); -#endif /* NEEDPROTOS */ - -#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS ) -#ifdef NEEDPROTOS -int send_server_request( LDAP *ld, BerElement *ber, int msgid, - LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc, - int bind ); -LDAPConn *new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb, - int connect, int bind ); -LDAPRequest *find_request_by_msgid( LDAP *ld, int msgid ); -void free_request( LDAP *ld, LDAPRequest *lr ); -void free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ); -void dump_connection( LDAP *ld, LDAPConn *lconns, int all ); -void dump_requests_and_responses( LDAP *ld ); -#else /* NEEDPROTOS */ -int send_server_request(); -LDAPConn *new_connection(); -LDAPRequest *find_request_by_msgid(); -void free_request(); -void free_connection(); -void dump_connection(); -void dump_requests_and_responses(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_REFERRALS || LDAP_DNS */ - -#ifdef LDAP_REFERRALS -#ifdef NEEDPROTOS -int chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ); -int append_referral( LDAP *ld, char **referralsp, char *s ); -#else /* NEEDPROTOS */ -int chase_referrals(); -int append_referral(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_REFERRALS */ +LDAP_F (ber_int_t) ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype, + const char *dn, BerElement *ber ); +LDAP_F (BerElement *) ldap_alloc_ber_with_options( LDAP *ld ); +LDAP_F (void) ldap_set_ber_options( LDAP *ld, BerElement *ber ); +LDAP_F (int) ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc *srvlist, LDAPConn *lc, LDAPreqinfo *bind ); +LDAP_F (LDAPConn *) ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb, int connect, LDAPreqinfo *bind ); +LDAP_F (LDAPRequest *) ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ); +LDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr ); +LDAP_F (void) ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ); +LDAP_F (void) ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ); +LDAP_F (void) ldap_dump_requests_and_responses( LDAP *ld ); +LDAP_F (int) ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, + char **errstrp, int sref, int *hadrefp ); +LDAP_F (int) ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, + char **refs, int sref, char **referralsp, int *hadrefp ); +LDAP_F (int) ldap_append_referral( LDAP *ld, char **referralsp, char *s ); + +/* + * in result.c: + */ +LDAP_F (char *) ldap_int_msgtype2str( ber_tag_t tag ); /* * in search.c */ -#ifdef NEEDPROTOS -BerElement *ldap_build_search_req( LDAP *ld, char *base, int scope, - char *filter, char **attrs, int attrsonly ); -#else /* NEEDPROTOS */ -BerElement *ldap_build_search_req(); -#endif /* NEEDPROTOS */ +LDAP_F (BerElement *) ldap_build_search_req LDAP_P(( + LDAP *ld, + const char *base, + ber_int_t scope, + const char *filter, + char **attrs, + ber_int_t attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + ber_int_t timelimit, + ber_int_t sizelimit )); /* * in unbind.c */ -#ifdef NEEDPROTOS -int ldap_ld_free( LDAP *ld, int close ); -int send_unbind( LDAP *ld, Sockbuf *sb ); -#else /* NEEDPROTOS */ -int ldap_ld_free(); -int send_unbind(); -#endif /* NEEDPROTOS */ +LDAP_F (int) ldap_ld_free LDAP_P(( + LDAP *ld, + int close, + LDAPControl **sctrls, + LDAPControl **cctrls )); +LDAP_F (int) ldap_send_unbind LDAP_P(( + LDAP *ld, + Sockbuf *sb, + LDAPControl **sctrls, + LDAPControl **cctrls )); -#ifdef LDAP_DNS /* - * in getdxbyname.c + * in url.c */ -#ifdef NEEDPROTOS -char **getdxbyname( char *domain ); -#else /* NEEDPROTOS */ -char **getdxbyname(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_DNS */ +LDAP_F (LDAPURLDesc *) ldap_url_dup LDAP_P(( + LDAPURLDesc *ludp )); + +LDAP_F (LDAPURLDesc *) ldap_url_duplist LDAP_P(( + LDAPURLDesc *ludlist )); + +LDAP_F (int) ldap_url_parselist LDAP_P(( + LDAPURLDesc **ludlist, + const char *url )); + +LDAP_F (int) ldap_url_parsehosts LDAP_P(( + LDAPURLDesc **ludlist, + const char *hosts, + int port )); + +LDAP_F (char *) ldap_url_list2hosts LDAP_P(( + LDAPURLDesc *ludlist )); + +LDAP_F (char *) ldap_url_list2urls LDAP_P(( + LDAPURLDesc *ludlist )); + +LDAP_F (void) ldap_free_urllist LDAP_P(( + LDAPURLDesc *ludlist )); + +/* + * in cyrus.c + */ + +LDAP_F (int) ldap_int_sasl_init LDAP_P(( void )); + +LDAP_F (int) ldap_int_sasl_open LDAP_P(( + LDAP *ld, LDAPConn *conn, + const char* host, ber_len_t ssf )); +LDAP_F (int) ldap_int_sasl_close LDAP_P(( LDAP *ld, LDAPConn *conn )); + +LDAP_F (int) ldap_int_sasl_external LDAP_P(( + LDAP *ld, LDAPConn *conn, + const char* authid, ber_len_t ssf )); + +LDAP_F (int) ldap_int_sasl_get_option LDAP_P(( LDAP *ld, + int option, void *arg )); +LDAP_F (int) ldap_int_sasl_set_option LDAP_P(( LDAP *ld, + int option, void *arg )); +LDAP_F (int) ldap_int_sasl_config LDAP_P(( struct ldapoptions *lo, + int option, const char *arg )); + +LDAP_F (int) ldap_int_sasl_bind LDAP_P(( + LDAP *ld, + const char *, + const char *, + LDAPControl **, LDAPControl **, + + /* should be passed in client controls */ + unsigned flags, + LDAP_SASL_INTERACT_PROC *interact, + void *defaults )); + +/* in schema.c */ +LDAP_F (char *) ldap_int_parse_numericoid LDAP_P(( + const char **sp, + int *code, + const int flags )); + +/* + * in tls.c + */ +LDAP_F (int) ldap_int_tls_config LDAP_P(( LDAP *ld, + int option, const char *arg )); + +LDAP_F (int) ldap_int_tls_start LDAP_P(( LDAP *ld, + LDAPConn *conn, LDAPURLDesc *srv )); + +LDAP_END_DECL + +#endif /* _LDAP_INT_H */ diff --git a/libraries/libldap/modify.c b/libraries/libldap/modify.c index 316dde787f7af9c61d80837fb169c542788ada09..cf9f6ed573161c9862ed3c87d4c7f84e4f6a77a5 100644 --- a/libraries/libldap/modify.c +++ b/libraries/libldap/modify.c @@ -1,38 +1,38 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * modify.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ - -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" /* - * ldap_modify - initiate an ldap (and X.500) modify operation. Parameters: + * ldap_modify_ext - initiate an ldap extended modify operation. + * + * Parameters: * * ld LDAP descriptor * dn DN of the object to modify * mods List of modifications to make. This is null-terminated * array of struct ldapmod's, specifying the modifications * to perform. + * sctrls Server Controls + * cctrls Client Controls + * msgidp Message ID pointer * * Example: * LDAPMod *mods[] = { @@ -40,10 +40,15 @@ static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of * { LDAP_MOD_REPLACE, "sn", { "jensen", 0 } }, * 0 * } - * msgid = ldap_modify( ld, dn, mods ); + * rc= ldap_modify_ext( ld, dn, mods, sctrls, cctrls, &msgid ); */ int -ldap_modify( LDAP *ld, char *dn, LDAPMod **mods ) +ldap_modify_ext( LDAP *ld, + LDAP_CONST char *dn, + LDAPMod **mods, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) { BerElement *ber; int i, rc; @@ -66,56 +71,120 @@ ldap_modify( LDAP *ld, char *dn, LDAPMod **mods ) * } */ - Debug( LDAP_DEBUG_TRACE, "ldap_modify\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY, "ldap_modify_ext\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_modify_ext\n", 0, 0, 0 ); +#endif + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + return( LDAP_NO_MEMORY ); } - if ( ber_printf( ber, "{it{s{", ++ld->ld_msgid, LDAP_REQ_MODIFY, dn ) + if ( ber_printf( ber, "{it{s{" /*}}}*/, ++ld->ld_msgid, LDAP_REQ_MODIFY, dn ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); } /* for each modification to be performed... */ for ( i = 0; mods[i] != NULL; i++ ) { if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) { - rc = ber_printf( ber, "{e{s[V]}}", - mods[i]->mod_op & ~LDAP_MOD_BVALUES, + rc = ber_printf( ber, "{e{s[V]N}N}", + (ber_int_t) ( mods[i]->mod_op & ~LDAP_MOD_BVALUES ), mods[i]->mod_type, mods[i]->mod_bvalues ); } else { - rc = ber_printf( ber, "{e{s[v]}}", mods[i]->mod_op, + rc = ber_printf( ber, "{e{s[v]N}N}", + (ber_int_t) mods[i]->mod_op, mods[i]->mod_type, mods[i]->mod_values ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); } } - if ( ber_printf( ber, "}}}" ) == -1 ) { + if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); } /* send the message */ - return( send_initial_request( ld, LDAP_REQ_MODIFY, dn, ber )); + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_MODIFY, dn, ber ); + return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); +} + +/* + * ldap_modify - initiate an ldap modify operation. + * + * Parameters: + * + * ld LDAP descriptor + * dn DN of the object to modify + * mods List of modifications to make. This is null-terminated + * array of struct ldapmod's, specifying the modifications + * to perform. + * + * Example: + * LDAPMod *mods[] = { + * { LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } }, + * { LDAP_MOD_REPLACE, "sn", { "jensen", 0 } }, + * 0 + * } + * msgid = ldap_modify( ld, dn, mods ); + */ +int +ldap_modify( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods ) +{ + int rc, msgid; + +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY, "ldap_modify\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_modify\n", 0, 0, 0 ); +#endif + + rc = ldap_modify_ext( ld, dn, mods, NULL, NULL, &msgid ); + + if ( rc != LDAP_SUCCESS ) + return -1; + + return msgid; } int -ldap_modify_s( LDAP *ld, char *dn, LDAPMod **mods ) +ldap_modify_ext_s( LDAP *ld, LDAP_CONST char *dn, + LDAPMod **mods, LDAPControl **sctrl, LDAPControl **cctrl ) { + int rc; int msgid; LDAPMessage *res; - if ( (msgid = ldap_modify( ld, dn, mods )) == -1 ) - return( ld->ld_errno ); + rc = ldap_modify_ext( ld, dn, mods, sctrl, cctrl, &msgid ); + + if ( rc != LDAP_SUCCESS ) + return( rc ); if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) return( ld->ld_errno ); @@ -123,3 +192,9 @@ ldap_modify_s( LDAP *ld, char *dn, LDAPMod **mods ) return( ldap_result2error( ld, res, 1 ) ); } +int +ldap_modify_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods ) +{ + return ldap_modify_ext_s( ld, dn, mods, NULL, NULL ); +} + diff --git a/libraries/libldap/modrdn.c b/libraries/libldap/modrdn.c index f4624a919a0b222c76baac3a4a4f06082f6ee9c7..5603d6dbeace7ac62affc73537098776b611780e 100644 --- a/libraries/libldap/modrdn.c +++ b/libraries/libldap/modrdn.c @@ -1,96 +1,251 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * modrdn.c */ +/* + * Support for MODIFYDN REQUEST V3 (newSuperior) by: + * + * 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. + */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +/* + * A modify rdn request looks like this: + * ModifyRDNRequest ::= SEQUENCE { + * entry DistinguishedName, + * newrdn RelativeDistinguishedName, + * deleteoldrdn BOOLEAN + * newSuperior [0] DistinguishedName [v3 only] + * } + */ -#include <stdio.h> -#include <string.h> +#include "portable.h" -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ +#include <stdio.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" /* - * ldap_modrdn2 - initiate an ldap (and X.500) modifyRDN operation. Parameters: + * ldap_rename - initiate an ldap extended modifyDN operation. * - * ld LDAP descriptor - * dn DN of the object to modify - * newrdn RDN to give the object + * Parameters: + * ld LDAP descriptor + * dn DN of the object to modify + * newrdn RDN to give the object * deleteoldrdn nonzero means to delete old rdn values from the entry + * newSuperior DN of the new parent if applicable * - * Example: - * msgid = ldap_modrdn( ld, dn, newrdn ); + * Returns the LDAP error code. */ + int -ldap_modrdn2( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn ) +ldap_rename( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *newrdn, + LDAP_CONST char *newSuperior, + int deleteoldrdn, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) { BerElement *ber; + int rc; - /* - * A modify rdn request looks like this: - * ModifyRDNRequest ::= SEQUENCE { - * entry DistinguishedName, - * newrdn RelativeDistinguishedName, - * deleteoldrdn BOOLEAN - * } - */ +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ENTRY, "ldap_rename\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_rename\n", 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "ldap_modrdn\n", 0, 0, 0 ); + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + return( LDAP_NO_MEMORY ); + } + + if( newSuperior != NULL ) { + /* must be version 3 (or greater) */ + if ( ld->ld_version < LDAP_VERSION3 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + ber_free( ber, 1 ); + return( ld->ld_errno ); + } + + rc = ber_printf( ber, "{it{ssbtsN}", /* '}' */ + ++ld->ld_msgid, LDAP_REQ_MODDN, + dn, newrdn, (ber_int_t) deleteoldrdn, + LDAP_TAG_NEWSUPERIOR, newSuperior ); + + } else { + rc = ber_printf( ber, "{it{ssbN}", /* '}' */ + ++ld->ld_msgid, LDAP_REQ_MODDN, + dn, newrdn, (ber_int_t) deleteoldrdn ); } - if ( ber_printf( ber, "{it{ssb}}", ++ld->ld_msgid, LDAP_REQ_MODRDN, dn, - newrdn, deleteoldrdn ) == -1 ) { + if ( rc < 0 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( -1 ); + return( ld->ld_errno ); + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + rc = ber_printf( ber, /*{*/ "N}" ); + if ( rc < 0 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); } /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_MODRDN, dn, ber )); + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_MODRDN, dn, ber ); + + if( *msgidp < 0 ) { + return( ld->ld_errno ); + } + + return LDAP_SUCCESS; +} + + +/* + * ldap_rename2 - initiate an ldap (and X.500) modifyDN operation. Parameters: + * (LDAP V3 MODIFYDN REQUEST) + * ld LDAP descriptor + * dn DN of the object to modify + * newrdn RDN to give the object + * deleteoldrdn nonzero means to delete old rdn values from the entry + * newSuperior DN of the new parent if applicable + * + * ldap_rename2 uses a U-Mich Style API. It returns the msgid. + */ + +int +ldap_rename2( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *newrdn, + LDAP_CONST char *newSuperior, + int deleteoldrdn ) +{ + int msgid; + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ENTRY, "ldap_rename2\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_rename2\n", 0, 0, 0 ); +#endif + + rc = ldap_rename( ld, dn, newrdn, newSuperior, + deleteoldrdn, NULL, NULL, &msgid ); + + return rc == LDAP_SUCCESS ? msgid : -1; +} + + +/* + * ldap_modrdn2 - initiate an ldap modifyRDN operation. Parameters: + * + * ld LDAP descriptor + * dn DN of the object to modify + * newrdn RDN to give the object + * deleteoldrdn nonzero means to delete old rdn values from the entry + * + * Example: + * msgid = ldap_modrdn( ld, dn, newrdn ); + */ +int +ldap_modrdn2( LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *newrdn, + int deleteoldrdn ) +{ + return ldap_rename2( ld, dn, newrdn, NULL, deleteoldrdn ); } int -ldap_modrdn( LDAP *ld, char *dn, char *newrdn ) +ldap_modrdn( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn ) { - return( ldap_modrdn2( ld, dn, newrdn, 1 ) ); + return( ldap_rename2( ld, dn, newrdn, NULL, 1 ) ); } + int -ldap_modrdn2_s( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn ) +ldap_rename_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *newrdn, + LDAP_CONST char *newSuperior, + int deleteoldrdn, + LDAPControl **sctrls, + LDAPControl **cctrls ) { - int msgid; - LDAPMessage *res; + int rc; + int msgid; + LDAPMessage *res; - if ( (msgid = ldap_modrdn2( ld, dn, newrdn, deleteoldrdn )) == -1 ) - return( ld->ld_errno ); + rc = ldap_rename( ld, dn, newrdn, newSuperior, + deleteoldrdn, sctrls, cctrls, &msgid ); - if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) - return( ld->ld_errno ); + if( rc != LDAP_SUCCESS ) { + return rc; + } + + rc = ldap_result( ld, msgid, 1, NULL, &res ); + + if( rc == -1 ) { + return ld->ld_errno; + } + + return ldap_result2error( ld, res, 1 ); +} + +int +ldap_rename2_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *newrdn, + LDAP_CONST char *newSuperior, + int deleteoldrdn ) +{ + return ldap_rename_s( ld, dn, newrdn, newSuperior, + deleteoldrdn, NULL, NULL ); +} - return( ldap_result2error( ld, res, 1 ) ); +int +ldap_modrdn2_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, int deleteoldrdn ) +{ + return ldap_rename_s( ld, dn, newrdn, NULL, deleteoldrdn, NULL, NULL ); } int -ldap_modrdn_s( LDAP *ld, char *dn, char *newrdn ) +ldap_modrdn_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn ) { - return( ldap_modrdn2_s( ld, dn, newrdn, 1 ) ); + return ldap_rename_s( ld, dn, newrdn, NULL, 1, NULL, NULL ); } + diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c index 244dde7317c1008b69688591543c6c012d070444..11a9b413318e67f2a750603c5066acc807613d98 100644 --- a/libraries/libldap/open.c +++ b/libraries/libldap/open.c @@ -54,8 +54,13 @@ ldap_open( LDAP_CONST char *host, int port ) int rc; LDAP *ld; +#ifdef NEW_LOGGING + LDAP_LOG (( "open", LDAP_LEVEL_ARGS, "ldap_open(%s, %d)\n", + host, port )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n", host, port, 0 ); +#endif ld = ldap_init( host, port ); if ( ld == NULL ) { @@ -69,8 +74,13 @@ ldap_open( LDAP_CONST char *host, int port ) ld = NULL; } +#ifdef NEW_LOGGING + LDAP_LOG (( "open", LDAP_LEVEL_RESULTS, "ldap_open: %s\n", + ld == NULL ? "succeeded" : "failed" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_open: %s\n", ld == NULL ? "succeeded" : "failed", 0, 0 ); +#endif return ld; } @@ -96,7 +106,11 @@ ldap_create( LDAP **ldp ) return LDAP_LOCAL_ERROR; } +#ifdef NEW_LOGGING + LDAP_LOG (( "open", LDAP_LEVEL_ENTRY, "ldap_create\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_create\n", 0, 0, 0 ); +#endif if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) { return( LDAP_NO_MEMORY ); @@ -225,7 +239,11 @@ ldap_int_open_connection( int port, proto; long addr; +#ifdef NEW_LOGGING + LDAP_LOG (( "open", LDAP_LEVEL_ENTRY, "ldap_int_open_connection\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 ); +#endif switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) { case LDAP_PROTO_TCP: diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c index de03b7f68b6bb775935a1a7351b0b96315b9d5b9..0084743d8498fe922a32e9aade7835416abbe656 100644 --- a/libraries/libldap/os-ip.c +++ b/libraries/libldap/os-ip.c @@ -152,7 +152,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) #if defined( notyet ) /* && defined( SO_ERROR ) */ { int so_errno; - int dummy = sizeof(so_errno); + socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == AC_SOCKET_ERROR ) { @@ -170,7 +170,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) /* error slippery */ struct sockaddr_in sin; char ch; - int dummy = sizeof(sin); + socklen_t dummy = sizeof(sin); if ( getpeername( s, (struct sockaddr *) &sin, &dummy ) == AC_SOCKET_ERROR ) { @@ -344,7 +344,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, hints.ai_socktype = socktype; snprintf(serv, sizeof serv, "%d", port ); - if ( err = getaddrinfo(host, serv, &hints, &res) ) { + if ( ( err = getaddrinfo(host, serv, &hints, &res) ) ) { osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n", AC_GAI_STRERROR(err), 0, 0); return -1; @@ -681,7 +681,11 @@ ldap_int_select( LDAP *ld, struct timeval *timeout ) { struct selectinfo *sip; +#ifdef NEW_LOGGING + LDAP_LOG (( "os-ip", LDAP_LEVEL_ENTRY, "ldap_int_select\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_int_select\n", 0, 0, 0 ); +#endif if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c new file mode 100644 index 0000000000000000000000000000000000000000..8b3da9f2285d919e42e786f8f973b2b649f404b2 --- /dev/null +++ b/libraries/libldap/os-local.c @@ -0,0 +1,229 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions + * Copyright (c) 1995 Regents of the University of Michigan. + * All rights reserved. + * Copyright (c) 1999 PADL Software Pty Ltd. + * os-ip.c -- platform-specific domain socket code + */ + + +#include "portable.h" + +#ifdef LDAP_PF_LOCAL + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +/* XXX non-portable */ +#include <sys/stat.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif /* HAVE_IO_H */ + +#include "ldap-int.h" +#include "ldap_defaults.h" + +/* int ldap_int_tblsize = 0; */ + +#define oslocal_debug(ld,fmt,arg1,arg2,arg3) \ +do { \ + ldap_log_printf(ld, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \ +} while(0) + +static void +ldap_pvt_set_errno(int err) +{ + errno = err; +} + +static int +ldap_pvt_ndelay_on(LDAP *ld, int fd) +{ + oslocal_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0); + return ber_pvt_socket_set_nonblock( fd, 1 ); +} + +static int +ldap_pvt_ndelay_off(LDAP *ld, int fd) +{ + oslocal_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0); + return ber_pvt_socket_set_nonblock( fd, 0 ); +} + +static ber_socket_t +ldap_pvt_socket(LDAP *ld) +{ + ber_socket_t s = socket(PF_LOCAL, SOCK_STREAM, 0); + oslocal_debug(ld, "ldap_new_socket: %d\n",s,0,0); + return ( s ); +} + +static int +ldap_pvt_close_socket(LDAP *ld, int s) +{ + oslocal_debug(ld, "ldap_close_socket: %d\n",s,0,0); + return tcp_close(s); +} + +#undef TRACE +#define TRACE do { \ + oslocal_debug(ld, \ + "ldap_is_socket_ready: errror on socket %d: errno: %d (%s)\n", \ + s, \ + errno, \ + STRERROR(errno) ); \ +} while( 0 ) + +/* + * check the socket for errors after select returned. + */ +static int +ldap_pvt_is_socket_ready(LDAP *ld, int s) +{ + oslocal_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0); + +#if defined( notyet ) /* && defined( SO_ERROR ) */ +{ + int so_errno; + socklen_t dummy = sizeof(so_errno); + if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) + == AC_SOCKET_ERROR ) + { + return -1; + } + if ( so_errno ) { + ldap_pvt_set_errno(so_errno); + TRACE; + return -1; + } + return 0; +} +#else +{ + /* error slippery */ + struct sockaddr_un sa; + char ch; + socklen_t dummy = sizeof(sa); + if ( getpeername( s, (struct sockaddr *) &sa, &dummy ) + == AC_SOCKET_ERROR ) + { + /* XXX: needs to be replace with ber_stream_read() */ + read(s, &ch, 1); + TRACE; + return -1; + } + return 0; +} +#endif + return -1; +} +#undef TRACE + +static int +ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sa, int async) +{ + struct timeval tv, *opt_tv=NULL; + fd_set wfds, *z=NULL; + + if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) { + tv.tv_usec = opt_tv->tv_usec; + tv.tv_sec = opt_tv->tv_sec; + } + + oslocal_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n", + s, opt_tv ? tv.tv_sec : -1L, async); + + if ( ldap_pvt_ndelay_on(ld, s) == -1 ) + return ( -1 ); + + if ( connect(s, (struct sockaddr *) sa, sizeof(struct sockaddr_un)) + != AC_SOCKET_ERROR ) + { + if ( ldap_pvt_ndelay_off(ld, s) == -1 ) { + return ( -1 ); + } + return ( 0 ); + } + + if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) { + return ( -1 ); + } + +#ifdef notyet + if ( async ) return ( -2 ); +#endif + + FD_ZERO(&wfds); + FD_SET(s, &wfds ); + + if ( select(ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL) + == AC_SOCKET_ERROR ) + { + return ( -1 ); + } + + if ( FD_ISSET(s, &wfds) ) { + if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) + return ( -1 ); + if ( ldap_pvt_ndelay_off(ld, s) == -1 ) + return ( -1 ); + return ( 0 ); + } + oslocal_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0); + ldap_pvt_set_errno( ETIMEDOUT ); + return ( -1 ); +} + +int +ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async) +{ + struct sockaddr_un server; + ber_socket_t s; + int rc; + + oslocal_debug(ld, "ldap_connect_to_path\n",0,0,0); + + s = ldap_pvt_socket( ld ); + if ( s == AC_SOCKET_INVALID ) { + return -1; + } + + if ( path == NULL || path[0] == '\0' ) { + path = LDAPI_SOCK; + } else { + if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) { + ldap_pvt_set_errno( ENAMETOOLONG ); + return -1; + } + } + + oslocal_debug(ld, "ldap_connect_to_path: Trying %s\n", path, 0, 0); + + memset( &server, '\0', sizeof(server) ); + server.sun_family = AF_LOCAL; + strcpy( server.sun_path, path ); + + rc = ldap_pvt_connect(ld, s, &server, async); + + if (rc == 0) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, (void *)&s ); + } else { + ldap_pvt_close_socket(ld, s); + } + return rc; +} +#else +static int dummy; +#endif /* LDAP_PF_LOCAL */ diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index b8b50eac7b33ca173b0515356a474b478a28d902..3c4d2347f7cbe8cbdcdcddf0758843f5e2740f53 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -1,98 +1,65 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. + */ +/*--- + * This notice applies to changes, created by or for Novell, Inc., + * to preexisting works for which notices appear elsewhere in this file. * + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. + * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION + * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT + * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE + * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS + * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC + * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE + * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + *--- + * Modification to OpenLDAP source by Novell, Inc. + * April 2000 sfs Added code to chase V3 referrals * request.c - sending of ldap requests; handling of referrals */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include <time.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#include <time.h> -#include <stdlib.h> -#ifdef PCNFS -#include <tklib.h> -#include <tk_errno.h> -#include <bios.h> -#endif /* PCNFS */ -#ifdef NCSA -#include "externs.h" -#endif /* NCSA */ -#else /* DOS */ -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <errno.h> -#ifdef _AIX -#include <sys/select.h> -#endif /* _AIX */ -#include "portable.h" -#endif /* DOS */ -#endif /* MACOS */ -#ifdef VMS -#include "ucx_select.h" -#endif -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + #include "ldap-int.h" +#include "lber.h" -#ifdef USE_SYSCONF -#include <unistd.h> -#endif /* USE_SYSCONF */ - - -#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS ) -#ifdef NEEDPROTOS -static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any ); -static void use_connection( LDAP *ld, LDAPConn *lc ); -static void free_servers( LDAPServer *srvlist ); -#else /* NEEDPROTOS */ -static LDAPConn *find_connection(); -static void use_connection(); -static void free_servers(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_REFERRALS || LDAP_DNS */ - - -#ifdef LDAP_DNS -#ifdef NEEDPROTOS -static LDAPServer *dn2servers( LDAP *ld, char *dn ); -#else /* NEEDPROTOS */ -static LDAPServer *dn2servers(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_DNS */ - -#ifdef LDAP_REFERRALS -#ifdef NEEDPROTOS -static BerElement *re_encode_request( LDAP *ld, BerElement *origber, - int msgid, char **dnp ); -#else /* NEEDPROTOS */ -static BerElement *re_encode_request(); -#endif /* NEEDPROTOS */ -#endif /* LDAP_REFERRALS */ +static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any )); +static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc )); +static BerElement * +re_encode_request( LDAP *ld, + BerElement *origber, + ber_int_t msgid, + int sref, + LDAPURLDesc *srv, + int *type ); BerElement * -alloc_ber_with_options( LDAP *ld ) +ldap_alloc_ber_with_options( LDAP *ld ) { BerElement *ber; - if (( ber = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) { + if (( ber = ber_alloc_t( ld->ld_lberoptions )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; -#ifdef STR_TRANSLATION - } else { - set_ber_options( ld, ber ); -#endif /* STR_TRANSLATION */ } return( ber ); @@ -100,87 +67,96 @@ alloc_ber_with_options( LDAP *ld ) void -set_ber_options( LDAP *ld, BerElement *ber ) +ldap_set_ber_options( LDAP *ld, BerElement *ber ) { ber->ber_options = ld->ld_lberoptions; -#ifdef STR_TRANSLATION - if (( ld->ld_lberoptions & LBER_TRANSLATE_STRINGS ) != 0 ) { - ber_set_string_translators( ber, - ld->ld_lber_encode_translate_proc, - ld->ld_lber_decode_translate_proc ); - } -#endif /* STR_TRANSLATION */ } -int -send_initial_request( LDAP *ld, unsigned long msgtype, char *dn, +ber_int_t +ldap_send_initial_request( + LDAP *ld, + ber_tag_t msgtype, + const char *dn, BerElement *ber ) { -#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS ) - LDAPServer *servers; -#endif /* LDAP_REFERRALS || LDAP_DNS */ + LDAPURLDesc *servers; + int rc; - Debug( LDAP_DEBUG_TRACE, "send_initial_request\n", 0, 0, 0 ); - -#if !defined( LDAP_REFERRALS ) && !defined( LDAP_DNS ) - if ( ber_flush( &ld->ld_sb, ber, 1 ) != 0 ) { - ld->ld_errno = LDAP_SERVER_DOWN; - return( -1 ); - } +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_send_initial_request\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); +#endif - ld->ld_errno = LDAP_SUCCESS; - return( ld->ld_msgid ); -#else /* !LDAP_REFERRALS && !LDAP_DNS */ + if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { + /* not connected yet */ + int rc = ldap_open_defconn( ld ); -#ifdef LDAP_DNS - if (( ld->ld_options & LDAP_OPT_DNS ) != 0 && ldap_is_dns_dn( dn )) { - if (( servers = dn2servers( ld, dn )) == NULL ) { + if( rc < 0 ) { ber_free( ber, 1 ); return( -1 ); } -#ifdef LDAP_DEBUG - if ( ldap_debug & LDAP_DEBUG_TRACE ) { - LDAPServer *srv; +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_send_initial_request: ldap_open_defconn: successful\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_open_defconn: successful\n", + 0, 0, 0 ); +#endif + } - for ( srv = servers; srv != NULL; - srv = srv->lsrv_next ) { - fprintf( stderr, - "LDAP server %s: dn %s, port %d\n", - srv->lsrv_host, ( srv->lsrv_dn == NULL ) ? - "(default)" : srv->lsrv_dn, - srv->lsrv_port ); - } - } -#endif /* LDAP_DEBUG */ - } else { -#endif /* LDAP_DNS */ + { /* * use of DNS is turned off or this is an X.500 DN... * use our default connection */ servers = NULL; -#ifdef LDAP_DNS } -#endif /* LDAP_DNS */ - return( send_server_request( ld, ber, ld->ld_msgid, NULL, servers, - NULL, 0 )); -#endif /* !LDAP_REFERRALS && !LDAP_DNS */ +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld)) { + if (msgtype == LDAP_REQ_BIND) { + if (ld->ld_options.ldo_cldapdn) + ldap_memfree(ld->ld_options.ldo_cldapdn); + ld->ld_options.ldo_cldapdn = ldap_strdup(dn); + return 0; + } + if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) + return LDAP_PARAM_ERROR; + } +#endif + rc = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, + servers, NULL, NULL ); + if (servers) + ldap_free_urllist(servers); + return(rc); } -#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS ) int -send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest - *parentreq, LDAPServer *srvlist, LDAPConn *lc, int bind ) +ldap_send_server_request( + LDAP *ld, + BerElement *ber, + ber_int_t msgid, + LDAPRequest *parentreq, + LDAPURLDesc *srvlist, + LDAPConn *lc, + LDAPreqinfo *bind ) { LDAPRequest *lr; + int incparent; - Debug( LDAP_DEBUG_TRACE, "send_server_request\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_send_server_request\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 ); +#endif + incparent = 0; ld->ld_errno = LDAP_SUCCESS; /* optimistic */ if ( lc == NULL ) { @@ -189,9 +165,13 @@ send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest } else { if (( lc = find_connection( ld, srvlist, 1 )) == NULL ) { - lc = new_connection( ld, &srvlist, 0, 1, bind ); + if ( (bind != NULL) && (parentreq != NULL) ) { + /* Remember the bind in the parent */ + incparent = 1; + ++parentreq->lr_outrefcnt; + } + lc = ldap_new_connection( ld, srvlist, 0, 1, bind ); } - free_servers( srvlist ); } } @@ -200,15 +180,23 @@ send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_SERVER_DOWN; } + if ( incparent ) { + /* Forget about the bind */ + --parentreq->lr_outrefcnt; + } return( -1 ); } use_connection( ld, lc ); - if (( lr = (LDAPRequest *)calloc( 1, sizeof( LDAPRequest ))) == + if (( lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ))) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; - free_connection( ld, lc, 0, 0 ); + ldap_free_connection( ld, lc, 0, 0 ); ber_free( ber, 1 ); + if ( incparent ) { + /* Forget about the bind */ + --parentreq->lr_outrefcnt; + } return( -1 ); } lr->lr_msgid = msgid; @@ -217,12 +205,15 @@ send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest lr->lr_ber = ber; lr->lr_conn = lc; if ( parentreq != NULL ) { /* sub-request */ - ++parentreq->lr_outrefcnt; + if ( !incparent ) { + /* Increment if we didn't do it before the bind */ + ++parentreq->lr_outrefcnt; + } lr->lr_origid = parentreq->lr_origid; lr->lr_parentcnt = parentreq->lr_parentcnt + 1; lr->lr_parent = parentreq; - lr->lr_refnext = parentreq->lr_refnext; - parentreq->lr_refnext = lr; + lr->lr_refnext = parentreq->lr_child; + parentreq->lr_child = lr; } else { /* original request */ lr->lr_origid = lr->lr_msgid; } @@ -235,17 +226,15 @@ send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest if ( ber_flush( lc->lconn_sb, ber, 0 ) != 0 ) { #ifdef notyet - extern int errno; - if ( errno == EWOULDBLOCK ) { /* need to continue write later */ lr->lr_status = LDAP_REQST_WRITING; - mark_select_write( ld, lc->lconn_sb ); + ldap_mark_select_write( ld, lc->lconn_sb ); } else { #else /* notyet */ ld->ld_errno = LDAP_SERVER_DOWN; - free_request( ld, lr ); - free_connection( ld, lc, 0, 0 ); + ldap_free_request( ld, lr ); + ldap_free_connection( ld, lc, 0, 0 ); return( -1 ); #endif /* notyet */ #ifdef notyet @@ -258,65 +247,58 @@ send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest } /* sent -- waiting for a response */ - mark_select_read( ld, lc->lconn_sb ); + ldap_mark_select_read( ld, lc->lconn_sb ); } ld->ld_errno = LDAP_SUCCESS; return( msgid ); } - LDAPConn * -new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb, - int connect, int bind ) +ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb, + int connect, LDAPreqinfo *bind ) { LDAPConn *lc; - LDAPServer *prevsrv, *srv; - Sockbuf *sb; + LDAPURLDesc *srv; + Sockbuf *sb = NULL; +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_new_connection\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_new_connection\n", 0, 0, 0 ); +#endif /* * make a new LDAP server connection * XXX open connection synchronously for now */ - if (( lc = (LDAPConn *)calloc( 1, sizeof( LDAPConn ))) == NULL || - ( !use_ldsb && ( sb = (Sockbuf *)calloc( 1, sizeof( Sockbuf ))) - == NULL )) { + if (( lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ))) == NULL || + ( !use_ldsb && ( (sb = ber_sockbuf_alloc()) == NULL ))) { if ( lc != NULL ) { - free( (char *)lc ); + LDAP_FREE( (char *)lc ); } ld->ld_errno = LDAP_NO_MEMORY; return( NULL ); } - lc->lconn_sb = ( use_ldsb ) ? &ld->ld_sb : sb; + lc->lconn_sb = ( use_ldsb ) ? ld->ld_sb : sb; if ( connect ) { - prevsrv = NULL; - - for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) { - if ( open_ldap_connection( ld, lc->lconn_sb, - srv->lsrv_host, srv->lsrv_port, - &lc->lconn_krbinstance, 0 ) != -1 ) { + for ( srv = srvlist; srv != NULL; srv = srv->lud_next ) { + if ( ldap_int_open_connection( ld, lc, srv, 0 ) != -1 ) { break; } - prevsrv = srv; } if ( srv == NULL ) { - if ( !use_ldsb ) { - free( (char *)lc->lconn_sb ); - } - free( (char *)lc ); + if ( !use_ldsb ) { + ber_sockbuf_free( lc->lconn_sb ); + } + LDAP_FREE( (char *)lc ); ld->ld_errno = LDAP_SERVER_DOWN; return( NULL ); } - if ( prevsrv == NULL ) { - *srvlistp = srv->lsrv_next; - } else { - prevsrv->lsrv_next = srv->lsrv_next; - } - lc->lconn_server = srv; + lc->lconn_server = ldap_url_dup(srv); } lc->lconn_status = LDAP_CONNST_CONNECTED; @@ -327,72 +309,93 @@ new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb, * XXX for now, we always do a synchronous bind. This will have * to change in the long run... */ - if ( bind ) { - int err, freepasswd, authmethod; - char *binddn, *passwd; + if ( bind != NULL) { + int err = 0; LDAPConn *savedefconn; - freepasswd = err = 0; - - if ( ld->ld_rebindproc == NULL ) { - binddn = passwd = ""; - authmethod = LDAP_AUTH_SIMPLE; - } else { - if (( err = (*ld->ld_rebindproc)( ld, &binddn, &passwd, - &authmethod, 0 )) == LDAP_SUCCESS ) { - freepasswd = 1; + /* Set flag to prevent additional referrals from being processed on this + * connection until the bind has completed + */ + lc->lconn_rebind_inprogress = 1; + /* V3 rebind function */ + if ( ld->ld_rebind_proc != NULL) { + LDAPURLDesc *srvfunc; + if( ( srvfunc = ldap_url_dup( srvlist)) == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + err = -1; } else { - ld->ld_errno = err; + savedefconn = ld->ld_defconn; + ++lc->lconn_refcnt; /* avoid premature free */ + ld->ld_defconn = lc; + +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_new_connection: Call application rebind_proc\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0); +#endif + err = (*ld->ld_rebind_proc)( ld, + bind->ri_url, bind->ri_request, bind->ri_msgid, + ld->ld_rebind_params ); + + ld->ld_defconn = savedefconn; + --lc->lconn_refcnt; + + if( err != 0) { err = -1; + ldap_free_connection( ld, lc, 1, 0 ); + lc = NULL; } + ldap_free_urldesc( srvfunc); } - - - if ( err == 0 ) { + } else { savedefconn = ld->ld_defconn; - ld->ld_defconn = lc; ++lc->lconn_refcnt; /* avoid premature free */ + ld->ld_defconn = lc; - if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != - LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_new_connection: anonymous rebind via ldap_bind_s\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_bind_s\n", 0, 0, 0); +#endif + if ( ldap_bind_s( ld, "", "", LDAP_AUTH_SIMPLE ) != LDAP_SUCCESS ) { err = -1; } - --lc->lconn_refcnt; ld->ld_defconn = savedefconn; - } - - if ( freepasswd ) { - (*ld->ld_rebindproc)( ld, &binddn, &passwd, - &authmethod, 1 ); - } + --lc->lconn_refcnt; if ( err != 0 ) { - free_connection( ld, lc, 1, 0 ); + ldap_free_connection( ld, lc, 1, 0 ); lc = NULL; } } + if( lc != NULL) + lc->lconn_rebind_inprogress = 0; + } return( lc ); } static LDAPConn * -find_connection( LDAP *ld, LDAPServer *srv, int any ) +find_connection( LDAP *ld, LDAPURLDesc *srv, int any ) /* * return an existing connection (if any) to the server srv * if "any" is non-zero, check for any server in the "srv" chain */ { LDAPConn *lc; - LDAPServer *ls; + LDAPURLDesc *ls; for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { - for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) { - if ( lc->lconn_server->lsrv_host != NULL && - ls->lsrv_host != NULL && strcasecmp( - ls->lsrv_host, lc->lconn_server->lsrv_host ) == 0 - && ls->lsrv_port == lc->lconn_server->lsrv_port ) { - return( lc ); + for ( ls = srv; ls != NULL; ls = ls->lud_next ) { + if ( lc->lconn_server->lud_host != NULL && + *lc->lconn_server->lud_host != '\0' && + ls->lud_host != NULL && *ls->lud_host != '\0' && + strcasecmp( ls->lud_host, lc->lconn_server->lud_host ) == 0 + && ls->lud_port == lc->lconn_server->lud_port ) { + return lc; } if ( !any ) { break; @@ -400,7 +403,7 @@ find_connection( LDAP *ld, LDAPServer *srv, int any ) } } - return( NULL ); + return NULL; } @@ -409,28 +412,35 @@ static void use_connection( LDAP *ld, LDAPConn *lc ) { ++lc->lconn_refcnt; - lc->lconn_lastused = time( 0 ); + lc->lconn_lastused = time( NULL ); } void -free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) +ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) { LDAPConn *tmplc, *prevlc; - Debug( LDAP_DEBUG_TRACE, "free_connection\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_free_connection\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_free_connection\n", 0, 0, 0 ); +#endif if ( force || --lc->lconn_refcnt <= 0 ) { if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { - mark_select_clear( ld, lc->lconn_sb ); + ldap_mark_select_clear( ld, lc->lconn_sb ); if ( unbind ) { - send_unbind( ld, lc->lconn_sb ); - } - close_connection( lc->lconn_sb ); - if ( lc->lconn_sb->sb_ber.ber_buf != NULL ) { - free( lc->lconn_sb->sb_ber.ber_buf ); + ldap_send_unbind( ld, lc->lconn_sb, NULL, NULL ); } } + + if( lc->lconn_ber != NULL ) { + ber_free( lc->lconn_ber, 1 ); + } + + ldap_int_sasl_close( ld, lc ); + prevlc = NULL; for ( tmplc = ld->ld_conns; tmplc != NULL; tmplc = tmplc->lconn_next ) { @@ -442,46 +452,83 @@ free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) } break; } + prevlc = tmplc; } - free_servers( lc->lconn_server ); + ldap_free_urllist( lc->lconn_server ); +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND if ( lc->lconn_krbinstance != NULL ) { - free( lc->lconn_krbinstance ); + LDAP_FREE( lc->lconn_krbinstance ); } - if ( lc->lconn_sb != &ld->ld_sb ) { - free( (char *)lc->lconn_sb ); +#endif + if ( lc->lconn_sb != ld->ld_sb ) { + ber_sockbuf_free( lc->lconn_sb ); + } + if( lc->lconn_rebind_queue != NULL) { + int i; + for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++) { + LDAP_VFREE(lc->lconn_rebind_queue[i]); + } + LDAP_FREE( lc->lconn_rebind_queue); } - free( lc ); - Debug( LDAP_DEBUG_TRACE, "free_connection: actually freed\n", + LDAP_FREE( lc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_RESULTS, + "ldap_free_connection: actually freed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: actually freed\n", 0, 0, 0 ); +#endif } else { - lc->lconn_lastused = time( 0 ); - Debug( LDAP_DEBUG_TRACE, "free_connection: refcnt %d\n", + lc->lconn_lastused = time( NULL ); +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_RESULTS, + "ldap_free_connection: refcnt %d\n", lc->lconn_refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n", lc->lconn_refcnt, 0, 0 ); +#endif } } #ifdef LDAP_DEBUG void -dump_connection( LDAP *ld, LDAPConn *lconns, int all ) +ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) { LDAPConn *lc; + char timebuf[32]; fprintf( stderr, "** Connection%s:\n", all ? "s" : "" ); for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) { if ( lc->lconn_server != NULL ) { fprintf( stderr, "* host: %s port: %d%s\n", - ( lc->lconn_server->lsrv_host == NULL ) ? "(null)" - : lc->lconn_server->lsrv_host, - lc->lconn_server->lsrv_port, ( lc->lconn_sb == - &ld->ld_sb ) ? " (default)" : "" ); + ( lc->lconn_server->lud_host == NULL ) ? "(null)" + : lc->lconn_server->lud_host, + lc->lconn_server->lud_port, ( lc->lconn_sb == + ld->ld_sb ) ? " (default)" : "" ); } fprintf( stderr, " refcnt: %d status: %s\n", lc->lconn_refcnt, ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ? "NeedSocket" : ( lc->lconn_status == LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" ); - fprintf( stderr, " last used: %s\n", - ctime( &lc->lconn_lastused )); + fprintf( stderr, " last used: %s", + ldap_pvt_ctime( &lc->lconn_lastused, timebuf )); + if( lc->lconn_rebind_inprogress ) { + fprintf( stderr, " rebind in progress\n"); + if( lc->lconn_rebind_queue != NULL) { + int i = 0; + for( ;lc->lconn_rebind_queue[i] != NULL; i++) { + int j = 0; + for( ;lc->lconn_rebind_queue[i][j] != 0; j++) { + fprintf( stderr, " queue %d entry %d - %s\n", + i, j, lc->lconn_rebind_queue[i][j]); + } + } + } else { + fprintf( stderr, " queue is empty\n"); + } + } + fprintf(stderr, "\n"); if ( !all ) { break; } @@ -490,7 +537,7 @@ dump_connection( LDAP *ld, LDAPConn *lconns, int all ) void -dump_requests_and_responses( LDAP *ld ) +ldap_dump_requests_and_responses( LDAP *ld ) { LDAPRequest *lr; LDAPMessage *lm, *l; @@ -501,53 +548,39 @@ dump_requests_and_responses( LDAP *ld ) } for ( ; lr != NULL; lr = lr->lr_next ) { fprintf( stderr, " * msgid %d, origid %d, status %s\n", - lr->lr_msgid, lr->lr_origid, ( lr->lr_status == - LDAP_REQST_INPROGRESS ) ? "InProgress" : + lr->lr_msgid, lr->lr_origid, + ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" : ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" : ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" : - "Writing" ); + ( lr->lr_status == LDAP_REQST_WRITING) ? "Writing" : + ( lr->lr_status == LDAP_REQST_COMPLETED ? "Request Completed" : "Invalid Status")); fprintf( stderr, " outstanding referrals %d, parent count %d\n", lr->lr_outrefcnt, lr->lr_parentcnt ); } fprintf( stderr, "** Response Queue:\n" ); - if (( lm = ld->ld_responses ) == NULLMSG ) { + if (( lm = ld->ld_responses ) == NULL ) { fprintf( stderr, " Empty\n" ); } - for ( ; lm != NULLMSG; lm = lm->lm_next ) { - fprintf( stderr, " * msgid %d, type %d\n", - lm->lm_msgid, lm->lm_msgtype ); + for ( ; lm != NULL; lm = lm->lm_next ) { + fprintf( stderr, " * msgid %d, type %lu\n", + lm->lm_msgid, (unsigned long) lm->lm_msgtype ); if (( l = lm->lm_chain ) != NULL ) { fprintf( stderr, " chained responses:\n" ); - for ( ; l != NULLMSG; l = l->lm_chain ) { + for ( ; l != NULL; l = l->lm_chain ) { fprintf( stderr, - " * msgid %d, type %d\n", - l->lm_msgid, l->lm_msgtype ); + " * msgid %d, type %lu\n", + l->lm_msgid, + (unsigned long) l->lm_msgtype ); } } } } #endif /* LDAP_DEBUG */ - void -free_request( LDAP *ld, LDAPRequest *lr ) +ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) { - LDAPRequest *tmplr, *nextlr; - - Debug( LDAP_DEBUG_TRACE, "free_request (origid %d, msgid %d)\n", - lr->lr_origid, lr->lr_msgid, 0 ); - - if ( lr->lr_parent != NULL ) { - --lr->lr_parent->lr_outrefcnt; - } else { - /* free all referrals (child requests) */ - for ( tmplr = lr->lr_refnext; tmplr != NULL; tmplr = nextlr ) { - nextlr = tmplr->lr_refnext; - free_request( ld, tmplr ); - } - } - if ( lr->lr_prev == NULL ) { ld->ld_requests = lr->lr_next; } else { @@ -563,54 +596,322 @@ free_request( LDAP *ld, LDAPRequest *lr ) } if ( lr->lr_res_error != NULL ) { - free( lr->lr_res_error ); + LDAP_FREE( lr->lr_res_error ); } if ( lr->lr_res_matched != NULL ) { - free( lr->lr_res_matched ); + LDAP_FREE( lr->lr_res_matched ); } - free( lr ); + LDAP_FREE( lr ); +} + +void +ldap_free_request( LDAP *ld, LDAPRequest *lr ) +{ + LDAPRequest **ttmplr; + +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ARGS, + "ldap_free_request (origid %d, msgid %d)\n", + lr->lr_origid, lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n", + lr->lr_origid, lr->lr_msgid, 0 ); +#endif + + if ( lr->lr_parent != NULL ) { + --lr->lr_parent->lr_outrefcnt; + for ( ttmplr = &lr->lr_parent->lr_child; *ttmplr && *ttmplr != lr; ttmplr = &(*ttmplr)->lr_refnext ); + if ( *ttmplr == lr ) + *ttmplr = lr->lr_refnext; + } else { + /* free all referrals (child requests) */ + while ( lr->lr_child ) + ldap_free_request( ld, lr->lr_child ); + } + ldap_free_request_int( ld, lr ); } -static void -free_servers( LDAPServer *srvlist ) +/* + * Chase v3 referrals + * + * Parameters: + * (IN) ld = LDAP connection handle + * (IN) lr = LDAP Request structure + * (IN) refs = array of pointers to referral strings that we will chase + * The array will be free'd by this function when no longer needed + * (IN) sref != 0 if following search reference + * (OUT) errstrp = Place to return a string of referrals which could not be followed + * (OUT) hadrefp = 1 if sucessfully followed referral + * + * Return value - number of referrals followed + */ +int +ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp ) { - LDAPServer *nextsrv; + char *unfollowed; + int unfollowedcnt = 0; + LDAPRequest *origreq; + LDAPURLDesc *srv = NULL; + BerElement *ber; + char **refarray = NULL; + LDAPConn *lc; + int rc, count, i, j; + LDAPreqinfo rinfo; + + ld->ld_errno = LDAP_SUCCESS; /* optimistic */ + *hadrefp = 0; + +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_chase_v3referrals\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 ); +#endif - while ( srvlist != NULL ) { - nextsrv = srvlist->lsrv_next; - if ( srvlist->lsrv_dn != NULL ) { - free( srvlist->lsrv_dn ); + unfollowed = NULL; + rc = count = 0; + + /* If no referrals in array, return */ + if ( (refs == NULL) || ( (refs)[0] == NULL) ) { + rc = 0; + goto done; } - if ( srvlist->lsrv_host != NULL ) { - free( srvlist->lsrv_host ); + + /* Check for hop limit exceeded */ + if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_chase_v3referrals: more than %d referral hops (dropping)\n", + ld->ld_refhoplimit )); +#else + Debug( LDAP_DEBUG_ANY, + "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 ); +#endif + ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED; + rc = -1; + goto done; } - free( srvlist ); - srvlist = nextsrv; - } -} -#endif /* LDAP_REFERRALS || LDAP_DNS */ + /* find original request */ + for ( origreq = lr; + origreq->lr_parent != NULL; + origreq = origreq->lr_parent ) + { + /* empty */ ; + } + + refarray = refs; + refs = NULL; + /* parse out & follow referrals */ + for( i=0; refarray[i] != NULL; i++) { + /* Parse the referral URL */ + if (( rc = ldap_url_parse_ext( refarray[i], &srv)) != LDAP_SUCCESS) { + ld->ld_errno = rc; + rc = -1; + goto done; + } + + if( srv->lud_crit_exts ) { + /* we do not support any extensions */ + ld->ld_errno = LDAP_NOT_SUPPORTED; + rc = -1; + goto done; + } + + /* treat ldap://hostpart and ldap://hostpart/ the same */ + if ( srv->lud_dn && srv->lud_dn[0] == '\0' ) { + LDAP_FREE( srv->lud_dn ); + srv->lud_dn = NULL; + } + + /* check connection for re-bind in progress */ + if (( lc = find_connection( ld, srv, 1 )) != NULL ) { + if( lc->lconn_rebind_inprogress) { + /* We are already chasing a referral or search reference and a + * bind on that connection is in progress. We must queue + * referrals on that connection, so we don't get a request + * going out before the bind operation completes. This happens + * if two search references come in one behind the other + * for the same server with different contexts. + */ +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_chase_v3referrals: queue referral \"%s\"\n", + refarray[i] )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chase_v3referrals: queue referral \"%s\"\n", + refarray[i], 0, 0); +#endif + if( lc->lconn_rebind_queue == NULL ) { + /* Create a referral list */ + lc->lconn_rebind_queue = + (char ***) LDAP_MALLOC( sizeof(void *) * 2); + + if( lc->lconn_rebind_queue == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + rc = -1; + goto done; + } + + lc->lconn_rebind_queue[0] = refarray; + lc->lconn_rebind_queue[1] = NULL; + refarray = NULL; + + } else { + /* Count how many referral arrays we already have */ + for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { + /* empty */; + } + + /* Add the new referral to the list */ + lc->lconn_rebind_queue = (char ***) LDAP_REALLOC( + lc->lconn_rebind_queue, sizeof(void *) * (j + 2)); + + if( lc->lconn_rebind_queue == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + rc = -1; + goto done; + } + lc->lconn_rebind_queue[j] = refarray; + lc->lconn_rebind_queue[j+1] = NULL; + refarray = NULL; + } + + /* We have queued the referral/reference, now just return */ + rc = 0; + *hadrefp = 1; + count = 1; /* Pretend we already followed referral */ + goto done; + } + } + /* Re-encode the request with the new starting point of the search. + * Note: In the future we also need to replace the filter if one + * was provided with the search reference + */ + + /* For references we don't want old dn if new dn empty */ + if ( sref && srv->lud_dn == NULL ) { + srv->lud_dn = LDAP_STRDUP( "" ); + } + + ber = re_encode_request( ld, origreq->lr_ber, ++ld->ld_msgid, + sref, srv, &rinfo.ri_request ); + + if( ber == NULL ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + rc = -1; + goto done; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_chase_v3referrals: msgid %d, url \"%s\"\n", + lr->lr_msgid, refarray[i] )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chase_v3referral: msgid %d, url \"%s\"\n", + lr->lr_msgid, refarray[i], 0); +#endif + + /* Send the new request to the server - may require a bind */ + rinfo.ri_msgid = origreq->lr_origid; + rinfo.ri_url = refarray[i]; + if ( (rc = ldap_send_server_request( ld, ber, ld->ld_msgid, + origreq, srv, NULL, &rinfo )) < 0 ) { + /* Failure, try next referral in the list */ +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ERR, + "ldap_chase_v3referrals: Unable to chase referral \"%s\" (%s)\n", + refarray[i], ldap_err2string( ld->ld_errno ) )); +#else + Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%s)\n", + refarray[i], ldap_err2string( ld->ld_errno ), 0); +#endif + unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i]); + ldap_free_urllist(srv); + srv = NULL; + } else { + /* Success, no need to try this referral list further */ + rc = 0; + ++count; + *hadrefp = 1; + + /* check if there is a queue of referrals that came in during bind */ + if( lc == NULL) { + if (( lc = find_connection( ld, srv, 1 )) == NULL ) { + ld->ld_errno = LDAP_OPERATIONS_ERROR; + rc = -1; + goto done; + } + } + + if( lc->lconn_rebind_queue != NULL) { + /* Release resources of previous list */ + LDAP_VFREE(refarray); + refarray = NULL; + ldap_free_urllist(srv); + srv = NULL; + + /* Pull entries off end of queue so list always null terminated */ + for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { + ; + } + refarray = lc->lconn_rebind_queue[j-1]; + lc->lconn_rebind_queue[j-1] = NULL; + /* we pulled off last entry from queue, free queue */ + if ( j == 1 ) { + LDAP_FREE( lc->lconn_rebind_queue); + lc->lconn_rebind_queue = NULL; + } + /* restart the loop the with new referral list */ + i = -1; + continue; + } + break; /* referral followed, break out of for loop */ + } + } /* end for loop */ +done: + LDAP_VFREE(refarray); + ldap_free_urllist(srv); + LDAP_FREE( *errstrp ); + + if( rc == 0) { + *errstrp = NULL; + LDAP_FREE( unfollowed ); + return count; + } else { + ld->ld_errno = LDAP_REFERRAL; + *errstrp = unfollowed; + return rc; + } +} -#ifdef LDAP_REFERRALS /* * XXX merging of errors in this routine needs to be improved */ int -chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) +ldap_chase_referrals( LDAP *ld, + LDAPRequest *lr, + char **errstrp, + int sref, + int *hadrefp ) { - int rc, count, len, newdn; -#ifdef LDAP_DNS - int ldapref; -#endif /* LDAP_DNS */ - char *p, *ports, *ref, *tmpref, *refdn, *unfollowed; + int rc, count; + unsigned len; + char *p, *ref, *unfollowed; LDAPRequest *origreq; - LDAPServer *srv; + LDAPURLDesc *srv; BerElement *ber; + LDAPreqinfo rinfo; - Debug( LDAP_DEBUG_TRACE, "chase_referrals\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, "ldap_chase_referrals\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 ); +#endif ld->ld_errno = LDAP_SUCCESS; /* optimistic */ *hadrefp = 0; @@ -621,8 +922,7 @@ chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) len = strlen( *errstrp ); for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) { - if (( *p == 'R' || *p == 'r' ) && strncasecmp( p, - LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) { + if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) { *p = '\0'; p += LDAP_REF_STR_LEN; break; @@ -634,9 +934,15 @@ chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) } if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ENTRY, + "ldap_chase_referrals: more than %d referral hops (dropping)\n", + ld->ld_refhoplimit )); +#else Debug( LDAP_DEBUG_ANY, "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 ); +#endif /* XXX report as error in ld->ld_errno? */ return( 0 ); } @@ -644,7 +950,7 @@ chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) /* find original request */ for ( origreq = lr; origreq->lr_parent != NULL; origreq = origreq->lr_parent ) { - ; + /* empty */; } unfollowed = NULL; @@ -652,98 +958,79 @@ chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) /* parse out & follow referrals */ for ( ref = p; rc == 0 && ref != NULL; ref = p ) { -#ifdef LDAP_DNS - ldapref = 0; -#endif /* LDAP_DNS */ - if (( p = strchr( ref, '\n' )) != NULL ) { *p++ = '\0'; } else { p = NULL; } - len = strlen( ref ); - if ( len > LDAP_LDAP_REF_STR_LEN && strncasecmp( ref, - LDAP_LDAP_REF_STR, LDAP_LDAP_REF_STR_LEN ) == 0 ) { - Debug( LDAP_DEBUG_TRACE, - "chasing LDAP referral: <%s>\n", ref, 0, 0 ); -#ifdef LDAP_DNS - ldapref = 1; -#endif /* LDAP_DNS */ - tmpref = ref + LDAP_LDAP_REF_STR_LEN; -#ifdef LDAP_DNS - } else if ( len > LDAP_DX_REF_STR_LEN && strncasecmp( ref, - LDAP_DX_REF_STR, LDAP_DX_REF_STR_LEN ) == 0 ) { - Debug( LDAP_DEBUG_TRACE, - "chasing DX referral: <%s>\n", ref, 0, 0 ); - tmpref = ref + LDAP_DX_REF_STR_LEN; -#endif /* LDAP_DNS */ - } else { + rc = ldap_url_parse_ext( ref, &srv ); + + if ( rc != LDAP_URL_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_chase_referrals: ignoring unknown referral <%s>\n", + ref )); +#else Debug( LDAP_DEBUG_TRACE, "ignoring unknown referral <%s>\n", ref, 0, 0 ); - rc = append_referral( ld, &unfollowed, ref ); +#endif + rc = ldap_append_referral( ld, &unfollowed, ref ); *hadrefp = 1; continue; } - *hadrefp = 1; - if (( refdn = strchr( tmpref, '/' )) != NULL ) { - *refdn++ = '\0'; - newdn = 1; - } else { - newdn = 0; + if( srv->lud_dn != NULL && srv->lud_dn == '\0' ) { + LDAP_FREE( srv->lud_dn ); + srv->lud_dn = NULL; } - if (( ber = re_encode_request( ld, origreq->lr_ber, - ++ld->ld_msgid, &refdn )) == NULL ) { - return( -1 ); - } +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "ldap_chase_referrals: chasing LDAP referral <%s>\n", ref )); +#else + Debug( LDAP_DEBUG_TRACE, + "chasing LDAP referral: <%s>\n", ref, 0, 0 ); +#endif -#ifdef LDAP_DNS - if ( ldapref ) { -#endif /* LDAP_DNS */ - if (( srv = (LDAPServer *)calloc( 1, - sizeof( LDAPServer ))) == NULL ) { - ber_free( ber, 1 ); - ld->ld_errno = LDAP_NO_MEMORY; - return( -1 ); - } + *hadrefp = 1; - if (( srv->lsrv_host = strdup( tmpref )) == NULL ) { - free( (char *)srv ); - ber_free( ber, 1 ); - ld->ld_errno = LDAP_NO_MEMORY; - return( -1 ); - } + ber = re_encode_request( ld, origreq->lr_ber, + ++ld->ld_msgid, sref, srv, &rinfo.ri_request ); - if (( ports = strchr( srv->lsrv_host, ':' )) != NULL ) { - *ports++ = '\0'; - srv->lsrv_port = atoi( ports ); - } else { - srv->lsrv_port = LDAP_PORT; - } -#ifdef LDAP_DNS - } else { - srv = dn2servers( ld, tmpref ); + if( ber == NULL ) { + return -1 ; } -#endif /* LDAP_DNS */ - if ( srv != NULL && send_server_request( ld, ber, ld->ld_msgid, - lr, srv, NULL, 1 ) >= 0 ) { + /* copy the complete referral for rebind process */ + rinfo.ri_url = LDAP_STRDUP( ref ); + + rinfo.ri_msgid = origreq->lr_origid; + + rc = ldap_send_server_request( ld, ber, ld->ld_msgid, + lr, srv, NULL, &rinfo ); + + LDAP_FREE( rinfo.ri_url ); + + if( rc >= 0 ) { ++count; } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ERR, + "ldap_chase_referrals: Unable to chase referral <%s>\n", + ldap_err2string( ld->ld_errno) )); +#else Debug( LDAP_DEBUG_ANY, "Unable to chase referral (%s)\n", ldap_err2string( ld->ld_errno ), 0, 0 ); - rc = append_referral( ld, &unfollowed, ref ); +#endif + rc = ldap_append_referral( ld, &unfollowed, ref ); } - if ( !newdn && refdn != NULL ) { - free( refdn ); - } + ldap_free_urllist(srv); } - free( *errstrp ); + LDAP_FREE( *errstrp ); *errstrp = unfollowed; return(( rc == 0 ) ? count : rc ); @@ -751,17 +1038,17 @@ chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ) int -append_referral( LDAP *ld, char **referralsp, char *s ) +ldap_append_referral( LDAP *ld, char **referralsp, char *s ) { int first; if ( *referralsp == NULL ) { first = 1; - *referralsp = (char *)malloc( strlen( s ) + LDAP_REF_STR_LEN + *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN + 1 ); } else { first = 0; - *referralsp = (char *)realloc( *referralsp, + *referralsp = (char *)LDAP_REALLOC( *referralsp, strlen( *referralsp ) + strlen( s ) + 2 ); } @@ -783,94 +1070,152 @@ append_referral( LDAP *ld, char **referralsp, char *s ) static BerElement * -re_encode_request( LDAP *ld, BerElement *origber, int msgid, char **dnp ) +re_encode_request( LDAP *ld, + BerElement *origber, + ber_int_t msgid, + int sref, + LDAPURLDesc *srv, + int *type ) { -/* - * XXX this routine knows way too much about how the lber library works! - */ - unsigned long along, tag; - long ver; + /* + * XXX this routine knows way too much about how the lber library works! + */ + ber_int_t along; + ber_tag_t tag; + ber_tag_t rtag; + ber_int_t ver; + ber_int_t scope; int rc; BerElement tmpber, *ber; char *orig_dn; - + char *dn; + +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_ARGS, + "re_encode_request: new msgid %ld, new dn <%s>\n", + (long) msgid, + ( srv == NULL || srv->lud_dn == NULL ) ? "NONE" : srv->lud_dn )); +#else Debug( LDAP_DEBUG_TRACE, - "re_encode_request: new msgid %d, new dn <%s>\n", - msgid, ( *dnp == NULL ) ? "NONE" : *dnp, 0 ); + "re_encode_request: new msgid %ld, new dn <%s>\n", + (long) msgid, + ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 ); +#endif tmpber = *origber; /* - * all LDAP requests are sequences that start with a message id, - * followed by a sequence that is tagged with the operation code + * all LDAP requests are sequences that start with a message id. + * For all except delete, this is followed by a sequence that is + * tagged with the operation code. For delete, the provided DN + * is not wrapped by a sequence. */ - if ( ber_scanf( &tmpber, "{i", &along ) != LDAP_TAG_MSGID || - ( tag = ber_skip_tag( &tmpber, &along )) == LBER_DEFAULT ) { - ld->ld_errno = LDAP_DECODING_ERROR; + rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag ); + + if ( rtag == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } - if (( ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( NULL ); - } + assert( tag != 0); + if ( tag == LDAP_REQ_BIND ) { + /* bind requests have a version number before the DN & other stuff */ + rtag = ber_scanf( &tmpber, "{ia" /*}*/, &ver, &orig_dn ); + + } else if ( tag == LDAP_REQ_DELETE ) { + /* delete requests don't have a DN wrapping sequence */ + rtag = ber_scanf( &tmpber, "a", &orig_dn ); + + } else if ( tag == LDAP_REQ_SEARCH ) { + /* search requests need to be re-scope-ed */ + rtag = ber_scanf( &tmpber, "{ae" /*"}"*/, &orig_dn, &scope ); + + if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) { + /* use the scope provided in reference */ + scope = srv->lud_scope; + + } else if ( sref && scope != LDAP_SCOPE_SUBTREE ) { + /* use scope implied by previous operation */ + /* base -> base */ + /* one -> base */ + /* subtree -> subtree */ + scope = LDAP_SCOPE_BASE; + } - /* bind requests have a version number before the DN & other stuff */ - if ( tag == LDAP_REQ_BIND && ber_get_int( &tmpber, (long *)&ver ) == - LBER_DEFAULT ) { - ld->ld_errno = LDAP_DECODING_ERROR; - ber_free( ber, 1 ); - return( NULL ); + } else { + rtag = ber_scanf( &tmpber, "{a" /*}*/, &orig_dn ); } - /* the rest of the request is the DN followed by other stuff */ - if ( ber_get_stringa( &tmpber, &orig_dn ) == LBER_DEFAULT ) { - ber_free( ber, 1 ); - return( NULL ); + if( rtag == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + return NULL; + } + + if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + return NULL; } - if ( *dnp == NULL ) { - *dnp = orig_dn; + if ( srv->lud_dn == NULL ) { + dn = orig_dn; } else { - free( orig_dn ); + dn = srv->lud_dn; } if ( tag == LDAP_REQ_BIND ) { - rc = ber_printf( ber, "{it{is", msgid, tag, ver, *dnp ); + rc = ber_printf( ber, "{it{is" /*}}*/, msgid, tag, ver, dn ); + } else if ( tag == LDAP_REQ_DELETE ) { + rc = ber_printf( ber, "{itsN}", msgid, tag, dn ); + } else if ( tag == LDAP_REQ_SEARCH ) { + rc = ber_printf( ber, "{it{se" /*}}*/, msgid, tag, dn, scope ); } else { - rc = ber_printf( ber, "{it{s", msgid, tag, *dnp ); + rc = ber_printf( ber, "{it{s" /*}}*/, msgid, tag, dn ); } + LDAP_FREE( orig_dn ); + if ( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( NULL ); + return NULL; } - if ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end - - tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr ) || - ber_printf( ber, "}}" ) == -1 ) { + if ( tag != LDAP_REQ_DELETE && ( + ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0) + != ( tmpber.ber_end - tmpber.ber_ptr ) || + ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) ) + { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( NULL ); + return NULL; } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "request", LDAP_LEVEL_DETAIL1, + "re_encode_request: new request is:\n" )); +#else Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n", 0, 0, 0 ); - ber_dump( ber, 0 ); +#endif + ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 ); } #endif /* LDAP_DEBUG */ - return( ber ); + *type = tag; /* return request type */ + return ber; } LDAPRequest * -find_request_by_msgid( LDAP *ld, int msgid ) +ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) { - LDAPRequest *lr; + LDAPRequest *lr; for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { + if( lr->lr_status == LDAP_REQST_COMPLETED ) { + continue; /* Skip completed requests */ + } if ( msgid == lr->lr_msgid ) { break; } @@ -878,88 +1223,5 @@ find_request_by_msgid( LDAP *ld, int msgid ) return( lr ); } -#endif /* LDAP_REFERRALS */ - - -#ifdef LDAP_DNS -static LDAPServer * -dn2servers( LDAP *ld, char *dn ) /* dn can also be a domain.... */ -{ - char *p, *domain, *host, *server_dn, **dxs; - int i, port; - LDAPServer *srvlist, *prevsrv, *srv; - - if (( domain = strrchr( dn, '@' )) != NULL ) { - ++domain; - } else { - domain = dn; - } - - if (( dxs = getdxbyname( domain )) == NULL ) { - ld->ld_errno = LDAP_NO_MEMORY; - return( NULL ); - } - - srvlist = NULL; - - for ( i = 0; dxs[ i ] != NULL; ++i ) { - port = LDAP_PORT; - server_dn = NULL; - if ( strchr( dxs[ i ], ':' ) == NULL ) { - host = dxs[ i ]; - } else if ( strlen( dxs[ i ] ) >= 7 && - strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) { - host = dxs[ i ] + 7; - if (( p = strchr( host, ':' )) == NULL ) { - p = host; - } else { - *p++ = '\0'; - port = atoi( p ); - } - if (( p = strchr( p, '/' )) != NULL ) { - server_dn = ++p; - if ( *server_dn == '\0' ) { - server_dn = NULL; - } - } - } else { - host = NULL; - } - if ( host != NULL ) { /* found a server we can use */ - if (( srv = (LDAPServer *)calloc( 1, - sizeof( LDAPServer ))) == NULL ) { - free_servers( srvlist ); - srvlist = NULL; - break; /* exit loop & return */ - } - /* add to end of list of servers */ - if ( srvlist == NULL ) { - srvlist = srv; - } else { - prevsrv->lsrv_next = srv; - } - prevsrv = srv; - - /* copy in info. */ - if (( srv->lsrv_host = strdup( host )) == NULL || - ( server_dn != NULL && ( srv->lsrv_dn = - strdup( server_dn )) == NULL )) { - free_servers( srvlist ); - srvlist = NULL; - break; /* exit loop & return */ - } - srv->lsrv_port = port; - } - } - - ldap_value_free( dxs ); - - if ( srvlist == NULL ) { - ld->ld_errno = LDAP_SERVER_DOWN; - } - - return( srvlist ); -} -#endif /* LDAP_DNS */ diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 3f8408df18f7ae7b590de4a83f44a95299fad68c..c99e2a84ff93a43036a1e537d1d7b30116392ca9 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -1,128 +1,167 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. + */ +/*--- + * This notice applies to changes, created by or for Novell, Inc., + * to preexisting works for which notices appear elsewhere in this file. + * + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. + * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION + * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT + * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE + * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS + * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC + * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE + * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + *--- + * Modification to OpenLDAP source by Novell, Inc. + * April 2000 sfs Add code to process V3 referrals and search results * * result.c - wait for an ldap result */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +/* + * LDAPv3 (RFC2251) + * LDAPResult ::= SEQUENCE { + * resultCode ENUMERATED { ... }, + * matchedDN LDAPDN, + * errorMessage LDAPString, + * referral Referral OPTIONAL + * } + * Referral ::= SEQUENCE OF LDAPURL (one or more) + * LDAPURL ::= LDAPString (limited to URL chars) + */ -#include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include <time.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <time.h> -#include "msdos.h" -#ifdef PCNFS -#include <tklib.h> -#include <tk_errno.h> -#include <bios.h> -#endif /* PCNFS */ -#ifdef NCSA -#include "externs.h" -#endif /* NCSA */ -#else /* DOS */ -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/errno.h> -#ifdef _AIX -#include <sys/select.h> -#endif /* _AIX */ #include "portable.h" -#endif /* DOS */ -#endif /* MACOS */ -#ifdef VMS -#include "ucx_select.h" -#endif -#include "lber.h" -#include "ldap.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + #include "ldap-int.h" -#ifdef USE_SYSCONF -#include <unistd.h> -#endif /* USE_SYSCONF */ - -#ifdef NEEDPROTOS -static int ldap_abandoned( LDAP *ld, int msgid ); -static int ldap_mark_abandoned( LDAP *ld, int msgid ); -static int wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout, - LDAPMessage **result ); -#ifdef LDAP_REFERRALS -static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc, - LDAPMessage **result ); -static int build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr ); -static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ); -#else /* LDAP_REFERRALS */ -static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, - LDAPMessage **result ); -#endif /* LDAP_REFERRALS */ -#if defined( CLDAP ) || !defined( LDAP_REFERRALS ) -static int ldap_select1( LDAP *ld, struct timeval *timeout ); -#endif -#else /* NEEDPROTOS */ -static int ldap_abandoned(); -static int ldap_mark_abandoned(); -static int wait4msg(); -static int read1msg(); -#ifdef LDAP_REFERRALS -static int build_result_ber(); -static void merge_error_info(); -#endif /* LDAP_REFERRALS */ -#if defined( CLDAP ) || !defined( LDAP_REFERRALS ) -static int ldap_select1(); -#endif -#endif /* NEEDPROTOS */ - -#if !defined( MACOS ) && !defined( DOS ) -extern int errno; -#endif + +static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); +static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); +static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, + LDAPMessage **result )); +static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid, + int all, Sockbuf *sb, LDAPConn *lc, LDAPMessage **result )); +static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr )); +static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )); +static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all)); /* * ldap_result - wait for an ldap result response to a message from the - * ldap server. If msgid is -1, any message will be accepted, otherwise - * ldap_result will wait for a response with msgid. If all is 0 the - * first message with id msgid will be accepted, otherwise, ldap_result - * will wait for all responses with id msgid and then return a pointer to - * the entire list of messages. This is only useful for search responses, - * which can be of two message types (zero or more entries, followed by an - * ldap result). The type of the first message received is returned. + * ldap server. If msgid is LDAP_RES_ANY (-1), any message will be + * accepted. If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited + * message is accepted. Otherwise ldap_result will wait for a response + * with msgid. If all is LDAP_MSG_ONE (0) the first message with id + * msgid will be accepted, otherwise, ldap_result will wait for all + * responses with id msgid and then return a pointer to the entire list + * of messages. In general, this is only useful for search responses, + * which can be of three message types (zero or more entries, zero or + * search references, followed by an ldap result). An extension to + * LDAPv3 allows partial extended responses to be returned in response + * to any request. The type of the first message received is returned. * When waiting, any messages that have been abandoned are discarded. * * Example: * ldap_result( s, msgid, all, timeout, result ) */ int -ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout, +ldap_result( + LDAP *ld, + int msgid, + int all, + struct timeval *timeout, LDAPMessage **result ) { - LDAPMessage *lm, *lastlm, *nextlm; + LDAPMessage *lm; - /* - * First, look through the list of responses we have received on + assert( ld != NULL ); + assert( result != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "ldap_result msgid %d\n", msgid )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 ); +#endif + + if( ld == NULL ) { + return -1; + } + + if( result == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return -1; + } + + lm = chkResponseList(ld, msgid, all); + + if ( lm == NULL ) { + return( wait4msg( ld, msgid, all, timeout, result ) ); + } + + *result = lm; + ld->ld_errno = LDAP_SUCCESS; + return( lm->lm_msgtype ); +} + +static LDAPMessage * +chkResponseList( + LDAP *ld, + int msgid, + int all) +{ + LDAPMessage *lm, *lastlm, *nextlm; + /* + * Look through the list of responses we have received on * this association and see if the response we're interested in * is there. If it is, return it. If not, call wait4msg() to * wait until it arrives or timeout occurs. */ - Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 ); - - *result = NULLMSG; - lastlm = NULLMSG; - for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, + "ldap_chkResponseList for msgid=%d, all=%d\n", msgid, all )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList for msgid=%d, all=%d\n", + msgid, all, 0 ); +#endif + lastlm = NULL; + for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { nextlm = lm->lm_next; if ( ldap_abandoned( ld, lm->lm_msgid ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "ldap_chkResponseList msg abandoned, msgid %d\n", msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList msg abandoned, msgid %d\n", + msgid, 0, 0 ); +#endif ldap_mark_abandoned( ld, lm->lm_msgid ); - if ( lastlm == NULLMSG ) { + if ( lastlm == NULL ) { + /* Remove first entry in list */ ld->ld_responses = lm->lm_next; } else { lastlm->lm_next = nextlm; @@ -136,63 +175,103 @@ ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout, if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) { LDAPMessage *tmp; - if ( all == 0 - || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT - && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) + if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) { break; + } - for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) { - if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) + for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) { + if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY + && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE + && tmp->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) + { break; + } } - if ( tmp == NULLMSG ) { - return( wait4msg( ld, msgid, all, timeout, - result ) ); + if ( tmp == NULL ) { + lm = NULL; } break; } lastlm = lm; } - if ( lm == NULLMSG ) { - return( wait4msg( ld, msgid, all, timeout, result ) ); - } - if ( lastlm == NULLMSG ) { - ld->ld_responses = (all == 0 && lm->lm_chain != NULLMSG - ? lm->lm_chain : lm->lm_next); + if ( lm != NULL ) { + /* Found an entry, remove it from the list */ + if ( lastlm == NULL ) { + ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL + ? lm->lm_chain : lm->lm_next); + } else { + lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL + ? lm->lm_chain : lm->lm_next); + } + if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) { + lm->lm_chain->lm_next = lm->lm_next; + lm->lm_chain = NULL; + } + lm->lm_next = NULL; + } + +#ifdef LDAP_DEBUG + if( lm == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, + "ldap_chkResponseList returns NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList returns NULL\n", 0, 0, 0); +#endif } else { - lastlm->lm_next = (all == 0 && lm->lm_chain != NULLMSG - ? lm->lm_chain : lm->lm_next); +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, + "ldap_chkResponseList returns msgid %d, type 0x02lu\n", + lm->lm_msgid, (unsigned long) lm->lm_msgtype )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList returns msgid %d, type 0x%02lu\n", + lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0); +#endif } - if ( all == 0 ) - lm->lm_chain = NULLMSG; - lm->lm_next = NULLMSG; - - *result = lm; - ld->ld_errno = LDAP_SUCCESS; - return( lm->lm_msgtype ); +#endif + return lm; } static int -wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout, +wait4msg( + LDAP *ld, + ber_int_t msgid, + int all, + struct timeval *timeout, LDAPMessage **result ) { int rc; struct timeval tv, *tvp; - long start_time, tmp_time; -#ifdef LDAP_REFERRALS + time_t start_time = 0; + time_t tmp_time; LDAPConn *lc, *nextlc; -#endif /* LDAP_REFERRALS */ + + assert( ld != NULL ); + assert( result != NULL ); #ifdef LDAP_DEBUG if ( timeout == NULL ) { - Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n", - 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, + "wait4msg (infinite timeout), msgid %d\n", msgid )); +#else + Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n", + msgid, 0, 0 ); +#endif } else { - Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n", - timeout->tv_sec, timeout->tv_usec, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, + "wait4msg (timeout %ld sec, %ld usec), msgid %d\n", + (long) timeout->tv_sec, (long) timeout->tv_usec, msgid )); +#else + Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n", + (long) timeout->tv_sec, (long) timeout->tv_usec, msgid ); +#endif } #endif /* LDAP_DEBUG */ @@ -201,101 +280,99 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout, } else { tv = *timeout; tvp = &tv; - start_time = (long)time( NULL ); + start_time = time( NULL ); } rc = -2; while ( rc == -2 ) { -#ifndef LDAP_REFERRALS - /* hack attack */ - if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) { - rc = ldap_select1( ld, tvp ); - -#if !defined( MACOS ) && !defined( DOS ) - if ( rc == 0 || ( rc == -1 && (( ld->ld_options & - LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) { +#ifdef LDAP_DEBUG +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, + "wait4msg continue, msgid %d, all %d\n", msgid, all )); #else - if ( rc == -1 || rc == 0 ) { + Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n", + msgid, all, 0 ); #endif - ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : - LDAP_TIMEOUT); - return( rc ); - } - - } - if ( rc == -1 ) { - rc = -2; /* select interrupted: loop */ - } else { - rc = read1msg( ld, msgid, all, &ld->ld_sb, result ); - } -#else /* !LDAP_REFERRALS */ -#ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_TRACE ) { - dump_connection( ld, ld->ld_conns, 1 ); - dump_requests_and_responses( ld ); + ldap_dump_connection( ld, ld->ld_conns, 1 ); + ldap_dump_requests_and_responses( ld ); } #endif /* LDAP_DEBUG */ - for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { - if ( lc->lconn_sb->sb_ber.ber_ptr < - lc->lconn_sb->sb_ber.ber_end ) { - rc = read1msg( ld, msgid, all, lc->lconn_sb, - lc, result ); - break; - } - } - if ( lc == NULL ) { - rc = do_ldap_select( ld, tvp ); + if( (*result = chkResponseList(ld, msgid, all)) != NULL ) { + rc = (*result)->lm_msgtype; + } else { + for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { + if ( ber_sockbuf_ctrl( lc->lconn_sb, + LBER_SB_OPT_DATA_READY, NULL ) ) { + rc = try_read1msg( ld, msgid, all, lc->lconn_sb, + lc, result ); + break; + } + } -#if defined( LDAP_DEBUG ) && !defined( MACOS ) && !defined( DOS ) - if ( rc == -1 ) { - Debug( LDAP_DEBUG_TRACE, - "do_ldap_select returned -1: errno %d\n", - errno, 0, 0 ); - } -#endif + if ( lc == NULL ) { + rc = ldap_int_select( ld, tvp ); -#if !defined( MACOS ) && !defined( DOS ) - if ( rc == 0 || ( rc == -1 && (( ld->ld_options & - LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) { + +#ifdef LDAP_DEBUG + if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, + "wait4msg: ldap_int_select returned -1: errno %d\n", + errno )); #else - if ( rc == -1 || rc == 0 ) { + Debug( LDAP_DEBUG_TRACE, + "ldap_int_select returned -1: errno %d\n", + errno, 0, 0 ); +#endif + } #endif - ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : - LDAP_TIMEOUT); - return( rc ); - } - if ( rc == -1 ) { - rc = -2; /* select interrupted: loop */ - } else { - rc = -2; - for ( lc = ld->ld_conns; rc == -2 && lc != NULL; - lc = nextlc ) { - nextlc = lc->lconn_next; - if ( lc->lconn_status == - LDAP_CONNST_CONNECTED && - is_read_ready( ld, - lc->lconn_sb )) { - rc = read1msg( ld, msgid, all, - lc->lconn_sb, lc, result ); - } - } - } + if ( rc == 0 || ( rc == -1 && ( + !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) + || errno != EINTR ))) + { + ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : + LDAP_TIMEOUT); + return( rc ); + } + + if ( rc == -1 ) { + rc = -2; /* select interrupted: loop */ + } else { + rc = -2; + for ( lc = ld->ld_conns; rc == -2 && lc != NULL; + lc = nextlc ) { + nextlc = lc->lconn_next; + if ( lc->lconn_status == + LDAP_CONNST_CONNECTED && + ldap_is_read_ready( ld, + lc->lconn_sb )) { + rc = try_read1msg( ld, msgid, all, + lc->lconn_sb, lc, result ); + } + } + } + } } -#endif /* !LDAP_REFERRALS */ if ( rc == -2 && tvp != NULL ) { - tmp_time = (long)time( NULL ); + tmp_time = time( NULL ); if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) { rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "wait4msg: %ld secs to go\n", (long) tv.tv_sec )); +#else Debug( LDAP_DEBUG_TRACE, "wait4msg: %ld secs to go\n", - tv.tv_sec, 0, 0 ); + (long) tv.tv_sec, 0, 0 ); +#endif start_time = tmp_time; } } @@ -304,88 +381,290 @@ wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout, } -static int -read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, -#ifdef LDAP_REFERRALS - LDAPConn *lc, -#endif /* LDAP_REFERRALS */ - LDAPMessage **result ) +static ber_tag_t +try_read1msg( + LDAP *ld, + ber_int_t msgid, + int all, + Sockbuf *sb, + LDAPConn *lc, + LDAPMessage **result ) { - BerElement ber; + BerElement *ber; LDAPMessage *new, *l, *prev, *tmp; - long id; - unsigned long tag, len; + ber_int_t id; + ber_tag_t tag; + ber_len_t len; int foundit = 0; -#ifdef LDAP_REFERRALS - LDAPRequest *lr; + LDAPRequest *lr, *tmplr; BerElement tmpber; int rc, refer_cnt, hadref, simple_request; - unsigned long lderr; -#endif /* LDAP_REFERRALS */ + ber_int_t lderr; + /* + * v3ref = flag for V3 referral / search reference + * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application + */ + int v3ref; + + assert( ld != NULL ); + assert( lc != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "read1msg: msgid %d, all %d\n", + msgid, all )); +#else + Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 ); + if ( lc->lconn_ber == NULL ) { + lc->lconn_ber = ldap_alloc_ber_with_options(ld); + + if( lc->lconn_ber == NULL ) { + return -1; + } + } - ber_init( &ber, 0 ); - set_ber_options( ld, &ber ); + ber = lc->lconn_ber; + assert( LBER_VALID (ber) ); /* get the next message */ - if ( (tag = ber_get_next( sb, &len, &ber )) + errno = 0; +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { + struct sockaddr from; + ber_int_sb_read(sb, &from, sizeof(struct sockaddr)); + } +#endif + if ( (tag = ber_get_next( sb, &len, ber )) != LDAP_TAG_MESSAGE ) { - ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN : - LDAP_LOCAL_ERROR); - return( -1 ); + if ( tag == LBER_DEFAULT) { +#ifdef LDAP_DEBUG +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: ber_get_next failed\n" )); +#else + Debug( LDAP_DEBUG_CONNS, + "ber_get_next failed.\n", 0, 0, 0 ); +#endif +#endif +#ifdef EWOULDBLOCK + if (errno==EWOULDBLOCK) return -2; +#endif +#ifdef EAGAIN + if (errno == EAGAIN) return -2; +#endif + ld->ld_errno = LDAP_SERVER_DOWN; + return -1; + } + ld->ld_errno = LDAP_LOCAL_ERROR; + return -1; } + /* + * We read a complete message. + * The connection should no longer need this ber. + */ + lc->lconn_ber = NULL; + /* message id */ - if ( ber_get_int( &ber, &id ) == LBER_ERROR ) { + if ( ber_get_int( ber, &id ) == LBER_ERROR ) { + ber_free( ber, 1 ); ld->ld_errno = LDAP_DECODING_ERROR; return( -1 ); } /* if it's been abandoned, toss it */ - if ( ldap_abandoned( ld, (int)id ) ) { - free( ber.ber_buf ); /* gack! */ + if ( ldap_abandoned( ld, id ) ) { + ber_free( ber, 1 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: abandoned\n" )); +#else + Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0); +#endif return( -2 ); /* continue looking */ } -#ifdef LDAP_REFERRALS - if (( lr = find_request_by_msgid( ld, id )) == NULL ) { + if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: no request for response with msgid %ld (tossing)\n", + (long) id )); +#else Debug( LDAP_DEBUG_ANY, "no request for response with msgid %ld (tossing)\n", - id, 0, 0 ); - free( ber.ber_buf ); /* gack! */ + (long) id, 0, 0 ); +#endif + ber_free( ber, 1 ); return( -2 ); /* continue looking */ } - Debug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n", - ( tag == LDAP_RES_SEARCH_ENTRY ) ? "entry" : "result", id, - lr->lr_origid ); - id = lr->lr_origid; -#endif /* LDAP_REFERRALS */ - +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { + struct berval blank; + ber_scanf(ber, "m{", &blank); + } +#endif /* the message type */ - if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) { + if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; + ber_free( ber, 1 ); return( -1 ); } -#ifdef LDAP_REFERRALS +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: ldap_read: message type %s msgid %ld, original id %ld\n", + ldap_int_msgtype2str( tag ), + (long) lr->lr_msgid, (long) lr->lr_origid )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_read: message type %s msgid %ld, original id %ld\n", + ldap_int_msgtype2str( tag ), + (long) lr->lr_msgid, (long) lr->lr_origid ); +#endif + + id = lr->lr_origid; refer_cnt = 0; hadref = simple_request = 0; rc = -2; /* default is to keep looking (no response found) */ lr->lr_res_msgtype = tag; - if ( tag != LDAP_RES_SEARCH_ENTRY ) { + /* + * This code figures out if we are going to chase a + * referral / search reference, or pass it back to the application + */ + v3ref = 0; /* Assume not a V3 search reference or referral */ + if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) { + BerElement tmpber = *ber; /* struct copy */ + char **refs = NULL; + + if( tag == LDAP_RES_SEARCH_REFERENCE) { + /* This is a V3 search reference */ + /* Assume we do not chase the reference, but pass it to application */ + v3ref = -1; + if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || + (lr->lr_parent != NULL) ) + { + /* Get the referral list */ + if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) { + rc = LDAP_DECODING_ERROR; + } else { + /* Note: refs arrary is freed by ldap_chase_v3referrals */ + refer_cnt = ldap_chase_v3referrals( ld, lr, refs, + 1, &lr->lr_res_error, &hadref ); + if ( refer_cnt > 0 ) { /* sucessfully chased reference */ + /* If haven't got end search, set chasing referrals */ + if( lr->lr_status != LDAP_REQST_COMPLETED) { + lr->lr_status = LDAP_REQST_CHASINGREFS; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: search ref chased," + "mark request chasing refs, id = %d\n", + lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "read1msg: search ref chased, mark request chasing refs, id = %d\n", + lr->lr_msgid, 0, 0); +#endif + } + v3ref = 1; /* We sucessfully chased the reference */ + } + } + } + } else { + /* Check for V3 referral */ + ber_len_t len; + if ( ber_scanf( &tmpber, "{iaa",/*}*/ &lderr, + &lr->lr_res_matched, &lr->lr_res_error ) + != LBER_ERROR ) { + /* Check if V3 referral */ + if( ber_peek_tag( &tmpber, &len) == LDAP_TAG_REFERRAL ) { + /* We have a V3 referral, assume we cannot chase it */ + v3ref = -1; + if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) + || (lr->lr_parent != NULL) ) + { + v3ref = -1; /* Assume referral not chased and return it to app */ + /* Get the referral list */ + if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) { + rc = LDAP_DECODING_ERROR; + lr->lr_status = LDAP_REQST_COMPLETED; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: referral decode error," + "mark request completed, id = %d\n", + lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "read1msg: referral decode error, mark request completed, id = %d\n", + lr->lr_msgid, 0, 0); +#endif + } else { + /* Chase the referral + * Note: refs arrary is freed by ldap_chase_v3referrals + */ + refer_cnt = ldap_chase_v3referrals( ld, lr, refs, + 0, &lr->lr_res_error, &hadref ); + lr->lr_status = LDAP_REQST_COMPLETED; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: referral chased," + "mark request completed, id = %d\n", + lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "read1msg: referral chased, mark request completed, id = %d\n", + lr->lr_msgid, 0, 0); +#endif + if( refer_cnt > 0) { + v3ref = 1; /* Referral successfully chased */ + } + } + } + } + + if( lr->lr_res_matched != NULL ) { + LDAP_FREE( lr->lr_res_matched ); + lr->lr_res_matched = NULL; + } + if( lr->lr_res_error != NULL ) { + LDAP_FREE( lr->lr_res_error ); + lr->lr_res_error = NULL; + } + } + } + } + + /* All results that just return a status, i.e. don't return data + * go through the following code. This code also chases V2 referrals + * and checks if all referrals have been chased. + */ + if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) ) { + /* For a v3 search referral/reference, only come here if already chased it */ if ( ld->ld_version >= LDAP_VERSION2 && - ( lr->lr_parent != NULL || - ( ld->ld_options & LDAP_OPT_REFERRALS ) != 0 )) { - tmpber = ber; /* struct copy */ - if ( ber_scanf( &tmpber, "{iaa}", &lderr, + ( lr->lr_parent != NULL || + LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) ) + { + tmpber = *ber; /* struct copy */ + if ( v3ref == 1 ) { + ; /* V3 search reference or V3 referral sucessfully chased */ + } else if ( ber_scanf( &tmpber, "{iaa}", &lderr, &lr->lr_res_matched, &lr->lr_res_error ) != LBER_ERROR ) { if ( lderr != LDAP_SUCCESS ) { /* referrals are in error string */ - refer_cnt = chase_referrals( ld, lr, - &lr->lr_res_error, &hadref ); + refer_cnt = ldap_chase_referrals( ld, lr, + &lr->lr_res_error, -1, &hadref ); + lr->lr_status = LDAP_REQST_COMPLETED; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: V2 referral chased," + "mark request completed, id = %d\n", + lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "read1msg: V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0); +#endif } /* save errno, message, and matched string */ @@ -398,33 +677,53 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, } else { lr->lr_res_errno = LDAP_PARTIAL_RESULTS; } +#ifdef NEW_LOGGING +LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: new result: res_errno: %d, res_error: <%s>, res_matched: <%s>\n", + lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", + lr->lr_res_matched ? lr->lr_res_matched : "" )); +#else Debug( LDAP_DEBUG_TRACE, "new result: res_errno: %d, res_error: <%s>, res_matched: <%s>\n", lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", lr->lr_res_matched ? lr->lr_res_matched : "" ); +#endif } } +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: %d new referrals\n", refer_cnt )); +#else Debug( LDAP_DEBUG_TRACE, "read1msg: %d new referrals\n", refer_cnt, 0, 0 ); +#endif if ( refer_cnt != 0 ) { /* chasing referrals */ - free( ber.ber_buf ); /* gack! */ - ber.ber_buf = NULL; + ber_free( ber, 1 ); + ber = NULL; if ( refer_cnt < 0 ) { return( -1 ); /* fatal error */ } - lr->lr_status = LDAP_REQST_CHASINGREFS; + lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */ } else { if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { /* request without any referrals */ simple_request = ( hadref ? 0 : 1 ); } else { /* request with referrals or child request */ - free( ber.ber_buf ); /* gack! */ - ber.ber_buf = NULL; + ber_free( ber, 1 ); + ber = NULL; } + lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */ +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: mark request completed, id = %d\n", lr->lr_msgid )); +#else + Debug( LDAP_DEBUG_TRACE, + "read1msg: mark request completed, id = %d\n", lr->lr_msgid, 0, 0); +#endif while ( lr->lr_parent != NULL ) { merge_error_info( ld, lr->lr_parent, lr ); @@ -434,62 +733,79 @@ Debug( LDAP_DEBUG_TRACE, } } - if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { + /* Check if all requests are finished, lr is now parent */ + tmplr = lr; + if (tmplr->lr_status == LDAP_REQST_COMPLETED) { + for(tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) { + if( tmplr->lr_status != LDAP_REQST_COMPLETED) { + break; + } + } + } + + /* This is the parent request if the request has referrals */ + if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) { id = lr->lr_msgid; tag = lr->lr_res_msgtype; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: request %ld done\n", (long) id )); + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: res_errno: %d,res_error: <%s>, res_matched: <%s>\n", + lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", + lr->lr_res_matched ? lr->lr_res_matched : "" )); +#else Debug( LDAP_DEBUG_ANY, "request %ld done\n", - id, 0, 0 ); + (long) id, 0, 0 ); Debug( LDAP_DEBUG_TRACE, "res_errno: %d, res_error: <%s>, res_matched: <%s>\n", lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", lr->lr_res_matched ? lr->lr_res_matched : "" ); +#endif if ( !simple_request ) { - if ( ber.ber_buf != NULL ) { - free( ber.ber_buf ); /* gack! */ - ber.ber_buf = NULL; - } + ber_free( ber, 1 ); + ber = NULL; if ( build_result_ber( ld, &ber, lr ) == LBER_ERROR ) { - ld->ld_errno = LDAP_NO_MEMORY; rc = -1; /* fatal error */ } } - free_request( ld, lr ); + ldap_free_request( ld, lr ); } if ( lc != NULL ) { - free_connection( ld, lc, 0, 1 ); + ldap_free_connection( ld, lc, 0, 1 ); } } } - if ( ber.ber_buf == NULL ) { + if ( ber == NULL ) { return( rc ); } -#endif /* LDAP_REFERRALS */ /* make a new ldap message */ - if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) + if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } new->lm_msgid = (int)id; new->lm_msgtype = tag; - new->lm_ber = ber_dup( &ber ); + new->lm_ber = ber; -#ifndef NO_CACHE +#ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { - add_result_to_cache( ld, new ); + ldap_add_result_to_cache( ld, new ); } -#endif /* NO_CACHE */ +#endif /* LDAP_NOCACHE */ /* is this the one we're looking for? */ if ( msgid == LDAP_RES_ANY || id == msgid ) { - if ( all == 0 + if ( all == LDAP_MSG_ONE || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT - && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) { + && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY + && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) { *result = new; ld->ld_errno = LDAP_SUCCESS; return( tag ); @@ -504,15 +820,15 @@ lr->lr_res_matched ? lr->lr_res_matched : "" ); * search response. */ - prev = NULLMSG; - for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) { + prev = NULL; + for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) { if ( l->lm_msgid == new->lm_msgid ) break; prev = l; } /* not part of an existing search response */ - if ( l == NULLMSG ) { + if ( l == NULL ) { if ( foundit ) { *result = new; ld->ld_errno = LDAP_SUCCESS; @@ -524,57 +840,100 @@ lr->lr_res_matched ? lr->lr_res_matched : "" ); return( -2 ); /* continue looking */ } - Debug( LDAP_DEBUG_TRACE, "adding response id %d type %d:\n", - new->lm_msgid, new->lm_msgtype, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: adding response id %ld type %ld\n", + (long) new->lm_msgid, (long) new->lm_msgtype )); +#else + Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n", + (long) new->lm_msgid, (long) new->lm_msgtype, 0 ); +#endif /* part of a search response - add to end of list of entries */ - for ( tmp = l; tmp->lm_chain != NULLMSG && - tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY; + for ( tmp = l; (tmp->lm_chain != NULL) && + ((tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY) || + (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) || + (tmp->lm_chain->lm_msgtype == LDAP_RES_EXTENDED_PARTIAL )); tmp = tmp->lm_chain ) ; /* NULL */ tmp->lm_chain = new; /* return the whole chain if that's what we were looking for */ if ( foundit ) { - if ( prev == NULLMSG ) + if ( prev == NULL ) ld->ld_responses = l->lm_next; else prev->lm_next = l->lm_next; *result = l; ld->ld_errno = LDAP_SUCCESS; +#ifdef LDAP_WORLD_P16 + /* + * XXX questionable fix; see text for [P16] on + * http://www.critical-angle.com/ldapworld/patch/ + * + * inclusion of this patch causes searchs to hang on + * multiple platforms + */ + return( l->lm_msgtype ); +#else /* LDAP_WORLD_P16 */ return( tag ); +#endif /* !LDAP_WORLD_P16 */ } return( -2 ); /* continue looking */ } -#ifdef LDAP_REFERRALS -static int -build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr ) +static ber_tag_t +build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr ) { - unsigned long len; - long along; + ber_len_t len; + ber_tag_t tag; + ber_int_t along; + BerElement *ber; + + *bp = NULL; + ber = ldap_alloc_ber_with_options( ld ); + + if( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return LBER_ERROR; + } - ber_init( ber, 0 ); - set_ber_options( ld, ber ); if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid, - (long)lr->lr_res_msgtype, lr->lr_res_errno, + lr->lr_res_msgtype, lr->lr_res_errno, lr->lr_res_matched ? lr->lr_res_matched : "", - lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) { + lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) { + + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free(ber, 1); return( LBER_ERROR ); } ber_reset( ber, 1 ); + if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free(ber, 1); return( LBER_ERROR ); } if ( ber_get_int( ber, &along ) == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free(ber, 1); return( LBER_ERROR ); } - return( ber_peek_tag( ber, &len )); + tag = ber_peek_tag( ber, &len ); + + if ( tag == LBER_ERROR ) { + ld->ld_errno = LDAP_DECODING_ERROR; + ber_free(ber, 1); + return( LBER_ERROR ); + } + + *bp = ber; + return tag; } @@ -587,131 +946,79 @@ merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ) if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) { parentr->lr_res_errno = lr->lr_res_errno; if ( lr->lr_res_error != NULL ) { - (void)append_referral( ld, &parentr->lr_res_error, + (void)ldap_append_referral( ld, &parentr->lr_res_error, lr->lr_res_error ); } } else if ( lr->lr_res_errno != LDAP_SUCCESS && parentr->lr_res_errno == LDAP_SUCCESS ) { parentr->lr_res_errno = lr->lr_res_errno; if ( parentr->lr_res_error != NULL ) { - free( parentr->lr_res_error ); + LDAP_FREE( parentr->lr_res_error ); } parentr->lr_res_error = lr->lr_res_error; lr->lr_res_error = NULL; - if ( NAME_ERROR( lr->lr_res_errno )) { + if ( LDAP_NAME_ERROR( lr->lr_res_errno )) { if ( parentr->lr_res_matched != NULL ) { - free( parentr->lr_res_matched ); + LDAP_FREE( parentr->lr_res_matched ); } parentr->lr_res_matched = lr->lr_res_matched; lr->lr_res_matched = NULL; } } +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, + "read1msg: merged parent (id %d) error info: result errno %d, " + "error <%s>, matched <%s>\n", parentr->lr_msgid, + parentr->lr_res_errno, parentr->lr_res_error ? + parentr->lr_res_error : "", parentr->lr_res_matched ? + parentr->lr_res_matched : "" )); +#else Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ", parentr->lr_msgid, 0, 0 ); Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n", parentr->lr_res_errno, parentr->lr_res_error ? parentr->lr_res_error : "", parentr->lr_res_matched ? parentr->lr_res_matched : "" ); +#endif } -#endif /* LDAP_REFERRALS */ - - - -#if defined( CLDAP ) || !defined( LDAP_REFERRALS ) -#if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 ) -static int -ldap_select1( LDAP *ld, struct timeval *timeout ) -{ - fd_set readfds; - static int tblsize; - - if ( tblsize == 0 ) { -#ifdef USE_SYSCONF - tblsize = sysconf( _SC_OPEN_MAX ); -#else /* USE_SYSCONF */ - tblsize = getdtablesize(); -#endif /* USE_SYSCONF */ - } - FD_ZERO( &readfds ); - FD_SET( ld->ld_sb.sb_sd, &readfds ); - return( select( tblsize, &readfds, 0, 0, timeout ) ); -} -#endif /* !MACOS */ - -#ifdef MACOS -static int -ldap_select1( LDAP *ld, struct timeval *timeout ) +int +ldap_msgtype( LDAPMessage *lm ) { - return( tcpselect( ld->ld_sb.sb_sd, timeout )); + assert( lm != NULL ); + return ( lm != NULL ) ? lm->lm_msgtype : -1; } -#endif /* MACOS */ -#if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 ) -static int -ldap_select1( LDAP *ld, struct timeval *timeout ) +int +ldap_msgid( LDAPMessage *lm ) { - fd_set readfds; - int rc; + assert( lm != NULL ); - FD_ZERO( &readfds ); - FD_SET( ld->ld_sb.sb_sd, &readfds ); - - rc = select( 1, &readfds, 0, 0, timeout ); - return( rc == SOCKET_ERROR ? -1 : rc ); + return ( lm != NULL ) ? lm->lm_msgid : -1; } -#endif /* WINSOCK || _WIN32 */ -#ifdef DOS -#ifdef PCNFS -static int -ldap_select1( LDAP *ld, struct timeval *timeout ) +char * ldap_int_msgtype2str( ber_tag_t tag ) { - fd_set readfds; - int res; - - FD_ZERO( &readfds ); - FD_SET( ld->ld_sb.sb_sd, &readfds ); - - res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout ); - if ( res == -1 && errno == EINTR) { - /* We've been CTRL-C'ed at this point. It'd be nice to - carry on but PC-NFS currently won't let us! */ - printf("\n*** CTRL-C ***\n"); - exit(-1); + switch( tag ) { + case LDAP_RES_ADD: return "add"; + case LDAP_RES_BIND: return "bind"; + case LDAP_RES_COMPARE: return "compare"; + case LDAP_RES_DELETE: return "delete"; + case LDAP_RES_EXTENDED: return "extended-result"; + case LDAP_RES_EXTENDED_PARTIAL: return "extended-partial"; + case LDAP_RES_MODIFY: return "modify"; + case LDAP_RES_RENAME: return "rename"; + case LDAP_RES_SEARCH_ENTRY: return "search-entry"; + case LDAP_RES_SEARCH_REFERENCE: return "search-reference"; + case LDAP_RES_SEARCH_RESULT: return "search-result"; } - return( res ); + return "unknown"; } -#endif /* PCNFS */ - -#ifdef NCSA -static int -ldap_select1( LDAP *ld, struct timeval *timeout ) -{ - int rc; - clock_t endtime; - - if ( timeout != NULL ) { - endtime = timeout->tv_sec * CLK_TCK + - timeout->tv_usec * CLK_TCK / 1000000 + clock(); - } - - do { - Stask(); - rc = netqlen( ld->ld_sb.sb_sd ); - } while ( rc <= 0 && ( timeout == NULL || clock() < endtime )); - - return( rc > 0 ? 1 : 0 ); -} -#endif /* NCSA */ -#endif /* DOS */ -#endif /* !LDAP_REFERRALS */ - int ldap_msgfree( LDAPMessage *lm ) @@ -719,13 +1026,17 @@ ldap_msgfree( LDAPMessage *lm ) LDAPMessage *next; int type = 0; +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgfree\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 ); +#endif - for ( ; lm != NULLMSG; lm = next ) { + for ( ; lm != NULL; lm = next ) { next = lm->lm_chain; type = lm->lm_msgtype; ber_free( lm->lm_ber, 1 ); - free( (char *) lm ); + LDAP_FREE( (char *) lm ); } return( type ); @@ -741,19 +1052,25 @@ ldap_msgdelete( LDAP *ld, int msgid ) { LDAPMessage *lm, *prev; + assert( ld != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgdelete\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 ); +#endif - prev = NULLMSG; - for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) { + prev = NULL; + for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) { if ( lm->lm_msgid == msgid ) break; prev = lm; } - if ( lm == NULLMSG ) + if ( lm == NULL ) return( -1 ); - if ( prev == NULLMSG ) + if ( prev == NULL ) ld->ld_responses = lm->lm_next; else prev->lm_next = lm->lm_next; @@ -769,7 +1086,7 @@ ldap_msgdelete( LDAP *ld, int msgid ) * return 1 if message msgid is waiting to be abandoned, 0 otherwise */ static int -ldap_abandoned( LDAP *ld, int msgid ) +ldap_abandoned( LDAP *ld, ber_int_t msgid ) { int i; @@ -785,7 +1102,7 @@ ldap_abandoned( LDAP *ld, int msgid ) static int -ldap_mark_abandoned( LDAP *ld, int msgid ) +ldap_mark_abandoned( LDAP *ld, ber_int_t msgid ) { int i; @@ -805,32 +1122,3 @@ ldap_mark_abandoned( LDAP *ld, int msgid ) return( 0 ); } - - -#ifdef CLDAP -int -cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber ) -{ - int rc; - unsigned long tag, len; - - if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) { - rc = ldap_select1( ld, timeout ); - if ( rc == -1 || rc == 0 ) { - ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : - LDAP_TIMEOUT); - return( rc ); - } - } - - /* get the next message */ - if ( (tag = ber_get_next( &ld->ld_sb, &len, ber )) - != LDAP_TAG_MESSAGE ) { - ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN : - LDAP_LOCAL_ERROR); - return( -1 ); - } - - return( tag ); -} -#endif /* CLDAP */ diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c new file mode 100644 index 0000000000000000000000000000000000000000..93a52472f8e41630b0b8f01847e36cae27f9a7a9 --- /dev/null +++ b/libraries/libldap/sasl.c @@ -0,0 +1,499 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * BindRequest ::= SEQUENCE { + * version INTEGER, + * name DistinguishedName, -- who + * authentication CHOICE { + * simple [0] OCTET STRING -- passwd +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + * krbv42ldap [1] OCTET STRING + * krbv42dsa [2] OCTET STRING +#endif + * sasl [3] SaslCredentials -- LDAPv3 + * } + * } + * + * BindResponse ::= SEQUENCE { + * COMPONENTS OF LDAPResult, + * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 + * } + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/errno.h> + +#include "ldap-int.h" + +/* + * ldap_sasl_bind - bind to the ldap server (and X.500). + * The dn (usually NULL), mechanism, and credentials are provided. + * The message id of the request initiated is provided upon successful + * (LDAP_SUCCESS) return. + * + * Example: + * ldap_sasl_bind( ld, NULL, "mechanism", + * cred, NULL, NULL, &msgid ) + */ + +int +ldap_sasl_bind( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *mechanism, + struct berval *cred, + LDAPControl **sctrls, + LDAPControl **cctrls, + int *msgidp ) +{ + BerElement *ber; + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_ENTRY, "ldap_sasl_bind\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( msgidp != NULL ); + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; + + if( msgidp == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + if( mechanism == LDAP_SASL_SIMPLE ) { + if( dn == NULL && cred != NULL ) { + /* use default binddn */ + dn = ld->ld_defbinddn; + } + + } else if( ld->ld_version < LDAP_VERSION3 ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + + if ( dn == NULL ) { + dn = ""; + } + + /* create a message to send */ + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + assert( LBER_VALID( ber ) ); + + if( mechanism == LDAP_SASL_SIMPLE ) { + /* simple bind */ + rc = ber_printf( ber, "{it{istON}" /*}*/, + ++ld->ld_msgid, LDAP_REQ_BIND, + ld->ld_version, dn, LDAP_AUTH_SIMPLE, + cred ); + + } else if ( cred == NULL || !cred->bv_len ) { + /* SASL bind w/o creditials */ + rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/, + ++ld->ld_msgid, LDAP_REQ_BIND, + ld->ld_version, dn, LDAP_AUTH_SASL, + mechanism ); + + } else { + /* SASL bind w/ creditials */ + rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/, + ++ld->ld_msgid, LDAP_REQ_BIND, + ld->ld_version, dn, LDAP_AUTH_SASL, + mechanism, cred ); + } + + if( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( -1 ); + } + + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return ld->ld_errno; + } + +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { + ldap_flush_cache( ld ); + } +#endif /* !LDAP_NOCACHE */ + + /* send the message */ + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber ); + + if(*msgidp < 0) + return ld->ld_errno; + + return LDAP_SUCCESS; +} + + +int +ldap_sasl_bind_s( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *mechanism, + struct berval *cred, + LDAPControl **sctrls, + LDAPControl **cctrls, + struct berval **servercredp ) +{ + int rc, msgid; + LDAPMessage *result; + struct berval *scredp = NULL; + +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_ENTRY, "ldap_sasl_bind_s\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 ); +#endif + + /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ + if( servercredp != NULL ) { + if (ld->ld_version < LDAP_VERSION3) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + *servercredp = NULL; + } + + rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid ); + + if ( rc != LDAP_SUCCESS ) { + return( rc ); + } + +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld)) { + return( rc ); + } +#endif + + if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) { + return( ld->ld_errno ); /* ldap_result sets ld_errno */ + } + + /* parse the results */ + scredp = NULL; + if( servercredp != NULL ) { + rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 ); + } + + if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { + ldap_msgfree( result ); + return( rc ); + } + + rc = ldap_result2error( ld, result, 1 ); + + if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) { + if( servercredp != NULL ) { + *servercredp = scredp; + scredp = NULL; + } + } + + if ( scredp != NULL ) { + ber_bvfree(scredp); + } + + return rc; +} + + +/* +* Parse BindResponse: +* +* BindResponse ::= [APPLICATION 1] SEQUENCE { +* COMPONENTS OF LDAPResult, +* serverSaslCreds [7] OCTET STRING OPTIONAL } +* +* LDAPResult ::= SEQUENCE { +* resultCode ENUMERATED, +* matchedDN LDAPDN, +* errorMessage LDAPString, +* referral [3] Referral OPTIONAL } +*/ + +int +ldap_parse_sasl_bind_result( + LDAP *ld, + LDAPMessage *res, + struct berval **servercredp, + int freeit ) +{ + ber_int_t errcode; + struct berval* scred; + + ber_tag_t tag; + BerElement *ber; + +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_ENTRY, "ldap_parse_sasl_bind_result\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( res != NULL ); + + if ( ld == NULL || res == NULL ) { + return LDAP_PARAM_ERROR; + } + + if( servercredp != NULL ) { + if( ld->ld_version < LDAP_VERSION2 ) { + return LDAP_NOT_SUPPORTED; + } + *servercredp = NULL; + } + + if( res->lm_msgtype != LDAP_RES_BIND ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + scred = NULL; + + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + ld->ld_error = NULL; + } + if ( ld->ld_matched ) { + LDAP_FREE( ld->ld_matched ); + ld->ld_matched = NULL; + } + + /* parse results */ + + ber = ber_dup( res->lm_ber ); + + if( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + if ( ld->ld_version < LDAP_VERSION2 ) { + tag = ber_scanf( ber, "{ia}", + &errcode, &ld->ld_error ); + + if( tag == LBER_ERROR ) { + ber_free( ber, 0 ); + ld->ld_errno = LDAP_DECODING_ERROR; + return ld->ld_errno; + } + + } else { + ber_len_t len; + + tag = ber_scanf( ber, "{iaa" /*}*/, + &errcode, &ld->ld_matched, &ld->ld_error ); + + if( tag == LBER_ERROR ) { + ber_free( ber, 0 ); + ld->ld_errno = LDAP_DECODING_ERROR; + return ld->ld_errno; + } + + tag = ber_peek_tag(ber, &len); + + if( tag == LDAP_TAG_REFERRAL ) { + /* skip 'em */ + if( ber_scanf( ber, "x" ) == LBER_ERROR ) { + ber_free( ber, 0 ); + ld->ld_errno = LDAP_DECODING_ERROR; + return ld->ld_errno; + } + + tag = ber_peek_tag(ber, &len); + } + + if( tag == LDAP_TAG_SASL_RES_CREDS ) { + if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) { + ber_free( ber, 0 ); + ld->ld_errno = LDAP_DECODING_ERROR; + return ld->ld_errno; + } + } + } + + ber_free( ber, 0 ); + + if ( servercredp != NULL ) { + *servercredp = scred; + + } else if ( scred != NULL ) { + ber_bvfree( scred ); + } + + ld->ld_errno = errcode; + + if ( freeit ) { + ldap_msgfree( res ); + } + + return( ld->ld_errno ); +} + +int +ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist ) +{ + /* we need to query the server for supported mechs anyway */ + LDAPMessage *res, *e; + char *attrs[] = { "supportedSASLMechanisms", NULL }; + char **values, *mechlist; + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_ENTRY, "ldap_pvt_sasl_getmech\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 ); +#endif + + rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, + NULL, attrs, 0, &res ); + + if ( rc != LDAP_SUCCESS ) { + return ld->ld_errno; + } + + e = ldap_first_entry( ld, res ); + if ( e == NULL ) { + ldap_msgfree( res ); + if ( ld->ld_errno == LDAP_SUCCESS ) { + ld->ld_errno = LDAP_NO_SUCH_OBJECT; + } + return ld->ld_errno; + } + + values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); + if ( values == NULL ) { + ldap_msgfree( res ); + ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; + return ld->ld_errno; + } + + mechlist = ldap_charray2str( values, " " ); + if ( mechlist == NULL ) { + LDAP_VFREE( values ); + ldap_msgfree( res ); + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + LDAP_VFREE( values ); + ldap_msgfree( res ); + + *pmechlist = mechlist; + + return LDAP_SUCCESS; +} + +/* + * ldap_sasl_interactive_bind_s - interactive SASL authentication + * + * This routine uses interactive callbacks. + * + * LDAP_SUCCESS is returned upon success, the ldap error code + * otherwise. + */ +int +ldap_sasl_interactive_bind_s( + LDAP *ld, + LDAP_CONST char *dn, /* usually NULL */ + LDAP_CONST char *mechs, + LDAPControl **serverControls, + LDAPControl **clientControls, + unsigned flags, + LDAP_SASL_INTERACT_PROC *interact, + void *defaults ) +{ + int rc; + +#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) + ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex ); +#endif +#ifdef LDAP_CONNECTIONLESS + if( LDAP_IS_UDP(ld) ) { + /* Just force it to simple bind, silly to make the user + * ask all the time. No, we don't ever actually bind, but I'll + * let the final bind handler take care of saving the cdn. + */ + rc = ldap_simple_bind(ld, dn, NULL); + return rc < 0 ? rc : 0; + } else +#endif + if( mechs == NULL || *mechs == '\0' ) { + char *smechs; + + rc = ldap_pvt_sasl_getmechs( ld, &smechs ); + + if( rc != LDAP_SUCCESS ) { + goto done; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_DETAIL1, + "ldap_interactive_sasl_bind_s: server supports: %s\n", smechs )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_interactive_sasl_bind_s: server supports: %s\n", + smechs, 0, 0 ); +#endif + + mechs = smechs; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "sasl", LDAP_LEVEL_DETAIL1, + "ldap_interactive_sasl_bind_s: user selected: %s\n", mechs )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldap_interactive_sasl_bind_s: user selected: %s\n", + mechs, 0, 0 ); +#endif + } + + rc = ldap_int_sasl_bind( ld, dn, mechs, + serverControls, clientControls, + flags, interact, defaults ); + +done: +#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) + ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex ); +#endif + + return rc; +} diff --git a/libraries/libldap/sbind.c b/libraries/libldap/sbind.c index 656c722f155fcbc3e9b119da616154c6c19bea0b..eb8aaed4bd57f564e125b6011efa549c53f713cd 100644 --- a/libraries/libldap/sbind.c +++ b/libraries/libldap/sbind.c @@ -1,28 +1,44 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * sbind.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; +/* + * BindRequest ::= SEQUENCE { + * version INTEGER, + * name DistinguishedName, -- who + * authentication CHOICE { + * simple [0] OCTET STRING -- passwd +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + * krbv42ldap [1] OCTET STRING + * krbv42dsa [2] OCTET STRING #endif + * sasl [3] SaslCredentials -- LDAPv3 + * } + * } + * + * BindResponse ::= SEQUENCE { + * COMPONENTS OF LDAPResult, + * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 + * } + * + */ -#include <stdio.h> -#include <string.h> +#include "portable.h" -#ifdef MACOS -#include "macos.h" -#endif /* MACOS */ +#include <stdio.h> -#if !defined( MACOS ) && !defined( DOS ) -#include <sys/types.h> -#include <sys/socket.h> -#endif +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" @@ -37,50 +53,36 @@ static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of */ int -ldap_simple_bind( LDAP *ld, char *dn, char *passwd ) +ldap_simple_bind( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *passwd ) { - BerElement *ber; - - /* - * The bind request looks like this: - * BindRequest ::= SEQUENCE { - * version INTEGER, - * name DistinguishedName, -- who - * authentication CHOICE { - * simple [0] OCTET STRING -- passwd - * } - * } - * all wrapped up in an LDAPMessage sequence. - */ + int rc; + int msgid; + struct berval cred; +#ifdef NEW_LOGGING + LDAP_LOG (( "sbind", LDAP_LEVEL_ENTRY, "ldap_simple_bind\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_simple_bind\n", 0, 0, 0 ); +#endif - if ( dn == NULL ) - dn = ""; - if ( passwd == NULL ) - passwd = ""; - - /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( -1 ); - } + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); - /* fill it in */ - if ( ber_printf( ber, "{it{ists}}", ++ld->ld_msgid, LDAP_REQ_BIND, - ld->ld_version, dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) { - ld->ld_errno = LDAP_ENCODING_ERROR; - ber_free( ber, 1 ); - return( -1 ); + if ( passwd != NULL ) { + cred.bv_val = (char *) passwd; + cred.bv_len = strlen( passwd ); + } else { + cred.bv_val = ""; + cred.bv_len = 0; } -#ifndef NO_CACHE - if ( ld->ld_cache != NULL ) { - ldap_flush_cache( ld ); - } -#endif /* !NO_CACHE */ + rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, &cred, + NULL, NULL, &msgid ); - /* send the message */ - return( send_initial_request( ld, LDAP_REQ_BIND, dn, ber )); + return rc == LDAP_SUCCESS ? msgid : -1; } /* @@ -95,18 +97,24 @@ ldap_simple_bind( LDAP *ld, char *dn, char *passwd ) */ int -ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd ) +ldap_simple_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd ) { - int msgid; - LDAPMessage *result; + struct berval cred; +#ifdef NEW_LOGGING + LDAP_LOG (( "sbind", LDAP_LEVEL_ENTRY, "ldap_simple_bind_s\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 ); +#endif - if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 ) - return( ld->ld_errno ); - - if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 ) - return( ld->ld_errno ); /* ldap_result sets ld_errno */ + if ( passwd != NULL ) { + cred.bv_val = (char *) passwd; + cred.bv_len = strlen( passwd ); + } else { + cred.bv_val = ""; + cred.bv_len = 0; + } - return( ldap_result2error( ld, result, 1 ) ); + return ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, &cred, + NULL, NULL, NULL ); } diff --git a/libraries/libldap/schema.c b/libraries/libldap/schema.c new file mode 100644 index 0000000000000000000000000000000000000000..4fd83bc4bd182bbd95ba5eb69c4014bca89fd0c4 --- /dev/null +++ b/libraries/libldap/schema.c @@ -0,0 +1,2349 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1999-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * schema.c: parsing routines used by servers and clients to process + * schema definitions + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> + +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +#include <ldap_schema.h> + +static const char * +choose_name( char *names[], const char *fallback ) +{ + return( (names != NULL && names[0] != NULL) ? names[0] : fallback ); +} + +LDAP_CONST char * +ldap_syntax2name( LDAPSyntax * syn ) +{ + return( syn->syn_oid ); +} + +LDAP_CONST char * +ldap_matchingrule2name( LDAPMatchingRule * mr ) +{ + return( choose_name( mr->mr_names, mr->mr_oid ) ); +} + +LDAP_CONST char * +ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru ) +{ + return( choose_name( mru->mru_names, mru->mru_oid ) ); +} + +LDAP_CONST char * +ldap_attributetype2name( LDAPAttributeType * at ) +{ + return( choose_name( at->at_names, at->at_oid ) ); +} + +LDAP_CONST char * +ldap_objectclass2name( LDAPObjectClass * oc ) +{ + return( choose_name( oc->oc_names, oc->oc_oid ) ); +} + + +/* + * When pretty printing the entities we will be appending to a buffer. + * Since checking for overflow, realloc'ing and checking if no error + * is extremely boring, we will use a protection layer that will let + * us blissfully ignore the error until the end. This layer is + * implemented with the help of the next type. + */ + +typedef struct safe_string { + char * val; + ber_len_t size; + ber_len_t pos; + int at_whsp; +} safe_string; + +static safe_string * +new_safe_string(int size) +{ + safe_string * ss; + + ss = LDAP_MALLOC(sizeof(safe_string)); + if ( !ss ) + return(NULL); + + ss->val = LDAP_MALLOC(size); + if ( !ss->val ) { + LDAP_FREE(ss); + return(NULL); + } + + ss->size = size; + ss->pos = 0; + ss->at_whsp = 0; + + return ss; +} + +static void +safe_string_free(safe_string * ss) +{ + if ( !ss ) + return; + LDAP_FREE(ss->val); + LDAP_FREE(ss); +} + +static char * +safe_string_val(safe_string * ss) +{ + ss->val[ss->pos] = '\0'; + return(ss->val); +} + +static char * +safe_strdup(safe_string * ss) +{ + char *ret = LDAP_MALLOC(ss->pos+1); + if (!ret) + return NULL; + AC_MEMCPY(ret, ss->val, ss->pos); + ret[ss->pos] = '\0'; + return ret; +} + +static int +append_to_safe_string(safe_string * ss, char * s) +{ + int l = strlen(s); + char * temp; + + /* + * Some runaway process is trying to append to a string that + * overflowed and we could not extend. + */ + if ( !ss->val ) + return -1; + + /* We always make sure there is at least one position available */ + if ( ss->pos + l >= ss->size-1 ) { + ss->size *= 2; + if ( ss->pos + l >= ss->size-1 ) { + ss->size = ss->pos + l + 1; + } + + temp = LDAP_REALLOC(ss->val, ss->size); + if ( !temp ) { + /* Trouble, out of memory */ + LDAP_FREE(ss->val); + return -1; + } + ss->val = temp; + } + strncpy(&ss->val[ss->pos], s, l); + ss->pos += l; + if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) ) + ss->at_whsp = 1; + else + ss->at_whsp = 0; + + return 0; +} + +static int +print_literal(safe_string *ss, char *s) +{ + return(append_to_safe_string(ss,s)); +} + +static int +print_whsp(safe_string *ss) +{ + if ( ss->at_whsp ) + return(append_to_safe_string(ss,"")); + else + return(append_to_safe_string(ss," ")); +} + +static int +print_numericoid(safe_string *ss, char *s) +{ + if ( s ) + return(append_to_safe_string(ss,s)); + else + return(append_to_safe_string(ss,"")); +} + +/* This one is identical to print_qdescr */ +static int +print_qdstring(safe_string *ss, char *s) +{ + print_whsp(ss); + print_literal(ss,"'"); + append_to_safe_string(ss,s); + print_literal(ss,"'"); + return(print_whsp(ss)); +} + +static int +print_qdescr(safe_string *ss, char *s) +{ + print_whsp(ss); + print_literal(ss,"'"); + append_to_safe_string(ss,s); + print_literal(ss,"'"); + return(print_whsp(ss)); +} + +static int +print_qdescrlist(safe_string *ss, char **sa) +{ + char **sp; + int ret = 0; + + for (sp=sa; *sp; sp++) { + ret = print_qdescr(ss,*sp); + } + /* If the list was empty, we return zero that is potentially + * incorrect, but since we will be still appending things, the + * overflow will be detected later. Maybe FIX. + */ + return(ret); +} + +static int +print_qdescrs(safe_string *ss, char **sa) +{ + /* The only way to represent an empty list is as a qdescrlist + * so, if the list is empty we treat it as a long list. + * Really, this is what the syntax mandates. We should not + * be here if the list was empty, but if it happens, a label + * has already been output and we cannot undo it. + */ + if ( !sa[0] || ( sa[0] && sa[1] ) ) { + print_whsp(ss); + print_literal(ss,"("/*)*/); + print_qdescrlist(ss,sa); + print_literal(ss,/*(*/")"); + return(print_whsp(ss)); + } else { + return(print_qdescr(ss,*sa)); + } +} + +static int +print_woid(safe_string *ss, char *s) +{ + print_whsp(ss); + append_to_safe_string(ss,s); + return print_whsp(ss); +} + +static int +print_oidlist(safe_string *ss, char **sa) +{ + char **sp; + + for (sp=sa; *(sp+1); sp++) { + print_woid(ss,*sp); + print_literal(ss,"$"); + } + return(print_woid(ss,*sp)); +} + +static int +print_oids(safe_string *ss, char **sa) +{ + if ( sa[0] && sa[1] ) { + print_literal(ss,"("/*)*/); + print_oidlist(ss,sa); + print_whsp(ss); + return(print_literal(ss,/*(*/")")); + } else { + return(print_woid(ss,*sa)); + } +} + +static int +print_noidlen(safe_string *ss, char *s, int l) +{ + char buf[64]; + int ret; + + ret = print_numericoid(ss,s); + if ( l ) { + sprintf(buf,"{%d}",l); + ret = print_literal(ss,buf); + } + return(ret); +} + +static int +print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions) +{ + LDAPSchemaExtensionItem **ext; + + if ( extensions ) { + print_whsp(ss); + for ( ext = extensions; *ext != NULL; ext++ ) { + print_literal(ss, (*ext)->lsei_name); + print_whsp(ss); + /* Should be print_qdstrings */ + print_qdescrs(ss, (*ext)->lsei_values); + print_whsp(ss); + } + } + + return 0; +} + +char * +ldap_syntax2str( LDAPSyntax * syn ) +{ + struct berval bv; + if (ldap_syntax2bv( syn, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, syn->syn_oid); + print_whsp(ss); + + if ( syn->syn_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,syn->syn_desc); + } + + print_whsp(ss); + + print_extensions(ss, syn->syn_extensions); + + print_literal(ss,/*(*/ ")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_matchingrule2str( LDAPMatchingRule * mr ) +{ + struct berval bv; + if (ldap_matchingrule2bv( mr, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"(" /*)*/); + print_whsp(ss); + + print_numericoid(ss, mr->mr_oid); + print_whsp(ss); + + if ( mr->mr_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,mr->mr_names); + } + + if ( mr->mr_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,mr->mr_desc); + } + + if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( mr->mr_syntax_oid ) { + print_literal(ss,"SYNTAX"); + print_whsp(ss); + print_literal(ss, mr->mr_syntax_oid); + print_whsp(ss); + } + + print_whsp(ss); + + print_extensions(ss, mr->mr_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru ) +{ + struct berval bv; + if (ldap_matchingruleuse2bv( mru, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"(" /*)*/); + print_whsp(ss); + + print_numericoid(ss, mru->mru_oid); + print_whsp(ss); + + if ( mru->mru_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,mru->mru_names); + } + + if ( mru->mru_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,mru->mru_desc); + } + + if ( mru->mru_obsolete == LDAP_SCHEMA_YES ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( mru->mru_applies_oids ) { + print_literal(ss,"APPLIES"); + print_whsp(ss); + print_oids(ss, mru->mru_applies_oids); + print_whsp(ss); + } + + print_whsp(ss); + + print_extensions(ss, mru->mru_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_objectclass2str( LDAPObjectClass * oc ) +{ + struct berval bv; + if (ldap_objectclass2bv( oc, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, oc->oc_oid); + print_whsp(ss); + + if ( oc->oc_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,oc->oc_names); + } + + if ( oc->oc_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,oc->oc_desc); + } + + if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( oc->oc_sup_oids ) { + print_literal(ss,"SUP"); + print_whsp(ss); + print_oids(ss,oc->oc_sup_oids); + print_whsp(ss); + } + + switch (oc->oc_kind) { + case LDAP_SCHEMA_ABSTRACT: + print_literal(ss,"ABSTRACT"); + break; + case LDAP_SCHEMA_STRUCTURAL: + print_literal(ss,"STRUCTURAL"); + break; + case LDAP_SCHEMA_AUXILIARY: + print_literal(ss,"AUXILIARY"); + break; + default: + print_literal(ss,"KIND-UNKNOWN"); + break; + } + print_whsp(ss); + + if ( oc->oc_at_oids_must ) { + print_literal(ss,"MUST"); + print_whsp(ss); + print_oids(ss,oc->oc_at_oids_must); + print_whsp(ss); + } + + if ( oc->oc_at_oids_may ) { + print_literal(ss,"MAY"); + print_whsp(ss); + print_oids(ss,oc->oc_at_oids_may); + print_whsp(ss); + } + + print_whsp(ss); + + print_extensions(ss, oc->oc_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_attributetype2str( LDAPAttributeType * at ) +{ + struct berval bv; + if (ldap_attributetype2bv( at, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, at->at_oid); + print_whsp(ss); + + if ( at->at_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,at->at_names); + } + + if ( at->at_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,at->at_desc); + } + + if ( at->at_obsolete == LDAP_SCHEMA_YES ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( at->at_sup_oid ) { + print_literal(ss,"SUP"); + print_woid(ss,at->at_sup_oid); + } + + if ( at->at_equality_oid ) { + print_literal(ss,"EQUALITY"); + print_woid(ss,at->at_equality_oid); + } + + if ( at->at_ordering_oid ) { + print_literal(ss,"ORDERING"); + print_woid(ss,at->at_ordering_oid); + } + + if ( at->at_substr_oid ) { + print_literal(ss,"SUBSTR"); + print_woid(ss,at->at_substr_oid); + } + + if ( at->at_syntax_oid ) { + print_literal(ss,"SYNTAX"); + print_whsp(ss); + print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len); + print_whsp(ss); + } + + if ( at->at_single_value == LDAP_SCHEMA_YES ) { + print_literal(ss,"SINGLE-VALUE"); + print_whsp(ss); + } + + if ( at->at_collective == LDAP_SCHEMA_YES ) { + print_literal(ss,"COLLECTIVE"); + print_whsp(ss); + } + + if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) { + print_literal(ss,"NO-USER-MODIFICATION"); + print_whsp(ss); + } + + if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) { + print_literal(ss,"USAGE"); + print_whsp(ss); + switch (at->at_usage) { + case LDAP_SCHEMA_DIRECTORY_OPERATION: + print_literal(ss,"directoryOperation"); + break; + case LDAP_SCHEMA_DISTRIBUTED_OPERATION: + print_literal(ss,"distributedOperation"); + break; + case LDAP_SCHEMA_DSA_OPERATION: + print_literal(ss,"dSAOperation"); + break; + default: + print_literal(ss,"UNKNOWN"); + break; + } + } + + print_whsp(ss); + + print_extensions(ss, at->at_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +/* + * Now come the parsers. There is one parser for each entity type: + * objectclasses, attributetypes, etc. + * + * Each of them is written as a recursive-descent parser, except that + * none of them is really recursive. But the idea is kept: there + * is one routine per non-terminal that eithers gobbles lexical tokens + * or calls lower-level routines, etc. + * + * The scanner is implemented in the routine get_token. Actually, + * get_token is more than a scanner and will return tokens that are + * in fact non-terminals in the grammar. So you can see the whole + * approach as the combination of a low-level bottom-up recognizer + * combined with a scanner and a number of top-down parsers. Or just + * consider that the real grammars recognized by the parsers are not + * those of the standards. As a matter of fact, our parsers are more + * liberal than the spec when there is no ambiguity. + * + * The difference is pretty academic (modulo bugs or incorrect + * interpretation of the specs). + */ + +#define TK_NOENDQUOTE -2 +#define TK_OUTOFMEM -1 +#define TK_EOS 0 +#define TK_UNEXPCHAR 1 +#define TK_BAREWORD 2 +#define TK_QDSTRING 3 +#define TK_LEFTPAREN 4 +#define TK_RIGHTPAREN 5 +#define TK_DOLLAR 6 +#define TK_QDESCR TK_QDSTRING + +struct token { + int type; + char *sval; +}; + +static int +get_token( const char ** sp, char ** token_val ) +{ + int kind; + const char * p; + const char * q; + char * res; + + *token_val = NULL; + switch (**sp) { + case '\0': + kind = TK_EOS; + (*sp)++; + break; + case '(': + kind = TK_LEFTPAREN; + (*sp)++; + break; + case ')': + kind = TK_RIGHTPAREN; + (*sp)++; + break; + case '$': + kind = TK_DOLLAR; + (*sp)++; + break; + case '\'': + kind = TK_QDSTRING; + (*sp)++; + p = *sp; + while ( **sp != '\'' && **sp != '\0' ) + (*sp)++; + if ( **sp == '\'' ) { + q = *sp; + res = LDAP_MALLOC(q-p+1); + if ( !res ) { + kind = TK_OUTOFMEM; + } else { + strncpy(res,p,q-p); + res[q-p] = '\0'; + *token_val = res; + } + (*sp)++; + } else { + kind = TK_NOENDQUOTE; + } + break; + default: + kind = TK_BAREWORD; + p = *sp; + while ( !LDAP_SPACE(**sp) && + **sp != '(' && + **sp != ')' && + **sp != '$' && + **sp != '\'' && + **sp != '\0' ) + (*sp)++; + q = *sp; + res = LDAP_MALLOC(q-p+1); + if ( !res ) { + kind = TK_OUTOFMEM; + } else { + strncpy(res,p,q-p); + res[q-p] = '\0'; + *token_val = res; + } + break; +/* kind = TK_UNEXPCHAR; */ +/* break; */ + } + + return kind; +} + +/* Gobble optional whitespace */ +static void +parse_whsp(const char **sp) +{ + while (LDAP_SPACE(**sp)) + (*sp)++; +} + +/* TBC:!! + * General note for all parsers: to guarantee the algorithm halts they + * must always advance the pointer even when an error is found. For + * this one is not that important since an error here is fatal at the + * upper layers, but it is a simple strategy that will not get in + * endless loops. + */ + +/* Parse a sequence of dot-separated decimal strings */ +char * +ldap_int_parse_numericoid(const char **sp, int *code, const int flags) +{ + char * res = NULL; + const char * start = *sp; + int len; + int quoted = 0; + + /* Netscape puts the SYNTAX value in quotes (incorrectly) */ + if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) { + quoted = 1; + (*sp)++; + start++; + } + /* Each iteration of this loop gets one decimal string */ + while (**sp) { + if ( !LDAP_DIGIT(**sp) ) { + /* + * Initial char is not a digit or char after dot is + * not a digit + */ + *code = LDAP_SCHERR_NODIGIT; + return NULL; + } + (*sp)++; + while ( LDAP_DIGIT(**sp) ) + (*sp)++; + if ( **sp != '.' ) + break; + /* Otherwise, gobble the dot and loop again */ + (*sp)++; + } + /* Now *sp points at the char past the numericoid. Perfect. */ + len = *sp - start; + if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) { + if ( **sp == '\'' ) { + (*sp)++; + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + return NULL; + } + } + if (flags & LDAP_SCHEMA_SKIP) { + res = (char *)start; + } else { + res = LDAP_MALLOC(len+1); + if (!res) { + *code = LDAP_SCHERR_OUTOFMEM; + return(NULL); + } + strncpy(res,start,len); + res[len] = '\0'; + } + return(res); +} + +/* Parse a qdescr or a list of them enclosed in () */ +static char ** +parse_qdescrs(const char **sp, int *code) +{ + char ** res; + char ** res1; + int kind; + char * sval; + int size; + int pos; + + parse_whsp(sp); + kind = get_token(sp,&sval); + if ( kind == TK_LEFTPAREN ) { + /* Let's presume there will be at least 2 entries */ + size = 3; + res = LDAP_CALLOC(3,sizeof(char *)); + if ( !res ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + pos = 0; + while (1) { + parse_whsp(sp); + kind = get_token(sp,&sval); + if ( kind == TK_RIGHTPAREN ) + break; + if ( kind == TK_QDESCR ) { + if ( pos == size-2 ) { + size++; + res1 = LDAP_REALLOC(res,size*sizeof(char *)); + if ( !res1 ) { + LDAP_VFREE(res); + LDAP_FREE(sval); + *code = LDAP_SCHERR_OUTOFMEM; + return(NULL); + } + res = res1; + } + res[pos] = sval; + pos++; + parse_whsp(sp); + } else { + LDAP_VFREE(res); + LDAP_FREE(sval); + *code = LDAP_SCHERR_UNEXPTOKEN; + return(NULL); + } + } + res[pos] = NULL; + parse_whsp(sp); + return(res); + } else if ( kind == TK_QDESCR ) { + res = LDAP_CALLOC(2,sizeof(char *)); + if ( !res ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + res[0] = sval; + res[1] = NULL; + parse_whsp(sp); + return res; + } else { + LDAP_FREE(sval); + *code = LDAP_SCHERR_BADNAME; + return NULL; + } +} + +/* Parse a woid */ +static char * +parse_woid(const char **sp, int *code) +{ + char * sval; + int kind; + + parse_whsp(sp); + kind = get_token(sp, &sval); + if ( kind != TK_BAREWORD ) { + LDAP_FREE(sval); + *code = LDAP_SCHERR_UNEXPTOKEN; + return NULL; + } + parse_whsp(sp); + return sval; +} + +/* Parse a noidlen */ +static char * +parse_noidlen(const char **sp, int *code, int *len, int allow_quoted) +{ + char * sval; + int quoted = 0; + + *len = 0; + /* Netscape puts the SYNTAX value in quotes (incorrectly) */ + if ( allow_quoted && **sp == '\'' ) { + quoted = 1; + (*sp)++; + } + sval = ldap_int_parse_numericoid(sp, code, 0); + if ( !sval ) { + return NULL; + } + if ( **sp == '{' /*}*/ ) { + (*sp)++; + *len = atoi(*sp); + while ( LDAP_DIGIT(**sp) ) + (*sp)++; + if ( **sp != /*{*/ '}' ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); + return NULL; + } + (*sp)++; + } + if ( allow_quoted && quoted ) { + if ( **sp == '\'' ) { + (*sp)++; + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); + return NULL; + } + } + return sval; +} + +/* + * Next routine will accept a qdstring in place of an oid if + * allow_quoted is set. This is necessary to interoperate with + * Netscape Directory server that will improperly quote each oid (at + * least those of the descr kind) in the SUP clause. + */ + +/* Parse a woid or a $-separated list of them enclosed in () */ +static char ** +parse_oids(const char **sp, int *code, const int allow_quoted) +{ + char ** res; + char ** res1; + int kind; + char * sval; + int size; + int pos; + + /* + * Strictly speaking, doing this here accepts whsp before the + * ( at the begining of an oidlist, but this is harmless. Also, + * we are very liberal in what we accept as an OID. Maybe + * refine later. + */ + parse_whsp(sp); + kind = get_token(sp,&sval); + if ( kind == TK_LEFTPAREN ) { + /* Let's presume there will be at least 2 entries */ + size = 3; + res = LDAP_CALLOC(3,sizeof(char *)); + if ( !res ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + pos = 0; + parse_whsp(sp); + kind = get_token(sp,&sval); + if ( kind == TK_BAREWORD || + ( allow_quoted && kind == TK_QDSTRING ) ) { + res[pos] = sval; + pos++; + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); + LDAP_VFREE(res); + return NULL; + } + parse_whsp(sp); + while (1) { + kind = get_token(sp,&sval); + if ( kind == TK_RIGHTPAREN ) + break; + if ( kind == TK_DOLLAR ) { + parse_whsp(sp); + kind = get_token(sp,&sval); + if ( kind == TK_BAREWORD || + ( allow_quoted && + kind == TK_QDSTRING ) ) { + if ( pos == size-2 ) { + size++; + res1 = LDAP_REALLOC(res,size*sizeof(char *)); + if ( !res1 ) { + LDAP_FREE(sval); + LDAP_VFREE(res); + *code = LDAP_SCHERR_OUTOFMEM; + return(NULL); + } + res = res1; + } + res[pos] = sval; + pos++; + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); + LDAP_VFREE(res); + return NULL; + } + parse_whsp(sp); + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); + LDAP_VFREE(res); + return NULL; + } + } + res[pos] = NULL; + parse_whsp(sp); + return(res); + } else if ( kind == TK_BAREWORD || + ( allow_quoted && kind == TK_QDSTRING ) ) { + res = LDAP_CALLOC(2,sizeof(char *)); + if ( !res ) { + LDAP_FREE(sval); + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + res[0] = sval; + res[1] = NULL; + parse_whsp(sp); + return res; + } else { + LDAP_FREE(sval); + *code = LDAP_SCHERR_BADNAME; + return NULL; + } +} + +static int +add_extension(LDAPSchemaExtensionItem ***extensions, + char * name, char ** values) +{ + int n; + LDAPSchemaExtensionItem **tmp, *ext; + + ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem)); + if ( !ext ) + return 1; + ext->lsei_name = name; + ext->lsei_values = values; + + if ( !*extensions ) { + *extensions = + LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *)); + if ( !*extensions ) + return 1; + n = 0; + } else { + for ( n=0; (*extensions)[n] != NULL; n++ ) + ; + tmp = LDAP_REALLOC(*extensions, + (n+2)*sizeof(LDAPSchemaExtensionItem *)); + if ( !tmp ) + return 1; + *extensions = tmp; + } + (*extensions)[n] = ext; + (*extensions)[n+1] = NULL; + return 0; +} + +static void +free_extensions(LDAPSchemaExtensionItem **extensions) +{ + LDAPSchemaExtensionItem **ext; + + if ( extensions ) { + for ( ext = extensions; *ext != NULL; ext++ ) { + LDAP_FREE((*ext)->lsei_name); + LDAP_VFREE((*ext)->lsei_values); + LDAP_FREE(*ext); + } + LDAP_FREE(extensions); + } +} + +void +ldap_syntax_free( LDAPSyntax * syn ) +{ + LDAP_FREE(syn->syn_oid); + if (syn->syn_names) LDAP_VFREE(syn->syn_names); + if (syn->syn_desc) LDAP_FREE(syn->syn_desc); + free_extensions(syn->syn_extensions); + LDAP_FREE(syn); +} + +LDAPSyntax * +ldap_str2syntax( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + LDAPSyntax * syn; + char ** ext_vals; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + syn = LDAP_CALLOC(1,sizeof(LDAPSyntax)); + + if ( !syn ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + LDAP_FREE(sval); + *code = LDAP_SCHERR_NOLEFTPAREN; + ldap_syntax_free(syn); + return NULL; + } + + parse_whsp(&ss); + syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !syn->syn_oid ) { + *errp = ss; + ldap_syntax_free(syn); + return NULL; + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal and accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_syntax_free(syn); + return NULL; + case TK_RIGHTPAREN: + return syn; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_syntax_free(syn); + return(NULL); + } + seen_name = 1; + syn->syn_names = parse_qdescrs(&ss,code); + if ( !syn->syn_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_syntax_free(syn); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_syntax_free(syn); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_syntax_free(syn); + return NULL; + } + syn->syn_desc = sval; + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_syntax_free(syn); + return NULL; + } + if ( add_extension(&syn->syn_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_syntax_free(syn); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_syntax_free(syn); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_syntax_free(syn); + return NULL; + } + } +} + +void +ldap_matchingrule_free( LDAPMatchingRule * mr ) +{ + LDAP_FREE(mr->mr_oid); + if (mr->mr_names) LDAP_VFREE(mr->mr_names); + if (mr->mr_desc) LDAP_FREE(mr->mr_desc); + if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid); + free_extensions(mr->mr_extensions); + LDAP_FREE(mr); +} + +LDAPMatchingRule * +ldap_str2matchingrule( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_syntax = 0; + LDAPMatchingRule * mr; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule)); + + if ( !mr ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_matchingrule_free(mr); + return NULL; + } + + parse_whsp(&ss); + savepos = ss; + mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags); + if ( !mr->mr_oid ) { + if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "SYNTAX") || + !strncmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else { + /* Non-numerical OID, ignore */ + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal and accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + case TK_RIGHTPAREN: + return mr; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingrule_free(mr); + return(NULL); + } + seen_name = 1; + mr->mr_names = parse_qdescrs(&ss,code); + if ( !mr->mr_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingrule_free(mr); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingrule_free(mr); + return NULL; + } + mr->mr_desc = sval; + parse_whsp(&ss); + } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingrule_free(mr); + return(NULL); + } + seen_obsolete = 1; + mr->mr_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"SYNTAX") ) { + LDAP_FREE(sval); + if ( seen_syntax ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingrule_free(mr); + return(NULL); + } + seen_syntax = 1; + parse_whsp(&ss); + mr->mr_syntax_oid = + ldap_int_parse_numericoid(&ss,code,flags); + if ( !mr->mr_syntax_oid ) { + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + } + if ( add_extension(&mr->mr_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingrule_free(mr); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingrule_free(mr); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingrule_free(mr); + return NULL; + } + } +} + +void +ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru ) +{ + LDAP_FREE(mru->mru_oid); + if (mru->mru_names) LDAP_VFREE(mru->mru_names); + if (mru->mru_desc) LDAP_FREE(mru->mru_desc); + if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids); + free_extensions(mru->mru_extensions); + LDAP_FREE(mru); +} + +LDAPMatchingRuleUse * +ldap_str2matchingruleuse( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_applies = 0; + LDAPMatchingRuleUse * mru; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse)); + + if ( !mru ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + + parse_whsp(&ss); + savepos = ss; + mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags); + if ( !mru->mru_oid ) { + if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "APPLIES") || + !strncmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else { + /* Non-numerical OID, ignore */ + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal and accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + case TK_RIGHTPAREN: + return mru; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_name = 1; + mru->mru_names = parse_qdescrs(&ss,code); + if ( !mru->mru_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + mru->mru_desc = sval; + parse_whsp(&ss); + } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_obsolete = 1; + mru->mru_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"APPLIES") ) { + LDAP_FREE(sval); + if ( seen_applies ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_applies = 1; + mru->mru_applies_oids = parse_oids(&ss, + code, + flags); + if ( !mru->mru_applies_oids ) { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + if ( add_extension(&mru->mru_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + } +} + +void +ldap_attributetype_free(LDAPAttributeType * at) +{ + LDAP_FREE(at->at_oid); + if (at->at_names) LDAP_VFREE(at->at_names); + if (at->at_desc) LDAP_FREE(at->at_desc); + if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid); + if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid); + if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid); + if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid); + if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid); + free_extensions(at->at_extensions); + LDAP_FREE(at); +} + +LDAPAttributeType * +ldap_str2attributetype( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_sup = 0; + int seen_equality = 0; + int seen_ordering = 0; + int seen_substr = 0; + int seen_syntax = 0; + int seen_usage = 0; + LDAPAttributeType * at; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + at = LDAP_CALLOC(1,sizeof(LDAPAttributeType)); + + if ( !at ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + + /* + * Definitions MUST begin with an OID in the numericoid format. + * However, this routine is used by clients to parse the response + * from servers and very well known servers will provide an OID + * in the wrong format or even no OID at all. We do our best to + * extract info from those servers. + */ + parse_whsp(&ss); + savepos = ss; + at->at_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !at->at_oid ) { + if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID + | LDAP_SCHEMA_ALLOW_OID_MACRO ) ) + && (ss == savepos) ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "SUP") || + !strcmp(sval, "EQUALITY") || + !strcmp(sval, "ORDERING") || + !strcmp(sval, "SUBSTR") || + !strcmp(sval, "SYNTAX") || + !strcmp(sval, "SINGLE-VALUE") || + !strcmp(sval, "COLLECTIVE") || + !strcmp(sval, "NO-USER-MODIFICATION") || + !strcmp(sval, "USAGE") || + !strncmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else if ( flags + & LDAP_SCHEMA_ALLOW_OID_MACRO) { + /* Non-numerical OID ... */ + int len = ss-savepos; + at->at_oid = LDAP_MALLOC(len+1); + strncpy(at->at_oid, savepos, len); + at->at_oid[len] = 0; + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal and accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_attributetype_free(at); + return NULL; + case TK_RIGHTPAREN: + return at; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_name = 1; + at->at_names = parse_qdescrs(&ss,code); + if ( !at->at_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + at->at_desc = sval; + parse_whsp(&ss); + } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_obsolete = 1; + at->at_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"SUP") ) { + LDAP_FREE(sval); + if ( seen_sup ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_sup = 1; + at->at_sup_oid = parse_woid(&ss,code); + if ( !at->at_sup_oid ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } else if ( !strcmp(sval,"EQUALITY") ) { + LDAP_FREE(sval); + if ( seen_equality ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_equality = 1; + at->at_equality_oid = parse_woid(&ss,code); + if ( !at->at_equality_oid ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } else if ( !strcmp(sval,"ORDERING") ) { + LDAP_FREE(sval); + if ( seen_ordering ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_ordering = 1; + at->at_ordering_oid = parse_woid(&ss,code); + if ( !at->at_ordering_oid ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } else if ( !strcmp(sval,"SUBSTR") ) { + LDAP_FREE(sval); + if ( seen_substr ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_substr = 1; + at->at_substr_oid = parse_woid(&ss,code); + if ( !at->at_substr_oid ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } else if ( !strcmp(sval,"SYNTAX") ) { + LDAP_FREE(sval); + if ( seen_syntax ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_syntax = 1; + parse_whsp(&ss); + savepos = ss; + at->at_syntax_oid = + parse_noidlen(&ss, + code, + &at->at_syntax_len, + flags); + if ( !at->at_syntax_oid ) { + if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { + kind = get_token(&ss,&sval); + if (kind == TK_BAREWORD) + { + char *sp = strchr(sval, '{'); + at->at_syntax_oid = sval; + if (sp) + { + *sp++ = 0; + at->at_syntax_len = atoi(sp); + while ( LDAP_DIGIT(*sp) ) + sp++; + if ( *sp != '}' ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } + } + } else { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } + parse_whsp(&ss); + } else if ( !strcmp(sval,"SINGLE-VALUE") ) { + LDAP_FREE(sval); + if ( at->at_single_value ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + at->at_single_value = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"COLLECTIVE") ) { + LDAP_FREE(sval); + if ( at->at_collective ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + at->at_collective = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) { + LDAP_FREE(sval); + if ( at->at_no_user_mod ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + at->at_no_user_mod = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"USAGE") ) { + LDAP_FREE(sval); + if ( seen_usage ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_attributetype_free(at); + return(NULL); + } + seen_usage = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_BAREWORD ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + if ( !strcasecmp(sval,"userApplications") ) + at->at_usage = + LDAP_SCHEMA_USER_APPLICATIONS; + else if ( !strcasecmp(sval,"directoryOperation") ) + at->at_usage = + LDAP_SCHEMA_DIRECTORY_OPERATION; + else if ( !strcasecmp(sval,"distributedOperation") ) + at->at_usage = + LDAP_SCHEMA_DISTRIBUTED_OPERATION; + else if ( !strcasecmp(sval,"dSAOperation") ) + at->at_usage = + LDAP_SCHEMA_DSA_OPERATION; + else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + LDAP_FREE(sval); + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + if ( add_extension(&at->at_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_attributetype_free(at); + return NULL; + } + } +} + +void +ldap_objectclass_free(LDAPObjectClass * oc) +{ + LDAP_FREE(oc->oc_oid); + if (oc->oc_names) LDAP_VFREE(oc->oc_names); + if (oc->oc_desc) LDAP_FREE(oc->oc_desc); + if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids); + if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must); + if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may); + free_extensions(oc->oc_extensions); + LDAP_FREE(oc); +} + +LDAPObjectClass * +ldap_str2objectclass( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_sup = 0; + int seen_kind = 0; + int seen_must = 0; + int seen_may = 0; + LDAPObjectClass * oc; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass)); + + if ( !oc ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_objectclass_free(oc); + return NULL; + } + + /* + * Definitions MUST begin with an OID in the numericoid format. + * However, this routine is used by clients to parse the response + * from servers and very well known servers will provide an OID + * in the wrong format or even no OID at all. We do our best to + * extract info from those servers. + */ + parse_whsp(&ss); + savepos = ss; + oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !oc->oc_oid ) { + if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "SUP") || + !strcmp(sval, "ABSTRACT") || + !strcmp(sval, "STRUCTURAL") || + !strcmp(sval, "AUXILIARY") || + !strcmp(sval, "MUST") || + !strncmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else if ( flags & + LDAP_SCHEMA_ALLOW_OID_MACRO ) { + /* Non-numerical OID, ignore */ + int len = ss-savepos; + oc->oc_oid = LDAP_MALLOC(len+1); + strncpy(oc->oc_oid, savepos, len); + oc->oc_oid[len] = 0; + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal an accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + case TK_RIGHTPAREN: + return oc; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_name = 1; + oc->oc_names = parse_qdescrs(&ss,code); + if ( !oc->oc_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_objectclass_free(oc); + return NULL; + } + oc->oc_desc = sval; + parse_whsp(&ss); + } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_obsolete = 1; + oc->oc_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"SUP") ) { + LDAP_FREE(sval); + if ( seen_sup ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_sup = 1; + oc->oc_sup_oids = parse_oids(&ss, + code, + flags); + if ( !oc->oc_sup_oids ) { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + } else if ( !strcmp(sval,"ABSTRACT") ) { + LDAP_FREE(sval); + if ( seen_kind ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_kind = 1; + oc->oc_kind = LDAP_SCHEMA_ABSTRACT; + parse_whsp(&ss); + } else if ( !strcmp(sval,"STRUCTURAL") ) { + LDAP_FREE(sval); + if ( seen_kind ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_kind = 1; + oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; + parse_whsp(&ss); + } else if ( !strcmp(sval,"AUXILIARY") ) { + LDAP_FREE(sval); + if ( seen_kind ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_kind = 1; + oc->oc_kind = LDAP_SCHEMA_AUXILIARY; + parse_whsp(&ss); + } else if ( !strcmp(sval,"MUST") ) { + LDAP_FREE(sval); + if ( seen_must ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_must = 1; + oc->oc_at_oids_must = parse_oids(&ss,code,0); + if ( !oc->oc_at_oids_must ) { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcmp(sval,"MAY") ) { + LDAP_FREE(sval); + if ( seen_may ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_objectclass_free(oc); + return(NULL); + } + seen_may = 1; + oc->oc_at_oids_may = parse_oids(&ss,code,0); + if ( !oc->oc_at_oids_may ) { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + if ( add_extension(&oc->oc_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_objectclass_free(oc); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_objectclass_free(oc); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_objectclass_free(oc); + return NULL; + } + } +} + +static char *const err2text[] = { + "Success", + "Out of memory", + "Unexpected token", + "Missing opening parenthesis", + "Missing closing parenthesis", + "Expecting digit", + "Expecting a name", + "Bad description", + "Bad superiors", + "Duplicate option", + "Unexpected end of data" +}; + +char * +ldap_scherr2str(int code) +{ + if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { + return "Unknown error"; + } else { + return err2text[code]; + } +} diff --git a/libraries/libldap/search.c b/libraries/libldap/search.c index 2b73ddd07e5514e24bcd1ac57f4ffecbab8ff336..c0bc46df7899dae708c45b7ce4e559d476bc1fb2 100644 --- a/libraries/libldap/search.c +++ b/libraries/libldap/search.c @@ -1,55 +1,166 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * search.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <ctype.h> - -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#endif /* MACOS */ - -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#endif /* DOS */ - -#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 ) -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#endif -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "ldap-int.h" -#ifdef NEEDPROTOS -static char *find_right_paren( char *s ); -static char *put_complex_filter( BerElement *ber, char *str, - unsigned long tag, int not ); -static int put_filter( BerElement *ber, char *str ); -static int put_simple_filter( BerElement *ber, char *str ); -static int put_substring_filter( BerElement *ber, char *type, char *str ); -static int put_filter_list( BerElement *ber, char *str ); + +/* + * ldap_search_ext - initiate an ldap search operation. + * + * Parameters: + * + * ld LDAP descriptor + * base DN of the base object + * scope the search scope - one of LDAP_SCOPE_BASE, + * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE + * filter a string containing the search filter + * (e.g., "(|(cn=bob)(sn=bob))") + * attrs list of attribute types to return for matches + * attrsonly 1 => attributes only 0 => attributes and values + * + * Example: + * char *attrs[] = { "mail", "title", 0 }; + * ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob", + * attrs, attrsonly, sctrls, ctrls, timeout, sizelimit, + * &msgid ); + */ +int +ldap_search_ext( + LDAP *ld, + LDAP_CONST char *base, + int scope, + LDAP_CONST char *filter, + char **attrs, + int attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + struct timeval *timeout, + int sizelimit, + int *msgidp ) +{ + int rc; + BerElement *ber; + int timelimit; + +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_ENTRY, "ldap_search_ext\n" )); #else -static char *find_right_paren(); -static char *put_complex_filter(); -static int put_filter(); -static int put_simple_filter(); -static int put_substring_filter(); -static int put_filter_list(); -#endif /* NEEDPROTOS */ + Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 ); +#endif + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; + + /* + * if timeout is provided, both tv_sec and tv_usec must + * be non-zero + */ + if( timeout != NULL ) { + if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) { + return LDAP_PARAM_ERROR; + } + + /* timelimit must be non-zero if timeout is provided */ + timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1; + + } else { + /* no timeout, no timelimit */ + timelimit = -1; + } + + ber = ldap_build_search_req( ld, base, scope, filter, attrs, + attrsonly, sctrls, cctrls, timelimit, sizelimit ); + + if ( ber == NULL ) { + return ld->ld_errno; + } + +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { + if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) { + ber_free( ber, 1 ); + ld->ld_errno = LDAP_SUCCESS; + *msgidp = ld->ld_msgid; + return ld->ld_errno; + } + ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber ); + } +#endif /* LDAP_NOCACHE */ + + /* send the message */ + *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ); + + if( *msgidp < 0 ) + return ld->ld_errno; + + return LDAP_SUCCESS; +} + +int +ldap_search_ext_s( + LDAP *ld, + LDAP_CONST char *base, + int scope, + LDAP_CONST char *filter, + char **attrs, + int attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + struct timeval *timeout, + int sizelimit, + LDAPMessage **res ) +{ + int rc; + int msgid; + + rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, + sctrls, cctrls, timeout, sizelimit, &msgid ); + + if ( rc != LDAP_SUCCESS ) { + return( rc ); + } + + rc = ldap_result( ld, msgid, 1, timeout, res ); + + if( rc <= 0 ) { + /* error(-1) or timeout(0) */ + return( ld->ld_errno ); + } + + if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_EXTENDED_PARTIAL ) { + return( ld->ld_errno ); + } + + return( ldap_result2error( ld, *res, 0 ) ); +} /* - * ldap_search - initiate an ldap (and X.500) search operation. Parameters: + * ldap_search - initiate an ldap search operation. + * + * Parameters: * * ld LDAP descriptor * base DN of the base object @@ -62,41 +173,60 @@ static int put_filter_list(); * * Example: * char *attrs[] = { "mail", "title", 0 }; - * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob", + * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob", * attrs, attrsonly ); */ int -ldap_search( LDAP *ld, char *base, int scope, char *filter, +ldap_search( + LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly ) { BerElement *ber; +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_ENTRY, "ldap_search\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 ); +#endif - if (( ber = ldap_build_search_req( ld, base, scope, filter, attrs, - attrsonly )) == NULLBER ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + ber = ldap_build_search_req( ld, base, scope, filter, attrs, + attrsonly, NULL, NULL, -1, -1 ); + + if ( ber == NULL ) { return( -1 ); } -#ifndef NO_CACHE +#ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { - if ( check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) { + if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) { ber_free( ber, 1 ); ld->ld_errno = LDAP_SUCCESS; return( ld->ld_msgid ); } - add_request_to_cache( ld, LDAP_REQ_SEARCH, ber ); + ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber ); } -#endif /* NO_CACHE */ +#endif /* LDAP_NOCACHE */ /* send the message */ - return ( send_initial_request( ld, LDAP_REQ_SEARCH, base, ber )); + return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber )); } BerElement * -ldap_build_search_req( LDAP *ld, char *base, int scope, char *filter, - char **attrs, int attrsonly ) +ldap_build_search_req( + LDAP *ld, + LDAP_CONST char *base, + ber_int_t scope, + LDAP_CONST char *filter, + char **attrs, + ber_int_t attrsonly, + LDAPControl **sctrls, + LDAPControl **cctrls, + ber_int_t timelimit, + ber_int_t sizelimit ) { BerElement *ber; int err; @@ -126,413 +256,86 @@ ldap_build_search_req( LDAP *ld, char *base, int scope, char *filter, */ /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { - return( NULLBER ); + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { + return( NULL ); } if ( base == NULL ) { - base = ""; + /* no base provided, use session default base */ + base = ld->ld_options.ldo_defbase; + + if ( base == NULL ) { + /* no session default base, use top */ + base = ""; + } } -#ifdef CLDAP - if ( ld->ld_sb.sb_naddr > 0 ) { - err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid, - ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref, - ld->ld_sizelimit, ld->ld_timelimit, attrsonly ); - } else { -#endif /* CLDAP */ - err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid, - LDAP_REQ_SEARCH, base, scope, ld->ld_deref, - ld->ld_sizelimit, ld->ld_timelimit, attrsonly ); -#ifdef CLDAP +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { + err = ber_write( ber, ld->ld_options.ldo_peer, + sizeof(struct sockaddr), 0); + } + if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { + char *dn = ld->ld_options.ldo_cldapdn; + if (!dn) dn = ""; + err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid, dn, + LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref, + (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, + (timelimit < 0) ? ld->ld_timelimit : timelimit, + attrsonly ); + } else +#endif + { + err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid, + LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref, + (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, + (timelimit < 0) ? ld->ld_timelimit : timelimit, + attrsonly ); } -#endif /* CLDAP */ if ( err == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( NULLBER ); + return( NULL ); } - filter = strdup( filter ); - err = put_filter( ber, filter ); - free( filter ); + if( filter == NULL ) { + filter = "(objectclass=*)"; + } + + err = ldap_pvt_put_filter( ber, filter ); if ( err == -1 ) { ld->ld_errno = LDAP_FILTER_ERROR; ber_free( ber, 1 ); - return( NULLBER ); + return( NULL ); } - if ( ber_printf( ber, "{v}}}", attrs ) == -1 ) { + if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); - return( NULLBER ); - } - - return( ber ); -} - -static char * -find_right_paren( char *s ) -{ - int balance, escape; - - balance = 1; - escape = 0; - while ( *s && balance ) { - if ( escape == 0 ) { - if ( *s == '(' ) - balance++; - else if ( *s == ')' ) - balance--; - } - if ( *s == '\\' && ! escape ) - escape = 1; - else - escape = 0; - if ( balance ) - s++; - } - - return( *s ? s : NULL ); -} - -static char * -put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not ) -{ - char *next; - - /* - * We have (x(filter)...) with str sitting on - * the x. We have to find the paren matching - * the one before the x and put the intervening - * filters by calling put_filter_list(). - */ - - /* put explicit tag */ - if ( ber_printf( ber, "t{", tag ) == -1 ) - return( NULL ); -/* - if ( !not && ber_printf( ber, "{" ) == -1 ) - return( NULL ); -*/ - - str++; - if ( (next = find_right_paren( str )) == NULL ) - return( NULL ); - - *next = '\0'; - if ( put_filter_list( ber, str ) == -1 ) return( NULL ); - *next++ = ')'; - - /* flush explicit tagged thang */ - if ( ber_printf( ber, "}" ) == -1 ) - return( NULL ); -/* - if ( !not && ber_printf( ber, "}" ) == -1 ) - return( NULL ); -*/ - - return( next ); -} - -static int -put_filter( BerElement *ber, char *str ) -{ - char *next, *tmp, *s, *d; - int parens, balance, escape, gotescape; - - /* - * A Filter looks like this: - * Filter ::= CHOICE { - * and [0] SET OF Filter, - * or [1] SET OF Filter, - * not [2] Filter, - * equalityMatch [3] AttributeValueAssertion, - * substrings [4] SubstringFilter, - * greaterOrEqual [5] AttributeValueAssertion, - * lessOrEqual [6] AttributeValueAssertion, - * present [7] AttributeType,, - * approxMatch [8] AttributeValueAssertion - * } - * - * SubstringFilter ::= SEQUENCE { - * type AttributeType, - * SEQUENCE OF CHOICE { - * initial [0] IA5String, - * any [1] IA5String, - * final [2] IA5String - * } - * } - * Note: tags in a choice are always explicit - */ - - Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 ); - - gotescape = parens = 0; - while ( *str ) { - switch ( *str ) { - case '(': - str++; - parens++; - switch ( *str ) { - case '&': - Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", - 0, 0, 0 ); - - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_AND, 0 )) == NULL ) - return( -1 ); - - parens--; - break; - - case '|': - Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", - 0, 0, 0 ); - - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_OR, 0 )) == NULL ) - return( -1 ); - - parens--; - break; - - case '!': - Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", - 0, 0, 0 ); - - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_NOT, 1 )) == NULL ) - return( -1 ); - - parens--; - break; - - default: - Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", - 0, 0, 0 ); - - balance = 1; - escape = 0; - next = str; - while ( *next && balance ) { - if ( escape == 0 ) { - if ( *next == '(' ) - balance++; - else if ( *next == ')' ) - balance--; - } - if ( *next == '\\' && ! escape ) - gotescape = escape = 1; - else - escape = 0; - if ( balance ) - next++; - } - if ( balance != 0 ) - return( -1 ); - - *next = '\0'; - tmp = strdup( str ); - if ( gotescape ) { - escape = 0; - for ( s = d = tmp; *s; s++ ) { - if ( *s != '\\' || escape ) { - *d++ = *s; - escape = 0; - } else { - escape = 1; - } - } - *d = '\0'; - } - if ( put_simple_filter( ber, tmp ) == -1 ) { - free( tmp ); - return( -1 ); - } - free( tmp ); - *next++ = ')'; - str = next; - parens--; - break; - } - break; - - case ')': - Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0, - 0 ); - if ( ber_printf( ber, "]" ) == -1 ) - return( -1 ); - str++; - parens--; - break; - - case ' ': - str++; - break; - - default: /* assume it's a simple type=value filter */ - Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0, - 0 ); - next = strchr( str, '\0' ); - tmp = strdup( str ); - if ( strchr( tmp, '\\' ) != NULL ) { - escape = 0; - for ( s = d = tmp; *s; s++ ) { - if ( *s != '\\' || escape ) { - *d++ = *s; - escape = 0; - } else { - escape = 1; - } - } - *d = '\0'; - } - if ( put_simple_filter( ber, tmp ) == -1 ) { - free( tmp ); - return( -1 ); - } - free( tmp ); - str = next; - break; - } - } - - return( parens ? -1 : 0 ); -} - -/* - * Put a list of filters like this "(filter1)(filter2)..." - */ - -static int -put_filter_list( BerElement *ber, char *str ) -{ - char *next; - char save; - - Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 ); - - while ( *str ) { - while ( *str && isspace( *str ) ) - str++; - if ( *str == '\0' ) - break; - - if ( (next = find_right_paren( str + 1 )) == NULL ) - return( -1 ); - save = *++next; - - /* now we have "(filter)" with str pointing to it */ - *next = '\0'; - if ( put_filter( ber, str ) == -1 ) - return( -1 ); - *next = save; - - str = next; - } - - return( 0 ); -} - -static int -put_simple_filter( BerElement *ber, char *str ) -{ - char *s; - char *value, savechar; - unsigned long ftype; - int rc; - - Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 ); - - if ( (s = strchr( str, '=' )) == NULL ) - return( -1 ); - value = s + 1; - *s-- = '\0'; - savechar = *s; - - switch ( *s ) { - case '<': - ftype = LDAP_FILTER_LE; - *s = '\0'; - break; - case '>': - ftype = LDAP_FILTER_GE; - *s = '\0'; - break; - case '~': - ftype = LDAP_FILTER_APPROX; - *s = '\0'; - break; - default: - if ( strchr( value, '*' ) == NULL ) { - ftype = LDAP_FILTER_EQUALITY; - } else if ( strcmp( value, "*" ) == 0 ) { - ftype = LDAP_FILTER_PRESENT; - } else { - rc = put_substring_filter( ber, str, value ); - *(value-1) = '='; - return( rc ); - } - break; } - if ( ftype == LDAP_FILTER_PRESENT ) { - rc = ber_printf( ber, "ts", ftype, str ); - } else { - rc = ber_printf( ber, "t{ss}", ftype, str, value ); + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return( NULL ); } - *s = savechar; - *(value-1) = '='; - return( rc == -1 ? rc : 0 ); -} - -static int -put_substring_filter( BerElement *ber, char *type, char *val ) -{ - char *nextstar, gotstar = 0; - unsigned long ftype; - - Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type, - val, 0 ); - - if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) - return( -1 ); - - while ( val != NULL ) { - if ( (nextstar = strchr( val, '*' )) != NULL ) - *nextstar++ = '\0'; - - if ( gotstar == 0 ) { - ftype = LDAP_SUBSTRING_INITIAL; - } else if ( nextstar == NULL ) { - ftype = LDAP_SUBSTRING_FINAL; - } else { - ftype = LDAP_SUBSTRING_ANY; - } - if ( *val != '\0' ) { - if ( ber_printf( ber, "ts", ftype, val ) == -1 ) - return( -1 ); - } - - gotstar = 1; - if ( nextstar != NULL ) - *(nextstar-1) = '*'; - val = nextstar; + if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( NULL ); } - if ( ber_printf( ber, "}}" ) == -1 ) - return( -1 ); - - return( 0 ); + return( ber ); } int -ldap_search_st( LDAP *ld, char *base, int scope, char *filter, char **attrs, +ldap_search_st( + LDAP *ld, LDAP_CONST char *base, int scope, + LDAP_CONST char *filter, char **attrs, int attrsonly, struct timeval *timeout, LDAPMessage **res ) { int msgid; @@ -554,8 +357,14 @@ ldap_search_st( LDAP *ld, char *base, int scope, char *filter, char **attrs, } int -ldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs, - int attrsonly, LDAPMessage **res ) +ldap_search_s( + LDAP *ld, + LDAP_CONST char *base, + int scope, + LDAP_CONST char *filter, + char **attrs, + int attrsonly, + LDAPMessage **res ) { int msgid; diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c new file mode 100644 index 0000000000000000000000000000000000000000..7fcb778c1170e73ae900a5bc3d426fb2377bcfae --- /dev/null +++ b/libraries/libldap/tls.c @@ -0,0 +1,1529 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * tls.c - Handle tls/ssl using SSLeay or OpenSSL. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> +#include <ac/param.h> + +#include "ldap-int.h" + +#ifdef HAVE_TLS + +#ifdef LDAP_R_COMPILE +#include <ldap_pvt_thread.h> +#endif + +#ifdef HAVE_OPENSSL_SSL_H +#include <openssl/ssl.h> +#include <openssl/x509v3.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/safestack.h> +#elif defined( HAVE_SSL_H ) +#include <ssl.h> +#endif + +static int tls_opt_trace = 1; +static char *tls_opt_certfile = NULL; +static char *tls_opt_keyfile = NULL; +static char *tls_opt_cacertfile = NULL; +static char *tls_opt_cacertdir = NULL; +static int tls_opt_require_cert = 0; +static char *tls_opt_ciphersuite = NULL; +static char *tls_opt_randfile = NULL; + +#define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \ + (void *)&sb_tls_sbio ) + +static void tls_report_error( void ); + +static void tls_info_cb( SSL *ssl, int where, int ret ); +static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ); +static int tls_verify_ok( int ok, X509_STORE_CTX *ctx ); +static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); +static STACK_OF(X509_NAME) * get_ca_list( char * bundle, char * dir ); + +#if 0 /* Currently this is not used by anyone */ +static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ); +#endif + +static SSL_CTX *tls_def_ctx = NULL; + +static int tls_seed_PRNG( const char *randfile ); + +#ifdef LDAP_R_COMPILE +/* + * provide mutexes for the SSLeay library. + */ +static ldap_pvt_thread_mutex_t tls_mutexes[CRYPTO_NUM_LOCKS]; + +static void tls_locking_cb( int mode, int type, const char *file, int line ) +{ + if ( mode & CRYPTO_LOCK ) { + ldap_pvt_thread_mutex_lock( &tls_mutexes[type] ); + } else { + ldap_pvt_thread_mutex_unlock( &tls_mutexes[type] ); + } +} + +/* + * an extra mutex for the default ctx. + */ + +static ldap_pvt_thread_mutex_t tls_def_ctx_mutex; + +static void tls_init_threads( void ) +{ + int i; + + for( i=0; i< CRYPTO_NUM_LOCKS ; i++ ) { + ldap_pvt_thread_mutex_init( &tls_mutexes[i] ); + } + CRYPTO_set_locking_callback( tls_locking_cb ); + /* FIXME: the thread id should be added somehow... */ + + ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex ); +} +#endif /* LDAP_R_COMPILE */ + +/* + * Tear down the TLS subsystem. Should only be called once. + */ +void +ldap_pvt_tls_destroy( void ) +{ + SSL_CTX_free(tls_def_ctx); + tls_def_ctx = NULL; + + EVP_cleanup(); + ERR_free_strings(); + + if ( tls_opt_certfile ) { + LDAP_FREE( tls_opt_certfile ); + tls_opt_certfile = NULL; + } + if ( tls_opt_keyfile ) { + LDAP_FREE( tls_opt_keyfile ); + tls_opt_keyfile = NULL; + } + if ( tls_opt_cacertfile ) { + LDAP_FREE( tls_opt_cacertfile ); + tls_opt_cacertfile = NULL; + } + if ( tls_opt_cacertdir ) { + LDAP_FREE( tls_opt_cacertdir ); + tls_opt_cacertdir = NULL; + } + if ( tls_opt_ciphersuite ) { + LDAP_FREE( tls_opt_ciphersuite ); + tls_opt_ciphersuite = NULL; + } + if ( tls_opt_randfile ) { + LDAP_FREE( tls_opt_randfile ); + tls_opt_randfile = NULL; + } +} + +/* + * Initialize TLS subsystem. Should be called only once. + */ +int +ldap_pvt_tls_init( void ) +{ + static int tls_initialized = 0; + + if ( tls_initialized ) return 0; + tls_initialized = 1; + + (void) tls_seed_PRNG( tls_opt_randfile ); + +#ifdef LDAP_R_COMPILE + tls_init_threads(); +#endif + + SSL_load_error_strings(); + SSLeay_add_ssl_algorithms(); + + /* FIXME: mod_ssl does this */ + X509V3_add_standard_extensions(); + return 0; +} + +/* + * initialize the default context + */ +int +ldap_pvt_tls_init_def_ctx( void ) +{ + STACK_OF(X509_NAME) *calist; + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex ); +#endif + if ( tls_def_ctx == NULL ) { + int i; + tls_def_ctx = SSL_CTX_new( SSLv23_method() ); + if ( tls_def_ctx == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not allocate default ctx (%d).\n", + ERR_peek_error() )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: could not allocate default ctx (%lu).\n", + ERR_peek_error(),0,0); +#endif + goto error_exit; + } + if ( tls_opt_ciphersuite && + !SSL_CTX_set_cipher_list( tls_def_ctx, + tls_opt_ciphersuite ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not set cipher list %s.\n", + tls_opt_ciphersuite )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: could not set cipher list %s.\n", + tls_opt_ciphersuite, 0, 0 ); +#endif + tls_report_error(); + goto error_exit; + } + if (tls_opt_cacertfile != NULL || tls_opt_cacertdir != NULL) { + if ( !SSL_CTX_load_verify_locations( tls_def_ctx, + tls_opt_cacertfile, + tls_opt_cacertdir ) + || !SSL_CTX_set_default_verify_paths( tls_def_ctx ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not load verify locations (file:`%s',dir:`%s').\n", + tls_opt_cacertfile ? tls_opt_cacertfile : "", + tls_opt_cacertdir ? tls_opt_cacertdir : "" )); +#else + Debug( LDAP_DEBUG_ANY, "TLS: " + "could not load verify locations (file:`%s',dir:`%s').\n", + tls_opt_cacertfile ? tls_opt_cacertfile : "", + tls_opt_cacertdir ? tls_opt_cacertdir : "", + 0 ); +#endif + tls_report_error(); + goto error_exit; + } + calist = get_ca_list( tls_opt_cacertfile, tls_opt_cacertdir ); + if ( !calist ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not load client CA list (file: `%s',dir:`%s')\n", + tls_opt_cacertfile ? tls_opt_cacertfile : "", + tls_opt_cacertdir ? tls_opt_cacertdir : "" )); +#else + Debug( LDAP_DEBUG_ANY, "TLS: " + "could not load client CA list (file:`%s',dir:`%s').\n", + tls_opt_cacertfile ? tls_opt_cacertfile : "", + tls_opt_cacertdir ? tls_opt_cacertdir : "", + 0 ); +#endif + tls_report_error(); + goto error_exit; + } + SSL_CTX_set_client_CA_list( tls_def_ctx, calist ); + } + if ( tls_opt_keyfile && + !SSL_CTX_use_PrivateKey_file( tls_def_ctx, + tls_opt_keyfile, + SSL_FILETYPE_PEM ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not use key file `%s'.\n", tls_opt_keyfile )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: could not use key file `%s'.\n", + tls_opt_keyfile,0,0); +#endif + tls_report_error(); + goto error_exit; + } + if ( tls_opt_certfile && + !SSL_CTX_use_certificate_file( tls_def_ctx, + tls_opt_certfile, + SSL_FILETYPE_PEM ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS could not use certificate `%s'.\n", tls_opt_certfile )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: could not use certificate `%s'.\n", + tls_opt_certfile,0,0); +#endif + tls_report_error(); + goto error_exit; + } + if ( ( tls_opt_certfile || tls_opt_keyfile ) && + !SSL_CTX_check_private_key( tls_def_ctx ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_init_def_ctx: " + "TLS private key mismatch.\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: private key mismatch.\n", + 0,0,0); +#endif + tls_report_error(); + goto error_exit; + } + if ( tls_opt_trace ) { + SSL_CTX_set_info_callback( tls_def_ctx, tls_info_cb ); + } + i = SSL_VERIFY_NONE; + if ( tls_opt_require_cert ) { + i = SSL_VERIFY_PEER; + if ( tls_opt_require_cert == LDAP_OPT_X_TLS_DEMAND || + tls_opt_require_cert == LDAP_OPT_X_TLS_HARD ) { + i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + } + SSL_CTX_set_verify( tls_def_ctx, i, + tls_opt_require_cert == LDAP_OPT_X_TLS_ALLOW ? + tls_verify_ok : tls_verify_cb ); + SSL_CTX_set_tmp_rsa_callback( tls_def_ctx, tls_tmp_rsa_cb ); + /* SSL_CTX_set_tmp_dh_callback( tls_def_ctx, tls_tmp_dh_cb ); */ + } +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); +#endif + return 0; +error_exit: + if ( tls_def_ctx != NULL ) { + SSL_CTX_free( tls_def_ctx ); + tls_def_ctx = NULL; + } +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex ); +#endif + return -1; +} + +static STACK_OF(X509_NAME) * +get_ca_list( char * bundle, char * dir ) +{ + STACK_OF(X509_NAME) *ca_list = NULL; + + if ( bundle ) { + ca_list = SSL_load_client_CA_file( bundle ); + } + /* + * FIXME: We have now to go over all files in dir, load them + * and add every certificate there to ca_list. + */ + return ca_list; +} + +static SSL * +alloc_handle( void *ctx_arg ) +{ + SSL_CTX *ctx; + SSL *ssl; + + if ( ctx_arg ) { + ctx = (SSL_CTX *) ctx_arg; + } else { + if ( ldap_pvt_tls_init_def_ctx() < 0 ) return NULL; + ctx = tls_def_ctx; + } + + ssl = SSL_new( ctx ); + if ( ssl == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "alloc_handle: " + "TLS can't create ssl handle.\n" )); +#else + Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0); +#endif + return NULL; + } + return ssl; +} + +static int +update_flags( Sockbuf *sb, SSL * ssl, int rc ) +{ + int err = SSL_get_error(ssl, rc); + + sb->sb_trans_needs_read = 0; + sb->sb_trans_needs_write = 0; + if (err == SSL_ERROR_WANT_READ) + { + sb->sb_trans_needs_read = 1; + return 1; + } else if (err == SSL_ERROR_WANT_WRITE) + { + sb->sb_trans_needs_write = 1; + return 1; + } else if (err == SSL_ERROR_WANT_CONNECT) + { + return 1; + } + return 0; +} + +/* + * TLS support for LBER Sockbufs + */ + +struct tls_data { + SSL *ssl; + Sockbuf_IO_Desc *sbiod; +}; + +static BIO_METHOD sb_tls_bio_method; + +static int +sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + struct tls_data *p; + BIO *bio; + + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) + return -1; + + p->ssl = (SSL *)arg; + p->sbiod = sbiod; + bio = BIO_new( &sb_tls_bio_method ); + bio->ptr = (void *)p; + SSL_set_bio( p->ssl, bio, bio ); + sbiod->sbiod_pvt = p; + return 0; +} + +static int +sb_tls_remove( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_free( p->ssl ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static int +sb_tls_close( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_shutdown( p->ssl ); + return 0; +} + +static int +sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_GET_SSL ) { + *((SSL **)arg) = p->ssl; + return 1; + + } else if ( opt == LBER_SB_OPT_DATA_READY ) { + if( SSL_pending( p->ssl ) > 0 ) { + return 1; + } + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +static ber_slen_t +sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_read( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_READ ) { + sbiod->sbiod_sb->sb_trans_needs_read = 1; + errno = EWOULDBLOCK; + } + else + sbiod->sbiod_sb->sb_trans_needs_read = 0; + return ret; +} + +static ber_slen_t +sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_write( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_WRITE ) { + sbiod->sbiod_sb->sb_trans_needs_write = 1; + errno = EWOULDBLOCK; + } + else + sbiod->sbiod_sb->sb_trans_needs_write = 0; + return ret; +} + +static Sockbuf_IO sb_tls_sbio = +{ + sb_tls_setup, /* sbi_setup */ + sb_tls_remove, /* sbi_remove */ + sb_tls_ctrl, /* sbi_ctrl */ + sb_tls_read, /* sbi_read */ + sb_tls_write, /* sbi_write */ + sb_tls_close /* sbi_close */ +}; + +static int +sb_tls_bio_create( BIO *b ) { + b->init = 1; + b->num = 0; + b->ptr = NULL; + b->flags = 0; + return 1; +} + +static int +sb_tls_bio_destroy( BIO *b ) +{ + if ( b == NULL ) + return 0; + + b->ptr = NULL; /* sb_tls_remove() will free it */ + b->init = 0; + b->flags = 0; + return 1; +} + +static int +sb_tls_bio_read( BIO *b, char *buf, int len ) +{ + struct tls_data *p; + int ret; + + if ( buf == NULL || len <= 0 ) + return 0; + + p = (struct tls_data *)b->ptr; + + if ( p == NULL || p->sbiod == NULL ) + return 0; + + ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); + + BIO_clear_retry_flags( b ); + if ( ret < 0 && errno == EWOULDBLOCK ) + BIO_set_retry_read( b ); + + return ret; +} + +static int +sb_tls_bio_write( BIO *b, const char *buf, int len ) +{ + struct tls_data *p; + int ret; + + if ( buf == NULL || len <= 0 ) + return 0; + + p = (struct tls_data *)b->ptr; + + if ( p == NULL || p->sbiod == NULL ) + return 0; + + ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); + + BIO_clear_retry_flags( b ); + if ( ret < 0 && errno == EWOULDBLOCK ) + BIO_set_retry_write( b ); + + return ret; +} + +static long +sb_tls_bio_ctrl( BIO *b, int cmd, long num, void *ptr ) +{ + if ( cmd == BIO_CTRL_FLUSH ) { + /* The OpenSSL library needs this */ + return 1; + } + return 0; +} + +static int +sb_tls_bio_gets( BIO *b, char *buf, int len ) +{ + return -1; +} + +static int +sb_tls_bio_puts( BIO *b, const char *str ) +{ + return sb_tls_bio_write( b, str, strlen( str ) ); +} + +static BIO_METHOD sb_tls_bio_method = +{ + ( 100 | 0x400 ), /* it's a source/sink BIO */ + "sockbuf glue", + sb_tls_bio_write, + sb_tls_bio_read, + sb_tls_bio_puts, + sb_tls_bio_gets, + sb_tls_bio_ctrl, + sb_tls_bio_create, + sb_tls_bio_destroy +}; + +/* + * Call this to do a TLS connect on a sockbuf. ctx_arg can be + * a SSL_CTX * or NULL, in which case the default ctx is used. + * + * Return value: + * + * 0 - Success. Connection is ready for communication. + * <0 - Error. Can't create a TLS stream. + * >0 - Partial success. + * Do a select (using information from lber_pvt_sb_needs_{read,write} + * and call again. + */ + +static int +ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) +{ + Sockbuf *sb = conn->lconn_sb; + int err; + SSL *ssl; + + if ( HAS_TLS( sb ) ) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); + + } else { + void *ctx = ld->ld_defconn + ? ld->ld_defconn->lconn_tls_ctx : NULL; + + ssl = alloc_handle( ctx ); + + if ( ssl == NULL ) return -1; + +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); +#endif + ber_sockbuf_add_io( sb, &sb_tls_sbio, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); + + if( ctx == NULL ) { + conn->lconn_tls_ctx = tls_def_ctx; + } + } + + err = SSL_connect( ssl ); + +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + if ( err <= 0 ) { + if ( update_flags( sb, ssl, err )) { + return 1; + } + if ((err = ERR_peek_error())) { + char buf[256]; + ld->ld_error = LDAP_STRDUP(ERR_error_string(err, buf)); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_int_tls_connect: " + "TLS can't connect.\n" )); +#else + Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0); +#endif + ber_sockbuf_remove_io( sb, &sb_tls_sbio, + LBER_SBIOD_LEVEL_TRANSPORT ); +#ifdef LDAP_DEBUG + ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT ); +#endif + return -1; + } + + return 0; +} + +/* + * Call this to do a TLS accept on a sockbuf. + * Everything else is the same as with tls_connect. + */ +int +ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) +{ + int err; + SSL *ssl; + + if ( HAS_TLS( sb ) ) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); + } else { + ssl = alloc_handle( ctx_arg ); + if ( ssl == NULL ) + return -1; +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); +#endif + ber_sockbuf_add_io( sb, &sb_tls_sbio, + LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); + } + + err = SSL_accept( ssl ); + +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + if ( err <= 0 ) { + if ( update_flags( sb, ssl, err )) + return 1; +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_accept: " + "TLS can't accept.\n" )); +#else + Debug( LDAP_DEBUG_ANY,"TLS: can't accept.\n",0,0,0 ); +#endif + tls_report_error(); + ber_sockbuf_remove_io( sb, &sb_tls_sbio, + LBER_SBIOD_LEVEL_TRANSPORT ); +#ifdef LDAP_DEBUG + ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_TRANSPORT ); +#endif + return -1; + } + + return 0; +} + +int +ldap_pvt_tls_inplace ( Sockbuf *sb ) +{ + if ( HAS_TLS( sb ) ) + return(1); + return(0); +} + +void * +ldap_pvt_tls_sb_ctx( Sockbuf *sb ) +{ + void *p; + + if (HAS_TLS( sb )) { + ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p ); + return p; + } + + return NULL; +} + +int +ldap_pvt_tls_get_strength( void *s ) +{ + SSL_CIPHER *c; + + c = SSL_get_current_cipher((SSL *)s); + return SSL_CIPHER_get_bits(c, NULL); +} + + +static X509 * +tls_get_cert( SSL *s ) +{ + /* If peer cert was bad, treat as if no cert was given */ + if (SSL_get_verify_result(s)) { + /* If we can send an alert, do so */ + if (SSL_version(s) != SSL2_VERSION) { + ssl3_send_alert(s,SSL3_AL_WARNING,SSL3_AD_BAD_CERTIFICATE); + } + return NULL; + } + return SSL_get_peer_certificate(s); +} + +char * +ldap_pvt_tls_get_peer( void *s ) +{ + X509 *x; + X509_NAME *xn; + char buf[2048], *p; + + + x = tls_get_cert((SSL *)s); + + if (!x) + return NULL; + + xn = X509_get_subject_name(x); + p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf))); + X509_free(x); + return p; +} + +char * +ldap_pvt_tls_get_peer_dn( void *s ) +{ + X509 *x; + X509_NAME *xn; + char buf[2048], *p, *dn; + + x = tls_get_cert((SSL *)s); + + if (!x) return NULL; + + xn = X509_get_subject_name(x); + p = X509_NAME_oneline(xn, buf, sizeof(buf)); + + dn = ldap_dcedn2dn( p ); + + X509_free(x); + return dn; +} + +char * +ldap_pvt_tls_get_peer_hostname( void *s ) +{ + X509 *x; + X509_NAME *xn; + char buf[2048], *p; + int ret; + + x = tls_get_cert((SSL *)s); + + if (!x) + return NULL; + + xn = X509_get_subject_name(x); + + ret = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)); + if( ret == -1 ) { + X509_free(x); + return NULL; + } + + p = LDAP_STRDUP(buf); + X509_free(x); + return p; +} + +int +ldap_pvt_tls_check_hostname( void *s, const char *name_in ) +{ + int i, ret = LDAP_LOCAL_ERROR; + X509 *x; + const char *name; + + if( ldap_int_hostname && + ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) + { + name = ldap_int_hostname; + } else { + name = name_in; + } + + x = tls_get_cert((SSL *)s); + if (!x) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_check_hostname: " + "TLS unable to get peer certificate.\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get peer certificate.\n", + 0, 0, 0 ); +#endif + return ret; + } + + i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); + if (i >= 0) + { + X509_EXTENSION *ex; + STACK_OF(GENERAL_NAME) *alt; + + ex = X509_get_ext(x, i); + alt = X509V3_EXT_d2i(ex); + if (alt) + { + int n, len1, len2 = 0; + char *domain; + GENERAL_NAME *gn; + X509V3_EXT_METHOD *method; + + len1 = strlen(name); + n = sk_GENERAL_NAME_num(alt); + domain = strchr(name, '.'); + if (domain) + len2 = len1 - (domain-name); + for (i=0; i<n; i++) + { + gn = sk_GENERAL_NAME_value(alt, i); + if (gn->type == GEN_DNS) + { + char *sn = ASN1_STRING_data(gn->d.ia5); + int sl = ASN1_STRING_length(gn->d.ia5); + + /* Is this an exact match? */ + if ((len1 == sl) && !strncasecmp(name, sn, len1)) + break; + + /* Is this a wildcard match? */ + if ((*sn == '*') && domain && (len2 == sl-1) && + !strncasecmp(domain, sn+1, len2)) + break; + } + } + method = X509V3_EXT_get(ex); + method->ext_free(alt); + if (i < n) /* Found a match */ + ret = LDAP_SUCCESS; + } + } + + if (ret != LDAP_SUCCESS) + { + X509_NAME *xn; + char buf[2048]; + + xn = X509_get_subject_name(x); + + if (X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) + == -1) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_check_hostname: " + "TLS unable to get common name from peer certificate.\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get common name from peer certificate.\n", + 0, 0, 0 ); +#endif + } else if (strcasecmp(name, buf)) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "ldap_pvt_tls_check_hostname: " + "TLS hostname (%s) does not match " + "common name in certificate (%s).\n", name, buf )); +#else + Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " + "common name in certificate (%s).\n", + name, buf, 0 ); +#endif + ret = LDAP_CONNECT_ERROR; + } else + { + ret = LDAP_SUCCESS; + } + } + X509_free(x); + return ret; +} + +const char * +ldap_pvt_tls_get_peer_issuer( void *s ) +{ +#if 0 /* currently unused; see ldap_pvt_tls_get_peer() if needed */ + X509 *x; + X509_NAME *xn; + char buf[2048], *p; + + x = SSL_get_peer_certificate((SSL *)s); + + if (!x) + return NULL; + + xn = X509_get_issuer_name(x); + p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf))); + X509_free(x); + return p; +#else + return NULL; +#endif +} + +int +ldap_int_tls_config( LDAP *ld, int option, const char *arg ) +{ + int i; + + switch( option ) { + case LDAP_OPT_X_TLS_CACERTFILE: + case LDAP_OPT_X_TLS_CACERTDIR: + case LDAP_OPT_X_TLS_CERTFILE: + case LDAP_OPT_X_TLS_KEYFILE: + case LDAP_OPT_X_TLS_RANDOM_FILE: + return ldap_pvt_tls_set_option( ld, option, (void *) arg ); + + case LDAP_OPT_X_TLS_REQUIRE_CERT: + case LDAP_OPT_X_TLS: + i = -1; + if ( strcasecmp( arg, "never" ) == 0 ) + i = LDAP_OPT_X_TLS_NEVER ; + if ( strcasecmp( arg, "demand" ) == 0 ) + i = LDAP_OPT_X_TLS_DEMAND ; + if ( strcasecmp( arg, "allow" ) == 0 ) + i = LDAP_OPT_X_TLS_ALLOW ; + if ( strcasecmp( arg, "try" ) == 0 ) + i = LDAP_OPT_X_TLS_TRY ; + if ( ( strcasecmp( arg, "hard" ) == 0 ) || + ( strcasecmp( arg, "on" ) == 0 ) || + ( strcasecmp( arg, "yes" ) == 0) || + ( strcasecmp( arg, "true" ) == 0 ) ) + i = LDAP_OPT_X_TLS_HARD ; + + if (i >= 0) { + return ldap_pvt_tls_set_option( ld, option, &i ); + } + return -1; + } + + return -1; +} + +int +ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) +{ + struct ldapoptions *lo; + + if( ld != NULL ) { + assert( LDAP_VALID( ld ) ); + + if( !LDAP_VALID( ld ) ) { + return LDAP_OPT_ERROR; + } + + lo = &ld->ld_options; + + } else { + /* Get pointer to global option structure */ + lo = LDAP_INT_GLOBAL_OPT(); + if ( lo == NULL ) { + return LDAP_NO_MEMORY; + } + } + + switch( option ) { + case LDAP_OPT_X_TLS: + *(int *)arg = lo->ldo_tls_mode; + break; + case LDAP_OPT_X_TLS_CTX: + if ( ld == NULL ) + *(void **)arg = (void *) tls_def_ctx; + else + *(void **)arg = ld->ld_defconn->lconn_tls_ctx; + break; + case LDAP_OPT_X_TLS_CACERTFILE: + *(char **)arg = tls_opt_cacertfile ? + LDAP_STRDUP( tls_opt_cacertfile ) : NULL; + break; + case LDAP_OPT_X_TLS_CACERTDIR: + *(char **)arg = tls_opt_cacertdir ? + LDAP_STRDUP( tls_opt_cacertdir ) : NULL; + break; + case LDAP_OPT_X_TLS_CERTFILE: + *(char **)arg = tls_opt_certfile ? + LDAP_STRDUP( tls_opt_certfile ) : NULL; + break; + case LDAP_OPT_X_TLS_KEYFILE: + *(char **)arg = tls_opt_keyfile ? + LDAP_STRDUP( tls_opt_keyfile ) : NULL; + break; + case LDAP_OPT_X_TLS_REQUIRE_CERT: + *(int *)arg = tls_opt_require_cert; + break; + case LDAP_OPT_X_TLS_RANDOM_FILE: + *(char **)arg = tls_opt_randfile ? + LDAP_STRDUP( tls_opt_randfile ) : NULL; + break; + case LDAP_OPT_X_TLS_SSL_CTX: { + void *retval = 0; + if ( ld != NULL ) { + LDAPConn *conn = ld->ld_defconn; + if ( conn != NULL ) { + Sockbuf *sb = conn->lconn_sb; + retval = ldap_pvt_tls_sb_ctx( sb ); + } + } + *(void **)arg = retval; + break; + } + default: + return -1; + } + return 0; +} + +int +ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) +{ + struct ldapoptions *lo; + + if( ld != NULL ) { + assert( LDAP_VALID( ld ) ); + + if( !LDAP_VALID( ld ) ) { + return LDAP_OPT_ERROR; + } + + lo = &ld->ld_options; + + } else { + /* Get pointer to global option structure */ + lo = LDAP_INT_GLOBAL_OPT(); + if ( lo == NULL ) { + return LDAP_NO_MEMORY; + } + } + + switch( option ) { + case LDAP_OPT_X_TLS: + switch( *(int *) arg ) { + case LDAP_OPT_X_TLS_NEVER: + case LDAP_OPT_X_TLS_DEMAND: + case LDAP_OPT_X_TLS_ALLOW: + case LDAP_OPT_X_TLS_TRY: + case LDAP_OPT_X_TLS_HARD: + if (lo != NULL) { + lo->ldo_tls_mode = *(int *)arg; + } + + return 0; + } + return -1; + + case LDAP_OPT_X_TLS_CTX: + if ( ld == NULL ) { + tls_def_ctx = (SSL_CTX *) arg; + + } else { + ld->ld_defconn->lconn_tls_ctx = arg; + } + return 0; + } + + if ( ld != NULL ) { + return -1; + } + + switch( option ) { + case LDAP_OPT_X_TLS_CACERTFILE: + if ( tls_opt_cacertfile ) LDAP_FREE( tls_opt_cacertfile ); + tls_opt_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + case LDAP_OPT_X_TLS_CACERTDIR: + if ( tls_opt_cacertdir ) LDAP_FREE( tls_opt_cacertdir ); + tls_opt_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + case LDAP_OPT_X_TLS_CERTFILE: + if ( tls_opt_certfile ) LDAP_FREE( tls_opt_certfile ); + tls_opt_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + case LDAP_OPT_X_TLS_KEYFILE: + if ( tls_opt_keyfile ) LDAP_FREE( tls_opt_keyfile ); + tls_opt_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + case LDAP_OPT_X_TLS_REQUIRE_CERT: + switch( *(int *) arg ) { + case LDAP_OPT_X_TLS_NEVER: + case LDAP_OPT_X_TLS_DEMAND: + case LDAP_OPT_X_TLS_ALLOW: + case LDAP_OPT_X_TLS_TRY: + case LDAP_OPT_X_TLS_HARD: + tls_opt_require_cert = * (int *) arg; + return 0; + } + return -1; + case LDAP_OPT_X_TLS_CIPHER_SUITE: + if ( tls_opt_ciphersuite ) LDAP_FREE( tls_opt_ciphersuite ); + tls_opt_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + case LDAP_OPT_X_TLS_RANDOM_FILE: + if (tls_opt_randfile ) LDAP_FREE (tls_opt_randfile ); + tls_opt_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + break; + default: + return -1; + } + return 0; +} + +int +ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) +{ + Sockbuf *sb = conn->lconn_sb; + char *host; + void *ssl; + + if( srv ) { + host = srv->lud_host; + } else { + host = conn->lconn_server->lud_host; + } + + /* avoid NULL host */ + if( host == NULL ) { + host = "localhost"; + } + + (void) ldap_pvt_tls_init(); + + /* + * Fortunately, the lib uses blocking io... + */ + if ( ldap_int_tls_connect( ld, conn ) < 0 ) { + ld->ld_errno = LDAP_CONNECT_ERROR; + return (ld->ld_errno); + } + + ssl = ldap_pvt_tls_sb_ctx( sb ); + assert( ssl != NULL ); + + /* + * compare host with name(s) in certificate + */ + ld->ld_errno = ldap_pvt_tls_check_hostname( ssl, host ); + if (ld->ld_errno != LDAP_SUCCESS) { + return ld->ld_errno; + } + + /* + * set SASL properties to TLS ssf and authid + */ + { + const char *authid; + ber_len_t ssf; + + /* we need to let SASL know */ + ssf = ldap_pvt_tls_get_strength( ssl ); + authid = ldap_pvt_tls_get_peer( ssl ); + + (void) ldap_int_sasl_external( ld, conn, authid, ssf ); + } + + return LDAP_SUCCESS; +} + +/* Derived from openssl/apps/s_cb.c */ +static void +tls_info_cb( SSL *ssl, int where, int ret ) +{ + int w; + char *op; + + w = where & ~SSL_ST_MASK; + if ( w & SSL_ST_CONNECT ) { + op = "SSL_connect"; + } else if ( w & SSL_ST_ACCEPT ) { + op = "SSL_accept"; + } else { + op = "undefined"; + } + + if ( where & SSL_CB_LOOP ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_DETAIL1, "tls_info_cb: " + "TLS trace: %s:%s\n", op, SSL_state_string_long( ssl ) )); +#else + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:%s\n", + op, SSL_state_string_long( ssl ), 0 ); +#endif + } else if ( where & SSL_CB_ALERT ) { + op = ( where & SSL_CB_READ ) ? "read" : "write"; +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_DETAIL1, "tls_info_cb: " + "TLS trace: SSL3 alert %s:%s:%s\n", op, + SSL_alert_type_string_long( ret ), + SSL_alert_desc_string_long( ret) )); +#else + Debug( LDAP_DEBUG_TRACE, + "TLS trace: SSL3 alert %s:%s:%s\n", + op, + SSL_alert_type_string_long( ret ), + SSL_alert_desc_string_long( ret) ); +#endif + } else if ( where & SSL_CB_EXIT ) { + if ( ret == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "tls_info_cb: " + "TLS trace: %s:failed in %s\n", op, SSL_state_string_long( ssl ) )); +#else + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:failed in %s\n", + op, SSL_state_string_long( ssl ), 0 ); +#endif + } else if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "tls_info_cb: " + "TLS trace: %s:error in %s\n", op, SSL_state_string_long( ssl ) )); +#else + Debug( LDAP_DEBUG_TRACE, + "TLS trace: %s:error in %s\n", + op, SSL_state_string_long( ssl ), 0 ); +#endif + } + } +} + +static int +tls_verify_cb( int ok, X509_STORE_CTX *ctx ) +{ + X509 *cert; + int errnum; + int errdepth; + X509_NAME *subject; + X509_NAME *issuer; + char *sname; + char *iname; + + cert = X509_STORE_CTX_get_current_cert( ctx ); + errnum = X509_STORE_CTX_get_error( ctx ); + errdepth = X509_STORE_CTX_get_error_depth( ctx ); + + /* + * X509_get_*_name return pointers to the internal copies of + * those things requested. So do not free them. + */ + subject = X509_get_subject_name( cert ); + issuer = X509_get_issuer_name( cert ); + /* X509_NAME_oneline, if passed a NULL buf, allocate memomry */ + sname = X509_NAME_oneline( subject, NULL, 0 ); + iname = X509_NAME_oneline( issuer, NULL, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, "tls_verify_cb" + "TLS certificate verification: depth: %d, err: %d: " + "subject: %s, issuer: %s\n", errdepth, errnum, + sname ? sname : "-unknown-", iname ? iname : "-unknown-" )); +#else + Debug( LDAP_DEBUG_TRACE, + "TLS certificate verification: depth: %d, err: %d, subject: %s,", + errdepth, errnum, + sname ? sname : "-unknown-" ); + Debug( LDAP_DEBUG_TRACE, " issuer: %s\n", iname ? iname : "-unknown-", 0, 0 ); +#endif + if ( sname ) + CRYPTO_free ( sname ); + if ( iname ) + CRYPTO_free ( iname ); + + return ok; +} + +static int +tls_verify_ok( int ok, X509_STORE_CTX *ctx ) +{ + (void) tls_verify_cb( ok, ctx ); + return 1; +} + +/* Inspired by ERR_print_errors in OpenSSL */ +static void +tls_report_error( void ) +{ + unsigned long l; + char buf[200]; + const char *file; + int line; + + while ( ( l = ERR_get_error_line( &file, &line ) ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, + "tls_report_error: TLS %s %s:%d\n", + ERR_error_string( l, buf ), file, line )); +#else + Debug( LDAP_DEBUG_ANY, "TLS: %s %s:%d\n", + ERR_error_string( l, buf ), file, line ); +#endif + } +} + +static RSA * +tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ) +{ + RSA *tmp_rsa; + + /* FIXME: Pregenerate the key on startup */ + /* FIXME: Who frees the key? */ + tmp_rsa = RSA_generate_key( key_length, RSA_F4, NULL, NULL ); + + if ( !tmp_rsa ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_ERR, + "tls_tmp_rsa_cb: TLS Failed to generate temporary %d-bit %s RSA key\n", + key_length, is_export ? "export" : "domestic" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: Failed to generate temporary %d-bit %s RSA key\n", + key_length, is_export ? "export" : "domestic", 0 ); +#endif + return NULL; + } + return tmp_rsa; +} + +static int +tls_seed_PRNG( const char *randfile ) +{ +#ifndef URANDOM_DEVICE + /* no /dev/urandom (or equiv) */ + long total=0; + char buffer[MAXPATHLEN]; + + if (randfile == NULL) { + /* The seed file is $RANDFILE if defined, otherwise $HOME/.rnd. + * If $HOME is not set or buffer too small to hold the pathname, + * an error occurs. - From RAND_file_name() man page. + * The fact is that when $HOME is NULL, .rnd is used. + */ + randfile = RAND_file_name( buffer, sizeof( buffer ) ); + + } else if (RAND_egd(randfile) > 0) { + /* EGD socket */ + return 0; + } + + if (randfile == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_DETAIL1, + "tls_seed_PRNG: TLS Use configuration file or " + "$RANDFILE to define seed PRNG\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: Use configuration file or $RANDFILE to define seed PRNG\n", + 0, 0, 0); +#endif + return -1; + } + + total = RAND_load_file(randfile, -1); + + if (RAND_status() == 0) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tls", LDAP_LEVEL_DETAIL1, + "tls_seed_PRNG: TLS PRNG not been seeded with enough data\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "TLS: PRNG not been seeded with enough data\n", + 0, 0, 0); +#endif + return -1; + } + + /* assume if there was enough bits to seed that it's okay + * to write derived bits to the file + */ + RAND_write_file(randfile); + +#endif + + return 0; +} + +#if 0 +static DH * +tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) +{ + return NULL; +} +#endif +#endif + +int +ldap_start_tls_s ( LDAP *ld, + LDAPControl **serverctrls, + LDAPControl **clientctrls ) +{ + int rc; + +#ifdef HAVE_TLS + char *rspoid = NULL; + struct berval *rspdata = NULL; + + /* XXYYZ: this initiates operation only on default connection! */ + + if ( ld->ld_sb != NULL && ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) { + return LDAP_LOCAL_ERROR; + } + + rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS, + NULL, serverctrls, clientctrls, &rspoid, &rspdata ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( rspoid != NULL ) { + LDAP_FREE(rspoid); + } + + if ( rspdata != NULL ) { + ber_bvfree( rspdata ); + } + + rc = ldap_int_tls_start( ld, ld->ld_defconn, NULL ); +#else + rc = LDAP_NOT_SUPPORTED; +#endif + return rc; +} + diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index e7b5c401e6f2c8b28be7b23950286e5a4649ad73..4474920bf7bc97d65ce867aa47b7bd012384e8dc 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -1,81 +1,91 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * unbind.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +/* An Unbind Request looks like this: + * + * UnbindRequest ::= NULL + * + * and has no response. + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include "msdos.h" -#ifdef NCSA -#include "externs.h" -#endif /* NCSA */ -#else /* DOS */ -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "ldap-int.h" +int +ldap_unbind_ext( + LDAP *ld, + LDAPControl **sctrls, + LDAPControl **cctrls ) +{ + int rc; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + /* check client controls */ + rc = ldap_int_client_controls( ld, cctrls ); + if( rc != LDAP_SUCCESS ) return rc; + + return ldap_ld_free( ld, 1, sctrls, cctrls ); +} + +int +ldap_unbind_ext_s( + LDAP *ld, + LDAPControl **sctrls, + LDAPControl **cctrls ) +{ + return ldap_unbind_ext( ld, sctrls, cctrls ); +} int ldap_unbind( LDAP *ld ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "unbind", LDAP_LEVEL_ENTRY, "ldap_unbind\n" )); +#else Debug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0 ); +#endif - return( ldap_ld_free( ld, 1 )); + return( ldap_unbind_ext( ld, NULL, NULL ) ); } int -ldap_ld_free( LDAP *ld, int close ) +ldap_ld_free( + LDAP *ld, + int close, + LDAPControl **sctrls, + LDAPControl **cctrls ) { LDAPMessage *lm, *next; int err = LDAP_SUCCESS; -#ifdef LDAP_REFERRALS - LDAPRequest *lr, *nextlr; -#endif /* LDAP_REFERRALS */ - - if ( ld->ld_sb.sb_naddr == 0 ) { -#ifdef LDAP_REFERRALS - /* free LDAP structure and outstanding requests/responses */ - for ( lr = ld->ld_requests; lr != NULL; lr = nextlr ) { - nextlr = lr->lr_next; - free_request( ld, lr ); - } - - /* free and unbind from all open connections */ - while ( ld->ld_conns != NULL ) { - free_connection( ld, ld->ld_conns, 1, close ); - } -#else /* LDAP_REFERRALS */ - if ( close ) { - err = send_unbind( ld, &ld->ld_sb ); - close_connection( &ld->ld_sb ); - } -#endif /* LDAP_REFERRALS */ - } else { - int i; - - for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) { - free( ld->ld_sb.sb_addrs[ i ] ); - } - free( ld->ld_sb.sb_addrs ); - free( ld->ld_sb.sb_fromaddr ); + + /* free LDAP structure and outstanding requests/responses */ + while ( ld->ld_requests != NULL ) { + ldap_free_request( ld, ld->ld_requests ); + } + + /* free and unbind from all open connections */ + while ( ld->ld_conns != NULL ) { + ldap_free_connection( ld, ld->ld_conns, 1, close ); } for ( lm = ld->ld_responses; lm != NULL; lm = next ) { @@ -83,67 +93,128 @@ ldap_ld_free( LDAP *ld, int close ) ldap_msgfree( lm ); } -#ifndef NO_CACHE - if ( ld->ld_cache != NULL ) +#ifndef LDAP_NOCACHE + if ( ld->ld_cache != NULL ) { ldap_destroy_cache( ld ); -#endif /* !NO_CACHE */ - if ( ld->ld_error != NULL ) - free( ld->ld_error ); - if ( ld->ld_matched != NULL ) - free( ld->ld_matched ); - if ( ld->ld_host != NULL ) - free( ld->ld_host ); - if ( ld->ld_ufnprefix != NULL ) - free( ld->ld_ufnprefix ); - if ( ld->ld_filtd != NULL ) - ldap_getfilter_free( ld->ld_filtd ); -#ifndef LDAP_REFERRALS - if ( ld->ld_sb.sb_ber.ber_buf != NULL ) - free( ld->ld_sb.sb_ber.ber_buf ); -#endif /* !LDAP_REFERRALS */ - if ( ld->ld_abandoned != NULL ) - free( ld->ld_abandoned ); - -#ifdef LDAP_REFERRALS - if ( ld->ld_selectinfo != NULL ) - free_select_info( ld->ld_selectinfo ); -#endif /* LDAP_REFERRALS */ - - if ( ld->ld_defhost != NULL ) - free( ld->ld_defhost ); - - free( (char *) ld ); + ld->ld_cache = NULL; + } +#endif /* !LDAP_NOCACHE */ + + if ( ld->ld_error != NULL ) { + LDAP_FREE( ld->ld_error ); + ld->ld_error = NULL; + } + + if ( ld->ld_matched != NULL ) { + LDAP_FREE( ld->ld_matched ); + ld->ld_matched = NULL; + } + + if ( ld->ld_abandoned != NULL ) { + LDAP_FREE( ld->ld_abandoned ); + ld->ld_abandoned = NULL; + } + + if ( ld->ld_selectinfo != NULL ) { + ldap_free_select_info( ld->ld_selectinfo ); + ld->ld_selectinfo = NULL; + } + + if ( ld->ld_options.ldo_defludp != NULL ) { + ldap_free_urllist( ld->ld_options.ldo_defludp ); + ld->ld_options.ldo_defludp = NULL; + } + + if ( ld->ld_options.ldo_tm_api != NULL ) { + LDAP_FREE( ld->ld_options.ldo_tm_api ); + ld->ld_options.ldo_tm_api = NULL; + } + + if ( ld->ld_options.ldo_tm_net != NULL ) { + LDAP_FREE( ld->ld_options.ldo_tm_net ); + ld->ld_options.ldo_tm_net = NULL; + } + +#ifdef HAVE_CYRUS_SASL + if ( ld->ld_options.ldo_def_sasl_mech != NULL ) { + LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); + ld->ld_options.ldo_def_sasl_mech = NULL; + } + + if ( ld->ld_options.ldo_def_sasl_realm != NULL ) { + LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); + ld->ld_options.ldo_def_sasl_realm = NULL; + } + + if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) { + LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); + ld->ld_options.ldo_def_sasl_authcid = NULL; + } + + if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) { + LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); + ld->ld_options.ldo_def_sasl_authzid = NULL; + } +#endif + ber_sockbuf_free( ld->ld_sb ); + + LDAP_FREE( (char *) ld ); + return( err ); } int ldap_unbind_s( LDAP *ld ) { - return( ldap_ld_free( ld, 1 )); + return( ldap_unbind_ext( ld, NULL, NULL ) ); } int -send_unbind( LDAP *ld, Sockbuf *sb ) +ldap_send_unbind( + LDAP *ld, + Sockbuf *sb, + LDAPControl **sctrls, + LDAPControl **cctrls ) { BerElement *ber; - Debug( LDAP_DEBUG_TRACE, "send_unbind\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG (( "unbind", LDAP_LEVEL_ENTRY, "ldap_send_unbind\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_send_unbind\n", 0, 0, 0 ); +#endif +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld)) + return LDAP_SUCCESS; +#endif /* create a message to send */ - if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { + if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( ld->ld_errno ); } /* fill it in */ - if ( ber_printf( ber, "{itn}", ++ld->ld_msgid, + if ( ber_printf( ber, "{itn" /*}*/, ++ld->ld_msgid, LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } + /* Put Server Controls */ + if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { + ber_free( ber, 1 ); + return ld->ld_errno; + } + + if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + return( ld->ld_errno ); + } + /* send the message */ if ( ber_flush( sb, ber, 1 ) == -1 ) { ld->ld_errno = LDAP_SERVER_DOWN; diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 08b47efd6be668222fdd938388f11b4294d18fc2..97059170b7d214db18b30fe4d1e417de65933ef9 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -1,381 +1,1148 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1996 Regents of the University of Michigan. * All rights reserved. * - * LIBLDAP url.c -- LDAP URL related routines + * LIBLDAP url.c -- LDAP URL (RFC 2255) related routines * * LDAP URLs look like this: - * l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ] + * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * where: * attributes is a comma separated list * scope is one of these three strings: base one sub (default=base) - * filter is an string-represented filter as in RFC 1558 + * filter is an string-represented filter as in RFC 2254 * - * e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich + * e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension * * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl> */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <ctype.h> - -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#endif /* MACOS */ - -#if defined( DOS ) || defined( _WIN32 ) -#include <stdlib.h> -#include <malloc.h> -#include "msdos.h" -#endif /* DOS || _WIN32 */ - -#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 ) -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#endif /* !MACOS && !DOS && !_WIN32 */ - -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "ldap-int.h" -#ifdef NEEDPROTOS -static int skip_url_prefix( char **urlp, int *enclosedp ); -static void hex_unescape( char *s ); -static int unhex( char c ); -#else /* NEEDPROTOS */ -static int skip_url_prefix(); -static void hex_unescape(); -static int unhex(); -#endif /* NEEDPROTOS */ +/* local functions */ +static const char* skip_url_prefix LDAP_P(( + const char *url, + int *enclosedp, + const char **scheme )); + +int ldap_pvt_url_scheme2proto( const char *scheme ) +{ + assert( scheme ); + + if( scheme == NULL ) { + return -1; + } + + if( strcmp("ldap", scheme) == 0 ) { + return LDAP_PROTO_TCP; + } + + if( strcmp("ldapi", scheme) == 0 ) { + return LDAP_PROTO_IPC; + } + + if( strcmp("ldaps", scheme) == 0 ) { + return LDAP_PROTO_TCP; + } +#ifdef LDAP_CONNECTIONLESS + if( strcmp("cldap", scheme) == 0 ) { + return LDAP_PROTO_UDP; + } +#endif + + return -1; +} + +int +ldap_pvt_url_scheme2tls( const char *scheme ) +{ + assert( scheme ); + + if( scheme == NULL ) { + return -1; + } + return strcmp("ldaps", scheme) == 0; +} int -ldap_is_ldap_url( char *url ) +ldap_is_ldap_url( LDAP_CONST char *url ) { int enclosed; + const char * scheme; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { + return 0; + } - return( url != NULL && skip_url_prefix( &url, &enclosed )); + return 1; } +int +ldap_is_ldaps_url( LDAP_CONST char *url ) +{ + int enclosed; + const char * scheme; -static int -skip_url_prefix( char **urlp, int *enclosedp ) + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { + return 0; + } + + return strcmp(scheme, "ldaps") == 0; +} + +int +ldap_is_ldapi_url( LDAP_CONST char *url ) { -/* - * return non-zero if this looks like a LDAP URL; zero if not - * if non-zero returned, *urlp will be moved past "ldap://" part of URL - */ - if ( *urlp == NULL ) { - return( 0 ); + int enclosed; + const char * scheme; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { + return 0; + } + + return strcmp(scheme, "ldapi") == 0; +} + +#ifdef LDAP_CONNECTIONLESS +int +ldap_is_ldapc_url( LDAP_CONST char *url ) +{ + int enclosed; + const char * scheme; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { + return 0; + } + + return strcmp(scheme, "cldap") == 0; +} +#endif + +static const char* +skip_url_prefix( + const char *url, + int *enclosedp, + const char **scheme ) +{ + /* + * return non-zero if this looks like a LDAP URL; zero if not + * if non-zero returned, *urlp will be moved past "ldap://" part of URL + */ + const char *p; + + if ( url == NULL ) { + return( NULL ); } + p = url; + /* skip leading '<' (if any) */ - if ( **urlp == '<' ) { + if ( *p == '<' ) { *enclosedp = 1; - ++*urlp; + ++p; } else { *enclosedp = 0; } /* skip leading "URL:" (if any) */ - if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp( - *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) { - *urlp += LDAP_URL_URLCOLON_LEN; + if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) { + p += LDAP_URL_URLCOLON_LEN; + } + + /* check for "ldap://" prefix */ + if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldap://" prefix and return success */ + p += LDAP_URL_PREFIX_LEN; + *scheme = "ldap"; + return( p ); + } + + /* check for "ldaps://" prefix */ + if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldaps://" prefix and return success */ + p += LDAPS_URL_PREFIX_LEN; + *scheme = "ldaps"; + return( p ); + } + + /* check for "ldapi://" prefix */ + if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldapi://" prefix and return success */ + p += LDAPI_URL_PREFIX_LEN; + *scheme = "ldapi"; + return( p ); + } + +#ifdef LDAP_CONNECTIONLESS + /* check for "cldap://" prefix */ + if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) { + /* skip over "cldap://" prefix and return success */ + p += LDAPC_URL_PREFIX_LEN; + *scheme = "cldap"; + return( p ); + } +#endif + + return( NULL ); +} + + +static int str2scope( const char *p ) +{ + if ( strcasecmp( p, "one" ) == 0 ) { + return LDAP_SCOPE_ONELEVEL; + + } else if ( strcasecmp( p, "onetree" ) == 0 ) { + return LDAP_SCOPE_ONELEVEL; + + } else if ( strcasecmp( p, "base" ) == 0 ) { + return LDAP_SCOPE_BASE; + + } else if ( strcasecmp( p, "sub" ) == 0 ) { + return LDAP_SCOPE_SUBTREE; + + } else if ( strcasecmp( p, "subtree" ) == 0 ) { + return LDAP_SCOPE_SUBTREE; } - /* check for missing "ldap://" prefix */ - if ( strlen( *urlp ) < LDAP_URL_PREFIX_LEN || - strncasecmp( *urlp, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) { - return( 0 ); + return( -1 ); +} + +static int hex_escape( char *buf, const char *s, int list ) +{ + int i; + int pos; + static const char hex[] = "0123456789ABCDEF"; + + if( s == NULL ) return 0; + + for( pos=0,i=0; s[i]; i++ ) { + int escape = 0; + switch( s[i] ) { + case ',': + escape = list; + break; + case '%': + case '?': + case ' ': + case '<': + case '>': + case '"': + case '#': + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '`': + case '[': + case ']': + escape = 1; + break; + + default: + escape = s[i] < 0x20 || 0x1f >= s[i]; + } + + if( escape ) { + buf[pos++] = '%'; + buf[pos++] = hex[ (s[i] >> 4) & 0x0f ]; + buf[pos++] = hex[ s[i] & 0x0f ]; + } else { + buf[pos++] = s[i]; + } + } + + buf[pos] = '\0'; + return pos; +} + +static int hex_escape_args( char *buf, char **s ) +{ + int pos; + int i; + + if( s == NULL ) return 0; + + pos = 0; + for( i=0; s[i] != NULL; i++ ) { + if( pos ) { + buf[pos++] = ','; + } + pos += hex_escape( &buf[pos], s[i], 1 ); } - /* skip over "ldap://" prefix and return success */ - *urlp += LDAP_URL_PREFIX_LEN; - return( 1 ); + return pos; } +char * ldap_url_desc2str( LDAPURLDesc *u ) +{ + char *s; + int i; + int sep = 0; + int sofar; + size_t len = 0; + if( u == NULL ) return NULL; + + if( u->lud_exts ) { + for( i=0; u->lud_exts[i]; i++ ) { + len += strlen( u->lud_exts[i] ) + 1; + } + if( !sep ) sep = 5; + } + + if( u->lud_filter ) { + len += strlen( u->lud_filter ); + if( !sep ) sep = 4; + } + if ( len ) len++; /* ? */ + + switch( u->lud_scope ) { + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: + case LDAP_SCOPE_BASE: + len += sizeof("base"); + if( !sep ) sep = 3; + break; + + default: + if ( len ) len++; /* ? */ + } + + if( u->lud_attrs ) { + for( i=0; u->lud_attrs[i]; i++ ) { + len += strlen( u->lud_attrs[i] ) + 1; + } + if( !sep ) sep = 2; + } else if ( len ) len++; /* ? */ + + if( u->lud_dn ) { + len += strlen( u->lud_dn ) + 1; + if( !sep ) sep = 1; + }; + + if( u->lud_port ) { + len+=6; + } + + if( u->lud_host ) { + len+=strlen( u->lud_host ); + } + + len += strlen( u->lud_scheme ) + sizeof("://"); + + /* allocate enough to hex escape everything -- overkill */ + s = LDAP_MALLOC( 3*len ); + if( s == NULL ) return NULL; + + if( u->lud_port ) { + sprintf( s, "%s://%s:%d%n", u->lud_scheme, + u->lud_host, u->lud_port, &sofar ); + } else { + sprintf( s, "%s://%s%n", u->lud_scheme, + u->lud_host, &sofar ); + } + + if( sep < 1 ) goto done; + s[sofar++] = '/'; + + sofar += hex_escape( &s[sofar], u->lud_dn, 0 ); + + if( sep < 2 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape_args( &s[sofar], u->lud_attrs ); + + if( sep < 3 ) goto done; + s[sofar++] = '?'; + + switch( u->lud_scope ) { + case LDAP_SCOPE_BASE: + strcpy( &s[sofar], "base" ); + sofar += sizeof("base") - 1; + break; + case LDAP_SCOPE_ONELEVEL: + strcpy( &s[sofar], "one" ); + sofar += sizeof("one") - 1; + break; + case LDAP_SCOPE_SUBTREE: + strcpy( &s[sofar], "sub" ); + sofar += sizeof("sub") - 1; + break; + } + + if( sep < 4 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape( &s[sofar], u->lud_filter, 0 ); + + if( sep < 5 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape_args( &s[sofar], u->lud_exts ); + +done: + s[sofar] = '\0'; + return s; +} int -ldap_url_parse( char *url, LDAPURLDesc **ludpp ) +ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) { /* * Pick apart the pieces of an LDAP URL. */ LDAPURLDesc *ludp; - char *attrs, *p, *q; - int enclosed, i, nattrs; + char *p, *q, *r; + int i, enclosed; + const char *scheme = NULL; + const char *url_tmp; + char *url; + + if( url_in == NULL || ludpp == NULL ) { + return LDAP_URL_ERR_PARAM; + } - Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url, 0, 0 ); +#ifndef LDAP_INT_IN_KERNEL + /* Global options may not be created yet + * We can't test if the global options are initialized + * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate + * the options and cause infinite recursion + */ +#ifdef NEW_LOGGING + LDAP_LOG (( "url", LDAP_LEVEL_ENTRY, "ldap_url_parse_ext(%s)\n", url_in )); +#else + Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 ); +#endif +#endif *ludpp = NULL; /* pessimistic */ - if ( !skip_url_prefix( &url, &enclosed )) { - return( LDAP_URL_ERR_NOTLDAP ); - } + url_tmp = skip_url_prefix( url_in, &enclosed, &scheme ); - /* allocate return struct */ - if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc ))) - == NULLLDAPURLDESC ) { - return( LDAP_URL_ERR_MEM ); + if ( url_tmp == NULL ) { + return LDAP_URL_ERR_BADSCHEME; } + assert( scheme ); + /* make working copy of the remainder of the URL */ - if (( url = strdup( url )) == NULL ) { - ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_MEM ); + url = LDAP_STRDUP( url_tmp ); + if ( url == NULL ) { + return LDAP_URL_ERR_MEM; } - if ( enclosed && *((p = url + strlen( url ) - 1)) == '>' ) { + if ( enclosed ) { + p = &url[strlen(url)-1]; + + if( *p != '>' ) { + LDAP_FREE( url ); + return LDAP_URL_ERR_BADENCLOSURE; + } + *p = '\0'; } - /* set defaults */ - ludp->lud_scope = LDAP_SCOPE_BASE; - ludp->lud_filter = "(objectClass=*)"; + /* allocate return struct */ + ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc )); - /* lud_string is the only malloc'd string space we use */ - ludp->lud_string = url; + if ( ludp == NULL ) { + LDAP_FREE( url ); + return LDAP_URL_ERR_MEM; + } - /* scan forward for '/' that marks end of hostport and begin. of dn */ - if (( ludp->lud_dn = strchr( url, '/' )) == NULL ) { + ludp->lud_next = NULL; + ludp->lud_host = NULL; + ludp->lud_port = 0; + ludp->lud_dn = NULL; + ludp->lud_attrs = NULL; + ludp->lud_filter = NULL; + ludp->lud_scope = LDAP_SCOPE_DEFAULT; + ludp->lud_filter = NULL; + ludp->lud_exts = NULL; + + ludp->lud_scheme = LDAP_STRDUP( scheme ); + + if ( ludp->lud_scheme == NULL ) { + LDAP_FREE( url ); ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_NODN ); + return LDAP_URL_ERR_MEM; } - /* terminate hostport; point to start of dn */ - *ludp->lud_dn++ = '\0'; + /* scan forward for '/' that marks end of hostport and begin. of dn */ + p = strchr( url, '/' ); - if (( p = strchr( url, ':' )) != NULL ) { + if( p != NULL ) { + /* terminate hostport; point to start of dn */ *p++ = '\0'; - ludp->lud_port = atoi( p ); } - if ( *url == '\0' ) { - ludp->lud_host = NULL; + /* IPv6 syntax with [ip address]:port */ + if ( *url == '[' ) { + r = strchr( url, ']' ); + if ( r == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + *r++ = '\0'; + q = strchr( r, ':' ); } else { - ludp->lud_host = url; - hex_unescape( ludp->lud_host ); - } - - /* scan for '?' that marks end of dn and beginning of attributes */ - if (( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) { - /* terminate dn; point to start of attrs. */ - *attrs++ = '\0'; - - /* scan for '?' that marks end of attrs and begin. of scope */ - if (( p = strchr( attrs, '?' )) != NULL ) { - /* - * terminate attrs; point to start of scope and scan for - * '?' that marks end of scope and begin. of filter - */ - *p++ = '\0'; - - if (( q = strchr( p, '?' )) != NULL ) { - /* terminate scope; point to start of filter */ - *q++ = '\0'; - if ( *q != '\0' ) { - ludp->lud_filter = q; - hex_unescape( ludp->lud_filter ); - } + q = strchr( url, ':' ); + } + + if ( q != NULL ) { + *q++ = '\0'; + ldap_pvt_hex_unescape( q ); + + if( *q == '\0' ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + + ludp->lud_port = atoi( q ); + } + + ldap_pvt_hex_unescape( url ); + + /* If [ip address]:port syntax, url is [ip and we skip the [ */ + ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) ); + + if( ludp->lud_host == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; + } + + /* + * Kludge. ldap://111.222.333.444:389??cn=abc,o=company + * + * On early Novell releases, search references/referrals were returned + * in this format, i.e., the dn was kind of in the scope position, + * but the required slash is missing. The whole thing is illegal syntax, + * but we need to account for it. Fortunately it can't be confused with + * anything real. + */ + if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) { + q++; + /* ? immediately followed by question */ + if( *q == '?') { + q++; + if( *q != '\0' ) { + /* parse dn part */ + ldap_pvt_hex_unescape( q ); + ludp->lud_dn = LDAP_STRDUP( q ); + } else { + ludp->lud_dn = LDAP_STRDUP( "" ); } - if ( strcasecmp( p, "one" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_ONELEVEL; - } else if ( strcasecmp( p, "base" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_BASE; - } else if ( strcasecmp( p, "sub" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_SUBTREE; - } else if ( *p != '\0' ) { + if( ludp->lud_dn == NULL ) { + LDAP_FREE( url ); ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_BADSCOPE ); + return LDAP_URL_ERR_MEM; } } } - if ( *ludp->lud_dn == '\0' ) { - ludp->lud_dn = NULL; + if( p == NULL ) { + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of dn */ + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate dn part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse dn part */ + ldap_pvt_hex_unescape( p ); + ludp->lud_dn = LDAP_STRDUP( p ); } else { - hex_unescape( ludp->lud_dn ); + ludp->lud_dn = LDAP_STRDUP( "" ); } - /* - * if attrs list was included, turn it into a null-terminated array - */ - if ( attrs != NULL && *attrs != '\0' ) { - for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) { - if ( *p == ',' ) { - ++nattrs; - } - } + if( ludp->lud_dn == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; + } + + if( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of attributes */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate attributes part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse attributes */ + ldap_pvt_hex_unescape( p ); + ludp->lud_attrs = ldap_str2charray( p, "," ); - if (( ludp->lud_attrs = (char **)calloc( nattrs + 1, - sizeof( char * ))) == NULL ) { + if( ludp->lud_attrs == NULL ) { + LDAP_FREE( url ); ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_MEM ); + return LDAP_URL_ERR_BADATTRS; } + } - for ( i = 0, p = attrs; i < nattrs; ++i ) { - ludp->lud_attrs[ i ] = p; - if (( p = strchr( p, ',' )) != NULL ) { - *p++ ='\0'; - } - hex_unescape( ludp->lud_attrs[ i ] ); + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of scope */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate the scope part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse the scope */ + ldap_pvt_hex_unescape( p ); + ludp->lud_scope = str2scope( p ); + + if( ludp->lud_scope == -1 ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADSCOPE; } } - *ludpp = ludp; + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } - return( 0 ); -} + /* scan forward for '?' that may marks end of filter */ + p = q; + q = strchr( p, '?' ); + if( q != NULL ) { + /* terminate the filter part */ + *q++ = '\0'; + } -void -ldap_free_urldesc( LDAPURLDesc *ludp ) -{ - if ( ludp != NULLLDAPURLDESC ) { - if ( ludp->lud_string != NULL ) { - free( ludp->lud_string ); + if( *p != '\0' ) { + /* parse the filter */ + ldap_pvt_hex_unescape( p ); + + if( ! *p ) { + /* missing filter */ + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADFILTER; } - if ( ludp->lud_attrs != NULL ) { - free( ludp->lud_attrs ); + + LDAP_FREE( ludp->lud_filter ); + ludp->lud_filter = LDAP_STRDUP( p ); + + if( ludp->lud_filter == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; } - free( ludp ); } -} + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of extensions */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* extra '?' */ + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + + /* parse the extensions */ + ludp->lud_exts = ldap_str2charray( p, "," ); + + if( ludp->lud_exts == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADEXTS; + } + + for( i=0; ludp->lud_exts[i] != NULL; i++ ) { + ldap_pvt_hex_unescape( ludp->lud_exts[i] ); + + if( *ludp->lud_exts[i] == '!' ) { + /* count the number of critical extensions */ + ludp->lud_crit_exts++; + } + } + + if( i == 0 ) { + /* must have 1 or more */ + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADEXTS; + } + /* no more */ + *ludpp = ludp; + LDAP_FREE( url ); + return LDAP_URL_SUCCESS; +} int -ldap_url_search( LDAP *ld, char *url, int attrsonly ) +ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) { - int err; - LDAPURLDesc *ludp; - BerElement *ber; -#ifdef LDAP_REFERRALS - LDAPServer *srv = NULL; -#endif /* LDAP_REFERRALS */ + int rc = ldap_url_parse_ext( url_in, ludpp ); - if ( ldap_url_parse( url, &ludp ) != 0 ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return( -1 ); + if( rc != LDAP_URL_SUCCESS ) { + return rc; } - if (( ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, attrsonly )) == NULLBER ) { - return( -1 ); + if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) { + (*ludpp)->lud_scope = LDAP_SCOPE_BASE; } - err = 0; + if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') { + LDAP_FREE( (*ludpp)->lud_host ); + (*ludpp)->lud_host = NULL; + } - if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) { -#ifdef LDAP_REFERRALS - if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer ))) - == NULL || ( srv->lsrv_host = strdup( ludp->lud_host == - NULL ? ld->ld_defhost : ludp->lud_host )) == NULL ) { - if ( srv != NULL ) { - free( srv ); - } - ld->ld_errno = LDAP_NO_MEMORY; - err = -1; - } else { - if ( ludp->lud_port == 0 ) { - srv->lsrv_port = LDAP_PORT; - } else { - srv->lsrv_port = ludp->lud_port; - } + if ((*ludpp)->lud_port == 0) { + if( strcmp((*ludpp)->lud_scheme, "ldap") == 0 ) { + (*ludpp)->lud_port = LDAP_PORT; +#ifdef LDAP_CONNECTIONLESS + } else if( strcmp((*ludpp)->lud_scheme, "cldap") == 0 ) { + (*ludpp)->lud_port = LDAP_PORT; +#endif + } else if( strcmp((*ludpp)->lud_scheme, "ldaps") == 0 ) { + (*ludpp)->lud_port = LDAPS_PORT; } -#else /* LDAP_REFERRALS */ - ld->ld_errno = LDAP_LOCAL_ERROR; - err = -1; -#endif /* LDAP_REFERRALS */ } - if ( err != 0 ) { - ber_free( ber, 1 ); - } else { -#ifdef LDAP_REFERRALS - err = send_server_request( ld, ber, ld->ld_msgid, NULL, srv, - NULL, 1 ); -#else /* LDAP_REFERRALS */ - err = send_initial_request( ld, LDAP_REQ_SEARCH, - ludp->lud_dn, ber ); -#endif /* LDAP_REFERRALS */ + return rc; +} + +LDAPURLDesc * +ldap_url_dup ( LDAPURLDesc *ludp ) +{ + LDAPURLDesc *dest; + + if ( ludp == NULL ) { + return NULL; } - ldap_free_urldesc( ludp ); + dest = LDAP_MALLOC( sizeof(LDAPURLDesc) ); + if (dest == NULL) + return NULL; + + *dest = *ludp; + dest->lud_scheme = NULL; + dest->lud_host = NULL; + dest->lud_dn = NULL; + dest->lud_filter = NULL; + dest->lud_attrs = NULL; + dest->lud_exts = NULL; + dest->lud_next = NULL; + + if ( ludp->lud_scheme != NULL ) { + dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme ); + if (dest->lud_scheme == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_host != NULL ) { + dest->lud_host = LDAP_STRDUP( ludp->lud_host ); + if (dest->lud_host == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_dn != NULL ) { + dest->lud_dn = LDAP_STRDUP( ludp->lud_dn ); + if (dest->lud_dn == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_filter != NULL ) { + dest->lud_filter = LDAP_STRDUP( ludp->lud_filter ); + if (dest->lud_filter == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_attrs != NULL ) { + dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs ); + if (dest->lud_attrs == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_exts != NULL ) { + dest->lud_exts = ldap_charray_dup( ludp->lud_exts ); + if (dest->lud_exts == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + return dest; +} - return( err ); +LDAPURLDesc * +ldap_url_duplist (LDAPURLDesc *ludlist) +{ + LDAPURLDesc *dest, *tail, *ludp, *newludp; + + dest = NULL; + tail = NULL; + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + newludp = ldap_url_dup(ludp); + if (newludp == NULL) { + ldap_free_urllist(dest); + return NULL; + } + if (tail == NULL) + dest = newludp; + else + tail->lud_next = newludp; + tail = newludp; + } + return dest; } +int +ldap_url_parselist (LDAPURLDesc **ludlist, const char *url ) +{ + int i, rc; + LDAPURLDesc *ludp; + char **urls; + + *ludlist = NULL; + + if (url == NULL) + return LDAP_PARAM_ERROR; + + urls = ldap_str2charray(url, ", "); + if (urls == NULL) + return LDAP_NO_MEMORY; + + /* count the URLs... */ + for (i = 0; urls[i] != NULL; i++) ; + /* ...and put them in the "stack" backward */ + while (--i >= 0) { + rc = ldap_url_parse( urls[i], &ludp ); + if ( rc != 0 ) { + ldap_charray_free(urls); + ldap_free_urllist(*ludlist); + *ludlist = NULL; + return rc; + } + ludp->lud_next = *ludlist; + *ludlist = ludp; + } + ldap_charray_free(urls); + return LDAP_SUCCESS; +} int -ldap_url_search_st( LDAP *ld, char *url, int attrsonly, - struct timeval *timeout, LDAPMessage **res ) +ldap_url_parsehosts( + LDAPURLDesc **ludlist, + const char *hosts, + int port ) { - int msgid; + int i; + LDAPURLDesc *ludp; + char **specs, *p; + + *ludlist = NULL; + + if (hosts == NULL) + return LDAP_PARAM_ERROR; + + specs = ldap_str2charray(hosts, ", "); + if (specs == NULL) + return LDAP_NO_MEMORY; + + /* count the URLs... */ + for (i = 0; specs[i] != NULL; i++) /* EMPTY */; + + /* ...and put them in the "stack" backward */ + while (--i >= 0) { + ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) ); + if (ludp == NULL) { + ldap_charray_free(specs); + ldap_free_urllist(*ludlist); + *ludlist = NULL; + return LDAP_NO_MEMORY; + } + ludp->lud_port = port; + ludp->lud_host = specs[i]; + specs[i] = NULL; + p = strchr(ludp->lud_host, ':'); + if (p != NULL) { + /* more than one :, IPv6 address */ + if ( strchr(p+1, ':') != NULL ) { + /* allow [address] and [address]:port */ + if ( *ludp->lud_host == '[' ) { + p = LDAP_STRDUP(ludp->lud_host+1); + /* copied, make sure we free source later */ + specs[i] = ludp->lud_host; + ludp->lud_host = p; + p = strchr( ludp->lud_host, ']' ); + if ( p == NULL ) + return LDAP_PARAM_ERROR; + *p++ = '\0'; + if ( *p != ':' ) { + if ( *p != '\0' ) + return LDAP_PARAM_ERROR; + p = NULL; + } + } else { + p = NULL; + } + } + if (p != NULL) { + *p++ = 0; + ldap_pvt_hex_unescape(p); + ludp->lud_port = atoi(p); + } + } + ldap_pvt_hex_unescape(ludp->lud_host); + ludp->lud_scheme = LDAP_STRDUP("ldap"); + ludp->lud_next = *ludlist; + *ludlist = ludp; + } - if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) { - return( ld->ld_errno ); + /* this should be an array of NULLs now */ + /* except entries starting with [ */ + ldap_charray_free(specs); + return LDAP_SUCCESS; +} + +char * +ldap_url_list2hosts (LDAPURLDesc *ludlist) +{ + LDAPURLDesc *ludp; + int size; + char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */ + + if (ludlist == NULL) + return NULL; + + /* figure out how big the string is */ + size = 1; /* nul-term */ + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + size += strlen(ludp->lud_host) + 1; /* host and space */ + if (strchr(ludp->lud_host, ':')) /* will add [ ] below */ + size += 2; + if (ludp->lud_port != 0) + size += sprintf(buf, ":%d", ludp->lud_port); + } + s = LDAP_MALLOC(size); + if (s == NULL) + return NULL; + + p = s; + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + if (strchr(ludp->lud_host, ':')) { + p += sprintf(p, "[%s]", ludp->lud_host); + } else { + strcpy(p, ludp->lud_host); + p += strlen(ludp->lud_host); + } + if (ludp->lud_port != 0) + p += sprintf(p, ":%d", ludp->lud_port); + *p++ = ' '; } + if (p != s) + p--; /* nuke that extra space */ + *p = 0; + return s; +} - if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) { - return( ld->ld_errno ); +char * +ldap_url_list2urls( + LDAPURLDesc *ludlist ) +{ + LDAPURLDesc *ludp; + int size; + char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */ + + if (ludlist == NULL) + return NULL; + + /* figure out how big the string is */ + size = 1; /* nul-term */ + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + size += strlen(ludp->lud_scheme) + strlen(ludp->lud_host); + if (strchr(ludp->lud_host, ':')) /* will add [ ] below */ + size += 2; + size += sizeof(":/// "); + + if (ludp->lud_port != 0) { + size += sprintf(buf, ":%d", ludp->lud_port); + } } - if ( ld->ld_errno == LDAP_TIMEOUT ) { - (void) ldap_abandon( ld, msgid ); - ld->ld_errno = LDAP_TIMEOUT; - return( ld->ld_errno ); + s = LDAP_MALLOC(size); + if (s == NULL) { + return NULL; } - return( ldap_result2error( ld, *res, 0 )); + p = s; + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + p += sprintf(p, + strchr(ludp->lud_host, ':') ? "%s://[%s]" : "%s://%s", + ludp->lud_scheme, ludp->lud_host); + if (ludp->lud_port != 0) + p += sprintf(p, ":%d", ludp->lud_port); + *p++ = '/'; + *p++ = ' '; + } + if (p != s) + p--; /* nuke that extra space */ + *p = 0; + return s; } +void +ldap_free_urllist( LDAPURLDesc *ludlist ) +{ + LDAPURLDesc *ludp, *next; -int -ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res ) + for (ludp = ludlist; ludp != NULL; ludp = next) { + next = ludp->lud_next; + ldap_free_urldesc(ludp); + } +} + +void +ldap_free_urldesc( LDAPURLDesc *ludp ) { - int msgid; + if ( ludp == NULL ) { + return; + } + + if ( ludp->lud_scheme != NULL ) { + LDAP_FREE( ludp->lud_scheme ); + } + + if ( ludp->lud_host != NULL ) { + LDAP_FREE( ludp->lud_host ); + } + + if ( ludp->lud_dn != NULL ) { + LDAP_FREE( ludp->lud_dn ); + } - if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) { - return( ld->ld_errno ); + if ( ludp->lud_filter != NULL ) { + LDAP_FREE( ludp->lud_filter); } - if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) { - return( ld->ld_errno ); + if ( ludp->lud_attrs != NULL ) { + LDAP_VFREE( ludp->lud_attrs ); } - return( ldap_result2error( ld, *res, 0 )); + if ( ludp->lud_exts != NULL ) { + LDAP_VFREE( ludp->lud_exts ); + } + + LDAP_FREE( ludp ); } +static int +ldap_int_unhex( int c ) +{ + return( c >= '0' && c <= '9' ? c - '0' + : c >= 'A' && c <= 'F' ? c - 'A' + 10 + : c - 'a' + 10 ); +} -static void -hex_unescape( char *s ) +void +ldap_pvt_hex_unescape( char *s ) { -/* - * Remove URL hex escapes from s... done in place. The basic concept for - * this routine is borrowed from the WWW library HTUnEscape() routine. - */ + /* + * Remove URL hex escapes from s... done in place. The basic concept for + * this routine is borrowed from the WWW library HTUnEscape() routine. + */ char *p; for ( p = s; *s != '\0'; ++s ) { if ( *s == '%' ) { if ( *++s != '\0' ) { - *p = unhex( *s ) << 4; + *p = ldap_int_unhex( *s ) << 4; } if ( *++s != '\0' ) { - *p++ += unhex( *s ); + *p++ += ldap_int_unhex( *s ); } } else { *p++ = *s; @@ -386,10 +1153,3 @@ hex_unescape( char *s ) } -static int -unhex( char c ) -{ - return( c >= '0' && c <= '9' ? c - '0' - : c >= 'A' && c <= 'F' ? c - 'A' + 10 - : c - 'a' + 10 ); -} diff --git a/libraries/libldap/utf-8-conv.c b/libraries/libldap/utf-8-conv.c new file mode 100644 index 0000000000000000000000000000000000000000..9b51bcd6f6c041ac52fd0743e3178bef0a1fe534 --- /dev/null +++ b/libraries/libldap/utf-8-conv.c @@ -0,0 +1,464 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* $Novell: /ldap/src/cldap/libraries/libldap/utfconv.c,v 1.3 2000/12/11 19:35:37 dsteck Exp $ */ +/****************************************************************************** + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ + +/* + * UTF-8 Conversion Routines + * + * These routines convert between Wide Character and UTF-8, + * or between MultiByte and UTF-8 encodings. + * + * Both single character and string versions of the functions are provided. + * All functions return -1 if the character or string cannot be converted. + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> /* For wctomb, wcstombs, mbtowc, mbstowcs */ +#include <ac/string.h> +#include <ac/time.h> /* for time_t */ + +#include "ldap-int.h" + +#include <ldap_utf8.h> + +static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + + +/*----------------------------------------------------------------------------- + UTF-8 Format Summary + +ASCII chars 7 bits + 0xxxxxxx + +2-character UTF-8 sequence: 11 bits + 110xxxxx 10xxxxxx + +3-character UTF-8 16 bits + 1110xxxx 10xxxxxx 10xxxxxx + +4-char UTF-8 21 bits + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +5-char UTF-8 26 bits + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + +6-char UTF-8 31 bits + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + +Unicode address space (0 - 0x10FFFF) 21 bits +ISO-10646 address space (0 - 0x7FFFFFFF) 31 bits + +Note: This code does not prevent UTF-8 sequences which are longer than + necessary from being decoded. +*/ + +/*----------------------------------------------------------------------------- + Convert a UTF-8 character to a wide char. + Return the length of the UTF-8 input character in bytes. +*/ +int +ldap_x_utf8_to_wc ( wchar_t *wchar, const char *utf8char ) +{ + int utflen, i; + wchar_t ch; + + /* If input ptr is NULL, treat it as empty string. */ + if (utf8char == NULL) + utf8char = ""; + + /* Get UTF-8 sequence length from 1st byte */ + utflen = LDAP_UTF8_CHARLEN2(utf8char, utflen); + + if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) + return -1; /* Invalid input */ + + /* First byte minus length tag */ + ch = (wchar_t)(utf8char[0] & mask[utflen]); + + for(i=1; i < utflen; i++) + { + /* Subsequent bytes must start with 10 */ + if ((utf8char[i] & 0xc0) != 0x80) + return -1; + + ch <<= 6; /* 6 bits of data in each subsequent byte */ + ch |= (wchar_t)(utf8char[i] & 0x3f); + } + + if (wchar) + *wchar = ch; + + return utflen; +} + +/*----------------------------------------------------------------------------- + Convert a UTF-8 string to a wide char string. + No more than 'count' wide chars will be written to the output buffer. + Return the size of the converted string in wide chars, excl null terminator. +*/ +int +ldap_x_utf8s_to_wcs ( wchar_t *wcstr, const char *utf8str, size_t count ) +{ + size_t wclen = 0; + int utflen, i; + wchar_t ch; + + + /* If input ptr is NULL, treat it as empty string. */ + if (utf8str == NULL) + utf8str = ""; + + /* Examine next UTF-8 character. If output buffer is NULL, ignore count */ + while ( *utf8str && (wcstr==NULL || wclen<count) ) + { + /* Get UTF-8 sequence length from 1st byte */ + utflen = LDAP_UTF8_CHARLEN2(utf8str, utflen); + + if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) + return -1; /* Invalid input */ + + /* First byte minus length tag */ + ch = (wchar_t)(utf8str[0] & mask[utflen]); + + for(i=1; i < utflen; i++) + { + /* Subsequent bytes must start with 10 */ + if ((utf8str[i] & 0xc0) != 0x80) + return -1; + + ch <<= 6; /* 6 bits of data in each subsequent byte */ + ch |= (wchar_t)(utf8str[i] & 0x3f); + } + + if (wcstr) + wcstr[wclen] = ch; + + utf8str += utflen; /* Move to next UTF-8 character */ + wclen++; /* Count number of wide chars stored/required */ + } + + /* Add null terminator if there's room in the buffer. */ + if (wcstr && wclen < count) + wcstr[wclen] = 0; + + return wclen; +} + + +/*----------------------------------------------------------------------------- + Convert one wide char to a UTF-8 character. + Return the length of the converted UTF-8 character in bytes. + No more than 'count' bytes will be written to the output buffer. +*/ +int +ldap_x_wc_to_utf8 ( char *utf8char, wchar_t wchar, size_t count ) +{ + int len=0; + + if (utf8char == NULL) /* Just determine the required UTF-8 char length. */ + { /* Ignore count */ + if( wchar < 0 ) + return -1; + if( wchar < 0x80 ) + return 1; + if( wchar < 0x800 ) + return 2; + if( wchar < 0x10000 ) + return 3; + if( wchar < 0x200000 ) + return 4; + if( wchar < 0x4000000 ) + return 5; + if( wchar < 0x80000000 ) + return 6; + return -1; + } + + + if ( wchar < 0 ) { /* Invalid wide character */ + len = -1; + + } else if( wchar < 0x80 ) { + if (count >= 1) { + utf8char[len++] = (char)wchar; + } + + } else if( wchar < 0x800 ) { + if (count >=2) { + utf8char[len++] = 0xc0 | ( wchar >> 6 ); + utf8char[len++] = 0x80 | ( wchar & 0x3f ); + } + + } else if( wchar < 0x10000 ) { + if (count >= 3) { + utf8char[len++] = 0xe0 | ( wchar >> 12 ); + utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); + utf8char[len++] = 0x80 | ( wchar & 0x3f ); + } + + } else if( wchar < 0x200000 ) { + if (count >= 4) { + utf8char[len++] = 0xf0 | ( wchar >> 18 ); + utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); + utf8char[len++] = 0x80 | ( wchar & 0x3f ); + } + + } else if( wchar < 0x4000000 ) { + if (count >= 5) { + utf8char[len++] = 0xf8 | ( wchar >> 24 ); + utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); + utf8char[len++] = 0x80 | ( wchar & 0x3f ); + } + + } else if( wchar < 0x80000000 ) { + if (count >= 6) { + utf8char[len++] = 0xfc | ( wchar >> 30 ); + utf8char[len++] = 0x80 | ( (wchar >> 24) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); + utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); + utf8char[len++] = 0x80 | ( wchar & 0x3f ); + } + + } else + len = -1; + + return len; + +} + + +/*----------------------------------------------------------------------------- + Convert a wide char string to a UTF-8 string. + No more than 'count' bytes will be written to the output buffer. + Return the # of bytes written to the output buffer, excl null terminator. +*/ +int +ldap_x_wcs_to_utf8s ( char *utf8str, const wchar_t *wcstr, size_t count ) +{ + int len = 0; + int n; + char *p = utf8str; + wchar_t empty = 0; /* To avoid use of L"" construct */ + + if (wcstr == NULL) /* Treat input ptr NULL as an empty string */ + wcstr = ∅ + + if (utf8str == NULL) /* Just compute size of output, excl null */ + { + while (*wcstr) + { + /* Get UTF-8 size of next wide char */ + n = ldap_x_wc_to_utf8( NULL, *wcstr++, LDAP_MAX_UTF8_LEN); + if (n == -1) + return -1; + len += n; + } + + return len; + } + + + /* Do the actual conversion. */ + + n = 1; /* In case of empty wcstr */ + while (*wcstr) + { + n = ldap_x_wc_to_utf8( p, *wcstr++, count); + + if (n <= 0) /* If encoding error (-1) or won't fit (0), quit */ + break; + + p += n; + count -= n; /* Space left in output buffer */ + } + + /* If not enough room for last character, pad remainder with null + so that return value = original count, indicating buffer full. */ + if (n == 0) + { + while (count--) + *p++ = 0; + } + + /* Add a null terminator if there's room. */ + else if (count) + *p = 0; + + if (n == -1) /* Conversion encountered invalid wide char. */ + return -1; + + /* Return the number of bytes written to output buffer, excl null. */ + return (p - utf8str); +} + + +/*----------------------------------------------------------------------------- + Convert a UTF-8 character to a MultiByte character. + Return the size of the converted character in bytes. +*/ +int +ldap_x_utf8_to_mb ( char *mbchar, const char *utf8char, + int (*f_wctomb)(char *mbchar, wchar_t wchar) ) +{ + wchar_t wchar; + int n; + char tmp[6]; /* Large enough for biggest multibyte char */ + + if (f_wctomb == NULL) /* If no conversion function was given... */ + f_wctomb = wctomb; /* use the local ANSI C function */ + + /* First convert UTF-8 char to a wide char */ + n = ldap_x_utf8_to_wc( &wchar, utf8char); + + if (n == -1) + return -1; /* Invalid UTF-8 character */ + + if (mbchar == NULL) + n = f_wctomb( tmp, wchar ); + else + n = f_wctomb( mbchar, wchar); + + return n; +} + +/*----------------------------------------------------------------------------- + Convert a UTF-8 string to a MultiByte string. + No more than 'count' bytes will be written to the output buffer. + Return the size of the converted string in bytes, excl null terminator. +*/ +int +ldap_x_utf8s_to_mbs ( char *mbstr, const char *utf8str, size_t count, + size_t (*f_wcstombs)(char *mbstr, const wchar_t *wcstr, size_t count) ) +{ + wchar_t *wcs; + size_t wcsize; + int n; + + if (f_wcstombs == NULL) /* If no conversion function was given... */ + f_wcstombs = wcstombs; /* use the local ANSI C function */ + + if (utf8str == NULL || *utf8str == 0) /* NULL or empty input string */ + { + if (mbstr) + *mbstr = 0; + return 0; + } + +/* Allocate memory for the maximum size wchar string that we could get. */ + wcsize = strlen(utf8str) + 1; + wcs = (wchar_t *)LDAP_MALLOC(wcsize * sizeof(wchar_t)); + if (wcs == NULL) + return -1; /* Memory allocation failure. */ + + /* First convert the UTF-8 string to a wide char string */ + n = ldap_x_utf8s_to_wcs( wcs, utf8str, wcsize); + + /* Then convert wide char string to multi-byte string */ + if (n != -1) + { + n = f_wcstombs(mbstr, wcs, count); + } + + LDAP_FREE(wcs); + + return n; +} + +/*----------------------------------------------------------------------------- + Convert a MultiByte character to a UTF-8 character. + 'mbsize' indicates the number of bytes of 'mbchar' to check. + Returns the number of bytes written to the output character. +*/ +int +ldap_x_mb_to_utf8 ( char *utf8char, const char *mbchar, size_t mbsize, + int (*f_mbtowc)(wchar_t *wchar, const char *mbchar, size_t count) ) +{ + wchar_t wchar; + int n; + + if (f_mbtowc == NULL) /* If no conversion function was given... */ + f_mbtowc = mbtowc; /* use the local ANSI C function */ + + if (mbsize == 0) /* 0 is not valid. */ + return -1; + + if (mbchar == NULL || *mbchar == 0) + { + if (utf8char) + *utf8char = 0; + return 1; + } + + /* First convert the MB char to a Wide Char */ + n = f_mbtowc( &wchar, mbchar, mbsize); + + if (n == -1) + return -1; + + /* Convert the Wide Char to a UTF-8 character. */ + n = ldap_x_wc_to_utf8( utf8char, wchar, LDAP_MAX_UTF8_LEN); + + return n; +} + + +/*----------------------------------------------------------------------------- + Convert a MultiByte string to a UTF-8 string. + No more than 'count' bytes will be written to the output buffer. + Return the size of the converted string in bytes, excl null terminator. +*/ +int +ldap_x_mbs_to_utf8s ( char *utf8str, const char *mbstr, size_t count, + size_t (*f_mbstowcs)(wchar_t *wcstr, const char *mbstr, size_t count) ) +{ + wchar_t *wcs; + int n; + size_t wcsize; + + if (mbstr == NULL) /* Treat NULL input string as an empty string */ + mbstr = ""; + + if (f_mbstowcs == NULL) /* If no conversion function was given... */ + f_mbstowcs = mbstowcs; /* use the local ANSI C function */ + + /* Allocate memory for the maximum size wchar string that we could get. */ + wcsize = strlen(mbstr) + 1; + wcs = (wchar_t *)LDAP_MALLOC( wcsize * sizeof(wchar_t) ); + if (wcs == NULL) + return -1; + + /* First convert multi-byte string to a wide char string */ + n = f_mbstowcs(wcs, mbstr, wcsize); + + /* Convert wide char string to UTF-8 string */ + if (n != -1) + { + n = ldap_x_wcs_to_utf8s( utf8str, wcs, count); + } + + LDAP_FREE(wcs); + + return n; +} diff --git a/libraries/libldap/utf-8.c b/libraries/libldap/utf-8.c new file mode 100644 index 0000000000000000000000000000000000000000..a241a6313c1f4158c223fd545999a716ee182d3e --- /dev/null +++ b/libraries/libldap/utf-8.c @@ -0,0 +1,479 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * Basic UTF-8 routines + * + * These routines are "dumb". Though they understand UTF-8, + * they don't grok Unicode. That is, they can push bits, + * but don't have a clue what the bits represent. That's + * good enough for use with the LDAP Client SDK. + * + * These routines are not optimized. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap_utf8.h" + +#include "ldap-int.h" +#include "ldap_defaults.h" + +/* + * Basic UTF-8 routines + */ + +/* + * return the number of bytes required to hold the + * NULL-terminated UTF-8 string NOT INCLUDING the + * termination. + */ +ber_len_t ldap_utf8_bytes( const char * p ) +{ + ber_len_t bytes; + + for( bytes=0; p[bytes]; bytes++ ) { + /* EMPTY */ ; + } + + return bytes; +} + +ber_len_t ldap_utf8_chars( const char * p ) +{ + /* could be optimized and could check for invalid sequences */ + ber_len_t chars=0; + + for( ; *p ; LDAP_UTF8_INCR(p) ) { + chars++; + } + + return chars; +} + +/* return offset to next character */ +int ldap_utf8_offset( const char * p ) +{ + return LDAP_UTF8_NEXT(p) - p; +} + +/* + * Returns length indicated by first byte. + */ +const char ldap_utf8_lentab[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 }; + +int ldap_utf8_charlen( const char * p ) +{ + if (!(*p & 0x80)) + return 1; + + return ldap_utf8_lentab[*(const unsigned char *)p ^ 0x80]; +} + +/* + * Make sure the UTF-8 char used the shortest possible encoding + * returns charlen if valid, 0 if not. + * + * Here are the valid UTF-8 encodings, taken from RFC 2279 page 4. + * The table is slightly modified from that of the RFC. + * + * UCS-4 range (hex) UTF-8 sequence (binary) + * 0000 0000-0000 007F 0....... + * 0000 0080-0000 07FF 110++++. 10...... + * 0000 0800-0000 FFFF 1110++++ 10+..... 10...... + * 0001 0000-001F FFFF 11110+++ 10++.... 10...... 10...... + * 0020 0000-03FF FFFF 111110++ 10+++... 10...... 10...... 10...... + * 0400 0000-7FFF FFFF 1111110+ 10++++.. 10...... 10...... 10...... 10...... + * + * The '.' bits are "don't cares". When validating a UTF-8 sequence, + * at least one of the '+' bits must be set, otherwise the character + * should have been encoded in fewer octets. Note that in the two-octet + * case, only the first octet needs to be validated, and this is done + * in the ldap_utf8_lentab[] above. + */ + +/* mask of required bits in second octet */ +#undef c +#define c const char +c ldap_utf8_mintab[] = { + (c)0x20, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, + (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, + (c)0x30, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, + (c)0x38, (c)0x80, (c)0x80, (c)0x80, (c)0x3c, (c)0x80, (c)0x00, (c)0x00 }; +#undef c + +int ldap_utf8_charlen2( const char * p ) +{ + int i = LDAP_UTF8_CHARLEN( p ); + + if ( i > 2 ) { + if ( !( ldap_utf8_mintab[*p & 0x1f] & p[1] ) ) + i = 0; + } + return i; +} + +/* conv UTF-8 to UCS-4, useful for comparisons */ +ldap_ucs4_t ldap_x_utf8_to_ucs4( const char * p ) +{ + const unsigned char *c = p; + ldap_ucs4_t ch; + int len, i; + static unsigned char mask[] = { + 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + + len = LDAP_UTF8_CHARLEN2(p, len); + + if( len == 0 ) return LDAP_UCS4_INVALID; + + ch = c[0] & mask[len]; + + for(i=1; i < len; i++) { + if ((c[i] & 0xc0) != 0x80) { + return LDAP_UCS4_INVALID; + } + + ch <<= 6; + ch |= c[i] & 0x3f; + } + + return ch; +} + +/* conv UCS-4 to UTF-8, not used */ +int ldap_x_ucs4_to_utf8( ldap_ucs4_t c, char *buf ) +{ + int len=0; + unsigned char* p = buf; + if(buf == NULL) return 0; + + if ( c < 0 ) { + /* not a valid Unicode character */ + + } else if( c < 0x80 ) { + p[len++] = c; + + } else if( c < 0x800 ) { + p[len++] = 0xc0 | ( c >> 6 ); + p[len++] = 0x80 | ( c & 0x3f ); + + } else if( c < 0x10000 ) { + p[len++] = 0xe0 | ( c >> 12 ); + p[len++] = 0x80 | ( (c >> 6) & 0x3f ); + p[len++] = 0x80 | ( c & 0x3f ); + + } else if( c < 0x200000 ) { + p[len++] = 0xf0 | ( c >> 18 ); + p[len++] = 0x80 | ( (c >> 12) & 0x3f ); + p[len++] = 0x80 | ( (c >> 6) & 0x3f ); + p[len++] = 0x80 | ( c & 0x3f ); + + } else if( c < 0x4000000 ) { + p[len++] = 0xf8 | ( c >> 24 ); + p[len++] = 0x80 | ( (c >> 18) & 0x3f ); + p[len++] = 0x80 | ( (c >> 12) & 0x3f ); + p[len++] = 0x80 | ( (c >> 6) & 0x3f ); + p[len++] = 0x80 | ( c & 0x3f ); + + } else /* if( c < 0x80000000 ) */ { + p[len++] = 0xfc | ( c >> 30 ); + p[len++] = 0x80 | ( (c >> 24) & 0x3f ); + p[len++] = 0x80 | ( (c >> 18) & 0x3f ); + p[len++] = 0x80 | ( (c >> 12) & 0x3f ); + p[len++] = 0x80 | ( (c >> 6) & 0x3f ); + p[len++] = 0x80 | ( c & 0x3f ); + } + + buf[len] = '\0'; + return len; +} + +/* + * Advance to the next UTF-8 character + * + * Ignores length of multibyte character, instead rely on + * continuation markers to find start of next character. + * This allows for "resyncing" of when invalid characters + * are provided provided the start of the next character + * is appears within the 6 bytes examined. + */ +char* ldap_utf8_next( const char * p ) +{ + int i; + const unsigned char *u = p; + + if( LDAP_UTF8_ISASCII(u) ) { + return (char *) &p[1]; + } + + for( i=1; i<6; i++ ) { + if ( ( u[i] & 0xc0 ) != 0x80 ) { + return (char *) &p[i]; + } + } + + return (char *) &p[i]; +} + +/* + * Advance to the previous UTF-8 character + * + * Ignores length of multibyte character, instead rely on + * continuation markers to find start of next character. + * This allows for "resyncing" of when invalid characters + * are provided provided the start of the next character + * is appears within the 6 bytes examined. + */ +char* ldap_utf8_prev( const char * p ) +{ + int i; + const unsigned char *u = p; + + for( i=-1; i>-6 ; i-- ) { + if ( ( u[i] & 0xc0 ) != 0x80 ) { + return (char *) &p[i]; + } + } + + return (char *) &p[i]; +} + +/* + * Copy one UTF-8 character from src to dst returning + * number of bytes copied. + * + * Ignores length of multibyte character, instead rely on + * continuation markers to find start of next character. + * This allows for "resyncing" of when invalid characters + * are provided provided the start of the next character + * is appears within the 6 bytes examined. + */ +int ldap_utf8_copy( char* dst, const char *src ) +{ + int i; + const unsigned char *u = src; + + dst[0] = src[0]; + + if( LDAP_UTF8_ISASCII(u) ) { + return 1; + } + + for( i=1; i<6; i++ ) { + if ( ( u[i] & 0xc0 ) != 0x80 ) { + return i; + } + dst[i] = src[i]; + } + + return i; +} + +#ifndef UTF8_ALPHA_CTYPE +/* + * UTF-8 ctype routines + * Only deals with characters < 0x80 (ie: US-ASCII) + */ + +int ldap_utf8_isascii( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + return LDAP_ASCII(c); +} + +int ldap_utf8_isdigit( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_DIGIT( c ); +} + +int ldap_utf8_isxdigit( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_HEX(c); +} + +int ldap_utf8_isspace( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + switch(c) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\v': + case '\f': + return 1; + } + + return 0; +} + +/* + * These are not needed by the C SDK and are + * not "good enough" for general use. + */ +int ldap_utf8_isalpha( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_ALPHA(c); +} + +int ldap_utf8_isalnum( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_ALNUM(c); +} + +int ldap_utf8_islower( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_LOWER(c); +} + +int ldap_utf8_isupper( const char * p ) +{ + unsigned c = * (const unsigned char *) p; + + if(!LDAP_ASCII(c)) return 0; + + return LDAP_UPPER(c); +} +#endif + + +/* + * UTF-8 string routines + */ + +/* like strchr() */ +char * (ldap_utf8_strchr)( const char *str, const char *chr ) +{ + for( ; *str != '\0'; LDAP_UTF8_INCR(str) ) { + if( ldap_x_utf8_to_ucs4( str ) == ldap_x_utf8_to_ucs4( chr ) ) { + return (char *) str; + } + } + + return NULL; +} + +/* like strcspn() but returns number of bytes, not characters */ +ber_len_t (ldap_utf8_strcspn)( const char *str, const char *set ) +{ + const char *cstr; + const char *cset; + + for( cstr = str; *cstr != '\0'; LDAP_UTF8_INCR(cstr) ) { + for( cset = set; *cset != '\0'; LDAP_UTF8_INCR(cset) ) { + if( ldap_x_utf8_to_ucs4( cstr ) == ldap_x_utf8_to_ucs4( cset ) ) { + return cstr - str; + } + } + } + + return cstr - str; +} + +/* like strspn() but returns number of bytes, not characters */ +ber_len_t (ldap_utf8_strspn)( const char *str, const char *set ) +{ + const char *cstr; + const char *cset; + + for( cstr = str; *cstr != '\0'; LDAP_UTF8_INCR(cstr) ) { + for( cset = set; ; LDAP_UTF8_INCR(cset) ) { + if( *cset == '\0' ) { + return cstr - str; + } + + if( ldap_x_utf8_to_ucs4( cstr ) == ldap_x_utf8_to_ucs4( cset ) ) { + break; + } + } + } + + return cstr - str; +} + +/* like strpbrk(), replaces strchr() as well */ +char *(ldap_utf8_strpbrk)( const char *str, const char *set ) +{ + for( ; *str != '\0'; LDAP_UTF8_INCR(str) ) { + const char *cset; + + for( cset = set; *cset != '\0'; LDAP_UTF8_INCR(cset) ) { + if( ldap_x_utf8_to_ucs4( str ) == ldap_x_utf8_to_ucs4( cset ) ) { + return (char *) str; + } + } + } + + return NULL; +} + +/* like strtok_r(), not strtok() */ +char *(ldap_utf8_strtok)(char *str, const char *sep, char **last) +{ + char *begin; + char *end; + + if( last == NULL ) return NULL; + + begin = str ? str : *last; + + begin += ldap_utf8_strspn( begin, sep ); + + if( *begin == '\0' ) { + *last = NULL; + return NULL; + } + + end = &begin[ ldap_utf8_strcspn( begin, sep ) ]; + + if( *end != '\0' ) { + char *next = LDAP_UTF8_NEXT( end ); + *end = '\0'; + end = next; + } + + *last = end; + return begin; +} diff --git a/libraries/libldap_r/tpool.c b/libraries/libldap_r/tpool.c new file mode 100644 index 0000000000000000000000000000000000000000..923a1b9ce4e23c94e543c87b1e8fab17288e8744 --- /dev/null +++ b/libraries/libldap_r/tpool.c @@ -0,0 +1,419 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA + * 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 <ac/stdarg.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" +#include "ldap_pvt_thread.h" +#include "ldap_queue.h" + +#ifndef LDAP_THREAD_HAVE_TPOOL + +enum ldap_int_thread_pool_state { + LDAP_INT_THREAD_POOL_RUNNING, + LDAP_INT_THREAD_POOL_FINISHING, + LDAP_INT_THREAD_POOL_STOPPING +}; + +typedef struct ldap_int_thread_ctx_s { + union { + LDAP_STAILQ_ENTRY(ldap_int_thread_ctx_s) q; + LDAP_SLIST_ENTRY(ldap_int_thread_ctx_s) l; + } ltc_next; + void *(*ltc_start_routine)( void *); + void *ltc_arg; +} ldap_int_thread_ctx_t; + +struct ldap_int_thread_pool_s { + LDAP_STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next; + ldap_pvt_thread_mutex_t ltp_mutex; + ldap_pvt_thread_cond_t ltp_cond; + LDAP_STAILQ_HEAD(tcq, ldap_int_thread_ctx_s) ltp_pending_list; + LDAP_SLIST_HEAD(tcl, ldap_int_thread_ctx_s) ltp_free_list; + long ltp_state; + long ltp_max_count; + long ltp_max_pending; + long ltp_pending_count; + long ltp_active_count; + long ltp_open_count; + long ltp_starting; +}; + +static LDAP_STAILQ_HEAD(tpq, ldap_int_thread_pool_s) + ldap_int_thread_pool_list = + LDAP_STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list); + +static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex; + +static void *ldap_int_thread_pool_wrapper( void *pool ); + +int +ldap_int_thread_pool_startup ( void ) +{ + return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex); +} + +int +ldap_int_thread_pool_shutdown ( void ) +{ + struct ldap_int_thread_pool_s *pool; + + while ((pool = LDAP_STAILQ_FIRST(&ldap_int_thread_pool_list)) != NULL) { + LDAP_STAILQ_REMOVE_HEAD(&ldap_int_thread_pool_list, ltp_next); + ldap_pvt_thread_pool_destroy( &pool, 0); + } + ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex); + return(0); +} + +int +ldap_pvt_thread_pool_init ( + ldap_pvt_thread_pool_t *tpool, + int max_threads, + int max_pending ) +{ + ldap_pvt_thread_pool_t pool; + int rc; + + *tpool = NULL; + pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1, + sizeof(struct ldap_int_thread_pool_s)); + + if (pool == NULL) return(-1); + + rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex); + if (rc != 0) + return(rc); + rc = ldap_pvt_thread_cond_init(&pool->ltp_cond); + if (rc != 0) + return(rc); + pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING; + pool->ltp_max_count = max_threads; + pool->ltp_max_pending = max_pending; + LDAP_STAILQ_INIT(&pool->ltp_pending_list); + LDAP_SLIST_INIT(&pool->ltp_free_list); + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + LDAP_STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next); + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); + +#if 0 + /* THIS WILL NOT WORK on some systems. If the process + * forks after starting a thread, there is no guarantee + * that the thread will survive the fork. For example, + * slapd forks in order to daemonize, and does so after + * calling ldap_pvt_thread_pool_init. On some systems, + * this initial thread does not run in the child process, + * but ltp_open_count == 1, so two things happen: + * 1) the first client connection fails, and 2) when + * slapd is kill'ed, it never terminates since it waits + * for all worker threads to exit. */ + + /* start up one thread, just so there is one. no need to + * lock the mutex right now, since no threads are running. + */ + pool->ltp_open_count++; + + ldap_pvt_thread_t thr; + rc = ldap_pvt_thread_create( &thr, 1, ldap_int_thread_pool_wrapper, pool ); + + if( rc != 0) { + /* couldn't start one? then don't start any */ + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + LDAP_STAILQ_REMOVE(ldap_int_thread_pool_list, pool, + ldap_int_thread_pool_s, ltp_next); + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); + ldap_pvt_thread_cond_destroy(&pool->ltp_cond); + ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex); + LDAP_FREE(pool); + return(-1); + } +#endif + + *tpool = pool; + return(0); +} + +int +ldap_pvt_thread_pool_submit ( + ldap_pvt_thread_pool_t *tpool, + void *(*start_routine)( void * ), void *arg ) +{ + struct ldap_int_thread_pool_s *pool; + ldap_int_thread_ctx_t *ctx; + int need_thread = 0; + ldap_pvt_thread_t thr; + + if (tpool == NULL) + return(-1); + + pool = *tpool; + + if (pool == NULL) + return(-1); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING + || (pool->ltp_max_pending > 0 + && pool->ltp_pending_count >= pool->ltp_max_pending)) + { + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + return(-1); + } + ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list); + if (ctx) { + LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l); + } else { + ctx = (ldap_int_thread_ctx_t *) LDAP_MALLOC( + sizeof(ldap_int_thread_ctx_t)); + if (ctx == NULL) { + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + return(-1); + } + } + + ctx->ltc_start_routine = start_routine; + ctx->ltc_arg = arg; + + pool->ltp_pending_count++; + LDAP_STAILQ_INSERT_TAIL(&pool->ltp_pending_list, ctx, ltc_next.q); + ldap_pvt_thread_cond_signal(&pool->ltp_cond); + if ((pool->ltp_open_count <= 0 + || pool->ltp_pending_count > 1 + || pool->ltp_open_count == pool->ltp_active_count) + && (pool->ltp_max_count <= 0 + || pool->ltp_open_count < pool->ltp_max_count)) + { + pool->ltp_open_count++; + pool->ltp_starting++; + need_thread = 1; + } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + + if (need_thread) { + int rc = ldap_pvt_thread_create( &thr, 1, + ldap_int_thread_pool_wrapper, pool ); + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + if (rc == 0) { + pool->ltp_starting--; + } else { + /* couldn't create thread. back out of + * ltp_open_count and check for even worse things. + */ + pool->ltp_open_count--; + pool->ltp_starting--; + if (pool->ltp_open_count == 0) { + /* no open threads at all?!? + */ + ldap_int_thread_ctx_t *ptr; + LDAP_STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltc_next.q) + if (ptr == ctx) break; + if (ptr == ctx) { + /* no open threads, context not handled, so + * back out of ltp_pending_count, free the context, + * report the error. + */ + LDAP_STAILQ_REMOVE(&pool->ltp_pending_list, ctx, + ldap_int_thread_ctx_s, ltc_next.q); + pool->ltp_pending_count++; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + LDAP_FREE(ctx); + return(-1); + } + } + /* there is another open thread, so this + * context will be handled eventually. + * continue on and signal that the context + * is waiting. + */ + } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + } + + return(0); +} + +int +ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads ) +{ + struct ldap_int_thread_pool_s *pool; + + if (tpool == NULL) + return(-1); + + pool = *tpool; + + if (pool == NULL) + return(-1); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + pool->ltp_max_count = max_threads; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + return(0); +} + +int +ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool ) +{ + struct ldap_int_thread_pool_s *pool; + int count; + + if (tpool == NULL) + return(-1); + + pool = *tpool; + + if (pool == NULL) + return(0); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + count = pool->ltp_pending_count + pool->ltp_active_count; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + return(count); +} + +int +ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) +{ + struct ldap_int_thread_pool_s *pool, *pptr; + long waiting; + ldap_int_thread_ctx_t *ctx; + + if (tpool == NULL) + return(-1); + + pool = *tpool; + + if (pool == NULL) return(-1); + + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + LDAP_STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next) + if (pptr == pool) break; + if (pptr == pool) + LDAP_STAILQ_REMOVE(&ldap_int_thread_pool_list, pool, + ldap_int_thread_pool_s, ltp_next); + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); + + if (pool != pptr) return(-1); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + pool->ltp_state = run_pending + ? LDAP_INT_THREAD_POOL_FINISHING + : LDAP_INT_THREAD_POOL_STOPPING; + waiting = pool->ltp_open_count; + + /* broadcast could be used here, but only after + * it is fixed in the NT thread implementation + */ + while (--waiting >= 0) { + ldap_pvt_thread_cond_signal(&pool->ltp_cond); + } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + + do { + ldap_pvt_thread_yield(); + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + waiting = pool->ltp_open_count; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + } while (waiting > 0); + + while ((ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list)) != NULL) + { + LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q); + LDAP_FREE(ctx); + } + + while ((ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list)) != NULL) + { + LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l); + LDAP_FREE(ctx); + } + + ldap_pvt_thread_cond_destroy(&pool->ltp_cond); + ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex); + LDAP_FREE(pool); + return(0); +} + +static void * +ldap_int_thread_pool_wrapper ( + void *xpool ) +{ + struct ldap_int_thread_pool_s *pool = xpool; + ldap_int_thread_ctx_t *ctx; + + if (pool == NULL) + return NULL; + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + + while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) { + ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list); + if (ctx) { + LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q); + } else { + if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING) + break; + if (pool->ltp_max_count > 0 + && pool->ltp_open_count > pool->ltp_max_count) + { + /* too many threads running (can happen if the + * maximum threads value is set during ongoing + * operation using ldap_pvt_thread_pool_maxthreads) + * so let this thread die. + */ + break; + } + + /* we could check an idle timer here, and let the + * thread die if it has been inactive for a while. + * only die if there are other open threads (i.e., + * always have at least one thread open). the check + * should be like this: + * if (pool->ltp_open_count > 1 && pool->ltp_starting == 0) + * check timer, leave thread (break;) + */ + + if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING) + ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); + + continue; + } + + pool->ltp_pending_count--; + pool->ltp_active_count++; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + + (ctx->ltc_start_routine)(ctx->ltc_arg); + LDAP_SLIST_INSERT_HEAD(&pool->ltp_free_list, ctx, ltc_next.l); + ldap_pvt_thread_yield(); + + /* if we use an idle timer, here's + * a good place to update it + */ + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + pool->ltp_active_count--; + } + + pool->ltp_open_count--; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + + ldap_pvt_thread_exit(NULL); + return(NULL); +} +#endif /* LDAP_HAVE_THREAD_POOL */ diff --git a/libraries/libldif/line64.c b/libraries/libldif/line64.c index 54832f21a750f3cada79f6f5c1e939ed544d08f5..3f16c95d600a5a24c213d1dae8d76f0b99d04582 100644 --- a/libraries/libldif/line64.c +++ b/libraries/libldif/line64.c @@ -1,22 +1,42 @@ /* line64.c - routines for dealing with the slapd line format */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "lber.h" -#include "ldap.h" + +#include <ac/stdlib.h> +#include <ac/ctype.h> + +#include <ac/string.h> +#include <ac/socket.h> +#include <ac/time.h> + +int ldif_debug = 0; + +#include "ldap_log.h" +#include "lber_pvt.h" #include "ldif.h" #define RIGHT2 0x03 #define RIGHT4 0x0f -#define CONTINUED_LINE_MARKER '\001' +#define CONTINUED_LINE_MARKER '\r' + +#ifdef CSRIMALLOC +#define ber_memalloc malloc +#define ber_memcalloc calloc +#define ber_memrealloc realloc +#define ber_strdup strdup +#endif -static char nib2b64[0x40f] = +static const char nib2b64[0x40] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static unsigned char b642nib[0x80] = { +static const unsigned char b642nib[0x80] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -36,64 +56,85 @@ static unsigned char b642nib[0x80] = { }; /* - * str_parse_line - takes a line of the form "type:[:] value" and splits it + * ldif_parse_line - takes a line of the form "type:[:] value" and splits it * into components "type" and "value". if a double colon separates type from * value, then value is encoded in base 64, and parse_line un-decodes it * (in place) before returning. */ int -str_parse_line( - char *line, - char **type, - char **value, - int *vlen +ldif_parse_line( + LDAP_CONST char *line, + char **typep, + char **valuep, + ber_len_t *vlenp ) { - char *p, *s, *d, *byte, *stop; + char *s, *p, *d; char nib; - int i, b64; + int b64, url; + char *freeme, *type, *value; + ber_len_t vlen; + + *typep = NULL; + *valuep = NULL; + *vlenp = 0; /* skip any leading space */ - while ( isspace( *line ) ) { + while ( isspace( (unsigned char) *line ) ) { line++; } - *type = line; - for ( s = line; *s && *s != ':'; s++ ) - ; /* NULL */ - if ( *s == '\0' ) { - Debug( LDAP_DEBUG_PARSE, "parse_line missing ':'\n", 0, 0, 0 ); + freeme = ber_strdup( line ); + + if( freeme == NULL ) { + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_parse_line: line malloc failed\n"); + return( -1 ); + } + + type = freeme; + + s = strchr( type, ':' ); + + if ( s == NULL ) { + ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, + "ldif_parse_line: missing ':' after %s\n", + type ); + ber_memfree( freeme ); return( -1 ); } /* trim any space between type and : */ - for ( p = s - 1; p > line && isspace( *p ); p-- ) { + for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) { *p = '\0'; } *s++ = '\0'; - /* check for double : - indicates base 64 encoded value */ - if ( *s == ':' ) { + url = 0; + b64 = 0; + + if ( *s == '\0' ) { + /* no value */ + value = ""; + vlen = 0; + goto done; + } + + if ( *s == '<' ) { + s++; + url = 1; + } else if ( *s == ':' ) { + /* base 64 encoded value */ s++; b64 = 1; - - /* single : - normally encoded value */ - } else { - b64 = 0; } /* skip space between : and value */ - while ( isspace( *s ) ) { + while ( isspace( (unsigned char) *s ) ) { s++; } - /* if no value is present, error out */ - if ( *s == '\0' ) { - Debug( LDAP_DEBUG_PARSE, "parse_line missing value\n", 0,0,0 ); - return( -1 ); - } - /* check for continued line markers that should be deleted */ for ( p = s, d = s; *p; p++ ) { if ( *p != CONTINUED_LINE_MARKER ) @@ -101,17 +142,31 @@ str_parse_line( } *d = '\0'; - *value = s; + /* if no value is present, error out */ + if ( *s == '\0' ) { + ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, + "ldif_parse_line: %s missing %svalue\n", type, + url ? "URL " : b64 ? "base64 " : "" ); + value = NULL; + vlen = 0; + goto done; + } + if ( b64 ) { - stop = strchr( s, '\0' ); - byte = s; - for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) { - for ( i = 0; i < 3; i++ ) { + char *byte = s; + + value = s; + + for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) { + int i; + for ( i = 0; i < 4; i++ ) { if ( p[i] != '=' && (p[i] & 0x80 || b642nib[ p[i] & 0x7f ] > 0x3f) ) { - Debug( LDAP_DEBUG_ANY, - "invalid base 64 encoding char (%c) 0x%x\n", - p[i], p[i], 0 ); + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_parse_line: %s: invalid base64 encoding" + " char (%c) 0x%x\n", + type, p[i], p[i] ); + ber_memfree( freeme ); return( -1 ); } } @@ -125,7 +180,7 @@ str_parse_line( byte[1] = (nib & RIGHT4) << 4; /* third digit */ if ( p[2] == '=' ) { - *vlen += 1; + vlen += 1; break; } nib = b642nib[ p[2] & 0x7f ]; @@ -133,7 +188,7 @@ str_parse_line( byte[2] = (nib & RIGHT2) << 6; /* fourth digit */ if ( p[3] == '=' ) { - *vlen += 2; + vlen += 2; break; } nib = b642nib[ p[3] & 0x7f ]; @@ -141,143 +196,307 @@ str_parse_line( byte += 3; } - s[ *vlen ] = '\0'; + s[ vlen ] = '\0'; + + } else if ( url ) { + if( ldif_fetch_url( s, &value, &vlen ) ) { + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_parse_line: %s: URL \"%s\" fetch failed\n", + type, s ); + ber_memfree( freeme ); + return( -1 ); + } + } else { - *vlen = (int) (d - s); + value = s; + vlen = (int) (d - s); + } + +done: + type = ber_strdup( type ); + + if( type == NULL ) { + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_parse_line: type malloc failed\n"); + ber_memfree( freeme ); + return( -1 ); + } + + if( !url && value != NULL ) { + p = ber_memalloc( vlen + 1 ); + if( p == NULL ) { + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_parse_line: value malloc failed\n"); + ber_memfree( type ); + ber_memfree( freeme ); + return( -1 ); + } + AC_MEMCPY( p, value, vlen ); + p[vlen] = '\0'; + value = p; } + ber_memfree( freeme ); + + *typep = type; + *valuep = value; + *vlenp = vlen; + return( 0 ); } /* - * str_getline - return the next "line" (minus newline) of input from a + * ldif_getline - return the next "line" (minus newline) of input from a * string buffer of lines separated by newlines, terminated by \n\n * or \0. this routine handles continued lines, bundling them into * a single big line before returning. if a line begins with a white * space character, it is a continuation of the previous line. the white * space character (nb: only one char), and preceeding newline are changed * into CONTINUED_LINE_MARKER chars, to be deleted later by the - * str_parse_line() routine above. + * ldif_parse_line() routine above. * - * it takes a pointer to a pointer to the buffer on the first call, + * ldif_getline will skip over any line which starts '#'. + * + * ldif_getline takes a pointer to a pointer to the buffer on the first call, * which it updates and must be supplied on subsequent calls. */ char * -str_getline( char **next ) +ldif_getline( char **next ) { - char *l; - char c; + char *line; - if ( *next == NULL || **next == '\n' || **next == '\0' ) { - return( NULL ); - } + do { + if ( *next == NULL || **next == '\n' || **next == '\0' ) { + return( NULL ); + } + + line = *next; + + while ( (*next = strchr( *next, '\n' )) != NULL ) { +#if CONTINUED_LINE_MARKER != '\r' + if ( (*next)[-1] == '\r' ) { + (*next)[-1] = CONTINUED_LINE_MARKER; + } +#endif + + if ( (*next)[1] != ' ' ) { + if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) { + *(*next)++ = '\0'; + } + *(*next)++ = '\0'; + break; + } - l = *next; - while ( (*next = strchr( *next, '\n' )) != NULL ) { - c = *(*next + 1); - if ( isspace( c ) && c != '\n' ) { **next = CONTINUED_LINE_MARKER; - *(*next+1) = CONTINUED_LINE_MARKER; - } else { - *(*next)++ = '\0'; - break; + (*next)[1] = CONTINUED_LINE_MARKER; + (*next)++; } - *(*next)++; - } + } while( *line == '#' ); - return( l ); + return( line ); } +/* compatibility with U-Mich off by one bug */ +#define LDIF_KLUDGE 1 + void -put_type_and_value( char **out, char *t, char *val, int vlen ) +ldif_sput( + char **out, + int type, + LDAP_CONST char *name, + LDAP_CONST char *val, + ber_len_t vlen ) { - unsigned char *byte, *p, *stop; + const unsigned char *byte, *stop; unsigned char buf[3]; unsigned long bits; char *save; - int i, b64, pad, len, savelen; - len = 0; + int pad; + int namelen = 0; + + ber_len_t savelen; + ber_len_t len=0; + ber_len_t i; + + /* prefix */ + switch( type ) { + case LDIF_PUT_COMMENT: + *(*out)++ = '#'; + len++; + + if( vlen ) { + *(*out)++ = ' '; + len++; + } + + break; - /* put the type + ": " */ - for ( p = (unsigned char *) t; *p; p++, len++ ) { - *(*out)++ = *p; + case LDIF_PUT_SEP: + *(*out)++ = '\n'; + return; } - *(*out)++ = ':'; - len++; + + /* name (attribute type) */ + if( name != NULL ) { + /* put the name + ":" */ + namelen = strlen(name); + strcpy(*out, name); + *out += namelen; + len += namelen; + + if( type != LDIF_PUT_COMMENT ) { + *(*out)++ = ':'; + len++; + } + + } +#ifdef LDAP_DEBUG + else { + assert( type == LDIF_PUT_COMMENT ); + } +#endif + + if( vlen == 0 ) { + *(*out)++ = '\n'; + return; + } + + switch( type ) { + case LDIF_PUT_NOVALUE: + *(*out)++ = '\n'; + return; + + case LDIF_PUT_URL: /* url value */ + *(*out)++ = '<'; + len++; + break; + + case LDIF_PUT_B64: /* base64 value */ + *(*out)++ = ':'; + len++; + break; + } + + switch( type ) { + case LDIF_PUT_TEXT: + case LDIF_PUT_URL: + case LDIF_PUT_B64: + *(*out)++ = ' '; + len++; + /* fall-thru */ + + case LDIF_PUT_COMMENT: + /* pre-encoded names */ + for ( i=0; i < vlen; i++ ) { + if ( len > LDIF_LINE_WIDTH ) { + *(*out)++ = '\n'; + *(*out)++ = ' '; + len = 1; + } + + *(*out)++ = val[i]; + len++; + } + *(*out)++ = '\n'; + return; + } + save = *out; savelen = len; + *(*out)++ = ' '; - b64 = 0; + len++; - stop = (unsigned char *) (val + vlen); - if ( isascii( val[0] ) && isspace( val[0] ) || val[0] == ':' ) { - b64 = 1; - } else { - for ( byte = (unsigned char *) val; byte < stop; - byte++, len++ ) { + stop = (const unsigned char *) (val + vlen); + + if ( type == LDIF_PUT_VALUE + && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' + && isgraph( (unsigned char) val[vlen-1] ) +#ifndef LDAP_BINARY_DEBUG + && strstr( name, ";binary" ) == NULL +#endif +#ifndef LDAP_PASSWD_DEBUG + && (namelen != (sizeof("userPassword")-1) + || strcasecmp( name, "userPassword" ) != 0) /* encode userPassword */ + && (namelen != (sizeof("2.5.4.35")-1) + || strcasecmp( name, "2.5.4.35" ) != 0) /* encode userPassword */ +#endif + ) { + int b64 = 0; + + for ( byte = (const unsigned char *) val; byte < stop; + byte++, len++ ) + { if ( !isascii( *byte ) || !isprint( *byte ) ) { b64 = 1; break; } - if ( len > LINE_WIDTH ) { + if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) { *(*out)++ = '\n'; *(*out)++ = ' '; len = 1; } *(*out)++ = *byte; } + + if( !b64 ) { + *(*out)++ = '\n'; + return; + } } - if ( b64 ) { - *out = save; - *(*out)++ = ':'; - *(*out)++ = ' '; - len = savelen + 2; - /* convert to base 64 (3 bytes => 4 base 64 digits) */ - for ( byte = (unsigned char *) val; byte < stop - 2; - byte += 3 ) { - bits = (byte[0] & 0xff) << 16; - bits |= (byte[1] & 0xff) << 8; - bits |= (byte[2] & 0xff); - - for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { - if ( len > LINE_WIDTH ) { - *(*out)++ = '\n'; - *(*out)++ = ' '; - len = 1; - } - /* get b64 digit from high order 6 bits */ - *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; + *out = save; + *(*out)++ = ':'; + *(*out)++ = ' '; + len = savelen + 2; + + /* convert to base 64 (3 bytes => 4 base 64 digits) */ + for ( byte = (const unsigned char *) val; + byte < stop - 2; + byte += 3 ) + { + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { + if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) { + *(*out)++ = '\n'; + *(*out)++ = ' '; + len = 1; } + + /* get b64 digit from high order 6 bits */ + *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; } + } - /* add padding if necessary */ - if ( byte < stop ) { - for ( i = 0; byte + i < stop; i++ ) { - buf[i] = byte[i]; - } - for ( pad = 0; i < 3; i++, pad++ ) { - buf[i] = '\0'; + /* add padding if necessary */ + if ( byte < stop ) { + for ( i = 0; byte + i < stop; i++ ) { + buf[i] = byte[i]; + } + for ( pad = 0; i < 3; i++, pad++ ) { + buf[i] = '\0'; + } + byte = buf; + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { + if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) { + *(*out)++ = '\n'; + *(*out)++ = ' '; + len = 1; } - byte = buf; - bits = (byte[0] & 0xff) << 16; - bits |= (byte[1] & 0xff) << 8; - bits |= (byte[2] & 0xff); - - for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { - if ( len > LINE_WIDTH ) { - *(*out)++ = '\n'; - *(*out)++ = ' '; - len = 1; - } + if( i + pad < 4 ) { /* get b64 digit from low order 6 bits */ *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; - } - - for ( ; pad > 0; pad-- ) { - *(*out - pad) = '='; + } else { + *(*out)++ = '='; } } } @@ -285,23 +504,117 @@ put_type_and_value( char **out, char *t, char *val, int vlen ) } -char * -ldif_type_and_value( char *type, char *val, int vlen ) /* - * return malloc'd, zero-terminated LDIF line + * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line */ +char * +ldif_put( + int type, + LDAP_CONST char *name, + LDAP_CONST char *val, + ber_len_t vlen ) { char *buf, *p; - int tlen; + ber_len_t nlen; + + nlen = ( name != NULL ) ? strlen( name ) : 0; - tlen = strlen( type ); - if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) != - NULL ) { + buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 ); + + if ( buf == NULL ) { + ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, + "ldif_type_and_value: malloc failed!" ); + return NULL; } p = buf; - put_type_and_value( &p, type, val, vlen ); + ldif_sput( &p, type, name, val, vlen ); *p = '\0'; return( buf ); } + +int ldif_is_not_printable( + LDAP_CONST char *val, + ber_len_t vlen ) +{ + if( vlen == 0 || val == NULL ) { + return -1; + } + + if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' && + isgraph( (unsigned char) val[vlen-1] ) ) + { + ber_len_t i; + + for ( i = 0; val[i]; i++ ) { + if ( !isascii( val[i] ) || !isprint( val[i] ) ) { + return 1; + } + } + + return 0; + } + + return 1; +} + +/* + * slap_read_ldif - read an ldif record. Return 1 for success, 0 for EOF. + */ +int +ldif_read_record( + FILE *fp, + int *lno, /* ptr to line number counter */ + char **bufp, /* ptr to malloced output buffer */ + int *buflenp ) /* ptr to length of *bufp */ +{ + char linebuf[BUFSIZ], *line, *nbufp; + ber_len_t lcur = 0, len, linesize; + int last_ch = '\n', found_entry = 0, stop; + + line = linebuf; + linesize = sizeof( linebuf ); + + for ( stop = feof( fp ); !stop; last_ch = line[len-1] ) { + if ( fgets( line, linesize, fp ) == NULL ) { + stop = 1; + /* Add \n in case the file does not end with newline */ + line = "\n"; + } + len = strlen( line ); + + if ( last_ch == '\n' ) { + (*lno)++; + + if ( line[0] == '\n' ) { + if ( !found_entry ) + continue; + break; + } + + if ( !found_entry ) { + /* Found a new entry */ + found_entry = 1; + + if ( isdigit( (unsigned char) line[0] ) ) { + /* skip index */ + continue; + } + } + } + + if ( *buflenp - lcur <= len ) { + *buflenp += len + BUFSIZ; + nbufp = ber_memrealloc( *bufp, *buflenp ); + if( nbufp == NULL ) { + return 0; + } + *bufp = nbufp; + } + strcpy( *bufp + lcur, line ); + lcur += len; + } + + return( found_entry ); +} diff --git a/libraries/liblunicode/ucgendat.dsp b/libraries/liblunicode/ucgendat.dsp new file mode 100644 index 0000000000000000000000000000000000000000..065548cdb7dacca2d56fe6fac297b1af4308757d --- /dev/null +++ b/libraries/liblunicode/ucgendat.dsp @@ -0,0 +1,145 @@ +# Microsoft Developer Studio Project File - Name="ucgendat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ucgendat - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ucgendat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ucgendat.mak" CFG="ucgendat - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ucgendat - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ucgendat - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "ucgendat - Win32 Single Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ucgendat - Win32 Single Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ucgendat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\Release" +# PROP Intermediate_Dir "..\..\Release\ucgendat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 oldap32.lib olber32.lib sasl.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\Release" + +!ELSEIF "$(CFG)" == "ucgendat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ucgendat_" +# PROP BASE Intermediate_Dir "ucgendat_" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\Debug" +# PROP Intermediate_Dir "..\..\Debug\ucgendat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 oldap32.lib olber32.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\Debug" + +!ELSEIF "$(CFG)" == "ucgendat - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ucgendat_" +# PROP BASE Intermediate_Dir "ucgendat_" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\SDebug" +# PROP Intermediate_Dir "..\..\SDebug\ucgendat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 oldap32.lib olber32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\Debug" +# ADD LINK32 oldap32.lib olber32.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\SDebug" + +!ELSEIF "$(CFG)" == "ucgendat - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ucgendat0" +# PROP BASE Intermediate_Dir "ucgendat0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\SRelease" +# PROP Intermediate_Dir "..\..\SRelease\ucgendat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 oldap32.lib olber32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\Release" +# ADD LINK32 oldap32.lib olber32.lib sasl.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\SRelease" + +!ENDIF + +# Begin Target + +# Name "ucgendat - Win32 Release" +# Name "ucgendat - Win32 Debug" +# Name "ucgendat - Win32 Single Debug" +# Name "ucgendat - Win32 Single Release" +# Begin Source File + +SOURCE=.\ucdata\ucgendat.c +# End Source File +# End Target +# End Project diff --git a/libraries/liblunicode/ucstr.c b/libraries/liblunicode/ucstr.c index 31110542d14f3149ebf769215c9923a692252f65..f0cc6033221fdedb51faf08ce53657652c9f0abf 100644 --- a/libraries/liblunicode/ucstr.c +++ b/libraries/liblunicode/ucstr.c @@ -41,8 +41,8 @@ int ucstrncasecmp( ber_len_t n ) { for(; 0 < n; ++u1, ++u2, --n ) { - ldap_unicode_t uu1 = uctoupper( *u1 ); - ldap_unicode_t uu2 = uctoupper( *u2 ); + ldap_unicode_t uu1 = uctolower( *u1 ); + ldap_unicode_t uu2 = uctolower( *u2 ); if( uu1 != uu2 ) { return uu1 < uu2 ? -1 : +1; @@ -73,9 +73,9 @@ ldap_unicode_t * ucstrncasechr( ber_len_t n, ldap_unicode_t c ) { - c = uctoupper( c ); + c = uctolower( c ); for(; 0 < n; ++u, --n ) { - if( uctoupper( *u ) == c ) { + if( uctolower( *u ) == c ) { return (ldap_unicode_t *) u; } } @@ -92,165 +92,17 @@ void ucstr2upper( } } -char * UTF8normalize( - struct berval *bv, - unsigned casefold ) -{ - int i, j, len, clen, outpos, ucsoutlen, outsize, last; - char *out, *s; - unsigned long *ucs, *p, *ucsout; - - static unsigned char mask[] = { - 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; - - if ( bv == NULL ) { - return NULL; - } - - s = bv->bv_val; - len = bv->bv_len; - - /* See if the string is pure ASCII so we can shortcut */ - for ( i=0; i<len; i++ ) { - if ( s[i] & 0x80 ) /* non-ASCII */ - break; - } - - /* It's pure ASCII or zero-len */ - if ( i == len ) { - out = malloc( len + 1 ); - if ( i && !casefold ) { - strncpy( out, bv->bv_val, len ); - } else { - for ( j=0; j<i; j++ ) - out[j] = TOUPPER( s[j] ); - } - out[len] = '\0'; - return out; - } - - outsize = len + 7; - out = (char *) malloc( outsize ); - if ( out == NULL ) { - return NULL; - } - - /* FIXME: Should first check to see if string is already in - * proper normalized form. - */ - - outpos = 0; - - /* finish off everything up to character before first non-ascii */ - if ( LDAP_UTF8_ISASCII( s ) ) { - for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { - out[outpos++] = casefold ? TOUPPER( s[i-1] ) : s[i-1]; - } - if ( i == len ) { - out[outpos++] = casefold ? TOUPPER( s[len - 1] ) : s[len - 1]; - out[outpos] = '\0'; - return out; - } - } else { - i = 0; - } - - p = ucs = (long *) malloc( len * sizeof(*ucs) ); - if ( ucs == NULL ) { - free(out); - return NULL; - } - - /* convert character before first non-ascii to ucs-4 */ - if ( i > 0 ) { - *p = casefold ? TOUPPER( s[i - 1] ) : s[i - 1]; - p++; - } - - /* s[i] is now first non-ascii character */ - for (;;) { - /* s[i] is non-ascii */ - /* convert everything up to next ascii to ucs-4 */ - while ( i < len ) { - clen = LDAP_UTF8_CHARLEN2( s + i, clen ); - if ( clen == 0 ) { - free( ucs ); - free( out ); - return NULL; - } - if ( clen == 1 ) { - /* ascii */ - break; - } - *p = s[i] & mask[clen]; - i++; - for( j = 1; j < clen; j++ ) { - if ( (s[i] & 0xc0) != 0x80 ) { - free( ucs ); - free( out ); - return NULL; - } - *p <<= 6; - *p |= s[i] & 0x3f; - i++; - } - if ( casefold ) { - *p = uctoupper( *p ); - } - p++; - } - /* normalize ucs of length p - ucs */ - uccanondecomp( ucs, p - ucs, &ucsout, &ucsoutlen ); - ucsoutlen = uccanoncomp( ucsout, ucsoutlen ); - /* convert ucs to utf-8 and store in out */ - for ( j = 0; j < ucsoutlen; j++ ) { - /* allocate more space if not enough room for - 6 bytes and terminator */ - if ( outsize - outpos < 7 ) { - outsize = ucsoutlen - j + outpos + 6; - out = (char *) realloc( out, outsize ); - if ( out == NULL ) { - free( ucs ); - return NULL; - } - } - outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] ); - } - - if ( i == len ) { - break; - } - - last = i; - - /* s[i] is ascii */ - /* finish off everything up to char before next non-ascii */ - for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { - out[outpos++] = casefold ? TOUPPER( s[i-1] ) : s[i-1]; - } - if ( i == len ) { - out[outpos++] = casefold ? TOUPPER( s[len - 1] ) : s[len - 1]; - break; - } - - /* convert character before next non-ascii to ucs-4 */ - *ucs = casefold ? TOUPPER( s[i - 1] ) : s[i - 1]; - p = ucs + 1; - } - free( ucs ); - out[outpos] = '\0'; - return out; -} - struct berval * UTF8bvnormalize( struct berval *bv, struct berval *newbv, - unsigned casefold ) + unsigned flags ) { int i, j, len, clen, outpos, ucsoutlen, outsize, last; char *out, *s; unsigned long *ucs, *p, *ucsout; - + + unsigned casefold = flags & LDAP_UTF8_CASEFOLD; + unsigned approx = flags & LDAP_UTF8_APPROX; static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; @@ -281,10 +133,10 @@ struct berval * UTF8bvnormalize( outpos = 0; for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { - out[outpos++] = TOUPPER( s[i-1] ); + out[outpos++] = TOLOWER( s[i-1] ); } if ( i == len ) { - out[outpos++] = TOUPPER( s[len - 1] ); + out[outpos++] = TOLOWER( s[len - 1] ); out[outpos] = '\0'; return ber_str2bv( out, outpos, 0, newbv); } @@ -323,7 +175,7 @@ struct berval * UTF8bvnormalize( /* convert character before first non-ascii to ucs-4 */ if ( i > 0 ) { - *p = casefold ? TOUPPER( s[i - 1] ) : s[i - 1]; + *p = casefold ? TOLOWER( s[i - 1] ) : s[i - 1]; p++; } @@ -355,26 +207,34 @@ struct berval * UTF8bvnormalize( i++; } if ( casefold ) { - *p = uctoupper( *p ); + *p = uctolower( *p ); } p++; } /* normalize ucs of length p - ucs */ uccanondecomp( ucs, p - ucs, &ucsout, &ucsoutlen ); - ucsoutlen = uccanoncomp( ucsout, ucsoutlen ); - /* convert ucs to utf-8 and store in out */ - for ( j = 0; j < ucsoutlen; j++ ) { - /* allocate more space if not enough room for - 6 bytes and terminator */ - if ( outsize - outpos < 7 ) { - outsize = ucsoutlen - j + outpos + 6; - out = (char *) realloc( out, outsize ); - if ( out == NULL ) { - free( ucs ); - return NULL; + if ( approx ) { + for ( j = 0; j < ucsoutlen; j++ ) { + if ( ucsout[j] < 0x80 ) { + out[outpos++] = ucsout[j]; + } + } + } else { + ucsoutlen = uccanoncomp( ucsout, ucsoutlen ); + /* convert ucs to utf-8 and store in out */ + for ( j = 0; j < ucsoutlen; j++ ) { + /* allocate more space if not enough room for + 6 bytes and terminator */ + if ( outsize - outpos < 7 ) { + outsize = ucsoutlen - j + outpos + 6; + out = (char *) realloc( out, outsize ); + if ( out == NULL ) { + free( ucs ); + return NULL; + } } + outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] ); } - outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] ); } if ( i == len ) { @@ -386,15 +246,15 @@ struct berval * UTF8bvnormalize( /* s[i] is ascii */ /* finish off everything up to char before next non-ascii */ for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { - out[outpos++] = casefold ? TOUPPER( s[i-1] ) : s[i-1]; + out[outpos++] = casefold ? TOLOWER( s[i-1] ) : s[i-1]; } if ( i == len ) { - out[outpos++] = casefold ? TOUPPER( s[len - 1] ) : s[len - 1]; + out[outpos++] = casefold ? TOLOWER( s[len - 1] ) : s[len - 1]; break; } /* convert character before next non-ascii to ucs-4 */ - *ucs = casefold ? TOUPPER( s[i - 1] ) : s[i - 1]; + *ucs = casefold ? TOLOWER( s[i - 1] ) : s[i - 1]; p = ucs + 1; } free( ucs ); @@ -402,112 +262,19 @@ struct berval * UTF8bvnormalize( return ber_str2bv( out, outpos, 0, newbv ); } -/* compare UTF8-strings, optionally ignore casing, string pointers must not be NULL */ -/* slow, should be optimized */ -int UTF8normcmp( - const char *s1, - const char *s2, - unsigned casefold ) -{ - int i, l1, l2, len, ulen, res; - unsigned long *ucs, *ucsout1, *ucsout2; - - l1 = strlen( s1 ); - l2 = strlen( s2 ); - - if ( ( l1 == 0 ) || ( l2 == 0 ) ) { - if ( l1 == l2 ) { - return 0; - } - return *s1 - *s2 > 0 ? 1 : -1; - } - - /* See if we can get away with a straight ASCII compare */ - len = (l1 < l2) ? l1 : l2; - for ( i = 0; i<len; i++ ) { - /* Is either char non-ASCII? */ - if ((s1[i] & 0x80) || (s2[i] & 0x80)) - break; - if (casefold) { - char c1 = TOUPPER(s1[i]); - char c2 = TOUPPER(s2[i]); - res = c1 - c2; - } else { - res = s1[i] - s2[i]; - } - if (res) - return res; - } - /* Strings were ASCII, equal up to minlen */ - if (i == len) - return l1 - l2; - - /* FIXME: Should first check to see if strings are already in - * proper normalized form. - */ - - ucs = (long *) malloc( ( l1 > l2 ? l1 : l2 ) * sizeof(*ucs) ); - if ( ucs == NULL ) { - return l1 > l2 ? 1 : -1; /* what to do??? */ - } - - /* - * XXYYZ: we convert to ucs4 even though -llunicode - * expects ucs2 in an unsigned long - */ - - /* convert and normalize 1st string */ - for ( i = 0, ulen = 0; i < l1; i += len, ulen++ ) { - ucs[ulen] = ldap_x_utf8_to_ucs4( s1 + i ); - if ( ucs[ulen] == LDAP_UCS4_INVALID ) { - free( ucs ); - return -1; /* what to do??? */ - } - len = LDAP_UTF8_CHARLEN( s1 + i ); - } - uccanondecomp( ucs, ulen, &ucsout1, &l1 ); - l1 = uccanoncomp( ucsout1, l1 ); - - /* convert and normalize 2nd string */ - for ( i = 0, ulen = 0; i < l2; i += len, ulen++ ) { - ucs[ulen] = ldap_x_utf8_to_ucs4( s2 + i ); - if ( ucs[ulen] == LDAP_UCS4_INVALID ) { - free( ucsout1 ); - free( ucs ); - return 1; /* what to do??? */ - } - len = LDAP_UTF8_CHARLEN( s2 + i ); - } - uccanondecomp( ucs, ulen, &ucsout2, &l2 ); - l2 = uccanoncomp( ucsout2, l2 ); - - free( ucs ); - - res = casefold - ? ucstrncasecmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ) - : ucstrncmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ); - free( ucsout1 ); - free( ucsout2 ); - - if ( res != 0 ) { - return res; - } - if ( l1 == l2 ) { - return 0; - } - return l1 > l2 ? 1 : -1; -} - /* compare UTF8-strings, optionally ignore casing */ /* slow, should be optimized */ int UTF8bvnormcmp( struct berval *bv1, struct berval *bv2, - unsigned casefold ) + unsigned flags ) { - int i, l1, l2, len, ulen, res; + int i, l1, l2, len, ulen, res = 0; char *s1, *s2, *done; unsigned long *ucs, *ucsout1, *ucsout2; + unsigned casefold = flags & LDAP_UTF8_CASEFOLD; + unsigned norm1 = flags & LDAP_UTF8_ARG1NFC; + unsigned norm2 = flags & LDAP_UTF8_ARG2NFC; if (bv1 == NULL) { return bv2 == NULL ? 0 : -1; @@ -529,8 +296,8 @@ int UTF8bvnormcmp( while ( (s1 < done) && LDAP_UTF8_ISASCII(s1) && LDAP_UTF8_ISASCII(s2) ) { if (casefold) { - char c1 = TOUPPER(*s1); - char c2 = TOUPPER(*s2); + char c1 = TOLOWER(*s1); + char c2 = TOLOWER(*s2); res = c1 - c2; } else { res = *s1 - *s2; @@ -543,8 +310,8 @@ int UTF8bvnormcmp( if (!LDAP_UTF8_ISASCII(s1) || !LDAP_UTF8_ISASCII(s2)) { break; } - } else if ((len < l1) && !LDAP_UTF8_ISASCII(s1) || - (len < l2) && !LDAP_UTF8_ISASCII(s2)) { + } else if (((len < l1) && !LDAP_UTF8_ISASCII(s1)) || + ((len < l2) && !LDAP_UTF8_ISASCII(s2))) { break; } return res; @@ -575,7 +342,7 @@ int UTF8bvnormcmp( * proper normalized form. */ - ucs = (long *) malloc( ( l1 > l2 ? l1 : l2 ) * sizeof(*ucs) ); + ucs = (long *) malloc( ( ( norm1 || l1 > l2 ) ? l1 : l2 ) * sizeof(*ucs) ); if ( ucs == NULL ) { return l1 > l2 ? 1 : -1; /* what to do??? */ } @@ -594,8 +361,18 @@ int UTF8bvnormcmp( } len = LDAP_UTF8_CHARLEN( s1 + i ); } - uccanondecomp( ucs, ulen, &ucsout1, &l1 ); - l1 = uccanoncomp( ucsout1, l1 ); + + if ( norm1 ) { + ucsout1 = ucs; + l1 = ulen; + ucs = (long *) malloc( l2 * sizeof(*ucs) ); + if ( ucs == NULL ) { + return l1 > l2 ? 1 : -1; /* what to do??? */ + } + } else { + uccanondecomp( ucs, ulen, &ucsout1, &l1 ); + l1 = uccanoncomp( ucsout1, l1 ); + } /* convert and normalize 2nd string */ for ( i = 0, ulen = 0; i < l2; i += len, ulen++ ) { @@ -607,11 +384,16 @@ int UTF8bvnormcmp( } len = LDAP_UTF8_CHARLEN( s2 + i ); } - uccanondecomp( ucs, ulen, &ucsout2, &l2 ); - l2 = uccanoncomp( ucsout2, l2 ); - - free( ucs ); + if ( norm2 ) { + ucsout2 = ucs; + l2 = ulen; + } else { + uccanondecomp( ucs, ulen, &ucsout2, &l2 ); + l2 = uccanoncomp( ucsout2, l2 ); + free( ucs ); + } + res = casefold ? ucstrncasecmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ) : ucstrncmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ); diff --git a/libraries/liblunicode/ure/ure.c b/libraries/liblunicode/ure/ure.c new file mode 100644 index 0000000000000000000000000000000000000000..f546354199cd99a4a8e59d227a2c141e0c717b8b --- /dev/null +++ b/libraries/liblunicode/ure/ure.c @@ -0,0 +1,2123 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 1997, 1998, 1999 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: ure.c,v 1.2 1999/09/21 15:47:43 mleisher Exp $" */ + +#include "portable.h" + +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include "ure.h" + +/* + * Flags used internally in the DFA. + */ +#define _URE_DFA_CASEFOLD 0x01 +#define _URE_DFA_BLANKLINE 0x02 + +static unsigned long cclass_flags[] = { + 0, + _URE_NONSPACING, + _URE_COMBINING, + _URE_NUMDIGIT, + _URE_NUMOTHER, + _URE_SPACESEP, + _URE_LINESEP, + _URE_PARASEP, + _URE_CNTRL, + _URE_PUA, + _URE_UPPER, + _URE_LOWER, + _URE_TITLE, + _URE_MODIFIER, + _URE_OTHERLETTER, + _URE_DASHPUNCT, + _URE_OPENPUNCT, + _URE_CLOSEPUNCT, + _URE_OTHERPUNCT, + _URE_MATHSYM, + _URE_CURRENCYSYM, + _URE_OTHERSYM, + _URE_LTR, + _URE_RTL, + _URE_EURONUM, + _URE_EURONUMSEP, + _URE_EURONUMTERM, + _URE_ARABNUM, + _URE_COMMONSEP, + _URE_BLOCKSEP, + _URE_SEGMENTSEP, + _URE_WHITESPACE, + _URE_OTHERNEUT, +}; + +/* + * Symbol types for the DFA. + */ +#define _URE_ANY_CHAR 1 +#define _URE_CHAR 2 +#define _URE_CCLASS 3 +#define _URE_NCCLASS 4 +#define _URE_BOL_ANCHOR 5 +#define _URE_EOL_ANCHOR 6 + +/* + * Op codes for converting the NFA to a DFA. + */ +#define _URE_SYMBOL 10 +#define _URE_PAREN 11 +#define _URE_QUEST 12 +#define _URE_STAR 13 +#define _URE_PLUS 14 +#define _URE_ONE 15 +#define _URE_AND 16 +#define _URE_OR 17 + +#define _URE_NOOP 0xffff + +#define _URE_REGSTART 0x8000 +#define _URE_REGEND 0x4000 + +/* + * Structure used to handle a compacted range of characters. + */ +typedef struct { + ucs4_t min_code; + ucs4_t max_code; +} _ure_range_t; + +typedef struct { + _ure_range_t *ranges; + ucs2_t ranges_used; + ucs2_t ranges_size; +} _ure_ccl_t; + +typedef union { + ucs4_t chr; + _ure_ccl_t ccl; +} _ure_sym_t; + +/* + * This is a general element structure used for expressions and stack + * elements. + */ +typedef struct { + ucs2_t reg; + ucs2_t onstack; + ucs2_t type; + ucs2_t lhs; + ucs2_t rhs; +} _ure_elt_t; + +/* + * This is a structure used to track a list or a stack of states. + */ +typedef struct { + ucs2_t *slist; + ucs2_t slist_size; + ucs2_t slist_used; +} _ure_stlist_t; + +/* + * Structure to track the list of unique states for a symbol + * during reduction. + */ +typedef struct { + ucs2_t id; + ucs2_t type; + unsigned long mods; + unsigned long props; + _ure_sym_t sym; + _ure_stlist_t states; +} _ure_symtab_t; + +/* + * Structure to hold a single state. + */ +typedef struct { + ucs2_t id; + ucs2_t accepting; + ucs2_t pad; + _ure_stlist_t st; + _ure_elt_t *trans; + ucs2_t trans_size; + ucs2_t trans_used; +} _ure_state_t; + +/* + * Structure used for keeping lists of states. + */ +typedef struct { + _ure_state_t *states; + ucs2_t states_size; + ucs2_t states_used; +} _ure_statetable_t; + +/* + * Structure to track pairs of DFA states when equivalent states are + * merged. + */ +typedef struct { + ucs2_t l; + ucs2_t r; +} _ure_equiv_t; + +/* + * Structure used for constructing the NFA and reducing to a minimal DFA. + */ +typedef struct _ure_buffer_t { + int reducing; + int error; + unsigned long flags; + + _ure_stlist_t stack; + + /* + * Table of unique symbols encountered. + */ + _ure_symtab_t *symtab; + ucs2_t symtab_size; + ucs2_t symtab_used; + + /* + * Tracks the unique expressions generated for the NFA and when the NFA is + * reduced. + */ + _ure_elt_t *expr; + ucs2_t expr_used; + ucs2_t expr_size; + + /* + * The reduced table of unique groups of NFA states. + */ + _ure_statetable_t states; + + /* + * Tracks states when equivalent states are merged. + */ + _ure_equiv_t *equiv; + ucs2_t equiv_used; + ucs2_t equiv_size; +} _ure_buffer_t; + +typedef struct { + ucs2_t symbol; + ucs2_t next_state; +} _ure_trans_t; + +typedef struct { + ucs2_t accepting; + ucs2_t ntrans; + _ure_trans_t *trans; +} _ure_dstate_t; + +typedef struct _ure_dfa_t { + unsigned long flags; + + _ure_symtab_t *syms; + ucs2_t nsyms; + + _ure_dstate_t *states; + ucs2_t nstates; + + _ure_trans_t *trans; + ucs2_t ntrans; +} _ure_dfa_t; + +/************************************************************************* + * + * Functions. + * + *************************************************************************/ + +static void +_ure_memmove(char *dest, char *src, unsigned long bytes) +{ + long i, j; + + i = (long) bytes; + j = i & 7; + i = (i + 7) >> 3; + + /* + * Do a memmove using Ye Olde Duff's Device for efficiency. + */ + if (src < dest) { + src += bytes; + dest += bytes; + + switch (j) { + case 0: do { + *--dest = *--src; + case 7: *--dest = *--src; + case 6: *--dest = *--src; + case 5: *--dest = *--src; + case 4: *--dest = *--src; + case 3: *--dest = *--src; + case 2: *--dest = *--src; + case 1: *--dest = *--src; + } while (--i > 0); + } + } else if (src > dest) { + switch (j) { + case 0: do { + *dest++ = *src++; + case 7: *dest++ = *src++; + case 6: *dest++ = *src++; + case 5: *dest++ = *src++; + case 4: *dest++ = *src++; + case 3: *dest++ = *src++; + case 2: *dest++ = *src++; + case 1: *dest++ = *src++; + } while (--i > 0); + } + } +} + +static void +_ure_push(ucs2_t v, _ure_buffer_t *b) +{ + _ure_stlist_t *s; + + if (b == 0) + return; + + /* + * If the `reducing' parameter is non-zero, check to see if the value + * passed is already on the stack. + */ + if (b->reducing != 0 && b->expr[v].onstack != 0) + return; + + s = &b->stack; + if (s->slist_used == s->slist_size) { + if (s->slist_size == 0) + s->slist = (ucs2_t *) malloc(sizeof(ucs2_t) << 3); + else + s->slist = (ucs2_t *) realloc((char *) s->slist, + sizeof(ucs2_t) * (s->slist_size + 8)); + s->slist_size += 8; + } + s->slist[s->slist_used++] = v; + + /* + * If the `reducing' parameter is non-zero, flag the element as being on + * the stack. + */ + if (b->reducing != 0) + b->expr[v].onstack = 1; +} + +static ucs2_t +_ure_peek(_ure_buffer_t *b) +{ + if (b == 0 || b->stack.slist_used == 0) + return _URE_NOOP; + + return b->stack.slist[b->stack.slist_used - 1]; +} + +static ucs2_t +_ure_pop(_ure_buffer_t *b) +{ + ucs2_t v; + + if (b == 0 || b->stack.slist_used == 0) + return _URE_NOOP; + + v = b->stack.slist[--b->stack.slist_used]; + if (b->reducing) + b->expr[v].onstack = 0; + + return v; +} + +/************************************************************************* + * + * Start symbol parse functions. + * + *************************************************************************/ + +/* + * Parse a comma-separated list of integers that represent character + * properties. Combine them into a mask that is returned in the `mask' + * variable, and return the number of characters consumed. + */ +static unsigned long +_ure_prop_list(ucs2_t *pp, unsigned long limit, unsigned long *mask, + _ure_buffer_t *b) +{ + unsigned long n, m; + ucs2_t *sp, *ep; + + sp = pp; + ep = sp + limit; + + for (m = n = 0; b->error == _URE_OK && sp < ep; sp++) { + if (*sp == ',') { + /* + * Encountered a comma, so select the next character property flag + * and reset the number. + */ + m |= cclass_flags[n]; + n = 0; + } else if (*sp >= '0' && *sp <= '9') + /* + * Encountered a digit, so start or continue building the cardinal + * that represents the character property flag. + */ + n = (n * 10) + (*sp - '0'); + else + /* + * Encountered something that is not part of the property list. + * Indicate that we are done. + */ + break; + + /* + * If a property number greater than 32 occurs, then there is a + * problem. Most likely a missing comma separator. + */ + if (n > 32) + b->error = _URE_INVALID_PROPERTY; + } + + if (n != 0) + m |= cclass_flags[n]; + + /* + * Set the mask that represents the group of character properties. + */ + *mask = m; + + /* + * Return the number of characters consumed. + */ + return sp - pp; +} + +/* + * Collect a hex number with 1 to 4 digits and return the number + * of characters used. + */ +static unsigned long +_ure_hex(ucs2_t *np, unsigned long limit, ucs4_t *n) +{ + ucs2_t i; + ucs2_t *sp, *ep; + ucs4_t nn; + + sp = np; + ep = sp + limit; + + for (nn = 0, i = 0; i < 4 && sp < ep; i++, sp++) { + if (*sp >= '0' && *sp <= '9') + nn = (nn << 4) + (*sp - '0'); + else if (*sp >= 'A' && *sp <= 'F') + nn = (nn << 4) + ((*sp - 'A') + 10); + else if (*sp >= 'a' && *sp <= 'f') + nn = (nn << 4) + ((*sp - 'a') + 10); + else + /* + * Encountered something that is not a hex digit. + */ + break; + } + + /* + * Assign the character code collected and return the number of + * characters used. + */ + *n = nn; + + return sp - np; +} + +/* + * Insert a range into a character class, removing duplicates and ordering + * them in increasing range-start order. + */ +static void +_ure_add_range(_ure_ccl_t *ccl, _ure_range_t *r, _ure_buffer_t *b) +{ + ucs2_t i; + ucs4_t tmp; + _ure_range_t *rp; + + /* + * If the `casefold' flag is set, then make sure both endpoints of the + * range are converted to lower case. + */ + if (b->flags & _URE_DFA_CASEFOLD) { + r->min_code = _ure_tolower(r->min_code); + r->max_code = _ure_tolower(r->max_code); + } + + /* + * Swap the range endpoints if they are not in increasing order. + */ + if (r->min_code > r->max_code) { + tmp = r->min_code; + r->min_code = r->max_code; + r->max_code = tmp; + } + + for (i = 0, rp = ccl->ranges; + i < ccl->ranges_used && r->min_code < rp->min_code; i++, rp++) ; + + /* + * Check for a duplicate. + */ + if (i < ccl->ranges_used && + r->min_code == rp->min_code && r->max_code == rp->max_code) + return; + + if (ccl->ranges_used == ccl->ranges_size) { + if (ccl->ranges_size == 0) + ccl->ranges = (_ure_range_t *) malloc(sizeof(_ure_range_t) << 3); + else + ccl->ranges = (_ure_range_t *) + realloc((char *) ccl->ranges, + sizeof(_ure_range_t) * (ccl->ranges_size + 8)); + ccl->ranges_size += 8; + } + + rp = ccl->ranges + ccl->ranges_used; + + if (i < ccl->ranges_used) + _ure_memmove((char *) (rp + 1), (char *) rp, + sizeof(_ure_range_t) * (ccl->ranges_used - i)); + + ccl->ranges_used++; + rp->min_code = r->min_code; + rp->max_code = r->max_code; +} + +#define _URE_ALPHA_MASK (_URE_UPPER|_URE_LOWER|_URE_OTHERLETTER|\ +_URE_MODIFIER|_URE_TITLE|_URE_NONSPACING|_URE_COMBINING) +#define _URE_ALNUM_MASK (_URE_ALPHA_MASK|_URE_NUMDIGIT) +#define _URE_PUNCT_MASK (_URE_DASHPUNCT|_URE_OPENPUNCT|_URE_CLOSEPUNCT|\ +_URE_OTHERPUNCT) +#define _URE_GRAPH_MASK (_URE_NUMDIGIT|_URE_NUMOTHER|_URE_ALPHA_MASK|\ +_URE_MATHSYM|_URE_CURRENCYSYM|_URE_OTHERSYM) +#define _URE_PRINT_MASK (_URE_GRAPH_MASK|_URE_SPACESEP) +#define _URE_SPACE_MASK (_URE_SPACESEP|_URE_LINESEP|_URE_PARASEP) + +typedef void (*_ure_cclsetup_t)( + _ure_symtab_t *sym, + unsigned long mask, + _ure_buffer_t *b +); + +typedef struct { + ucs2_t key; + unsigned long len; + unsigned long next; + _ure_cclsetup_t func; + unsigned long mask; +} _ure_trie_t; + +static void +_ure_ccl_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) +{ + sym->props |= mask; +} + +static void +_ure_space_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) +{ + _ure_range_t range; + + sym->props |= mask; + + /* + * Add the additional characters needed for handling isspace(). + */ + range.min_code = range.max_code = '\t'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = range.max_code = '\r'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = range.max_code = '\n'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = range.max_code = '\f'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = range.max_code = 0xfeff; + _ure_add_range(&sym->sym.ccl, &range, b); +} + +static void +_ure_xdigit_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) +{ + _ure_range_t range; + + /* + * Add the additional characters needed for handling isxdigit(). + */ + range.min_code = '0'; + range.max_code = '9'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = 'A'; + range.max_code = 'F'; + _ure_add_range(&sym->sym.ccl, &range, b); + range.min_code = 'a'; + range.max_code = 'f'; + _ure_add_range(&sym->sym.ccl, &range, b); +} + +static _ure_trie_t cclass_trie[] = { + {0x003a, 1, 1, 0, 0}, + {0x0061, 9, 10, 0, 0}, + {0x0063, 8, 19, 0, 0}, + {0x0064, 7, 24, 0, 0}, + {0x0067, 6, 29, 0, 0}, + {0x006c, 5, 34, 0, 0}, + {0x0070, 4, 39, 0, 0}, + {0x0073, 3, 49, 0, 0}, + {0x0075, 2, 54, 0, 0}, + {0x0078, 1, 59, 0, 0}, + {0x006c, 1, 11, 0, 0}, + {0x006e, 2, 13, 0, 0}, + {0x0070, 1, 16, 0, 0}, + {0x0075, 1, 14, 0, 0}, + {0x006d, 1, 15, 0, 0}, + {0x003a, 1, 16, _ure_ccl_setup, _URE_ALNUM_MASK}, + {0x0068, 1, 17, 0, 0}, + {0x0061, 1, 18, 0, 0}, + {0x003a, 1, 19, _ure_ccl_setup, _URE_ALPHA_MASK}, + {0x006e, 1, 20, 0, 0}, + {0x0074, 1, 21, 0, 0}, + {0x0072, 1, 22, 0, 0}, + {0x006c, 1, 23, 0, 0}, + {0x003a, 1, 24, _ure_ccl_setup, _URE_CNTRL}, + {0x0069, 1, 25, 0, 0}, + {0x0067, 1, 26, 0, 0}, + {0x0069, 1, 27, 0, 0}, + {0x0074, 1, 28, 0, 0}, + {0x003a, 1, 29, _ure_ccl_setup, _URE_NUMDIGIT}, + {0x0072, 1, 30, 0, 0}, + {0x0061, 1, 31, 0, 0}, + {0x0070, 1, 32, 0, 0}, + {0x0068, 1, 33, 0, 0}, + {0x003a, 1, 34, _ure_ccl_setup, _URE_GRAPH_MASK}, + {0x006f, 1, 35, 0, 0}, + {0x0077, 1, 36, 0, 0}, + {0x0065, 1, 37, 0, 0}, + {0x0072, 1, 38, 0, 0}, + {0x003a, 1, 39, _ure_ccl_setup, _URE_LOWER}, + {0x0072, 2, 41, 0, 0}, + {0x0075, 1, 45, 0, 0}, + {0x0069, 1, 42, 0, 0}, + {0x006e, 1, 43, 0, 0}, + {0x0074, 1, 44, 0, 0}, + {0x003a, 1, 45, _ure_ccl_setup, _URE_PRINT_MASK}, + {0x006e, 1, 46, 0, 0}, + {0x0063, 1, 47, 0, 0}, + {0x0074, 1, 48, 0, 0}, + {0x003a, 1, 49, _ure_ccl_setup, _URE_PUNCT_MASK}, + {0x0070, 1, 50, 0, 0}, + {0x0061, 1, 51, 0, 0}, + {0x0063, 1, 52, 0, 0}, + {0x0065, 1, 53, 0, 0}, + {0x003a, 1, 54, _ure_space_setup, _URE_SPACE_MASK}, + {0x0070, 1, 55, 0, 0}, + {0x0070, 1, 56, 0, 0}, + {0x0065, 1, 57, 0, 0}, + {0x0072, 1, 58, 0, 0}, + {0x003a, 1, 59, _ure_ccl_setup, _URE_UPPER}, + {0x0064, 1, 60, 0, 0}, + {0x0069, 1, 61, 0, 0}, + {0x0067, 1, 62, 0, 0}, + {0x0069, 1, 63, 0, 0}, + {0x0074, 1, 64, 0, 0}, + {0x003a, 1, 65, _ure_xdigit_setup, 0}, +}; + +/* + * Probe for one of the POSIX colon delimited character classes in the static + * trie. + */ +static unsigned long +_ure_posix_ccl(ucs2_t *cp, unsigned long limit, _ure_symtab_t *sym, + _ure_buffer_t *b) +{ + int i; + unsigned long n; + _ure_trie_t *tp; + ucs2_t *sp, *ep; + + /* + * If the number of characters left is less than 7, then this cannot be + * interpreted as one of the colon delimited classes. + */ + if (limit < 7) + return 0; + + sp = cp; + ep = sp + limit; + tp = cclass_trie; + for (i = 0; sp < ep && i < 8; i++, sp++) { + n = tp->len; + + for (; n > 0 && tp->key != *sp; tp++, n--) ; + + if (n == 0) + return 0; + + if (*sp == ':' && (i == 6 || i == 7)) { + sp++; + break; + } + if (sp + 1 < ep) + tp = cclass_trie + tp->next; + } + if (tp->func == 0) + return 0; + + (*tp->func)(sym, tp->mask, b); + + return sp - cp; +} + +/* + * Construct a list of ranges and return the number of characters consumed. + */ +static unsigned long +_ure_cclass(ucs2_t *cp, unsigned long limit, _ure_symtab_t *symp, + _ure_buffer_t *b) +{ + int range_end; + unsigned long n; + ucs2_t *sp, *ep; + ucs4_t c, last; + _ure_ccl_t *cclp; + _ure_range_t range; + + sp = cp; + ep = sp + limit; + + if (*sp == '^') { + symp->type = _URE_NCCLASS; + sp++; + } else + symp->type = _URE_CCLASS; + + for (last = 0, range_end = 0; + b->error == _URE_OK && sp < ep && *sp != ']'; ) { + c = *sp++; + if (c == '\\') { + if (sp == ep) { + /* + * The EOS was encountered when expecting the reverse solidus + * to be followed by the character it is escaping. Set an + * error code and return the number of characters consumed up + * to this point. + */ + b->error = _URE_UNEXPECTED_EOS; + return sp - cp; + } + + c = *sp++; + switch (c) { + case 'a': + c = 0x07; + break; + case 'b': + c = 0x08; + break; + case 'f': + c = 0x0c; + break; + case 'n': + c = 0x0a; + break; + case 'r': + c = 0x0d; + break; + case 't': + c = 0x09; + break; + case 'v': + c = 0x0b; + break; + case 'p': + case 'P': + sp += _ure_prop_list(sp, ep - sp, &symp->props, b); + /* + * Invert the bit mask of the properties if this is a negated + * character class or if 'P' is used to specify a list of + * character properties that should *not* match in a + * character class. + */ + if (c == 'P') + symp->props = ~symp->props; + continue; + break; + case 'x': + case 'X': + case 'u': + case 'U': + if (sp < ep && + ((*sp >= '0' && *sp <= '9') || + (*sp >= 'A' && *sp <= 'F') || + (*sp >= 'a' && *sp <= 'f'))) + sp += _ure_hex(sp, ep - sp, &c); + } + } else if (c == ':') { + /* + * Probe for a POSIX colon delimited character class. + */ + sp--; + if ((n = _ure_posix_ccl(sp, ep - sp, symp, b)) == 0) + sp++; + else { + sp += n; + continue; + } + } + + cclp = &symp->sym.ccl; + + /* + * Check to see if the current character is a low surrogate that needs + * to be combined with a preceding high surrogate. + */ + if (last != 0) { + if (c >= 0xdc00 && c <= 0xdfff) + /* + * Construct the UTF16 character code. + */ + c = 0x10000 + (((last & 0x03ff) << 10) | (c & 0x03ff)); + else { + /* + * Add the isolated high surrogate to the range. + */ + if (range_end == 1) + range.max_code = last & 0xffff; + else + range.min_code = range.max_code = last & 0xffff; + + _ure_add_range(cclp, &range, b); + range_end = 0; + } + } + + /* + * Clear the last character code. + */ + last = 0; + + /* + * This slightly awkward code handles the different cases needed to + * construct a range. + */ + if (c >= 0xd800 && c <= 0xdbff) { + /* + * If the high surrogate is followed by a range indicator, simply + * add it as the range start. Otherwise, save it in case the next + * character is a low surrogate. + */ + if (*sp == '-') { + sp++; + range.min_code = c; + range_end = 1; + } else + last = c; + } else if (range_end == 1) { + range.max_code = c; + _ure_add_range(cclp, &range, b); + range_end = 0; + } else { + range.min_code = range.max_code = c; + if (*sp == '-') { + sp++; + range_end = 1; + } else + _ure_add_range(cclp, &range, b); + } + } + + if (sp < ep && *sp == ']') + sp++; + else + /* + * The parse was not terminated by the character class close symbol + * (']'), so set an error code. + */ + b->error = _URE_CCLASS_OPEN; + + return sp - cp; +} + +/* + * Probe for a low surrogate hex code. + */ +static unsigned long +_ure_probe_ls(ucs2_t *ls, unsigned long limit, ucs4_t *c) +{ + ucs4_t i, code; + ucs2_t *sp, *ep; + + for (i = code = 0, sp = ls, ep = sp + limit; i < 4 && sp < ep; sp++) { + if (*sp >= '0' && *sp <= '9') + code = (code << 4) + (*sp - '0'); + else if (*sp >= 'A' && *sp <= 'F') + code = (code << 4) + ((*sp - 'A') + 10); + else if (*sp >= 'a' && *sp <= 'f') + code = (code << 4) + ((*sp - 'a') + 10); + else + break; + } + + *c = code; + return (0xdc00 <= code && code <= 0xdfff) ? sp - ls : 0; +} + +static unsigned long +_ure_compile_symbol(ucs2_t *sym, unsigned long limit, _ure_symtab_t *symp, + _ure_buffer_t *b) +{ + ucs4_t c; + ucs2_t *sp, *ep; + + sp = sym; + ep = sym + limit; + + if ((c = *sp++) == '\\') { + + if (sp == ep) { + /* + * The EOS was encountered when expecting the reverse solidus to + * be followed by the character it is escaping. Set an error code + * and return the number of characters consumed up to this point. + */ + b->error = _URE_UNEXPECTED_EOS; + return sp - sym; + } + + c = *sp++; + switch (c) { + case 'p': + case 'P': + symp->type = (c == 'p') ? _URE_CCLASS : _URE_NCCLASS; + sp += _ure_prop_list(sp, ep - sp, &symp->props, b); + break; + case 'a': + symp->type = _URE_CHAR; + symp->sym.chr = 0x07; + break; + case 'b': + symp->type = _URE_CHAR; + symp->sym.chr = 0x08; + break; + case 'f': + symp->type = _URE_CHAR; + symp->sym.chr = 0x0c; + break; + case 'n': + symp->type = _URE_CHAR; + symp->sym.chr = 0x0a; + break; + case 'r': + symp->type = _URE_CHAR; + symp->sym.chr = 0x0d; + break; + case 't': + symp->type = _URE_CHAR; + symp->sym.chr = 0x09; + break; + case 'v': + symp->type = _URE_CHAR; + symp->sym.chr = 0x0b; + break; + case 'x': + case 'X': + case 'u': + case 'U': + /* + * Collect between 1 and 4 digits representing a UCS2 code. Fall + * through to the next case. + */ + if (sp < ep && + ((*sp >= '0' && *sp <= '9') || + (*sp >= 'A' && *sp <= 'F') || + (*sp >= 'a' && *sp <= 'f'))) + sp += _ure_hex(sp, ep - sp, &c); + /* FALLTHROUGH */ + default: + /* + * Simply add an escaped character here. + */ + symp->type = _URE_CHAR; + symp->sym.chr = c; + } + } else if (c == '^' || c == '$') + /* + * Handle the BOL and EOL anchors. This actually consists simply of + * setting a flag that indicates that the user supplied anchor match + * function should be called. This needs to be done instead of simply + * matching line/paragraph separators because beginning-of-text and + * end-of-text tests are needed as well. + */ + symp->type = (c == '^') ? _URE_BOL_ANCHOR : _URE_EOL_ANCHOR; + else if (c == '[') + /* + * Construct a character class. + */ + sp += _ure_cclass(sp, ep - sp, symp, b); + else if (c == '.') + symp->type = _URE_ANY_CHAR; + else { + symp->type = _URE_CHAR; + symp->sym.chr = c; + } + + /* + * If the symbol type happens to be a character and is a high surrogate, + * then probe forward to see if it is followed by a low surrogate that + * needs to be added. + */ + if (sp < ep && symp->type == _URE_CHAR && + 0xd800 <= symp->sym.chr && symp->sym.chr <= 0xdbff) { + + if (0xdc00 <= *sp && *sp <= 0xdfff) { + symp->sym.chr = 0x10000 + (((symp->sym.chr & 0x03ff) << 10) | + (*sp & 0x03ff)); + sp++; + } else if (*sp == '\\' && (*(sp + 1) == 'x' || *(sp + 1) == 'X' || + *(sp + 1) == 'u' || *(sp + 1) == 'U')) { + sp += _ure_probe_ls(sp + 2, ep - (sp + 2), &c); + if (0xdc00 <= c && c <= 0xdfff) { + /* + * Take into account the \[xu] in front of the hex code. + */ + sp += 2; + symp->sym.chr = 0x10000 + (((symp->sym.chr & 0x03ff) << 10) | + (c & 0x03ff)); + } + } + } + + /* + * Last, make sure any _URE_CHAR type symbols are changed to lower case if + * the `casefold' flag is set. + */ + if ((b->flags & _URE_DFA_CASEFOLD) && symp->type == _URE_CHAR) + symp->sym.chr = _ure_tolower(symp->sym.chr); + + /* + * If the symbol constructed is anything other than one of the anchors, + * make sure the _URE_DFA_BLANKLINE flag is removed. + */ + if (symp->type != _URE_BOL_ANCHOR && symp->type != _URE_EOL_ANCHOR) + b->flags &= ~_URE_DFA_BLANKLINE; + + /* + * Return the number of characters consumed. + */ + return sp - sym; +} + +static int +_ure_sym_neq(_ure_symtab_t *a, _ure_symtab_t *b) +{ + if (a->type != b->type || a->mods != b->mods || a->props != b->props) + return 1; + + if (a->type == _URE_CCLASS || a->type == _URE_NCCLASS) { + if (a->sym.ccl.ranges_used != b->sym.ccl.ranges_used) + return 1; + if (a->sym.ccl.ranges_used > 0 && + memcmp((char *) a->sym.ccl.ranges, (char *) b->sym.ccl.ranges, + sizeof(_ure_range_t) * a->sym.ccl.ranges_used) != 0) + return 1; + } else if (a->type == _URE_CHAR && a->sym.chr != b->sym.chr) + return 1; + return 0; +} + +/* + * Construct a symbol, but only keep unique symbols. + */ +static ucs2_t +_ure_make_symbol(ucs2_t *sym, unsigned long limit, unsigned long *consumed, + _ure_buffer_t *b) +{ + ucs2_t i; + _ure_symtab_t *sp, symbol; + + /* + * Build the next symbol so we can test to see if it is already in the + * symbol table. + */ + (void) memset((char *) &symbol, '\0', sizeof(_ure_symtab_t)); + *consumed = _ure_compile_symbol(sym, limit, &symbol, b); + + /* + * Check to see if the symbol exists. + */ + for (i = 0, sp = b->symtab; + i < b->symtab_used && _ure_sym_neq(&symbol, sp); i++, sp++) ; + + if (i < b->symtab_used) { + /* + * Free up any ranges used for the symbol. + */ + if ((symbol.type == _URE_CCLASS || symbol.type == _URE_NCCLASS) && + symbol.sym.ccl.ranges_size > 0) + free((char *) symbol.sym.ccl.ranges); + + return b->symtab[i].id; + } + + /* + * Need to add the new symbol. + */ + if (b->symtab_used == b->symtab_size) { + if (b->symtab_size == 0) + b->symtab = (_ure_symtab_t *) malloc(sizeof(_ure_symtab_t) << 3); + else + b->symtab = (_ure_symtab_t *) + realloc((char *) b->symtab, + sizeof(_ure_symtab_t) * (b->symtab_size + 8)); + sp = b->symtab + b->symtab_size; + (void) memset((char *) sp, '\0', sizeof(_ure_symtab_t) << 3); + b->symtab_size += 8; + } + + symbol.id = b->symtab_used++; + (void) AC_MEMCPY((char *) &b->symtab[symbol.id], (char *) &symbol, + sizeof(_ure_symtab_t)); + + return symbol.id; +} + +/************************************************************************* + * + * End symbol parse functions. + * + *************************************************************************/ + +static ucs2_t +_ure_make_expr(ucs2_t type, ucs2_t lhs, ucs2_t rhs, _ure_buffer_t *b) +{ + ucs2_t i; + + if (b == 0) + return _URE_NOOP; + + /* + * Determine if the expression already exists or not. + */ + for (i = 0; i < b->expr_used; i++) { + if (b->expr[i].type == type && b->expr[i].lhs == lhs && + b->expr[i].rhs == rhs) + break; + } + if (i < b->expr_used) + return i; + + /* + * Need to add a new expression. + */ + if (b->expr_used == b->expr_size) { + if (b->expr_size == 0) + b->expr = (_ure_elt_t *) malloc(sizeof(_ure_elt_t) << 3); + else + b->expr = (_ure_elt_t *) + realloc((char *) b->expr, + sizeof(_ure_elt_t) * (b->expr_size + 8)); + b->expr_size += 8; + } + + b->expr[b->expr_used].onstack = 0; + b->expr[b->expr_used].type = type; + b->expr[b->expr_used].lhs = lhs; + b->expr[b->expr_used].rhs = rhs; + + return b->expr_used++; +} + +static unsigned char spmap[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#define _ure_isspecial(cc) ((cc) > 0x20 && (cc) < 0x7f && \ + (spmap[(cc) >> 3] & (1 << ((cc) & 7)))) + +/* + * Convert the regular expression into an NFA in a form that will be easy to + * reduce to a DFA. The starting state for the reduction will be returned. + */ +static ucs2_t +_ure_re2nfa(ucs2_t *re, unsigned long relen, _ure_buffer_t *b) +{ + ucs2_t c, state, top, sym, *sp, *ep; + unsigned long used; + + state = _URE_NOOP; + + sp = re; + ep = sp + relen; + while (b->error == _URE_OK && sp < ep) { + c = *sp++; + switch (c) { + case '(': + _ure_push(_URE_PAREN, b); + break; + case ')': + /* + * Check for the case of too many close parentheses. + */ + if (_ure_peek(b) == _URE_NOOP) { + b->error = _URE_UNBALANCED_GROUP; + break; + } + + while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) + /* + * Make an expression with the AND or OR operator and its right + * hand side. + */ + state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); + + /* + * Remove the _URE_PAREN off the stack. + */ + (void) _ure_pop(b); + break; + case '*': + state = _ure_make_expr(_URE_STAR, state, _URE_NOOP, b); + break; + case '+': + state = _ure_make_expr(_URE_PLUS, state, _URE_NOOP, b); + break; + case '?': + state = _ure_make_expr(_URE_QUEST, state, _URE_NOOP, b); + break; + case '|': + while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) + /* + * Make an expression with the AND or OR operator and its right + * hand side. + */ + state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); + + _ure_push(state, b); + _ure_push(_URE_OR, b); + break; + default: + sp--; + sym = _ure_make_symbol(sp, ep - sp, &used, b); + sp += used; + state = _ure_make_expr(_URE_SYMBOL, sym, _URE_NOOP, b); + break; + } + + if (c != '(' && c != '|' && sp < ep && + (!_ure_isspecial(*sp) || *sp == '(')) { + _ure_push(state, b); + _ure_push(_URE_AND, b); + } + } + while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) + /* + * Make an expression with the AND or OR operator and its right + * hand side. + */ + state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); + + if (b->stack.slist_used > 0) + b->error = _URE_UNBALANCED_GROUP; + + return (b->error == _URE_OK) ? state : _URE_NOOP; +} + +static void +_ure_add_symstate(ucs2_t sym, ucs2_t state, _ure_buffer_t *b) +{ + ucs2_t i, *stp; + _ure_symtab_t *sp; + + /* + * Locate the symbol in the symbol table so the state can be added. + * If the symbol doesn't exist, then a real problem exists. + */ + for (i = 0, sp = b->symtab; i < b->symtab_used && sym != sp->id; + i++, sp++) ; + + /* + * Now find out if the state exists in the symbol's state list. + */ + for (i = 0, stp = sp->states.slist; + i < sp->states.slist_used && state > *stp; i++, stp++) ; + + if (i == sp->states.slist_used || state < *stp) { + /* + * Need to add the state in order. + */ + if (sp->states.slist_used == sp->states.slist_size) { + if (sp->states.slist_size == 0) + sp->states.slist = (ucs2_t *) malloc(sizeof(ucs2_t) << 3); + else + sp->states.slist = (ucs2_t *) + realloc((char *) sp->states.slist, + sizeof(ucs2_t) * (sp->states.slist_size + 8)); + sp->states.slist_size += 8; + } + if (i < sp->states.slist_used) + (void) _ure_memmove((char *) (sp->states.slist + i + 1), + (char *) (sp->states.slist + i), + sizeof(ucs2_t) * (sp->states.slist_used - i)); + sp->states.slist[i] = state; + sp->states.slist_used++; + } +} + +static ucs2_t +_ure_add_state(ucs2_t nstates, ucs2_t *states, _ure_buffer_t *b) +{ + ucs2_t i; + _ure_state_t *sp; + + for (i = 0, sp = b->states.states; i < b->states.states_used; i++, sp++) { + if (sp->st.slist_used == nstates && + memcmp((char *) states, (char *) sp->st.slist, + sizeof(ucs2_t) * nstates) == 0) + break; + } + + if (i == b->states.states_used) { + /* + * Need to add a new DFA state (set of NFA states). + */ + if (b->states.states_used == b->states.states_size) { + if (b->states.states_size == 0) + b->states.states = (_ure_state_t *) + malloc(sizeof(_ure_state_t) << 3); + else + b->states.states = (_ure_state_t *) + realloc((char *) b->states.states, + sizeof(_ure_state_t) * (b->states.states_size + 8)); + sp = b->states.states + b->states.states_size; + (void) memset((char *) sp, '\0', sizeof(_ure_state_t) << 3); + b->states.states_size += 8; + } + + sp = b->states.states + b->states.states_used++; + sp->id = i; + + if (sp->st.slist_used + nstates > sp->st.slist_size) { + if (sp->st.slist_size == 0) + sp->st.slist = (ucs2_t *) + malloc(sizeof(ucs2_t) * (sp->st.slist_used + nstates)); + else + sp->st.slist = (ucs2_t *) + realloc((char *) sp->st.slist, + sizeof(ucs2_t) * (sp->st.slist_used + nstates)); + sp->st.slist_size = sp->st.slist_used + nstates; + } + sp->st.slist_used = nstates; + (void) AC_MEMCPY((char *) sp->st.slist, (char *) states, + sizeof(ucs2_t) * nstates); + } + + /* + * Return the ID of the DFA state representing a group of NFA states. + */ + return i; +} + +static void +_ure_reduce(ucs2_t start, _ure_buffer_t *b) +{ + ucs2_t i, j, state, eval, syms, rhs; + ucs2_t s1, s2, ns1, ns2; + _ure_state_t *sp; + _ure_symtab_t *smp; + + b->reducing = 1; + + /* + * Add the starting state for the reduction. + */ + _ure_add_state(1, &start, b); + + /* + * Process each set of NFA states that get created. + */ + for (i = 0; i < b->states.states_used; i++) { + sp = b->states.states + i; + + /* + * Push the current states on the stack. + */ + for (j = 0; j < sp->st.slist_used; j++) + _ure_push(sp->st.slist[j], b); + + /* + * Reduce the NFA states. + */ + for (j = sp->accepting = syms = 0; j < b->stack.slist_used; j++) { + state = b->stack.slist[j]; + eval = 1; + + /* + * This inner loop is the iterative equivalent of recursively + * reducing subexpressions generated as a result of a reduction. + */ + while (eval) { + switch (b->expr[state].type) { + case _URE_SYMBOL: + ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); + _ure_add_symstate(b->expr[state].lhs, ns1, b); + syms++; + eval = 0; + break; + case _URE_ONE: + sp->accepting = 1; + eval = 0; + break; + case _URE_QUEST: + s1 = b->expr[state].lhs; + ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); + state = _ure_make_expr(_URE_OR, ns1, s1, b); + break; + case _URE_PLUS: + s1 = b->expr[state].lhs; + ns1 = _ure_make_expr(_URE_STAR, s1, _URE_NOOP, b); + state = _ure_make_expr(_URE_AND, s1, ns1, b); + break; + case _URE_STAR: + s1 = b->expr[state].lhs; + ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); + ns2 = _ure_make_expr(_URE_PLUS, s1, _URE_NOOP, b); + state = _ure_make_expr(_URE_OR, ns1, ns2, b); + break; + case _URE_OR: + s1 = b->expr[state].lhs; + s2 = b->expr[state].rhs; + _ure_push(s1, b); + _ure_push(s2, b); + eval = 0; + break; + case _URE_AND: + s1 = b->expr[state].lhs; + s2 = b->expr[state].rhs; + switch (b->expr[s1].type) { + case _URE_SYMBOL: + _ure_add_symstate(b->expr[s1].lhs, s2, b); + syms++; + eval = 0; + break; + case _URE_ONE: + state = s2; + break; + case _URE_QUEST: + ns1 = b->expr[s1].lhs; + ns2 = _ure_make_expr(_URE_AND, ns1, s2, b); + state = _ure_make_expr(_URE_OR, s2, ns2, b); + break; + case _URE_PLUS: + ns1 = b->expr[s1].lhs; + ns2 = _ure_make_expr(_URE_OR, s2, state, b); + state = _ure_make_expr(_URE_AND, ns1, ns2, b); + break; + case _URE_STAR: + ns1 = b->expr[s1].lhs; + ns2 = _ure_make_expr(_URE_AND, ns1, state, b); + state = _ure_make_expr(_URE_OR, s2, ns2, b); + break; + case _URE_OR: + ns1 = b->expr[s1].lhs; + ns2 = b->expr[s1].rhs; + ns1 = _ure_make_expr(_URE_AND, ns1, s2, b); + ns2 = _ure_make_expr(_URE_AND, ns2, s2, b); + state = _ure_make_expr(_URE_OR, ns1, ns2, b); + break; + case _URE_AND: + ns1 = b->expr[s1].lhs; + ns2 = b->expr[s1].rhs; + ns2 = _ure_make_expr(_URE_AND, ns2, s2, b); + state = _ure_make_expr(_URE_AND, ns1, ns2, b); + break; + } + } + } + } + + /* + * Clear the state stack. + */ + while (_ure_pop(b) != _URE_NOOP) ; + + /* + * Reset the state pointer because the reduction may have moved it + * during a reallocation. + */ + sp = b->states.states + i; + + /* + * Generate the DFA states for the symbols collected during the + * current reduction. + */ + if (sp->trans_used + syms > sp->trans_size) { + if (sp->trans_size == 0) + sp->trans = (_ure_elt_t *) + malloc(sizeof(_ure_elt_t) * (sp->trans_used + syms)); + else + sp->trans = (_ure_elt_t *) + realloc((char *) sp->trans, + sizeof(_ure_elt_t) * (sp->trans_used + syms)); + sp->trans_size = sp->trans_used + syms; + } + + /* + * Go through the symbol table and generate the DFA state transitions + * for each symbol that has collected NFA states. + */ + for (j = syms = 0, smp = b->symtab; j < b->symtab_used; j++, smp++) { + sp = b->states.states + i; + + if (smp->states.slist_used > 0) { + sp->trans[syms].lhs = smp->id; + rhs = _ure_add_state(smp->states.slist_used, + smp->states.slist, b); + /* + * Reset the state pointer in case the reallocation moves it + * in memory. + */ + sp = b->states.states + i; + sp->trans[syms].rhs = rhs; + + smp->states.slist_used = 0; + syms++; + } + } + + /* + * Set the number of transitions actually used. + */ + sp->trans_used = syms; + } + b->reducing = 0; +} + +static void +_ure_add_equiv(ucs2_t l, ucs2_t r, _ure_buffer_t *b) +{ + ucs2_t tmp; + + l = b->states.states[l].id; + r = b->states.states[r].id; + + if (l == r) + return; + + if (l > r) { + tmp = l; + l = r; + r = tmp; + } + + /* + * Check to see if the equivalence pair already exists. + */ + for (tmp = 0; tmp < b->equiv_used && + (b->equiv[tmp].l != l || b->equiv[tmp].r != r); + tmp++) ; + + if (tmp < b->equiv_used) + return; + + if (b->equiv_used == b->equiv_size) { + if (b->equiv_size == 0) + b->equiv = (_ure_equiv_t *) malloc(sizeof(_ure_equiv_t) << 3); + else + b->equiv = (_ure_equiv_t *) realloc((char *) b->equiv, + sizeof(_ure_equiv_t) * + (b->equiv_size + 8)); + b->equiv_size += 8; + } + b->equiv[b->equiv_used].l = l; + b->equiv[b->equiv_used].r = r; + b->equiv_used++; +} + +/* + * Merge the DFA states that are equivalent. + */ +static void +_ure_merge_equiv(_ure_buffer_t *b) +{ + ucs2_t i, j, k, eq, done; + _ure_state_t *sp1, *sp2, *ls, *rs; + + for (i = 0; i < b->states.states_used; i++) { + sp1 = b->states.states + i; + if (sp1->id != i) + continue; + for (j = 0; j < i; j++) { + sp2 = b->states.states + j; + if (sp2->id != j) + continue; + b->equiv_used = 0; + _ure_add_equiv(i, j, b); + for (eq = 0, done = 0; eq < b->equiv_used; eq++) { + ls = b->states.states + b->equiv[eq].l; + rs = b->states.states + b->equiv[eq].r; + if (ls->accepting != rs->accepting || + ls->trans_used != rs->trans_used) { + done = 1; + break; + } + for (k = 0; k < ls->trans_used && + ls->trans[k].lhs == rs->trans[k].lhs; k++) ; + if (k < ls->trans_used) { + done = 1; + break; + } + + for (k = 0; k < ls->trans_used; k++) + _ure_add_equiv(ls->trans[k].rhs, rs->trans[k].rhs, b); + } + if (done == 0) + break; + } + for (eq = 0; j < i && eq < b->equiv_used; eq++) + b->states.states[b->equiv[eq].r].id = + b->states.states[b->equiv[eq].l].id; + } + + /* + * Renumber the states appropriately. + */ + for (i = eq = 0, sp1 = b->states.states; i < b->states.states_used; + sp1++, i++) + sp1->id = (sp1->id == i) ? eq++ : b->states.states[sp1->id].id; +} + +/************************************************************************* + * + * API. + * + *************************************************************************/ + +ure_buffer_t +ure_buffer_create(void) +{ + ure_buffer_t b; + + b = (ure_buffer_t) calloc(1, sizeof(_ure_buffer_t)); + + return b; +} + +void +ure_buffer_free(ure_buffer_t buf) +{ + unsigned long i; + + if (buf == 0) + return; + + if (buf->stack.slist_size > 0) + free((char *) buf->stack.slist); + + if (buf->expr_size > 0) + free((char *) buf->expr); + + for (i = 0; i < buf->symtab_size; i++) { + if (buf->symtab[i].states.slist_size > 0) + free((char *) buf->symtab[i].states.slist); + } + + if (buf->symtab_size > 0) + free((char *) buf->symtab); + + for (i = 0; i < buf->states.states_size; i++) { + if (buf->states.states[i].trans_size > 0) + free((char *) buf->states.states[i].trans); + if (buf->states.states[i].st.slist_size > 0) + free((char *) buf->states.states[i].st.slist); + } + + if (buf->states.states_size > 0) + free((char *) buf->states.states); + + if (buf->equiv_size > 0) + free((char *) buf->equiv); + + free((char *) buf); +} + +ure_dfa_t +ure_compile(ucs2_t *re, unsigned long relen, int casefold, ure_buffer_t buf) +{ + ucs2_t i, j, state; + _ure_state_t *sp; + _ure_dstate_t *dsp; + _ure_trans_t *tp; + ure_dfa_t dfa; + + if (re == 0 || *re == 0 || relen == 0 || buf == 0) + return 0; + + /* + * Reset the various fields of the compilation buffer. Default the flags + * to indicate the presense of the "^$" pattern. If any other pattern + * occurs, then this flag will be removed. This is done to catch this + * special pattern and handle it specially when matching. + */ + buf->flags = _URE_DFA_BLANKLINE | ((casefold) ? _URE_DFA_CASEFOLD : 0); + buf->reducing = 0; + buf->stack.slist_used = 0; + buf->expr_used = 0; + + for (i = 0; i < buf->symtab_used; i++) + buf->symtab[i].states.slist_used = 0; + buf->symtab_used = 0; + + for (i = 0; i < buf->states.states_used; i++) { + buf->states.states[i].st.slist_used = 0; + buf->states.states[i].trans_used = 0; + } + buf->states.states_used = 0; + + /* + * Construct the NFA. If this stage returns a 0, then an error occured or + * an empty expression was passed. + */ + if ((state = _ure_re2nfa(re, relen, buf)) == _URE_NOOP) + return 0; + + /* + * Do the expression reduction to get the initial DFA. + */ + _ure_reduce(state, buf); + + /* + * Merge all the equivalent DFA states. + */ + _ure_merge_equiv(buf); + + /* + * Construct the minimal DFA. + */ + dfa = (ure_dfa_t) malloc(sizeof(_ure_dfa_t)); + (void) memset((char *) dfa, '\0', sizeof(_ure_dfa_t)); + + dfa->flags = buf->flags & (_URE_DFA_CASEFOLD|_URE_DFA_BLANKLINE); + + /* + * Free up the NFA state groups and transfer the symbols from the buffer + * to the DFA. + */ + for (i = 0; i < buf->symtab_size; i++) { + if (buf->symtab[i].states.slist_size > 0) + free((char *) buf->symtab[i].states.slist); + } + dfa->syms = buf->symtab; + dfa->nsyms = buf->symtab_used; + + buf->symtab_used = buf->symtab_size = 0; + + /* + * Collect the total number of states and transitions needed for the DFA. + */ + for (i = state = 0, sp = buf->states.states; i < buf->states.states_used; + i++, sp++) { + if (sp->id == state) { + dfa->nstates++; + dfa->ntrans += sp->trans_used; + state++; + } + } + + /* + * Allocate enough space for the states and transitions. + */ + dfa->states = (_ure_dstate_t *) malloc(sizeof(_ure_dstate_t) * + dfa->nstates); + dfa->trans = (_ure_trans_t *) malloc(sizeof(_ure_trans_t) * dfa->ntrans); + + /* + * Actually transfer the DFA states from the buffer. + */ + dsp = dfa->states; + tp = dfa->trans; + for (i = state = 0, sp = buf->states.states; i < buf->states.states_used; + i++, sp++) { + if (sp->id == state) { + dsp->trans = tp; + dsp->ntrans = sp->trans_used; + dsp->accepting = sp->accepting; + + /* + * Add the transitions for the state. + */ + for (j = 0; j < dsp->ntrans; j++, tp++) { + tp->symbol = sp->trans[j].lhs; + tp->next_state = buf->states.states[sp->trans[j].rhs].id; + } + + dsp++; + state++; + } + } + + return dfa; +} + +void +ure_dfa_free(ure_dfa_t dfa) +{ + ucs2_t i; + + if (dfa == 0) + return; + + for (i = 0; i < dfa->nsyms; i++) { + if ((dfa->syms[i].type == _URE_CCLASS || + dfa->syms[i].type == _URE_NCCLASS) && + dfa->syms[i].sym.ccl.ranges_size > 0) + free((char *) dfa->syms[i].sym.ccl.ranges); + } + if (dfa->nsyms > 0) + free((char *) dfa->syms); + + if (dfa->nstates > 0) + free((char *) dfa->states); + if (dfa->ntrans > 0) + free((char *) dfa->trans); + free((char *) dfa); +} + +void +ure_write_dfa(ure_dfa_t dfa, FILE *out) +{ + ucs2_t i, j, k, h, l; + _ure_dstate_t *sp; + _ure_symtab_t *sym; + _ure_range_t *rp; + + if (dfa == 0 || out == 0) + return; + + /* + * Write all the different character classes. + */ + for (i = 0, sym = dfa->syms; i < dfa->nsyms; i++, sym++) { + if (sym->type == _URE_CCLASS || sym->type == _URE_NCCLASS) { + fprintf(out, "C%hd = ", sym->id); + if (sym->sym.ccl.ranges_used > 0) { + putc('[', out); + if (sym->type == _URE_NCCLASS) + putc('^', out); + } + if (sym->props != 0) { + if (sym->type == _URE_NCCLASS) + fprintf(out, "\\P"); + else + fprintf(out, "\\p"); + for (k = h = 0; k < 32; k++) { + if (sym->props & (1 << k)) { + if (h != 0) + putc(',', out); + fprintf(out, "%hd", k + 1); + h = 1; + } + } + } + /* + * Dump the ranges. + */ + for (k = 0, rp = sym->sym.ccl.ranges; + k < sym->sym.ccl.ranges_used; k++, rp++) { + /* + * Check for UTF16 characters. + */ + if (0x10000 <= rp->min_code && + rp->min_code <= 0x10ffff) { + h = (ucs2_t) (((rp->min_code - 0x10000) >> 10) + 0xd800); + l = (ucs2_t) (((rp->min_code - 0x10000) & 1023) + 0xdc00); + fprintf(out, "\\x%04hX\\x%04hX", h, l); + } else + fprintf(out, "\\x%04lX", rp->min_code & 0xffff); + if (rp->max_code != rp->min_code) { + putc('-', out); + if (rp->max_code >= 0x10000 && + rp->max_code <= 0x10ffff) { + h = (ucs2_t) (((rp->max_code - 0x10000) >> 10) + 0xd800); + l = (ucs2_t) (((rp->max_code - 0x10000) & 1023) + 0xdc00); + fprintf(out, "\\x%04hX\\x%04hX", h, l); + } else + fprintf(out, "\\x%04lX", rp->max_code & 0xffff); + } + } + if (sym->sym.ccl.ranges_used > 0) + putc(']', out); + putc('\n', out); + } + } + + for (i = 0, sp = dfa->states; i < dfa->nstates; i++, sp++) { + fprintf(out, "S%hd = ", i); + if (sp->accepting) { + fprintf(out, "1 "); + if (sp->ntrans) + fprintf(out, "| "); + } + for (j = 0; j < sp->ntrans; j++) { + if (j > 0) + fprintf(out, "| "); + + sym = dfa->syms + sp->trans[j].symbol; + switch (sym->type) { + case _URE_CHAR: + if (0x10000 <= sym->sym.chr && sym->sym.chr <= 0x10ffff) { + /* + * Take care of UTF16 characters. + */ + h = (ucs2_t) (((sym->sym.chr - 0x10000) >> 10) + 0xd800); + l = (ucs2_t) (((sym->sym.chr - 0x10000) & 1023) + 0xdc00); + fprintf(out, "\\x%04hX\\x%04hX ", h, l); + } else + fprintf(out, "\\x%04lX ", sym->sym.chr & 0xffff); + break; + case _URE_ANY_CHAR: + fprintf(out, "<any> "); + break; + case _URE_BOL_ANCHOR: + fprintf(out, "<bol-anchor> "); + break; + case _URE_EOL_ANCHOR: + fprintf(out, "<eol-anchor> "); + break; + case _URE_CCLASS: + case _URE_NCCLASS: + fprintf(out, "[C%hd] ", sym->id); + break; + } + fprintf(out, "S%hd", sp->trans[j].next_state); + if (j + 1 < sp->ntrans) + putc(' ', out); + } + putc('\n', out); + } +} + +#define _ure_issep(cc) ((cc) == '\n' || (cc) == '\r' || (cc) == 0x2028 ||\ + (cc) == 0x2029) + +int +ure_exec(ure_dfa_t dfa, int flags, ucs2_t *text, unsigned long textlen, + unsigned long *match_start, unsigned long *match_end) +{ + int i, j, matched, found, skip; + unsigned long ms, me; + ucs4_t c; + ucs2_t *sp, *ep, *lp; + _ure_dstate_t *stp; + _ure_symtab_t *sym; + _ure_range_t *rp; + + if (dfa == 0 || text == 0) + return 0; + + /* + * Handle the special case of an empty string matching the "^$" pattern. + */ + if (textlen == 0 && (dfa->flags & _URE_DFA_BLANKLINE)) { + *match_start = *match_end = 0; + return 1; + } + + sp = text; + ep = sp + textlen; + + ms = me = ~0; + + stp = dfa->states; + + for (found = skip = 0; found == 0 && sp < ep; ) { + lp = sp; + c = *sp++; + + /* + * Check to see if this is a high surrogate that should be + * combined with a following low surrogate. + */ + if (sp < ep && 0xd800 <= c && c <= 0xdbff && + 0xdc00 <= *sp && *sp <= 0xdfff) + c = 0x10000 + (((c & 0x03ff) << 10) | (*sp++ & 0x03ff)); + + /* + * Determine if the character is non-spacing and should be skipped. + */ + if (_ure_matches_properties(_URE_NONSPACING, c) && + (flags & URE_IGNORE_NONSPACING)) { + sp++; + continue; + } + + if (dfa->flags & _URE_DFA_CASEFOLD) + c = _ure_tolower(c); + + /* + * See if one of the transitions matches. + */ + for (i = 0, matched = 0; matched == 0 && i < stp->ntrans; i++) { + sym = dfa->syms + stp->trans[i].symbol; + switch (sym->type) { + case _URE_ANY_CHAR: + if ((flags & URE_DOT_MATCHES_SEPARATORS) || + !_ure_issep(c)) + matched = 1; + break; + case _URE_CHAR: + if (c == sym->sym.chr) + matched = 1; + break; + case _URE_BOL_ANCHOR: + if (lp == text) { + sp = lp; + matched = 1; + } else if (_ure_issep(c)) { + if (c == '\r' && sp < ep && *sp == '\n') + sp++; + lp = sp; + matched = 1; + } + break; + case _URE_EOL_ANCHOR: + if (_ure_issep(c)) { + /* + * Put the pointer back before the separator so the match + * end position will be correct. This case will also + * cause the `sp' pointer to be advanced over the current + * separator once the match end point has been recorded. + */ + sp = lp; + matched = 1; + } + break; + case _URE_CCLASS: + case _URE_NCCLASS: + if (sym->props != 0) + matched = _ure_matches_properties(sym->props, c); + for (j = 0, rp = sym->sym.ccl.ranges; + j < sym->sym.ccl.ranges_used; j++, rp++) { + if (rp->min_code <= c && c <= rp->max_code) + matched = 1; + } + if (sym->type == _URE_NCCLASS) + matched = !matched; + break; + } + + if (matched) { + if (ms == ~0UL) + ms = lp - text; + else + me = sp - text; + stp = dfa->states + stp->trans[i].next_state; + + /* + * If the match was an EOL anchor, adjust the pointer past the + * separator that caused the match. The correct match + * position has been recorded already. + */ + if (sym->type == _URE_EOL_ANCHOR) { + /* + * Skip the character that caused the match. + */ + sp++; + + /* + * Handle the infamous CRLF situation. + */ + if (sp < ep && c == '\r' && *sp == '\n') + sp++; + } + } + } + + if (matched == 0) { + if (stp->accepting == 0) { + /* + * If the last state was not accepting, then reset + * and start over. + */ + stp = dfa->states; + ms = me = ~0; + } else + /* + * The last state was accepting, so terminate the matching + * loop to avoid more work. + */ + found = 1; + } else if (sp == ep) { + if (!stp->accepting) { + /* + * This ugly hack is to make sure the end-of-line anchors + * match when the source text hits the end. This is only done + * if the last subexpression matches. + */ + for (i = 0; found == 0 && i < stp->ntrans; i++) { + sym = dfa->syms + stp->trans[i].symbol; + if (sym->type ==_URE_EOL_ANCHOR) { + stp = dfa->states + stp->trans[i].next_state; + if (stp->accepting) { + me = sp - text; + found = 1; + } else + break; + } + } + } else { + /* + * Make sure any conditions that match all the way to the end + * of the string match. + */ + found = 1; + me = sp - text; + } + } + } + + if (found == 0) + ms = me = ~0; + + *match_start = ms; + *match_end = me; + + return (ms != ~0UL) ? 1 : 0; +} diff --git a/libraries/liblutil/entropy.c b/libraries/liblutil/entropy.c new file mode 100644 index 0000000000000000000000000000000000000000..cd379c67246abdf878a57de454cef4123ba8aa20 --- /dev/null +++ b/libraries/liblutil/entropy.c @@ -0,0 +1,149 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#ifdef HAVE_PROCESS_H +#include <process.h> +#endif + +#include <fcntl.h> + +#include <lutil.h> +#include <lutil_md5.h> + +/* + * lutil_entropy() provides nbytes of entropy in buf. + * Quality offerred is suitable for one-time uses, such as "once" keys. + * Values may not be suitable for multi-time uses. + * + * Note: Callers are encouraged to provide additional bytes of + * of entropy in the buf argument. This information is used in + * fallback mode to improve the quality of bytes returned. + * + * This routinue should be extended to support additional sources + * of entropy. + */ +int lutil_entropy( unsigned char *buf, ber_len_t nbytes ) +{ + if( nbytes == 0 ) return 0; + +#ifdef URANDOM_DEVICE + /* Linux and *BSD offer a urandom device */ + { + int rc, fd; + + fd = open( URANDOM_DEVICE, O_RDONLY ); + + if( fd < 0 ) return -1; + + rc = read( fd, buf, nbytes ); + close(fd); + + /* should return nbytes */ + if( rc != nbytes ) return -1; + + return 0; + } +#elif PROV_RSA_FULL + { + /* Not used since _WIN32_WINNT not set... */ + HCRYPTPROV hProv = 0; + + /* Get handle to user default provider */ + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) { + return -1; + } + + /* Generate random initialization vector */ + if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) { + return -1; + } + + /* Release provider handle */ + if(hProv != 0) CryptReleaseContext(hProv, 0); + + return 0; + } +#else + { + /* based upon Phil Karn's "practical randomness" idea + * but implementation 100% OpenLDAP. So don't blame Phil. + * + * Worse case is that this is a MD5 hash of a counter, if + * MD5 is a strong cryptographic hash, this should be fairly + * resistant to attack + */ + + /* + * the caller may need to provide external synchronization OR + * provide entropy (in buf) to ensure quality results as + * access to this counter may not be atomic. + */ + static int counter = 0; + ber_len_t n; + + struct rdata_s { + int counter; + + unsigned char *buf; + struct rdata_s *stack; + + pid_t pid; + +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; +#else + time_t time; +#endif + + unsigned long junk; /* purposely not initialized */ + } rdata; + + /* make sure rdata differs for each process */ + rdata.pid = getpid(); + + /* make sure rdata differs for each program */ + rdata.buf = buf; + rdata.stack = &rdata; + + for( n = 0; n < nbytes; n += 16 ) { + struct lutil_MD5Context ctx; + char digest[16]; + + /* poor resolution */ +#ifdef HAVE_GETTIMEOFDAY + (void) gettimeofday( &rdata.tv, NULL ); +#else + (void) time( &rdata.time ); +#endif + + /* make sure rdata differs */ + rdata.counter = ++counter; + rdata.pid++; + rdata.junk++; + + lutil_MD5Init( &ctx ); + lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) ); + + /* allow caller to provided additional entropy */ + lutil_MD5Update( &ctx, buf, nbytes ); + + lutil_MD5Final( digest, &ctx ); + + AC_MEMCPY( &buf[n], digest, + nbytes - n >= 16 ? 16 : nbytes - n ); + } + + return 0; + } +#endif + return -1; +} diff --git a/libraries/liblutil/passwd.c b/libraries/liblutil/passwd.c new file mode 100644 index 0000000000000000000000000000000000000000..ee9282310cb85f6302e15753d021a00776fdd159 --- /dev/null +++ b/libraries/liblutil/passwd.c @@ -0,0 +1,1251 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * int lutil_passwd( + * const struct berval *passwd, + * const struct berval *cred, + * const char **schemes ) + * + * Returns true if user supplied credentials (cred) matches + * the stored password (passwd). + * + * Due to the use of the crypt(3) function + * this routine is NOT thread-safe. + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#ifdef SLAPD_LMHASH +# include <openssl/des.h> +#endif /* SLAPD_LMHASH */ + +#ifdef SLAPD_SPASSWD +# include <sasl.h> +#endif + +#ifdef SLAPD_KPASSWD +# include <ac/krb.h> +# include <ac/krb5.h> +#endif + +#include <ac/param.h> + +#ifdef SLAPD_CRYPT +# include <ac/crypt.h> + +# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) +# ifdef HAVE_SHADOW_H +# include <shadow.h> +# endif +# ifdef HAVE_PWD_H +# include <pwd.h> +# endif +# ifdef HAVE_AIX_SECURITY +# include <userpw.h> +# endif +# endif +#endif + +#include <lber.h> + +#include "ldap_pvt.h" + +#include "lutil_md5.h" +#include "lutil_sha1.h" +#include "lutil.h" + +static const unsigned char crypt64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./"; + +#ifdef SLAPD_CRYPT +static char *salt_format = NULL; +#endif + +struct pw_scheme; + +typedef int (*PASSWD_CHK_FUNC)( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); + +typedef struct berval * (*PASSWD_HASH_FUNC) ( + const struct pw_scheme *scheme, + const struct berval *passwd ); + +struct pw_scheme { + struct berval name; + PASSWD_CHK_FUNC chk_fn; + PASSWD_HASH_FUNC hash_fn; +}; + +/* password check routines */ +static int chk_md5( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); + +static int chk_smd5( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); + +#ifdef LUTIL_SHA1_BYTES +static int chk_ssha1( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); + +static int chk_sha1( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); +#endif + +#ifdef SLAPD_LMHASH +static int chk_lanman( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); +#endif + +#ifdef SLAPD_SPASSWD +static int chk_sasl( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); +#endif + +#ifdef SLAPD_KPASSWD +static int chk_kerberos( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); +#endif + +#ifdef SLAPD_CRYPT +static int chk_crypt( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); + +#if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) +static int chk_unix( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ); +#endif +#endif + + +#ifdef LUTIL_SHA1_BYTES +/* password hash routines */ +static struct berval *hash_sha1( + const struct pw_scheme *scheme, + const struct berval *passwd ); + +static struct berval *hash_ssha1( + const struct pw_scheme *scheme, + const struct berval *passwd ); +#endif + +static struct berval *hash_smd5( + const struct pw_scheme *scheme, + const struct berval *passwd ); + +static struct berval *hash_md5( + const struct pw_scheme *scheme, + const struct berval *passwd ); + +#ifdef SLAPD_LMHASH +static struct berval *hash_lanman( + const struct pw_scheme *scheme, + const struct berval *passwd ); +#endif + +#ifdef SLAPD_CRYPT +static struct berval *hash_crypt( + const struct pw_scheme *scheme, + const struct berval *passwd ); +#endif + + +static const struct pw_scheme pw_schemes[] = +{ +#ifdef LUTIL_SHA1_BYTES + { {sizeof("{SSHA}")-1, "{SSHA}"}, chk_ssha1, hash_ssha1 }, + { {sizeof("{SHA}")-1, "{SHA}"}, chk_sha1, hash_sha1 }, +#endif + + { {sizeof("{SMD5}")-1, "{SMD5}"}, chk_smd5, hash_smd5 }, + { {sizeof("{MD5}")-1, "{MD5}"}, chk_md5, hash_md5 }, + +#ifdef SLAPD_LMHASH + { {sizeof("{LANMAN}")-1, "{LANMAN}"}, chk_lanman, hash_lanman }, +#endif /* SLAPD_LMHASH */ + +#ifdef SLAPD_SPASSWD + { {sizeof("{SASL}")-1, "{SASL}"}, chk_sasl, NULL }, +#endif + +#ifdef SLAPD_KPASSWD + { {sizeof("{KERBEROS}")-1, "{KERBEROS}"}, chk_kerberos, NULL }, +#endif + +#ifdef SLAPD_CRYPT + { {sizeof("{CRYPT}")-1, "{CRYPT}"}, chk_crypt, hash_crypt }, +# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) + { {sizeof("{UNIX}")-1, "{UNIX}"}, chk_unix, NULL }, +# endif +#endif + +#ifdef SLAPD_CLEARTEXT + /* psuedo scheme */ + { {0, "{CLEARTEXT}"}, NULL, NULL }, +#endif + + { {0, NULL}, NULL, NULL } +}; + +static const struct pw_scheme *get_scheme( + const char* scheme ) +{ + int i; + + for( i=0; pw_schemes[i].name.bv_val; i++) { + if( pw_schemes[i].name.bv_len == 0 ) continue; + + if( strncasecmp(scheme, pw_schemes[i].name.bv_val, + pw_schemes[i].name.bv_len) == 0 ) + { + return &pw_schemes[i]; + } + } + + return NULL; +} + +int lutil_passwd_scheme( + const char* scheme ) +{ + if( scheme == NULL ) { + return 0; + } + + return get_scheme(scheme) != NULL; +} + + +static int is_allowed_scheme( + const char* scheme, + const char** schemes ) +{ + int i; + + if( schemes == NULL ) return 1; + + for( i=0; schemes[i] != NULL; i++ ) { + if( strcasecmp( scheme, schemes[i] ) == 0 ) { + return 1; + } + } + return 0; +} + +static struct berval *passwd_scheme( + const struct pw_scheme *scheme, + const struct berval * passwd, + const char** allowed ) +{ + if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) { + return NULL; + } + + if( passwd->bv_len >= scheme->name.bv_len ) { + if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) { + struct berval *bv = ber_memalloc( sizeof(struct berval) ); + + if( bv == NULL ) return NULL; + + bv->bv_val = &passwd->bv_val[scheme->name.bv_len]; + bv->bv_len = passwd->bv_len - scheme->name.bv_len; + + return bv; + } + } + + return NULL; +} + +/* + * Return 0 if creds are good. + */ +int +lutil_passwd( + const struct berval *passwd, /* stored passwd */ + const struct berval *cred, /* user cred */ + const char **schemes ) +{ + int i; + + if (cred == NULL || cred->bv_len == 0 || + passwd == NULL || passwd->bv_len == 0 ) + { + return -1; + } + + for( i=0; pw_schemes[i].name.bv_val != NULL; i++ ) { + if( pw_schemes[i].chk_fn ) { + struct berval *p = passwd_scheme( &pw_schemes[i], + passwd, schemes ); + + if( p != NULL ) { + int rc = (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred ); + + /* only free the berval structure as the bv_val points + * into passwd->bv_val + */ + ber_memfree( p ); + + return rc; + } + } + } + +#ifdef SLAPD_CLEARTEXT + if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) { + return passwd->bv_len == cred->bv_len + ? memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len ) + : 1; + } +#endif + return 1; +} + +struct berval * lutil_passwd_generate( ber_len_t len ) +{ + struct berval *pw; + + if( len < 1 ) return NULL; + + pw = ber_memalloc( sizeof( struct berval ) ); + if( pw == NULL ) return NULL; + + pw->bv_len = len; + pw->bv_val = ber_memalloc( len + 1 ); + + if( pw->bv_val == NULL ) { + ber_memfree( pw ); + return NULL; + } + + if( lutil_entropy( pw->bv_val, pw->bv_len) < 0 ) { + ber_bvfree( pw ); + return NULL; + } + + for( len = 0; len < pw->bv_len; len++ ) { + pw->bv_val[len] = crypt64[ + pw->bv_val[len] % (sizeof(crypt64)-1) ]; + } + + pw->bv_val[len] = '\0'; + + return pw; +} + +struct berval * lutil_passwd_hash( + const struct berval * passwd, + const char * method ) +{ + const struct pw_scheme *sc = get_scheme( method ); + + if( sc == NULL ) return NULL; + if( ! sc->hash_fn ) return NULL; + + return (sc->hash_fn)( sc, passwd ); +} + +/* pw_string is only called when SLAPD_LMHASH or SLAPD_CRYPT is defined */ +#if defined(SLAPD_LMHASH) || defined(SLAPD_CRYPT) +static struct berval * pw_string( + const struct pw_scheme *sc, + const struct berval *passwd ) +{ + struct berval *pw = ber_memalloc( sizeof( struct berval ) ); + if( pw == NULL ) return NULL; + + pw->bv_len = sc->name.bv_len + passwd->bv_len; + pw->bv_val = ber_memalloc( pw->bv_len + 1 ); + + if( pw->bv_val == NULL ) { + ber_memfree( pw ); + return NULL; + } + + AC_MEMCPY( pw->bv_val, sc->name.bv_val, sc->name.bv_len ); + AC_MEMCPY( &pw->bv_val[sc->name.bv_len], passwd->bv_val, passwd->bv_len ); + + pw->bv_val[pw->bv_len] = '\0'; + return pw; +} +#endif /* SLAPD_LMHASH || SLAPD_CRYPT */ + +static struct berval * pw_string64( + const struct pw_scheme *sc, + const struct berval *hash, + const struct berval *salt ) +{ + int rc; + struct berval string; + struct berval *b64 = ber_memalloc( sizeof(struct berval) ); + size_t b64len; + + if( b64 == NULL ) return NULL; + + if( salt ) { + /* need to base64 combined string */ + string.bv_len = hash->bv_len + salt->bv_len; + string.bv_val = ber_memalloc( string.bv_len + 1 ); + + if( string.bv_val == NULL ) { + ber_memfree( b64 ); + return NULL; + } + + AC_MEMCPY( string.bv_val, hash->bv_val, + hash->bv_len ); + AC_MEMCPY( &string.bv_val[hash->bv_len], salt->bv_val, + salt->bv_len ); + string.bv_val[string.bv_len] = '\0'; + + } else { + string = *hash; + } + + b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1; + b64->bv_len = b64len + sc->name.bv_len; + b64->bv_val = ber_memalloc( b64->bv_len + 1 ); + + if( b64->bv_val == NULL ) { + if( salt ) ber_memfree( string.bv_val ); + ber_memfree( b64 ); + return NULL; + } + + AC_MEMCPY(b64->bv_val, sc->name.bv_val, sc->name.bv_len); + + rc = lutil_b64_ntop( + string.bv_val, string.bv_len, + &b64->bv_val[sc->name.bv_len], b64len ); + + if( salt ) ber_memfree( string.bv_val ); + + if( rc < 0 ) { + ber_bvfree( b64 ); + return NULL; + } + + /* recompute length */ + b64->bv_len = sc->name.bv_len + rc; + assert( strlen(b64->bv_val) == b64->bv_len ); + return b64; +} + +/* PASSWORD CHECK ROUTINES */ + +#ifdef LUTIL_SHA1_BYTES +static int chk_ssha1( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[LUTIL_SHA1_BYTES]; + int rc; + unsigned char *orig_pass = NULL; + + /* decode base64 password */ + orig_pass = (unsigned char *) ber_memalloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) ); + + if( orig_pass == NULL ) return -1; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len); + + if(rc < 0) { + ber_memfree(orig_pass); + return -1; + } + + /* hash credentials with salt */ + lutil_SHA1Init(&SHA1context); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) cred->bv_val, cred->bv_len); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) &orig_pass[sizeof(SHA1digest)], + rc - sizeof(SHA1digest)); + lutil_SHA1Final(SHA1digest, &SHA1context); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); + ber_memfree(orig_pass); + return rc ? 1 : 0; +} + +static int chk_sha1( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[LUTIL_SHA1_BYTES]; + int rc; + unsigned char *orig_pass = NULL; + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) ); + + if( orig_pass == NULL ) return -1; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len); + + if( rc != sizeof(SHA1digest) ) { + ber_memfree(orig_pass); + return -1; + } + + /* hash credentials with salt */ + lutil_SHA1Init(&SHA1context); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) cred->bv_val, cred->bv_len); + lutil_SHA1Final(SHA1digest, &SHA1context); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); + ber_memfree(orig_pass); + return rc ? 1 : 0; +} +#endif + +static int chk_smd5( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES]; + int rc; + unsigned char *orig_pass = NULL; + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) ); + + if( orig_pass == NULL ) return -1; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len); + if ( rc < 0 ) { + ber_memfree(orig_pass); + return -1; + } + + /* hash credentials with salt */ + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *) cred->bv_val, + cred->bv_len ); + lutil_MD5Update(&MD5context, + &orig_pass[sizeof(MD5digest)], + rc - sizeof(MD5digest)); + lutil_MD5Final(MD5digest, &MD5context); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); + ber_memfree(orig_pass); + return rc ? 1 : 0; +} + +static int chk_md5( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES]; + int rc; + unsigned char *orig_pass = NULL; + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) ); + + if( orig_pass == NULL ) return -1; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len); + if ( rc != sizeof(MD5digest) ) { + ber_memfree(orig_pass); + return -1; + } + + /* hash credentials with salt */ + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *) cred->bv_val, + cred->bv_len ); + lutil_MD5Final(MD5digest, &MD5context); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); + ber_memfree(orig_pass); + return rc ? 1 : 0; +} + +#ifdef SLAPD_LMHASH +static int chk_lanman( + const struct pw_scheme *scheme, + const struct berval *passwd, + const struct berval *cred ) +{ + struct berval *hash; + + hash = hash_lanman( scheme, cred ); + return memcmp( &hash->bv_val[scheme->name.bv_len], passwd->bv_val, 32); +} +#endif /* SLAPD_LMHASH */ + +#ifdef SLAPD_SPASSWD +#ifdef HAVE_CYRUS_SASL +sasl_conn_t *lutil_passwd_sasl_conn = NULL; +#endif + +static int chk_sasl( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + unsigned int i; + int rtn; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return 1; /* NUL character in password */ + } + } + + if( cred->bv_val[i] != '\0' ) { + return 1; /* cred must behave like a string */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return 1; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return 1; /* passwd must behave like a string */ + } + + rtn = 1; + +#ifdef HAVE_CYRUS_SASL + if( lutil_passwd_sasl_conn != NULL ) { + const char *errstr = NULL; + int sc; + + sc = sasl_checkpass( lutil_passwd_sasl_conn, + passwd->bv_val, passwd->bv_len, + cred->bv_val, cred->bv_len, + &errstr ); + + rtn = ( sc != SASL_OK ); + } +#endif + + return rtn; +} +#endif + +#ifdef SLAPD_KPASSWD +static int chk_kerberos( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + unsigned int i; + int rtn; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return 1; /* NUL character in password */ + } + } + + if( cred->bv_val[i] != '\0' ) { + return 1; /* cred must behave like a string */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return 1; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return 1; /* passwd must behave like a string */ + } + + rtn = 1; + +#ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */ + { +/* Portions: + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + krb5_context context; + krb5_error_code ret; + krb5_creds creds; + krb5_get_init_creds_opt get_options; + krb5_verify_init_creds_opt verify_options; + krb5_principal client, server; +#ifdef notdef + krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; +#endif + + ret = krb5_init_context( &context ); + if (ret) { + return 1; + } + +#ifdef notdef + krb5_get_init_creds_opt_set_preauth_list(&get_options, + pre_auth_types, 1); +#endif + + krb5_get_init_creds_opt_init( &get_options ); + + krb5_verify_init_creds_opt_init( &verify_options ); + + ret = krb5_parse_name( context, passwd->bv_val, &client ); + + if (ret) { + krb5_free_context( context ); + return 1; + } + + ret = krb5_get_init_creds_password( context, + &creds, client, cred->bv_val, NULL, + NULL, 0, NULL, &get_options ); + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return 1; + } + + { + char *host = ldap_pvt_get_fqdn( NULL ); + + if( host == NULL ) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return 1; + } + + ret = krb5_sname_to_principal( context, + host, "ldap", KRB5_NT_SRV_HST, &server ); + + ber_memfree( host ); + } + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return 1; + } + + ret = krb5_verify_init_creds( context, + &creds, server, NULL, NULL, &verify_options ); + + krb5_free_principal( context, client ); + krb5_free_principal( context, server ); + krb5_free_cred_contents( context, &creds ); + krb5_free_context( context ); + + rtn = !!ret; + } +#elif defined(HAVE_KRB4) + { + /* Borrowed from Heimdal kpopper */ +/* Portions: + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + + int status; + char lrealm[REALM_SZ]; + char tkt[MAXHOSTNAMELEN]; + + status = krb_get_lrealm(lrealm,1); + if (status == KFAILURE) { + return 1; + } + + snprintf(tkt, sizeof(tkt), "%s_slapd.%u", + TKT_ROOT, (unsigned)getpid()); + krb_set_tkt_string (tkt); + + status = krb_verify_user( passwd->bv_val, "", lrealm, + cred->bv_val, 1, "ldap"); + + dest_tkt(); /* no point in keeping the tickets */ + + return status == KFAILURE; + } +#endif + + return rtn; +} +#endif /* SLAPD_KPASSWD */ + +#ifdef SLAPD_CRYPT +static int chk_crypt( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + char *cr; + unsigned int i; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return 1; /* NUL character in password */ + } + } + + if( cred->bv_val[i] != '\0' ) { + return -1; /* cred must behave like a string */ + } + + if( passwd->bv_len < 2 ) { + return -1; /* passwd must be at least two characters long */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return -1; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return -1; /* passwd must behave like a string */ + } + + cr = crypt( cred->bv_val, passwd->bv_val ); + + if( cr == NULL || cr[0] == '\0' ) { + /* salt must have been invalid */ + return -1; + } + + return strcmp( passwd->bv_val, cr ) ? 1 : 0; +} + +# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) +static int chk_unix( + const struct pw_scheme *sc, + const struct berval * passwd, + const struct berval * cred ) +{ + unsigned int i; + char *pw,*cr; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return -1; /* NUL character in password */ + } + } + if( cred->bv_val[i] != '\0' ) { + return -1; /* cred must behave like a string */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return -1; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return -1; /* passwd must behave like a string */ + } + + { + struct passwd *pwd = getpwnam(passwd->bv_val); + + if(pwd == NULL) { + return -1; /* not found */ + } + + pw = pwd->pw_passwd; + } +# ifdef HAVE_GETSPNAM + { + struct spwd *spwd = getspnam(passwd->bv_val); + + if(spwd != NULL) { + pw = spwd->sp_pwdp; + } + } +# endif +# ifdef HAVE_AIX_SECURITY + { + struct userpw *upw = getuserpw(passwd->bv_val); + + if (upw != NULL) { + pw = upw->upw_passwd; + } + } +# endif + + if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) { + /* password must must be at least two characters long */ + return -1; + } + + cr = crypt(cred->bv_val, pw); + + if( cr == NULL || cr[0] == '\0' ) { + /* salt must have been invalid */ + return -1; + } + + return strcmp(pw, cr) ? 1 : 0; + +} +# endif +#endif + +/* PASSWORD GENERATION ROUTINES */ + +#ifdef LUTIL_SHA1_BYTES +static struct berval *hash_ssha1( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[LUTIL_SHA1_BYTES]; + unsigned char saltdata[4]; + struct berval digest; + struct berval salt; + + digest.bv_val = SHA1digest; + digest.bv_len = sizeof(SHA1digest); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) { + return NULL; + } + + lutil_SHA1Init( &SHA1context ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)passwd->bv_val, passwd->bv_len ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)salt.bv_val, salt.bv_len ); + lutil_SHA1Final( SHA1digest, &SHA1context ); + + return pw_string64( scheme, &digest, &salt); +} + +static struct berval *hash_sha1( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[LUTIL_SHA1_BYTES]; + struct berval digest; + digest.bv_val = SHA1digest; + digest.bv_len = sizeof(SHA1digest); + + lutil_SHA1Init( &SHA1context ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)passwd->bv_val, passwd->bv_len ); + lutil_SHA1Final( SHA1digest, &SHA1context ); + + return pw_string64( scheme, &digest, NULL); +} +#endif + +static struct berval *hash_smd5( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES]; + unsigned char saltdata[4]; + struct berval digest; + struct berval salt; + + digest.bv_val = MD5digest; + digest.bv_len = sizeof(MD5digest); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) { + return NULL; + } + + lutil_MD5Init( &MD5context ); + lutil_MD5Update( &MD5context, + (const unsigned char *) passwd->bv_val, passwd->bv_len ); + lutil_MD5Update( &MD5context, + (const unsigned char *) salt.bv_val, salt.bv_len ); + lutil_MD5Final( MD5digest, &MD5context ); + + return pw_string64( scheme, &digest, &salt ); +} + +static struct berval *hash_md5( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES]; + + struct berval digest; + + digest.bv_val = MD5digest; + digest.bv_len = sizeof(MD5digest); + + lutil_MD5Init( &MD5context ); + lutil_MD5Update( &MD5context, + (const unsigned char *) passwd->bv_val, passwd->bv_len ); + lutil_MD5Final( MD5digest, &MD5context ); + + return pw_string64( scheme, &digest, NULL ); +; +} + +#ifdef SLAPD_LMHASH +/* pseudocode from RFC2433 + * A.2 LmPasswordHash() + * + * LmPasswordHash( + * IN 0-to-14-oem-char Password, + * OUT 16-octet PasswordHash ) + * { + * Set UcasePassword to the uppercased Password + * Zero pad UcasePassword to 14 characters + * + * DesHash( 1st 7-octets of UcasePassword, + * giving 1st 8-octets of PasswordHash ) + * + * DesHash( 2nd 7-octets of UcasePassword, + * giving 2nd 8-octets of PasswordHash ) + * } + * + * + * A.3 DesHash() + * + * DesHash( + * IN 7-octet Clear, + * OUT 8-octet Cypher ) + * { + * * + * * Make Cypher an irreversibly encrypted form of Clear by + * * encrypting known text using Clear as the secret key. + * * The known text consists of the string + * * + * * KGS!@#$% + * * + * + * Set StdText to "KGS!@#$%" + * DesEncrypt( StdText, Clear, giving Cypher ) + * } + * + * + * A.4 DesEncrypt() + * + * DesEncrypt( + * IN 8-octet Clear, + * IN 7-octet Key, + * OUT 8-octet Cypher ) + * { + * * + * * Use the DES encryption algorithm [4] in ECB mode [9] + * * to encrypt Clear into Cypher such that Cypher can + * * only be decrypted back to Clear by providing Key. + * * Note that the DES algorithm takes as input a 64-bit + * * stream where the 8th, 16th, 24th, etc. bits are + * * parity bits ignored by the encrypting algorithm. + * * Unless you write your own DES to accept 56-bit input + * * without parity, you will need to insert the parity bits + * * yourself. + * * + * } + */ + +static void lmPasswd_to_key( + const unsigned char *lmPasswd, + des_cblock *key) +{ + /* make room for parity bits */ + ((char *)key)[0] = lmPasswd[0]; + ((char *)key)[1] = ((lmPasswd[0]&0x01)<<7) | (lmPasswd[1]>>1); + ((char *)key)[2] = ((lmPasswd[1]&0x03)<<6) | (lmPasswd[2]>>2); + ((char *)key)[3] = ((lmPasswd[2]&0x07)<<5) | (lmPasswd[3]>>3); + ((char *)key)[4] = ((lmPasswd[3]&0x0F)<<4) | (lmPasswd[4]>>4); + ((char *)key)[5] = ((lmPasswd[4]&0x1F)<<3) | (lmPasswd[5]>>5); + ((char *)key)[6] = ((lmPasswd[5]&0x3F)<<2) | (lmPasswd[6]>>6); + ((char *)key)[7] = ((lmPasswd[6]&0x7F)<<1); + + des_set_odd_parity( key ); +} + +static struct berval *hash_lanman( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + + int i; + char UcasePassword[15]; + des_cblock key; + des_key_schedule schedule; + des_cblock StdText = "KGS!@#$%"; + des_cblock hash1, hash2; + char lmhash[33]; + struct berval hash; + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return NULL; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return NULL; /* passwd must behave like a string */ + } + + strncpy( UcasePassword, passwd->bv_val, 14 ); + UcasePassword[14] = '\0'; + ldap_pvt_str2upper( UcasePassword ); + + lmPasswd_to_key( UcasePassword, &key ); + des_set_key_unchecked( &key, schedule ); + des_ecb_encrypt( &StdText, &hash1, schedule , DES_ENCRYPT ); + + lmPasswd_to_key( &UcasePassword[7], &key ); + des_set_key_unchecked( &key, schedule ); + des_ecb_encrypt( &StdText, &hash2, schedule , DES_ENCRYPT ); + + sprintf( lmhash, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + hash1[0],hash1[1],hash1[2],hash1[3],hash1[4],hash1[5],hash1[6],hash1[7], + hash2[0],hash2[1],hash2[2],hash2[3],hash2[4],hash2[5],hash2[6],hash2[7] ); + + hash.bv_val = lmhash; + hash.bv_len = 32; + + return pw_string( scheme, &hash ); +} +#endif /* SLAPD_LMHASH */ + +#ifdef SLAPD_CRYPT +static struct berval *hash_crypt( + const struct pw_scheme *scheme, + const struct berval *passwd ) +{ + struct berval hash; + unsigned char salt[32]; /* salt suitable for most anything */ + unsigned int i; + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return NULL; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return NULL; /* passwd must behave like a string */ + } + + if( lutil_entropy( salt, sizeof( salt ) ) < 0 ) { + return NULL; + } + + for( i=0; i< ( sizeof(salt) - 1 ); i++ ) { + salt[i] = crypt64[ salt[i] % (sizeof(crypt64)-1) ]; + } + salt[sizeof( salt ) - 1 ] = '\0'; + + if( salt_format != NULL ) { + /* copy the salt we made into entropy before snprintfing + it back into the salt */ + char entropy[sizeof(salt)]; + strcpy( entropy, salt ); + snprintf( salt, sizeof(entropy), salt_format, entropy ); + } + + hash.bv_val = crypt( passwd->bv_val, salt ); + + if( hash.bv_val == NULL ) return NULL; + + hash.bv_len = strlen( hash.bv_val ); + + if( hash.bv_len == 0 ) { + return NULL; + } + + return pw_string( scheme, &hash ); +} +#endif + +int lutil_salt_format(const char *format) +{ +#ifdef SLAPD_CRYPT + free( salt_format ); + + salt_format = format != NULL ? strdup( format ) : NULL; +#endif + + return 0; +} diff --git a/libraries/librewrite/config.c b/libraries/librewrite/config.c new file mode 100644 index 0000000000000000000000000000000000000000..556fd3094779810f1add33e235ea9e45a198b635 --- /dev/null +++ b/libraries/librewrite/config.c @@ -0,0 +1,407 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" +#include "rewrite-map.h" + +/* + * Parses a plugin map + */ +static int +rewrite_parse_builtin_map( + struct rewrite_info *info, + const char *fname, + int lineno, + int argc, + char **argv +); + +/* + * Parses a config line and takes actions to fit content in rewrite structure; + * lines handled are of the form: + * + * rewriteEngine {on|off} + * rewriteMaxPasses numPasses + * rewriteContext contextName [alias aliasedContextName] + * rewriteRule pattern substPattern [ruleFlags] + * rewriteMap mapType mapName [mapArgs] + * rewriteParam paramName paramValue + */ +int +rewrite_parse( + struct rewrite_info *info, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + int rc = -1; + + assert( info != NULL ); + assert( fname != NULL ); + assert( argv != NULL ); + assert( argc > 0 ); + + /* + * Switch on the rewrite engine + */ + if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) { + if ( argc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteEngine needs 'state'\n%s", + fname, lineno, "" ); + return -1; + } else if ( argc > 2 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] extra fields in rewriteEngine" + " will be discarded\n%s", + fname, lineno, "" ); + } + + if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) { + info->li_state = REWRITE_ON; + } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) { + info->li_state = REWRITE_OFF; + } else { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] unknown 'state' in rewriteEngine;" + " assuming 'on'\n%s", + fname, lineno, "" ); + info->li_state = REWRITE_ON; + } + rc = REWRITE_SUCCESS; + + /* + * Alter max passes + */ + } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) { + if ( argc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteMaxPasses needs 'value'\n%s", + fname, lineno, "" ); + return -1; + } + info->li_max_passes = atoi( argv[ 1 ] ); + rc = REWRITE_SUCCESS; + + /* + * Start a new rewrite context and set current context + */ + } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) { + if ( argc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteContext needs 'name'\n%s", + fname, lineno, "" ); + return -1; + } + + /* + * Checks for existence (lots of contexts should be + * available by default ...) + */ + __curr_context = rewrite_context_find( info, argv[ 1 ] ); + if ( __curr_context == NULL ) { + __curr_context = rewrite_context_create( info, + argv[ 1 ] ); + } + if ( __curr_context == NULL ) { + return -1; + } + + if ( argc > 2 ) { + + /* + * A context can alias another (e.g., the `builtin' + * contexts for backend operations, if not defined, + * alias the `default' rewrite context (with the + * notable exception of the searchResult context, + * which can be undefined) + */ + if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) { + struct rewrite_context *aliased; + + if ( argc == 3 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteContext" + " needs 'name' after" + " 'alias'\n%s", + fname, lineno, "" ); + return -1; + } else if ( argc > 4 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] extra fields in" + " rewriteContext" + " after aliased name" + " will be" + " discarded\n%s", + fname, lineno, "" ); + } + + aliased = rewrite_context_find( info, + argv[ 3 ] ); + if ( aliased == NULL ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] aliased" + " rewriteContext '%s'" + " does not exists\n", + fname, lineno, + argv[ 3 ] ); + return -1; + } + + __curr_context->lc_alias = aliased; + __curr_context = aliased; + } else { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] extra fields" + " in rewriteContext" + " will be discarded\n%s", + fname, lineno, "" ); + } + } + rc = REWRITE_SUCCESS; + + /* + * Compile a rule in current context + */ + } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) { + if ( argc < 3 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteRule needs 'pattern'" + " 'subst' ['flags']\n%s", + fname, lineno, "" ); + return -1; + } else if ( argc > 4 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] extra fields in rewriteRule" + " will be discarded\n%s", + fname, lineno, "" ); + } + + if ( __curr_context == NULL ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteRule outside a" + " context; will add to default\n%s", + fname, lineno, "" ); + __curr_context = rewrite_context_find( info, + REWRITE_DEFAULT_CONTEXT ); + + /* + * Default context MUST exist in a properly initialized + * struct rewrite_info + */ + assert( __curr_context != NULL ); + } + + rc = rewrite_rule_compile( info, __curr_context, argv[ 1 ], + argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); + + /* + * Add a plugin map to the map tree + */ + } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) { + if ( argc < 3 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteMap needs at least 'type'" + " and 'name' ['args']\n%s", + fname, lineno, "" ); + return -1; + } + + rc = rewrite_parse_builtin_map( info, fname, lineno, + argc, argv ); + + /* + * Set the value of a global scope parameter + */ + } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) { + if ( argc < 3 ) { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] rewriteParam needs 'name'" + " and 'value'\n%s", + fname, lineno, "" ); + return -1; + } + + rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] ); + + /* + * Error + */ + } else { + Debug( LDAP_DEBUG_ANY, + "[%s:%d] unknown command '%s'\n", + fname, lineno, "" ); + return -1; + } + + return rc; +} + +/* + * Compares two maps + */ +static int +rewrite_builtin_map_cmp( + const void *c1, + const void *c2 +) +{ + const struct rewrite_builtin_map *m1, *m2; + + m1 = ( const struct rewrite_builtin_map * )c1; + m2 = ( const struct rewrite_builtin_map * )c2; + + assert( m1 != NULL ); + assert( m2 != NULL ); + assert( m1->lb_name != NULL ); + assert( m2->lb_name != NULL ); + + return strcasecmp( m1->lb_name, m2->lb_name ); +} + +/* + * Duplicate map ? + */ +static int +rewrite_builtin_map_dup( + void *c1, + void *c2 +) +{ + struct rewrite_builtin_map *m1, *m2; + + m1 = ( struct rewrite_builtin_map * )c1; + m2 = ( struct rewrite_builtin_map * )c2; + + assert( m1 != NULL ); + assert( m2 != NULL ); + assert( m1->lb_name != NULL ); + assert( m2->lb_name != NULL ); + + return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 ); +} + +/* + * Adds a map to the info map tree + */ +static int +rewrite_builtin_map_insert( + struct rewrite_info *info, + struct rewrite_builtin_map *map +) +{ + /* + * May need a mutex? + */ + return avl_insert( &info->li_maps, ( caddr_t )map, + rewrite_builtin_map_cmp, + rewrite_builtin_map_dup ); +} + +/* + * Retrieves a map + */ +struct rewrite_builtin_map * +rewrite_builtin_map_find( + struct rewrite_info *info, + const char *name +) +{ + struct rewrite_builtin_map tmp; + + assert( info != NULL ); + assert( name != NULL ); + + tmp.lb_name = ( char * )name; + + return ( struct rewrite_builtin_map * )avl_find( info->li_maps, + ( caddr_t )&tmp, rewrite_builtin_map_cmp ); +} + +/* + * Parses a plugin map + */ +static int +rewrite_parse_builtin_map( + struct rewrite_info *info, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + struct rewrite_builtin_map *map; + +#define MAP_TYPE 1 +#define MAP_NAME 2 + + assert( info != NULL ); + assert( fname != NULL ); + assert( argc > 2 ); + assert( argv != NULL ); + assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ); + + map = calloc( sizeof( struct rewrite_builtin_map ), 1 ); + if ( map == NULL ) { + return REWRITE_ERR; + } + + map->lb_name = strdup( argv[ MAP_NAME ] ); + if ( map->lb_name == NULL ) { + free( map ); + return REWRITE_ERR; + } + + /* + * Built-in ldap map + */ + if ( strcasecmp( argv[ MAP_TYPE ], "ldap" ) == 0 ) { + map->lb_type = REWRITE_BUILTIN_MAP_LDAP; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) { + free( map->lb_name ); + free( map ); + return REWRITE_ERR; + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + map->lb_private = map_ldap_parse( info, fname, lineno, + argc - 3, argv + 3 ); + + /* + * Error + */ + } else { + Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s", + fname, lineno, "" ); + return -1; + } + + return rewrite_builtin_map_insert( info, map ); +} diff --git a/libraries/librewrite/context.c b/libraries/librewrite/context.c new file mode 100644 index 0000000000000000000000000000000000000000..115cca6f1e26200d0d5f89bb6525d15ed7f9b747 --- /dev/null +++ b/libraries/librewrite/context.c @@ -0,0 +1,415 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" + +/* + * Compares two struct rewrite_context based on the name; + * used by avl stuff + */ +static int +rewrite_context_cmp( + const void *c1, + const void *c2 +) +{ + const struct rewrite_context *lc1, *lc2; + + lc1 = (const struct rewrite_context *)c1; + lc2 = (const struct rewrite_context *)c2; + + assert( c1 != NULL ); + assert( c2 != NULL ); + assert( lc1->lc_name != NULL ); + assert( lc2->lc_name != NULL ); + + return strcasecmp( lc1->lc_name, lc2->lc_name ); +} + +/* + * Returns -1 in case a duplicate struct rewrite_context + * has been inserted; used by avl stuff + */ +static int +rewrite_context_dup( + void *c1, + void *c2 + ) +{ + struct rewrite_context *lc1, *lc2; + + lc1 = (struct rewrite_context *)c1; + lc2 = (struct rewrite_context *)c2; + + assert( c1 != NULL ); + assert( c2 != NULL ); + assert( lc1->lc_name != NULL ); + assert( lc2->lc_name != NULL ); + + return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 ); +} + +/* + * Finds the context named rewriteContext in the context tree + */ +struct rewrite_context * +rewrite_context_find( + struct rewrite_info *info, + const char *rewriteContext +) +{ + struct rewrite_context *context, c; + + assert( info != NULL ); + assert( rewriteContext != NULL ); + + /* + * Fetches the required rewrite context + */ + c.lc_name = (char *)rewriteContext; + context = (struct rewrite_context *)avl_find( info->li_context, + (caddr_t)&c, rewrite_context_cmp ); + if ( context == NULL ) { + return NULL; + } + + /* + * De-aliases the context if required + */ + if ( context->lc_alias ) { + return context->lc_alias; + } + + return context; +} + +/* + * Creates a new context called rewriteContext and stores in into the tree + */ +struct rewrite_context * +rewrite_context_create( + struct rewrite_info *info, + const char *rewriteContext +) +{ + struct rewrite_context *context; + int rc; + + assert( info != NULL ); + assert( rewriteContext != NULL ); + + context = calloc( sizeof( struct rewrite_context ), 1 ); + if ( context == NULL ) { + return NULL; + } + + /* + * Context name + */ + context->lc_name = strdup( rewriteContext ); + if ( context->lc_name == NULL ) { + free( context ); + return NULL; + } + + /* + * The first, empty rule + */ + context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 ); + if ( context->lc_rule == NULL ) { + free( context->lc_name ); + free( context ); + return NULL; + } + + /* + * Add context to tree + */ + rc = avl_insert( &info->li_context, (caddr_t)context, + rewrite_context_cmp, rewrite_context_dup ); + if ( rc == -1 ) { + free( context->lc_rule ); + free( context->lc_name ); + free( context ); + return NULL; + } + + return context; +} + +/* + * Finds the next rule according to a goto action statement, + * or null in case of error. + * Helper for rewrite_context_apply. + */ +static struct rewrite_rule * +rewrite_action_goto( + struct rewrite_action *action, + struct rewrite_rule *rule +) +{ + int n; + + assert( action != NULL ); + assert( action->la_args != NULL ); + assert( rule != NULL ); + + n = ((int *)action->la_args)[ 0 ]; + + if ( n > 0 ) { + for ( ; n > 1 && rule != NULL ; n-- ) { + rule = rule->lr_next; + } + } else if ( n <= 0 ) { + for ( ; n < 1 && rule != NULL ; n++ ) { + rule = rule->lr_prev; + } + } + + return rule; +} + +/* + * Rewrites string according to context; may return: + * OK: fine; if *result != NULL rule matched and rewrite succeeded. + * STOP: fine, rule matched; stop processing following rules + * UNWILL: rule matched; force 'unwilling to perform' + */ +int +rewrite_context_apply( + struct rewrite_info *info, + struct rewrite_op *op, + struct rewrite_context *context, + const char *string, + char **result +) +{ + struct rewrite_rule *rule; + char *s, *res = NULL; + int return_code = REWRITE_REGEXEC_OK; + + assert( info != NULL ); + assert( op != NULL ); + assert( context != NULL ); + assert( context->lc_rule != NULL ); + assert( string != NULL ); + assert( result != NULL ); + + op->lo_depth++; + assert( op->lo_depth > 0 ); + + Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" + " [depth=%d] string='%s'\n%s", + op->lo_depth, string, "" ); + + s = strdup( string ); + + for ( rule = context->lc_rule->lr_next; + rule != NULL && op->lo_num_passes < info->li_max_passes; + rule = rule->lr_next, op->lo_num_passes++ ) { + int rc; + + /* + * Apply a single rule + */ + rc = rewrite_rule_apply( info, op, rule, s, &res ); + + /* + * A rule may return: + * OK with result != NULL if matched + * ERR if anything was wrong + * UNWILLING if the server should drop the request + * the latter case in honored immediately; + * the other two may require some special actions to take + * place. + */ + switch ( rc ) { + + case REWRITE_REGEXEC_ERR: + Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" + " error ...\n%s%s%s", "", "", ""); + + /* + * Checks for special actions to be taken + * in case of error ... + */ + if ( rule->lr_action != NULL ) { + struct rewrite_action *action; + int do_continue = 0; + + for ( action = rule->lr_action; + action != NULL; + action = action->la_next ) { + switch ( action->la_type ) { + + /* + * This action takes precedence + * over the others in case of failure + */ + case REWRITE_ACTION_IGNORE_ERR: + Debug( LDAP_DEBUG_ANY, + "==> rewrite_context_apply" + " ignoring error ...\n%s%s%s", + "", "", "" ); + do_continue = 1; + break; + + /* + * Goto is honored only if it comes + * after ignore error + */ + case REWRITE_ACTION_GOTO: + if ( do_continue ) { + rule = rewrite_action_goto( action, rule ); + if ( rule == NULL ) { + return_code = REWRITE_REGEXEC_ERR; + goto rc_end_of_context; + } + } + break; + + /* + * Other actions are ignored + */ + default: + break; + } + } + + if ( do_continue ) { + if ( rule->lr_next == NULL ) { + res = s; + } + goto rc_continue; + } + } + + /* + * Default behavior is to bail out ... + */ + return_code = REWRITE_REGEXEC_ERR; + goto rc_end_of_context; + + /* + * OK means there were no errors or special return codes; + * if res is defined, it means the rule matched and we + * got a sucessful rewriting + */ + case REWRITE_REGEXEC_OK: + + /* + * It matched! Check for actions ... + */ + if ( res != NULL ) { + struct rewrite_action *action; + + free( s ); + s = res; + + for ( action = rule->lr_action; + action != NULL; + action = action->la_next ) { + + switch ( action->la_type ) { + + /* + * This ends the rewrite context + * successfully + */ + case REWRITE_ACTION_STOP: + goto rc_end_of_context; + + /* + * This instructs the server to return + * an `unwilling to perform' error + * message + */ + case REWRITE_ACTION_UNWILLING: + return_code = REWRITE_REGEXEC_UNWILLING; + goto rc_end_of_context; + + /* + * This causes the processing to + * jump n rules back and forth + */ + case REWRITE_ACTION_GOTO: + rule = rewrite_action_goto( action, rule ); + if ( rule == NULL ) { + return_code = REWRITE_REGEXEC_ERR; + goto rc_end_of_context; + } + break; + + default: + /* ... */ + break; + } + } + + /* + * If result was OK and string didn't match, + * in case of last rule we need to set the + * result back to the string + */ + } else if ( rule->lr_next == NULL ) { + res = s; + } + + break; + + /* + * A STOP has propagated ... + */ + case REWRITE_REGEXEC_STOP: + goto rc_end_of_context; + + /* + * This will instruct the server to return + * an `unwilling to perform' error message + */ + case REWRITE_REGEXEC_UNWILLING: + return_code = REWRITE_REGEXEC_UNWILLING; + goto rc_end_of_context; + + } + +rc_continue:; /* sent here by actions that require to continue */ + + } + +rc_end_of_context:; + *result = res; + + Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" + " [depth=%d] res={%d,'%s'}\n", + op->lo_depth, return_code, ( res ? res : "NULL" ) ); + + assert( op->lo_depth > 0 ); + op->lo_depth--; + + return return_code; +} + diff --git a/libraries/librewrite/map.c b/libraries/librewrite/map.c new file mode 100644 index 0000000000000000000000000000000000000000..2180d8907757164816ad4c23e19b8babe54a5fe2 --- /dev/null +++ b/libraries/librewrite/map.c @@ -0,0 +1,811 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif + +#include "rewrite-int.h" +#include "rewrite-map.h" + +/* + * Global data + */ +#ifdef USE_REWRITE_LDAP_PVT_THREADS +ldap_pvt_thread_mutex_t xpasswd_mutex; +static int xpasswd_mutex_init = 0; +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + +/* + * Map parsing + * NOTE: these are old-fashion maps; new maps will be parsed on separate + * config lines, and referred by name. + */ +struct rewrite_map * +rewrite_xmap_parse( + struct rewrite_info *info, + const char *s, + const char **currpos +) +{ + struct rewrite_map *map; + + assert( info != NULL ); + assert( s != NULL ); + assert( currpos != NULL ); + + Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n%s%s", + s, "", "" ); + + *currpos = NULL; + + map = calloc( sizeof( struct rewrite_map ), 1 ); + if ( map == NULL ) { + Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:" + " calloc failed\n%s%s%s", "", "", "" ); + return NULL; + } + + /* + * Experimental passwd map: + * replaces the uid with the matching gecos from /etc/passwd file + */ + if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) { + map->lm_type = REWRITE_MAP_XPWDMAP; + map->lm_name = strdup( "xpasswd" ); + + assert( s[7] == '}' ); + *currpos = s + 8; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( !xpasswd_mutex_init ) { + xpasswd_mutex_init = 1; + if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) { + free( map ); + return NULL; + } + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + /* Don't really care if fails */ + return map; + + /* + * Experimental file map: + * looks up key in a `key value' ascii file + */ + } else if ( strncasecmp(s, "xfile", 5 ) == 0 ) { + char *filename; + const char *p; + int l; + int c = 5; + + map->lm_type = REWRITE_MAP_XFILEMAP; + + if ( s[ c ] != '(' ) { + free( map ); + return NULL; + } + + /* Must start with '/' for security concerns */ + c++; + if ( s[ c ] != '/' ) { + free( map ); + return NULL; + } + + for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ ); + if ( p[ 0 ] != ')' ) { + free( map ); + return NULL; + } + + l = p - s - c; + filename = calloc( sizeof( char ), l + 1 ); + AC_MEMCPY( filename, s + c, l ); + filename[ l ] = '\0'; + + map->lm_args = ( void * )fopen( filename, "r" ); + free( filename ); + + if ( map->lm_args == NULL ) { + free( map ); + return NULL; + } + + *currpos = p + 1; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { + fclose( ( FILE * )map->lm_args ); + free( map ); + return NULL; + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return map; + + /* + * Experimental ldap map: + * looks up key on the fly (not implemented!) + */ + } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) { + char *p; + char *url; + int l, rc; + int c = 5; + LDAPURLDesc *lud; + + if ( s[ c ] != '(' ) { + free( map ); + return NULL; + } + c++; + + p = strchr( s, '}' ); + if ( p == NULL ) { + free( map ); + return NULL; + } + p--; + + *currpos = p + 2; + + /* + * Add two bytes for urlencoding of '%s' + */ + l = p - s - c; + url = calloc( sizeof( char ), l + 3 ); + AC_MEMCPY( url, s + c, l ); + url[ l ] = '\0'; + + /* + * Urlencodes the '%s' for ldap_url_parse + */ + p = strchr( url, '%' ); + if ( p != NULL ) { + AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 ); + p[ 1 ] = '2'; + p[ 2 ] = '5'; + } + + rc = ldap_url_parse( url, &lud ); + free( url ); + + if ( rc != LDAP_SUCCESS ) { + free( map ); + return NULL; + } + assert( lud != NULL ); + + map->lm_args = ( void * )lud; + map->lm_type = REWRITE_MAP_XLDAPMAP; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { + ldap_free_urldesc( lud ); + free( map ); + return NULL; + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return map; + + /* Unhandled map */ + } + + return NULL; +} + +struct rewrite_map * +rewrite_map_parse( + struct rewrite_info *info, + const char *string, + const char **currpos +) +{ + struct rewrite_map *map = NULL; + struct rewrite_subst *subst = NULL; + char *s, *begin = NULL, *end; + const char *p; + int l, cnt; + + assert( info != NULL ); + assert( string != NULL ); + assert( currpos != NULL ); + + *currpos = NULL; + + /* + * Go to the end of the map invocation (the right closing brace) + */ + for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) { + if ( p[ 0 ] == REWRITE_SUBMATCH_ESCAPE ) { + /* + * '\' marks the beginning of a new map + */ + if ( p[ 1 ] == '{' ) { + cnt++; + /* + * '\' followed by a digit may mark the beginning + * of an old map + */ + } else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) { + cnt++; + p++; + } + p++; + } else if ( p[ 0 ] == '}' ) { + cnt--; + } + } + if ( cnt != 0 ) { + return NULL; + } + *currpos = p; + + /* + * Copy the map invocation + */ + l = p - string - 1; + s = calloc( sizeof( char ), l + 1 ); + AC_MEMCPY( s, string, l ); + s[ l ] = 0; + + /* + * Isolate the map name (except for variable deref) + */ + switch ( s[ 0 ] ) { + case REWRITE_OPERATOR_VARIABLE_GET: + case REWRITE_OPERATOR_PARAM_GET: + break; + default: + begin = strchr( s, '(' ); + if ( begin == NULL ) { + free( s ); + return NULL; + } + begin[ 0 ] = '\0'; + begin++; + break; + } + + /* + * Check for special map types + */ + p = s; + switch ( p[ 0 ] ) { + case REWRITE_OPERATOR_SUBCONTEXT: + case REWRITE_OPERATOR_COMMAND: + case REWRITE_OPERATOR_VARIABLE_SET: + case REWRITE_OPERATOR_VARIABLE_GET: + case REWRITE_OPERATOR_PARAM_GET: + p++; + break; + } + + /* + * Variable set and get may be repeated to indicate session-wide + * instead of operation-wide variables + */ + switch ( p[ 0 ] ) { + case REWRITE_OPERATOR_VARIABLE_SET: + case REWRITE_OPERATOR_VARIABLE_GET: + p++; + break; + } + + /* + * Variable get token can be appended to variable set to mean store + * AND rewrite + */ + if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) { + p++; + } + + /* + * Check the syntax of the variable name + */ + if ( !isalpha( (unsigned char) p[ 0 ] ) ) { + free( s ); + return NULL; + } + for ( p++; p[ 0 ] != '\0'; p++ ) { + if ( !isalnum( (unsigned char) p[ 0 ] ) ) { + free( s ); + return NULL; + } + } + + /* + * Isolate the argument of the map (except for variable deref) + */ + switch ( s[ 0 ] ) { + case REWRITE_OPERATOR_VARIABLE_GET: + case REWRITE_OPERATOR_PARAM_GET: + break; + default: + end = strrchr( begin, ')' ); + if ( end == NULL ) { + free( s ); + return NULL; + } + end[ 0 ] = '\0'; + + /* + * Compile the substitution pattern of the map argument + */ + subst = rewrite_subst_compile( info, begin ); + if ( subst == NULL ) { + free( s ); + return NULL; + } + break; + } + + /* + * Create the map + */ + map = calloc( sizeof( struct rewrite_map ), 1 ); + if ( map == NULL ) { + if ( subst != NULL ) { + free( subst ); + } + free( s ); + return NULL; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { + if ( subst != NULL ) { + free( subst ); + } + free( s ); + free( map ); + return NULL; + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + /* + * No subst for variable deref + */ + switch ( s[ 0 ] ) { + case REWRITE_OPERATOR_VARIABLE_GET: + case REWRITE_OPERATOR_PARAM_GET: + break; + default: + map->lm_subst = subst; + break; + } + + /* + * Parses special map types + */ + switch ( s[ 0 ] ) { + + /* + * Subcontext + */ + case REWRITE_OPERATOR_SUBCONTEXT: /* '>' */ + + /* + * Fetch the rewrite context + * it MUST have been defined previously + */ + map->lm_type = REWRITE_MAP_SUBCONTEXT; + map->lm_name = strdup( s + 1 ); + map->lm_data = rewrite_context_find( info, s + 1 ); + if ( map->lm_data == NULL ) { + free( s ); + free( map ); + return NULL; + } + break; + + /* + * External command + */ + case REWRITE_OPERATOR_COMMAND: /* '|' */ + free( map ); + map = NULL; + break; + + /* + * Variable set + */ + case REWRITE_OPERATOR_VARIABLE_SET: /* '&' */ + if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) { + if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) { + map->lm_type = REWRITE_MAP_SETW_SESN_VAR; + map->lm_name = strdup( s + 3 ); + } else { + map->lm_type = REWRITE_MAP_SET_SESN_VAR; + map->lm_name = strdup( s + 2 ); + } + } else { + if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { + map->lm_type = REWRITE_MAP_SETW_OP_VAR; + map->lm_name = strdup( s + 2 ); + } else { + map->lm_type = REWRITE_MAP_SET_OP_VAR; + map->lm_name = strdup( s + 1 ); + } + } + break; + + /* + * Variable dereference + */ + case REWRITE_OPERATOR_VARIABLE_GET: /* '*' */ + if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { + map->lm_type = REWRITE_MAP_GET_SESN_VAR; + map->lm_name = strdup( s + 2 ); + } else { + map->lm_type = REWRITE_MAP_GET_OP_VAR; + map->lm_name = strdup( s + 1 ); + } + break; + + /* + * Parameter + */ + case REWRITE_OPERATOR_PARAM_GET: /* '$' */ + map->lm_type = REWRITE_MAP_GET_PARAM; + map->lm_name = strdup( s + 1 ); + break; + + /* + * Built-in map + */ + default: + map->lm_type = REWRITE_MAP_BUILTIN; + map->lm_name = strdup( s ); + map->lm_data = rewrite_builtin_map_find( info, s ); + if ( map->lm_data == NULL ) { + return NULL; + } + break; + + } + + free( s ); + return map; +} + +/* + * Map key -> value resolution + * NOTE: these are old-fashion maps; new maps will be parsed on separate + * config lines, and referred by name. + */ +int +rewrite_xmap_apply( + struct rewrite_info *info, + struct rewrite_op *op, + struct rewrite_map *map, + struct berval *key, + struct berval *val +) +{ + int rc = REWRITE_SUCCESS; + + assert( info != NULL ); + assert( op != NULL ); + assert( map != NULL ); + assert( key != NULL ); + assert( val != NULL ); + + val->bv_val = NULL; + val->bv_len = 0; + + switch ( map->lm_type ) { +#ifdef HAVE_GETPWNAM + case REWRITE_MAP_XPWDMAP: { + struct passwd *pwd; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_lock( &xpasswd_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + pwd = getpwnam( key->bv_val ); + if ( pwd == NULL ) { + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rc = REWRITE_NO_SUCH_OBJECT; + break; + } + + if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) { + int l = strlen( pwd->pw_gecos ); + + val->bv_val = strdup( pwd->pw_gecos ); + if ( val->bv_val == NULL ) { + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rc = REWRITE_ERR; + break; + } + val->bv_len = l; + } else { + val->bv_val = strdup( key->bv_val ); + val->bv_len = key->bv_len; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + break; + } +#endif /* HAVE_GETPWNAM*/ + + case REWRITE_MAP_XFILEMAP: { + char buf[1024]; + + if ( map->lm_args == NULL ) { + rc = REWRITE_ERR; + break; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_lock( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rewind( ( FILE * )map->lm_args ); + + while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) { + char *p; + int blen; + + blen = strlen( buf ); + if ( buf[ blen - 1 ] == '\n' ) { + buf[ blen - 1 ] = '\0'; + } + + p = strtok( buf, " " ); + if ( p == NULL ) { +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + rc = REWRITE_ERR; + goto rc_return; + } + if ( strcasecmp( p, key->bv_val ) == 0 + && ( p = strtok( NULL, "" ) ) ) { + val->bv_val = strdup( p ); + if ( val->bv_val == NULL ) { + return REWRITE_ERR; + } + + val->bv_len = strlen( p ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + goto rc_return; + } + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rc = REWRITE_ERR; + + break; + } + + case REWRITE_MAP_XLDAPMAP: { + LDAP *ld; + char filter[ LDAP_FILT_MAXSIZ ]; + LDAPMessage *res = NULL, *entry; + LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args; + int attrsonly = 0; + char **values; + + assert( lud != NULL ); + + /* + * No mutex because there is no write on the map data + */ + + ld = ldap_init( lud->lud_host, lud->lud_port ); + if ( ld == NULL ) { + rc = REWRITE_ERR; + goto rc_return; + } + + snprintf( filter, sizeof( filter ), lud->lud_filter, + key->bv_val ); + + if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) { + attrsonly = 1; + } + rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, + filter, lud->lud_attrs, attrsonly, &res ); + if ( rc != LDAP_SUCCESS ) { + ldap_unbind( ld ); + rc = REWRITE_ERR; + goto rc_return; + } + + if ( ldap_count_entries( ld, res ) != 1 ) { + ldap_unbind( ld ); + rc = REWRITE_ERR; + goto rc_return; + } + + entry = ldap_first_entry( ld, res ); + if ( entry == NULL ) { + ldap_msgfree( res ); + ldap_unbind( ld ); + rc = REWRITE_ERR; + goto rc_return; + } + if ( attrsonly == 1 ) { + val->bv_val = ldap_get_dn( ld, entry ); + if ( val->bv_val == NULL ) { + ldap_msgfree( res ); + ldap_unbind( ld ); + rc = REWRITE_ERR; + goto rc_return; + } + } else { + values = ldap_get_values( ld, entry, + lud->lud_attrs[0] ); + if ( values == NULL ) { + ldap_msgfree( res ); + ldap_unbind( ld ); + rc = REWRITE_ERR; + goto rc_return; + } + val->bv_val = strdup( values[ 0 ] ); + ldap_value_free( values ); + } + val->bv_len = strlen( val->bv_val ); + + ldap_msgfree( res ); + ldap_unbind( ld ); + + rc = REWRITE_SUCCESS; + } + } + +rc_return:; + return rc; +} + +/* + * Applies the new map type + */ +int +rewrite_map_apply( + struct rewrite_info *info, + struct rewrite_op *op, + struct rewrite_map *map, + struct berval *key, + struct berval *val +) +{ + int rc = REWRITE_SUCCESS; + + assert( info != NULL ); + assert( op != NULL ); + assert( map != NULL ); + assert( key != NULL ); + assert( val != NULL ); + + val->bv_val = NULL; + val->bv_len = 0; + + switch ( map->lm_type ) { + case REWRITE_MAP_SUBCONTEXT: + rc = rewrite_context_apply( info, op, + ( struct rewrite_context * )map->lm_data, + key->bv_val, &val->bv_val ); + if ( val->bv_val != NULL ) { + val->bv_len = strlen( val->bv_val ); + } + break; + + case REWRITE_MAP_SET_OP_VAR: + case REWRITE_MAP_SETW_OP_VAR: + rc = rewrite_var_set( &op->lo_vars, map->lm_name, + key->bv_val, 1 ) + ? REWRITE_SUCCESS : REWRITE_ERR; + if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) { + val->bv_val = strdup( "" ); + } else { + val->bv_val = strdup( key->bv_val ); + val->bv_len = key->bv_len; + } + break; + + case REWRITE_MAP_GET_OP_VAR: { + struct rewrite_var *var; + + var = rewrite_var_find( op->lo_vars, map->lm_name ); + if ( var == NULL ) { + rc = REWRITE_ERR; + } else { + val->bv_val = strdup( var->lv_value.bv_val ); + val->bv_len = var->lv_value.bv_len; + } + break; + } + + case REWRITE_MAP_SET_SESN_VAR: + case REWRITE_MAP_SETW_SESN_VAR: + if ( op->lo_cookie == NULL ) { + rc = REWRITE_ERR; + break; + } + rc = rewrite_session_var_set( info, op->lo_cookie, + map->lm_name, key->bv_val ); + if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) { + val->bv_val = strdup( "" ); + } else { + val->bv_val = strdup( key->bv_val ); + val->bv_len = key->bv_len; + } + break; + + case REWRITE_MAP_GET_SESN_VAR: + rc = rewrite_session_var_get( info, op->lo_cookie, + map->lm_name, val ); + break; + + case REWRITE_MAP_GET_PARAM: + rc = rewrite_param_get( info, map->lm_name, val ); + break; + + case REWRITE_MAP_BUILTIN: { + struct rewrite_builtin_map *bmap = map->lm_data; + switch ( bmap->lb_type ) { + case REWRITE_BUILTIN_MAP_LDAP: + rc = map_ldap_apply( bmap, key->bv_val, val ); + break; + default: + rc = REWRITE_ERR; + break; + } + break; + } + + default: + rc = REWRITE_ERR; + break; + } + + return rc; +} + diff --git a/libraries/librewrite/parse.c b/libraries/librewrite/parse.c new file mode 100644 index 0000000000000000000000000000000000000000..a8129c41aed5ecfd83b2bce50d2961282eff3beb --- /dev/null +++ b/libraries/librewrite/parse.c @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" + +static int +parse_line( + char **argv, + int *argc, + int maxargs, + char *buf +) +{ + char *p, *begin; + int in_quoted_field = 0, cnt = 0; + char quote = '\0'; + + for ( p = buf; isspace( (unsigned char) p[ 0 ] ); p++ ); + + if ( p[ 0 ] == '#' ) { + return 0; + } + + for ( begin = p; p[ 0 ] != '\0'; p++ ) { + if ( p[ 0 ] == '\\' ) { + p++; + } else if ( p[ 0 ] == '\'' || p[ 0 ] == '\"') { + if ( in_quoted_field && p[ 0 ] == quote ) { + in_quoted_field = 1 - in_quoted_field; + quote = '\0'; + p[ 0 ] = '\0'; + argv[ cnt ] = begin; + if ( ++cnt == maxargs ) { + *argc = cnt; + return 1; + } + for ( p++; isspace( (unsigned char) p[ 0 ] ); p++ ); + begin = p; + p--; + + } else if ( !in_quoted_field ) { + if ( p != begin ) { + return -1; + } + begin++; + in_quoted_field = 1 - in_quoted_field; + quote = p[ 0 ]; + } + } else if ( isspace( (unsigned char) p[ 0 ] ) && !in_quoted_field ) { + p[ 0 ] = '\0'; + argv[ cnt ] = begin; + + if ( ++cnt == maxargs ) { + *argc = cnt; + return 1; + } + + for ( p++; isspace( (unsigned char) p[ 0 ] ); p++ ); + begin = p; + p--; + } + } + + *argc = cnt; + + return 1; +} + +int +rewrite_read( + FILE *fin, + struct rewrite_info *info +) +{ + char buf[ 1024 ]; + char *argv[11]; + int argc, lineno; + + /* + * Empty rule at the beginning of the context + */ + + for ( lineno = 0; fgets( buf, sizeof( buf ), fin ); lineno++ ) { + switch ( parse_line( argv, &argc, sizeof( argv ) - 1, buf ) ) { + case -1: + return REWRITE_ERR; + case 0: + break; + case 1: + if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) { + int rc; + rc = rewrite_parse( info, "file", lineno, + argc, argv ); + if ( rc != REWRITE_SUCCESS ) { + return rc; + } + } + break; + } + } + + return REWRITE_SUCCESS; +} + diff --git a/libraries/librewrite/session.c b/libraries/librewrite/session.c new file mode 100644 index 0000000000000000000000000000000000000000..fa5c78354a682211ca80e85084c50c3ed3e2d5cf --- /dev/null +++ b/libraries/librewrite/session.c @@ -0,0 +1,330 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" + +/* + * Compares two cookies + */ +static int +rewrite_cookie_cmp( + const void *c1, + const void *c2 +) +{ + const struct rewrite_session *s1, *s2; + + s1 = ( const struct rewrite_session * )c1; + s2 = ( const struct rewrite_session * )c2; + + assert( s1 != NULL ); + assert( s2 != NULL ); + assert( s1->ls_cookie != NULL ); + assert( s2->ls_cookie != NULL ); + + return ( ( s1->ls_cookie < s2->ls_cookie ) ? -1 : + ( ( s1->ls_cookie > s2->ls_cookie ) ? 1 : 0 ) ); +} + +/* + * Duplicate cookies? + */ +static int +rewrite_cookie_dup( + void *c1, + void *c2 +) +{ + struct rewrite_session *s1, *s2; + + s1 = ( struct rewrite_session * )c1; + s2 = ( struct rewrite_session * )c2; + + assert( s1 != NULL ); + assert( s2 != NULL ); + assert( s1->ls_cookie != NULL ); + assert( s2->ls_cookie != NULL ); + + return ( ( s1->ls_cookie == s2->ls_cookie ) ? -1 : 0 ); +} + +/* + * Inits a session + */ +struct rewrite_session * +rewrite_session_init( + struct rewrite_info *info, + const void *cookie +) +{ + struct rewrite_session *session; + int rc; + + assert( info != NULL ); + assert( cookie != NULL ); + + session = calloc( sizeof( struct rewrite_session ), 1 ); + if ( session == NULL ) { + return NULL; + } + session->ls_cookie = ( void * )cookie; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_rdwr_init( &session->ls_vars_mutex ) ) { + free( session ); + return NULL; + } + ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rc = avl_insert( &info->li_cookies, ( caddr_t )session, + rewrite_cookie_cmp, rewrite_cookie_dup ); + info->li_num_cookies++; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + if ( rc != 0 ) { + free( session ); + return NULL; + } + + return session; +} + +/* + * Fetches a session + */ +struct rewrite_session * +rewrite_session_find( + struct rewrite_info *info, + const void *cookie +) +{ + struct rewrite_session *session, tmp; + + assert( info != NULL ); + assert( cookie != NULL ); + + tmp.ls_cookie = ( void * )cookie; +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_rlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + session = ( struct rewrite_session * )avl_find( info->li_cookies, + ( caddr_t )&tmp, rewrite_cookie_cmp ); +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_runlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return session; + +} + +/* + * Defines and inits a var with session scope + */ +int +rewrite_session_var_set( + struct rewrite_info *info, + const void *cookie, + const char *name, + const char *value +) +{ + struct rewrite_session *session; + struct rewrite_var *var; + + assert( info != NULL ); + assert( cookie != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + session = rewrite_session_find( info, cookie ); + if ( session == NULL ) { + session = rewrite_session_init( info, cookie ); + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + var = rewrite_var_find( session->ls_vars, name ); + if ( var != NULL ) { + assert( var->lv_value.bv_val != NULL ); + free( var->lv_value.bv_val ); + var->lv_value.bv_val = strdup( value ); + var->lv_value.bv_len = strlen( value ); + } else { + var = rewrite_var_insert( &session->ls_vars, name, value ); + if ( var == NULL ) { +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + return REWRITE_ERR; + } + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + +/* + * Gets a var with session scope + */ +int +rewrite_session_var_get( + struct rewrite_info *info, + const void *cookie, + const char *name, + struct berval *value +) +{ + struct rewrite_session *session; + struct rewrite_var *var; + + assert( info != NULL ); + assert( cookie != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + value->bv_val = NULL; + value->bv_len = 0; + + if ( cookie == NULL ) { + return REWRITE_ERR; + } + + session = rewrite_session_find( info, cookie ); + if ( session == NULL ) { + return REWRITE_ERR; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_rlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + var = rewrite_var_find( session->ls_vars, name ); + if ( var == NULL ) { + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_ERR; + } else { + value->bv_val = strdup( var->lv_value.bv_val ); + value->bv_len = var->lv_value.bv_len; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + +/* + * Deletes a session + */ +int +rewrite_session_delete( + struct rewrite_info *info, + const void *cookie +) +{ + struct rewrite_session *session, tmp; + + assert( info != NULL ); + assert( cookie != NULL ); + + tmp.ls_cookie = ( void * )cookie; + + session = rewrite_session_find( info, cookie ); + + if ( session != NULL ) { +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + rewrite_var_delete( session->ls_vars ); +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + assert( info->li_num_cookies > 0 ); + info->li_num_cookies--; + + /* + * There is nothing to delete in the return value + */ + avl_delete( &info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + +/* + * Destroys the cookie tree + */ +int +rewrite_session_destroy( + struct rewrite_info *info +) +{ + int count; + + assert( info != NULL ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + /* + * Should call per-session destruction routine ... + */ + + count = avl_free( info->li_cookies, NULL ); + info->li_cookies = NULL; + assert( count == info->li_num_cookies ); + info->li_num_cookies = 0; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + diff --git a/libraries/librewrite/subst.c b/libraries/librewrite/subst.c new file mode 100644 index 0000000000000000000000000000000000000000..1024517463519212239e7985e28a8f1b6cd81b61 --- /dev/null +++ b/libraries/librewrite/subst.c @@ -0,0 +1,439 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" + +/* + * Compiles a substitution pattern + */ +struct rewrite_subst * +rewrite_subst_compile( + struct rewrite_info *info, + const char *result +) +{ + size_t subs_len; + struct berval **subs = NULL, **tmps; + struct rewrite_submatch **submatch = NULL; + + struct rewrite_subst *s = NULL; + + const char *begin, *p; + int nsub = 0, l; + + assert( info != NULL ); + assert( result != NULL ); + + /* + * Take care of substitution string + */ + for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) { + + /* + * Keep only single escapes '\' + */ + if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) { + continue; + } + if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) { + AC_MEMCPY((char *)p, p + 1, strlen( p ) ); + continue; + } + + nsub++; + + tmps = (struct berval **)realloc( subs, + sizeof( struct berval * )*( nsub + 1 ) ); + if ( tmps == NULL ) { + /* cleanup */ + return NULL; + } + subs = tmps; + subs[ nsub ] = NULL; + + /* + * I think an `if l > 0' at runtime is better outside than + * inside a function call ... + */ + l = p - begin; + if ( l > 0 ) { + subs_len += l; + subs[ nsub - 1 ] = + calloc( sizeof( struct berval ), 1 ); + if ( subs[ nsub - 1 ] == NULL ) { + /* cleanup */ + return NULL; + } + subs[ nsub - 1 ]->bv_len = l; + subs[ nsub - 1 ]->bv_val = malloc( l + 1 ); + if ( subs[ nsub - 1 ]->bv_val == NULL ) { + return NULL; + } + AC_MEMCPY( subs[ nsub - 1 ]->bv_val, begin, l ); + subs[ nsub - 1 ]->bv_val[ l ] = '\0'; + } else { + subs[ nsub - 1 ] = NULL; + } + + /* + * Substitution pattern + */ + if ( isdigit( (unsigned char) p[ 1 ] ) ) { + int d = p[ 1 ] - '0'; + struct rewrite_submatch **tmpsm; + + /* + * Add a new value substitution scheme + */ + tmpsm = realloc( submatch, + sizeof( struct rewrite_submatch * )*( nsub + 1 ) ); + if ( tmpsm == NULL ) { + /* cleanup */ + return NULL; + } + submatch = tmpsm; + submatch[ nsub ] = NULL; + + submatch[ nsub - 1 ] = + calloc( sizeof( struct rewrite_submatch ), 1 ); + if ( submatch[ nsub - 1 ] == NULL ) { + /* cleanup */ + return NULL; + } + submatch[ nsub - 1 ]->ls_submatch = d; + + /* + * If there is no argument, use default + * (substitute substring as is) + */ + if ( p[ 2 ] != '{' ) { + submatch[ nsub - 1 ]->ls_type = + REWRITE_SUBMATCH_ASIS; + begin = ++p + 1; + } else { + struct rewrite_map *map; + + submatch[ nsub - 1 ]->ls_type = + REWRITE_SUBMATCH_XMAP; + + map = rewrite_xmap_parse( info, + p + 3, &begin ); + if ( map == NULL ) { + /* cleanup */ + return NULL; + } + p = begin - 1; + + submatch[ nsub - 1 ]->ls_map = map; + } + + /* + * Map with args ... + */ + } else if ( p[ 1 ] == '{' ) { + struct rewrite_map *map; + struct rewrite_submatch **tmpsm; + + map = rewrite_map_parse( info, p + 2, &begin ); + if ( map == NULL ) { + /* cleanup */ + return NULL; + } + p = begin - 1; + + /* + * Add a new value substitution scheme + */ + tmpsm = realloc( submatch, + sizeof( struct rewrite_submatch * )*( nsub + 1 ) ); + if ( tmpsm == NULL ) { + /* cleanup */ + return NULL; + } + submatch = tmpsm; + submatch[ nsub ] = NULL; + submatch[ nsub - 1 ] = + calloc( sizeof( struct rewrite_submatch ), 1 ); + if ( submatch[ nsub - 1 ] == NULL ) { + /* cleanup */ + return NULL; + } + + submatch[ nsub - 1 ]->ls_type = + REWRITE_SUBMATCH_MAP_W_ARG; + + submatch[ nsub - 1 ]->ls_map = map; + } + } + + /* + * Last part of string + */ + tmps = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) ); + if ( tmps == NULL ) { + /* + * XXX need to free the value subst stuff! + */ + free( submatch ); + return NULL; + } + + subs = tmps; + subs[ nsub + 1 ] = NULL; + l = p - begin; + if ( l > 0 ) { + subs[ nsub ] = calloc( sizeof( struct berval ), 1 ); + subs_len += l; + subs[ nsub ]->bv_len = l; + subs[ nsub ]->bv_val = malloc( l + 1 ); + AC_MEMCPY( subs[ nsub ]->bv_val, begin, l ); + subs[ nsub ]->bv_val[ l ] = '\0'; + } else { + subs[ nsub ] = NULL; + } + + s = calloc( sizeof( struct rewrite_subst ), 1 ); + if ( s == NULL ) { + /* cleanup */ + return NULL; + } + + s->lt_subs_len = subs_len; + s->lt_subs = subs; + s->lt_num_submatch = nsub; + s->lt_submatch = submatch; + + return s; +} + +/* + * Copies the match referred to by submatch and fetched in string by match. + * Helper for rewrite_rule_apply. + */ +static int +submatch_copy( + struct rewrite_submatch *submatch, + const char *string, + const regmatch_t *match, + struct berval *val +) +{ + int c, l; + const char *s; + + assert( submatch != NULL ); + assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS + || submatch->ls_type == REWRITE_SUBMATCH_XMAP ); + assert( string != NULL ); + assert( match != NULL ); + assert( val != NULL ); + + c = submatch->ls_submatch; + s = string + match[ c ].rm_so; + l = match[ c ].rm_eo - match[ c ].rm_so; + + val->bv_val = NULL; + val->bv_len = l; + val->bv_val = calloc( sizeof( char ), l + 1 ); + if ( val->bv_val == NULL ) { + return REWRITE_ERR; + } + + AC_MEMCPY( val->bv_val, s, l ); + val->bv_val[ l ] = '\0'; + + return REWRITE_SUCCESS; +} + +/* + * Substitutes a portion of rewritten string according to substitution + * pattern using submatches + */ +int +rewrite_subst_apply( + struct rewrite_info *info, + struct rewrite_op *op, + struct rewrite_subst *subst, + const char *string, + const regmatch_t *match, + struct berval *val +) +{ + struct berval *submatch = NULL; + char *res = NULL; + int n, l, cl; + int rc = REWRITE_REGEXEC_OK; + + assert( info != NULL ); + assert( op != NULL ); + assert( subst != NULL ); + assert( string != NULL ); + assert( match != NULL ); + assert( val != NULL ); + + val->bv_val = NULL; + val->bv_len = 0; + + /* + * Prepare room for submatch expansion + */ + submatch = calloc( sizeof( struct berval ), + subst->lt_num_submatch ); + if ( submatch == NULL ) { + return REWRITE_REGEXEC_ERR; + } + + /* + * Resolve submatches (simple subst, map expansion and so). + */ + for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) { + struct berval key; + int rc; + + /* + * Get key + */ + switch( subst->lt_submatch[ n ]->ls_type ) { + case REWRITE_SUBMATCH_ASIS: + case REWRITE_SUBMATCH_XMAP: + rc = submatch_copy( subst->lt_submatch[ n ], + string, match, &key ); + if ( rc != REWRITE_SUCCESS ) { + free( submatch ); + return REWRITE_REGEXEC_ERR; + } + break; + + case REWRITE_SUBMATCH_MAP_W_ARG: + switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) { + case REWRITE_MAP_GET_OP_VAR: + case REWRITE_MAP_GET_SESN_VAR: + case REWRITE_MAP_GET_PARAM: + rc = REWRITE_SUCCESS; + break; + default: + rc = rewrite_subst_apply( info, op, + subst->lt_submatch[ n ]->ls_map->lm_subst, + string, match, &key); + } + + if ( rc != REWRITE_SUCCESS ) { + free( submatch ); + return REWRITE_REGEXEC_ERR; + } + break; + + default: + Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s", + "", "", "" ); + rc = REWRITE_ERR; + break; + } + + if ( rc != REWRITE_SUCCESS ) { + free( submatch ); + return REWRITE_REGEXEC_ERR; + } + + /* + * Resolve key + */ + switch ( subst->lt_submatch[ n ]->ls_type ) { + case REWRITE_SUBMATCH_ASIS: + submatch[ n ] = key; + rc = REWRITE_SUCCESS; + break; + + case REWRITE_SUBMATCH_XMAP: + rc = rewrite_xmap_apply( info, op, + subst->lt_submatch[ n ]->ls_map, + &key, &submatch[ n ] ); + break; + + case REWRITE_SUBMATCH_MAP_W_ARG: + rc = rewrite_map_apply( info, op, + subst->lt_submatch[ n ]->ls_map, + &key, &submatch[ n ] ); + break; + + default: + /* + * When implemented, this might return the + * exit status of a rewrite context, + * which may include a stop, or an + * unwilling to perform + */ + rc = REWRITE_ERR; + break; + } + + if ( rc != REWRITE_SUCCESS ) { + free( submatch ); + return REWRITE_REGEXEC_ERR; + } + + /* + * Increment the length of the resulting string + */ + l += submatch[ n ].bv_len; + } + + /* + * Alloc result buffer as big as the constant part + * of the subst pattern and initialize it + */ + l += subst->lt_subs_len; + res = calloc( sizeof( char ), l + 1 ); + if ( res == NULL ) { + free( submatch ); + return REWRITE_REGEXEC_ERR; + } + + /* + * Apply submatches (possibly resolved thru maps + */ + for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { + if ( subst->lt_subs[ n ] != NULL ) { + AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val, + subst->lt_subs[ n ]->bv_len ); + cl += subst->lt_subs[ n ]->bv_len; + } + AC_MEMCPY( res + cl, submatch[ n ].bv_val, + submatch[ n ].bv_len ); + cl += submatch[ n ].bv_len; + free( submatch[ n ].bv_val ); + } + if ( subst->lt_subs[ n ] != NULL ) { + AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val, + subst->lt_subs[ n ]->bv_len ); + } + + val->bv_val = res; + val->bv_len = l; + + return rc; +} + diff --git a/libraries/librewrite/var.c b/libraries/librewrite/var.c new file mode 100644 index 0000000000000000000000000000000000000000..d4d28ad4b1bd56823ecf2d421a85d7d89b59665c --- /dev/null +++ b/libraries/librewrite/var.c @@ -0,0 +1,199 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it> + * All rights reserved. + * + * 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> + +#include "rewrite-int.h" + +/* + * Compares two vars + */ +static int +rewrite_var_cmp( + const void *c1, + const void *c2 +) +{ + const struct rewrite_var *v1, *v2; + + v1 = ( const struct rewrite_var * )c1; + v2 = ( const struct rewrite_var * )c2; + + assert( v1 != NULL ); + assert( v2 != NULL ); + assert( v1->lv_name != NULL ); + assert( v2->lv_name != NULL ); + + return strcasecmp( v1->lv_name, v2->lv_name ); +} + +/* + * Duplicate var ? + */ +static int +rewrite_var_dup( + void *c1, + void *c2 +) +{ + struct rewrite_var *v1, *v2; + + v1 = ( struct rewrite_var * )c1; + v2 = ( struct rewrite_var * )c2; + + assert( v1 != NULL ); + assert( v2 != NULL ); + assert( v1->lv_name != NULL ); + assert( v2->lv_name != NULL ); + + return ( strcasecmp( v1->lv_name, v2->lv_name ) == 0 ? -1 : 0 ); +} + +/* + * Finds a var + */ +struct rewrite_var * +rewrite_var_find( + Avlnode *tree, + const char *name +) +{ + struct rewrite_var var; + + assert( name != NULL ); + + var.lv_name = ( char * )name; + return ( struct rewrite_var * )avl_find( tree, + ( caddr_t )&var, rewrite_var_cmp ); +} + +/* + * Inserts a newly created var + */ +struct rewrite_var * +rewrite_var_insert( + Avlnode **tree, + const char *name, + const char *value +) +{ + struct rewrite_var *var; + int rc; + + assert( tree != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + var = calloc( sizeof( struct rewrite_var ), 1 ); + if ( var == NULL ) { + return NULL; + } + var->lv_name = ( char * )strdup( name ); + if ( var->lv_name == NULL ) { + free( var ); + return NULL; + } + var->lv_value.bv_val = strdup( value ); + if ( var->lv_value.bv_val == NULL ) { + free( var ); + free( var->lv_name ); + return NULL; + } + var->lv_value.bv_len = strlen( value ); + rc = avl_insert( tree, ( caddr_t )var, + rewrite_var_cmp, rewrite_var_dup ); + if ( rc != 0 ) { + free( var ); + free( var->lv_name ); + free( var->lv_value.bv_val ); + return NULL; + } + + return var; +} + +/* + * Sets/inserts a var + */ +struct rewrite_var * +rewrite_var_set( + Avlnode **tree, + const char *name, + const char *value, + int insert +) +{ + struct rewrite_var *var; + + assert( tree != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + var = rewrite_var_find( *tree, name ); + if ( var == NULL ) { + if ( insert ) { + return rewrite_var_insert( tree, name, value ); + } else { + return NULL; + } + } else { + assert( var->lv_value.bv_val != NULL ); + + free( var->lv_value.bv_val ); + var->lv_value.bv_val = ( char * )value; + var->lv_value.bv_len = strlen( value ); + } + + return var; +} + +/* + * Frees a var + */ +static void +rewrite_var_free( + struct rewrite_var *var +) +{ + assert( var != NULL ); + + assert( var->lv_name != NULL ); + assert( var->lv_value.bv_val != NULL ); + + free( var->lv_name ); + free( var->lv_value.bv_val ); +} + +/* + * Deletes a var tree + */ +int +rewrite_var_delete( + Avlnode *tree +) +{ + avl_free( tree, ( AVL_FREE )rewrite_var_free ); + return REWRITE_SUCCESS; +} + diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index d6f7291c7817f83558d1e222cadbd6bc0eb5e647..b092d124f338f2c1d2713d7a0fe672af46949edd 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -1,4 +1,9 @@ /* abandon.c - decode and handle an ldap abandon operation */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. @@ -12,26 +17,29 @@ * is provided ``as is'' without express or implied warranty. */ -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" +#include "portable.h" -extern Backend *select_backend(); +#include <stdio.h> +#include <ac/socket.h> -extern char *default_referral; +#include "slap.h" -void +int do_abandon( Connection *conn, Operation *op ) { - int id; - Backend *be; + ber_int_t id; Operation *o; + int rc; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, "conn: %d do_abandon\n", + conn->c_connid)); +#else Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 ); +#endif /* * Parse the abandon request. It looks like this: @@ -40,31 +48,73 @@ do_abandon( */ if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0 ,0 ); - return; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "conn: %d do_abandon: ber_scanf failed\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_abandon: ber_scanf failed\n", 0, 0 ,0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + return -1; } - Debug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 ); + if( (rc = get_ctrls( conn, op, 0 )) != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "do_abandon: get_ctrls failed\n", 0, 0 ,0 ); + return rc; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_abandon: conn: %d id=%ld\n", conn->c_connid, (long) id )); +#else + Debug( LDAP_DEBUG_ARGS, "do_abandon: id=%ld\n", (long) id, 0 ,0 ); +#endif + + if( id <= 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_abandon: conn: %d bad msgid %ld\n", conn->c_connid, (long) id )); +#else + Debug( LDAP_DEBUG_ANY, + "do_abandon: bad msgid %ld\n", (long) id, 0, 0 ); +#endif + return LDAP_SUCCESS; + } + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); /* * find the operation being abandoned and set the o_abandon * flag. It's up to the backend to periodically check this * flag and abort the operation at a convenient time. */ - pthread_mutex_lock( &conn->c_opsmutex ); - for ( o = conn->c_ops; o != NULL; o = o->o_next ) { - if ( o->o_msgid == id ) - break; + LDAP_STAILQ_FOREACH( o, &conn->c_ops, o_next ) { + if ( o->o_msgid == id ) { + o->o_abandon = 1; + goto done; + } } - if ( o != NULL ) { - pthread_mutex_lock( &o->o_abandonmutex ); - o->o_abandon = 1; - pthread_mutex_unlock( &o->o_abandonmutex ); - } else { - Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0, - 0 ); + LDAP_STAILQ_FOREACH( o, &conn->c_pending_ops, o_next ) { + if ( o->o_msgid == id ) { + LDAP_STAILQ_REMOVE( &conn->c_pending_ops, o, slap_op, o_next ); + slap_op_free( o ); + goto done; + } } - pthread_mutex_unlock( &conn->c_opsmutex ); + +done: + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_abandon: conn: %d op=%ld %sfound\n", + conn->c_connid, (long)id, o ? "" : "not " )); +#else + Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n", + (long) id, o ? "" : "not ", 0 ); +#endif + return LDAP_SUCCESS; } diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 518238084374f30251ed14a186a81a9f59a43648..f3433e90082af5bbc941ffc9daa91fb1caa1bef7 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -17,25 +17,27 @@ #include "sets.h" #include "lber_pvt.h" +#define ACL_BUF_SIZE 1024 /* use most appropriate size */ + /* * speed up compares */ static struct berval - aci_bv_entry = { sizeof("entry") - 1, "entry" }, - aci_bv_br_entry = { sizeof("[entry]") - 1, "[entry]" }, - aci_bv_br_all = { sizeof("[all]") - 1, "[all]" }, - aci_bv_access_id = { sizeof("access-id") - 1, "access-id" }, - aci_bv_anonymous = { sizeof("anonymous") - 1, "anonymous" }, - aci_bv_users = { sizeof("users") - 1, "users" }, - aci_bv_self = { sizeof("self") - 1, "self" }, - aci_bv_dnattr = { sizeof("dnattr") - 1, "dnattr" }, - aci_bv_group = { sizeof("group") - 1, "group" }, - aci_bv_role = { sizeof("role") - 1, "role" }, - aci_bv_set = { sizeof("set") - 1, "set" }, - aci_bv_set_ref = { sizeof("set-ref") - 1, "set-ref"}, - aci_bv_grant = { sizeof("grant") - 1, "grant" }, - aci_bv_deny = { sizeof("deny") - 1, "deny" }; + aci_bv_entry = BER_BVC("entry"), + aci_bv_br_entry = BER_BVC("[entry]"), + aci_bv_br_all = BER_BVC("[all]"), + aci_bv_access_id = BER_BVC("access-id"), + aci_bv_anonymous = BER_BVC("anonymous"), + aci_bv_users = BER_BVC("users"), + aci_bv_self = BER_BVC("self"), + aci_bv_dnattr = BER_BVC("dnattr"), + aci_bv_group = BER_BVC("group"), + aci_bv_role = BER_BVC("role"), + aci_bv_set = BER_BVC("set"), + aci_bv_set_ref = BER_BVC("set-ref"), + aci_bv_grant = BER_BVC("grant"), + aci_bv_deny = BER_BVC("deny"); static AccessControl * acl_get( AccessControl *ac, int *count, @@ -145,7 +147,7 @@ access_allowed( #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY, - "access_allowed: conn %d %s access to \"%s\" \"%s\" requested\n", + "access_allowed: conn %lu %s access to \"%s\" \"%s\" requested\n", conn ? conn->c_connid : -1, access2str( access ), e->e_dn, attr )); #else Debug( LDAP_DEBUG_ACL, @@ -165,7 +167,7 @@ access_allowed( if ( be != NULL && be_isroot( be, &op->o_ndn ) ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_INFO, - "access_allowed: conn %d root access granted\n", + "access_allowed: conn %lu root access granted\n", conn->c_connid)); #else Debug( LDAP_DEBUG_ACL, @@ -186,7 +188,7 @@ access_allowed( { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d NoUserMod Operational attribute: %s access granted\n", + "access_allowed: conn %lu NoUserMod Operational attribute: %s access granted\n", conn->c_connid, attr )); #else Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:" @@ -200,7 +202,7 @@ access_allowed( if( be != NULL && be->be_acl == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d backend default %s access %s to \"%s\"\n", + "access_allowed: conn %lu backend default %s access %s to \"%s\"\n", conn->c_connid, access2str( access ), be->be_dfltaccess >= access ? "granted" : "denied", op->o_dn.bv_val )); #else @@ -218,7 +220,7 @@ access_allowed( } else if ( be == NULL && global_acl == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d global default %s access %s to \"%s\"\n", + "access_allowed: conn %lu global default %s access %s to \"%s\"\n", conn->c_connid, access2str( access ), global_default_access >= access ? "granted" : "denied", op->o_dn.bv_val )); #else @@ -260,7 +262,7 @@ access_allowed( for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d match[%d]: %d %d ", + "access_allowed: conn %lu match[%d]: %d %d ", conn->c_connid, i, (int)matches[i].rm_so, (int)matches[i].rm_eo )); #else @@ -294,7 +296,7 @@ vd_access: if ( ACL_IS_INVALID( mask ) ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d \"%s\" (%s) invalid!\n", + "access_allowed: conn %lu \"%s\" (%s) invalid!\n", conn->c_connid, e->e_dn, attr )); #else Debug( LDAP_DEBUG_ACL, @@ -306,7 +308,8 @@ vd_access: } else if ( control == ACL_BREAK ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "access_allowed: conn %d no more rules\n", conn->c_connid )); + "access_allowed: conn %lu no more rules\n", + conn->c_connid )); #else Debug( LDAP_DEBUG_ACL, "=> access_allowed: no more rules\n", 0, 0, 0); @@ -317,7 +320,7 @@ vd_access: #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY, - "access_allowed: conn %d %s access %s by %s\n", + "access_allowed: conn %lu %s access %s by %s\n", conn->c_connid, access2str( access ), ACL_GRANT( mask, access ) ? "granted" : "denied", @@ -535,7 +538,6 @@ acl_mask( AccessControlState *state ) { int i, odnlen, patlen; - int vd_recorded = 0; Access *b; #ifdef LDAP_DEBUG char accessmaskbuf[ACCESSMASK_MAXLEN]; @@ -552,7 +554,7 @@ acl_mask( #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY, - "acl_mask: conn %d access to entry \"%s\", attr \"%s\" requested\n", + "acl_mask: conn %lu access to entry \"%s\", attr \"%s\" requested\n", conn->c_connid, e->e_dn, attr )); LDAP_LOG(( "acl", LDAP_LEVEL_ARGS, @@ -592,7 +594,7 @@ acl_mask( if ( b->a_dn_pat.bv_len != 0 ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_dn_pat: %s\n", + "acl_mask: conn %lu check a_dn_pat: %s\n", conn->c_connid, b->a_dn_pat.bv_val )); #else Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n", @@ -623,7 +625,7 @@ acl_mask( } } else if ( b->a_dn_style == ACL_STYLE_REGEX ) { - if ( ber_bvccmp( &b->a_dn_pat, '*' ) == 0 ) { + if ( !ber_bvccmp( &b->a_dn_pat, '*' ) ) { int ret = regex_matches( &b->a_dn_pat, op->o_ndn.bv_val, e->e_ndn, matches ); @@ -633,59 +635,97 @@ acl_mask( } } else { + struct berval pat; + int got_match = 0; + if ( e->e_dn == NULL ) continue; - patlen = b->a_dn_pat.bv_len; + if ( b->a_dn_expand ) { + struct berval bv; + char buf[ACL_BUF_SIZE]; + + bv.bv_len = sizeof( buf ) - 1; + bv.bv_val = buf; + + string_expand(&bv, &b->a_dn_pat, + e->e_ndn, matches); + if ( dnNormalize2(NULL, &bv, &pat) != LDAP_SUCCESS ) { + /* did not expand to a valid dn */ + continue; + } + } else { + pat = b->a_dn_pat; + } + + patlen = pat.bv_len; odnlen = op->o_ndn.bv_len; - if ( odnlen < patlen ) - continue; + if ( odnlen < patlen ) { + goto dn_match_cleanup; + + } if ( b->a_dn_style == ACL_STYLE_BASE ) { /* base dn -- entire object DN must match */ - if ( odnlen != patlen ) - continue; + if ( odnlen != patlen ) { + goto dn_match_cleanup; + } } else if ( b->a_dn_style == ACL_STYLE_ONE ) { int rdnlen = -1; - if ( odnlen <= patlen ) - continue; + if ( odnlen <= patlen ) { + goto dn_match_cleanup; + } - if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) - continue; + if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) { + goto dn_match_cleanup; + } rdnlen = dn_rdnlen( NULL, &op->o_ndn ); - if ( rdnlen != odnlen - patlen - 1 ) - continue; + if ( rdnlen != odnlen - patlen - 1 ) { + goto dn_match_cleanup; + } } else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) { - if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) - continue; + if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) { + goto dn_match_cleanup; + } } else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) { - if ( odnlen <= patlen ) - continue; - if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) - continue; + if ( odnlen <= patlen ) { + goto dn_match_cleanup; + } + + if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) { + goto dn_match_cleanup; + } + } + + got_match = !strcmp( pat.bv_val, op->o_ndn.bv_val + odnlen - patlen ); + +dn_match_cleanup:; + if ( pat.bv_val != b->a_dn_pat.bv_val ) { + free( pat.bv_val ); } - if ( strcmp( b->a_dn_pat.bv_val, op->o_ndn.bv_val + odnlen - patlen ) != 0 ) + if ( !got_match ) { continue; + } } } if ( b->a_sockurl_pat.bv_len ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_sockurl_pat: %s\n", + "acl_mask: conn %lu check a_sockurl_pat: %s\n", conn->c_connid, b->a_sockurl_pat.bv_val )); #else Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n", b->a_sockurl_pat.bv_val, 0, 0 ); #endif - if ( ber_bvccmp( &b->a_sockurl_pat, '*' ) != 0) { + if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) { if ( b->a_sockurl_style == ACL_STYLE_REGEX) { if (!regex_matches( &b->a_sockurl_pat, conn->c_listener_url.bv_val, e->e_ndn, matches ) ) @@ -702,13 +742,13 @@ acl_mask( if ( b->a_domain_pat.bv_len ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_domain_pat: %s\n", + "acl_mask: conn %lu check a_domain_pat: %s\n", conn->c_connid, b->a_domain_pat.bv_val )); #else Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n", b->a_domain_pat.bv_val, 0, 0 ); #endif - if ( ber_bvccmp( &b->a_domain_pat, '*' ) != 0) { + if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) { if ( b->a_domain_style == ACL_STYLE_REGEX) { if (!regex_matches( &b->a_domain_pat, conn->c_peer_domain.bv_val, e->e_ndn, matches ) ) @@ -716,8 +756,39 @@ acl_mask( continue; } } else { - if ( ber_bvstrcasecmp( &b->a_domain_pat, &conn->c_peer_domain ) != 0 ) + char buf[ACL_BUF_SIZE]; + + struct berval cmp = conn->c_peer_domain; + struct berval pat = b->a_domain_pat; + + if ( b->a_domain_expand ) { + struct berval bv; + + bv.bv_len = sizeof(buf); + bv.bv_val = buf; + + string_expand(&bv, &b->a_domain_pat, e->e_ndn, matches); + pat = bv; + } + + if ( b->a_domain_style == ACL_STYLE_SUBTREE ) { + int offset = cmp.bv_len - pat.bv_len; + if ( offset < 0 ) { + continue; + } + + if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) { + continue; + } + + /* trim the domain */ + cmp.bv_val = &cmp.bv_val[ offset ]; + cmp.bv_len -= offset; + } + + if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) { continue; + } } } } @@ -725,13 +796,13 @@ acl_mask( if ( b->a_peername_pat.bv_len ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_perrname_path: %s\n", + "acl_mask: conn %lu check a_perrname_path: %s\n", conn->c_connid, b->a_peername_pat.bv_val )); #else Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n", b->a_peername_pat.bv_val, 0, 0 ); #endif - if ( ber_bvccmp( &b->a_peername_pat, '*' ) != 0) { + if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) { if ( b->a_peername_style == ACL_STYLE_REGEX) { if (!regex_matches( &b->a_peername_pat, conn->c_peer_name.bv_val, e->e_ndn, matches ) ) @@ -748,13 +819,13 @@ acl_mask( if ( b->a_sockname_pat.bv_len ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_sockname_path: %s\n", + "acl_mask: conn %lu check a_sockname_path: %s\n", conn->c_connid, b->a_sockname_pat.bv_val )); #else Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n", b->a_sockname_pat.bv_val, 0, 0 ); #endif - if ( ber_bvccmp( &b->a_sockname_pat, '*' ) != 0) { + if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) { if ( b->a_sockname_style == ACL_STYLE_REGEX) { if (!regex_matches( &b->a_sockname_pat, conn->c_sock_name.bv_val, e->e_ndn, matches ) ) @@ -768,7 +839,7 @@ acl_mask( } } - if ( b->a_dn_at != NULL && op->o_ndn.bv_len != 0 ) { + if ( b->a_dn_at != NULL ) { Attribute *at; struct berval bv; int rc, match = 0; @@ -777,9 +848,13 @@ acl_mask( assert( attr != NULL ); + if ( op->o_ndn.bv_len == 0 ) { + continue; + } + #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_dn_pat: %s\n", + "acl_mask: conn %lu check a_dn_pat: %s\n", conn->c_connid, attr )); #else Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n", @@ -843,12 +918,16 @@ acl_mask( } } - if ( b->a_group_pat.bv_len && op->o_ndn.bv_len ) { - char buf[1024]; + if ( b->a_group_pat.bv_len ) { + char buf[ACL_BUF_SIZE]; struct berval bv; struct berval ndn = { 0, NULL }; int rc; + if ( op->o_ndn.bv_len == 0 ) { + continue; + } + bv.bv_len = sizeof(buf) - 1; bv.bv_val = buf; @@ -886,7 +965,7 @@ acl_mask( if ( b->a_authz.sai_ssf ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_authz.sai_ssf: ACL %u > OP %u\n", + "acl_mask: conn %lu check a_authz.sai_ssf: ACL %u > OP %u\n", conn->c_connid, b->a_authz.sai_ssf, op->o_ssf )); #else Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n", @@ -900,7 +979,7 @@ acl_mask( if ( b->a_authz.sai_transport_ssf ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_authz.sai_transport_ssf: ACL %u > OP %u\n", + "acl_mask: conn %lu check a_authz.sai_transport_ssf: ACL %u > OP %u\n", conn->c_connid, b->a_authz.sai_transport_ssf, op->o_transport_ssf )); #else Debug( LDAP_DEBUG_ACL, @@ -915,7 +994,7 @@ acl_mask( if ( b->a_authz.sai_tls_ssf ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_authz.sai_tls_ssf: ACL %u > OP %u\n", + "acl_mask: conn %lu check a_authz.sai_tls_ssf: ACL %u > OP %u\n", conn->c_connid, b->a_authz.sai_tls_ssf, op->o_tls_ssf )); #else Debug( LDAP_DEBUG_ACL, @@ -930,7 +1009,7 @@ acl_mask( if ( b->a_authz.sai_sasl_ssf ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d check a_authz.sai_sasl_ssf: ACL %u > OP %u\n", + "acl_mask: conn %lu check a_authz.sai_sasl_ssf: ACL %u > OP %u\n", conn->c_connid, b->a_authz.sai_sasl_ssf, op->o_sasl_ssf )); #else Debug( LDAP_DEBUG_ACL, @@ -1025,7 +1104,7 @@ acl_mask( #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_RESULTS, - "acl_mask: conn %d [%d] applying %s (%s)\n", + "acl_mask: conn %lu [%d] applying %s (%s)\n", conn->c_connid, i, accessmask2str( modmask, accessmaskbuf), b->a_type == ACL_CONTINUE ? "continue" : b->a_type == ACL_BREAK ? "break" : "stop" )); @@ -1063,7 +1142,7 @@ acl_mask( #ifdef NEW_LOGGING LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, - "acl_mask: conn %d [%d] mask: %s\n", + "acl_mask: conn %lu [%d] mask: %s\n", conn->c_connid, i, accessmask2str( *mask, accessmaskbuf) )); #else Debug( LDAP_DEBUG_ACL, @@ -1087,7 +1166,7 @@ acl_mask( #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_RESULTS, - "acl_mask: conn %d no more <who> clauses, returning %d (stop)\n", + "acl_mask: conn %lu no more <who> clauses, returning %d (stop)\n", conn->c_connid, accessmask2str( *mask, accessmaskbuf) )); #else Debug( LDAP_DEBUG_ACL, @@ -1121,7 +1200,7 @@ acl_check_modlist( if ( be_isroot( be, &op->o_ndn ) ) { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1, - "acl_check_modlist: conn %d access granted to root user\n", + "acl_check_modlist: conn %lu access granted to root user\n", conn->c_connid )); #else Debug( LDAP_DEBUG_ACL, @@ -1135,7 +1214,7 @@ acl_check_modlist( if( be != NULL && be->be_acl == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, - "acl_check_modlist: conn %d backend default %s access %s to \"%s\"\n", + "acl_check_modlist: conn %lu backend default %s access %s to \"%s\"\n", conn->c_connid, access2str( ACL_WRITE ), be->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn.bv_val )); #else @@ -1152,7 +1231,7 @@ acl_check_modlist( } else if ( be == NULL && global_acl == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, - "acl_check_modlist: conn %d global default %s access %s to \"%s\"\n", + "acl_check_modlist: conn %lu global default %s access %s to \"%s\"\n", conn->c_connid, access2str( ACL_WRITE ), global_default_access >= ACL_WRITE ? "granted" : "denied", op->o_dn )); #else @@ -1177,7 +1256,7 @@ acl_check_modlist( if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) ) { #ifdef NEW_LOGGING LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, - "acl_check_modlist: conn %d no-user-mod %s: modify access granted\n", + "acl_check_modlist: conn %lu no-user-mod %s: modify access granted\n", conn->c_connid, mlist->sml_desc->ad_cname.bv_val )); #else Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:" @@ -1249,6 +1328,7 @@ acl_check_modlist( return( 1 ); } +#if 0 /* not used any more */ static char * aci_bvstrdup( struct berval *bv ) { @@ -1261,6 +1341,7 @@ aci_bvstrdup( struct berval *bv ) } return(s); } +#endif static int aci_get_part( @@ -1565,7 +1646,6 @@ aci_group_member ( regmatch_t *matches ) { - struct berval bv; struct berval subjdn; struct berval grpoc; struct berval grpat; @@ -1597,15 +1677,13 @@ aci_group_member ( grp_oc = oc_bvfind( &grpoc ); if (grp_oc != NULL && grp_ad != NULL ) { - struct berval ndn; - bv.bv_val = (char *)ch_malloc(1024); - bv.bv_len = 1024; + char buf[ACL_BUF_SIZE]; + struct berval bv = { sizeof(buf), buf }, ndn; string_expand(&bv, &subjdn, e->e_ndn, matches); if ( dnNormalize2(NULL, &bv, &ndn) == LDAP_SUCCESS ) { rc = (backend_group(be, conn, op, e, &ndn, &op->o_ndn, grp_oc, grp_ad) == 0); free( ndn.bv_val ); } - ch_free(bv.bv_val); } done: @@ -1766,26 +1844,48 @@ string_expand( for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len && sp < pat->bv_val + pat->bv_len ; sp++) { /* did we previously see a $ */ - if (flag) { - if (*sp == '$') { + if ( flag ) { + if ( flag == 1 && *sp == '$' ) { *dp++ = '$'; size++; - } else if (*sp >= '0' && *sp <= '9' ) { + flag = 0; + + } else if ( flag == 1 && *sp == '{') { + flag = 2; + + } else if ( *sp >= '0' && *sp <= '9' ) { int n; int i; int l; n = *sp - '0'; + + if ( flag == 2 ) { + for ( sp++; *sp != '\0' && *sp != /* { */ '}'; sp++ ) { + if ( *sp >= '0' && *sp <= '9' ) { + n = 10*n + ( *sp - '0' ); + } + } + + if ( *sp != /* { */ '}' ) { + /* error */ + } + } + + if ( n >= MAXREMATCHES ) { + + } + *dp = '\0'; i = matches[n].rm_so; l = matches[n].rm_eo; for ( ; size < bv->bv_len && i < l; size++, i++ ) { *dp++ = match[i]; - size++; } *dp = '\0'; + + flag = 0; } - flag = 0; } else { if (*sp == '$') { flag = 1; @@ -1796,7 +1896,7 @@ string_expand( } } - if (flag) { + if ( flag ) { /* must have ended with a single $ */ *dp++ = '$'; size++; @@ -1807,11 +1907,11 @@ string_expand( #ifdef NEW_LOGGING LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, - "string_expand: pattern = %.*s\n", pat->bv_len, pat->bv_val )); + "string_expand: pattern = %.*s\n", (int)pat->bv_len, pat->bv_val )); LDAP_LOG(( "aci", LDAP_LEVEL_DETAIL1, "string_expand: expanded = %s\n", bv->bv_val )); #else - Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern: %.*s\n", pat->bv_len, pat->bv_val, 0 ); + Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 ); Debug( LDAP_DEBUG_TRACE, "=> string_expand: expanded: %s\n", bv->bv_val, 0, 0 ); #endif } diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index 10fa6a07210cd7681b2599953df1ceabeee7d107..95397c2668eb71b7d04639b4e679df4f75d082bc 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -1,44 +1,106 @@ -/* acl.c - routines to parse and check acl's */ +/* aclparse.c - routines to parse and check acl's */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include "regex.h" + +#include <ac/ctype.h> +#include <ac/regex.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/unistd.h> + #include "slap.h" -#include "portable.h" +#include "lber_pvt.h" + +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)); -extern Filter *str2filter(); -extern char *re_comp(); -extern struct acl *global_acl; -extern char **str2charray(); -extern char *dn_upcase(); +static void acl_regex_normalized_dn(struct berval *pattern); -static void split(); -static void acl_append(); -static void access_append(); -static void acl_usage(); #ifdef LDAP_DEBUG -static void print_acl(); -static void print_access(); +static void print_acl(Backend *be, AccessControl *a); +static void print_access(Access *b); #endif +static int +regtest(const char *fname, int lineno, char *pat) { + int e; + regex_t re; + + char buf[512]; + unsigned size; + + char *sp; + char *dp; + int flag; + + sp = pat; + dp = buf; + size = 0; + buf[0] = '\0'; + + for (size = 0, flag = 0; (size < sizeof(buf)) && *sp; sp++) { + if (flag) { + if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) { + *dp++ = *sp; + size++; + } + flag = 0; + + } else { + if (*sp == '$') { + flag = 1; + } else { + *dp++ = *sp; + size++; + } + } + } + + *dp = '\0'; + if ( size >= (sizeof(buf)-1) ) { + fprintf( stderr, + "%s: line %d: regular expression \"%s\" too large\n", + fname, lineno, pat ); + acl_usage(); + } + + if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) { + char error[512]; + regerror(e, &re, error, sizeof(error)); + fprintf( stderr, + "%s: line %d: regular expression \"%s\" bad because of %s\n", + fname, lineno, pat, error ); + acl_usage(); + return(0); + } + regfree(&re); + return(1); +} + void parse_acl( Backend *be, - char *fname, + const char *fname, int lineno, int argc, char **argv ) { int i; - char *e, *left, *right; - struct acl *a; - struct access *b; + char *left, *right, *style; + struct berval bv; + AccessControl *a; + Access *b; + int rc; + const char *text; a = NULL; for ( i = 1; i < argc; i++ ) { @@ -50,142 +112,934 @@ parse_acl( fname, lineno ); acl_usage(); } - a = (struct acl *) ch_calloc( 1, sizeof(struct acl) ); + a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) ); for ( ++i; i < argc; i++ ) { if ( strcasecmp( argv[i], "by" ) == 0 ) { i--; break; } - if ( strcasecmp( argv[i], "*" ) == 0 ) { - a->acl_dnpat = strdup( ".*" ); + if ( strcasecmp( argv[i], "*" ) == 0 ) { + if( a->acl_dn_pat.bv_len != 0 ) { + fprintf( stderr, + "%s: line %d: dn pattern" + " already specified in to clause.\n", + fname, lineno ); + acl_usage(); + } + + a->acl_dn_pat.bv_val = ch_strdup( "*" ); + a->acl_dn_pat.bv_len = 1; + continue; + } + + split( argv[i], '=', &left, &right ); + split( left, '.', &left, &style ); + + if ( right == NULL ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in \"%s\" in to clause\n", + fname, lineno, left ); + acl_usage(); + } + + if ( strcasecmp( left, "dn" ) == 0 ) { + if( a->acl_dn_pat.bv_len != 0 ) { + fprintf( stderr, + "%s: line %d: dn pattern" + " already specified in to clause.\n", + fname, lineno ); + acl_usage(); + } + + if ( style == NULL || *style == '\0' + || strcasecmp( style, "regex" ) == 0 ) + { + a->acl_dn_style = ACL_STYLE_REGEX; + + if ( *right == '\0' ) { + /* empty regex should match empty DN */ + a->acl_dn_style = ACL_STYLE_BASE; + ber_str2bv( right, 0, 1, &a->acl_dn_pat ); + + } else if ( strcmp(right, "*") == 0 + || strcmp(right, ".*") == 0 + || strcmp(right, ".*$") == 0 + || strcmp(right, "^.*") == 0 + || strcmp(right, "^.*$$") == 0 + || strcmp(right, ".*$$") == 0 + || strcmp(right, "^.*$$") == 0 ) + { + a->acl_dn_pat.bv_val = ch_strdup( "*" ); + a->acl_dn_pat.bv_len = sizeof("*")-1; + + } else { + a->acl_dn_pat.bv_val = right; + acl_regex_normalized_dn( &a->acl_dn_pat ); + } + } else if ( strcasecmp( style, "base" ) == 0 ) { + a->acl_dn_style = ACL_STYLE_BASE; + ber_str2bv( right, 0, 1, &a->acl_dn_pat ); + } else if ( strcasecmp( style, "one" ) == 0 ) { + a->acl_dn_style = ACL_STYLE_ONE; + ber_str2bv( right, 0, 1, &a->acl_dn_pat ); + } else if ( strcasecmp( style, "subtree" ) == 0 ) { + a->acl_dn_style = ACL_STYLE_SUBTREE; + ber_str2bv( right, 0, 1, &a->acl_dn_pat ); + } else if ( strcasecmp( style, "children" ) == 0 ) { + a->acl_dn_style = ACL_STYLE_CHILDREN; + ber_str2bv( right, 0, 1, &a->acl_dn_pat ); + } else { + fprintf( stderr, + "%s: line %d: unknown dn style \"%s\" in to clause\n", + fname, lineno, style ); + acl_usage(); + } + + continue; + } + + if ( strcasecmp( left, "filter" ) == 0 ) { + if ( (a->acl_filter = str2filter( + right )) == NULL ) { + fprintf( stderr, + "%s: line %d: bad filter \"%s\" in to clause\n", + fname, lineno, right ); + acl_usage(); + } + + } else if ( strncasecmp( left, "attr", 4 ) == 0 ) { + a->acl_attrs = str2anlist( a->acl_attrs, + right, "," ); + if ( a->acl_attrs == NULL ) { + fprintf( stderr, + "%s: line %d: unknown attr \"%s\" in to clause\n", + fname, lineno, right ); + acl_usage(); + } + } else { + fprintf( stderr, + "%s: line %d: expecting <what> got \"%s\"\n", + fname, lineno, left ); + acl_usage(); + } + } + + if ( a->acl_dn_pat.bv_len != 0 && + strcmp(a->acl_dn_pat.bv_val, "*") == 0) + { + free( a->acl_dn_pat.bv_val ); + a->acl_dn_pat.bv_val = NULL; + a->acl_dn_pat.bv_len = 0; + } + + 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); + free( a->acl_dn_pat.bv_val ); + a->acl_dn_pat = bv; + } else { + int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val, + REG_EXTENDED | REG_ICASE ); + if ( e ) { + char buf[512]; + regerror( e, &a->acl_dn_re, buf, sizeof(buf) ); + fprintf( stderr, "%s: line %d: " + "regular expression \"%s\" bad because of %s\n", + fname, lineno, right, buf ); + acl_usage(); + } + } + } + + /* by clause - select who has what access to entries */ + } else if ( strcasecmp( argv[i], "by" ) == 0 ) { + if ( a == NULL ) { + fprintf( stderr, + "%s: line %d: to clause required before by clause in access line\n", + fname, lineno ); + acl_usage(); + } + + /* + * by clause consists of <who> and <access> + */ + + b = (Access *) ch_calloc( 1, sizeof(Access) ); + + ACL_INVALIDATE( b->a_access_mask ); + + if ( ++i == argc ) { + fprintf( stderr, + "%s: line %d: premature eol: expecting <who>\n", + fname, lineno ); + acl_usage(); + } + + /* get <who> */ + for ( ; i < argc; i++ ) { + slap_style_t sty = ACL_STYLE_REGEX; + char *style_modifier = NULL; + int expand = 0; + + split( argv[i], '=', &left, &right ); + split( left, '.', &left, &style ); + if ( style ) { + split( style, ',', &style, &style_modifier); + } + if ( style == NULL || *style == '\0' + || strcasecmp( style, "regex" ) == 0 ) + { + sty = ACL_STYLE_REGEX; + } else if ( strcasecmp( style, "exact" ) == 0 ) { + sty = ACL_STYLE_EXACT; + } else if ( strcasecmp( style, "base" ) == 0 ) { + sty = ACL_STYLE_BASE; + } else if ( strcasecmp( style, "one" ) == 0 ) { + sty = ACL_STYLE_ONE; + } else if ( strcasecmp( style, "subtree" ) == 0 ) { + sty = ACL_STYLE_SUBTREE; + } else if ( strcasecmp( style, "children" ) == 0 ) { + sty = ACL_STYLE_CHILDREN; + } else { + fprintf( stderr, + "%s: line %d: unknown style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( style_modifier && strcasecmp( style_modifier, "expand" ) == 0 ) { + expand = 1; + } + + if ( strcasecmp( argv[i], "*" ) == 0 ) { + bv.bv_val = ch_strdup( "*" ); + bv.bv_len = 1; + + } else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) { + ber_str2bv("anonymous", + sizeof("anonymous")-1, + 1, &bv); + + } else if ( strcasecmp( argv[i], "self" ) == 0 ) { + ber_str2bv("self", + sizeof("self")-1, + 1, &bv); + + } else if ( strcasecmp( argv[i], "users" ) == 0 ) { + ber_str2bv("users", + sizeof("users")-1, + 1, &bv); + + } else if ( strcasecmp( left, "dn" ) == 0 ) { + if ( sty == ACL_STYLE_REGEX ) { + b->a_dn_style = ACL_STYLE_REGEX; + if( right == NULL ) { + /* no '=' */ + ber_str2bv("users", + sizeof("users")-1, + 1, &bv); + } else if (*right == '\0' ) { + /* dn="" */ + ber_str2bv("anonymous", + sizeof("anonymous")-1, + 1, &bv); + } else if ( strcmp( right, "*" ) == 0 ) { + /* dn=* */ + /* any or users? users for now */ + ber_str2bv("users", + sizeof("users")-1, + 1, &bv); + } else if ( strcmp( right, ".+" ) == 0 + || strcmp( right, "^.+" ) == 0 + || strcmp( right, ".+$" ) == 0 + || strcmp( right, "^.+$" ) == 0 + || strcmp( right, ".+$$" ) == 0 + || strcmp( right, "^.+$$" ) == 0 ) + { + ber_str2bv("users", + sizeof("users")-1, + 1, &bv); + } else if ( strcmp( right, ".*" ) == 0 + || strcmp( right, "^.*" ) == 0 + || strcmp( right, ".*$" ) == 0 + || strcmp( right, "^.*$" ) == 0 + || strcmp( right, ".*$$" ) == 0 + || strcmp( right, "^.*$$" ) == 0 ) + { + ber_str2bv("*", + sizeof("*")-1, + 1, &bv); + + } else { + bv.bv_val = right; + acl_regex_normalized_dn( &bv ); + if ( !ber_bvccmp( &bv, '*' ) ) { + regtest(fname, lineno, bv.bv_val); + } + } + } else if ( right == NULL || *right == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + + } else { + ber_str2bv( right, 0, 1, &bv ); + } + + } else { + bv.bv_val = NULL; + } + + if( bv.bv_val != NULL ) { + if( b->a_dn_pat.bv_len != 0 ) { + fprintf( stderr, + "%s: line %d: dn pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( sty != ACL_STYLE_REGEX && expand == 0 ) { + dnNormalize2(NULL, &bv, &b->a_dn_pat); + free(bv.bv_val); + } else { + b->a_dn_pat = bv; + } + b->a_dn_style = sty; + b->a_dn_expand = expand; + continue; + } + + if ( strcasecmp( left, "dnattr" ) == 0 ) { + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_dn_at != NULL ) { + fprintf( stderr, + "%s: line %d: dnattr already specified.\n", + fname, lineno ); + acl_usage(); + } + + rc = slap_str2ad( right, &b->a_dn_at, &text ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: dnattr \"%s\": %s\n", + fname, lineno, right, text ); + acl_usage(); + } + + + if( !is_at_syntax( b->a_dn_at->ad_type, + SLAPD_DN_SYNTAX ) && + !is_at_syntax( b->a_dn_at->ad_type, + SLAPD_NAMEUID_SYNTAX )) + { + fprintf( stderr, + "%s: line %d: dnattr \"%s\": " + "inappropriate syntax: %s\n", + fname, lineno, right, + b->a_dn_at->ad_type->sat_syntax_oid ); + acl_usage(); + } + + continue; + } + + if ( strncasecmp( left, "group", sizeof("group")-1 ) == 0 ) { + char *name = NULL; + char *value = NULL; + + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_group_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: group pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + /* format of string is "group/objectClassValue/groupAttrName" */ + if ((value = strchr(left, '/')) != NULL) { + *value++ = '\0'; + if (*value + && (name = strchr(value, '/')) != NULL) + { + *name++ = '\0'; + } + } + + b->a_group_style = sty; + if (sty == ACL_STYLE_REGEX) { + bv.bv_val = right; + acl_regex_normalized_dn( &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 ); + } + + if (value && *value) { + b->a_group_oc = oc_find( value ); + *--value = '/'; + + if( b->a_group_oc == NULL ) { + fprintf( stderr, + "%s: line %d: group objectclass " + "\"%s\" unknown\n", + fname, lineno, value ); + acl_usage(); + } + } else { + b->a_group_oc = oc_find(SLAPD_GROUP_CLASS); + + if( b->a_group_oc == NULL ) { + fprintf( stderr, + "%s: line %d: group default objectclass " + "\"%s\" unknown\n", + fname, lineno, SLAPD_GROUP_CLASS ); + acl_usage(); + } + } + + if( is_object_subclass( slap_schema.si_oc_referral, + b->a_group_oc )) + { + fprintf( stderr, + "%s: line %d: group objectclass \"%s\" " + "is subclass of referral\n", + fname, lineno, value ); + acl_usage(); + } + + if( is_object_subclass( slap_schema.si_oc_alias, + b->a_group_oc )) + { + fprintf( stderr, + "%s: line %d: group objectclass \"%s\" " + "is subclass of alias\n", + fname, lineno, value ); + acl_usage(); + } + + if (name && *name) { + rc = slap_str2ad( name, &b->a_group_at, &text ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: group \"%s\": %s\n", + fname, lineno, right, text ); + acl_usage(); + } + *--name = '/'; + } else { + rc = slap_str2ad( SLAPD_GROUP_ATTR, &b->a_group_at, &text ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: group \"%s\": %s\n", + fname, lineno, SLAPD_GROUP_ATTR, text ); + acl_usage(); + } + } + + if( !is_at_syntax( b->a_group_at->ad_type, + SLAPD_DN_SYNTAX ) && + !is_at_syntax( b->a_group_at->ad_type, + SLAPD_NAMEUID_SYNTAX ) ) + { + fprintf( stderr, + "%s: line %d: group \"%s\": inappropriate syntax: %s\n", + fname, lineno, right, + b->a_group_at->ad_type->sat_syntax_oid ); + acl_usage(); + } + + + { + int rc; + struct berval vals[2]; + + vals[0].bv_val = b->a_group_oc->soc_oid; + vals[0].bv_len = strlen(vals[0].bv_val); + vals[1].bv_val = NULL; + + + rc = oc_check_allowed( b->a_group_at->ad_type, vals, NULL ); + + if( rc != 0 ) { + fprintf( stderr, + "%s: line %d: group: \"%s\" not allowed by \"%s\"\n", + fname, lineno, + b->a_group_at->ad_cname.bv_val, + b->a_group_oc->soc_oid ); + acl_usage(); + } + } + continue; + } + + if ( strcasecmp( left, "peername" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_peername_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: peername pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + b->a_peername_style = sty; + if (sty == ACL_STYLE_REGEX) { + bv.bv_val = right; + acl_regex_normalized_dn( &bv ); + if ( !ber_bvccmp( &bv, '*' ) ) { + regtest(fname, lineno, bv.bv_val); + } + b->a_peername_pat = bv; + } else { + ber_str2bv( right, 0, 1, &b->a_peername_pat ); + } + continue; + } + + if ( strcasecmp( left, "sockname" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_sockname_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: sockname pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + b->a_sockname_style = sty; + if (sty == ACL_STYLE_REGEX) { + bv.bv_val = right; + acl_regex_normalized_dn( &bv ); + if ( !ber_bvccmp( &bv, '*' ) ) { + regtest(fname, lineno, bv.bv_val); + } + b->a_sockname_pat = bv; + } else { + ber_str2bv( right, 0, 1, &b->a_sockname_pat ); + } + continue; + } + + if ( strcasecmp( left, "domain" ) == 0 ) { + switch ( sty ) { + case ACL_STYLE_REGEX: + case ACL_STYLE_BASE: + case ACL_STYLE_SUBTREE: + break; + + default: + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_domain_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: domain pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + b->a_domain_style = sty; + b->a_domain_expand = expand; + if (sty == ACL_STYLE_REGEX) { + bv.bv_val = right; + acl_regex_normalized_dn( &bv ); + if ( !ber_bvccmp( &bv, '*' ) ) { + regtest(fname, lineno, bv.bv_val); + } + b->a_domain_pat = bv; + } else { + ber_str2bv( right, 0, 1, &b->a_domain_pat ); + } + continue; + } + + if ( strcasecmp( left, "sockurl" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if ( right == NULL || right[ 0 ] == '\0' ) { + fprintf( stderr, + "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", + fname, lineno, left ); + acl_usage(); + } + + if( b->a_sockurl_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: sockurl pattern already specified.\n", + fname, lineno ); + acl_usage(); + } + + b->a_sockurl_style = sty; + if (sty == ACL_STYLE_REGEX) { + bv.bv_val = right; + acl_regex_normalized_dn( &bv ); + if ( !ber_bvccmp( &bv, '*' ) ) { + regtest(fname, lineno, bv.bv_val); + } + b->a_sockurl_pat = bv; + } else { + ber_str2bv( right, 0, 1, &b->a_sockurl_pat ); + } + continue; + } + + if ( strcasecmp( left, "set" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if( b->a_set_pat.bv_len != 0 ) { + fprintf( stderr, + "%s: line %d: set attribute already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( right == NULL || *right == '\0' ) { + fprintf( stderr, + "%s: line %d: no set is defined\n", + fname, lineno ); + acl_usage(); + } + + b->a_set_style = sty; + ber_str2bv( right, 0, 1, &b->a_set_pat ); + + continue; + } + +#ifdef SLAPD_ACI_ENABLED + if ( strcasecmp( left, "aci" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if( b->a_aci_at != NULL ) { + fprintf( stderr, + "%s: line %d: aci attribute already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( right != NULL && *right != '\0' ) { + rc = slap_str2ad( right, &b->a_aci_at, &text ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: aci \"%s\": %s\n", + fname, lineno, right, text ); + acl_usage(); + } + + } else { + b->a_aci_at = slap_schema.si_ad_aci; + } + + if( !is_at_syntax( b->a_aci_at->ad_type, + SLAPD_ACI_SYNTAX) ) + { + fprintf( stderr, + "%s: line %d: aci \"%s\": inappropriate syntax: %s\n", + fname, lineno, right, + b->a_aci_at->ad_type->sat_syntax_oid ); + acl_usage(); + } + + continue; + } +#endif /* SLAPD_ACI_ENABLED */ + + if ( strcasecmp( left, "ssf" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if( b->a_authz.sai_ssf ) { + fprintf( stderr, + "%s: line %d: ssf attribute already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( right == NULL || *right == '\0' ) { + fprintf( stderr, + "%s: line %d: no ssf is defined\n", + fname, lineno ); + acl_usage(); + } + + b->a_authz.sai_ssf = atoi( right ); + + if( !b->a_authz.sai_ssf ) { + fprintf( stderr, + "%s: line %d: invalid ssf value (%s)\n", + fname, lineno, right ); + acl_usage(); + } + continue; + } + + if ( strcasecmp( left, "transport_ssf" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if( b->a_authz.sai_transport_ssf ) { + fprintf( stderr, + "%s: line %d: transport_ssf attribute already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( right == NULL || *right == '\0' ) { + fprintf( stderr, + "%s: line %d: no transport_ssf is defined\n", + fname, lineno ); + acl_usage(); + } + + b->a_authz.sai_transport_ssf = atoi( right ); + + if( !b->a_authz.sai_transport_ssf ) { + fprintf( stderr, + "%s: line %d: invalid transport_ssf value (%s)\n", + fname, lineno, right ); + acl_usage(); + } + continue; + } + + if ( strcasecmp( left, "tls_ssf" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } + + if( b->a_authz.sai_tls_ssf ) { + fprintf( stderr, + "%s: line %d: tls_ssf attribute already specified.\n", + fname, lineno ); + acl_usage(); + } + + if ( right == NULL || *right == '\0' ) { + fprintf( stderr, + "%s: line %d: no tls_ssf is defined\n", + fname, lineno ); + acl_usage(); + } + + b->a_authz.sai_tls_ssf = atoi( right ); + + if( !b->a_authz.sai_tls_ssf ) { + fprintf( stderr, + "%s: line %d: invalid tls_ssf value (%s)\n", + fname, lineno, right ); + acl_usage(); + } continue; } - split( argv[i], '=', &left, &right ); - if ( right == NULL || *right == '\0' ) { - fprintf( stderr, - "%s: line %d: missing \"=\" in (or value after) \"%s\" in to clause\n", - fname, lineno, left ); - acl_usage(); - } + if ( strcasecmp( left, "sasl_ssf" ) == 0 ) { + if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { + fprintf( stderr, + "%s: line %d: inappropriate style \"%s\" in by clause\n", + fname, lineno, style ); + acl_usage(); + } - if ( strcasecmp( left, "filter" ) == 0 ) { - if ( (a->acl_filter = str2filter( - right )) == NULL ) { + if( b->a_authz.sai_sasl_ssf ) { fprintf( stderr, - "%s: line %d: bad filter \"%s\" in to clause\n", - fname, lineno, right ); + "%s: line %d: sasl_ssf attribute already specified.\n", + fname, lineno ); acl_usage(); } - } else if ( strcasecmp( left, "dn" ) == 0 ) { - if ( (e = re_comp( right )) != NULL ) { + + if ( right == NULL || *right == '\0' ) { fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad because of %s\n", - fname, lineno, right, e ); + "%s: line %d: no sasl_ssf is defined\n", + fname, lineno ); acl_usage(); } - a->acl_dnpat = dn_upcase( strdup( - right ) ); - } else if ( strncasecmp( left, "attr", 4 ) - == 0 ) { - char **alist; - alist = str2charray( right, "," ); - charray_merge( &a->acl_attrs, alist ); - free( alist ); - } else { - fprintf( stderr, - "%s: line %d: expecting <what> got \"%s\"\n", - fname, lineno, left ); - acl_usage(); + b->a_authz.sai_sasl_ssf = atoi( right ); + + if( !b->a_authz.sai_sasl_ssf ) { + fprintf( stderr, + "%s: line %d: invalid sasl_ssf value (%s)\n", + fname, lineno, right ); + acl_usage(); + } + continue; + } + + if( right != NULL ) { + /* unsplit */ + right[-1] = '='; } + break; } - /* by clause - select who has what access to entries */ - } else if ( strcasecmp( argv[i], "by" ) == 0 ) { - if ( a == NULL ) { - fprintf( stderr, - "%s: line %d: to clause required before by clause in access line\n", - fname, lineno ); - acl_usage(); + if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { + /* out of arguments or plain stop */ + + ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); + b->a_type = ACL_STOP; + + access_append( &a->acl_access, b ); + continue; } - /* - * by clause consists of <who> and <access> - */ - b = (struct access *) ch_calloc( 1, - sizeof(struct access) ); + if( strcasecmp( left, "continue" ) == 0 ) { + /* plain continue */ - if ( ++i == argc ) { - fprintf( stderr, - "%s: line %d: premature eol: expecting <who>\n", - fname, lineno ); - acl_usage(); + ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); + b->a_type = ACL_CONTINUE; + + access_append( &a->acl_access, b ); + continue; } - /* get <who> */ - split( argv[i], '=', &left, &right ); - if ( strcasecmp( argv[i], "*" ) == 0 ) { - b->a_dnpat = strdup( ".*" ); - } else if ( strcasecmp( argv[i], "self" ) == 0 ) { - b->a_dnpat = strdup( "self" ); - } else if ( strcasecmp( left, "dn" ) == 0 ) { - if ( (e = re_comp( right )) != NULL ) { - fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", - fname, lineno, right, e ); - acl_usage(); - } - b->a_dnpat = dn_upcase( strdup( right ) ); - } else if ( strcasecmp( left, "dnattr" ) - == 0 ) { - b->a_dnattr = strdup( right ); - } else if ( strcasecmp( left, "domain" ) - == 0 ) { - char *s; - - if ( (e = re_comp( right )) != NULL ) { - fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", - fname, lineno, right, e ); - acl_usage(); - } - b->a_domainpat = strdup( right ); - /* normalize the domain */ - for ( s = b->a_domainpat; *s; s++ ) { - *s = TOLOWER( *s ); - } - } else if ( strcasecmp( left, "addr" ) == 0 ) { - if ( (e = re_comp( right )) != NULL ) { - fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", - fname, lineno, right, e ); - acl_usage(); - } - b->a_addrpat = strdup( right ); - } else { - fprintf( stderr, - "%s: line %d: expecting <who> got \"%s\"\n", - fname, lineno, left ); - acl_usage(); + if( strcasecmp( left, "break" ) == 0 ) { + /* plain continue */ + + ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); + b->a_type = ACL_BREAK; + + access_append( &a->acl_access, b ); + continue; } - if ( ++i == argc ) { - fprintf( stderr, - "%s: line %d: premature eol: expecting <access>\n", - fname, lineno ); - acl_usage(); + if ( strcasecmp( left, "by" ) == 0 ) { + /* we've gone too far */ + --i; + ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); + b->a_type = ACL_STOP; + + access_append( &a->acl_access, b ); + continue; } /* get <access> */ - split( argv[i], '=', &left, &right ); - if ( (b->a_access = str2access( left )) == -1 ) { + if( strncasecmp( left, "self", 4 ) == 0 ) { + b->a_dn_self = 1; + ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) ); + + } else { + ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) ); + } + + if( ACL_IS_INVALID( b->a_access_mask ) ) { fprintf( stderr, - "%s: line %d: expecting <access> got \"%s\"\n", - fname, lineno, left ); + "%s: line %d: expecting <access> got \"%s\"\n", + fname, lineno, left ); acl_usage(); } + + b->a_type = ACL_STOP; + + if( ++i == argc ) { + /* out of arguments or plain stop */ + access_append( &a->acl_access, b ); + continue; + } + + if( strcasecmp( argv[i], "continue" ) == 0 ) { + /* plain continue */ + b->a_type = ACL_CONTINUE; + + } else if( strcasecmp( argv[i], "break" ) == 0 ) { + /* plain continue */ + b->a_type = ACL_BREAK; + + } else if ( strcasecmp( argv[i], "stop" ) != 0 ) { + /* gone to far */ + i--; + } + access_append( &a->acl_access, b ); } else { @@ -198,16 +1052,19 @@ parse_acl( /* if we have no real access clause, complain and do nothing */ if ( a == NULL ) { - fprintf( stderr, - "%s: line %d: warning: no access clause(s) specified in access line\n", + "%s: line %d: warning: no access clause(s) specified in access line\n", fname, lineno ); } else { +#ifdef LDAP_DEBUG + if (ldap_debug & LDAP_DEBUG_ACL) + print_acl(be, a); +#endif if ( a->acl_access == NULL ) { fprintf( stderr, - "%s: line %d: warning: no by clause(s) specified in access line\n", + "%s: line %d: warning: no by clause(s) specified in access line\n", fname, lineno ); } @@ -220,71 +1077,246 @@ parse_acl( } char * -access2str( int access ) +accessmask2str( slap_mask_t mask, char *buf ) { - static char buf[12]; + int none=1; + char *ptr = buf; + + assert( buf != NULL ); + + if ( ACL_IS_INVALID( mask ) ) { + return "invalid"; + } + + buf[0] = '\0'; + + if ( ACL_IS_LEVEL( mask ) ) { + if ( ACL_LVL_IS_NONE(mask) ) { + ptr = slap_strcopy( ptr, "none" ); + + } else if ( ACL_LVL_IS_AUTH(mask) ) { + ptr = slap_strcopy( ptr, "auth" ); + + } else if ( ACL_LVL_IS_COMPARE(mask) ) { + ptr = slap_strcopy( ptr, "compare" ); + + } else if ( ACL_LVL_IS_SEARCH(mask) ) { + ptr = slap_strcopy( ptr, "search" ); + + } else if ( ACL_LVL_IS_READ(mask) ) { + ptr = slap_strcopy( ptr, "read" ); + + } else if ( ACL_LVL_IS_WRITE(mask) ) { + ptr = slap_strcopy( ptr, "write" ); + } else { + ptr = slap_strcopy( ptr, "unknown" ); + } + + *ptr++ = '('; + } + + if( ACL_IS_ADDITIVE( mask ) ) { + *ptr++ = '+'; + + } else if( ACL_IS_SUBTRACTIVE( mask ) ) { + *ptr++ = '-'; - if ( access & ACL_SELF ) { - strcpy( buf, "self" ); - } else { - buf[0] = '\0'; - } - - if ( access & ACL_NONE ) { - strcat( buf, "none" ); - } else if ( access & ACL_COMPARE ) { - strcat( buf, "compare" ); - } else if ( access & ACL_SEARCH ) { - strcat( buf, "search" ); - } else if ( access & ACL_READ ) { - strcat( buf, "read" ); - } else if ( access & ACL_WRITE ) { - strcat( buf, "write" ); } else { - strcat( buf, "unknown" ); + *ptr++ = '='; + } + + if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) { + none = 0; + *ptr++ = 'w'; + } + + if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) { + none = 0; + *ptr++ = 'r'; + } + + if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) { + none = 0; + *ptr++ = 's'; + } + + if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) { + none = 0; + *ptr++ = 'c'; + } + + if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) { + none = 0; + *ptr++ = 'x'; + } + + if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) { + none = 0; + *ptr++ = 'n'; + } + + if ( none ) { + *ptr++ = '0'; + } + + if ( ACL_IS_LEVEL( mask ) ) { + *ptr++ = ')'; } - return( buf ); + *ptr = '\0'; + + return buf; } -int -str2access( char *str ) +slap_mask_t +str2accessmask( const char *str ) { - int access; + slap_mask_t mask; + + if( !ASCII_ALPHA(str[0]) ) { + int i; + + if ( str[0] == '=' ) { + ACL_INIT(mask); + + } else if( str[0] == '+' ) { + ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE); + + } else if( str[0] == '-' ) { + ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE); - access = 0; - if ( strncasecmp( str, "self", 4 ) == 0 ) { - access |= ACL_SELF; - str += 4; + } else { + ACL_INVALIDATE(mask); + return mask; + } + + for( i=1; str[i] != '\0'; i++ ) { + if( TOLOWER(str[i]) == 'w' ) { + ACL_PRIV_SET(mask, ACL_PRIV_WRITE); + + } else if( TOLOWER(str[i]) == 'r' ) { + ACL_PRIV_SET(mask, ACL_PRIV_READ); + + } else if( TOLOWER(str[i]) == 's' ) { + ACL_PRIV_SET(mask, ACL_PRIV_SEARCH); + + } else if( TOLOWER(str[i]) == 'c' ) { + ACL_PRIV_SET(mask, ACL_PRIV_COMPARE); + + } else if( TOLOWER(str[i]) == 'x' ) { + ACL_PRIV_SET(mask, ACL_PRIV_AUTH); + + } else if( str[i] != '0' ) { + ACL_INVALIDATE(mask); + return mask; + } + } + + return mask; } if ( strcasecmp( str, "none" ) == 0 ) { - access |= ACL_NONE; + ACL_LVL_ASSIGN_NONE(mask); + + } else if ( strcasecmp( str, "auth" ) == 0 ) { + ACL_LVL_ASSIGN_AUTH(mask); + } else if ( strcasecmp( str, "compare" ) == 0 ) { - access |= ACL_COMPARE; + ACL_LVL_ASSIGN_COMPARE(mask); + } else if ( strcasecmp( str, "search" ) == 0 ) { - access |= ACL_SEARCH; + ACL_LVL_ASSIGN_SEARCH(mask); + } else if ( strcasecmp( str, "read" ) == 0 ) { - access |= ACL_READ; + ACL_LVL_ASSIGN_READ(mask); + } else if ( strcasecmp( str, "write" ) == 0 ) { - access |= ACL_WRITE; + ACL_LVL_ASSIGN_WRITE(mask); + } else { - access = -1; + ACL_INVALIDATE( mask ); } - return( access ); + return mask; +} + +static void +acl_usage( void ) +{ + fprintf( stderr, "\n" + "<access clause> ::= access to <what> " + "[ by <who> <access> [ <control> ] ]+ \n" + "<what> ::= * | [dn[.<dnstyle>]=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" + "<attrlist> ::= <attr> | <attr> , <attrlist>\n" + "<attr> ::= <attrname> | entry | children\n" + "<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<regex> ]\n" + "\t[dnattr=<attrname>]\n" + "\t[group[/<objectclass>[/<attrname>]][.<style>]=<regex>]\n" + "\t[peername[.<style>]=<regex>] [sockname[.<style>]=<regex>]\n" + "\t[domain[.<style>]=<regex>] [sockurl[.<style>]=<regex>]\n" +#ifdef SLAPD_ACI_ENABLED + "\t[aci=<attrname>]\n" +#endif + "\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n" + "<dnstyle> ::= regex | base | exact (alias of base) | one | sub | children\n" + "<style> ::= regex | base | exact (alias of base)\n" + "<groupflags> ::= R\n" + "<access> ::= [self]{<level>|<priv>}\n" + "<level> ::= none | auth | compare | search | read | write\n" + "<priv> ::= {=|+|-}{w|r|s|c|x}+\n" + "<control> ::= [ stop | continue | break ]\n" + ); + exit( EXIT_FAILURE ); } +/* + * 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_usage() +acl_regex_normalized_dn( + struct berval *pattern +) { - fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" ); - fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" ); - fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" ); - fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" ); - fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" ); - fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" ); - exit( 1 ); + char *str, *p; + + str = ch_strdup( pattern->bv_val ); + + for ( p = str; p && p[ 0 ]; p++ ) { + /* escape */ + if ( p[ 0 ] == '\\' ) { + /* + * if escaping a hex pair we should + * increment p twice; however, in that + * case the second hex number does + * no harm + */ + p++; + } + + if ( p[ 0 ] == ',' ) { + if ( p[ 1 ] == ' ' ) { + char *q; + + /* + * too much space should be + * an error if we are pedantic + */ + for ( q = &p[ 2 ]; q[ 0 ] == ' '; q++ ) { + /* DO NOTHING */ ; + } + AC_MEMCPY( p+1, q, pattern->bv_len-(q-str)+1); + } + } + } + pattern->bv_val = str; + pattern->bv_len = p-str; + + return; } static void @@ -302,7 +1334,7 @@ split( } static void -access_append( struct access **l, struct access *a ) +access_append( Access **l, Access *a ) { for ( ; *l != NULL; l = &(*l)->a_next ) ; /* NULL */ @@ -310,8 +1342,8 @@ access_append( struct access **l, struct access *a ) *l = a; } -static void -acl_append( struct acl **l, struct acl *a ) +void +acl_append( AccessControl **l, AccessControl *a ) { for ( ; *l != NULL; l = &(*l)->acl_next ) ; /* NULL */ @@ -319,58 +1351,272 @@ acl_append( struct acl **l, struct acl *a ) *l = a; } +static void +access_free( Access *a ) +{ + if ( a->a_dn_pat.bv_val ) + free ( a->a_dn_pat.bv_val ); + if ( a->a_peername_pat.bv_val ) + free ( a->a_peername_pat.bv_val ); + if ( a->a_sockname_pat.bv_val ) + free ( a->a_sockname_pat.bv_val ); + if ( a->a_domain_pat.bv_val ) + free ( a->a_domain_pat.bv_val ); + if ( a->a_sockurl_pat.bv_val ) + free ( a->a_sockurl_pat.bv_val ); + if ( a->a_set_pat.bv_len ) + free ( a->a_set_pat.bv_val ); + if ( a->a_group_pat.bv_len ) + free ( a->a_group_pat.bv_val ); + free( a ); +} + +void +acl_free( AccessControl *a ) +{ + Access *n; + AttributeName *an; + + if ( a->acl_filter ) + filter_free( a->acl_filter ); + if ( a->acl_dn_pat.bv_len ) + free ( a->acl_dn_pat.bv_val ); + if ( a->acl_attrs ) { + for ( an = a->acl_attrs; an->an_name.bv_val; an++ ) { + free( an->an_name.bv_val ); + } + free( a->acl_attrs ); + } + for (; a->acl_access; a->acl_access = n) { + n = a->acl_access->a_next; + access_free( a->acl_access ); + } + free( a ); +} + +/* Because backend_startup uses acl_append to tack on the global_acl to + * the end of each backend's acl, we cannot just take one argument and + * merrily free our way to the end of the list. backend_destroy calls us + * with the be_acl in arg1, and global_acl in arg2 to give us a stopping + * point. config_destroy calls us with global_acl in arg1 and NULL in + * arg2, so we then proceed to polish off the global_acl. + */ +void +acl_destroy( AccessControl *a, AccessControl *end ) +{ + AccessControl *n; + + for (; a && a!= end; a=n) { + n = a->acl_next; + acl_free( a ); + } +} + +char * +access2str( slap_access_t access ) +{ + if ( access == ACL_NONE ) { + return "none"; + + } else if ( access == ACL_AUTH ) { + return "auth"; + + } else if ( access == ACL_COMPARE ) { + return "compare"; + + } else if ( access == ACL_SEARCH ) { + return "search"; + + } else if ( access == ACL_READ ) { + return "read"; + + } else if ( access == ACL_WRITE ) { + return "write"; + } + + return "unknown"; +} + +slap_access_t +str2access( const char *str ) +{ + if ( strcasecmp( str, "none" ) == 0 ) { + return ACL_NONE; + + } else if ( strcasecmp( str, "auth" ) == 0 ) { + return ACL_AUTH; + + } else if ( strcasecmp( str, "compare" ) == 0 ) { + return ACL_COMPARE; + + } else if ( strcasecmp( str, "search" ) == 0 ) { + return ACL_SEARCH; + + } else if ( strcasecmp( str, "read" ) == 0 ) { + return ACL_READ; + + } else if ( strcasecmp( str, "write" ) == 0 ) { + return ACL_WRITE; + } + + return( ACL_INVALID_ACCESS ); +} + #ifdef LDAP_DEBUG +static char *style_strings[5] = { + "regex", + "base", + "one", + "subtree", + "children" + }; + + static void -print_access( struct access *b ) +print_access( Access *b ) { - printf( "\tby" ); - if ( b->a_dnpat != NULL ) { - printf( " dn=%s", b->a_dnpat ); - } else if ( b->a_addrpat != NULL ) { - printf( " addr=%s", b->a_addrpat ); - } else if ( b->a_domainpat != NULL ) { - printf( " domain=%s", b->a_domainpat ); - } else if ( b->a_dnattr != NULL ) { - printf( " dnattr=%s", b->a_dnattr ); - } - printf( " %s\n", access2str( b->a_access ) ); + char maskbuf[ACCESSMASK_MAXLEN]; + + fprintf( stderr, "\tby" ); + + if ( b->a_dn_pat.bv_len != 0 ) { + if( strcmp(b->a_dn_pat.bv_val, "*") == 0 + || strcmp(b->a_dn_pat.bv_val, "users") == 0 + || strcmp(b->a_dn_pat.bv_val, "anonymous") == 0 + || strcmp(b->a_dn_pat.bv_val, "self") == 0 ) + { + fprintf( stderr, " %s", b->a_dn_pat.bv_val ); + + } else { + fprintf( stderr, " dn.%s=%s", + style_strings[b->a_dn_style], b->a_dn_pat.bv_val ); + } + } + + if ( b->a_dn_at != NULL ) { + fprintf( stderr, " dnattr=%s", b->a_dn_at->ad_cname.bv_val ); + } + + if ( b->a_group_pat.bv_len ) { + fprintf( stderr, " group=%s", b->a_group_pat.bv_val ); + + if ( b->a_group_oc ) { + fprintf( stderr, " objectClass: %s", + b->a_group_oc->soc_oclass.oc_oid ); + + if ( b->a_group_at ) { + fprintf( stderr, " attributeType: %s", b->a_group_at->ad_cname.bv_val ); + } + } + } + + if ( b->a_peername_pat.bv_len != 0 ) { + fprintf( stderr, " peername=%s", b->a_peername_pat.bv_val ); + } + + if ( b->a_sockname_pat.bv_len != 0 ) { + fprintf( stderr, " sockname=%s", b->a_sockname_pat.bv_val ); + } + + if ( b->a_domain_pat.bv_len != 0 ) { + fprintf( stderr, " domain=%s", b->a_domain_pat.bv_val ); + } + + if ( b->a_sockurl_pat.bv_len != 0 ) { + fprintf( stderr, " sockurl=%s", b->a_sockurl_pat.bv_val ); + } + +#ifdef SLAPD_ACI_ENABLED + if ( b->a_aci_at != NULL ) { + fprintf( stderr, " aci=%s", b->a_aci_at->ad_cname.bv_val ); + } +#endif + + /* Security Strength Factors */ + if ( b->a_authz.sai_ssf ) { + fprintf( stderr, " ssf=%u", + b->a_authz.sai_ssf ); + } + if ( b->a_authz.sai_transport_ssf ) { + fprintf( stderr, " transport_ssf=%u", + b->a_authz.sai_transport_ssf ); + } + if ( b->a_authz.sai_tls_ssf ) { + fprintf( stderr, " tls_ssf=%u", + b->a_authz.sai_tls_ssf ); + } + if ( b->a_authz.sai_sasl_ssf ) { + fprintf( stderr, " sasl_ssf=%u", + b->a_authz.sai_sasl_ssf ); + } + + fprintf( stderr, " %s%s", + b->a_dn_self ? "self" : "", + accessmask2str( b->a_access_mask, maskbuf ) ); + + if( b->a_type == ACL_BREAK ) { + fprintf( stderr, " break" ); + + } else if( b->a_type == ACL_CONTINUE ) { + fprintf( stderr, " continue" ); + + } else if( b->a_type != ACL_STOP ) { + fprintf( stderr, " unknown-control" ); + } + + fprintf( stderr, "\n" ); } + static void -print_acl( struct acl *a ) +print_acl( Backend *be, AccessControl *a ) { - int i; - struct access *b; + int to = 0; + Access *b; - if ( a == NULL ) { - printf( "NULL\n" ); + fprintf( stderr, "%s ACL: access to", + be == NULL ? "Global" : "Backend" ); + + if ( a->acl_dn_pat.bv_len != 0 ) { + to++; + fprintf( stderr, " dn.%s=%s\n", + style_strings[a->acl_dn_style], a->acl_dn_pat.bv_val ); } - printf( "access to" ); + if ( a->acl_filter != NULL ) { - printf( " filter=" ); - filter_print( a->acl_filter ); - } - if ( a->acl_dnpat != NULL ) { - printf( " dn=" ); - printf( a->acl_dnpat ); + struct berval bv = { 0, NULL }; + to++; + filter2bv( a->acl_filter, &bv ); + fprintf( stderr, " filter=%s\n", bv.bv_val ); + ch_free( bv.bv_val ); } + if ( a->acl_attrs != NULL ) { int first = 1; + AttributeName *an; + to++; - printf( " attrs=" ); - for ( i = 0; a->acl_attrs[i] != NULL; i++ ) { + fprintf( stderr, " attrs=" ); + for ( an = a->acl_attrs; an && an->an_name.bv_val; an++ ) { if ( ! first ) { - printf( "," ); + fprintf( stderr, "," ); } - printf( a->acl_attrs[i] ); + fputs( an->an_name.bv_val, stderr ); first = 0; } + fprintf( stderr, "\n" ); + } + + if( !to ) { + fprintf( stderr, " *\n" ); } - printf( "\n" ); + for ( b = a->acl_access; b != NULL; b = b->a_next ) { print_access( b ); } + + fprintf( stderr, "\n" ); } -#endif +#endif /* LDAP_DEBUG */ diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 027e40a8e4d2af935172366a8266aeb7a7bd41ca..3c5c66a9ddfc54b760b424ca9ed11c0433830bae 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -1,3 +1,8 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. @@ -10,36 +15,46 @@ * is provided ``as is'' without express or implied warranty. */ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" +#include "portable.h" -extern Backend *select_backend(); -extern char *dn_normalize(); +#include <stdio.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/socket.h> -extern char *default_referral; -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; -extern int global_lastmod; +#include "ldap_pvt.h" +#include "slap.h" -static void add_created_attrs(); +static int slap_mods2entry( + Modifications *mods, + Entry **e, + int repl_user, + const char **text, + char *textbuf, size_t textlen ); -void -do_add( conn, op ) - Connection *conn; - Operation *op; +int +do_add( Connection *conn, Operation *op ) { BerElement *ber = op->o_ber; - char *dn, *last; - unsigned long len, tag; + char *last; + struct berval dn = { 0, NULL }; + ber_len_t len; + ber_tag_t tag; Entry *e; Backend *be; + Modifications *modlist = NULL; + Modifications **modtail = &modlist; + Modifications tmp; + const char *text; + int rc = LDAP_SUCCESS; + int manageDSAit; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_add: conn %d enter\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 ); - +#endif /* * Parse the add request. It looks like this: * @@ -52,61 +67,170 @@ do_add( conn, op ) * } */ + /* get the name */ + if ( ber_scanf( ber, "{m", /*}*/ &dn ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_add: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + return -1; + } + e = (Entry *) ch_calloc( 1, sizeof(Entry) ); - /* get the name */ - if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, - "decoding error" ); - return; + rc = dnPrettyNormal( NULL, &dn, &e->e_name, &e->e_nname ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_add: conn %d invalid dn (%s)\n", conn->c_connid, + dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "do_add: invalid dn (%s)\n", dn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto done; } - e->e_dn = dn; - dn = dn_normalize( strdup( dn ) ); - Debug( LDAP_DEBUG_ARGS, " do_add: dn (%s)\n", dn, 0, 0 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_add: conn %d dn (%s)\n", conn->c_connid, e->e_dn )); +#else + Debug( LDAP_DEBUG_ARGS, "do_add: dn (%s)\n", e->e_dn, 0, 0 ); +#endif /* get the attrs */ - e->e_attrs = NULL; for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT; - tag = ber_next_element( ber, &len, last ) ) { - char *type; - struct berval **vals; - - if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) { - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, - NULL, "decoding error" ); - entry_free( e ); - return; + tag = ber_next_element( ber, &len, last ) ) + { + Modifications *mod; + ber_tag_t rtag; + + rtag = ber_scanf( ber, "{m{W}}", &tmp.sml_type, &tmp.sml_bvalues ); + + if ( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_add: conn %d decoding error \n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_add: decoding error\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = -1; + goto done; } - if ( vals == NULL ) { - Debug( LDAP_DEBUG_ANY, "no values for type %s\n", type, - 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, - NULL ); - entry_free( e ); - return; + if ( tmp.sml_bvalues == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_add: conn %d no values for type %s\n", + conn->c_connid, tmp.sml_type.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "no values for type %s\n", + tmp.sml_type.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "no values for attribute type", NULL, NULL ); + free( tmp.sml_type.bv_val ); + goto done; } + mod = (Modifications *) ch_malloc( sizeof(Modifications) ); + + mod->sml_op = LDAP_MOD_ADD; + mod->sml_next = NULL; + mod->sml_desc = NULL; + mod->sml_type = tmp.sml_type; + mod->sml_bvalues = tmp.sml_bvalues; + + *modtail = mod; + modtail = &mod->sml_next; + } + + if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_add: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = -1; + goto done; + } - attr_merge( e, type, vals ); + if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_add: conn %d get_ctrls failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 ); +#endif + goto done; + } - free( type ); - ber_bvecfree( vals ); + if ( modlist == NULL ) { + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "no attributes provided", NULL, NULL ); + goto done; } - Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d ADD dn=\"%s\"\n", - conn->c_connid, op->o_opid, dn, 0, 0 ); + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu ADD dn=\"%s\"\n", + op->o_connid, op->o_opid, e->e_dn, 0, 0 ); + + if( e->e_nname.bv_len == 0 ) { + /* protocolError may be a more appropriate error */ + send_ldap_result( conn, op, rc = LDAP_ALREADY_EXISTS, + NULL, "root DSE already exists", + NULL, NULL ); + goto done; + +#if defined( SLAPD_SCHEMA_DN ) + } else if ( strcasecmp( e->e_ndn, SLAPD_SCHEMA_DN ) == 0 ) { + send_ldap_result( conn, op, rc = LDAP_ALREADY_EXISTS, + NULL, "subschema subentry already exists", + NULL, NULL ); + goto done; +#endif + } + + manageDSAit = get_manageDSAit( op ); /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - if ( (be = select_backend( dn )) == NULL ) { - entry_free( e ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); - return; + be = select_backend( &e->e_nname, manageDSAit, 0 ); + if ( be == NULL ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &e->e_name, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + if ( ref ) ber_bvarray_free( ref ); + goto done; + } + + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto done; + } + + /* check for referrals */ + rc = backend_check_referrals( be, conn, op, &e->e_name, &e->e_nname ); + if ( rc != LDAP_SUCCESS ) { + goto done; } /* @@ -115,72 +239,228 @@ do_add( conn, op ) * 2) this backend is master for what it holds; * 3) it's a replica and the dn supplied is the updatedn. */ - if ( be->be_add != NULL ) { + if ( be->be_add ) { /* do the update here */ - if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn, - op->o_dn ) == 0 ) { - if ( (be->be_lastmod == ON || be->be_lastmod == 0 && - global_lastmod == ON) && be->be_updatedn == NULL ) { - add_created_attrs( op, e ); + int repl_user = be_isupdate(be, &op->o_ndn ); +#ifndef SLAPD_MULTIMASTER + if ( !be->be_update_ndn.bv_len || repl_user ) +#endif + { + int update = be->be_update_ndn.bv_len; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + + rc = slap_mods_check( modlist, update, &text, + textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto done; + } + + if ( SLAP_LASTMOD(be) && !repl_user ) { + for( modtail = &modlist; + *modtail != NULL; + modtail = &(*modtail)->sml_next ) + { + assert( (*modtail)->sml_op == LDAP_MOD_ADD ); + assert( (*modtail)->sml_desc != NULL ); + } + rc = slap_mods_opattrs( op, modlist, modtail, &text, + textbuf, textlen ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto done; + } } + + rc = slap_mods2entry( modlist, &e, repl_user, &text, + textbuf, textlen ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto done; + } + if ( (*be->be_add)( be, conn, op, e ) == 0 ) { - replog( be, LDAP_REQ_ADD, e->e_dn, e, 0 ); +#ifdef SLAPD_MULTIMASTER + if ( !repl_user ) +#endif + { + replog( be, op, &e->e_name, &e->e_nname, e ); + } + be_entry_release_w( be, conn, op, e ); + e = NULL; } + +#ifndef SLAPD_MULTIMASTER } else { - entry_free( e ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + BerVarray defref = be->be_update_refs + ? be->be_update_refs : default_referral; + BerVarray ref = referral_rewrite( defref, + NULL, &e->e_name, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + ref ? ref : defref, NULL ); + + if ( ref ) ber_bvarray_free( ref ); +#endif } } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_add: conn %d no backend support\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ARGS, " do_add: no backend support\n", 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", NULL, NULL ); + } + +done: + if( modlist != NULL ) { + slap_mods_free( modlist ); + } + if( e != NULL ) { entry_free( e ); - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); } + + return rc; } -static void -add_created_attrs( Operation *op, Entry *e ) +static int slap_mods2entry( + Modifications *mods, + Entry **e, + int repl_user, + const char **text, + char *textbuf, size_t textlen ) { - char buf[20]; - struct berval bv; - struct berval *bvals[2]; - Attribute **a, **next; - Attribute *tmp; - struct tm *ltm; - - Debug( LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0 ); - - bvals[0] = &bv; - bvals[1] = NULL; - - /* remove any attempts by the user to add these attrs */ - for ( a = &e->e_attrs; *a != NULL; a = next ) { - if ( strcasecmp( (*a)->a_type, "createtimestamp" ) == 0 - || strcasecmp( (*a)->a_type, "creatorsname" ) == 0 ) { - tmp = *a; - *a = (*a)->a_next; - attr_free( tmp ); - next = a; - } else { - next = &(*a)->a_next; + Attribute **tail = &(*e)->e_attrs; + assert( *tail == NULL ); + + *text = textbuf; + + for( ; mods != NULL; mods = mods->sml_next ) { + Attribute *attr; + + assert( mods->sml_op == LDAP_MOD_ADD ); + assert( mods->sml_desc != NULL ); + + attr = attr_find( (*e)->e_attrs, mods->sml_desc ); + + if( attr != NULL ) { +#define SLURPD_FRIENDLY +#ifdef SLURPD_FRIENDLY + ber_len_t i,j; + + if( !repl_user ) { + snprintf( textbuf, textlen, + "attribute '%s' provided more than once", + mods->sml_desc->ad_cname.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + + for( i=0; attr->a_vals[i].bv_val; i++ ) { + /* count them */ + } + for( j=0; mods->sml_bvalues[j].bv_val; j++ ) { + /* count them */ + } + j++; /* NULL */ + + attr->a_vals = ch_realloc( attr->a_vals, + sizeof( struct berval ) * (i+j) ); + + /* should check for duplicates */ + + AC_MEMCPY( &attr->a_vals[i], mods->sml_bvalues, + sizeof( struct berval ) * j ); + + /* trim the mods array */ + ch_free( mods->sml_bvalues ); + mods->sml_bvalues = NULL; + + continue; +#else + snprintf( textbuf, textlen, + "attribute '%s' provided more than once", + mods->sml_desc->ad_cname.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; +#endif } - } - if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) { - bv.bv_val = "NULLDN"; - bv.bv_len = strlen( bv.bv_val ); - } else { - bv.bv_val = op->o_dn; - bv.bv_len = strlen( bv.bv_val ); - } - attr_merge( e, "creatorsname", bvals ); + if( mods->sml_bvalues[1].bv_val != NULL ) { + /* check for duplicates */ + int i, j; + MatchingRule *mr = mods->sml_desc->ad_type->sat_equality; + + /* check if the values we're adding already exist */ + if( mr == NULL || !mr->smr_match ) { + for ( i = 0; mods->sml_bvalues[i].bv_val != NULL; i++ ) { + /* test asserted values against themselves */ + for( j = 0; j < i; j++ ) { + int rc = ber_bvcmp( &mods->sml_bvalues[i], + &mods->sml_bvalues[j] ); + + if( rc == 0 ) { + /* value exists already */ + snprintf( textbuf, textlen, + "%s: value #%d provided more than once", + mods->sml_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + } + + } else { + for ( i = 0; mods->sml_bvalues[i].bv_val != NULL; i++ ) { + int rc, match; + const char *text = NULL; + struct berval asserted; + + rc = value_normalize( mods->sml_desc, + SLAP_MR_EQUALITY, + &mods->sml_bvalues[i], + &asserted, + &text ); + + if( rc != LDAP_SUCCESS ) return rc; - pthread_mutex_lock( ¤ttime_mutex ); - ltm = localtime( ¤ttime ); - strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); - pthread_mutex_unlock( ¤ttime_mutex ); + for ( j = 0; j < i; j++ ) { + int rc = value_match( &match, mods->sml_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &mods->sml_bvalues[j], &asserted, &text ); + + if( rc == LDAP_SUCCESS && match == 0 ) { + free( asserted.bv_val ); + snprintf( textbuf, textlen, + "%s: value #%d provided more than once", + mods->sml_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + + free( asserted.bv_val ); + } + } + } + + attr = ch_calloc( 1, sizeof(Attribute) ); + + /* move ad to attr structure */ + attr->a_desc = mods->sml_desc; + mods->sml_desc = NULL; + + /* move values to attr structure */ + /* should check for duplicates */ + attr->a_vals = mods->sml_bvalues; + mods->sml_bvalues = NULL; + + *tail = attr; + tail = &attr->a_next; + } - bv.bv_val = buf; - bv.bv_len = strlen( bv.bv_val ); - attr_merge( e, "createtimestamp", bvals ); + return LDAP_SUCCESS; } diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index 7686d94767df285a23ad73347ff036fc5f7e0853..39c2594189c7ab44906db93556891c6942e66392 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -1,86 +1,106 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* attr.c - routines for dealing with attributes */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <ctype.h> + +#ifdef HAVE_FCNTL_H #include <fcntl.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/param.h> -#include <sys/stat.h> -#include "portable.h" +#endif + +#include <ac/ctype.h> +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap_pvt.h" #include "slap.h" -extern char **charray_dup(); -extern char *ch_malloc(); -extern int errno; +#ifdef LDAP_DEBUG +static void at_index_print( void ) +{ +} +#endif void attr_free( Attribute *a ) { - free( a->a_type ); - ber_bvecfree( a->a_vals ); + ber_bvarray_free( a->a_vals ); free( a ); } -/* - * attr_normalize - normalize an attribute name (make it all lowercase) - */ - -char * -attr_normalize( char *s ) +void +attrs_free( Attribute *a ) { - char *save; + Attribute *next; - for ( save = s; *s; s++ ) { - *s = TOLOWER( *s ); + for( ; a != NULL ; a = next ) { + next = a->a_next; + attr_free( a ); } - - return( save ); } -/* - * attr_merge_fast - merge the given type and value with the list of - * attributes in attrs. called from str2entry(), where we can make some - * assumptions to make things faster. - * returns 0 everything went ok - * -1 trouble - */ - -int -attr_merge_fast( - Entry *e, - char *type, - struct berval **vals, - int nvals, - int naddvals, - int *maxvals, - Attribute ***a -) +Attribute *attr_dup( Attribute *a ) { - int i; + Attribute *tmp; - if ( *a == NULL ) { - for ( *a = &e->e_attrs; **a != NULL; *a = &(**a)->a_next ) { - if ( strcasecmp( (**a)->a_type, type ) == 0 ) { - break; - } + if( a == NULL) return NULL; + + tmp = ch_malloc( sizeof(Attribute) ); + + if( a->a_vals != NULL ) { + int i; + + for( i=0; a->a_vals[i].bv_val != NULL; i++ ) { + /* EMPTY */ ; } + + tmp->a_vals = ch_malloc((i+1) * sizeof(struct berval)); + + for( i=0; a->a_vals[i].bv_val != NULL; i++ ) { + ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] ); + if( tmp->a_vals[i].bv_val == NULL ) break; + } + + tmp->a_vals[i].bv_val = NULL; + + } else { + tmp->a_vals = NULL; } - if ( **a == NULL ) { - **a = (Attribute *) ch_malloc( sizeof(Attribute) ); - (**a)->a_type = attr_normalize( strdup( type ) ); - (**a)->a_vals = NULL; - (**a)->a_syntax = attr_syntax( type ); - (**a)->a_next = NULL; + tmp->a_desc = a->a_desc; + tmp->a_next = NULL; + tmp->a_flags = 0; + + return tmp; +} + +Attribute *attrs_dup( Attribute *a ) +{ + Attribute *tmp, **next; + + if( a == NULL ) return NULL; + + tmp = NULL; + next = &tmp; + + for( ; a != NULL ; a = a->a_next ) { + *next = attr_dup( a ); + next = &((*next)->a_next); } + *next = NULL; - return( value_add_fast( &(**a)->a_vals, vals, nvals, naddvals, - maxvals ) ); + return tmp; } + + /* * attr_merge - merge the given type and value with the list of * attributes in attrs. @@ -90,43 +110,42 @@ attr_merge_fast( int attr_merge( - Entry *e, - char *type, - struct berval **vals -) + Entry *e, + AttributeDescription *desc, + BerVarray vals ) { - int i; Attribute **a; for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) { - if ( strcasecmp( (*a)->a_type, type ) == 0 ) { + if ( ad_cmp( (*a)->a_desc, desc ) == 0 ) { break; } } if ( *a == NULL ) { *a = (Attribute *) ch_malloc( sizeof(Attribute) ); - (*a)->a_type = attr_normalize( strdup( type ) ); + (*a)->a_desc = desc; (*a)->a_vals = NULL; - (*a)->a_syntax = attr_syntax( type ); (*a)->a_next = NULL; + (*a)->a_flags = 0; } return( value_add( &(*a)->a_vals, vals ) ); } /* - * attr_find - find and return attribute type in list a + * attrs_find - find attribute(s) by AttributeDescription + * returns next attribute which is subtype of provided description. */ Attribute * -attr_find( +attrs_find( Attribute *a, - char *type + AttributeDescription *desc ) { for ( ; a != NULL; a = a->a_next ) { - if ( strcasecmp( a->a_type, type ) == 0 ) { + if ( is_ad_subtype( a->a_desc, desc ) ) { return( a ); } } @@ -135,205 +154,49 @@ attr_find( } /* - * attr_delete - delete the attribute type in list pointed to by attrs - * return 0 deleted ok - * 1 not found in list a - * -1 something bad happened + * attr_find - find attribute by type */ -int -attr_delete( - Attribute **attrs, - char *type -) -{ - Attribute **a; - Attribute *save; - - for ( a = attrs; *a != NULL; a = &(*a)->a_next ) { - if ( strcasecmp( (*a)->a_type, type ) == 0 ) { - break; - } - } - - if ( *a == NULL ) { - return( 1 ); - } - - save = *a; - *a = (*a)->a_next; - attr_free( save ); - - return( 0 ); -} - -#define DEFAULT_SYNTAX SYNTAX_CIS - -struct asyntaxinfo { - char **asi_names; - int asi_syntax; -}; - -static Avlnode *attr_syntaxes = NULL; - -static int -attr_syntax_cmp( - struct asyntaxinfo *a1, - struct asyntaxinfo *a2 -) -{ - return( strcasecmp( a1->asi_names[0], a2->asi_names[0] ) ); -} - -static int -attr_syntax_name_cmp( - char *type, - struct asyntaxinfo *a -) -{ - return( strcasecmp( type, a->asi_names[0] ) ); -} - -static int -attr_syntax_names_cmp( - char *type, - struct asyntaxinfo *a +Attribute * +attr_find( + Attribute *a, + AttributeDescription *desc ) { - int i; - - for ( i = 0; a->asi_names[i] != NULL; i++ ) { - if ( strcasecmp( type, a->asi_names[i] ) == 0 ) { - return( 0 ); + for ( ; a != NULL; a = a->a_next ) { + if ( ad_cmp( a->a_desc, desc ) == 0 ) { + return( a ); } } - return( 1 ); -} -static int -attr_syntax_dup( - struct asyntaxinfo *a1, - struct asyntaxinfo *a2 -) -{ - if ( a1->asi_syntax != a2->asi_syntax ) { - return( -1 ); - } - - return( 1 ); + return( NULL ); } /* - * attr_syntax - return the syntax of attribute type + * attr_delete - delete the attribute type in list pointed to by attrs + * return 0 deleted ok + * 1 not found in list a + * -1 something bad happened */ int -attr_syntax( char *type ) -{ - struct asyntaxinfo *asi = NULL; - - if ( (asi = (struct asyntaxinfo *) avl_find( attr_syntaxes, type, - attr_syntax_name_cmp )) != NULL || (asi = (struct asyntaxinfo *) - avl_find_lin( attr_syntaxes, type, attr_syntax_names_cmp )) - != NULL ) - { - return( asi->asi_syntax ); - } - - return( DEFAULT_SYNTAX ); -} - -/* - * attr_syntax_config - process an attribute syntax config line - */ - -void -attr_syntax_config( - char *fname, - int lineno, - int argc, - char **argv +attr_delete( + Attribute **attrs, + AttributeDescription *desc ) { - char *save; - struct asyntaxinfo *a; - int i, lasti; - - if ( argc < 2 ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: missing name in \"attribute <name>+ <syntax>\" (ignored)\n", - fname, lineno, 0 ); - return; - } - - a = (struct asyntaxinfo *) ch_calloc( 1, sizeof(struct asyntaxinfo) ); - - lasti = argc - 1; - if ( strcasecmp( argv[lasti], "caseignorestring" ) == 0 || - strcasecmp( argv[lasti], "cis" ) == 0 ) { - a->asi_syntax = SYNTAX_CIS; - } else if ( strcasecmp( argv[lasti], "telephone" ) == 0 || - strcasecmp( argv[lasti], "tel" ) == 0 ) { - a->asi_syntax = (SYNTAX_CIS | SYNTAX_TEL); - } else if ( strcasecmp( argv[lasti], "dn" ) == 0 ) { - a->asi_syntax = (SYNTAX_CIS | SYNTAX_DN); - } else if ( strcasecmp( argv[lasti], "caseexactstring" ) == 0 || - strcasecmp( argv[lasti], "ces" ) == 0 ) { - a->asi_syntax = SYNTAX_CES; - } else if ( strcasecmp( argv[lasti], "binary" ) == 0 || - strcasecmp( argv[lasti], "bin" ) == 0 ) { - a->asi_syntax = SYNTAX_BIN; - } else { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: unknown syntax \"%s\" in attribute line (ignored)\n", - fname, lineno, 0 ); - Debug( LDAP_DEBUG_ANY, - "possible syntaxes are \"cis\", \"ces\", \"tel\", \"dn\", or \"bin\"\n", - 0, 0, 0 ); - free( (char *) a ); - return; - } - save = argv[lasti]; - argv[lasti] = NULL; - a->asi_names = charray_dup( argv ); - argv[lasti] = save; - - switch ( avl_insert( &attr_syntaxes, a, attr_syntax_cmp, - attr_syntax_dup ) ) { - case -1: /* duplicate - different syntaxes */ - Debug( LDAP_DEBUG_ARGS, "%s: line %d: duplicate attribute\n", - fname, lineno, 0 ); - /* FALL */ - - case 1: /* duplicate - same syntaxes */ - charray_free( a->asi_names ); - free( (char *) a ); - break; - - default: /* inserted */ - break; - } -} - -#ifdef LDAP_DEBUG + Attribute **a; -static -attr_syntax_printnode( struct asyntaxinfo *a ) -{ - int i; + for ( a = attrs; *a != NULL; a = &(*a)->a_next ) { + if ( ad_cmp( (*a)->a_desc, desc ) == 0 ) { + Attribute *save = *a; + *a = (*a)->a_next; + attr_free( save ); - printf( "syntax: 0x%x\n", a->asi_syntax ); - for ( i = 0; a->asi_names[i] != NULL; i++ ) { - printf( " name: %s\n", a->asi_names[i] ); + return LDAP_SUCCESS; + } } - return( 0 ); -} -static -attr_syntax_print() -{ - (void) avl_apply( attr_syntaxes, attr_syntax_printnode, 0, -1, - AVL_INORDER ); + return LDAP_NO_SUCH_ATTRIBUTE; } -#endif diff --git a/servers/slapd/ava.c b/servers/slapd/ava.c index ef0487c7aafcc0c0f05b0f252c7f2a27ae7b4294..c521993c54bf3b9c66c667357e96ec052b9b444d 100644 --- a/servers/slapd/ava.c +++ b/servers/slapd/ava.c @@ -1,38 +1,78 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* ava.c - routines for dealing with attribute value assertions */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" + +void +ava_free( + AttributeAssertion *ava, + int freeit +) +{ + free( ava->aa_value.bv_val ); + if ( freeit ) { + ch_free( (char *) ava ); + } +} + int get_ava( BerElement *ber, - Ava *ava + AttributeAssertion **ava, + unsigned usage, + const char **text ) { - if ( ber_scanf( ber, "{ao}", &ava->ava_type, &ava->ava_value ) - == LBER_ERROR ) { + int rc; + ber_tag_t rtag; + struct berval type, value; + AttributeAssertion *aa; + + rtag = ber_scanf( ber, "{mm}", &type, &value ); + + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "get_ava: ber_scanf failure\n" )); +#else Debug( LDAP_DEBUG_ANY, " get_ava ber_scanf\n", 0, 0, 0 ); - return( LDAP_PROTOCOL_ERROR ); +#endif + *text = "Error decoding attribute value assertion"; + return SLAPD_DISCONNECT; } - attr_normalize( ava->ava_type ); - value_normalize( ava->ava_value.bv_val, attr_syntax( ava->ava_type ) ); - return( 0 ); -} + aa = ch_malloc( sizeof( AttributeAssertion ) ); + aa->aa_desc = NULL; + aa->aa_value.bv_val = NULL; -void -ava_free( - Ava *ava, - int freeit -) -{ - free( (char *) ava->ava_type ); - free( (char *) ava->ava_value.bv_val ); - if ( freeit ) { - free( (char *) ava ); + rc = slap_bv2ad( &type, &aa->aa_desc, text ); + + if( rc != LDAP_SUCCESS ) { + ch_free( aa ); + return rc; } -} + rc = value_validate_normalize( aa->aa_desc, usage, + &value, &aa->aa_value, text ); + + if( rc != LDAP_SUCCESS ) { + ch_free( aa ); + return rc; + } + + *ava = aa; + + return LDAP_SUCCESS; +} diff --git a/servers/slapd/back-bdb/Makefile.in b/servers/slapd/back-bdb/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..e2208232dae7a601a0f9ebe8cdf56dbb145935e9 --- /dev/null +++ b/servers/slapd/back-bdb/Makefile.in @@ -0,0 +1,36 @@ +# $OpenLDAP$ + +SRCS = init.c tools.c config.c \ + add.c bind.c compare.c delete.c modify.c modrdn.c search.c \ + extended.c passwd.c referral.c attribute.c group.c operational.c \ + attr.c index.c key.c dbcache.c filterindex.c \ + dn2entry.c dn2id.c error.c id2entry.c idl.c nextid.c cache.c +OBJS = init.lo tools.lo config.lo \ + add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \ + extended.lo passwd.lo referral.lo attribute.lo group.lo operational.lo \ + attr.lo index.lo key.lo dbcache.lo filterindex.lo \ + dn2entry.lo dn2id.lo error.lo id2entry.lo idl.lo nextid.lo cache.lo + +LDAP_INCDIR= ../../../include +LDAP_LIBDIR= ../../../libraries + +BUILD_OPT = "--enable-bdb" +BUILD_MOD = @BUILD_BDB@ +BUILD_MOD_DYNAMIC = @BUILD_BDB_DYNAMIC@ + +mod_DEFS = -DSLAPD_IMPORT +MOD_DEFS = $(@BUILD_BDB@_DEFS) + +shared_LDAP_LIBS = $(LDAP_LIBPATH) -lldap_r -llber +NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS) + +LIBBASE = back_bdb + +XINCPATH = -I.. -I$(srcdir)/.. +XDEFS = $(MODULES_CPPFLAGS) + +all-local-lib: ../.backend + +../.backend: lib$(LIBBASE).a + @touch $@ + diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c new file mode 100644 index 0000000000000000000000000000000000000000..d5e949b3d233eee3e65adf7467ec4695a6e7f1ce --- /dev/null +++ b/servers/slapd/back-bdb/add.c @@ -0,0 +1,490 @@ +/* add.c - ldap BerkeleyDB back-end add routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_add( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct berval pdn; + Entry *p = NULL; + int rc; + const char *text; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + AttributeDescription *children = slap_schema.si_ad_children; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; +#ifdef BDB_SUBENTRIES + int subentry; +#endif +#if 0 + u_int32_t lockid; + DB_LOCK lock; +#endif + +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ARGS, "==> bdb_add: %s\n", e->e_dn )); +#else + Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0); +#endif + + /* check entry's schema */ + rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: entry failed schema check: %s (%d)\n", text, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_add: entry failed schema check: %s (%d)\n", + text, rc, 0 ); +#endif + goto return_results; + } + +#ifdef BDB_SUBENTRIES + subentry = is_entry_subentry( e ); +#endif + + /* + * acquire an ID outside of the operation transaction + * to avoid serializing adds. + */ + rc = bdb_next_id( be, NULL, &e->e_id ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: next_id failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_add: next_id failed (%d)\n", + rc, 0, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( 0 ) { +retry: /* transaction retry */ + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + bdb->bi_db_opflags ); + text = NULL; + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: txn_begin failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_add: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } +#if 0 + lockid = TXN_ID( ltid ); +#endif + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* + * Get the parent dn and see if the corresponding entry exists. + * If the parent does not exist, only allow the "root" user to + * add the entry. + */ + if ( be_issuffix( be, &e->e_nname ) ) { + pdn = slap_empty_bv; + } else { + dnParent( &e->e_nname, &pdn ); + } + + if( pdn.bv_len != 0 ) { + Entry *matched = NULL; + +#if 0 + if ( ltid ) { + DBT obj; + obj.data = pdn.bv_val-1; + obj.size = pdn.bv_len+1; + rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj, + DB_LOCK_WRITE, &lock); + } +#endif + + /* get parent */ + rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( p == NULL ) { + char *matched_dn = NULL; + BerVarray refs; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_cache_return_entry_r(&bdb->bi_cache, matched); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, &e->e_name, LDAP_SCOPE_DEFAULT ); + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent does not exist\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + ch_free( matched_dn ); + + goto done; + } + + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + /* free parent and reader lock */ + bdb_cache_return_entry_r( &bdb->bi_cache, p ); + p = NULL; + goto retry; + } + + if ( ! rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n", + 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + text = "no write access to parent"; + goto return_results;; + } + +#ifdef BDB_SUBENTRIES + if ( is_entry_subentry( p ) ) { + /* parent is a subentry, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is subentry\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n", + 0, 0, 0 ); +#endif + rc = LDAP_OBJECT_CLASS_VIOLATION; + text = "parent is a subentry"; + goto return_results;; + } +#endif +#ifdef BDB_ALIASES + if ( is_entry_alias( p ) ) { + /* parent is an alias, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is alias\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n", + 0, 0, 0 ); +#endif + rc = LDAP_ALIAS_PROBLEM; + text = "parent is an alias"; + goto return_results;; + } +#endif + + if ( is_entry_referral( p ) ) { + /* parent is a referral, don't allow add */ + char *matched_dn = p->e_dn; + BerVarray refs = get_entry_referrals( be, conn, op, p ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + bdb_cache_return_entry_r( &bdb->bi_cache, p ); + p = NULL; + goto done; + } + +#ifdef BDB_SUBENTRIES + if ( subentry ) { + /* FIXME: */ + /* parent must be an administrative point of the required kind */ + } +#endif + + /* free parent and reader lock */ + bdb_cache_return_entry_r( &bdb->bi_cache, p ); + p = NULL; + + } else { + /* + * no parent! + * must be adding entry at suffix or with parent "" + */ + if ( !be_isroot( be, &op->o_ndn )) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) + || be_isupdate( be, &op->o_ndn ) ) { + p = (Entry *)&slap_entry_root; + + /* check parent for "children" acl */ + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + p = NULL; + + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + if ( ! rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_add: no write access to parent\n", + 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + text = "no write access to parent"; + goto return_results;; + } + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: %s denied\n", pdn.bv_len == 0 ? "suffix" : "entry at root" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n", + pdn.bv_len == 0 ? "suffix" : "entry at root", + 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + } + +#ifdef BDB_SUBENTRIES + if( subentry ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no parent, cannot add subentry\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_add: no parent, cannot add subentry\n", + 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + text = "no parent, cannot add subentry"; + goto return_results;; + } +#endif +#if 0 + if ( ltid ) { + DBT obj; + obj.data = ","; + obj.size = 1; + rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj, + DB_LOCK_WRITE, &lock); + } +#endif + } + + /* dn2id index */ + rc = bdb_dn2id_add( be, ltid, &pdn, e ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: dn2id_add failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case DB_KEYEXIST: + rc = LDAP_ALREADY_EXISTS; + break; + default: + rc = LDAP_OTHER; + } + goto return_results; + } + + /* id2entry index */ + rc = bdb_id2entry_add( be, ltid, e ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: id2entry_add failed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n", + 0, 0, 0 ); +#endif + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + } + text = "entry store failed"; + goto return_results; + } + + /* attribute indexes */ + rc = bdb_index_entry_add( be, ltid, e, e->e_attrs ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: index_entry_add failed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n", + 0, 0, 0 ); +#endif + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + } + text = "index generation failed"; + goto return_results; + } + + if( op->o_noop ) { + if (( rc=TXN_ABORT( ltid )) != 0 ) { + text = "txn_abort (no-op) failed"; + } else { + rc = LDAP_SUCCESS; + } + + } else { + char gid[DB_XIDDATASIZE]; + + snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx", + bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid ); + + if (( rc=TXN_PREPARE( ltid, gid )) != 0 ) { + text = "txn_prepare failed"; + + } else { + if ( bdb_cache_add_entry_rw(&bdb->bi_cache, + e, CACHE_WRITE_LOCK) != 0 ) + { + if(( rc=TXN_ABORT( ltid )) != 0 ) { + text = "cache add & txn_abort failed"; + } else { + rc = LDAP_OTHER; + text = "cache add failed"; + } + } else { + if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) { + text = "txn_commit failed"; + } else { + rc = LDAP_SUCCESS; + } + } + } + } + + ltid = NULL; + op->o_private = NULL; + + if (rc == LDAP_SUCCESS) { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_RESULTS, "bdb_add: added%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn )); +#else + Debug(LDAP_DEBUG_TRACE, "bdb_add: added%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn ); +#endif + text = NULL; + bdb_cache_entry_commit( e ); + } + else { +#ifdef NEW_LOGGING + LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: %s : %s (%d)\n", text, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n", + text, db_strerror(rc), rc ); +#endif + rc = LDAP_OTHER; + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + ldap_pvt_thread_yield(); + TXN_CHECKPOINT( bdb->bi_dbenv, + bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); + } + +done: + + if( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + return rc; +} diff --git a/servers/slapd/back-bdb/attr.c b/servers/slapd/back-bdb/attr.c new file mode 100644 index 0000000000000000000000000000000000000000..c05cfc393390b46624cc01f5b3531c55d89ef096 --- /dev/null +++ b/servers/slapd/back-bdb/attr.c @@ -0,0 +1,219 @@ +/* attr.c - backend routines for dealing with attributes */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-bdb.h" + +/* for the cache of attribute information (which are indexed, etc.) */ +typedef struct bdb_attrinfo { + AttributeDescription *ai_desc; /* attribute description cn;lang-en */ + slap_mask_t ai_indexmask; /* how the attr is indexed */ +} AttrInfo; + +static int +ainfo_type_cmp( + AttributeDescription *desc, + AttrInfo *a +) +{ + return desc - a->ai_desc; +} + +static int +ainfo_cmp( + AttrInfo *a, + AttrInfo *b +) +{ + return a->ai_desc - b->ai_desc; +} + +void +bdb_attr_mask( + struct bdb_info *bdb, + AttributeDescription *desc, + slap_mask_t *indexmask ) +{ + AttrInfo *a; + + a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, + (AVL_CMP) ainfo_type_cmp ); + + *indexmask = a != NULL ? a->ai_indexmask : 0; +} + +int +bdb_attr_index_config( + struct bdb_info *bdb, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + int rc; + int i; + slap_mask_t mask; + char **attrs; + char **indexes = NULL; + + attrs = str2charray( argv[0], "," ); + + if( attrs == NULL ) { + fprintf( stderr, "%s: line %d: " + "no attributes specified: %s\n", + fname, lineno, argv[0] ); + return LDAP_PARAM_ERROR; + } + + if ( argc > 1 ) { + indexes = str2charray( argv[1], "," ); + + if( indexes == NULL ) { + fprintf( stderr, "%s: line %d: " + "no indexes specified: %s\n", + fname, lineno, argv[1] ); + return LDAP_PARAM_ERROR; + } + } + + if( indexes == NULL ) { + mask = bdb->bi_defaultmask; + + } else { + mask = 0; + + for ( i = 0; indexes[i] != NULL; i++ ) { + slap_mask_t index; + rc = slap_str2index( indexes[i], &index ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: " + "index type \"%s\" undefined\n", + fname, lineno, indexes[i] ); + return LDAP_PARAM_ERROR; + } + + mask |= index; + } + } + + if( !mask ) { + fprintf( stderr, "%s: line %d: " + "no indexes selected\n", + fname, lineno ); + return LDAP_PARAM_ERROR; + } + + for ( i = 0; attrs[i] != NULL; i++ ) { + AttrInfo *a; + AttributeDescription *ad; + const char *text; + + if( strcasecmp( attrs[i], "default" ) == 0 ) { + bdb->bi_defaultmask = mask; + continue; + } + + a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) ); + + ad = NULL; + rc = slap_str2ad( attrs[i], &ad, &text ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: " + "index attribute \"%s\" undefined\n", + fname, lineno, attrs[i] ); + return rc; + } + + if( slap_ad_is_binary( ad ) ) { + fprintf( stderr, "%s: line %d: " + "index of attribute \"%s\" disallowed\n", + fname, lineno, attrs[i] ); + return LDAP_UNWILLING_TO_PERFORM; + } + + if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !( + ( ad->ad_type->sat_approx + && ad->ad_type->sat_approx->smr_indexer + && ad->ad_type->sat_approx->smr_filter ) + && ( ad->ad_type->sat_equality + && ad->ad_type->sat_equality->smr_indexer + && ad->ad_type->sat_equality->smr_filter ) ) ) + { + fprintf( stderr, "%s: line %d: " + "approx index of attribute \"%s\" disallowed\n", + fname, lineno, attrs[i] ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !( + ad->ad_type->sat_equality + && ad->ad_type->sat_equality->smr_indexer + && ad->ad_type->sat_equality->smr_filter ) ) + { + fprintf( stderr, "%s: line %d: " + "equality index of attribute \"%s\" disallowed\n", + fname, lineno, attrs[i] ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !( + ad->ad_type->sat_substr + && ad->ad_type->sat_substr->smr_indexer + && ad->ad_type->sat_substr->smr_filter ) ) + { + fprintf( stderr, "%s: line %d: " + "substr index of attribute \"%s\" disallowed\n", + fname, lineno, attrs[i] ); + return LDAP_INAPPROPRIATE_MATCHING; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "attr_index_config: index %s 0x%04lx\n", + ad->ad_cname.bv_val, mask )); +#else + Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n", + ad->ad_cname.bv_val, mask, 0 ); +#endif + + + a->ai_desc = ad; + a->ai_indexmask = mask; + + rc = avl_insert( &bdb->bi_attrs, (caddr_t) a, + (AVL_CMP) ainfo_cmp, (AVL_DUP) avl_dup_error ); + + if( rc ) { + fprintf( stderr, "%s: line %d: duplicate index definition " + "for attr \"%s\" (ignored)\n", + fname, lineno, attrs[i] ); + + return LDAP_PARAM_ERROR; + } + } + + charray_free( attrs ); + if ( indexes != NULL ) charray_free( indexes ); + + return LDAP_SUCCESS; +} + +void +bdb_attr_index_destroy( Avlnode *tree ) +{ + avl_free( tree, free ); +} + diff --git a/servers/slapd/back-bdb/attribute.c b/servers/slapd/back-bdb/attribute.c new file mode 100644 index 0000000000000000000000000000000000000000..f0bfd306f23c0c6221f912922b22ab509557a019 --- /dev/null +++ b/servers/slapd/back-bdb/attribute.c @@ -0,0 +1,220 @@ +/* attribute.c - bdb backend acl attribute routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-bdb.h" +#include "proto-bdb.h" + +/* return LDAP_SUCCESS IFF we can retrieve the attributes + * of entry with e_ndn + */ +int +bdb_attribute( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *entry_ndn, + AttributeDescription *entry_at, + BerVarray *vals ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct bdb_op_info *boi = (struct bdb_op_info *) op->o_private; + DB_TXN *txn = NULL; + Entry *e; + int i, j = 0, rc; + Attribute *attr; + BerVarray v; + const char *entry_at_name = entry_at->ad_cname.bv_val; + AccessControlState acl_state = ACL_STATE_INIT; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "bdb_attribute: gr dn: \"%s\"\n", entry_ndn->bv_val )); + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "bdb_attribute: at: \"%s\"\n", entry_at_name)); + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "bdb_attribute: tr dn: \"%s\"\n", + target ? target->e_ndn : "" )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_attribute: gr dn: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ARGS, + "=> bdb_attribute: at: \"%s\"\n", + entry_at_name, 0, 0 ); + + Debug( LDAP_DEBUG_ARGS, + "=> bdb_attribute: tr dn: \"%s\"\n", + target ? target->e_ndn : "", 0, 0 ); +#endif + + if( boi != NULL && be == boi->boi_bdb ) { + txn = boi->boi_txn; + } + + if (target != NULL && dn_match(&target->e_nname, entry_ndn)) { + /* we already have a LOCKED copy of the entry */ + e = target; +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_attribute: target is LOCKED (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_attribute: target is entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + + + } else { + /* can we find entry */ + rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0 ); + switch( rc ) { + case DB_NOTFOUND: + case 0: + break; + default: + if( txn != NULL ) { + boi->boi_err = rc; + } + return LDAP_OTHER; + } + if (e == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_attribute: cannot find entry (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> bdb_attribute: cannot find entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + return LDAP_NO_SUCH_OBJECT; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_attribute: found entry (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> bdb_attribute: found entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + } + +#ifdef BDB_ALIASES + /* find attribute values */ + if( is_entry_alias( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_attribute: entry (%s) is an alias\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_attribute: entry is an alias\n", 0, 0, 0 ); +#endif + rc = LDAP_ALIAS_PROBLEM; + goto return_results; + } +#endif + + if( is_entry_referral( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_attribute: entry (%s) is a referral.\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_attribute: entry is a referral\n", 0, 0, 0 ); +#endif + rc = LDAP_REFERRAL; + goto return_results; + } + + if (conn != NULL && op != NULL + && access_allowed( be, conn, op, e, slap_schema.si_ad_entry, + NULL, ACL_READ, &acl_state ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + if ((attr = attr_find(e->e_attrs, entry_at)) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_attribute: failed to find %s.\n", entry_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_attribute: failed to find %s\n", + entry_at_name, 0, 0 ); +#endif + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_results; + } + + if (conn != NULL && op != NULL + && access_allowed( be, conn, op, e, entry_at, NULL, ACL_READ, + &acl_state ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + for ( i = 0; attr->a_vals[i].bv_val != NULL; i++ ) { + /* count them */ + } + + v = (BerVarray) ch_malloc( sizeof(struct berval) * (i+1) ); + + for ( i=0, j=0; attr->a_vals[i].bv_val != NULL; i++ ) { + if( conn != NULL + && op != NULL + && access_allowed(be, conn, op, e, entry_at, + &attr->a_vals[i], ACL_READ, &acl_state ) == 0) + { + continue; + } + ber_dupbv( &v[j], &attr->a_vals[i] ); + + if( v[j].bv_val != NULL ) j++; + } + + if( j == 0 ) { + ch_free( v ); + *vals = NULL; + rc = LDAP_INSUFFICIENT_ACCESS; + } else { + v[j].bv_val = NULL; + v[j].bv_len = 0; + *vals = v; + rc = LDAP_SUCCESS; + } + +return_results: + if( target != e ) { + /* free entry */ + bdb_cache_return_entry_r(&bdb->bi_cache, e); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "bdb_attribute: rc=%d nvals=%d.\n", + rc, j )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_attribute: rc=%d nvals=%d\n", + rc, j, 0 ); +#endif + return(rc); +} diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h new file mode 100644 index 0000000000000000000000000000000000000000..832a6bb95958ad226542cf967540dd079b490f17 --- /dev/null +++ b/servers/slapd/back-bdb/back-bdb.h @@ -0,0 +1,168 @@ +/* back-bdb.h - bdb back-end header file */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#ifndef _BACK_BDB_H_ +#define _BACK_BDB_H_ + +#include <portable.h> +#include <db.h> + +#include "slap.h" + +LDAP_BEGIN_DECL + +#define BDB_IDL_MULTI 1 +/* #define BDB_HIER 1 */ + +#define DN_BASE_PREFIX SLAP_INDEX_EQUALITY_PREFIX +#define DN_ONE_PREFIX '%' +#define DN_SUBTREE_PREFIX '@' + +#define DBTzero(t) (memset((t), 0, sizeof(DBT))) +#define DBT2bv(t,bv) ((bv)->bv_val = (t)->data, \ + (bv)->bv_len = (t)->size) +#define bv2DBT(bv,t) ((t)->data = (bv)->bv_val, \ + (t)->size = (bv)->bv_len ) + +#define BDB_TXN_RETRIES 16 + +#ifdef BDB_SUBDIRS +#define BDB_TMP_SUBDIR LDAP_DIRSEP "tmp" +#define BDB_LG_SUBDIR LDAP_DIRSEP "log" +#define BDB_DATA_SUBDIR LDAP_DIRSEP "data" +#endif + +#define BDB_SUFFIX ".bdb" +#define BDB_ID2ENTRY 0 +#ifdef BDB_HIER +#define BDB_ID2PARENT 1 +#else +#define BDB_DN2ID 1 +#endif +#define BDB_NDB 2 + +/* The bdb on-disk entry format is pretty space-inefficient. Average + * sized user entries are 3-4K each. You need at least two entries to + * fit into a single database page, more is better. 64K is BDB's + * upper bound. The same issues arise with IDLs in the index databases, + * but it's nearly impossible to avoid overflows there. + * + * When using BDB_IDL_MULTI, the IDL size is no longer an issue. Smaller + * pages are better for concurrency. + */ +#ifndef BDB_ID2ENTRY_PAGESIZE +#define BDB_ID2ENTRY_PAGESIZE 16384 +#endif + +#ifndef BDB_PAGESIZE +#ifdef BDB_IDL_MULTI +#define BDB_PAGESIZE 4096 /* BDB's original default */ +#else +#define BDB_PAGESIZE 16384 +#endif +#endif + +#define DEFAULT_CACHE_SIZE 1000 + +/* for the in-core cache of entries */ +typedef struct bdb_cache { + int c_maxsize; + int c_cursize; + Avlnode *c_dntree; + Avlnode *c_idtree; + Entry *c_lruhead; /* lru - add accessed entries here */ + Entry *c_lrutail; /* lru - rem lru entries from here */ + ldap_pvt_thread_rdwr_t c_rwlock; + ldap_pvt_thread_mutex_t lru_mutex; +} Cache; + +#define CACHE_READ_LOCK 0 +#define CACHE_WRITE_LOCK 1 + +#define BDB_INDICES 128 + +struct bdb_db_info { + char *bdi_name; + DB *bdi_db; +}; + +struct bdb_info { + DB_ENV *bi_dbenv; + + /* DB_ENV parameters */ + /* The DB_ENV can be tuned via DB_CONFIG */ + char *bi_dbenv_home; + u_int32_t bi_dbenv_xflags; /* extra flags */ + int bi_dbenv_mode; + + int bi_ndatabases; + struct bdb_db_info **bi_databases; + ldap_pvt_thread_mutex_t bi_database_mutex; + int bi_db_opflags; /* db-specific flags */ + + slap_mask_t bi_defaultmask; + Cache bi_cache; + Avlnode *bi_attrs; +#ifdef BDB_HIER + Avlnode *bi_tree; + ldap_pvt_thread_rdwr_t bi_tree_rdwr; + void *bi_troot; + int bi_nrdns; +#endif + + int bi_txn_cp; + u_int32_t bi_txn_cp_min; + u_int32_t bi_txn_cp_kbyte; + +#ifndef NO_THREADS + int bi_lock_detect; + int bi_lock_detect_seconds; + ldap_pvt_thread_t bi_lock_detect_tid; +#endif + + ID bi_lastid; + ldap_pvt_thread_mutex_t bi_lastid_mutex; +}; + +#define bi_id2entry bi_databases[BDB_ID2ENTRY] +#ifdef BDB_HIER +#define bi_id2parent bi_databases[BDB_ID2PARENT] +#else +#define bi_dn2id bi_databases[BDB_DN2ID] +#endif + +struct bdb_op_info { + BackendDB* boi_bdb; + DB_TXN* boi_txn; + int boi_err; +}; + +#if DB_VERSION_MAJOR < 4 +#define LOCK_DETECT(env,f,t,a) lock_detect(env, f, t, a) +#define LOCK_GET(env,i,f,o,m,l) lock_get(env, i, f, o, m, l) +#define TXN_CHECKPOINT(env,k,m,f) txn_checkpoint(env, k, m, f) +#define TXN_BEGIN(env,p,t,f) txn_begin((env), p, t, f) +#define TXN_PREPARE(txn,gid) txn_prepare((txn), (gid)) +#define TXN_COMMIT(txn,f) txn_commit((txn), (f)) +#define TXN_ABORT(txn) txn_abort((txn)) +#define TXN_ID(txn) txn_id(txn) +#else +#define LOCK_DETECT(env,f,t,a) (env)->lock_detect(env, f, t, a) +#define LOCK_GET(env,i,f,o,m,l) (env)->lock_get(env, i, f, o, m, l) +#define TXN_CHECKPOINT(env,k,m,f) (env)->txn_checkpoint(env, k, m, f) +#define TXN_BEGIN(env,p,t,f) (env)->txn_begin((env), p, t, f) +#define TXN_PREPARE(txn,g) (txn)->prepare((txn), (g)) +#define TXN_COMMIT(txn,f) (txn)->commit((txn), (f)) +#define TXN_ABORT(txn) (txn)->abort((txn)) +#define TXN_ID(txn) (txn)->id(txn) +#endif + +LDAP_END_DECL + +#include "proto-bdb.h" + +#endif /* _BACK_BDB_H_ */ diff --git a/servers/slapd/back-bdb/backbdb.dsp b/servers/slapd/back-bdb/backbdb.dsp new file mode 100644 index 0000000000000000000000000000000000000000..9c465633690d56e66c5285b9c363e61dd5bfb71b --- /dev/null +++ b/servers/slapd/back-bdb/backbdb.dsp @@ -0,0 +1,257 @@ +# Microsoft Developer Studio Project File - Name="backbdb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=backbdb - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "backbdb.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "backbdb.mak" CFG="backbdb - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "backbdb - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "backbdb - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "backbdb - Win32 Single Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "backbdb - Win32 Single Release" (based on\ + "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe + +!IF "$(CFG)" == "backbdb - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\Release" +# PROP Intermediate_Dir "..\..\..\Release\backbdb" +# PROP Target_Dir "" +RSC=rc.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "backbdb - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\Debug" +# PROP Intermediate_Dir "..\..\..\Debug\backbdb" +# PROP Target_Dir "" +RSC=rc.exe +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "backbdb - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "backbdb" +# PROP BASE Intermediate_Dir "backbdb" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\SDebug" +# PROP Intermediate_Dir "..\..\..\SDebug\backbdb" +# PROP Target_Dir "" +RSC=rc.exe +# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "backbdb - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "backldb0" +# PROP BASE Intermediate_Dir "backldb0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\SRelease" +# PROP Intermediate_Dir "..\..\..\SRelease\backbdb" +# PROP Target_Dir "" +RSC=rc.exe +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "backbdb - Win32 Release" +# Name "backbdb - Win32 Debug" +# Name "backbdb - Win32 Single Debug" +# Name "backbdb - Win32 Single Release" +# Begin Source File + +SOURCE=.\add.c +# End Source File +# Begin Source File + +SOURCE=.\attr.c +# End Source File +# Begin Source File + +SOURCE=.\attribute.c +# End Source File +# Begin Source File + +SOURCE=".\back-bdb.h" +# End Source File +# Begin Source File + +SOURCE=.\bind.c +# End Source File +# Begin Source File + +SOURCE=.\cache.c +# End Source File +# Begin Source File + +SOURCE=.\compare.c +# End Source File +# Begin Source File + +SOURCE=.\config.c +# End Source File +# Begin Source File + +SOURCE=.\dbcache.c +# End Source File +# Begin Source File + +SOURCE=.\delete.c +# End Source File +# Begin Source File + +SOURCE=.\dn2entry.c +# End Source File +# Begin Source File + +SOURCE=.\dn2id.c +# End Source File +# Begin Source File + +SOURCE=.\error.c +# End Source File +# Begin Source File + +SOURCE=.\extended.c +# End Source File +# Begin Source File + +SOURCE=.\external.h +# End Source File +# Begin Source File + +SOURCE=.\filterindex.c +# End Source File +# Begin Source File + +SOURCE=.\group.c +# End Source File +# Begin Source File + +SOURCE=.\id2entry.c +# End Source File +# Begin Source File + +SOURCE=.\idl.c +# End Source File +# Begin Source File + +SOURCE=.\idl.h +# End Source File +# Begin Source File + +SOURCE=.\index.c +# End Source File +# Begin Source File + +SOURCE=.\init.c +# End Source File +# Begin Source File + +SOURCE=.\key.c +# End Source File +# Begin Source File + +SOURCE=.\modify.c +# End Source File +# Begin Source File + +SOURCE=.\modrdn.c +# End Source File +# Begin Source File + +SOURCE=.\nextid.c +# End Source File +# Begin Source File + +SOURCE=.\operational.c +# End Source File +# Begin Source File + +SOURCE=.\passwd.c +# End Source File +# Begin Source File + +SOURCE=".\proto-bdb.h" +# End Source File +# Begin Source File + +SOURCE=.\referral.c +# End Source File +# Begin Source File + +SOURCE=.\search.c +# End Source File +# Begin Source File + +SOURCE=.\tools.c +# End Source File +# End Target +# End Project diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c new file mode 100644 index 0000000000000000000000000000000000000000..d05777336e1ddfb43288f1c838b971e48cbeccc4 --- /dev/null +++ b/servers/slapd/back-bdb/bind.c @@ -0,0 +1,278 @@ +/* bind.c - bdb backend bind routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/krb.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_bind( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int method, + struct berval *cred, + struct berval *edn +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + Entry *e; + Attribute *a; + int rc; + Entry *matched; +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + char krbname[MAX_K_NAME_SZ + 1]; + AttributeDescription *krbattr = slap_schema.si_ad_krbName; + AUTH_DAT ad; +#endif + + AttributeDescription *password = slap_schema.si_ad_userPassword; + +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val, 0, 0); +#endif + + /* get entry */ + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + + switch(rc) { + case DB_NOTFOUND: + case 0: + break; + default: + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return rc; + } + + /* get entry with reader lock */ + if ( e == NULL ) { + char *matched_dn = NULL; + BerVarray refs; + + if( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + + bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + /* allow noauth binds */ + rc = 1; + if ( method == LDAP_AUTH_SIMPLE ) { + if ( be_isroot_pw( be, conn, ndn, cred ) ) { + ber_dupbv( edn, be_root_dn( be ) ); + rc = LDAP_SUCCESS; /* front end will send result */ + + } else if ( refs != NULL ) { + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + } else { + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + } + + } else if ( refs != NULL ) { + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + } else { + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + } + + ber_bvarray_free( refs ); + free( matched_dn ); + + return rc; + } + + ber_dupbv( edn, &e->e_name ); + + /* check for deleted */ +#ifdef BDB_SUBENTRIES + if ( is_entry_subentry( e ) ) { + /* entry is an subentry, don't allow bind */ +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_DETAIL1, "bdb_bind: entry is subentry\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0, + 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + + goto done; + } +#endif + +#ifdef BDB_ALIASES + if ( is_entry_alias( e ) ) { + /* entry is an alias, don't allow bind */ +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_DETAIL1, "bdb_bind: entry is alias\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, + 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM, + NULL, "entry is alias", NULL, NULL ); + + goto done; + } +#endif + + if ( is_entry_referral( e ) ) { + /* entry is a referral, don't allow bind */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "bind", LDAP_LEVEL_DETAIL1, "bdb_bind: entry is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); +#endif + + if( refs != NULL ) { + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + } else { + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + } + + ber_bvarray_free( refs ); + + goto done; + } + + switch ( method ) { + case LDAP_AUTH_SIMPLE: + /* check for root dn/passwd */ + if ( be_isroot_pw( be, conn, ndn, cred ) ) { + /* front end will send result */ + if(edn->bv_val != NULL) free( edn->bv_val ); + ber_dupbv( edn, be_root_dn( be ) ); + rc = LDAP_SUCCESS; + goto done; + } + + if ( ! access_allowed( be, conn, op, e, + password, NULL, ACL_AUTH, NULL ) ) + { + send_ldap_result( conn, op, rc = LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto done; + } + + if ( (a = attr_find( e->e_attrs, password )) == NULL ) { + send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH, + NULL, NULL, NULL, NULL ); + goto done; + } + + if ( slap_passwd_check( conn, a, cred ) != 0 ) { + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + goto done; + } + + rc = 0; + break; + +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + case LDAP_AUTH_KRBV41: + if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + goto done; + } + + if ( ! access_allowed( be, conn, op, e, + krbattr, NULL, ACL_AUTH, NULL ) ) + { + send_ldap_result( conn, op, rc = LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto done; + } + + sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "." + : "", ad.pinst, ad.prealm ); + + if ( (a = attr_find( e->e_attrs, krbattr )) == NULL ) { + /* + * no krbname values present: check against DN + */ + if ( strcasecmp( dn, krbname ) == 0 ) { + rc = 0; + break; + } + send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH, + NULL, NULL, NULL, NULL ); + goto done; + + } else { /* look for krbname match */ + struct berval krbval; + + krbval.bv_val = krbname; + krbval.bv_len = strlen( krbname ); + + if ( value_find( a->a_desc, a->a_vals, &krbval ) != 0 ) { + send_ldap_result( conn, op, + rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + goto done; + } + } + rc = 0; + break; + + case LDAP_AUTH_KRBV42: + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Kerberos bind step 2 not supported", + NULL, NULL ); + goto done; +#endif + + default: + send_ldap_result( conn, op, rc = LDAP_STRONG_AUTH_NOT_SUPPORTED, + NULL, "authentication method not supported", NULL, NULL ); + goto done; + } + +done: + /* free entry and reader lock */ + if( e != NULL ) { + bdb_cache_return_entry_r( &bdb->bi_cache, e ); + } + + /* front end with send result on success (rc==0) */ + return rc; +} diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c new file mode 100644 index 0000000000000000000000000000000000000000..1dd74f1cd8e873509b565e0b7f21a135aeee19a0 --- /dev/null +++ b/servers/slapd/back-bdb/cache.c @@ -0,0 +1,904 @@ +/* cache.c - routines to maintain an in-core cache of entries */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" + +#include "back-bdb.h" + +/* BDB backend specific entry info -- visible only to the cache */ +typedef struct bdb_entry_info { + ldap_pvt_thread_rdwr_t bei_rdwr; /* reader/writer lock */ + + /* + * remaining fields require backend cache lock to access + * These items are specific to the BDB backend and should + * be hidden. + */ + int bei_state; /* for the cache */ +#define CACHE_ENTRY_UNDEFINED 0 +#define CACHE_ENTRY_CREATING 1 +#define CACHE_ENTRY_READY 2 +#define CACHE_ENTRY_DELETED 3 +#define CACHE_ENTRY_COMMITTED 4 + + int bei_refcnt; /* # threads ref'ing this entry */ + Entry *bei_lrunext; /* for cache lru list */ + Entry *bei_lruprev; +} EntryInfo; +#undef BEI +#define BEI(e) ((EntryInfo *) ((e)->e_private)) + +static int bdb_cache_delete_entry_internal(Cache *cache, Entry *e); +#ifdef LDAP_DEBUG +static void bdb_lru_print(Cache *cache); +#endif + +static int +bdb_cache_entry_rdwr_lock(Entry *e, int rw) +{ +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n", + rw ? "w" : "r", e->e_id )); +#else + Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n", + rw ? "w" : "r", e->e_id, 0); +#endif + + if (rw) + return ldap_pvt_thread_rdwr_wlock(&BEI(e)->bei_rdwr); + else + return ldap_pvt_thread_rdwr_rlock(&BEI(e)->bei_rdwr); +} + +static int +bdb_cache_entry_rdwr_trylock(Entry *e, int rw) +{ +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n", + rw ? "w" : "r", e->e_id )); +#else + Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n", + rw ? "w" : "r", e->e_id, 0); +#endif + + if (rw) + return ldap_pvt_thread_rdwr_wtrylock(&BEI(e)->bei_rdwr); + else + return ldap_pvt_thread_rdwr_rtrylock(&BEI(e)->bei_rdwr); +} + +static int +bdb_cache_entry_rdwr_unlock(Entry *e, int rw) +{ +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n", + rw ? "w" : "r", e->e_id )); +#else + Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n", + rw ? "w" : "r", e->e_id, 0); +#endif + + if (rw) + return ldap_pvt_thread_rdwr_wunlock(&BEI(e)->bei_rdwr); + else + return ldap_pvt_thread_rdwr_runlock(&BEI(e)->bei_rdwr); +} + +static int +bdb_cache_entry_rdwr_init(Entry *e) +{ + return ldap_pvt_thread_rdwr_init( &BEI(e)->bei_rdwr ); +} + +static int +bdb_cache_entry_rdwr_destroy(Entry *e) +{ + return ldap_pvt_thread_rdwr_destroy( &BEI(e)->bei_rdwr ); +} + +static int +bdb_cache_entry_private_init( Entry *e ) +{ + assert( e->e_private == NULL ); + + if( e->e_private != NULL ) { + /* this should never happen */ + return 1; + } + + e->e_private = ch_calloc(1, sizeof(struct bdb_entry_info)); + + if( bdb_cache_entry_rdwr_init( e ) != 0 ) { + free( BEI(e) ); + e->e_private = NULL; + return 1; + } + + return 0; +} + +/* + * marks an entry in CREATING state as committed, so it is really returned + * to the cache. Otherwise an entry in CREATING state is removed. + * Makes e_private be destroyed at the following cache_return_entry_w, + * but lets the entry untouched (owned by someone else) + */ +void +bdb_cache_entry_commit( Entry *e ) +{ + assert( e ); + assert( e->e_private ); + assert( BEI(e)->bei_state == CACHE_ENTRY_CREATING ); + /* assert( BEI(e)->bei_refcnt == 1 ); */ + + BEI(e)->bei_state = CACHE_ENTRY_COMMITTED; +} + +static int +bdb_cache_entry_private_destroy( Entry *e ) +{ + assert( e->e_private ); + + bdb_cache_entry_rdwr_destroy( e ); + + free( e->e_private ); + e->e_private = NULL; + return 0; +} + +void +bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ) +{ + ID id; + int refcnt, freeit = 1; + + /* set cache mutex */ + ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); + + assert( e->e_private ); + + bdb_cache_entry_rdwr_unlock(e, rw); + + id = e->e_id; + refcnt = --BEI(e)->bei_refcnt; + + /* + * if the entry is returned when in CREATING state, it is deleted + * but not freed because it may belong to someone else (do_add, + * for instance) + */ + if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) { + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + bdb_cache_delete_entry_internal( cache, e ); + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + freeit = 0; + /* now the entry is in DELETED state */ + } + + if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) { + BEI(e)->bei_state = CACHE_ENTRY_READY; + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n", + id, rw ? "w" : "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + + } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) { + if( refcnt > 0 ) { + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + } else { + bdb_cache_entry_private_destroy( e ); + if ( freeit ) { + bdb_entry_return( e ); + } + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + } + + } else { + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n", + id, rw ? "w": "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n", + rw ? "w" : "r", id, refcnt); +#endif + } +} + +#define LRU_DELETE( cache, e ) do { \ + if ( BEI(e)->bei_lruprev != NULL ) { \ + BEI(BEI(e)->bei_lruprev)->bei_lrunext = BEI(e)->bei_lrunext; \ + } else { \ + (cache)->c_lruhead = BEI(e)->bei_lrunext; \ + } \ + if ( BEI(e)->bei_lrunext != NULL ) { \ + BEI(BEI(e)->bei_lrunext)->bei_lruprev = BEI(e)->bei_lruprev; \ + } else { \ + (cache)->c_lrutail = BEI(e)->bei_lruprev; \ + } \ +} while(0) + +#define LRU_ADD( cache, e ) do { \ + BEI(e)->bei_lrunext = (cache)->c_lruhead; \ + if ( BEI(e)->bei_lrunext != NULL ) { \ + BEI(BEI(e)->bei_lrunext)->bei_lruprev = (e); \ + } \ + (cache)->c_lruhead = (e); \ + BEI(e)->bei_lruprev = NULL; \ + if ( (cache)->c_lrutail == NULL ) { \ + (cache)->c_lrutail = (e); \ + } \ +} while(0) + +/* + * cache_add_entry_rw - create and lock an entry in the cache + * returns: 0 entry has been created and locked + * 1 entry already existed + * -1 something bad happened + */ +int +bdb_cache_add_entry_rw( + Cache *cache, + Entry *e, + int rw +) +{ + int i, rc; + Entry *ee; + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_add_entry_rw: add (%s):%s to cache\n", + e->e_dn, rw ? "w" : "r" )); +#endif + /* set cache mutex */ + 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 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ERR, + "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n", + e->e_id, e->e_dn, 0 ); +#endif + + + return( -1 ); + } + + if ( avl_insert( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 ) + { + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_add_entry: (%s):%ld already in cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + bdb_cache_entry_private_destroy(e); + + return( 1 ); + } + + /* id tree */ + if ( avl_insert( &cache->c_idtree, (caddr_t) e, + (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_add_entry: (%s):%ls already in cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + /* delete from dn tree inserted above */ + if ( avl_delete( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp ) == NULL ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_add_entry: can't delete (%s) from cache.\n", + e->e_dn )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", + 0, 0, 0 ); +#endif + } + + bdb_cache_entry_private_destroy(e); + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( -1 ); + } + + bdb_cache_entry_rdwr_lock( e, rw ); + + /* put the entry into 'CREATING' state */ + /* will be marked after when entry is returned */ + BEI(e)->bei_state = CACHE_ENTRY_CREATING; + BEI(e)->bei_refcnt = 1; + + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + /* lru */ + LRU_ADD( cache, e ); + if ( ++cache->c_cursize > cache->c_maxsize ) { + /* + * find the lru entry not currently in use and delete it. + * in case a lot of entries are in use, only look at the + * first 10 on the tail of the list. + */ + i = 0; + while ( cache->c_lrutail != NULL && + BEI(cache->c_lrutail)->bei_refcnt != 0 && + i < 10 ) + { + /* move this in-use entry to the front of the q */ + ee = cache->c_lrutail; + LRU_DELETE( cache, ee ); + LRU_ADD( cache, ee ); + i++; + } + + /* + * found at least one to delete - try to get back under + * the max cache size. + */ + while ( cache->c_lrutail != NULL && + BEI(cache->c_lrutail)->bei_refcnt == 0 && + cache->c_cursize > cache->c_maxsize ) + { + e = cache->c_lrutail; + + /* delete from cache and lru q */ + /* XXX do we need rc ? */ + rc = bdb_cache_delete_entry_internal( cache, e ); + bdb_cache_entry_private_destroy( e ); + bdb_entry_return( e ); + } + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( 0 ); +} + +/* + * cache_update_entry - update a LOCKED entry which has been deleted. + * returns: 0 entry has been created and locked + * 1 entry already existed + * -1 something bad happened + */ +int +bdb_cache_update_entry( + Cache *cache, + Entry *e +) +{ + int i, rc; + Entry *ee; + + /* set cache mutex */ + ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); + + assert( e->e_private ); + + if ( avl_insert( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_update_entry: (%s):%ld already in dn cache\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( 1 ); + } + + /* id tree */ + if ( avl_insert( &cache->c_idtree, (caddr_t) e, + (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_update_entry: (%s)%ld already in id cache\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + /* delete from dn tree inserted above */ + if ( avl_delete( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp ) == NULL ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", + 0, 0, 0 ); +#endif + } + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( -1 ); + } + + + /* put the entry into 'CREATING' state */ + /* will be marked after when entry is returned */ + BEI(e)->bei_state = CACHE_ENTRY_CREATING; + + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + /* lru */ + LRU_ADD( cache, e ); + if ( ++cache->c_cursize > cache->c_maxsize ) { + /* + * find the lru entry not currently in use and delete it. + * in case a lot of entries are in use, only look at the + * first 10 on the tail of the list. + */ + i = 0; + while ( cache->c_lrutail != NULL && + BEI(cache->c_lrutail)->bei_refcnt != 0 && + i < 10 ) + { + /* move this in-use entry to the front of the q */ + ee = cache->c_lrutail; + LRU_DELETE( cache, ee ); + LRU_ADD( cache, ee ); + i++; + } + + /* + * found at least one to delete - try to get back under + * the max cache size. + */ + while ( cache->c_lrutail != NULL && + BEI(cache->c_lrutail)->bei_refcnt == 0 && + cache->c_cursize > cache->c_maxsize ) + { + e = cache->c_lrutail; + + /* delete from cache and lru q */ + /* XXX do we need rc ? */ + rc = bdb_cache_delete_entry_internal( cache, e ); + bdb_cache_entry_private_destroy( e ); + bdb_entry_return( e ); + } + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( 0 ); +} + +ID +bdb_cache_find_entry_ndn2id( + Backend *be, + Cache *cache, + struct berval *ndn +) +{ + Entry e, *ep; + ID id; + int count = 0; + + /* this function is always called with normalized DN */ + e.e_nname = *ndn; + +try_again: + /* set cache mutex */ + ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock ); + + if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e, + (AVL_CMP) entry_dn_cmp )) != NULL ) + { + int state; + count++; + + /* + * ep now points to an unlocked entry + * we do not need to lock the entry if we only + * check the state, refcnt, LRU, and id. + */ + + assert( ep->e_private ); + + /* save id */ + id = ep->e_id; + state = BEI(ep)->bei_state; + + /* + * entry is deleted or not fully created yet + */ + if ( state != CACHE_ENTRY_READY ) { + assert(state != CACHE_ENTRY_UNDEFINED); + + /* free cache mutex */ + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n", + ndn->bv_val, id, state )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n", + ndn->bv_val, id, state); +#endif + + + ldap_pvt_thread_yield(); + goto try_again; + } + + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + + /* lru */ + LRU_DELETE( cache, ep ); + LRU_ADD( cache, ep ); + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n", + ndn->bv_val, id, count )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n", + ndn->bv_val, id, count); +#endif + + } else { + /* free cache mutex */ + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + + id = NOID; + } + + return( id ); +} + +/* + * cache_find_entry_id - find an entry in the cache, given id + */ + +Entry * +bdb_cache_find_entry_id( + Cache *cache, + ID id, + int rw +) +{ + Entry e; + Entry *ep; + int count = 0; + + e.e_id = id; + +try_again: + /* set cache mutex */ + ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock ); + + if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e, + (AVL_CMP) entry_id_cmp )) != NULL ) + { + int state; + ID ep_id; + + count++; + + assert( ep->e_private ); + + ep_id = ep->e_id; + state = BEI(ep)->bei_state; + + /* + * entry is deleted or not fully created yet + */ + if ( state != CACHE_ENTRY_READY ) { + + assert(state != CACHE_ENTRY_UNDEFINED); + + /* free cache mutex */ + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n", + id, ep_id, state )); + +#else + Debug(LDAP_DEBUG_TRACE, + "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n", + id, ep_id, state); +#endif + + ldap_pvt_thread_yield(); + goto try_again; + } + + /* acquire reader lock */ + if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) { + /* could not acquire entry lock... + * owner cannot free as we have the cache locked. + * so, unlock the cache, yield, and try again. + */ + + /* free cache mutex */ + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n", + id, ep_id, state )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n", + id, ep_id, state); +#endif + + ldap_pvt_thread_yield(); + goto try_again; + } + + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + /* lru */ + LRU_DELETE( cache, ep ); + LRU_ADD( cache, ep ); + + BEI(ep)->bei_refcnt++; + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_cache_find_entry_id: %ld -> %s found %d tries.\n", + ep_id, ep->e_dn, count )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n", + ep_id, ep->e_dn, count); +#endif + + + return( ep ); + } + + /* free cache mutex */ + ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); + + return( NULL ); +} + +/* + * cache_delete_entry - delete the entry e from the cache. the caller + * should have obtained e (increasing its ref count) via a call to one + * of the cache_find_* routines. the caller should *not* call the + * cache_return_entry() routine prior to calling cache_delete_entry(). + * it performs this function. + * + * returns: 0 e was deleted ok + * 1 e was not in the cache + * -1 something bad happened + */ +int +bdb_cache_delete_entry( + Cache *cache, + Entry *e +) +{ + int rc; + + /* set cache mutex */ + ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); + + assert( e->e_private ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_delete_entry: delete %ld.\n", e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n", + e->e_id, 0, 0 ); +#endif + + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + rc = bdb_cache_delete_entry_internal( cache, e ); + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + + /* free cache mutex */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return( rc ); +} + +static int +bdb_cache_delete_entry_internal( + Cache *cache, + Entry *e +) +{ + int rc = 0; /* return code */ + + /* dn tree */ + if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp ) + == NULL ) + { + rc = -1; + } + + /* id tree */ + if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp ) + == NULL ) + { + rc = -1; + } + + if (rc != 0) { + return rc; + } + + /* lru */ + LRU_DELETE( cache, e ); + cache->c_cursize--; + + /* + * flag entry to be freed later by a call to cache_return_entry() + */ + BEI(e)->bei_state = CACHE_ENTRY_DELETED; + + return( 0 ); +} + +void +bdb_cache_release_all( Cache *cache ) +{ + Entry *e; + int rc; + + /* set cache mutex */ + ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "bdb_cache_release_all: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 ); +#endif + + while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) { +#ifdef LDAP_RDWR_DEBUG + assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr)); +#endif + + /* delete from cache and lru q */ + /* XXX do we need rc ? */ + rc = bdb_cache_delete_entry_internal( cache, e ); + bdb_cache_entry_private_destroy( e ); + bdb_entry_return( e ); + } + + if ( cache->c_cursize ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_release_all: Entry cache could not be emptied.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 ); +#endif + + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); +} + +#ifdef LDAP_DEBUG +static void +bdb_lru_print( Cache *cache ) +{ + Entry *e; + + fprintf( stderr, "LRU queue (head to tail):\n" ); + for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) { + fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n", + e->e_dn, e->e_id, BEI(e)->bei_refcnt ); + } + fprintf( stderr, "LRU queue (tail to head):\n" ); + for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) { + fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n", + e->e_dn, e->e_id, BEI(e)->bei_refcnt ); + } +} +#endif diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c new file mode 100644 index 0000000000000000000000000000000000000000..37e621905aee2eb4409db016da9a3df8a920d67c --- /dev/null +++ b/servers/slapd/back-bdb/compare.c @@ -0,0 +1,129 @@ +/* compare.c - bdb backend compare routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_compare( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + AttributeAssertion *ava +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + Entry *matched; + Entry *e; + Attribute *a; + int rc; + const char *text = NULL; + int manageDSAit = get_manageDSAit( op ); + + /* get entry */ + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + + switch( rc ) { + case DB_NOTFOUND: + case 0: + break; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + BerVarray refs; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + free( matched_dn ); + + goto done; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "compare", LDAP_LEVEL_DETAIL1,"bdb_compare: entry is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + goto done; + } + + if ( ! access_allowed( be, conn, op, e, + ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + rc = LDAP_NO_SUCH_ATTRIBUTE; + + for(a = attrs_find( e->e_attrs, ava->aa_desc ); + a != NULL; + a = attrs_find( a->a_next, ava->aa_desc )) + { + rc = LDAP_COMPARE_FALSE; + + if ( value_find( ava->aa_desc, a->a_vals, &ava->aa_value ) == 0 ) { + rc = LDAP_COMPARE_TRUE; + break; + } + + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + if( rc == LDAP_COMPARE_FALSE || rc == LDAP_COMPARE_TRUE ) { + rc = LDAP_SUCCESS; + } + +done: + /* free entry */ + if( e != NULL ) { + bdb_cache_return_entry_r( &bdb->bi_cache, e ); + } + + return rc; +} diff --git a/servers/slapd/back-bdb/dbcache.c b/servers/slapd/back-bdb/dbcache.c new file mode 100644 index 0000000000000000000000000000000000000000..85ed700fbba42bed33ffe66a739e4ad5c323f394 --- /dev/null +++ b/servers/slapd/back-bdb/dbcache.c @@ -0,0 +1,137 @@ +/* dbcache.c - manage cache of open databases */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <sys/stat.h> + +#include "slap.h" +#include "back-bdb.h" +#include "lutil_hash.h" + +/* Pass-thru hash function. Since the indexer is already giving us hash + * values as keys, we don't need BDB to re-hash them. + */ +static u_int32_t +bdb_db_hash( + DB *db, + const void *bytes, + u_int32_t length +) +{ + u_int32_t ret = 0; + unsigned char *dst = (unsigned char *)&ret; + const unsigned char *src = (const unsigned char *)bytes; + + if ( length > sizeof(u_int32_t) ) + length = sizeof(u_int32_t); + + while ( length ) { + *dst++ = *src++; + length--; + } + return ret; +} + +int +bdb_db_cache( + Backend *be, + const char *name, + DB **dbout ) +{ + int i; + int rc; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct bdb_db_info *db; + char *file; + + *dbout = NULL; + + for( i=BDB_NDB; bdb->bi_databases[i]; i++ ) { + if( !strcmp( bdb->bi_databases[i]->bdi_name, name) ) { + *dbout = bdb->bi_databases[i]->bdi_db; + return 0; + } + } + + ldap_pvt_thread_mutex_lock( &bdb->bi_database_mutex ); + + /* check again! may have been added by another thread */ + for( i=BDB_NDB; bdb->bi_databases[i]; i++ ) { + if( !strcmp( bdb->bi_databases[i]->bdi_name, name) ) { + *dbout = bdb->bi_databases[i]->bdi_db; + ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); + return 0; + } + } + + if( i >= BDB_INDICES ) { + ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); + return -1; + } + + db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); + + db->bdi_name = ch_strdup( name ); + + rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_ERR, "bdb_db_cache: db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "bdb_db_cache: db_create(%s) failed: %s (%d)\n", + bdb->bi_dbenv_home, db_strerror(rc), rc ); +#endif + ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); + return rc; + } + + rc = db->bdi_db->set_pagesize( db->bdi_db, BDB_PAGESIZE ); + rc = db->bdi_db->set_h_hash( db->bdi_db, bdb_db_hash ); +#ifdef BDB_IDL_MULTI + rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); + rc = db->bdi_db->set_dup_compare( db->bdi_db, bdb_bt_compare ); +#endif + + file = ch_malloc( strlen( name ) + sizeof(BDB_SUFFIX) ); + sprintf( file, "%s" BDB_SUFFIX, name ); + + rc = db->bdi_db->open( db->bdi_db, + file, name, + DB_HASH, bdb->bi_db_opflags | DB_CREATE | DB_THREAD, + bdb->bi_dbenv_mode ); + + ch_free( file ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_ERR, "bdb_db_cache: db_open(%s) failed: %s (%d)\n", name, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "bdb_db_cache: db_open(%s) failed: %s (%d)\n", + name, db_strerror(rc), rc ); +#endif + ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); + return rc; + } + + bdb->bi_databases[i+1] = NULL; + bdb->bi_databases[i] = db; + bdb->bi_ndatabases = i+1; + + *dbout = db->bdi_db; + + ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); + return 0; +} diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c new file mode 100644 index 0000000000000000000000000000000000000000..9c37cf835f1298c8453f0a3143839ee9bdda74ab --- /dev/null +++ b/servers/slapd/back-bdb/delete.c @@ -0,0 +1,470 @@ +/* delete.c - bdb backend delete routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_delete( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + Entry *matched; + struct berval pdn = {0, NULL}; + Entry *e, *p = NULL; + int rc; + const char *text; + int manageDSAit = get_manageDSAit( op ); + AttributeDescription *children = slap_schema.si_ad_children; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; +#if 0 + u_int32_t lockid; + DB_LOCK lock; +#endif + +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ARGS, "==> bdb_delete: %s\n", + dn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", + dn->bv_val, 0, 0 ); +#endif + + if( 0 ) { +retry: /* transaction retry */ + if( e != NULL ) { + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "==> bdb_delete: retrying...\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "==> bdb_delete: retrying...\n", + 0, 0, 0 ); +#endif + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + bdb->bi_db_opflags ); + text = NULL; + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "==> bdb_delete: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } +#if 0 + lockid = TXN_ID( ltid ); +#endif + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + if ( !be_issuffix( be, ndn ) ) { + dnParent( ndn, &pdn ); + } + + if( pdn.bv_len != 0 ) { +#if 0 + if ( ltid ) { + DBT obj; + obj.data = pdn.bv_val-1; + obj.size = pdn.bv_len+1; + rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj, + DB_LOCK_WRITE, &lock); + } +#endif + /* get parent */ + rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( p == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: parent does not exist\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- bdb_delete: parent does not exist\n", + 0, 0, 0); +#endif + rc = LDAP_OTHER; + text = "could not locate parent of entry"; + goto return_results; + } + + /* check parent for "children" acl */ + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + + bdb_cache_return_entry_r(&bdb->bi_cache, p); + p = NULL; + + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + if ( !rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: no access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- bdb_delete: no access to parent\n", + 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + } else { + /* no parent, must be root to delete */ + if( ! be_isroot( be, &op->o_ndn ) ) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) + || be_isupdate( be, &op->o_ndn ) ) { + p = (Entry *)&slap_entry_root; + + /* check parent for "children" acl */ + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + p = NULL; + + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + if ( !rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: no access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- bdb_delete: no access " + "to parent\n", 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: no parent and not root\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- bdb_delete: no parent " + "and not root\n", 0, 0, 0); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + } + +#if 0 + if ( ltid ) { + DBT obj; + obj.data = ","; + obj.size = 1; + rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj, + DB_LOCK_WRITE, &lock); + } +#endif + } + + /* get entry for read/modify/write */ + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + BerVarray refs; + +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ARGS, + "<=- bdb_delete: no such object %s\n", + dn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, + "<=- bdb_delete: no such object %s\n", + dn->bv_val, 0, 0); +#endif + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_cache_return_entry_r(&bdb->bi_cache, matched ); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + free( matched_dn ); + + rc = -1; + goto done; + } + + if ( !manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow delete */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: entry is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: entry is referral\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + + rc = 1; + goto done; + } + + rc = bdb_dn2id_children( be, ltid, &e->e_nname ); + if( rc != DB_NOTFOUND ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case 0: +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, + "<=- bdb_delete: non-leaf %s\n", + dn->bv_val )); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_delete: non-leaf %s\n", + dn->bv_val, 0, 0); +#endif + rc = LDAP_NOT_ALLOWED_ON_NONLEAF; + text = "subtree delete not supported"; + break; + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "<=- bdb_delete: has_children failed %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_delete: has_children failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + } + goto return_results; + } + + /* delete from dn2id */ + rc = bdb_dn2id_delete( be, ltid, pdn.bv_val, e ); + if ( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + } +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "<=- bdb_delete: dn2id failed %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_delete: dn2id failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + text = "DN index delete failed"; + goto return_results; + } + + /* delete from id2entry */ + rc = bdb_id2entry_delete( be, ltid, e ); + if ( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + } +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "<=- bdb_delete: id2entry failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_delete: id2entry failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + text = "entry delete failed"; + goto return_results; + } + + /* delete indices for old attributes */ + rc = bdb_index_entry_del( be, ltid, e, e->e_attrs ); + if ( rc != LDAP_SUCCESS ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + } +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "<=- bdb_delete: entry index delete failed!\n" )); +#else + Debug( LDAP_DEBUG_ANY, "entry index delete failed!\n", + 0, 0, 0 ); +#endif + text = "entry index delete failed"; + goto return_results; + } + +#if 0 /* Do we want to reclaim deleted IDs? */ + ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex ); + if ( e->e_id == bdb->bi_lastid ) { + bdb_last_id( be, ltid ); + } + ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex ); +#endif + + if( op->o_noop ) { + rc = TXN_ABORT( ltid ); + } else { + rc = TXN_COMMIT( ltid, 0 ); + } + ltid = NULL; + op->o_private = NULL; + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_ERR, + "bdb_delete: txn_%s failed: %s (%d)\n", + op->o_noop ? "abort (no-op)" : "commit", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: txn_%s failed: %s (%d)\n", + op->o_noop ? "abort (no-op)" : "commit", + db_strerror(rc), rc ); +#endif + rc = LDAP_OTHER; + text = "commit failed"; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "delete", LDAP_LEVEL_RESULTS, + "bdb_delete: deleted%s id=%08lx db=\"%s\"\n", + op->o_noop ? " (no-op)" : "", + e->e_id, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: deleted%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", + e->e_id, e->e_dn ); +#endif + rc = LDAP_SUCCESS; + text = NULL; + } + +return_results: + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + + if(rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + ldap_pvt_thread_yield(); + TXN_CHECKPOINT( bdb->bi_dbenv, + bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); + } + +done: + /* free entry */ + if( e != NULL ) { + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } + + if( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + return rc; +} diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c new file mode 100644 index 0000000000000000000000000000000000000000..00cd9efed7cea38446f909fe4af43ce29d6312a1 --- /dev/null +++ b/servers/slapd/back-bdb/dn2entry.c @@ -0,0 +1,61 @@ +/* dn2entry.c - routines to deal with the dn2id / id2entry glue */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" + +/* + * dn2entry - look up dn in the cache/indexes and return the corresponding + * entry. + */ + +int +bdb_dn2entry_rw( + BackendDB *be, + DB_TXN *tid, + struct berval *dn, + Entry **e, + Entry **matched, + int flags, + int rw ) +{ + int rc; + ID id, id2 = 0; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2entry", LDAP_LEVEL_ARGS, "bdb_dn2entry_rw(\"%s\")\n", + dn->bv_val )); +#else + Debug(LDAP_DEBUG_TRACE, "bdb_dn2entry_rw(\"%s\")\n", + dn->bv_val, 0, 0 ); +#endif + + *e = NULL; + + if( matched != NULL ) { + *matched = NULL; + rc = bdb_dn2id_matched( be, tid, dn, &id, &id2 ); + } else { + rc = bdb_dn2id( be, tid, dn, &id ); + } + + if( rc != 0 ) { + return rc; + } + + if( id2 == 0 ) { + rc = bdb_id2entry_rw( be, tid, id, e, rw ); + } else { + rc = bdb_id2entry_r( be, tid, id2, matched); + } + + return rc; +} diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c new file mode 100644 index 0000000000000000000000000000000000000000..6511e6706bbb08cf17a29c3d3f294c65d5ba2614 --- /dev/null +++ b/servers/slapd/back-bdb/dn2id.c @@ -0,0 +1,1060 @@ +/* dn2id.c - routines to deal with the dn2id index */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "idl.h" + +#ifndef BDB_HIER +int +bdb_dn2id_add( + BackendDB *be, + DB_TXN *txn, + struct berval *pbv, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + int rc; + DBT key, data; + char *buf; + struct berval ptr, pdn; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, "bdb_dn2id_add( \"%s\", 0x%08lx )\n", + e->e_ndn, (long) e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n", + e->e_ndn, (long) e->e_id, 0 ); +#endif + assert( e->e_id != NOID ); + + DBTzero( &key ); + key.size = e->e_nname.bv_len + 2; + buf = ch_malloc( key.size ); + key.data = buf; + buf[0] = DN_BASE_PREFIX; + ptr.bv_val = buf + 1; + ptr.bv_len = e->e_nname.bv_len; + AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); + ptr.bv_val[ptr.bv_len] = '\0'; + + DBTzero( &data ); + data.data = (char *) &e->e_id; + data.size = sizeof( e->e_id ); + + /* store it -- don't override */ + rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "bdb_dn2id_add: put failed: %s %d\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n", + db_strerror(rc), rc, 0 ); +#endif + goto done; + } + + if( !be_issuffix( be, &ptr )) { + buf[0] = DN_SUBTREE_PREFIX; + rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + goto done; + } + + dnParent( &ptr, &pdn ); + + key.size = pdn.bv_len + 2; + pdn.bv_val[-1] = DN_ONE_PREFIX; + key.data = pdn.bv_val-1; + ptr = pdn; + + rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_add: parent (%s) insert failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_add: parent (%s) insert failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + goto done; + } + } + + while( !be_issuffix( be, &ptr )) { + ptr.bv_val[-1] = DN_SUBTREE_PREFIX; + + rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + break; + } + dnParent( &ptr, &pdn ); + + key.size = pdn.bv_len + 2; + key.data = pdn.bv_val - 1; + ptr = pdn; + } + +done: + ch_free( buf ); +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_RESULTS, + "<= bdb_dn2id_add: %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 ); +#endif + return rc; +} + +int +bdb_dn2id_delete( + BackendDB *be, + DB_TXN *txn, + char *pdnc, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + int rc; + DBT key; + char *buf; + struct berval pdn, ptr; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, + "=> bdb_dn2id_delete ( \"%s\", 0x08lx )\n", + e->e_ndn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n", + e->e_ndn, e->e_id, 0 ); +#endif + + DBTzero( &key ); + key.size = e->e_nname.bv_len + 2; + buf = ch_malloc( key.size ); + key.data = buf; + key.flags = DB_DBT_USERMEM; + buf[0] = DN_BASE_PREFIX; + ptr.bv_val = buf+1; + ptr.bv_len = e->e_nname.bv_len; + AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); + ptr.bv_val[ptr.bv_len] = '\0'; + + /* delete it */ + rc = db->del( db, txn, &key, 0 ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_delete: delete failed: %s %d\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n", + db_strerror(rc), rc, 0 ); +#endif + goto done; + } + + if( !be_issuffix( be, &ptr )) { + buf[0] = DN_SUBTREE_PREFIX; + rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + goto done; + } + + dnParent( &ptr, &pdn ); + + key.size = pdn.bv_len + 2; + pdn.bv_val[-1] = DN_ONE_PREFIX; + key.data = pdn.bv_val - 1; + ptr = pdn; + + rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + goto done; + } + } + + while( !be_issuffix( be, &ptr )) { + ptr.bv_val[-1] = DN_SUBTREE_PREFIX; + + rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", + ptr.bv_val, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", + ptr.bv_val, rc, 0 ); +#endif + goto done; + } + dnParent( &ptr, &pdn ); + + key.size = pdn.bv_len + 2; + key.data = pdn.bv_val - 1; + ptr = pdn; + } + +done: + ch_free( buf ); +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_RESULTS, "<= bdb_dn2id_delete %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 ); +#endif + return rc; +} + +int +bdb_dn2id( + BackendDB *be, + DB_TXN *txn, + struct berval *dn, + ID *id ) +{ + int rc; + DBT key, data; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, "=> bdb_dn2id( \"%s\" )\n", + dn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 ); +#endif + + assert (id); + + *id = bdb_cache_find_entry_ndn2id(be, &bdb->bi_cache, dn); + if (*id != NOID) { + return 0; + } + + DBTzero( &key ); + key.size = dn->bv_len + 2; + key.data = ch_malloc( key.size ); + ((char *)key.data)[0] = DN_BASE_PREFIX; + AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); + + /* store the ID */ + DBTzero( &data ); + data.data = id; + data.ulen = sizeof(ID); + data.flags = DB_DBT_USERMEM; + + /* fetch it */ + rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "<= bdb_dn2id: get failed %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n", + db_strerror( rc ), rc, 0 ); +#endif + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_RESULTS, + "<= bdb_dn2id: got id=0x%08lx\n", *id )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n", + *id, 0, 0 ); +#endif + } + + ch_free( key.data ); + return rc; +} + +int +bdb_dn2id_matched( + BackendDB *be, + DB_TXN *txn, + struct berval *in, + ID *id, + ID *id2 ) +{ + int rc; + DBT key, data; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + char *buf; + struct berval dn; + ID cached_id; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, + "=> bdb_dn2id_matched( \"%s\" )\n", in->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_matched( \"%s\" )\n", in->bv_val, 0, 0 ); +#endif + + DBTzero( &key ); + key.size = in->bv_len + 2; + buf = ch_malloc( key.size ); + key.data = buf; + dn.bv_val = buf+1; + dn.bv_len = key.size - 2; + AC_MEMCPY( dn.bv_val, in->bv_val, key.size - 1 ); + + /* store the ID */ + DBTzero( &data ); + data.data = id; + data.ulen = sizeof(ID); + data.flags = DB_DBT_USERMEM; + + while(1) { + dn.bv_val[-1] = DN_BASE_PREFIX; + + *id = NOID; + + /* lookup cache */ + cached_id = bdb_cache_find_entry_ndn2id(be, &bdb->bi_cache, &dn); + + if (cached_id != NOID) { + rc = 0; + *id = cached_id; + if ( dn.bv_val != buf+1 ) { + *id2 = *id; + } + break; + } else { + /* fetch it */ + rc = db->get(db, txn, &key, &data, bdb->bi_db_opflags ); + } + + if( rc == DB_NOTFOUND ) { + struct berval pdn; + + if ( ! be_issuffix( be, &dn ) ) { + dnParent( &dn, &pdn ); + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_DETAIL1, + "<= bdb_dn2id_matched: no match\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_dn2id_matched: no match\n", + 0, 0, 0 ); +#endif + break; + } + + key.size = pdn.bv_len + 2; + dn = pdn; + key.data = pdn.bv_val - 1; + + } else if ( rc == 0 ) { + if( data.size != sizeof( ID ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_DETAIL1, + "<= bdb_dn2id_matched: get size mismatch:" + "expected %ld, got %ld\n", + (long) sizeof(ID), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_dn2id_matched: get size mismatch: " + "expected %ld, got %ld\n", + (long) sizeof(ID), (long) data.size, 0 ); +#endif + } + + if( dn.bv_val != buf+1 ) { + *id2 = *id; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_DETAIL1, + "<= bdb_dn2id_matched: id=0x%08lx: %s %s\n", + (long) *id, *id2 == 0 ? "entry" : "matched", dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_dn2id_matched: id=0x%08lx: %s %s\n", + (long) *id, *id2 == 0 ? "entry" : "matched", dn.bv_val ); +#endif + break; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "<= bdb_dn2id_matched: get failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_dn2id_matched: get failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + break; + } + } + + ch_free( buf ); + return rc; +} + +int +bdb_dn2id_children( + BackendDB *be, + DB_TXN *txn, + struct berval *dn ) +{ + int rc; + DBT key, data; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + ID id; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, + "=> bdb_dn2id_children( %s )\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n", + dn->bv_val, 0, 0 ); +#endif + + DBTzero( &key ); + key.size = dn->bv_len + 2; + key.data = ch_malloc( key.size ); + ((char *)key.data)[0] = DN_ONE_PREFIX; + AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); + + /* we actually could do a empty get... */ + DBTzero( &data ); + data.data = &id; + data.ulen = sizeof(id); + data.flags = DB_DBT_USERMEM; + data.doff = 0; + data.dlen = sizeof(id); + + rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags ); + free( key.data ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_DETAIL1, + "<= bdb_dn2id_children( %s ): %schildren (%d)\n", + dn->bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : + db_strerror(rc)), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %schildren (%d)\n", + dn->bv_val, + rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : + db_strerror(rc) ), rc ); +#endif + + return rc; +} + +int +bdb_dn2idl( + BackendDB *be, + struct berval *dn, + int prefix, + ID *ids ) +{ + int rc; + DBT key; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ARGS, + "=> bdb_dn2ididl( \"%s\" )\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n", dn->bv_val, 0, 0 ); +#endif + + if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) + { + BDB_IDL_ALL(bdb, ids); + return 0; + } + + DBTzero( &key ); + key.size = dn->bv_len + 2; + key.data = ch_malloc( key.size ); + ((char *)key.data)[0] = prefix; + AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); + + rc = bdb_idl_fetch_key( be, db, NULL, &key, ids ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_ERR, + "<= bdb_dn2ididl: get failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_dn2idl: get failed: %s (%d)\n", + db_strerror( rc ), rc, 0 ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "db2id", LDAP_LEVEL_RESULTS, + "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", + (long) ids[0], (long) BDB_IDL_FIRST( ids ), + (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) ); +#endif + } + + ch_free( key.data ); + return rc; +} +#else /* BDB_HIER */ + +/* Experimental management routines for a hierarchically structured backend. + * + * Unsupported! Use at your own risk! + * + * Instead of a dn2id database, we use an id2parent database. Each entry in + * this database is a struct diskNode, containing the ID of the node's parent + * and the RDN of the node. + */ +typedef struct diskNode { + ID parent; + struct berval rdn; + struct berval nrdn; +} diskNode; + +/* In bdb_db_open() we call bdb_build_tree() which reads the entire id2parent + * database into memory (into an AVL tree). Next we iterate through each node + * of this tree, connecting each child to its parent. The nodes in this AVL + * tree are a struct idNode. The immediate (Onelevel) children of a node are + * referenced in the i_kids AVL tree. With this arrangement, there is no need + * to maintain the DN_ONE_PREFIX or DN_SUBTREE_PREFIX database keys. Note that + * the DN of an entry is constructed by walking up the list of i_parent + * pointers, so no full DN is stored on disk anywhere. This makes modrdn + * extremely efficient, even when operating on a populated subtree. + * + * The idNode tree is searched directly from the root when performing id to + * entry lookups. The tree is traversed using the i_kids subtrees when + * performing dn to id lookups. + */ +typedef struct idNode { + ID i_id; + struct idNode *i_parent; + diskNode *i_rdn; + Avlnode *i_kids; + ldap_pvt_thread_rdwr_t i_kids_rdwr; +} idNode; + + +/* The main AVL tree is sorted in ID order. The i_kids AVL trees are + * sorted in lexical order. These are the various helper routines used + * for the searches and sorts. + */ +static int +node_find_cmp( + ID id, + idNode *n +) +{ + return id - n->i_id; +} + +static int +node_frdn_cmp( + char *nrdn, + idNode *n +) +{ + return strcmp(nrdn, n->i_rdn->nrdn.bv_val); +} + +static int +node_add_cmp( + idNode *a, + idNode *b +) +{ + return a->i_id - b->i_id; +} + +static int +node_rdn_cmp( + idNode *a, + idNode *b +) +{ +#if 0 + return strcmp(a->i_rdn->nrdn.bv_val, b->i_rdn->nrdn.bv_val); +#endif + /* should be slightly better without ordering drawbacks */ + return ber_bvcmp(&a->i_rdn->nrdn, &b->i_rdn->nrdn); +} + +idNode * bdb_find_id_node( + ID id, + Avlnode *tree +) +{ + return avl_find(tree, (const void *)id, (AVL_CMP)node_find_cmp); +} + +idNode * bdb_find_rdn_node( + char *nrdn, + Avlnode *tree +) +{ + return avl_find(tree, (const void *)nrdn, (AVL_CMP)node_frdn_cmp); +} + +/* This function links a node into its parent's i_kids tree. */ +int bdb_insert_kid( + idNode *a, + Avlnode *tree +) +{ + int rc; + + if (a->i_rdn->parent == 0) + return 0; + a->i_parent = bdb_find_id_node(a->i_rdn->parent, tree); + if (!a->i_parent) + return -1; + ldap_pvt_thread_rdwr_wlock(&a->i_parent->i_kids_rdwr); + rc = avl_insert( &a->i_parent->i_kids, (caddr_t) a, + (AVL_CMP)node_rdn_cmp, (AVL_DUP) avl_dup_error ); + ldap_pvt_thread_rdwr_wunlock(&a->i_parent->i_kids_rdwr); + return rc; +} + +/* This function adds a node into the main AVL tree */ +idNode *bdb_add_node( + ID id, + char *d, + struct bdb_info *bdb +) +{ + idNode *node; + + node = (idNode *)ch_malloc(sizeof(idNode)); + node->i_id = id; + node->i_parent = NULL; + node->i_kids = NULL; + node->i_rdn = (diskNode *)d; + node->i_rdn->rdn.bv_val += (long)d; + node->i_rdn->nrdn.bv_val += (long)d; + ldap_pvt_thread_rdwr_init(&node->i_kids_rdwr); + avl_insert( &bdb->bi_tree, (caddr_t) node, + (AVL_CMP)node_add_cmp, (AVL_DUP) avl_dup_error ); + if (id == 1) + bdb->bi_troot = node; + return node; +} + +/* This function initializes the trees at startup time. */ +int bdb_build_tree( + Backend *be +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int i, rc; + DBC *cursor; + DBT key, data; + ID id; + idNode *node; + char **rdns; + + bdb->bi_tree = NULL; + + rc = bdb->bi_id2parent->bdi_db->cursor( + bdb->bi_id2parent->bdi_db, NULL, &cursor, + bdb->bi_db_opflags ); + if( rc != 0 ) { + return NOID; + } + + /* When be_suffix is turned into struct berval or LDAPDN + * life will get a lot easier... Since no DNs live on disk, we + * need to operate on the be_suffix to fully qualify our DNs. + * We need to know how many components are in the suffix DN, + * so we can tell where the suffix ends and our nodes begin. + * + * Note that this code always uses be_suffix[0], so defining + * multiple suffixes for a single backend won't work! + */ + rdns = ldap_explode_dn(be->be_nsuffix[0]->bv_val, 0); + for (i=0; rdns[i]; i++); + bdb->bi_nrdns = i; + charray_free(rdns); + + DBTzero( &key ); + DBTzero( &data ); + key.data = (char *)&id; + key.ulen = sizeof( id ); + key.flags = DB_DBT_USERMEM; + data.flags = DB_DBT_MALLOC; + + while (cursor->c_get( cursor, &key, &data, DB_NEXT ) == 0) { + bdb_add_node( id, data.data, bdb ); + } + cursor->c_close( cursor ); + + rc = avl_apply(bdb->bi_tree, (AVL_APPLY)bdb_insert_kid, bdb->bi_tree, + -1, AVL_INORDER ); + + return rc; +} + +/* This function constructs a full DN for a given id. We really should + * be passing idNodes directly, to save some effort... + */ +int bdb_fix_dn( + BackendDB *be, + ID id, + Entry *e +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + idNode *n, *o; + int rlen, nrlen; + char *ptr, *nptr; + + ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); + o = bdb_find_id_node(id, bdb->bi_tree); + rlen = be->be_suffix[0]->bv_len + 1; + nrlen = be->be_nsuffix[0]->bv_len + 1; + for (n = o; n && n->i_parent; n=n->i_parent) { + rlen += n->i_rdn->rdn.bv_len + 1; + nrlen += n->i_rdn->nrdn.bv_len + 1; + } + e->e_name.bv_len = rlen - 1; + e->e_nname.bv_len = nrlen - 1; + e->e_name.bv_val = ch_malloc(rlen + nrlen); + e->e_nname.bv_val = e->e_name.bv_val + rlen; + ptr = e->e_name.bv_val; + nptr = e->e_nname.bv_val; + for (n = o; n && n->i_parent; n=n->i_parent) { + ptr = slap_strcopy(ptr, n->i_rdn->rdn.bv_val); + *ptr++ = ','; + nptr = slap_strcopy(nptr, n->i_rdn->nrdn.bv_val); + *nptr++ = ','; + } + ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); + + strcpy(ptr, be->be_suffix[0]->bv_val); + strcpy(nptr, be->be_nsuffix[0]->bv_val); + + return 0; +} + +int +bdb_dn2id_add( + BackendDB *be, + DB_TXN *txn, + struct berval *pdn, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc, rlen, nrlen; + DBT key, data; + DB *db = bdb->bi_id2parent->bdi_db; + diskNode *d; + idNode *n; + + nrlen = dn_rdnlen( be, &e->e_nname ); + if (nrlen) { + rlen = dn_rdnlen( be, &e->e_name ); + } else { + rlen = 0; + } + + d = ch_malloc(sizeof(diskNode) + rlen + nrlen + 2); + d->rdn.bv_len = rlen; + d->nrdn.bv_len = nrlen; + d->rdn.bv_val = (char *)(d+1); + d->nrdn.bv_val = d->rdn.bv_val + rlen + 1; + strncpy(d->rdn.bv_val, e->e_dn, rlen); + d->rdn.bv_val[rlen] = '\0'; + strncpy(d->nrdn.bv_val, e->e_ndn, nrlen); + d->nrdn.bv_val[nrlen] = '\0'; + d->rdn.bv_val -= (long)d; + d->nrdn.bv_val -= (long)d; + + if (pdn->bv_len) { + bdb_dn2id(be, txn, pdn, &d->parent); + } else { + d->parent = 0; + } + + DBTzero(&key); + DBTzero(&data); + key.data = &e->e_id; + key.size = sizeof(ID); + key.flags = DB_DBT_USERMEM; + + data.data = d; + data.size = sizeof(diskNode) + rlen + nrlen + 2; + data.flags = DB_DBT_USERMEM; + + rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); + + if (rc == 0) { + ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr); + n = bdb_add_node( e->e_id, data.data, bdb); + ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr); + + if (d->parent) { + ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); + bdb_insert_kid(n, bdb->bi_tree); + ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); + } + } else { + free(d); + } + return rc; +} + +int +bdb_dn2id_delete( + BackendDB *be, + DB_TXN *txn, + char *pdn, + Entry *e ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + DBT key; + DB *db = bdb->bi_id2parent->bdi_db; + idNode *n; + + DBTzero(&key); + key.size = sizeof(e->e_id); + key.data = &e->e_id; + + rc = db->del( db, txn, &key, 0); + + ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr); + n = avl_delete(&bdb->bi_tree, (void *)e->e_id, (AVL_CMP)node_find_cmp); + if (n) { + if (n->i_parent) { + ldap_pvt_thread_rdwr_wlock(&n->i_parent->i_kids_rdwr); + avl_delete(&n->i_parent->i_kids, n->i_rdn->nrdn.bv_val, + (AVL_CMP)node_frdn_cmp); + ldap_pvt_thread_rdwr_wunlock(&n->i_parent->i_kids_rdwr); + } + free(n->i_rdn); + ldap_pvt_thread_rdwr_destroy(&n->i_kids_rdwr); + free(n); + } + if (e->e_id == 1) + bdb->bi_troot = NULL; + ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr); + + return rc; +} + +int +bdb_dn2id_matched( + BackendDB *be, + DB_TXN *txn, + struct berval *in, + ID *id, + ID *id2 ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int i; + char **rdns; + idNode *n, *p; + + if (!bdb->bi_troot) + return DB_NOTFOUND; + + p = bdb->bi_troot; + if (be_issuffix(be, in)) { + *id = p->i_id; + return 0; + } + + rdns = ldap_explode_dn(in->bv_val, 0); + for (i=0; rdns[i]; i++); + i -= bdb->bi_nrdns; + if (i < 0) { + charray_free(rdns); + return -1; + } + n = p; + ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); + for (--i; i>=0; i--) { + ldap_pvt_thread_rdwr_rlock(&p->i_kids_rdwr); + n = bdb_find_rdn_node(rdns[i], p->i_kids); + ldap_pvt_thread_rdwr_runlock(&p->i_kids_rdwr); + if (!n) break; + p = n; + } + ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); + charray_free(rdns); + + if (n) { + *id = n->i_id; + } else if (id2) { + *id2 = p->i_id; + } + return n ? 0 : DB_NOTFOUND; +} + +int +bdb_dn2id( + BackendDB *be, + DB_TXN *txn, + struct berval *dn, + ID *id ) +{ + return bdb_dn2id_matched(be, txn, dn, id, NULL); +} + +int +bdb_dn2id_children( + BackendDB *be, + DB_TXN *txn, + struct berval *dn ) +{ + int rc; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + ID id; + idNode *n; + + rc = bdb_dn2id(be, txn, dn, &id); + if (rc != 0) + return rc; + + ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); + n = bdb_find_id_node(id, bdb->bi_tree); + ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); + + if (!n->i_kids) + return DB_NOTFOUND; + else + return 0; +} + +/* Since we don't store IDLs for onelevel or subtree, we have to construct + * them on the fly... Perhaps the i_kids tree ought to just be an IDL? + */ +static int +insert_one( + idNode *n, + ID *ids +) +{ + return bdb_idl_insert(ids, n->i_id); +} + +static int +insert_sub( + idNode *n, + ID *ids +) +{ + int rc; + + rc = bdb_idl_insert(ids, n->i_id); + if (rc == 0) { + ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr); + rc = avl_apply(n->i_kids, (AVL_APPLY)insert_sub, ids, -1, + AVL_INORDER); + ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr); + } + return rc; +} + +int +bdb_dn2idl( + BackendDB *be, + struct berval *dn, + int prefix, + ID *ids ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + ID id; + idNode *n; + + if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) { + BDB_IDL_ALL(bdb, ids); + return 0; + } + + rc = bdb_dn2id(be, NULL, dn, &id); + if (rc) return rc; + + ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); + n = bdb_find_id_node(id, bdb->bi_tree); + ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); + + ids[0] = 0; + ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr); + if (prefix == DN_ONE_PREFIX) { + rc = avl_apply(n->i_kids, (AVL_APPLY)insert_one, ids, -1, + AVL_INORDER); + } else { + rc = avl_apply(n->i_kids, (AVL_APPLY)insert_sub, ids, -1, + AVL_INORDER); + } + ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr); + return rc; +} +#endif /* BDB_HIER */ diff --git a/servers/slapd/back-bdb/error.c b/servers/slapd/back-bdb/error.c new file mode 100644 index 0000000000000000000000000000000000000000..ba96309a390940ed192a23323aaa66ea22ac7cd7 --- /dev/null +++ b/servers/slapd/back-bdb/error.c @@ -0,0 +1,23 @@ +/* error.c - BDB errcall routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-bdb.h" + +void bdb_errcall( const char *pfx, char * msg ) +{ +#ifdef NEW_LOGGING + LDAP_LOG (( "error", LDAP_LEVEL_INFO, "bdb(%s): %s\n", pfx, msg )); +#else + Debug( LDAP_DEBUG_ANY, "bdb(%s): %s\n", pfx, msg, 0 ); +#endif +} diff --git a/servers/slapd/back-bdb/external.h b/servers/slapd/back-bdb/external.h new file mode 100644 index 0000000000000000000000000000000000000000..f7c285a808621fd2c84810ded9b298ca033c3f8d --- /dev/null +++ b/servers/slapd/back-bdb/external.h @@ -0,0 +1,49 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#ifndef _BDB_EXTERNAL_H +#define _BDB_EXTERNAL_H + +LDAP_BEGIN_DECL + +extern BI_init bdb_initialize; + +extern BI_db_config bdb_db_config; + +extern BI_op_add bdb_add; + +extern BI_op_bind bdb_bind; + +extern BI_op_compare bdb_compare; + +extern BI_op_delete bdb_delete; + +extern BI_op_modify bdb_modify; + +extern BI_op_modrdn bdb_modrdn; + +extern BI_op_search bdb_search; + +extern BI_op_extended bdb_extended; + +extern BI_chk_referrals bdb_referrals; + +extern BI_operational bdb_operational; + +/* tools.c */ +extern BI_tool_entry_open bdb_tool_entry_open; +extern BI_tool_entry_close bdb_tool_entry_close; +extern BI_tool_entry_next bdb_tool_entry_next; +extern BI_tool_entry_get bdb_tool_entry_get; +extern BI_tool_entry_put bdb_tool_entry_put; +extern BI_tool_entry_reindex bdb_tool_entry_reindex; + + + +LDAP_END_DECL + +#endif /* _BDB_EXTERNAL_H */ + diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c new file mode 100644 index 0000000000000000000000000000000000000000..bd8adc0bdc8c2deb688b4adf0a0c59f0ee3757c5 --- /dev/null +++ b/servers/slapd/back-bdb/filterindex.c @@ -0,0 +1,753 @@ +/* filterindex.c - generate the list of candidate entries from a filter */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "idl.h" + +static int presence_candidates( + Backend *be, + AttributeDescription *desc, + ID *ids ); + +static int equality_candidates( + Backend *be, + AttributeAssertion *ava, + ID *ids, + ID *tmp ); +static int approx_candidates( + Backend *be, + AttributeAssertion *ava, + ID *ids, + ID *tmp ); +static int substring_candidates( + Backend *be, + SubstringsAssertion *sub, + ID *ids, + ID *tmp ); + +static int list_candidates( + Backend *be, + Filter *flist, + int ftype, + ID *ids, + ID *tmp, + ID *stack ); + +int +bdb_filter_candidates( + Backend *be, + Filter *f, + ID *ids, + ID *tmp, + ID *stack ) +{ + int rc = -1; +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ENTRY, "=> bdb_filter_candidates\n")); +#else + Debug( LDAP_DEBUG_FILTER, "=> bdb_filter_candidates\n", 0, 0, 0 ); +#endif + + switch ( f->f_choice ) { + case SLAPD_FILTER_DN_ONE: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tDN ONE\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tDN ONE\n", 0, 0, 0 ); +#endif + rc = bdb_dn2idl( be, f->f_dn, DN_ONE_PREFIX, ids ); + break; + + case SLAPD_FILTER_DN_SUBTREE: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tDN SUBTREE\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tDN SUBTREE\n", 0, 0, 0 ); +#endif + rc = bdb_dn2idl( be, f->f_dn, DN_SUBTREE_PREFIX, ids ); + break; + + case LDAP_FILTER_PRESENT: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tPRESENT\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 ); +#endif + rc = presence_candidates( be, f->f_desc, ids ); + break; + + case LDAP_FILTER_EQUALITY: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tEQUALITY\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 ); +#endif + rc = equality_candidates( be, f->f_ava, ids, tmp ); + break; + + case LDAP_FILTER_APPROX: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tAPPROX\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 ); +#endif + rc = approx_candidates( be, f->f_ava, ids, tmp ); + break; + + case LDAP_FILTER_SUBSTRINGS: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tSUBSTRINGS\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 ); +#endif + rc = substring_candidates( be, f->f_sub, ids, tmp ); + break; + + case LDAP_FILTER_GE: + /* no GE index, use pres */ +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tGE\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 ); +#endif + rc = presence_candidates( be, f->f_ava->aa_desc, ids ); + break; + + case LDAP_FILTER_LE: + /* no LE index, use pres */ +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tLE\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 ); +#endif + rc = presence_candidates( be, f->f_ava->aa_desc, ids ); + break; + + case LDAP_FILTER_NOT: + /* no indexing to support NOT filters */ +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tNOT\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 ); +#endif + break; + + case LDAP_FILTER_AND: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tAND\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 ); +#endif + rc = list_candidates( be, + f->f_and, LDAP_FILTER_AND, ids, tmp, stack ); + break; + + case LDAP_FILTER_OR: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tOR\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 ); +#endif + rc = list_candidates( be, + f->f_or, LDAP_FILTER_OR, ids, tmp, stack ); + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_filter_candidates: \tUNKNOWN\n")); +#else + Debug( LDAP_DEBUG_FILTER, "\tUNKNOWN %lu\n", + (unsigned long) f->f_choice, 0, 0 ); +#endif + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_filter_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_FILTER, + "<= bdb_filter_candidates: id=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST( ids ), + (long) BDB_IDL_LAST( ids ) ); +#endif + + return rc; +} + +static int +list_candidates( + Backend *be, + Filter *flist, + int ftype, + ID *ids, + ID *tmp, + ID *save ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc = 0; + Filter *f; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "=> bdb_list_candidates: 0x%x\n", ftype)); +#else + Debug( LDAP_DEBUG_FILTER, "=> bdb_list_candidates 0x%x\n", ftype, 0, 0 ); +#endif + + if ( ftype == LDAP_FILTER_OR ) { + BDB_IDL_ALL( bdb, save ); + BDB_IDL_ZERO( ids ); + } else { + BDB_IDL_CPY( save, ids ); + } + + for ( f = flist; f != NULL; f = f->f_next ) { + rc = bdb_filter_candidates( be, f, save, tmp, + save+BDB_IDL_UM_SIZE ); + + if ( rc != 0 ) { + if ( ftype == LDAP_FILTER_AND ) { + rc = 0; + continue; + } + break; + } + + if ( ftype == LDAP_FILTER_AND ) { + bdb_idl_intersection( ids, save ); + if( BDB_IDL_IS_ZERO( ids ) ) + break; + } else { + bdb_idl_union( ids, save ); + BDB_IDL_ALL( bdb, save ); + } + } + + if( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_list_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_FILTER, + "<= bdb_list_candidates: id=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ARGS, "<= bdb_list_candidates: rc=%d\n", rc)); +#else + Debug( LDAP_DEBUG_FILTER, + "<= bdb_list_candidates: undefined rc=%d\n", + rc, 0, 0 ); +#endif + } + + return rc; +} + +static int +presence_candidates( + Backend *be, + AttributeDescription *desc, + ID *ids ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db; + int rc; + slap_mask_t mask; + struct berval prefix = {0}; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ENTRY, "=> bdb_presence_candidates\n")); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_presence_candidates\n", 0, 0, 0 ); +#endif + + if( desc == slap_schema.si_ad_objectClass ) { + BDB_IDL_ALL( bdb, ids ); + return 0; + } + + rc = bdb_index_param( be, desc, LDAP_FILTER_PRESENT, + &db, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_presence_candidates: index_parm returned=%d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_presence_candidates: index_param returned=%d\n", + rc, 0, 0 ); +#endif + return 0; + } + + if( db == NULL ) { + /* not indexed */ +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_presence_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_presence_candidates: not indexed\n", + 0, 0, 0 ); +#endif + return 0; + } + + if( prefix.bv_val == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_presence_candidates: no prefix\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_presence_candidates: no prefix\n", + 0, 0, 0 ); +#endif + return 0; + } + + rc = bdb_key_read( be, db, NULL, &prefix, ids ); + + if( rc == DB_NOTFOUND ) { + BDB_IDL_ZERO( ids ); + rc = 0; + } else if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_presence_candidates: key read failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_presense_candidates: key read failed (%d)\n", + rc, 0, 0 ); +#endif + goto done; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_presence_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug(LDAP_DEBUG_TRACE, + "<= bdb_presence_candidates: id=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + +done: + return rc; +} + +static int +equality_candidates( + Backend *be, + AttributeAssertion *ava, + ID *ids, + ID *tmp ) +{ + DB *db; + int i; + int rc; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ENTRY, "=> equality_candidates\n")); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_equality_candidates\n", 0, 0, 0 ); +#endif + + rc = bdb_index_param( be, ava->aa_desc, LDAP_FILTER_EQUALITY, + &db, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_equality_candidates: index_param failed (%d)\n", rc)); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_equality_candidates: index_param failed (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_equality_candidates: not indexed\n")); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_equality_candidates: not indexed\n", 0, 0, 0 ); +#endif + return -1; + } + + mr = ava->aa_desc->ad_type->sat_equality; + if( !mr ) { + return -1; + } + + if( !mr->smr_filter ) { + return -1; + } + + rc = (mr->smr_filter)( + LDAP_FILTER_EQUALITY, + mask, + ava->aa_desc->ad_type->sat_syntax, + mr, + &prefix, + &ava->aa_value, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_equality_candidates: MR filter failed (%d)\n", rc)); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_equality_candidates: MR filter failed (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_equality_candidates: no keys\n")); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_equality_candidates: no keys\n", + 0, 0, 0 ); +#endif + return 0; + } + + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + rc = bdb_key_read( be, db, NULL, &keys[i], tmp ); + + if( rc == DB_NOTFOUND ) { + BDB_IDL_ZERO( ids ); + rc = 0; + } else if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_equality_candidates: key read failed (%d)\n", rc)); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_equality_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + break; + } + + if( BDB_IDL_IS_ZERO( tmp ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "=> bdb_equality_candidates: NULL\n")); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_equality_candidates NULL\n", + 0, 0, 0 ); +#endif + BDB_IDL_ZERO( ids ); + break; + } + + bdb_idl_intersection( ids, tmp ); + + if( BDB_IDL_IS_ZERO( ids ) ) + break; + } + + ber_bvarray_free( keys ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_equality_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_equality_candidates id=%ld, first=%ld, last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + return( rc ); +} + + +static int +approx_candidates( + Backend *be, + AttributeAssertion *ava, + ID *ids, + ID *tmp ) +{ + DB *db; + int i; + int rc; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ENTRY, "=> bdb_approx_candidates\n")); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_approx_candidates\n", 0, 0, 0 ); +#endif + + rc = bdb_index_param( be, ava->aa_desc, LDAP_FILTER_APPROX, + &db, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: index_param failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_approx_candidates: index_param failed (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_approx_candidates: not indexed\n", 0, 0, 0 ); +#endif + return -1; + } + + mr = ava->aa_desc->ad_type->sat_approx; + if( !mr ) { + /* no approx matching rule, try equality matching rule */ + mr = ava->aa_desc->ad_type->sat_equality; + } + + if( !mr ) { + return -1; + } + + if( !mr->smr_filter ) { + return -1; + } + + rc = (mr->smr_filter)( + LDAP_FILTER_APPROX, + mask, + ava->aa_desc->ad_type->sat_syntax, + mr, + &prefix, + &ava->aa_value, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: MR filter failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_approx_candidates: (%s) MR filter failed (%d)\n", + prefix.bv_val, rc, 0 ); +#endif + return rc; + } + + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: no keys (%s)\n", prefix.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_approx_candidates: no keys (%s)\n", + prefix.bv_val, 0, 0 ); +#endif + return 0; + } + + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + rc = bdb_key_read( be, db, NULL, &keys[i], tmp ); + + if( rc == DB_NOTFOUND ) { + BDB_IDL_ZERO( ids ); + rc = 0; + break; + } else if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: key read failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_approx_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + break; + } + + if( BDB_IDL_IS_ZERO( tmp ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_approx_candidates NULL\n", + 0, 0, 0 ); +#endif + BDB_IDL_ZERO( ids ); + break; + } + + bdb_idl_intersection( ids, tmp ); + + if( BDB_IDL_IS_ZERO( ids ) ) + break; + } + + ber_bvarray_free( keys ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_approx_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_approx_candidates %ld, first=%ld, last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + return( rc ); +} + +static int +substring_candidates( + Backend *be, + SubstringsAssertion *sub, + ID *ids, + ID *tmp ) +{ + DB *db; + int i; + int rc; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_ENTRY, "=> bdb_substring_candidates\n")); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_substring_candidates\n", 0, 0, 0 ); +#endif + + rc = bdb_index_param( be, sub->sa_desc, LDAP_FILTER_SUBSTRINGS, + &db, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: index_param failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_substring_candidates: index_param failed (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: not indexed\n")); +#else + Debug( LDAP_DEBUG_ANY, + "<= bdb_substring_candidates not indexed\n", + 0, 0, 0 ); +#endif + return -1; + } + + mr = sub->sa_desc->ad_type->sat_substr; + + if( !mr ) { + return -1; + } + + if( !mr->smr_filter ) { + return -1; + } + + rc = (mr->smr_filter)( + LDAP_FILTER_SUBSTRINGS, + mask, + sub->sa_desc->ad_type->sat_syntax, + mr, + &prefix, + sub, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: (%s) MR filter failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_substring_candidates: (%s) MR filter failed (%d)\n", + sub->sa_desc->ad_cname.bv_val, rc, 0 ); +#endif + return rc; + } + + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: (%s) MR filter failed (%d)\n", mask, sub->sa_desc->ad_cname.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= bdb_substring_candidates: (0x%04lx) no keys (%s)\n", + mask, sub->sa_desc->ad_cname.bv_val, 0 ); +#endif + return 0; + } + + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + rc = bdb_key_read( be, db, NULL, &keys[i], tmp ); + + if( rc == DB_NOTFOUND ) { + BDB_IDL_ZERO( ids ); + rc = 0; + break; + } else if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: key read failed (%d)\n", rc)); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + break; + } + + if( BDB_IDL_IS_ZERO( tmp ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: NULL \n" )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates NULL\n", + 0, 0, 0 ); +#endif + BDB_IDL_ZERO( ids ); + break; + } + + bdb_idl_intersection( ids, tmp ); + + if( BDB_IDL_IS_ZERO( ids ) ) + break; + } + + ber_bvarray_free( keys ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "filterindex", LDAP_LEVEL_RESULTS, "<= bdb_substring_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates %ld, first=%ld, last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + return( 0 ); +} + diff --git a/servers/slapd/back-bdb/group.c b/servers/slapd/back-bdb/group.c new file mode 100644 index 0000000000000000000000000000000000000000..70d1523be9529c2edee66ec126f3911cc62e9f3f --- /dev/null +++ b/servers/slapd/back-bdb/group.c @@ -0,0 +1,225 @@ +/* group.c - bdb backend acl group routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-bdb.h" +#include "proto-bdb.h" + + +/* return 0 IFF op_dn is a value in member attribute + * of entry with gr_dn AND that entry has an objectClass + * value of groupOfNames + */ +int +bdb_group( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct bdb_op_info *boi = (struct bdb_op_info *) op->o_private; + DB_TXN *txn = NULL; + Entry *e; + int rc = 1; + Attribute *attr; + + AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; + const char *group_oc_name = NULL; + const char *group_at_name = group_at->ad_cname.bv_val; + + if( group_oc->soc_names && group_oc->soc_names[0] ) { + group_oc_name = group_oc->soc_names[0]; + } else { + group_oc_name = group_oc->soc_oid; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "bdb_group: check (%s) member of (%s), oc %s\n", + op_ndn->bv_val, gr_ndn->bv_val, group_oc_name )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_group: gr dn: \"%s\"\n", + gr_ndn->bv_val, 0, 0 ); + + Debug( LDAP_DEBUG_ARGS, + "=> bdb_group: op dn: \"%s\"\n", + op_ndn->bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ARGS, + "=> bdb_group: oc: \"%s\" at: \"%s\"\n", + group_oc_name, group_at_name, 0 ); + + Debug( LDAP_DEBUG_ARGS, + "=> bdb_group: tr dn: \"%s\"\n", + target->e_ndn, 0, 0 ); +#endif + + if( boi != NULL && be == boi->boi_bdb ) { + txn = boi->boi_txn; + } + + if (dn_match(&target->e_name, gr_ndn)) { + /* we already have a LOCKED copy of the entry */ + e = target; +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_group: target is group (%s)\n", gr_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_group: target is group: \"%s\"\n", + gr_ndn->bv_val, 0, 0 ); +#endif + } else { + /* can we find group entry */ + rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0 ); + if( rc ) { + if( txn ) { + boi->boi_err = rc; + } + return( 1 ); + } + if (e == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_group: cannot find group (%s)\n", + gr_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> bdb_group: cannot find group: \"%s\"\n", + gr_ndn->bv_val, 0, 0 ); +#endif + return( 1 ); + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_group: found group (%s)\n", gr_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> bdb_group: found group: \"%s\"\n", + gr_ndn->bv_val, 0, 0 ); +#endif + } + + /* find it's objectClass and member attribute values + * make sure this is a group entry + * finally test if we can find op_dn in the member attribute value list + */ + rc = 1; + +#ifdef BDB_ALIASES + if( is_entry_alias( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_group: group (%s) is an alias\n", gr_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: group is an alias\n", 0, 0, 0 ); +#endif + goto return_results; + } +#endif + + if( is_entry_referral( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_group: group (%s) is a referral.\n", gr_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: group is a referral\n", 0, 0, 0 ); +#endif + goto return_results; + } + + if( !is_entry_objectclass( e, group_oc, 0 ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "bdb_group: failed to find %s in objectClass.\n", + group_oc_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: failed to find %s in objectClass\n", + group_oc_name, 0, 0 ); +#endif + goto return_results; + } + + if ((attr = attr_find(e->e_attrs, group_at)) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "bdb_group: failed to find %s\n", group_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: failed to find %s\n", + group_at_name, 0, 0 ); +#endif + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "bdb_group: found objectClass %s and %s\n", + group_oc_name, group_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: found objectClass %s and %s\n", + group_oc_name, group_at_name, 0 ); +#endif + + if( value_find( group_at, attr->a_vals, op_ndn ) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_group: \"%s\" not in \"%s\": %s\n", + op_ndn->bv_val, gr_ndn->bv_val, group_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: \"%s\" not in \"%s\": %s\n", + op_ndn->bv_val, gr_ndn->bv_val, group_at_name ); +#endif + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "bdb_group: %s is in %s: %s\n", + op_ndn->bv_val, gr_ndn->bv_val, group_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= bdb_group: \"%s\" is in \"%s\": %s\n", + op_ndn->bv_val, gr_ndn->bv_val, group_at_name ); +#endif + + rc = 0; + +return_results: + if( target != e ) { + /* free entry */ + bdb_cache_return_entry_r( &bdb->bi_cache, e ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "bdb_group: rc=%d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_group: rc=%d\n", rc, 0, 0 ); +#endif + + return(rc); +} + diff --git a/servers/slapd/back-bdb/idl.c b/servers/slapd/back-bdb/idl.c new file mode 100644 index 0000000000000000000000000000000000000000..ec193efeece06c9cc48c22d26d2b7e4364785819 --- /dev/null +++ b/servers/slapd/back-bdb/idl.c @@ -0,0 +1,1105 @@ +/* idl.c - ldap id list handling routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "idl.h" + +#define IDL_MAX(x,y) ( x > y ? x : y ) +#define IDL_MIN(x,y) ( x < y ? x : y ) + +#define IDL_CMP(x,y) ( x < y ? -1 : ( x > y ? 1 : 0 ) ) + +#if IDL_DEBUG > 0 +static void idl_check( ID *ids ) +{ + if( BDB_IDL_IS_RANGE( ids ) ) { + assert( BDB_IDL_RANGE_FIRST(ids) <= BDB_IDL_RANGE_LAST(ids) ); + } else { + ID i; + for( i=1; i < ids[0]; i++ ) { + assert( ids[i+1] > ids[i] ); + } + } +} + +#if IDL_DEBUG > 1 +static void idl_dump( ID *ids ) +{ + if( BDB_IDL_IS_RANGE( ids ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, "IDL: range (%ld - %ld)\n", + (long) BDB_IDL_RANGE_FIRST( ids ), + (long) BDB_IDL_RANGE_LAST( ids ) )); +#else + Debug( LDAP_DEBUG_ANY, + "IDL: range ( %ld - %ld )\n", + (long) BDB_IDL_RANGE_FIRST( ids ), + (long) BDB_IDL_RANGE_LAST( ids ) ); +#endif + + } else { + ID i; +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, "IDL: size %ld", + (long) ids[0] )); +#else + Debug( LDAP_DEBUG_ANY, "IDL: size %ld", (long) ids[0], 0, 0 ); +#endif + + for( i=1; i<=ids[0]; i++ ) { + if( i % 16 == 1 ) { + Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 ); + } +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, "%02lx",(long)ids[i] )); +#else + Debug( LDAP_DEBUG_ANY, " %02lx", (long) ids[i], 0, 0 ); +#endif + } + + Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 ); + } + + idl_check( ids ); +} +#endif /* IDL_DEBUG > 1 */ +#endif /* IDL_DEBUG > 0 */ + +unsigned bdb_idl_search( ID *ids, ID id ) +{ +#define IDL_BINARY_SEARCH 1 +#ifdef IDL_BINARY_SEARCH + /* + * binary search of id in ids + * if found, returns position of id + * if not found, returns first postion greater than id + */ + unsigned base = 0; + unsigned cursor = 0; + int val = 0; + unsigned n = ids[0]; + +#if IDL_DEBUG > 0 + idl_check( ids ); +#endif + + while( 0 < n ) { + int pivot = n >> 1; + cursor = base + pivot; + val = IDL_CMP( id, ids[cursor + 1] ); + + if( val < 0 ) { + n = pivot; + + } else if ( val > 0 ) { + base = cursor + 1; + n -= pivot + 1; + + } else { + return cursor + 1; + } + } + + if( val > 0 ) { + return cursor + 2; + } else { + return cursor + 1; + } + +#else + /* (reverse) linear search */ + int i; + +#if IDL_DEBUG > 0 + idl_check( ids ); +#endif + + for( i=ids[0]; i; i-- ) { + if( id > ids[i] ) { + break; + } + } + + return i+1; +#endif +} + +int bdb_idl_insert( ID *ids, ID id ) +{ + unsigned x = bdb_idl_search( ids, id ); + +#if IDL_DEBUG > 1 +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_DETAIL1, "insert: %04lx at %d\n", + (long) id, x )); +#else + Debug( LDAP_DEBUG_ANY, "insert: %04lx at %d\n", (long) id, x, 0 ); + idl_dump( ids ); +#endif +#elif IDL_DEBUG > 0 + idl_check( ids ); +#endif + + assert( x > 0 ); + + if( x < 1 ) { + /* internal error */ + return -2; + } + + if ( x <= ids[0] && ids[x] == id ) { + /* duplicate */ + return -1; + } + + if ( ++ids[0] >= BDB_IDL_DB_MAX ) { + if( id < ids[1] ) { + ids[1] = id; + ids[2] = ids[ids[0]-1]; + } else if ( ids[ids[0]-1] < id ) { + ids[2] = id; + } else { + ids[2] = ids[ids[0]-1]; + } + ids[0] = NOID; + + } else { + /* insert id */ + AC_MEMCPY( &ids[x+1], &ids[x], (ids[0]-x) * sizeof(ID) ); + ids[x] = id; + } + +#if IDL_DEBUG > 1 + idl_dump( ids ); +#elif IDL_DEBUG > 0 + idl_check( ids ); +#endif + + return 0; +} + +static int idl_delete( ID *ids, ID id ) +{ + unsigned x = bdb_idl_search( ids, id ); + +#if IDL_DEBUG > 1 +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_DETAIL1, "delete: %04lx at %d\n", + (long) id, x )); +#else + Debug( LDAP_DEBUG_ANY, "delete: %04lx at %d\n", (long) id, x, 0 ); + idl_dump( ids ); +#endif +#elif IDL_DEBUG > 0 + idl_check( ids ); +#endif + + assert( x > 0 ); + + if( x <= 0 ) { + /* internal error */ + return -2; + } + + if( x > ids[0] || ids[x] != id ) { + /* not found */ + return -1; + + } else if ( --ids[0] == 0 ) { + if( x != 1 ) { + return -3; + } + + } else { + AC_MEMCPY( &ids[x], &ids[x+1], (1+ids[0]-x) * sizeof(ID) ); + } + +#if IDL_DEBUG > 1 + idl_dump( ids ); +#elif IDL_DEBUG > 0 + idl_check( ids ); +#endif + + return 0; +} + +int +bdb_idl_fetch_key( + BackendDB *be, + DB *db, + DB_TXN *tid, + DBT *key, + ID *ids ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + DBT data; + + assert( ids != NULL ); + + DBTzero( &data ); + +#ifdef BDB_IDL_MULTI + { + DBC *cursor; + ID buf[BDB_PAGESIZE*4]; + ID *i; + void *ptr; + size_t len; + int rc2; + int flags = bdb->bi_db_opflags | DB_MULTIPLE; + data.data = buf; + data.ulen = sizeof(buf); + data.flags = DB_DBT_USERMEM; + + if ( tid ) + flags |= DB_RMW; + + rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_fetch_key: cursor failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif + return rc; + } + rc = cursor->c_get( cursor, key, &data, flags | DB_SET ); + if (rc == 0) { + i = ids; + while (rc == 0) { + u_int8_t *j; + + DB_MULTIPLE_INIT( ptr, &data ); + while (ptr) { + DB_MULTIPLE_NEXT(ptr, &data, j, len); + if (j) { + ++i; + AC_MEMCPY( i, j, sizeof(ID) ); + } + } + rc = cursor->c_get( cursor, key, &data, flags | DB_NEXT_DUP ); + } + if ( rc == DB_NOTFOUND ) rc = 0; + ids[0] = i - ids; + /* On disk, a range is denoted by 0 in the first element */ + if (ids[1] == 0) { + if (ids[0] != BDB_IDL_RANGE_SIZE) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "=> bdb_idl_fetch_key: range size mismatch: expected %ld, got %ld\n", BDB_IDL_RANGE_SIZE, ids[0] )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "range size mismatch: expected %d, got %ld\n", + BDB_IDL_RANGE_SIZE, ids[0], 0 ); +#endif + cursor->c_close( cursor ); + return -1; + } + BDB_IDL_RANGE( ids, ids[2], ids[3] ); + } + data.size = BDB_IDL_SIZEOF(ids); + } + rc2 = cursor->c_close( cursor ); + if (rc2) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_fetch_key: close failed: %s (%d)\n", db_strerror(rc2), rc2 )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 ); +#endif + return rc2; + } + } +#else + data.data = ids; + data.ulen = BDB_IDL_UM_SIZEOF; + data.flags = DB_DBT_USERMEM; + /* fetch it */ + rc = db->get( db, tid, key, &data, bdb->bi_db_opflags ); +#endif + + if( rc == DB_NOTFOUND ) { + return rc; + + } else if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_fetch_key: get failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "get failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + return rc; + + } else if ( data.size == 0 || data.size % sizeof( ID ) ) { + /* size not multiple of ID size */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_fetch_key: odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "odd size: expected %ld multiple, got %ld\n", + (long) sizeof( ID ), (long) data.size, 0 ); +#endif + return -1; + + } else if ( data.size != BDB_IDL_SIZEOF(ids) ) { + /* size mismatch */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_fetch_key: get size mismatch: expected %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " + "get size mismatch: expected %ld, got %ld\n", + (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); +#endif + return -1; + } + + return rc; +} + +int +bdb_idl_insert_key( + BackendDB *be, + DB *db, + DB_TXN *tid, + DBT *key, + ID id ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + DBT data; +#ifndef BDB_IDL_MULTI + ID ids[BDB_IDL_DB_SIZE]; +#endif + +#if 0 + /* for printable keys only */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ARGS, "bdb_idl_insert_key: %s %ld\n", (char *)key->data, (long) id )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_idl_insert_key: %s %ld\n", + (char *)key->data, (long) id, 0 ); +#endif +#endif + + assert( id != NOID ); + + DBTzero( &data ); +#ifdef BDB_IDL_MULTI + { + DBC *cursor; + ID lo, hi, tmp; + char *err; + + data.size = sizeof( ID ); + data.ulen = data.size; + data.flags = DB_DBT_USERMEM; + + rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: cursor failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif + return rc; + } + data.data = &tmp; + /* Fetch the first data item for this key, to see if it + * exists and if it's a range. + */ + rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW ); + err = "c_get"; + if ( rc == 0 ) { + if ( tmp != 0 ) { + /* not a range, count the number of items */ + db_recno_t count; + rc = cursor->c_count( cursor, &count, 0 ); + if ( rc != 0 ) { + err = "c_count"; + goto fail; + } + if ( count >= BDB_IDL_DB_SIZE ) { + /* No room, convert to a range */ + lo = tmp; + data.data = &hi; + rc = cursor->c_get( cursor, key, &data, DB_LAST ); + if ( rc != 0 ) { + err = "c_get last"; + goto fail; + } + if ( id < lo ) + lo = id; + else if ( id > hi ) + hi = id; + rc = db->del( db, tid, key, 0 ); + if ( rc != 0 ) { + err = "del"; + goto fail; + } + data.data = &id; + id = 0; + rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); + if ( rc != 0 ) { + err = "c_put 0"; + goto fail; + } + id = lo; + rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); + if ( rc != 0 ) { + err = "c_put lo"; + goto fail; + } + id = hi; + rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); + if ( rc != 0 ) { + err = "c_put hi"; + goto fail; + } + } else { + /* There's room, just store it */ + goto put1; + } + } else { + /* It's a range, see if we need to rewrite + * the boundaries + */ + hi = id; + data.data = &lo; + rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); + if ( rc != 0 ) { + err = "c_get lo"; + goto fail; + } + if ( id > lo ) { + data.data = &hi; + rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); + if ( rc != 0 ) { + err = "c_get hi"; + goto fail; + } + } + if ( id < lo || id > hi ) { + /* Delete the current lo/hi */ + rc = cursor->c_del( cursor, 0 ); + if ( rc != 0 ) { + err = "c_del"; + goto fail; + } + data.data = &id; + rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); + if ( rc != 0 ) { + err = "c_put lo/hi"; + goto fail; + } + } + } + } else if ( rc == DB_NOTFOUND ) { +put1: data.data = &id; + rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); + /* Don't worry if it's already there */ + if ( rc != 0 && rc != DB_KEYEXIST ) { + err = "c_put id"; + goto fail; + } + } else { + /* initial c_get failed, nothing was done */ +fail: +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: %s failed: %s (%d)\n", err, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); +#endif + cursor->c_close( cursor ); + return rc; + } + rc = cursor->c_close( cursor ); + } +#else /* !BDB_IDL_MULTI */ + data.data = ids; + data.ulen = sizeof ids; + data.flags = DB_DBT_USERMEM; + + /* fetch the key for read/modify/write */ + rc = db->get( db, tid, key, &data, DB_RMW | bdb->bi_db_opflags ); + + if( rc == DB_NOTFOUND ) { + ids[0] = 1; + ids[1] = id; + data.size = 2 * sizeof( ID ); + + } else if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: get failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "get failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + return rc; + + } else if ( data.size == 0 || data.size % sizeof( ID ) ) { + /* size not multiple of ID size */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "odd size: expected %ld multiple, got %ld\n", + (long) sizeof( ID ), (long) data.size, 0 ); +#endif + return -1; + + } else if ( data.size != BDB_IDL_SIZEOF(ids) ) { + /* size mismatch */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: odd size: expected %ld multiple, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "get size mismatch: expected %ld, got %ld\n", + (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); +#endif + return -1; + + } else if ( BDB_IDL_IS_RANGE(ids) ) { + if( id < ids[1] ) { + ids[1] = id; + } else if ( ids[2] > id ) { + ids[2] = id; + } else { + return 0; + } + + } else { + rc = bdb_idl_insert( ids, id ); + + if( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_DETAIL1, "bdb_idl_insert_key: dup\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_idl_insert_key: dup\n", + 0, 0, 0 ); +#endif + return 0; + } + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: insert failed: (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "bdb_idl_insert failed (%d)\n", + rc, 0, 0 ); +#endif + + return rc; + } + + data.size = BDB_IDL_SIZEOF( ids ); + } + + /* store the key */ + rc = db->put( db, tid, key, &data, 0 ); +#endif + if( rc == DB_KEYEXIST ) rc = 0; + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_insert_key: put failed: (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " + "put failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + } + return rc; +} + +int +bdb_idl_delete_key( + BackendDB *be, + DB *db, + DB_TXN *tid, + DBT *key, + ID id ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + DBT data; +#ifndef BDB_IDL_MULTI + ID ids[BDB_IDL_DB_SIZE]; +#endif + +#if 0 + /* for printable keys only */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ARGS, "bdb_idl_delete_key: %s %ld\n", (char *)key->data, (long) id )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> bdb_idl_delete_key: %s %ld\n", + (char *)key->data, (long) id, 0 ); +#endif +#endif + + assert( id != NOID ); + + DBTzero( &data ); +#ifdef BDB_IDL_MULTI + { + DBC *cursor; + ID lo, hi, tmp; + char *err; + + data.data = &tmp; + data.size = sizeof( id ); + data.ulen = data.size; + data.flags = DB_DBT_USERMEM; + + rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: cursor failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif + return rc; + } + /* Fetch the first data item for this key, to see if it + * exists and if it's a range. + */ + rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW ); + err = "c_get"; + if ( rc == 0 ) { + if ( tmp != 0 ) { + /* Not a range, just delete it */ + data.data = &id; + rc = cursor->c_get( cursor, key, &data, + DB_GET_BOTH | DB_RMW ); + if ( rc == 0 ) { + rc = cursor->c_del( cursor, 0 ); + if ( rc != 0 ) { + err = "c_del id"; + goto fail; + } + } + } else { + /* It's a range, see if we need to rewrite + * the boundaries + */ + hi = 0; + data.data = &lo; + rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); + if ( rc != 0 ) { + err = "c_get lo"; + goto fail; + } + if ( id > lo ) { + data.data = &hi; + rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); + if ( rc != 0 ) { + err = "c_get hi"; + goto fail; + } + } + if ( id == lo || id == hi ) { + if ( id == lo ) { + id++; + lo = id; + } else if ( id == hi ) { + id--; + hi = id; + } + if ( lo >= hi ) { + /* The range has collapsed... */ + rc = db->del( db, tid, key, 0 ); + if ( rc != 0 ) { + err = "del"; + goto fail; + } + } else { + rc = cursor->c_del( cursor, 0 ); + if ( rc != 0 ) { + err = "c_del"; + goto fail; + } + } + if ( lo <= hi ) { + data.data = &id; + rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); + if ( rc != 0 ) { + err = "c_put lo/hi"; + goto fail; + } + } + } + } + } else { + /* initial c_get failed, nothing was done */ +fail: +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: %s failed: %s (%d)\n", err, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); +#endif + cursor->c_close( cursor ); + return rc; + } + rc = cursor->c_close( cursor ); + } +#else + data.data = ids; + data.ulen = sizeof( ids ); + data.flags = DB_DBT_USERMEM; + + /* fetch the key for read/modify/write */ + rc = db->get( db, tid, key, &data, DB_RMW | bdb->bi_db_opflags ); + + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: get failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "get failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + return rc; + + } else if ( data.size == 0 || data.size % sizeof( ID ) ) { + /* size not multiple of ID size */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: odd size: expected: %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "odd size: expected %ld multiple, got %ld\n", + (long) sizeof( ID ), (long) data.size, 0 ); +#endif + return -1; + + } else if ( BDB_IDL_IS_RANGE(ids) ) { + return 0; + + } else if ( data.size != (1 + ids[0]) * sizeof( ID ) ) { + /* size mismatch */ +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: get size mismatch: expected: %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "get size mismatch: expected %ld, got %ld\n", + (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); +#endif + return -1; + + } else { + rc = idl_delete( ids, id ); + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: delete failed: (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "idl_delete failed (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + if( ids[0] == 0 ) { + /* delete the key */ + rc = db->del( db, tid, key, 0 ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: delete failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " + "delete failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + } + return rc; + } + + data.size = (ids[0]+1) * sizeof( ID ); + } + + /* store the key */ + rc = db->put( db, tid, key, &data, 0 ); + +#endif /* BDB_IDL_MULTI */ + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, "bdb_idl_delete_key: put failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_idl_delete_key: put failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + } + + return rc; +} + + +/* + * idl_intersection - return a = a intersection b + */ +int +bdb_idl_intersection( + ID *a, + ID *b ) +{ + ID ida, idb; + ID idmax, idmin; + ID cursora = 0, cursorb = 0, cursorc; + int swap = 0; + + if ( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) ) { + a[0] = 0; + return 0; + } + + idmin = IDL_MAX( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) ); + idmax = IDL_MIN( BDB_IDL_LAST(a), BDB_IDL_LAST(b) ); + if ( idmin > idmax ) { + a[0] = 0; + return 0; + } else if ( idmin == idmax ) { + a[0] = 1; + a[1] = idmin; + return 0; + } + + if ( BDB_IDL_IS_RANGE( a ) && BDB_IDL_IS_RANGE(b) ) { + a[1] = idmin; + a[2] = idmax; + return 0; + } + + if ( BDB_IDL_IS_RANGE( a ) ) { + ID *tmp = a; + a = b; + b = tmp; + swap = 1; + } + + if ( BDB_IDL_IS_RANGE( b ) && BDB_IDL_FIRST( b ) <= idmin && + BDB_IDL_LAST( b ) >= idmax) { + if (idmax - idmin + 1 == a[0]) + { + a[0] = NOID; + a[1] = idmin; + a[2] = idmax; + } + goto done; + } + + ida = bdb_idl_first( a, &cursora ); + idb = bdb_idl_first( b, &cursorb ); + cursorc = 0; + + while( ida < idmin ) + ida = bdb_idl_next( a, &cursora ); + while( idb < idmin ) + idb = bdb_idl_next( b, &cursorb ); + + while( ida <= idmax || idb <= idmax ) { + if( ida == idb ) { + a[++cursorc] = ida; + ida = bdb_idl_next( a, &cursora ); + idb = bdb_idl_next( b, &cursorb ); + } else if ( ida < idb ) { + ida = bdb_idl_next( a, &cursora ); + } else { + idb = bdb_idl_next( b, &cursorb ); + } + } + a[0] = cursorc; +done: + if (swap) + BDB_IDL_CPY( b, a ); + + return 0; +} + + +/* + * idl_union - return a = a union b + */ +int +bdb_idl_union( + ID *a, + ID *b ) +{ + ID ida, idb; + ID cursora = 0, cursorb = 0, cursorc; + + if ( BDB_IDL_IS_ZERO( b ) ) { + return 0; + } + + if ( BDB_IDL_IS_ZERO( a ) ) { + BDB_IDL_CPY( a, b ); + return 0; + } + + if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) ) { +over: a[1] = IDL_MIN( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) ); + a[2] = IDL_MAX( BDB_IDL_LAST(a), BDB_IDL_LAST(b) ); + return 0; + } + + ida = bdb_idl_first( a, &cursora ); + idb = bdb_idl_first( b, &cursorb ); + + cursorc = b[0]; + + /* The distinct elements of a are cat'd to b */ + while( ida != NOID || idb != NOID ) { + if ( ida < idb ) { + if( ++cursorc > BDB_IDL_UM_MAX ) { + a[0] = NOID; + goto over; + } + b[cursorc] = ida; + ida = bdb_idl_next( a, &cursora ); + + } else { + if ( ida == idb ) + ida = bdb_idl_next( a, &cursora ); + idb = bdb_idl_next( b, &cursorb ); + } + } + + /* b is copied back to a in sorted order */ + a[0] = cursorc; + cursora = 1; + cursorb = 1; + cursorc = b[0]+1; + while (cursorb <= b[0] || cursorc <= a[0]) { + if (cursorc > a[0]) + idb = NOID; + else + idb = b[cursorc]; + if (b[cursorb] < idb) + a[cursora++] = b[cursorb++]; + else { + a[cursora++] = idb; + cursorc++; + } + } + + return 0; +} + + +#if 0 +/* + * bdb_idl_notin - return a intersection ~b (or a minus b) + */ +int +bdb_idl_notin( + ID *a, + ID *b, + ID *ids ) +{ + ID ida, idb; + ID cursora = 0, cursorb = 0; + + if( BDB_IDL_IS_ZERO( a ) || + BDB_IDL_IS_ZERO( b ) || + BDB_IDL_IS_RANGE( b ) ) + { + BDB_IDL_CPY( ids, a ); + return 0; + } + + if( BDB_IDL_IS_RANGE( a ) ) { + BDB_IDL_CPY( ids, a ); + return 0; + } + + ida = bdb_idl_first( a, &cursora ), + idb = bdb_idl_first( b, &cursorb ); + + ids[0] = 0; + + while( ida != NOID ) { + if ( idb == NOID ) { + /* we could shortcut this */ + ids[++ids[0]] = ida; + ida = bdb_idl_next( a, &cursora ); + + } else if ( ida < idb ) { + ids[++ids[0]] = ida; + ida = bdb_idl_next( a, &cursora ); + + } else if ( ida > idb ) { + idb = bdb_idl_next( b, &cursorb ); + + } else { + ida = bdb_idl_next( a, &cursora ); + idb = bdb_idl_next( b, &cursorb ); + } + } + + return 0; +} +#endif + +ID bdb_idl_first( ID *ids, ID *cursor ) +{ + ID pos; + + if ( ids[0] == 0 ) { + *cursor = NOID; + return NOID; + } + + if ( BDB_IDL_IS_RANGE( ids ) ) { + if( *cursor < ids[1] ) { + *cursor = ids[1]; + } + return *cursor; + } + + if ( *cursor == 0 ) + pos = 1; + else + pos = bdb_idl_search( ids, *cursor ); + + if( pos > ids[0] ) { + return NOID; + } + + *cursor = pos; + return ids[pos]; +} + +ID bdb_idl_next( ID *ids, ID *cursor ) +{ + if ( BDB_IDL_IS_RANGE( ids ) ) { + if( ids[2] < ++(*cursor) ) { + return NOID; + } + return *cursor; + } + + if ( ++(*cursor) <= ids[0] ) { + return ids[*cursor]; + } + + return NOID; +} diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index ccd08dc62bfb4135d676be3c230956b62d70df17..d0c27ba340abb03ddcbce38eb1d1d22cf8948d6a 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -60,9 +60,13 @@ bdb_db_init( BackendDB *be ) { struct bdb_info *bdb; +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ENTRY, "bdb_db_init" )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_init: Initializing BDB database\n", 0, 0, 0 ); +#endif /* indicate system schema supported */ be->be_flags |= @@ -94,7 +98,8 @@ bdb_db_init( BackendDB *be ) ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex ); ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex ); - ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_mutex ); + ldap_pvt_thread_mutex_init( &bdb->bi_cache.lru_mutex ); + ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock ); #ifdef BDB_HIER ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr ); #endif @@ -120,9 +125,13 @@ static void *lock_detect_task( void *arg ) break; } +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_init: aborted %d locks\n", aborted )); +#else Debug( LDAP_DEBUG_ANY, "bdb_lock_detect: aborted %d locks\n", aborted, 0, 0 ); +#endif } return NULL; @@ -161,17 +170,25 @@ bdb_db_open( BackendDB *be ) struct bdb_info *bdb = (struct bdb_info *) be->be_private; u_int32_t flags; +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ARGS, "bdb_db_open: %s\n", be->be_suffix[0]->bv_val )); +#else Debug( LDAP_DEBUG_ARGS, "bdb_db_open: %s\n", be->be_suffix[0]->bv_val, 0, 0 ); +#endif /* we should check existance of dbenv_home and db_directory */ rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: db_env_create failed: %s (%d)\n", db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: db_env_create failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif return rc; } @@ -194,9 +211,13 @@ bdb_db_open( BackendDB *be ) rc = bdb->bi_dbenv->set_tmp_dir( bdb->bi_dbenv, dir ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc ); +#endif return rc; } @@ -204,9 +225,13 @@ bdb_db_open( BackendDB *be ) rc = bdb->bi_dbenv->set_lg_dir( bdb->bi_dbenv, dir ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc ); +#endif return rc; } @@ -214,26 +239,38 @@ bdb_db_open( BackendDB *be ) rc = bdb->bi_dbenv->set_data_dir( bdb->bi_dbenv, dir ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: set_data_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: set_data_dir(%s) failed: %s (%d)\n", dir, db_strerror(rc), rc ); +#endif return rc; } } #endif +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_DETAIL1, "bdb_db_open: dbenv_open %s\n", bdb->bi_dbenv_home )); +#else Debug( LDAP_DEBUG_TRACE, "bdb_db_open: dbenv_open(%s)\n", bdb->bi_dbenv_home, 0, 0); +#endif rc = bdb->bi_dbenv->open( bdb->bi_dbenv, bdb->bi_dbenv_home, flags, bdb->bi_dbenv_mode ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: dbenv_open failed: %s (%d)\n", db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: dbenv_open failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif return rc; } @@ -241,9 +278,13 @@ bdb_db_open( BackendDB *be ) rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv, bdb->bi_dbenv_xflags, 1); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: dbenv_set_flags failed: %s (%d)\n", db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: dbenv_set_flags failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif return rc; } } @@ -261,9 +302,13 @@ bdb_db_open( BackendDB *be ) rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); +#endif return rc; } @@ -294,9 +339,13 @@ bdb_db_open( BackendDB *be ) bdb->bi_dbenv_mode ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: db_open(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); +#endif return rc; } @@ -310,9 +359,13 @@ bdb_db_open( BackendDB *be ) /* get nextid */ rc = bdb_last_id( be, NULL ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_open: last_id(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_open: last_id(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); +#endif return rc; } @@ -365,9 +418,13 @@ bdb_db_destroy( BackendDB *be ) /* force a checkpoint */ rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE ); if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_destroy: txn_checkpoint failed: %s (%d)\n", db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_destroy: txn_checkpoint failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif } bdb_cache_release_all (&bdb->bi_cache); @@ -375,9 +432,13 @@ bdb_db_destroy( BackendDB *be ) rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); bdb->bi_dbenv = NULL; if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_destroy: close failed: %s (%d)\n", db_strerror(rc), rc )); +#else Debug( LDAP_DEBUG_ANY, "bdb_db_destroy: close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); +#endif return rc; } } @@ -417,8 +478,12 @@ bdb_initialize( bi->bi_controls = controls; /* initialize the underlying database system */ +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ENTRY, "bdb_db_initialize\n" )); +#else Debug( LDAP_DEBUG_TRACE, "bdb_open: initialize BDB backend\n", 0, 0, 0 ); +#endif { /* version check */ int major, minor, patch; @@ -428,14 +493,22 @@ bdb_initialize( minor != DB_VERSION_MINOR || patch < DB_VERSION_PATCH ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_ERR, "bdb_db_initialize: version mismatch: \texpected: %s \tgot: %s\n", DB_VERSION_STRING, version )); +#else Debug( LDAP_DEBUG_ANY, "bdb_open: version mismatch\n" "\texpected: " DB_VERSION_STRING "\n" "\tgot: %s \n", version, 0, 0 ); +#endif } +#ifdef NEW_LOGGING + LDAP_LOG(( "init", LDAP_LEVEL_DETAIL1, "bdb_db_initialize: bdb_open: %s\n", version )); +#else Debug( LDAP_DEBUG_ANY, "bdb_open: %s\n", version, 0, 0 ); +#endif } #if 0 @@ -490,6 +563,7 @@ bdb_initialize( #endif bi->bi_chk_referrals = bdb_referrals; + bi->bi_operational = bdb_operational; bi->bi_entry_release_rw = bdb_entry_release; /* diff --git a/servers/slapd/back-bdb/key.c b/servers/slapd/back-bdb/key.c new file mode 100644 index 0000000000000000000000000000000000000000..ea6433fa6eebf38301a286322ef24ab24c3ff452 --- /dev/null +++ b/servers/slapd/back-bdb/key.c @@ -0,0 +1,109 @@ +/* index.c - routines for dealing with attribute indexes */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "back-bdb.h" +#include "idl.h" + +/* read a key */ +int +bdb_key_read( + Backend *be, + DB *db, + DB_TXN *txn, + struct berval *k, + ID *ids +) +{ + int rc; + DBT key; + +#ifdef NEW_LOGGING + LDAP_LOG(( "index", LDAP_LEVEL_ENTRY, + "key_read: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> key_read\n", 0, 0, 0 ); +#endif + + DBTzero( &key ); + bv2DBT(k,&key); + + rc = bdb_idl_fetch_key( be, db, txn, &key, ids ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "index", LDAP_LEVEL_ERR, + "bdb_key_read: failed (%d)\n", + rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_index_read: failed (%d)\n", + rc, 0, 0 ); +#endif + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "index", LDAP_LEVEL_DETAIL1, + "bdb_key_read: %ld candidates\n", (long) BDB_IDL_N(ids) )); +#else + Debug( LDAP_DEBUG_TRACE, "<= bdb_index_read %ld candidates\n", + (long) BDB_IDL_N(ids), 0, 0 ); +#endif + } + + return rc; +} + +/* Add or remove stuff from index files */ +int +bdb_key_change( + Backend *be, + DB *db, + DB_TXN *txn, + struct berval *k, + ID id, + int op +) +{ + int rc; + DBT key; + +#ifdef NEW_LOGGING + LDAP_LOG(( "index", LDAP_LEVEL_DETAIL1, + "key_change: %s ID %lx\n", + op == SLAP_INDEX_ADD_OP ? "Add" : "Delete", (long) id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> key_change(%s,%lx)\n", + op == SLAP_INDEX_ADD_OP ? "ADD":"DELETE", (long) id, 0 ); +#endif + + DBTzero( &key ); + bv2DBT(k,&key); + + if (op == SLAP_INDEX_ADD_OP) { + /* Add values */ + rc = bdb_idl_insert_key( be, db, txn, &key, id ); + + } else { + /* Delete values */ + rc = bdb_idl_delete_key( be, db, txn, &key, id ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "index", LDAP_LEVEL_RESULTS, + "key_change: return %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= key_change %d\n", rc, 0, 0 ); +#endif + + return rc; +} diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c new file mode 100644 index 0000000000000000000000000000000000000000..d3fde84883d9ce42989e7bfaad5f27228c80a9c2 --- /dev/null +++ b/servers/slapd/back-bdb/modify.c @@ -0,0 +1,467 @@ +/* modify.c - bdb backend modify routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "back-bdb.h" +#include "external.h" + +int bdb_modify_internal( + BackendDB *be, + Connection *conn, + Operation *op, + DB_TXN *tid, + Modifications *modlist, + Entry *e, + const char **text, + char *textbuf, + size_t textlen ) +{ + int rc, err; + Modification *mod; + Modifications *ml; + Attribute *save_attrs; + Attribute *ap; + +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY,"bdb_modify_internal: 0x%08lx: %s\n", e->e_id, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modify_internal: 0x%08lx: %s\n", + e->e_id, e->e_dn, 0); +#endif + + if ( !acl_check_modlist( be, conn, op, e, modlist )) { + return LDAP_INSUFFICIENT_ACCESS; + } + + save_attrs = e->e_attrs; + e->e_attrs = attrs_dup( e->e_attrs ); + + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + mod = &ml->sml_mod; + + switch ( mod->sm_op ) { + case LDAP_MOD_ADD: +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify_internal: add\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: add\n", 0, 0, 0); +#endif + err = modify_add_values( e, mod, text, textbuf, textlen ); + if( err != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); +#endif + } + break; + + case LDAP_MOD_DELETE: +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify_internal: delete\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: delete\n", 0, 0, 0); +#endif + err = modify_delete_values( e, mod, text, textbuf, textlen ); + assert( err != LDAP_TYPE_OR_VALUE_EXISTS ); + if( err != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); +#endif + } + break; + + case LDAP_MOD_REPLACE: +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify_internal: replace\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0); +#endif + err = modify_replace_values( e, mod, text, textbuf, textlen ); + assert( err != LDAP_TYPE_OR_VALUE_EXISTS ); + if( err != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); +#endif + } + break; + + case SLAP_MOD_SOFTADD: +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify_internal: softadd\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: softadd\n", 0, 0, 0); +#endif + /* Avoid problems in index_add_mods() + * We need to add index if necessary. + */ + mod->sm_op = LDAP_MOD_ADD; + + err = modify_add_values( e, mod, text, textbuf, textlen ); + if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { + err = LDAP_SUCCESS; + } + + if( err != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); +#endif + } + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: invalid op %d\n", mod->sm_op )); +#else + Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n", + mod->sm_op, 0, 0); +#endif + *text = "Invalid modify operation"; + err = LDAP_OTHER; +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); +#endif + } + + if ( err != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; + /* unlock entry, delete from cache */ + return err; + } + + /* If objectClass was modified, reset the flags */ + if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { + e->e_ocflags = 0; + } + + /* check if modified attribute was indexed */ + err = bdb_index_is_indexed( be, mod->sm_desc ); + if ( err == LDAP_SUCCESS ) { + ap = attr_find( save_attrs, mod->sm_desc ); + if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL; + + ap = attr_find( e->e_attrs, mod->sm_desc ); + if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD; + } + } + + /* check that the entry still obeys the schema */ + rc = entry_schema_check( be, e, save_attrs, text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: entry failed schema check %s\n", *text )); +#else + Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", + *text, 0, 0 ); +#endif + return rc; + } + + /* update the indices of the modified attributes */ + + /* start with deleting the old index entries */ + for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { + if ( ap->a_flags & SLAP_ATTR_IXDEL ) { + rc = bdb_index_values( be, tid, ap->a_desc, ap->a_vals, + e->e_id, SLAP_INDEX_DELETE_OP ); + if ( rc != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: attribute index delete failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "Attribute index delete failure", + 0, 0, 0 ); +#endif + return rc; + } + ap->a_flags &= ~SLAP_ATTR_IXDEL; + } + } + + /* add the new index entries */ + for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { + if (ap->a_flags & SLAP_ATTR_IXADD) { + rc = bdb_index_values( be, tid, ap->a_desc, ap->a_vals, + e->e_id, SLAP_INDEX_ADD_OP ); + if ( rc != LDAP_SUCCESS ) { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: attribute index add failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "Attribute index add failure", + 0, 0, 0 ); +#endif + return rc; + } + ap->a_flags &= ~SLAP_ATTR_IXADD; + } + } + + return rc; +} + + +int +bdb_modify( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + Modifications *modlist ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + Entry *matched; + Entry *e; + int manageDSAit = get_manageDSAit( op ); + const char *text = NULL; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; + +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY, "bdb_modify: %s\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "bdb_modify: %s\n", dn->bv_val, 0, 0 ); +#endif + + if( 0 ) { +retry: /* transaction retry */ + if( e != NULL ) { + bdb_cache_delete_entry(&bdb->bi_cache, e); + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: retrying...\n" )); +#else + Debug(LDAP_DEBUG_TRACE, + "bdb_modify: retrying...\n", 0, 0, 0); +#endif + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + bdb->bi_db_opflags ); + text = NULL; + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: txn_begin failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 ); + + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: dn2entry failed: (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: dn2entry failed (%d)\n", + rc, 0, 0 ); +#endif + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case DB_NOTFOUND: + break; + default: + rc = LDAP_OTHER; + } + text = "internal error"; + goto return_results; + } + + /* acquire and lock entry */ + if ( e == NULL ) { + char* matched_dn = NULL; + BerVarray refs; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_cache_return_entry_r (&bdb->bi_cache, matched); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + free( matched_dn ); + + return rc; + } + + if ( !manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow modify */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: entry is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: entry is referral\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + goto done; + } + + /* Modify the entry */ + rc = bdb_modify_internal( be, conn, op, ltid, modlist, e, + &text, textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify: modify failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: modify failed (%d)\n", + rc, 0, 0 ); +#endif + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + goto return_results; + } + + /* change the entry itself */ + rc = bdb_id2entry_update( be, ltid, e ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify: id2entry update failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: id2entry update failed (%d)\n", + rc, 0, 0 ); +#endif + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + text = "entry update failed"; + goto return_results; + } + + if( op->o_noop ) { + rc = TXN_ABORT( ltid ); + } else { + rc = TXN_COMMIT( ltid, 0 ); + } + ltid = NULL; + op->o_private = NULL; + + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify: txn_%s failed %s (%d)\n", op->o_noop ? "abort (no_op)" : "commit", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: txn_%s failed: %s (%d)\n", + op->o_noop ? "abort (no-op)" : "commit", + db_strerror(rc), rc ); +#endif + rc = LDAP_OTHER; + text = "commit failed"; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: updated%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no_op)" : "", e->e_id, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: updated%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", + e->e_id, e->e_dn ); +#endif + rc = LDAP_SUCCESS; + text = NULL; + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + ldap_pvt_thread_yield(); + TXN_CHECKPOINT( bdb->bi_dbenv, + bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); + } + +done: + if( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + if( e != NULL ) { + bdb_cache_return_entry_w (&bdb->bi_cache, e); + } + return rc; +} diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c new file mode 100644 index 0000000000000000000000000000000000000000..bc8fb973616c3cc6923ab3eaa09e6beca2baf204 --- /dev/null +++ b/servers/slapd/back-bdb/modrdn.c @@ -0,0 +1,867 @@ +/* modrdn.c - bdb backend modrdn routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_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 ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + AttributeDescription *children = slap_schema.si_ad_children; + struct berval p_dn, p_ndn; + struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; + int isroot = -1; + Entry *e, *p = NULL; + Entry *matched; + int rc; + const char *text; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + DB_TXN * ltid = NULL; + struct bdb_op_info opinfo; + + ID id; + int a_cnt, d_cnt; + LDAPRDN *new_rdn = NULL; + LDAPRDN *old_rdn = NULL; + + Entry *np = NULL; /* newSuperior Entry */ + struct berval *np_dn = NULL; /* newSuperior dn */ + struct berval *np_ndn = NULL; /* newSuperior ndn */ + struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ + + /* Used to interface with bdb_modify_internal() */ + Modifications *mod = NULL; /* Used to delete old rdn */ + + int manageDSAit = get_manageDSAit( op ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", + dn->bv_val,newrdn->bv_val, + newSuperior ? newSuperior->bv_val : "NULL" )); +#else + Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n", + dn->bv_val, newrdn->bv_val, + newSuperior ? newSuperior->bv_val : "NULL" ); +#endif + +#if 0 + if( newSuperior != NULL ) { + rc = LDAP_UNWILLING_TO_PERFORM; + text = "newSuperior not implemented (yet)"; + goto return_results; + } +#endif + + if( 0 ) { +retry: /* transaction retry */ + if (e != NULL) { + bdb_cache_delete_entry(&bdb->bi_cache, e); + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } + if (p != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, p); + } + if (np != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, np); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: retrying...\n")); +#else + Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 ); +#endif + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + bdb->bi_db_opflags ); + text = NULL; + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: txn_begin failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if ( e == NULL ) { + char* matched_dn = NULL; + BerVarray refs; + + if( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + matched = NULL; + + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + free( matched_dn ); + + goto done; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: entry %s is referral \n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n", + e->e_dn, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvarray_free( refs ); + goto done; + } + + if ( be_issuffix( be, &e->e_nname ) ) { + p_ndn = slap_empty_bv; + } else { + dnParent( &e->e_nname, &p_ndn ); + } + np_ndn = &p_ndn; + if ( p_ndn.bv_len != 0 ) { + /* Make sure parent entry exist and we can write its + * children. + */ + rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( p == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: parent does not exist\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n", + 0, 0, 0); +#endif + rc = LDAP_OTHER; + goto return_results; + } + + /* check parent for "children" acl */ + if ( ! access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: no access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, + 0, 0 ); +#endif + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to children of entry %s OK\n", + p_ndn.bv_val, 0, 0 ); +#endif + + if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { + p_dn = slap_empty_bv; + } else { + dnParent( &e->e_name, &p_dn ); + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: parent dn=%s\n", + p_dn.bv_val, 0, 0 ); +#endif + + } else { + /* no parent, modrdn entry directly under root */ + isroot = be_isroot( be, &op->o_ndn ); + if ( ! isroot ) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) + || be_isupdate( be, &op->o_ndn ) ) { + + p = (Entry *)&slap_entry_root; + + /* check parent for "children" acl */ + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + + p = NULL; + + if ( ! rc ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: no access to parent\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "no access to parent\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: wr to children of entry \"\" OK\n", p_dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to children of entry \"\" OK\n", + 0, 0, 0 ); +#endif + + p_dn.bv_val = ""; + p_dn.bv_len = 0; + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: parent dn=\"\" \n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: parent dn=\"\"\n", + 0, 0, 0 ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: no parent, not root &\"\" is not suffix\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: no parent, not root " + "& \"\" is not suffix\n", + 0, 0, 0); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + } + } + + new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ + + if ( newSuperior != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: new parent \"%s\" requested...\n", newSuperior->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new parent \"%s\" requested...\n", + newSuperior->bv_val, 0, 0 ); +#endif + + if ( newSuperior->bv_len ) { + np_dn = newSuperior; + np_ndn = nnewSuperior; + + /* newSuperior == oldParent?, if so ==> ERROR */ + /* newSuperior == entry being moved?, if so ==> ERROR */ + /* Get Entry with dn=newSuperior. Does newSuperior exist? */ + + rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0 ); + + switch( rc ) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + + if( np == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: newSup(ndn=%s) not here!\n", np_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: newSup(ndn=%s) not here!\n", + np_ndn->bv_val, 0, 0); +#endif + rc = LDAP_OTHER; + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", np, (long) np->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", + np, (long) np->e_id, 0 ); +#endif + + /* check newSuperior for "children" acl */ + if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE, NULL ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: no wr to newSup children\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: no wr to newSup children\n", + 0, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + +#ifdef BDB_ALIASES + if ( is_entry_alias( np ) ) { + /* parent is an alias, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: entry is alias\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n", + 0, 0, 0 ); +#endif + + rc = LDAP_ALIAS_PROBLEM; + goto return_results; + } +#endif + + if ( is_entry_referral( np ) ) { + /* parent is a referral, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: entry is referral\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n", + 0, 0, 0 ); +#endif + + rc = LDAP_OPERATIONS_ERROR; + goto return_results; + } + + } else { + if ( isroot == -1 ) { + isroot = be_isroot( be, &op->o_ndn ); + } + + np_dn = NULL; + + /* no parent, modrdn entry directly under root */ + if ( ! isroot ) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) + || be_isupdate( be, &op->o_ndn ) ) { + np = (Entry *)&slap_entry_root; + + /* check parent for "children" acl */ + rc = access_allowed( be, conn, op, np, + children, NULL, ACL_WRITE, NULL ); + + np = NULL; + + if ( ! rc ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "==>bdb_modrdn: no access to superior\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "no access to new superior\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "bdb_modrdn: wr to children entry \"\" OK\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to children of entry \"\" OK\n", + 0, 0, 0 ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: new superior=\"\", not root & \"\" is not suffix\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new superior=\"\", not root " + "& \"\" is not suffix\n", + 0, 0, 0); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "bdb_modrdn: new superior=\"\"\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new superior=\"\"\n", + 0, 0, 0 ); +#endif + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "bdb_modrdn: wr to new parent's children OK\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: wr to new parent's children OK\n", + 0, 0, 0 ); +#endif + + new_parent_dn = np_dn; + } + + /* Build target dn and make sure target entry doesn't exist already. */ + build_new_dn( &new_dn, new_parent_dn, newrdn ); + + dnNormalize2( NULL, &new_dn, &new_ndn ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_RESULTS, "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n", + new_ndn.bv_val, 0, 0 ); +#endif + + rc = bdb_dn2id ( be, ltid, &new_ndn, &id ); + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case DB_NOTFOUND: + break; + case 0: + rc = LDAP_ALREADY_EXISTS; + goto return_results; + default: + rc = LDAP_OTHER; + text = "internal error"; + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: new ndn=%s does not exist\n", new_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new ndn=%s does not exist\n", + new_ndn.bv_val, 0, 0 ); +#endif + + /* Get attribute type and attribute value of our new rdn, we will + * need to add that to our new entry + */ + if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: can't figure out type(s)/values(s) of newrdn\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: can't figure out type(s)/values(s) " + "of newrdn\n", 0, 0, 0 ); +#endif + rc = LDAP_OPERATIONS_ERROR; + text = "unknown type(s) used in RDN"; + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_RESULTS, "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", + new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val, 0 ); +#endif + + if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: can't figure out type(s)/values(s) of old_rdn\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_back_modrdn: can't figure out the old_rdn " + "type(s)/value(s)\n", 0, 0, 0 ); +#endif + rc = LDAP_OTHER; + text = "cannot parse RDN from old DN"; + goto return_results; + } + +#if 0 + if ( newSuperior == NULL + && charray_strcasecmp( ( const char ** )old_rdn_types, + ( const char ** )new_rdn_types ) != 0 ) { + /* Not a big deal but we may say something */ +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: old_rdn_type(s)=%s, new_rdn_type(s)=%s do not match\n", old_rdn_types[ 0 ], new_rdn_types[ 0 ] )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: old_rdn_type(s)=%s, new_rdn_type(s)=%s " + "do not match\n", + old_rdn_types[ 0 ], new_rdn_types[ 0 ], 0 ); +#endif + } +#endif + + /* Add new attribute values to the entry */ + for ( a_cnt = 0; new_rdn[0][ a_cnt ]; a_cnt++ ) { + int rc; + AttributeDescription *desc = NULL; + Modifications *mod_tmp; + + rc = slap_bv2ad( &new_rdn[0][ a_cnt ]->la_attr, &desc, &text ); + + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: %s: %s (new)\n", text, new_rdn[0][a_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: %s: %s (new)\n", + text, new_rdn[0][ a_cnt ]->la_attr.bv_val, 0 ); +#endif + goto return_results; + } + + /* ACL check of newly added attrs */ + if ( !access_allowed( be, conn, op, e, desc, + &new_rdn[0][ a_cnt ]->la_value, ACL_WRITE, NULL ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: access to attr \"%s\" (new) not allowed\n", new_rdn[0][a_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: access to attr \"%s\" " + "(new) not allowed\n", + new_rdn[0][ a_cnt ]->la_attr.bv_val, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + /* Apply modification */ + mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) + + 2 * sizeof( struct berval ) ); + mod_tmp->sml_desc = desc; + mod_tmp->sml_bvalues = ( BerVarray )( mod_tmp + 1 ); + mod_tmp->sml_bvalues[ 0 ] = new_rdn[0][ a_cnt ]->la_value; + mod_tmp->sml_bvalues[ 1 ].bv_val = NULL; + mod_tmp->sml_op = SLAP_MOD_SOFTADD; + mod_tmp->sml_next = mod; + mod = mod_tmp; + } + + /* Remove old rdn value if required */ + if ( deleteoldrdn ) { + /* Get value of old rdn */ + if ( old_rdn == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: can't figure out old RDN values(s) from old RDN\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: can't figure out old RDN value(s) " + "from old RDN\n", 0, 0, 0 ); +#endif + rc = LDAP_OTHER; + text = "could not parse value(s) from old RDN"; + goto return_results; + } + + for ( d_cnt = 0; old_rdn[0][ d_cnt ]; d_cnt++ ) { + int rc; + AttributeDescription *desc = NULL; + Modifications *mod_tmp; + + rc = slap_bv2ad( &old_rdn[0][ d_cnt ]->la_attr, + &desc, &text ); + + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: %s: %s (old)\n", text, old_rdn[0][d_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: %s: %s (old)\n", + text, old_rdn[0][ d_cnt ]->la_attr.bv_val, 0 ); +#endif + goto return_results; + } + + /* ACL check of newly added attrs */ + if ( !access_allowed( be, conn, op, e, desc, + &old_rdn[0][d_cnt]->la_value, ACL_WRITE, NULL ) ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_ERR, "bdb_modrdn: access to attr \"%s\" (old) not allowed\n", old_rdn[0][d_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: access to attr \"%s\" " + "(old) not allowed\n", + old_rdn[0][ d_cnt ]->la_attr.bv_val, 0, 0 ); +#endif + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + /* Apply modification */ + mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) + + 2 * sizeof ( struct berval ) ); + mod_tmp->sml_desc = desc; + mod_tmp->sml_bvalues = ( BerVarray )(mod_tmp+1); + mod_tmp->sml_bvalues[ 0 ] = old_rdn[0][ d_cnt ]->la_value; + mod_tmp->sml_bvalues[ 1 ].bv_val = NULL; + mod_tmp->sml_op = LDAP_MOD_DELETE; + mod_tmp->sml_next = mod; + mod = mod_tmp; + } + } + + /* delete old one */ + rc = bdb_dn2id_delete( be, ltid, p_ndn.bv_val, e ); + if ( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + rc = LDAP_OTHER; + text = "DN index delete fail"; + goto return_results; + } + + (void) bdb_cache_delete_entry(&bdb->bi_cache, e); + + /* Binary format uses a single contiguous block, cannot + * free individual fields. Leave new_dn/new_ndn set so + * they can be individually freed later. + */ + e->e_name = new_dn; + e->e_nname = new_ndn; + + new_dn.bv_val = NULL; + new_ndn.bv_val = NULL; + + /* add new one */ + rc = bdb_dn2id_add( be, ltid, np_ndn, e ); + if ( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + rc = LDAP_OTHER; + text = "DN index add failed"; + goto return_results; + } + + /* modify entry */ + rc = bdb_modify_internal( be, conn, op, ltid, &mod[0], e, + &text, textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + goto return_results; + } + + /* id2entry index */ + rc = bdb_id2entry_update( be, ltid, e ); + if ( rc != 0 ) { + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + rc = LDAP_OTHER; + text = "entry update failed"; + goto return_results; + } + + if( op->o_noop ) { + if(( rc=TXN_ABORT( ltid )) != 0 ) { + text = "txn_abort (no-op) failed"; + } else { + rc = LDAP_SUCCESS; + } + + } else { + char gid[DB_XIDDATASIZE]; + + snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx", + bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid ); + + if(( rc=TXN_PREPARE( ltid, gid )) != 0 ) { + text = "txn_prepare failed"; + } else { + if( bdb_cache_update_entry(&bdb->bi_cache, e) == -1 ) { + if(( rc=TXN_ABORT( ltid )) != 0 ) { + text ="cache update & txn_abort failed"; + } else { + rc = LDAP_OTHER; + text = "cache update failed"; + } + + } else { + if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) { + text = "txn_commit failed"; + } else { + rc = LDAP_SUCCESS; + } + } + } + } + + ltid = NULL; + op->o_private = NULL; + + if( rc == LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_RESULTS, "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn )); +#else + Debug(LDAP_DEBUG_TRACE, + "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn ); +#endif + text = NULL; + bdb_cache_entry_commit( e ); + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "modrdn", LDAP_LEVEL_RESULTS, "bdb_modrdn: %s : %s (%d)\n", text, db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n", + text, db_strerror(rc), rc ); +#endif + rc = LDAP_OTHER; + } + +return_results: + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + ldap_pvt_thread_yield(); + TXN_CHECKPOINT( bdb->bi_dbenv, + bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); + } + +done: + if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); + if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); + + /* LDAP v2 supporting correct attribute handling. */ + if( new_rdn != NULL ) ldap_rdnfree( new_rdn ); + if( old_rdn != NULL ) ldap_rdnfree( old_rdn ); + if( mod != NULL ) { + Modifications *tmp; + for (; mod; mod=tmp ) { + tmp = mod->sml_next; + free( mod ); + } + } + + /* LDAP v3 Support */ + if( np != NULL ) { + /* free new parent and reader lock */ + bdb_cache_return_entry_r(&bdb->bi_cache, np); + } + + if( p != NULL ) { + /* free parent and reader lock */ + bdb_cache_return_entry_r(&bdb->bi_cache, p); + } + + /* free entry */ + if( e != NULL ) { + bdb_cache_return_entry_w( &bdb->bi_cache, e ); + } + + if( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + return rc; +} diff --git a/servers/slapd/back-bdb/nextid.c b/servers/slapd/back-bdb/nextid.c new file mode 100644 index 0000000000000000000000000000000000000000..f5d0e618b17508df03e4b6e47f82f37fcc9da5df --- /dev/null +++ b/servers/slapd/back-bdb/nextid.c @@ -0,0 +1,76 @@ +/* init.c - initialize bdb backend */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" + +int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *out ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + + ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex ); + *out = ++bdb->bi_lastid; + ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex ); + + return 0; +} + +int bdb_last_id( BackendDB *be, DB_TXN *tid ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + ID id = 0; + DBT key, data; + DBC *cursor; + + DBTzero( &key ); + key.flags = DB_DBT_USERMEM; + key.data = (char *) &id; + key.ulen = sizeof( id ); + + DBTzero( &data ); + data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; + + /* Get a read cursor */ + rc = bdb->bi_id2entry->bdi_db->cursor( bdb->bi_id2entry->bdi_db, + tid, &cursor, 0 ); + + if (rc == 0) { + rc = cursor->c_get(cursor, &key, &data, DB_LAST); + cursor->c_close(cursor); + } + + switch(rc) { + case DB_NOTFOUND: + id = 0; + rc = 0; + /* FALLTHROUGH */ + case 0: + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "nextid", LDAP_LEVEL_ERR, + "bdb_last_id: get failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_last_id: get failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + goto done; + } + + bdb->bi_lastid = id; + +done: + return rc; +} diff --git a/servers/slapd/back-bdb/operational.c b/servers/slapd/back-bdb/operational.c new file mode 100644 index 0000000000000000000000000000000000000000..08172b8c2d173278de42aa9669ca1114285caf58 --- /dev/null +++ b/servers/slapd/back-bdb/operational.c @@ -0,0 +1,130 @@ +/* operational.c - bdb backend operational attributes function */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "back-bdb.h" +#include "proto-bdb.h" + +/* + * sets the supported operational attributes (if required) + */ + +int +bdb_operational( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e, + AttributeName *attrs, + int opattrs, + Attribute **a ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + Attribute **aa = a; + int rc; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; + + assert( e ); + + if ( !opattrs && !ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) { + return 0; + } + + + if( 0 ) { +retry: /* transaction retry */ + if( e != NULL ) { + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "operational", LDAP_LEVEL_DETAIL1, + "=> bdb_operational: retrying...\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "==> bdb_operational: retrying...\n", + 0, 0, 0 ); +#endif + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + goto return_results; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, bdb->bi_db_opflags ); + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "operational", LDAP_LEVEL_ERR, + "=> bdb_operational: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_operational: txn_begin failed: %s (%d)\n", + db_strerror( rc ), rc, 0 ); +#endif + rc = LDAP_OTHER; + return rc; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + rc = bdb_dn2id_children( be, ltid, &e->e_nname ); + + switch( rc ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + + case 0: + case DB_NOTFOUND: + *aa = slap_operational_hasSubordinate( rc == 0 ); + if ( *aa != NULL ) { + aa = &(*aa)->a_next; + } + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "operational", LDAP_LEVEL_ERR, + "=> bdb_operational: has_children failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_operational: has_children failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + } + +return_results: + if ( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + ldap_pvt_thread_yield(); + TXN_CHECKPOINT( bdb->bi_dbenv, + bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); + } + + if ( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + return rc; +} + diff --git a/servers/slapd/back-bdb/passwd.c b/servers/slapd/back-bdb/passwd.c new file mode 100644 index 0000000000000000000000000000000000000000..5d72674985eb34e3301e5bb27d007a1198bf270b --- /dev/null +++ b/servers/slapd/back-bdb/passwd.c @@ -0,0 +1,269 @@ +/* passwd.c - bdb backend password routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_exop_passwd( + Backend *be, + Connection *conn, + Operation *op, + const char *reqoid, + struct berval *reqdata, + char **rspoid, + struct berval **rspdata, + LDAPControl *** rspctrls, + const char **text, + BerVarray *refs ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + Entry *e = NULL; + struct berval hash = { 0, NULL }; + DB_TXN *ltid = NULL; + struct bdb_op_info opinfo; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + + struct berval id = { 0, NULL }; + struct berval new = { 0, NULL }; + + struct berval dn; + struct berval ndn; + + assert( reqoid != NULL ); + assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 ); + + rc = slap_passwd_parse( reqdata, + &id, NULL, &new, text ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "passwd", LDAP_LEVEL_ENTRY, "==>bdb_exop_passwd: \"%s\"\n", + id.bv_val ? id.bv_val : "" )); +#else + Debug( LDAP_DEBUG_ARGS, "==> bdb_exop_passwd: \"%s\"\n", + id.bv_val ? id.bv_val : "", 0, 0 ); +#endif + + if( rc != LDAP_SUCCESS ) { + goto done; + } + + if( new.bv_len == 0 ) { + slap_passwd_generate(&new); + + if( new.bv_len == 0 ) { + *text = "password generation failed."; + rc = LDAP_OTHER; + goto done; + } + + *rspdata = slap_passwd_return( &new ); + } + + slap_passwd_hash( &new, &hash ); + + if( hash.bv_len == 0 ) { + *text = "password hash failed"; + rc = LDAP_OTHER; + goto done; + } + + if( id.bv_len ) { + dn = id; + } else { + dn = op->o_dn; + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "passwd", LDAP_LEVEL_DETAIL1, "bdb_exop_passwd: \"%s\"%s\"\n", + dn.bv_val, id.bv_len ? " (proxy)" : "" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: \"%s\"%s\n", + dn.bv_val, id.bv_len ? " (proxy)" : "", 0 ); +#endif + + if( dn.bv_len == 0 ) { + *text = "No password is associated with the Root DSE"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = dnNormalize2( NULL, &dn, &ndn ); + if( rc != LDAP_SUCCESS ) { + *text = "Invalid DN"; + goto done; + } + + if( 0 ) { +retry: /* transaction retry */ + if ( e != NULL ) { + bdb_cache_delete_entry(&bdb->bi_cache, e); + bdb_cache_return_entry_w(&bdb->bi_cache, e); + } +#ifdef NEW_LOGGING + LDAP_LOG (( "passwd", LDAP_LEVEL_DETAIL1, "bdb_exop_passwd: retrying...\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: retrying...\n", 0, 0, 0 ); +#endif + rc = TXN_ABORT( ltid ); + ltid = NULL; + op->o_private = NULL; + if( rc != 0 ) { + rc = LDAP_OTHER; + *text = "internal error"; + goto done; + } + ldap_pvt_thread_yield(); + } + + /* begin transaction */ + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + bdb->bi_db_opflags ); + *text = NULL; + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "passwd", LDAP_LEVEL_ERR, "bdb_exop_passwd: txn_begin failed: %s (%d)\n", db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_exop_passwd: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + rc = LDAP_OTHER; + *text = "internal error"; + goto done; + } + + opinfo.boi_bdb = be; + opinfo.boi_txn = ltid; + opinfo.boi_err = 0; + op->o_private = &opinfo; + + /* get entry */ + rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 ); + + switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case DB_NOTFOUND: + case 0: + break; + default: + rc = LDAP_OTHER; + *text = "internal error"; + goto done; + } + + if( e == NULL ) { + *text = "could not locate authorization entry"; + rc = LDAP_NO_SUCH_OBJECT; + goto done; + } + +#ifdef BDB_SUBENTRIES + if( is_entry_subentry( e ) ) { + /* entry is an alias, don't allow operation */ + *text = "authorization entry is subentry"; + rc = LDAP_OTHER; + goto done; + } +#endif +#ifdef BDB_ALIASES + if( is_entry_alias( e ) ) { + /* entry is an alias, don't allow operation */ + *text = "authorization entry is alias"; + rc = LDAP_ALIAS_PROBLEM; + goto done; + } +#endif + + if( is_entry_referral( e ) ) { + /* entry is an referral, don't allow operation */ + *text = "authorization entry is referral"; + rc = LDAP_OTHER; + goto done; + } + + { + Modifications ml; + struct berval vals[2]; + + vals[0] = hash; + vals[1].bv_val = NULL; + + ml.sml_desc = slap_schema.si_ad_userPassword; + ml.sml_bvalues = vals; + ml.sml_op = LDAP_MOD_REPLACE; + ml.sml_next = NULL; + + rc = bdb_modify_internal( be, conn, op, ltid, + &ml, e, text, textbuf, textlen ); + + switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + *text = NULL; + goto retry; + case 0: + *text = NULL; + break; + default: + rc = LDAP_OTHER; + *text = "entry modify failed"; + goto done; + } + + /* change the entry itself */ + rc = bdb_id2entry_update( be, ltid, e ); + if( rc != 0 ) { + switch(rc) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + *text = "entry update failed"; + rc = LDAP_OTHER; + } + + if( rc == 0 ) { + if( op->o_noop ) { + rc = TXN_ABORT( ltid ); + } else { + rc = TXN_COMMIT( ltid, 0 ); + } + ltid = NULL; + } + op->o_private = NULL; + + if( rc == LDAP_SUCCESS ) { + replog( be, op, &e->e_name, &e->e_nname, &ml ); + } + } + +done: + if( e != NULL ) { + bdb_cache_return_entry_w( &bdb->bi_cache, e ); + } + + if( hash.bv_val != NULL ) { + free( hash.bv_val ); + } + + if( ltid != NULL ) { + TXN_ABORT( ltid ); + op->o_private = NULL; + } + + return rc; +} diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h new file mode 100644 index 0000000000000000000000000000000000000000..cdea9803e190411fc29f2d066bf0051eca884bc4 --- /dev/null +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -0,0 +1,334 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#ifndef _PROTO_BDB_H +#define _PROTO_BDB_H + +LDAP_BEGIN_DECL + +/* + * alias.c + */ +Entry *bdb_deref_internal_r LDAP_P(( + BackendDB *be, + Entry *e, + struct berval *dn, + int *err, + Entry **matched, + const char **text )); + +#define deref_entry_r( be, e, err, matched, text ) \ + bdb_deref_internal_r( be, e, NULL, err, matched, text ) +#define deref_dn_r( be, dn, err, matched, text ) \ + bdb_deref_internal_r( be, NULL, dn, err, matched, text) + +/* + * attr.c + */ + +void bdb_attr_mask( struct bdb_info *bdb, + AttributeDescription *desc, + slap_mask_t *indexmask ); + +int bdb_attr_index_config LDAP_P(( struct bdb_info *bdb, + const char *fname, int lineno, + int argc, char **argv )); + +void bdb_attr_index_destroy LDAP_P(( Avlnode *tree )); + +/* + * attribute.c + */ + +BI_acl_attribute bdb_attribute; + +/* + * dbcache.c + */ +int +bdb_db_cache( + Backend *be, + const char *name, + DB **db ); + +/* + * dn2entry.c + */ +int bdb_dn2entry_rw LDAP_P(( BackendDB *be, DB_TXN *tid, + struct berval *dn, Entry **e, Entry **matched, int flags, int rw )); +#define bdb_dn2entry_r(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0) +#define bdb_dn2entry_w(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1) + +/* + * dn2id.c + */ +int bdb_dn2id( + BackendDB *be, + DB_TXN *tid, + struct berval *dn, + ID *id ); + +int bdb_dn2id_matched( + BackendDB *be, + DB_TXN *tid, + struct berval *dn, + ID *id, + ID *id2 ); + +int bdb_dn2id_add( + BackendDB *be, + DB_TXN *tid, + struct berval *pdn, + Entry *e ); + +int bdb_dn2id_delete( + BackendDB *be, + DB_TXN *tid, + char *pdn, + Entry *e ); + +int bdb_dn2id_children( + BackendDB *be, + DB_TXN *tid, + struct berval *dn ); + +int +bdb_dn2idl( + BackendDB *be, + struct berval *dn, + int prefix, + ID *ids ); + +/* + * entry.c + */ +int bdb_entry_return( Entry *e ); +BI_entry_release_rw bdb_entry_release; + +/* + * error.c + */ +void bdb_errcall( const char *pfx, char * msg ); + +/* + * filterentry.c + */ +int bdb_filter_candidates( + Backend *be, + Filter *f, + ID *ids, + ID *tmp, + ID *stack ); + +/* + * group.c + */ + +BI_acl_group bdb_group; + +/* + * id2entry.c + */ +int bdb_id2entry_add( + BackendDB *be, + DB_TXN *tid, + Entry *e ); + +int bdb_id2entry_update( + BackendDB *be, + DB_TXN *tid, + Entry *e ); + +int bdb_id2entry_delete( + BackendDB *be, + DB_TXN *tid, + Entry *e); + +int bdb_id2entry_rw( + BackendDB *be, + DB_TXN *tid, + ID id, + Entry **e, + int rw ); +#define bdb_id2entry_r(be, tid, id, e) bdb_id2entry_rw((be), (tid), (id), (e), 0) +#define bdb_id2entry_w(be, tid, id, e) bdb_id2entry_rw((be), (tid), (id), (e), 1) + +void bdb_entry_free ( Entry *e ); + +/* + * idl.c + */ +unsigned bdb_idl_search( ID *ids, ID id ); + +int bdb_bt_compare( + DB *db, + const DBT *a, + const DBT *b ); + +int bdb_idl_fetch_key( + BackendDB *be, + DB *db, + DB_TXN *txn, + DBT *key, + ID *ids ); + +int bdb_idl_insert_key( + BackendDB *be, + DB *db, + DB_TXN *txn, + DBT *key, + ID id ); + +int bdb_idl_delete_key( + BackendDB *be, + DB *db, + DB_TXN *txn, + DBT *key, + ID id ); + +#if 0 +int +bdb_idl_notin( + ID *a, + ID *b, + ID *ids ); +#endif + +int +bdb_idl_intersection( + ID *a, + ID *b ); + +int +bdb_idl_union( + ID *a, + ID *b ); + +ID bdb_idl_first( ID *ids, ID *cursor ); +ID bdb_idl_next( ID *ids, ID *cursor ); + + +/* + * index.c + */ +extern int +bdb_index_is_indexed LDAP_P(( + Backend *be, + AttributeDescription *desc )); + +extern int +bdb_index_param LDAP_P(( + Backend *be, + AttributeDescription *desc, + int ftype, + DB **db, + slap_mask_t *mask, + struct berval *prefix )); + +extern int +bdb_index_values LDAP_P(( + Backend *be, + DB_TXN *txn, + AttributeDescription *desc, + BerVarray vals, + ID id, + int op )); + +int bdb_index_entry LDAP_P(( Backend *be, DB_TXN *t, + int r, Entry *e, Attribute *ap )); + +#define bdb_index_entry_add(be,t,e,ap) \ + bdb_index_entry((be),(t),SLAP_INDEX_ADD_OP,(e),(ap)) +#define bdb_index_entry_del(be,t,e,ap) \ + bdb_index_entry((be),(t),SLAP_INDEX_DELETE_OP,(e),(ap)) + +/* + * init.c + */ +extern struct berval bdb_uuid; + +/* + * key.c + */ +extern int +bdb_key_read( + Backend *be, + DB *db, + DB_TXN *txn, + struct berval *k, + ID *ids ); + +extern int +bdb_key_change( + Backend *be, + DB *db, + DB_TXN *txn, + struct berval *k, + ID id, + int op ); + +/* + * nextid.c + */ +int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *id ); +int bdb_last_id( BackendDB *be, DB_TXN *tid ); + +/* + * modify.c + */ +int bdb_modify_internal( + BackendDB *be, + Connection *conn, + Operation *op, + DB_TXN *tid, + Modifications *modlist, + Entry *e, + const char **text, + char *textbuf, + size_t textlen ); + +/* + * passwd.c + */ +BI_op_extended bdb_exop_passwd; + + +/* + * cache.c + */ + +void bdb_cache_entry_commit( Entry *e ); +void bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ); +#define bdb_cache_return_entry_r(c, e) bdb_cache_return_entry_rw((c), (e), 0) +#define bdb_cache_return_entry_w(c, e) bdb_cache_return_entry_rw((c), (e), 1) +int bdb_cache_add_entry_rw( + Cache *cache, + Entry *e, + int rw +); +int bdb_cache_update_entry( + Cache *cache, + Entry *e +); +ID bdb_cache_find_entry_ndn2id( + Backend *be, + Cache *cache, + struct berval *ndn +); +Entry* bdb_cache_find_entry_id( + Cache *cache, + ID id, + int rw +); +int bdb_cache_delete_entry( + Cache *cache, + Entry *e +); +void bdb_cache_release_all( Cache *cache ); + +LDAP_END_DECL + +#endif /* _PROTO_BDB_H */ diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c new file mode 100644 index 0000000000000000000000000000000000000000..8166d3da05688f276f9f56a61e1ea54eb098727a --- /dev/null +++ b/servers/slapd/back-bdb/referral.c @@ -0,0 +1,142 @@ +/* referral.c - BDB backend referral handler */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "external.h" + +int +bdb_referrals( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + const char **text ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc = LDAP_SUCCESS; + Entry *e = NULL, *matched; + + if( op->o_tag == LDAP_REQ_SEARCH ) { + /* let search take care of itself */ + return rc; + } + + if( get_manageDSAit( op ) ) { + /* let op take care of DSA management */ + return rc; + } + + /* get entry */ + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + + switch(rc) { + case DB_NOTFOUND: + rc = 0; + case 0: + break; + default: +#ifdef NEW_LOGGING + LDAP_LOG (( "referral", LDAP_LEVEL_ERR, + "bdb_referrals: dn2entry failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_referrals: dn2entry failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + if (e != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, e); + } + if (matched != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, matched); + } + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return rc; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + BerVarray refs = NULL; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "referral", LDAP_LEVEL_DETAIL1, + "bdb_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + (long) op->o_tag, dn->bv_val, matched_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + (long) op->o_tag, dn->bv_val, matched_dn ); +#endif + + if( is_entry_referral( matched ) ) { + rc = LDAP_OTHER; + refs = get_entry_referrals( be, conn, op, matched ); + } + + bdb_cache_return_entry_r (&bdb->bi_cache, matched); + matched = NULL; + } else if ( default_referral != NULL ) { + rc = LDAP_OTHER; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + } + + if( refs != NULL ) { + /* send referrals */ + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + ber_bvarray_free( refs ); + } else if ( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, matched_dn, + matched_dn ? "bad referral object" : NULL, + NULL, NULL ); + } + + free( matched_dn ); + return rc; + } + + if ( is_entry_referral( e ) ) { + /* entry is a referral */ + BerVarray refs = get_entry_referrals( be, conn, op, e ); + BerVarray rrefs = referral_rewrite( + refs, &e->e_name, dn, LDAP_SCOPE_DEFAULT ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "referral", LDAP_LEVEL_DETAIL1, + "bdb_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + (long) op->o_tag, dn->bv_val, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + (long) op->o_tag, dn->bv_val, e->e_dn ); +#endif + + if( rrefs != NULL ) { + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + e->e_dn, NULL, rrefs, NULL ); + ber_bvarray_free( rrefs ); + } else { + send_ldap_result( conn, op, rc = LDAP_OTHER, e->e_dn, + "bad referral object", NULL, NULL ); + } + + ber_bvarray_free( refs ); + } + + bdb_cache_return_entry_r(&bdb->bi_cache, e); + return rc; +} diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c new file mode 100644 index 0000000000000000000000000000000000000000..84fc36164e262c88017588db28514282d9a874d6 --- /dev/null +++ b/servers/slapd/back-bdb/search.c @@ -0,0 +1,699 @@ +/* search.c - search operation */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" +#include "idl.h" +#include "external.h" + +static int base_candidate( + BackendDB *be, + Entry *e, + ID *ids ); +static int search_candidates( + BackendDB *be, + Operation *op, + Entry *e, + Filter *filter, + int scope, + int deref, + ID *ids ); + +int +bdb_search( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *base, + struct berval *nbase, + int scope, + int deref, + int slimit, + int tlimit, + Filter *filter, + struct berval *filterstr, + AttributeName *attrs, + int attrsonly ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + int rc; + const char *text = NULL; + time_t stoptime; + ID id, cursor; + ID candidates[BDB_IDL_UM_SIZE]; + Entry *e = NULL; + BerVarray v2refs = NULL; + Entry *matched = NULL; + struct berval realbase = { 0, NULL }; + int nentries = 0; + int manageDSAit; + + struct slap_limits_set *limit = NULL; + int isroot = 0; + +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_ENTRY,"bdb_back_search\n")); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n", + 0, 0, 0); +#endif + + manageDSAit = get_manageDSAit( op ); + + if ( nbase->bv_len == 0 ) { + /* DIT root special case */ + e = (Entry *) &slap_entry_root; + rc = 0; + } else +#ifdef BDB_ALIASES + /* get entry with reader lock */ + if ( deref & LDAP_DEREF_FINDING ) { + e = deref_dn_r( be, nbase-, &err, &matched, &text ); + + } else +#endif + { + rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0 ); + } + + switch(rc) { + case DB_NOTFOUND: + case 0: + break; + default: + if (e != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, e); + } + if (matched != NULL) { + bdb_cache_return_entry_r(&bdb->bi_cache, matched); + } + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return rc; + } + + if ( e == NULL ) { + struct berval matched_dn = { 0, NULL }; + BerVarray refs = NULL; + + if ( matched != NULL ) { + BerVarray erefs; + + ber_dupbv( &matched_dn, &matched->e_name ); + + erefs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + + bdb_cache_return_entry_r (&bdb->bi_cache, matched); + matched = NULL; + + if( erefs ) { + refs = referral_rewrite( erefs, &matched_dn, + base, scope ); + ber_bvarray_free( erefs ); + } + + } else { + refs = referral_rewrite( default_referral, + NULL, base, scope ); + } + + send_ldap_result( conn, op, rc=LDAP_REFERRAL , + matched_dn.bv_val, text, refs, NULL ); + + if ( refs ) ber_bvarray_free( refs ); + if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val ); + return rc; + } + + if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval matched_dn; + BerVarray erefs, refs; + + ber_dupbv( &matched_dn, &e->e_name ); + erefs = get_entry_referrals( be, conn, op, e ); + refs = NULL; + + bdb_cache_return_entry_r( &bdb->bi_cache, e ); + e = NULL; + + if( erefs ) { + refs = referral_rewrite( erefs, &matched_dn, + base, scope ); + ber_bvarray_free( erefs ); + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: entry is referral\n")); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn.bv_val, + refs ? NULL : "bad referral object", + refs, NULL ); + + ber_bvarray_free( refs ); + ber_memfree( matched_dn.bv_val ); + return 1; + } + + /* if not root, get appropriate limits */ + if ( be_isroot( be, &op->o_ndn ) ) { + isroot = 1; + } else { + ( void ) get_limits( be, &op->o_ndn, &limit ); + } + + /* The time/size limits come first because they require very little + * effort, so there's no chance the candidates are selected and then + * the request is not honored only because of time/size constraints */ + + /* if no time limit requested, use soft limit (unless root!) */ + if ( isroot ) { + if ( tlimit == 0 ) { + tlimit = -1; /* allow root to set no limit */ + } + + if ( slimit == 0 ) { + slimit = -1; + } + + } else { + /* if no limit is required, use soft limit */ + if ( tlimit <= 0 ) { + tlimit = limit->lms_t_soft; + + /* if requested limit higher than hard limit, abort */ + } else if ( tlimit > limit->lms_t_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_t_hard == 0 ) { + tlimit = limit->lms_t_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_t_hard > 0 ) { + send_search_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto done; + } + + /* negative hard limit means no limit */ + } + + /* if no limit is required, use soft limit */ + if ( slimit <= 0 ) { + slimit = limit->lms_s_soft; + + /* if requested limit higher than hard limit, abort */ + } else if ( slimit > limit->lms_s_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_s_hard == 0 ) { + slimit = limit->lms_s_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_s_hard > 0 ) { + send_search_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto done; + } + + /* negative hard limit means no limit */ + } + } + + /* compute it anyway; root does not use it */ + stoptime = op->o_time + tlimit; + + /* select candidates */ + if ( scope == LDAP_SCOPE_BASE ) { + rc = base_candidate( be, e, candidates ); + + } else { + BDB_IDL_ALL( bdb, candidates ); + rc = search_candidates( be, op, e, filter, + scope, deref, candidates ); + } + + /* need normalized dn below */ + ber_dupbv( &realbase, &e->e_nname ); + + /* start cursor at base entry's id + * FIXME: hack to make "" base work + * FIXME: moddn needs to assign new ID for this to work + */ + cursor = e->e_id == NOID ? 1 : e->e_id; + + if ( e != &slap_entry_root ) { + bdb_cache_return_entry_r(&bdb->bi_cache, e); + } + e = NULL; + + if ( candidates[0] == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: no candidates\n")); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n", + 0, 0, 0 ); +#endif + + send_search_result( conn, op, + LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 0 ); + + rc = 1; + goto done; + } + + /* if not root and candidates exceed to-be-checked entries, abort */ + if ( !isroot && limit->lms_s_unchecked != -1 ) { + if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) { + send_search_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 1; + goto done; + } + } + + for ( id = bdb_idl_first( candidates, &cursor ); + id != NOID; + id = bdb_idl_next( candidates, &cursor ) ) + { + int scopeok = 0; + + /* check for abandon */ + if ( op->o_abandon ) { + rc = 0; + goto done; + } + + /* check time limit */ + if ( tlimit != -1 && slap_get_time() > stoptime ) { + send_search_result( conn, op, rc = LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, v2refs, NULL, nentries ); + goto done; + } + + /* get the entry with reader lock */ + rc = bdb_id2entry_r( be, NULL, id, &e ); + + if ( e == NULL ) { + if( !BDB_IDL_IS_RANGE(candidates) ) { + /* only complain for non-range IDLs */ +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: candidate %ld not found\n", (long) id)); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: candidate %ld not found\n", + (long) id, 0, 0 ); +#endif + } + + goto loop_continue; + } + +#ifdef BDB_SUBENTRIES + if ( is_entry_subentry( e ) ) { + if( scope != LDAP_SCOPE_BASE ) { + if(!get_subentries_visibility( op )) { + /* only subentries are visible */ + goto loop_continue; + } + + } else if ( get_subentries( op ) && + !get_subentries_visibility( op )) + { + /* only subentries are visible */ + goto loop_continue; + } + + } else if ( get_subentries_visibility( op )) { + /* only subentries are visible */ + goto loop_continue; + } +#endif + +#ifdef BDB_ALIASES + if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) { + Entry *matched; + int err; + const char *text; + + e = deref_entry_r( be, e, &err, &matched, &text ); + + if( e == NULL ) { + e = matched; + goto loop_continue; + } + + if( e->e_id == id ) { + /* circular loop */ + goto loop_continue; + } + + /* need to skip alias which deref into scope */ + if( scope & LDAP_SCOPE_ONELEVEL ) { + struct berval pdn; + + dnParent( &e->e_nname, &pdn ): + if ( ber_bvcmp( pdn, &realbase ) ) { + goto loop_continue; + } + + } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) { + /* alias is within scope */ +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: \"%s\" in subtree\n", e->edn)); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: \"%s\" in subtree\n", + e->e_dn, 0, 0 ); +#endif + goto loop_continue; + } + + scopeok = 1; + } +#endif + + /* + * if it's a referral, add it to the list of referrals. only do + * this for non-base searches, and don't check the filter + * explicitly here since it's only a candidate anyway. + */ + if ( !manageDSAit && scope != LDAP_SCOPE_BASE && + is_entry_referral( e ) ) + { + BerVarray erefs = get_entry_referrals( + be, conn, op, e ); + BerVarray refs = referral_rewrite( erefs, + &e->e_name, NULL, + scope == LDAP_SCOPE_SUBTREE + ? LDAP_SCOPE_SUBTREE + : LDAP_SCOPE_BASE ); + + send_search_reference( be, conn, op, + e, refs, NULL, &v2refs ); + + ber_bvarray_free( refs ); + + goto loop_continue; + } + + /* if it matches the filter and scope, send it */ + rc = test_filter( be, conn, op, e, filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + struct berval dn; + + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( be_issuffix( be, &e->e_nname ) ) { + scopeok = (realbase.bv_len == 0); + } else { + dnParent( &e->e_nname, &dn ); + scopeok = dn_match( &dn, &realbase ); + } + + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + scopeok = dnIsSuffix( &e->e_nname, &realbase ); + + } else { + scopeok = 1; + } + + if ( scopeok ) { + /* check size limit */ + if ( --slimit == -1 ) { + bdb_cache_return_entry_r (&bdb->bi_cache, e); + e = NULL; + send_search_result( conn, op, + rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, + v2refs, NULL, nentries ); + goto done; + } + + if (e) { + int result; + + if( op->o_noop ) { + result = 0; + } else { + result = send_search_entry( be, conn, op, + e, attrs, attrsonly, NULL); + } + + switch (result) { + case 0: /* entry sent ok */ + nentries++; + break; + case 1: /* entry not sent */ + break; + case -1: /* connection closed */ + bdb_cache_return_entry_r(&bdb->bi_cache, e); + e = NULL; + rc = LDAP_OTHER; + goto done; + } + } + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: %ld scope not okay\n", (long) id)); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: %ld scope not okay\n", + (long) id, 0, 0 ); +#endif + } + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_RESULTS,"bdb_search: %ld does match filter\n", (long) id)); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: %ld does match filter\n", + (long) id, 0, 0 ); +#endif + } + +loop_continue: + if( e != NULL ) { + /* free reader lock */ + bdb_cache_return_entry_r ( &bdb->bi_cache, e ); + e = NULL; + } + + ldap_pvt_thread_yield(); + } + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, NULL, nentries ); + + rc = 0; + +done: + if( e != NULL ) { + /* free reader lock */ + bdb_cache_return_entry_r ( &bdb->bi_cache, e ); + } + + if( v2refs ) ber_bvarray_free( v2refs ); + if( realbase.bv_val ) ch_free( realbase.bv_val ); + + return rc; +} + + +static int base_candidate( + BackendDB *be, + Entry *e, + ID *ids ) +{ +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_ENTRY,"base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id)); +#else + Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n", + e->e_dn, (long) e->e_id, 0); +#endif + + ids[0] = 1; + ids[1] = e->e_id; + return 0; +} + +/* Is "objectClass=xx" mentioned anywhere in this filter? Presence + * doesn't count, we're looking for explicit values. Also count depth + * of filter tree while we're at it. + */ +static int oc_filter( + Filter *f, + int cur, + int *max +) +{ + int rc = 0; + + if( cur > *max ) *max = cur; + + switch(f->f_choice) { + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_APPROX: + if (f->f_av_desc == slap_schema.si_ad_objectClass) + rc = 1; + break; + + case LDAP_FILTER_SUBSTRINGS: + if (f->f_sub_desc == slap_schema.si_ad_objectClass) + rc = 1; + break; + + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: + cur++; + for (f=f->f_and; f; f=f->f_next) + if ((rc = oc_filter(f, cur, max))) + break; + break; + default: + break; + } + return rc; +} + +static int search_candidates( + BackendDB *be, + Operation *op, + Entry *e, + Filter *filter, + int scope, + int deref, + ID *ids ) +{ + int rc, depth = 1; + Filter f, scopef, rf, xf; + ID *stack; + AttributeAssertion aa_ref; +#ifdef BDB_SUBENTRIES + Filter sf; + AttributeAssertion aa_subentry; +#endif +#ifdef BDB_ALIASES + Filter af; + AttributeAssertion aa_alias; +#endif + + /* + * This routine takes as input a filter (user-filter) + * and rewrites it as follows: + * (&(scope=DN)[(objectClass=subentry)] + * (|[(objectClass=referral)(objectClass=alias)](user-filter)) + */ + +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_ENTRY,"search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", e->e_dn, (long) e->e_id, scope)); +#else + Debug(LDAP_DEBUG_TRACE, + "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", + e->e_dn, (long) e->e_id, scope ); +#endif + + xf.f_or = filter; + xf.f_choice = LDAP_FILTER_OR; + xf.f_next = NULL; + + /* If the user's filter doesn't mention objectClass, or if + * it just uses objectClass=*, these clauses are redundant. + */ + if (oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) { + if( !get_manageDSAit(op) ) { /* match referrals */ + struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" }; + rf.f_choice = LDAP_FILTER_EQUALITY; + rf.f_ava = &aa_ref; + rf.f_av_desc = slap_schema.si_ad_objectClass; + rf.f_av_value = bv_ref; + rf.f_next = xf.f_or; + xf.f_or = &rf; + } + +#ifdef BDB_ALIASES + if( deref & LDAP_DEREF_SEARCHING ) { /* match aliases */ + struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" }; + af.f_choice = LDAP_FILTER_EQUALITY; + af.f_ava = &aa_alias; + af.f_av_desc = slap_schema.si_ad_objectClass; + af.f_av_value = bv_alias; + af.f_next = xf.f_or; + xf.f_or = ⁡ + } +#endif + /* We added one of these clauses, filter depth increased */ + if( xf.f_or != filter ) depth++; + } + + f.f_next = NULL; + f.f_choice = LDAP_FILTER_AND; + f.f_and = &scopef; + scopef.f_choice = scope == LDAP_SCOPE_SUBTREE + ? SLAPD_FILTER_DN_SUBTREE + : SLAPD_FILTER_DN_ONE; + scopef.f_dn = &e->e_nname; + scopef.f_next = xf.f_or == filter ? filter : &xf ; + /* Filter depth increased again, adding scope clause */ + depth++; + +#ifdef BDB_SUBENTRIES + if( get_subentries_visibility( op ) ) { + struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" }; + sf.f_choice = LDAP_FILTER_EQUALITY; + sf.f_ava = &aa_subentry; + sf.f_av_desc = slap_schema.si_ad_objectClass; + sf.f_av_value = bv_subentry; + sf.f_next = scopef.f_next; + scopef.f_next = &sf; + } +#endif + + /* Allocate IDL stack, plus 1 more for former tmp */ + stack = malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) ); + + rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE ); + + free( stack ); + + if( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_DETAIL1,"bdb_search_candidates: failed (rc=%d)\n", rc)); +#else + Debug(LDAP_DEBUG_TRACE, + "bdb_search_candidates: failed (rc=%d)\n", + rc, NULL, NULL ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG (( "search", LDAP_LEVEL_DETAIL1,"bdb_search_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids))); +#else + Debug(LDAP_DEBUG_TRACE, + "bdb_search_candidates: id=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) BDB_IDL_FIRST(ids), + (long) BDB_IDL_LAST(ids) ); +#endif + } + + return rc; +} diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c new file mode 100644 index 0000000000000000000000000000000000000000..0203ef71068b7ede316b0f0bc60d540f3d00abc4 --- /dev/null +++ b/servers/slapd/back-bdb/tools.c @@ -0,0 +1,374 @@ +/* tools.c - tools for slap tools */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "back-bdb.h" + +static DBC *cursor = NULL; +static DBT key, data; + +int bdb_tool_entry_open( + BackendDB *be, int mode ) +{ + /* initialize key and data thangs */ + DBTzero( &key ); + DBTzero( &data ); + key.flags = DB_DBT_REALLOC; + data.flags = DB_DBT_REALLOC; + + return 0; +} + +int bdb_tool_entry_close( + BackendDB *be ) +{ + assert( be != NULL ); + + if( key.data ) { + ch_free( key.data ); + key.data = NULL; + } + if( data.data ) { + ch_free( data.data ); + data.data = NULL; + } + + if( cursor ) { + cursor->c_close( cursor ); + cursor = NULL; + } + + return 0; +} + +ID bdb_tool_entry_next( + BackendDB *be ) +{ + int rc; + ID id; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + + assert( be != NULL ); + assert( slapMode & SLAP_TOOL_MODE ); + assert( bdb != NULL ); + + if (cursor == NULL) { + rc = bdb->bi_id2entry->bdi_db->cursor( + bdb->bi_id2entry->bdi_db, NULL, &cursor, + bdb->bi_db_opflags ); + if( rc != 0 ) { + return NOID; + } + } + + rc = cursor->c_get( cursor, &key, &data, DB_NEXT ); + + if( rc != 0 ) { + return NOID; + } + + if( data.data == NULL ) { + return NOID; + } + + AC_MEMCPY( &id, key.data, key.size ); + return id; +} + +Entry* bdb_tool_entry_get( BackendDB *be, ID id ) +{ + int rc; + Entry *e; + struct berval bv; + + assert( be != NULL ); + assert( slapMode & SLAP_TOOL_MODE ); + assert( data.data != NULL ); + + DBT2bv( &data, &bv ); + + rc = entry_decode( &bv, &e ); + + if( rc == LDAP_SUCCESS ) { + e->e_id = id; + } + +#ifdef BDB_HIER + bdb_fix_dn(be, id, e); +#endif + + return e; +} + +ID bdb_tool_entry_put( + BackendDB *be, + Entry *e, + struct berval *text ) +{ + int rc; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB_TXN *tid = NULL; + struct berval pdn; + + assert( be != NULL ); + assert( slapMode & SLAP_TOOL_MODE ); + + assert( text ); + assert( text->bv_val ); + assert( text->bv_val[0] == '\0' ); + +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ARGS, + "=> bdb_tool_entry_put( %ld, \"%s\" )\n", + (long) e->e_id, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_put( %ld, \"%s\" )\n", + (long) e->e_id, e->e_dn, 0 ); +#endif + + rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, + bdb->bi_db_opflags ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "txn_begin failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", + text->bv_val, 0, 0 ); +#endif + return NOID; + } + + rc = bdb_next_id( be, tid, &e->e_id ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "next_id failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 ); +#endif + goto done; + } + + /* add dn2id indices */ + if ( be_issuffix( be, &e->e_nname ) ) { + pdn = slap_empty_bv; + } else { + dnParent( &e->e_nname, &pdn ); + } + rc = bdb_dn2id_add( be, tid, &pdn, e ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "dn2id_add failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 ); +#endif + goto done; + } + + /* id2entry index */ + rc = bdb_id2entry_add( be, tid, e ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "id2entry_add failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 ); +#endif + goto done; + } + + rc = bdb_index_entry_add( be, tid, e, e->e_attrs ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "index_entry_add failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 ); +#endif + goto done; + } + +done: + if( rc == 0 ) { + rc = TXN_COMMIT( tid, 0 ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "txn_commit failed: %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", + text->bv_val, 0, 0 ); +#endif + e->e_id = NOID; + } + + } else { + TXN_ABORT( tid ); + snprintf( text->bv_val, text->bv_len, + "txn_aborted! %s (%d)", + db_strerror(rc), rc ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_put: %s\n", text->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_put: %s\n", + text->bv_val, 0, 0 ); +#endif + e->e_id = NOID; + } + + return e->e_id; +} + +int bdb_tool_entry_reindex( + BackendDB *be, + ID id ) +{ + struct bdb_info *bi = (struct bdb_info *) be->be_private; + int rc; + Entry *e; + DB_TXN *tid = NULL; + struct berval pdn; + +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ARGS, + "=> bdb_tool_entry_reindex( %ld )\n", (long) id )); +#else + Debug( LDAP_DEBUG_ARGS, "=> bdb_tool_entry_reindex( %ld )\n", + (long) id, 0, 0 ); +#endif + + e = bdb_tool_entry_get( be, id ); + + if( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_DETAIL1, + "bdb_tool_entry_reindex:: could not locate id=%ld\n", + (long) id )); +#else + Debug( LDAP_DEBUG_ANY, + "bdb_tool_entry_reindex:: could not locate id=%ld\n", + (long) id, 0, 0 ); +#endif + return -1; + } + + rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + goto done; + } + + /* + * just (re)add them for now + * assume that some other routine (not yet implemented) + * will zap index databases + * + */ + +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n", + (long) id, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n", + (long) id, e->e_dn, 0 ); +#endif + + /* add dn2id indices */ + if ( be_issuffix( be, &e->e_nname ) ) { + pdn = slap_empty_bv; + } else { + dnParent( &e->e_nname, &pdn ); + } + rc = bdb_dn2id_add( be, tid, &pdn, e ); + if( rc != 0 && rc != DB_KEYEXIST ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + goto done; + } + + rc = bdb_index_entry_add( be, tid, e, e->e_attrs ); + +done: + if( rc == 0 ) { + rc = TXN_COMMIT( tid, 0 ); + if( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_ERR, + "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + e->e_id = NOID; + } + + } else { + TXN_ABORT( tid ); +#ifdef NEW_LOGGING + LDAP_LOG (( "tools", LDAP_LEVEL_DETAIL1, + "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n", + db_strerror(rc), rc )); +#else + Debug( LDAP_DEBUG_ANY, + "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n", + db_strerror(rc), rc, 0 ); +#endif + e->e_id = NOID; + } + + return rc; +} diff --git a/servers/slapd/back-dnssrv/bind.c b/servers/slapd/back-dnssrv/bind.c new file mode 100644 index 0000000000000000000000000000000000000000..adb59251481b4f9f6620fe23adefbc9ae6389144 --- /dev/null +++ b/servers/slapd/back-dnssrv/bind.c @@ -0,0 +1,58 @@ +/* bind.c - DNS SRV backend bind function */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "external.h" + +int +dnssrv_back_bind( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int method, + struct berval *cred, + struct berval *edn ) +{ + Debug( LDAP_DEBUG_TRACE, "DNSSRV: bind %s (%d)\n", + dn->bv_val == NULL ? "" : dn->bv_val, + method, NULL ); + + if( method == LDAP_AUTH_SIMPLE && cred != NULL && cred->bv_len ) { + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu DNSSRV BIND dn=\"%s\" provided passwd\n", + op->o_connid, op->o_opid, + dn->bv_val == NULL ? "" : dn->bv_val , 0, 0 ); + + Debug( LDAP_DEBUG_TRACE, + "DNSSRV: BIND dn=\"%s\" provided cleartext password\n", + dn->bv_val == NULL ? "" : dn->bv_val, 0, 0 ); + + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "you shouldn\'t send strangers your password", + NULL, NULL ); + + } else { + Debug( LDAP_DEBUG_TRACE, "DNSSRV: BIND dn=\"%s\"\n", + dn->bv_val == NULL ? "" : dn->bv_val, 0, 0 ); + + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "anonymous bind expected", + NULL, NULL ); + } + + return 1; +} diff --git a/servers/slapd/back-dnssrv/config.c b/servers/slapd/back-dnssrv/config.c new file mode 100644 index 0000000000000000000000000000000000000000..4bdb093846b17b19536f7e09c5fbe538d13a21eb --- /dev/null +++ b/servers/slapd/back-dnssrv/config.c @@ -0,0 +1,42 @@ +/* config.c - DNS SRV backend configuration file routine */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "external.h" + +int +dnssrv_back_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + + if ( li == NULL ) { + fprintf( stderr, "%s: line %d: DNSSRV backend info is null!\n", + fname, lineno ); + return( 1 ); + } + + /* no configuration options (yet) */ + { + fprintf( stderr, + "%s: line %d: unknown directive \"%s\"" + " in DNSSRV database definition (ignored)\n", + fname, lineno, argv[0] ); + } + return 0; +} diff --git a/servers/slapd/back-dnssrv/referral.c b/servers/slapd/back-dnssrv/referral.c new file mode 100644 index 0000000000000000000000000000000000000000..6d7e240dcecf9ecdfa712763c80a051c420866b5 --- /dev/null +++ b/servers/slapd/back-dnssrv/referral.c @@ -0,0 +1,109 @@ +/* referral.c - DNS SRV backend referral handler */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "external.h" + +int +dnssrv_back_referrals( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + const char **text ) +{ + int i; + int rc = LDAP_OTHER; + char *domain = NULL; + char *hostlist = NULL; + char **hosts = NULL; + BerVarray urls = NULL; + + if( ndn->bv_len == 0 ) { + *text = "DNS SRV operation upon null (empty) DN disallowed"; + return LDAP_UNWILLING_TO_PERFORM; + } + + if( get_manageDSAit( op ) ) { + if( op->o_tag == LDAP_REQ_SEARCH ) { + return LDAP_SUCCESS; + } + + *text = "DNS SRV problem processing manageDSAit control"; + return LDAP_OTHER; + } + + if( ldap_dn2domain( dn->bv_val, &domain ) ) { + send_ldap_result( conn, op, LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); + return LDAP_REFERRAL; + } + + Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> domain=\"%s\"\n", + dn->bv_val, + domain == NULL ? "" : domain, + 0 ); + + if( ( rc = ldap_domain2hostlist( domain, &hostlist ) ) ) { + Debug( LDAP_DEBUG_TRACE, + "DNSSRV: domain2hostlist(%s) returned %d\n", + domain, rc, 0 ); + *text = "no DNS SRV RR available for DN"; + rc = LDAP_NO_SUCH_OBJECT; + goto done; + } + + hosts = str2charray( hostlist, " " ); + + if( hosts == NULL ) { + Debug( LDAP_DEBUG_TRACE, "DNSSRV: str2charrary error\n", 0, 0, 0 ); + *text = "problem processing DNS SRV records for DN"; + goto done; + } + + for( i=0; hosts[i] != NULL; i++) { + struct berval url; + + url.bv_len = sizeof("ldap://")-1 + strlen(hosts[i]); + url.bv_val = ch_malloc( url.bv_len + 1 ); + + strcpy( url.bv_val, "ldap://" ); + strcpy( &url.bv_val[sizeof("ldap://")-1], hosts[i] ); + + if ( ber_bvarray_add( &urls, &url ) < 0 ) { + free( url.bv_val ); + *text = "problem processing DNS SRV records for DN"; + goto done; + } + } + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu DNSSRV p=%d dn=\"%s\" url=\"%s\"\n", + op->o_connid, op->o_opid, op->o_protocol, + dn->bv_val, urls[0].bv_val ); + + Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> url=\"%s\"\n", + dn->bv_val, urls[0].bv_val, 0 ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, "DNS SRV generated referrals", urls, NULL ); + +done: + if( domain != NULL ) ch_free( domain ); + if( hostlist != NULL ) ch_free( hostlist ); + if( hosts != NULL ) charray_free( hosts ); + ber_bvarray_free( urls ); + return rc; +} diff --git a/servers/slapd/back-dnssrv/search.c b/servers/slapd/back-dnssrv/search.c new file mode 100644 index 0000000000000000000000000000000000000000..a619e3c23d391c7b137acf10de218f58d8fb9bcb --- /dev/null +++ b/servers/slapd/back-dnssrv/search.c @@ -0,0 +1,231 @@ +/* search.c - DNS SRV backend search function */ +/* $OpenLDAP$ */ +/* + * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "slap.h" +#include "external.h" + +int +dnssrv_back_search( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int scope, + int deref, + int size, + int time, + Filter *filter, + struct berval *filterstr, + AttributeName *attrs, + int attrsonly ) +{ + int i; + int rc; + char *domain = NULL; + char *hostlist = NULL; + char **hosts = NULL; + char *refdn; + struct berval nrefdn = { 0, NULL }; + BerVarray urls = NULL; + + assert( get_manageDSAit( op ) ); + + if( ldap_dn2domain( dn->bv_val, &domain ) ) { + send_ldap_result( conn, op, LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); + goto done; + } + + Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> domain=\"%s\"\n", + dn->bv_len ? dn->bv_val : "", + domain == NULL ? "" : domain, + 0 ); + + if( ( rc = ldap_domain2hostlist( domain, &hostlist ) ) ) { + Debug( LDAP_DEBUG_TRACE, "DNSSRV: domain2hostlist returned %d\n", + rc, 0, 0 ); + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, + NULL, "no DNS SRV RR available for DN", NULL, NULL ); + goto done; + } + + hosts = str2charray( hostlist, " " ); + + if( hosts == NULL ) { + Debug( LDAP_DEBUG_TRACE, "DNSSRV: str2charrary error\n", 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "problem processing DNS SRV records for DN", NULL, NULL ); + goto done; + } + + for( i=0; hosts[i] != NULL; i++) { + struct berval url; + + url.bv_len = sizeof("ldap://")-1 + strlen(hosts[i]); + url.bv_val = ch_malloc( url.bv_len + 1 ); + + strcpy( url.bv_val, "ldap://" ); + strcpy( &url.bv_val[sizeof("ldap://")-1], hosts[i] ); + + if( ber_bvarray_add( &urls, &url ) < 0 ) { + free( url.bv_val ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "problem processing DNS SRV records for DN", + NULL, NULL ); + goto done; + } + } + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu DNSSRV p=%d dn=\"%s\" url=\"%s\"\n", + op->o_connid, op->o_opid, op->o_protocol, + dn->bv_len ? dn->bv_val : "", urls[0].bv_val ); + + Debug( LDAP_DEBUG_TRACE, + "DNSSRV: ManageDSAit scope=%d dn=\"%s\" -> url=\"%s\"\n", + scope, + dn->bv_len ? dn->bv_val : "", + urls[0].bv_val ); + + rc = ldap_domain2dn(domain, &refdn); + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "DNS SRV problem processing manageDSAit control", + NULL, NULL ); + goto done; + + } else { + struct berval bv; + bv.bv_val = refdn; + bv.bv_len = strlen( refdn ); + + rc = dnNormalize2( NULL, &bv, &nrefdn ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "DNS SRV problem processing manageDSAit control", + NULL, NULL ); + goto done; + } + } + + if( !dn_match( &nrefdn, ndn ) ) { + /* requested dn is subordinate */ + + Debug( LDAP_DEBUG_TRACE, + "DNSSRV: dn=\"%s\" subordindate to refdn=\"%s\"\n", + dn->bv_len ? dn->bv_val : "", + refdn == NULL ? "" : refdn, + NULL ); + + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, + refdn, NULL, + NULL, NULL ); + + } else if ( scope == LDAP_SCOPE_ONELEVEL ) { + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + + } else { + struct berval vals[2]; + Entry *e = ch_calloc( 1, sizeof(Entry) ); + AttributeDescription *ad_objectClass + = slap_schema.si_ad_objectClass; + AttributeDescription *ad_ref = slap_schema.si_ad_ref; + e->e_dn = strdup( dn->bv_val ); + e->e_name.bv_len = dn->bv_len; + e->e_ndn = strdup( ndn->bv_val ); + e->e_nname.bv_len = ndn->bv_len; + + e->e_attrs = NULL; + e->e_private = NULL; + + vals[1].bv_val = NULL; + + vals[0].bv_val = "top"; + vals[0].bv_len = sizeof("top")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = "referral"; + vals[0].bv_len = sizeof("referral")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = "extensibleObject"; + vals[0].bv_len = sizeof("extensibleObject")-1; + attr_merge( e, ad_objectClass, vals ); + + { + AttributeDescription *ad = NULL; + const char *text; + + rc = slap_str2ad( "dc", &ad, &text ); + + if( rc == LDAP_SUCCESS ) { + char *p; + vals[0].bv_val = ch_strdup( domain ); + + p = strchr( vals[0].bv_val, '.' ); + + if( p == vals[0].bv_val ) { + vals[0].bv_val[1] = '\0'; + } else if ( p != NULL ) { + *p = '\0'; + } + + vals[0].bv_len = strlen(vals[0].bv_val); + attr_merge( e, ad, vals ); + } + } + + { + AttributeDescription *ad = NULL; + const char *text; + + rc = slap_str2ad( "associatedDomain", &ad, &text ); + + if( rc == LDAP_SUCCESS ) { + vals[0].bv_val = domain; + vals[0].bv_len = strlen(domain); + attr_merge( e, ad, vals ); + } + } + + attr_merge( e, ad_ref, urls ); + + rc = test_filter( be, conn, op, e, filter ); + + if( rc == LDAP_COMPARE_TRUE ) { + send_search_entry( be, conn, op, + e, attrs, attrsonly, NULL ); + } + + entry_free( e ); + + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + } + + if ( refdn ) free( refdn ); + if ( nrefdn.bv_val ) free( nrefdn.bv_val ); + +done: + if( domain != NULL ) ch_free( domain ); + if( hostlist != NULL ) ch_free( hostlist ); + if( hosts != NULL ) charray_free( hosts ); + if( urls != NULL ) ber_bvarray_free( urls ); + return 0; +} diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c new file mode 100644 index 0000000000000000000000000000000000000000..064bca788eea1f9ede2b0fc37a3f501bb0b9f3bb --- /dev/null +++ b/servers/slapd/back-ldap/bind.c @@ -0,0 +1,435 @@ +/* bind.c - ldap backend bind 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> + + +#define AVL_INTERNAL +#include "slap.h" +#include "back-ldap.h" + +#define PRINT_CONNTREE 0 + +int +ldap_back_bind( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int method, + struct berval *cred, + struct berval *edn +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + struct ldapconn *lc; + + struct berval mdn = { 0, NULL }; + int rc = 0; + + lc = ldap_back_getconn(li, conn, op); + if ( !lc ) { + return( -1 ); + } + + /* + * Rewrite the bind dn if needed + */ +#ifdef ENABLE_REWRITE + switch ( rewrite_session( li->rwinfo, "bindDn", dn->bv_val, conn, &mdn.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mdn.bv_val == NULL ) { + mdn.bv_val = ( char * )dn->bv_val; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] bindDn: \"%s\" -> \"%s\"\n", dn->bv_val, mdn.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> bindDn: \"%s\" -> \"%s\"\n%s", + dn->bv_val, mdn.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", NULL, NULL ); + return( -1 ); + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "Operations error", NULL, NULL ); + return( -1 ); + } +#else /* !ENABLE_REWRITE */ + ldap_back_dn_massage( li, dn, &mdn, 0, 1 ); +#endif /* !ENABLE_REWRITE */ + + rc = ldap_bind_s(lc->ld, mdn.bv_val, cred->bv_val, method); + if (rc != LDAP_SUCCESS) { + rc = ldap_back_op_result( lc, op ); + } else { + lc->bound = 1; + } + + if ( mdn.bv_val != dn->bv_val ) { + free( mdn.bv_val ); + } + + return( rc ); +} + +/* + * ldap_back_conn_cmp + * + * compares two struct ldapconn based on the value of the conn pointer; + * used by avl stuff + */ +int +ldap_back_conn_cmp( + const void *c1, + const void *c2 + ) +{ + const struct ldapconn *lc1 = (const struct ldapconn *)c1; + const struct ldapconn *lc2 = (const struct ldapconn *)c2; + + return ( ( lc1->conn < lc2->conn ) ? -1 : ( ( lc1->conn > lc2-> conn ) ? 1 : 0 ) ); +} + +/* + * ldap_back_conn_dup + * + * returns -1 in case a duplicate struct ldapconn has been inserted; + * used by avl stuff + */ +int +ldap_back_conn_dup( + void *c1, + void *c2 + ) +{ + struct ldapconn *lc1 = (struct ldapconn *)c1; + struct ldapconn *lc2 = (struct ldapconn *)c2; + + return( ( lc1->conn == lc2->conn ) ? -1 : 0 ); +} + +#if PRINT_CONNTREE > 0 +static void ravl_print( Avlnode *root, int depth ) +{ + int i; + + if ( root == 0 ) + return; + + ravl_print( root->avl_right, depth+1 ); + + for ( i = 0; i < depth; i++ ) + printf( " " ); + + printf( "c(%ld) %d\n", ((struct ldapconn *) root->avl_data)->conn->c_connid, root->avl_bf ); + + ravl_print( root->avl_left, depth+1 ); +} + +static void myprint( Avlnode *root ) +{ + printf( "********\n" ); + + if ( root == 0 ) + printf( "\tNULL\n" ); + + else + ravl_print( root, 0 ); + + printf( "********\n" ); +} +#endif /* PRINT_CONNTREE */ + +struct ldapconn * +ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op) +{ + struct ldapconn *lc, lc_curr; + LDAP *ld; + + /* Searches for a ldapconn in the avl tree */ + lc_curr.conn = conn; + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + lc = (struct ldapconn *)avl_find( li->conntree, + (caddr_t)&lc_curr, ldap_back_conn_cmp ); + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + + /* Looks like we didn't get a bind. Open a new session... */ + if (!lc) { + int vers = conn->c_protocol; + int err = ldap_initialize(&ld, li->url); + + if (err != LDAP_SUCCESS) { + err = ldap_back_map_result(err); + send_ldap_result( conn, op, err, + NULL, "ldap_init failed", NULL, NULL ); + return( NULL ); + } + /* Set LDAP version. This will always succeed: If the client + * bound with a particular version, then so can we. + */ + ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &vers); + + lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn)); + lc->conn = conn; + lc->ld = ld; + +#ifdef ENABLE_REWRITE + /* + * Sets a cookie for the rewrite session + */ + ( void )rewrite_session_init( li->rwinfo, conn ); +#endif /* ENABLE_REWRITE */ + + if ( lc->conn->c_cdn.bv_len != 0 ) { + + /* + * Rewrite the bind dn if needed + */ +#ifdef ENABLE_REWRITE + lc->bound_dn.bv_val = NULL; + lc->bound_dn.bv_len = 0; + switch ( rewrite_session( li->rwinfo, "bindDn", + lc->conn->c_cdn.bv_val, conn, + &lc->bound_dn.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( lc->bound_dn.bv_val == NULL ) { + ber_dupbv( &lc->bound_dn, &lc->conn->c_cdn ); + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] bindDn: \"%s\" ->" + " \"%s\"\n%s", + lc->conn->c_cdn.bv_val, + lc->bound_dn.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> bindDn: \"%s\" ->" + " \"%s\"\n%s", + lc->conn->c_cdn.bv_val, + lc->bound_dn.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", + NULL, NULL ); + return( NULL ); + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, + LDAP_OPERATIONS_ERROR, + NULL, "Operations error", + NULL, NULL ); + return( NULL ); + } +#else /* !ENABLE_REWRITE */ + struct berval bv; + ldap_back_dn_massage( li, &lc->conn->c_cdn, &bv, 0, 1 ); + if ( bv.bv_val == lc->conn->c_cdn.bv_val ) + ber_dupbv( &lc->bound_dn, &bv ); + else + lc->bound_dn = bv; +#endif /* !ENABLE_REWRITE */ + } else { + lc->bound_dn.bv_val = NULL; + lc->bound_dn.bv_len = 0; + } + lc->bound = 0; + + /* Inserts the newly created ldapconn in the avl tree */ + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + err = avl_insert( &li->conntree, (caddr_t)lc, + ldap_back_conn_cmp, ldap_back_conn_dup ); + +#if PRINT_CONNTREE > 0 + myprint( li->conntree ); +#endif /* PRINT_CONNTREE */ + + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldap_back_getconn: conn %ld inserted\n", + lc->conn->c_connid )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_getconn: conn %ld inserted\n%s%s", + lc->conn->c_connid, "", "" ); +#endif /* !NEW_LOGGING */ + + /* Err could be -1 in case a duplicate ldapconn is inserted */ + if ( err != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "internal server error", NULL, NULL ); + /* better destroy the ldapconn struct? */ + return( NULL ); + } + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldap_back_getconn: conn %ld inserted\n", + lc->conn->c_connid )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_getconn: conn %ld fetched%s%s\n", + lc->conn->c_connid, "", "" ); +#endif /* !NEW_LOGGING */ + } + + return( lc ); +} + +/* + * ldap_back_dobind + * + * Note: as the check for the value of lc->bound was already here, I removed + * it from all the callers, and I made the function return the flag, so + * it can be used to simplify the check. + */ +int +ldap_back_dobind(struct ldapconn *lc, Operation *op) +{ + if (lc->bound) { + return( lc->bound ); + } + + if (ldap_bind_s(lc->ld, lc->bound_dn.bv_val, NULL, LDAP_AUTH_SIMPLE) != + LDAP_SUCCESS) { + ldap_back_op_result(lc, op); + return( 0 ); + } /* else */ + return( lc->bound = 1 ); +} + +/* Map API errors to protocol errors... */ + +int +ldap_back_map_result(int err) +{ + switch(err) + { + case LDAP_SERVER_DOWN: + return LDAP_UNAVAILABLE; + case LDAP_LOCAL_ERROR: + return LDAP_OPERATIONS_ERROR; + case LDAP_ENCODING_ERROR: + case LDAP_DECODING_ERROR: + return LDAP_PROTOCOL_ERROR; + case LDAP_TIMEOUT: + return LDAP_UNAVAILABLE; + case LDAP_AUTH_UNKNOWN: + return LDAP_AUTH_METHOD_NOT_SUPPORTED; + case LDAP_FILTER_ERROR: + return LDAP_OPERATIONS_ERROR; + case LDAP_USER_CANCELLED: + return LDAP_OPERATIONS_ERROR; + case LDAP_PARAM_ERROR: + return LDAP_PROTOCOL_ERROR; + case LDAP_NO_MEMORY: + return LDAP_OPERATIONS_ERROR; + case LDAP_CONNECT_ERROR: + return LDAP_UNAVAILABLE; + case LDAP_NOT_SUPPORTED: + return LDAP_UNWILLING_TO_PERFORM; + case LDAP_CONTROL_NOT_FOUND: + return LDAP_PROTOCOL_ERROR; + case LDAP_NO_RESULTS_RETURNED: + return LDAP_NO_SUCH_OBJECT; + case LDAP_MORE_RESULTS_TO_RETURN: + return LDAP_OTHER; + case LDAP_CLIENT_LOOP: + case LDAP_REFERRAL_LIMIT_EXCEEDED: + return LDAP_LOOP_DETECT; + default: + if LDAP_API_ERROR(err) + return LDAP_OTHER; + else + return err; + } +} + +int +ldap_back_op_result(struct ldapconn *lc, Operation *op) +{ + int err = LDAP_SUCCESS; + char *msg = NULL; + char *match = NULL; + + ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &err); + ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &msg); + ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match); + err = ldap_back_map_result(err); + +#ifdef ENABLE_REWRITE + + /* + * FIXME: need rewrite info for match; mmmh ... + */ + send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL ); + /* better test the pointers before freeing? */ + if ( match ) { + free( match ); + } + +#else /* !ENABLE_REWRITE */ + + send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL ); + /* better test the pointers before freeing? */ + if ( match ) { + free( match ); + } + +#endif /* !ENABLE_REWRITE */ + + if ( msg ) free( msg ); + return( (err==LDAP_SUCCESS) ? 0 : -1 ); +} + diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c new file mode 100644 index 0000000000000000000000000000000000000000..87e4fe40a0f8208a474aad90b05e62ad39c474c0 --- /dev/null +++ b/servers/slapd/back-ldap/config.c @@ -0,0 +1,449 @@ +/* config.c - ldap backend configuration file routine */ +/* $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/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "back-ldap.h" + +int +ldap_back_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + + if ( li == NULL ) { + fprintf( stderr, "%s: line %d: ldap backend info is null!\n", + fname, lineno ); + return( 1 ); + } + + /* server address to query (depricated, use "uri" directive) */ + if ( strcasecmp( argv[0], "server" ) == 0 ) { + if (argc != 2) { + fprintf( stderr, + "%s: line %d: missing address in \"server <address>\" line\n", + fname, lineno ); + return( 1 ); + } + if (li->url != NULL) + ch_free(li->url); + li->url = ch_calloc(strlen(argv[1]) + 9, sizeof(char)); + if (li->url != NULL) { + strcpy(li->url, "ldap://"); + strcat(li->url, argv[1]); + strcat(li->url, "/"); + } + + /* URI of server to query (preferred over "server" directive) */ + } else if ( strcasecmp( argv[0], "uri" ) == 0 ) { + if (argc != 2) { + fprintf( stderr, + "%s: line %d: missing address in \"uri <address>\" line\n", + fname, lineno ); + return( 1 ); + } + if (li->url != NULL) + ch_free(li->url); + li->url = ch_strdup(argv[1]); + + /* name to use for ldap_back_group */ + } else if ( strcasecmp( argv[0], "binddn" ) == 0 ) { + if (argc != 2) { + fprintf( stderr, + "%s: line %d: missing name in \"binddn <name>\" line\n", + fname, lineno ); + return( 1 ); + } + li->binddn = ch_strdup(argv[1]); + + /* password to use for ldap_back_group */ + } else if ( strcasecmp( argv[0], "bindpw" ) == 0 ) { + if (argc != 2) { + fprintf( stderr, + "%s: line %d: missing password in \"bindpw <password>\" line\n", + fname, lineno ); + return( 1 ); + } + li->bindpw = ch_strdup(argv[1]); + + /* dn massaging */ + } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) { +#ifndef ENABLE_REWRITE + struct berval *bd2, *nd2; +#endif /* ENABLE_REWRITE */ + BackendDB *tmp_be; + struct berval bdn, ndn; + + /* + * syntax: + * + * suffixmassage <suffix> <massaged suffix> + * + * the <suffix> field must be defined as a valid suffix + * (or suffixAlias?) for the current database; + * the <massaged suffix> shouldn't have already been + * defined as a valid suffix or suffixAlias for the + * current server + */ + if ( argc != 3 ) { + fprintf( stderr, "%s: line %d: syntax is" + " \"suffixMassage <suffix>" + " <massaged suffix>\"\n", + fname, lineno ); + return( 1 ); + } + + bdn.bv_val = argv[1]; + bdn.bv_len = strlen(bdn.bv_val); + if ( dnNormalize2( NULL, &bdn, &ndn ) != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n", + fname, lineno, bdn.bv_val ); + return( 1 ); + } + tmp_be = select_backend( &ndn, 0, 0 ); + ch_free( ndn.bv_val ); + if ( tmp_be != NULL && tmp_be != be ) { + fprintf( stderr, "%s: line %d: suffix already in use" + " by another backend in" + " \"suffixMassage <suffix>" + " <massaged suffix>\"\n", + fname, lineno ); + return( 1 ); + } + + bdn.bv_val = argv[2]; + bdn.bv_len = strlen(bdn.bv_val); + if ( dnNormalize2( NULL, &bdn, &ndn ) != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n", + fname, lineno, bdn.bv_val ); + return( 1 ); + } + tmp_be = select_backend( &ndn, 0, 0 ); + ch_free( ndn.bv_val ); + if ( tmp_be != NULL ) { + fprintf( stderr, "%s: line %d: massaged suffix" + " already in use by another backend in" + " \"suffixMassage <suffix>" + " <massaged suffix>\"\n", + fname, lineno ); + return( 1 ); + } + +#ifdef ENABLE_REWRITE + /* + * The suffix massaging is emulated by means of the + * rewrite capabilities + * FIXME: no extra rewrite capabilities should be added + * to the database + */ + return suffix_massage_config( li->rwinfo, argc, argv ); +#else /* !ENABLE_REWRITE */ + bd2 = ber_bvstrdup( argv[1] ); + ber_bvecadd( &li->suffix_massage, bd2 ); + nd2 = NULL; + dnNormalize( NULL, bd2, &nd2 ); + ber_bvecadd( &li->suffix_massage, nd2 ); + + bd2 = ber_bvstrdup( argv[2] ); + ber_bvecadd( &li->suffix_massage, bd2 ); + nd2 = NULL; + dnNormalize( NULL, bd2, &nd2 ); + ber_bvecadd( &li->suffix_massage, nd2 ); +#endif /* !ENABLE_REWRITE */ + +#ifdef ENABLE_REWRITE + /* rewrite stuff ... */ + } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) { + return rewrite_parse( li->rwinfo, fname, lineno, argc, argv ); +#endif /* ENABLE_REWRITE */ + + /* objectclass/attribute mapping */ + } else if ( strcasecmp( argv[0], "map" ) == 0 ) { + struct ldapmap *map; + struct ldapmapping *mapping; + char *src, *dst; + + if ( argc < 3 || argc > 4 ) { + fprintf( stderr, + "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n", + fname, lineno ); + return( 1 ); + } + + if ( strcasecmp( argv[1], "objectclass" ) == 0 ) { + map = &li->oc_map; + } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) { + map = &li->at_map; + } else { + fprintf( stderr, "%s: line %d: syntax is " + "\"map {objectclass | attribute} {<source> | *} " + "[<dest> | *]\"\n", + fname, lineno ); + return( 1 ); + } + + if ( strcasecmp( argv[2], "*" ) != 0 ) { + src = argv[2]; + if ( argc < 4 ) + dst = ""; + else if ( strcasecmp( argv[3], "*" ) == 0 ) + dst = src; + else + dst = argv[3]; + } else { + if ( argc < 4 ) { + map->drop_missing = 1; + return 0; + } + if ( strcasecmp( argv[3], "*" ) == 0 ) { + map->drop_missing = 0; + return 0; + } + + src = argv[3]; + dst = src; + } + + if ( ( map == &li->at_map ) + && ( strcasecmp( src, "objectclass" ) == 0 + || strcasecmp( dst, "objectclass" ) == 0 ) ) + { + fprintf( stderr, + "%s: line %d: objectclass attribute cannot be mapped\n", + fname, lineno ); + } + + mapping = (struct ldapmapping *)ch_calloc( 2, + sizeof(struct ldapmapping) ); + if ( mapping == NULL ) { + fprintf( stderr, + "%s: line %d: out of memory\n", + fname, lineno ); + return( 1 ); + } + ber_str2bv( src, 0, 1, &mapping->src ); + ber_str2bv( dst, 0, 1, &mapping->dst ); + if ( *dst != 0 ) { + mapping[1].src = mapping->dst; + mapping[1].dst = mapping->src; + } else { + mapping[1].src = mapping->src; + mapping[1].dst = mapping->dst; + } + + if ( avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL || + avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL) + { + fprintf( stderr, + "%s: line %d: duplicate mapping found (ignored)\n", + fname, lineno ); + return 0; + } + + avl_insert( &map->map, (caddr_t)mapping, + mapping_cmp, mapping_dup ); + avl_insert( &map->remap, (caddr_t)&mapping[1], + mapping_cmp, mapping_dup ); + + /* anything else */ + } else { + fprintf( stderr, "%s: line %d: unknown directive \"%s\" " + "in ldap database definition (ignored)\n", + fname, lineno, argv[0] ); + } + return 0; +} + +#ifdef ENABLE_REWRITE +static char * +suffix_massage_regexize( const char *s ) +{ + char *res, *ptr; + const char *p, *r; + int i; + + for ( i = 0, p = s; + ( r = strchr( p, ',' ) ) != NULL; + p = r + 1, i++ ) + ; + + res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 ); + + ptr = slap_strcopy( res, "(.*)" ); + for ( i = 0, p = s; + ( r = strchr( p, ',' ) ) != NULL; + p = r + 1 , i++ ) { + ptr = slap_strncopy( ptr, p, r - p + 1 ); + ptr = slap_strcopy( ptr, "[ ]?" ); + + if ( r[ 1 ] == ' ' ) { + r++; + } + } + slap_strcopy( ptr, p ); + + return res; +} + +static char * +suffix_massage_patternize( const char *s, int normalize ) +{ + struct berval dn = { 0, NULL }, odn = { 0, NULL }; + int rc; + char *res; + + dn.bv_val = ( char * )s; + dn.bv_len = strlen( s ); + + if ( normalize ) { + rc = dnNormalize2( NULL, &dn, &odn ); + } else { + rc = dnPretty2( NULL, &dn, &odn ); + } + + if ( rc != LDAP_SUCCESS ) { + return NULL; + } + + res = ch_calloc( sizeof( char ), odn.bv_len + sizeof( "%1" ) ); + if ( res == NULL ) { + return NULL; + } + + strcpy( res, "%1" ); + strcpy( res + sizeof( "%1" ) - 1, odn.bv_val ); + + /* FIXME: what FREE should I use? */ + free( odn.bv_val ); + + return res; +} + +int +suffix_massage_config( + struct rewrite_info *info, + int argc, + char **argv +) +{ + char *rargv[ 5 ]; + + rargv[ 0 ] = "rewriteEngine"; + rargv[ 1 ] = "on"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "<suffix massage>", 1, 2, rargv ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "default"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "<suffix massage>", 2, 2, rargv ); + + rargv[ 0 ] = "rewriteRule"; + rargv[ 1 ] = suffix_massage_regexize( argv[ 1 ] ); + rargv[ 2 ] = suffix_massage_patternize( argv[ 2 ], 0 ); + rargv[ 3 ] = ":"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "<suffix massage>", 3, 4, rargv ); + ch_free( rargv[ 1 ] ); + ch_free( rargv[ 2 ] ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "searchResult"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "<suffix massage>", 4, 2, rargv ); + + rargv[ 0 ] = "rewriteRule"; + rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] ); + rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 0 ); + rargv[ 3 ] = ":"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "<suffix massage>", 5, 4, rargv ); + ch_free( rargv[ 1 ] ); + ch_free( rargv[ 2 ] ); + + /* + * the filter should be rewritten as + * + * rewriteRule + * "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)" + * "%1member=%2,dc=example,dc=com%3" + * + * where "o=Foo Bar, c=US" is the virtual naming context, + * and "dc=example, dc=com" is the real naming context + */ + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "searchFilter"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "<suffix massage>", 6, 2, rargv ); + +#if 0 /* matched is not normalized */ + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "matchedDn"; + rargv[ 2 ] = "alias"; + rargv[ 3 ] = "searchResult"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "<suffix massage>", 7, 4, rargv ); +#else /* normalize matched */ + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "matchedDn"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "<suffix massage>", 7, 2, rargv ); + + rargv[ 0 ] = "rewriteRule"; + rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] ); + rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 1 ); + rargv[ 3 ] = ":"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "<suffix massage>", 8, 4, rargv ); + ch_free( rargv[ 1 ] ); + ch_free( rargv[ 2 ] ); +#endif /* normalize matched */ + + return 0; +} +#endif /* ENABLE_REWRITE */ diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c new file mode 100644 index 0000000000000000000000000000000000000000..00777661d052ba729832cab1442df828a2c6c5a2 --- /dev/null +++ b/servers/slapd/back-ldap/search.c @@ -0,0 +1,554 @@ +/* search.c - ldap backend search 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 <ac/time.h> + +#include "slap.h" +#include "back-ldap.h" +#undef ldap_debug /* silence a warning in ldap-int.h */ +#include "../../../libraries/libldap/ldap-int.h" + +static void ldap_send_entry( Backend *be, Operation *op, struct ldapconn *lc, + LDAPMessage *e, AttributeName *attrs, int attrsonly ); + +int +ldap_back_search( + Backend *be, + Connection *conn, + Operation *op, + struct berval *base, + struct berval *nbase, + int scope, + int deref, + int slimit, + int tlimit, + Filter *filter, + struct berval *filterstr, + AttributeName *attrs, + int attrsonly +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + struct ldapconn *lc; + struct timeval tv; + LDAPMessage *res, *e; + int count, rc = 0, msgid, sres = LDAP_SUCCESS; + char *match = NULL, *err = NULL; + char *mapped_filter = NULL, **mapped_attrs = NULL; + struct berval mbase; +#ifdef ENABLE_REWRITE + char *mmatch = NULL; + struct berval mfilter = { 0, NULL }; +#endif /* ENABLE_REWRITE */ + struct slap_limits_set *limit = NULL; + int isroot = 0; + + lc = ldap_back_getconn(li, conn, op); + if ( !lc ) { + return( -1 ); + } + + /* if not root, get appropriate limits */ + if ( be_isroot( be, &op->o_ndn ) ) { + isroot = 1; + } else { + ( void ) get_limits( be, &op->o_ndn, &limit ); + } + + /* if no time limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && tlimit > limit->lms_t_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_t_hard == 0 ) { + tlimit = limit->lms_t_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_t_hard > 0 ) { + send_search_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + /* if no size limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && slimit > limit->lms_s_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_s_hard == 0 ) { + slimit = limit->lms_s_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_s_hard > 0 ) { + send_search_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + if (deref != -1) + ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref); + if (tlimit != -1) + ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&tlimit); + if (slimit != -1) + ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&slimit); + + if ( !ldap_back_dobind( lc, op ) ) { + return( -1 ); + } + + /* + * Rewrite the search base, if required + */ +#ifdef ENABLE_REWRITE + switch ( rewrite_session( li->rwinfo, "searchBase", + base->bv_val, conn, &mbase.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mbase.bv_val == NULL ) { + mbase = *base; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchBase: \"%s\" -> \"%s\"\n%", + base->bv_val, mbase.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s", + base->bv_val, mbase.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", NULL, NULL ); + rc = -1; + goto finish; + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "Operations error", NULL, NULL ); + rc = -1; + goto finish; + } + + /* + * Rewrite the search filter, if required + */ + switch ( rewrite_session( li->rwinfo, "searchFilter", + filterstr->bv_val, conn, &mfilter.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mfilter.bv_val == NULL || mfilter.bv_val[0] == '\0') { + if ( mfilter.bv_val != NULL ) { + free( mfilter.bv_val ); + } + mfilter = *filterstr; + } else { + mfilter.bv_len = strlen( mfilter.bv_val ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchFilter: \"%s\" -> \"%s\"\n", + filterstr->bv_val, mfilter.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> searchFilter: \"%s\" -> \"%s\"\n%s", + filterstr->bv_val, mfilter.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", NULL, NULL ); + case REWRITE_REGEXEC_ERR: + rc = -1; + goto finish; + } +#else /* !ENABLE_REWRITE */ + ldap_back_dn_massage( li, base, &mbase, 0, 1 ); +#endif /* !ENABLE_REWRITE */ + + mapped_filter = ldap_back_map_filter(&li->at_map, &li->oc_map, +#ifdef ENABLE_REWRITE + &mfilter, +#else /* !ENABLE_REWRITE */ + filterstr, +#endif /* !ENABLE_REWRITE */ + 0); + if ( mapped_filter == NULL ) { +#ifdef ENABLE_REWRITE + mapped_filter = mfilter.bv_val; +#else /* !ENABLE_REWRITE */ + mapped_filter = filterstr->bv_val; +#endif /* !ENABLE_REWRITE */ + } + +#ifdef ENABLE_REWRITE + if ( mfilter.bv_val != filterstr->bv_val ) { + free( mfilter.bv_val ); + } +#endif /* ENABLE_REWRITE */ + + mapped_attrs = ldap_back_map_attrs(&li->at_map, attrs, 0); + if ( mapped_attrs == NULL && attrs) { + for (count=0; attrs[count].an_name.bv_val; count++); + mapped_attrs = ch_malloc( (count+1) * sizeof(char *)); + for (count=0; attrs[count].an_name.bv_val; count++) { + mapped_attrs[count] = attrs[count].an_name.bv_val; + } + mapped_attrs[count] = NULL; + } + + if ((msgid = ldap_search(lc->ld, mbase.bv_val, scope, mapped_filter, mapped_attrs, + attrsonly)) == -1) + { +fail:; + rc = ldap_back_op_result(lc, op); + goto finish; + } + + /* We pull apart the ber result, stuff it into a slapd entry, and + * let send_search_entry stuff it back into ber format. Slow & ugly, + * but this is necessary for version matching, and for ACL processing. + */ + + for ( count=0, rc=0; + rc != -1; + rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res)) + { + /* check for abandon */ + if (op->o_abandon) { + ldap_abandon(lc->ld, msgid); + rc = 0; + goto finish; + } + if (rc == 0) { + tv.tv_sec = 0; + tv.tv_usec = 100000; + ldap_pvt_thread_yield(); + } else if (rc == LDAP_RES_SEARCH_ENTRY) { + e = ldap_first_entry(lc->ld,res); + ldap_send_entry(be, op, lc, e, attrs, attrsonly); + count++; + ldap_msgfree(res); + } else { + sres = ldap_result2error(lc->ld, res, 1); + sres = ldap_back_map_result(sres); + ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &err); + ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match); + rc = 0; + break; + } + } + + if (rc == -1) + goto fail; + +#ifdef ENABLE_REWRITE + /* + * Rewrite the matched portion of the search base, if required + */ + if ( match != NULL ) { + switch ( rewrite_session( li->rwinfo, "matchedDn", + match, conn, &mmatch ) ) { + case REWRITE_REGEXEC_OK: + if ( mmatch == NULL ) { + mmatch = ( char * )match; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] matchedDn:" + " \"%s\" -> \"%s\"\n", + match, mmatch )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:" + " \"%s\" -> \"%s\"\n%s", + match, mmatch, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", + NULL, NULL ); + + case REWRITE_REGEXEC_ERR: + rc = -1; + goto finish; + } + } + + send_search_result( conn, op, sres, + mmatch, err, NULL, NULL, count ); + +#else /* !ENABLE_REWRITE */ + send_search_result( conn, op, sres, + match, err, NULL, NULL, count ); +#endif /* !ENABLE_REWRITE */ + +finish:; + if ( match ) { +#ifdef ENABLE_REWRITE + if ( mmatch != match ) { + free( mmatch ); + } +#endif /* ENABLE_REWRITE */ + LDAP_FREE(match); + } + if ( err ) { + LDAP_FREE( err ); + } + if ( mapped_attrs ) { + ch_free( mapped_attrs ); + } + if ( mapped_filter != filterstr->bv_val ) { + ch_free( mapped_filter ); + } + if ( mbase.bv_val != base->bv_val ) { + free( mbase.bv_val ); + } + + return rc; +} + +static void +ldap_send_entry( + Backend *be, + Operation *op, + struct ldapconn *lc, + LDAPMessage *e, + AttributeName *attrs, + int attrsonly +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + struct berval a, mapped; + Entry ent; + BerElement ber = *e->lm_ber; + Attribute *attr, **attrp; + struct berval dummy = { 0, NULL }; + struct berval *bv, bdn; + const char *text; + + if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) { + return; + } +#ifdef ENABLE_REWRITE + + /* + * Rewrite the dn of the result, if needed + */ + switch ( rewrite_session( li->rwinfo, "searchResult", + bdn.bv_val, lc->conn, &ent.e_name.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( ent.e_name.bv_val == NULL ) { + ent.e_name = bdn; + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchResult: \"%s\"" + " -> \"%s\"\n", bdn.bv_val, ent.e_dn )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> searchResult: \"%s\"" + " -> \"%s\"\n%s", bdn.bv_val, ent.e_dn, "" ); +#endif /* !NEW_LOGGING */ + ent.e_name.bv_len = strlen( ent.e_name.bv_val ); + } + break; + + case REWRITE_REGEXEC_ERR: + case REWRITE_REGEXEC_UNWILLING: + return; + } +#else /* !ENABLE_REWRITE */ + ldap_back_dn_massage( li, &bdn, &ent.e_name, 0, 0 ); +#endif /* !ENABLE_REWRITE */ + + dnNormalize2( NULL, &ent.e_name, &ent.e_nname ); + ent.e_id = 0; + ent.e_attrs = 0; + ent.e_private = 0; + attrp = &ent.e_attrs; + + while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { + ldap_back_map(&li->at_map, &a, &mapped, 1); + if (mapped.bv_val == NULL) + continue; + attr = (Attribute *)ch_malloc( sizeof(Attribute) ); + if (attr == NULL) + continue; + attr->a_flags = 0; + attr->a_next = 0; + attr->a_desc = NULL; + if (slap_bv2ad(&mapped, &attr->a_desc, &text) != LDAP_SUCCESS) { + if (slap_bv2undef_ad(&mapped, &attr->a_desc, &text) + != LDAP_SUCCESS) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "slap_bv2undef_ad(%s): " + "%s\n", mapped.bv_val, text )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "slap_bv2undef_ad(%s): " + "%s\n%s", mapped.bv_val, text, "" ); +#endif /* !NEW_LOGGING */ + ch_free(attr); + continue; + } + } + + /* no subschemaSubentry */ + if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) { + ch_free(attr); + continue; + } + + if (ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR ) { + attr->a_vals = &dummy; + } else if ( attr->a_desc == slap_schema.si_ad_objectClass + || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { + int i, last; + for ( last = 0; attr->a_vals[last].bv_val; last++ ) ; + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + ldap_back_map(&li->oc_map, bv, &mapped, 1); + if (mapped.bv_val == NULL) { + LBER_FREE(bv->bv_val); + bv->bv_val = NULL; + if (--last < 0) + break; + *bv = attr->a_vals[last]; + attr->a_vals[last].bv_val = NULL; + i--; + } else if ( mapped.bv_val != bv->bv_val ) { + /* + * FIXME: after LBER_FREEing + * the value is replaced by + * ch_alloc'ed memory + */ + LBER_FREE(bv->bv_val); + ber_dupbv( bv, &mapped ); + } + } + +#ifdef ENABLE_REWRITE + /* + * It is necessary to try to rewrite attributes with + * dn syntax because they might be used in ACLs as + * members of groups; since ACLs are applied to the + * rewritten stuff, no dn-based subecj clause could + * be used at the ldap backend side (see + * http://www.OpenLDAP.org/faq/data/cache/452.html) + * The problem can be overcome by moving the dn-based + * ACLs to the target directory server, and letting + * everything pass thru the ldap backend. + */ + } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid, + SLAPD_DN_SYNTAX ) == 0 ) { + int i; + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + char *newval; + + switch ( rewrite_session( li->rwinfo, + "searchResult", + bv->bv_val, + lc->conn, &newval )) { + case REWRITE_REGEXEC_OK: + /* left as is */ + if ( newval == NULL ) { + break; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", + LDAP_LEVEL_DETAIL1, + "[rw] searchResult on" + " attr=%s:" + " \"%s\" -> \"%s\"\n", + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> searchResult on attr=%s: \"%s\" -> \"%s\"\n", + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval ); +#endif /* !NEW_LOGGING */ + free( bv->bv_val ); + bv->bv_val = newval; + bv->bv_len = strlen( newval ); + + break; + + case REWRITE_REGEXEC_UNWILLING: + + case REWRITE_REGEXEC_ERR: + /* + * FIXME: better give up, + * skip the attribute + * or leave it untouched? + */ + break; + } + } +#endif /* ENABLE_REWRITE */ + } + + *attrp = attr; + attrp = &attr->a_next; + } + send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, NULL ); + while (ent.e_attrs) { + attr = ent.e_attrs; + ent.e_attrs = attr->a_next; + if (attr->a_vals != &dummy) + ber_bvarray_free(attr->a_vals); + ch_free(attr); + } + + if ( ent.e_dn && ent.e_dn != bdn.bv_val ) + free( ent.e_dn ); + if ( ent.e_ndn ) + free( ent.e_ndn ); +} diff --git a/servers/slapd/back-ldbm/attribute.c b/servers/slapd/back-ldbm/attribute.c new file mode 100644 index 0000000000000000000000000000000000000000..eaa8d3e116e2cece0b479d0b0cb8c1f4605e0b89 --- /dev/null +++ b/servers/slapd/back-ldbm/attribute.c @@ -0,0 +1,213 @@ +/* attribute.c - ldbm backend acl attribute routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" + + +/* return LDAP_SUCCESS IFF we can retrieve the attributes + * of entry with e_ndn + */ +int +ldbm_back_attribute( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *entry_ndn, + AttributeDescription *entry_at, + BerVarray *vals ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + int rc; + Attribute *attr; + BerVarray v; + const char *entry_at_name = entry_at->ad_cname.bv_val; + struct berval *iv, *jv; + AccessControlState acl_state = ACL_STATE_INIT; + int nvals = 0; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "ldbm_back_attribute: gr dn: \"%s\"\n", entry_ndn->bv_val )); + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "ldbm_back_attribute: at: \"%s\"\n", entry_at_name)); + LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, + "ldbm_back_attribute: tr dn: \"%s\"\n", + target ? target->e_ndn : "" )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> ldbm_back_attribute: gr dn: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ARGS, + "=> ldbm_back_attribute: at: \"%s\"\n", + entry_at_name, 0, 0 ); + + Debug( LDAP_DEBUG_ARGS, + "=> ldbm_back_attribute: tr dn: \"%s\"\n", + target ? target->e_ndn : "", 0, 0 ); +#endif + + if (target != NULL && dn_match( &target->e_nname, entry_ndn) ) { + /* we already have a LOCKED copy of the entry */ + e = target; +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_attribute: target is LOCKED (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, + "=> ldbm_back_attribute: target is entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + + + } else { + /* can we find entry with reader lock */ + if ((e = dn2entry_r(be, entry_ndn, NULL )) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_attribute: cannot find entry (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> ldbm_back_attribute: cannot find entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + + return LDAP_NO_SUCH_OBJECT; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_attribute: found entry (%s)\n", + entry_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_ACL, + "=> ldbm_back_attribute: found entry: \"%s\"\n", + entry_ndn->bv_val, 0, 0 ); +#endif + + } + + /* find attribute values */ + + if( is_entry_alias( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_attribute: entry (%s) is an alias\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_attribute: entry is an alias\n", 0, 0, 0 ); +#endif + + rc = LDAP_ALIAS_PROBLEM; + goto return_results; + } + + if( is_entry_referral( e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_attribute: entry (%s) is a referral.\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_attribute: entry is an referral\n", 0, 0, 0 ); +#endif + + rc = LDAP_REFERRAL; + goto return_results; + } + + if (conn != NULL && op != NULL + && access_allowed( be, conn, op, e, slap_schema.si_ad_entry, + NULL, ACL_READ, NULL ) == 0) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + if ((attr = attr_find(e->e_attrs, entry_at)) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_attribute: failed to find %s.\n", entry_at_name )); +#else + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_attribute: failed to find %s\n", + entry_at_name, 0, 0 ); +#endif + + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_results; + } + + if (conn != NULL && op != NULL + && access_allowed( be, conn, op, e, entry_at, NULL, + ACL_READ, &acl_state ) == 0) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + for ( iv = attr->a_vals; iv->bv_val != NULL; iv++ ) { + /* count them */ + } + + v = (BerVarray) ch_malloc( sizeof(struct berval) * ((iv - attr->a_vals)+1) ); + + for ( iv=attr->a_vals, jv=v; iv->bv_val; iv++ ) { + if( conn != NULL + && op != NULL + && access_allowed( be, conn, op, e, entry_at, + iv, ACL_READ, &acl_state ) == 0) + { + continue; + } + ber_dupbv( jv, iv ); + + if( jv->bv_val != NULL ) jv++; + } + + nvals = jv - v; + + if( jv == v ) { + ch_free( v ); + *vals = NULL; + rc = LDAP_INSUFFICIENT_ACCESS; + } else { + jv->bv_val = NULL; + *vals = v; + rc = LDAP_SUCCESS; + } + +return_results: + if( target != e ) { + /* free entry and reader lock */ + cache_return_entry_r( &li->li_cache, e ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_back_attribute: rc=%d nvals=%d.\n", + rc, nvals )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_attribute: rc=%d nvals=%d\n", + rc, nvals, 0 ); +#endif + + return(rc); +} + diff --git a/servers/slapd/back-ldbm/cache.c b/servers/slapd/back-ldbm/cache.c index 49fafb6975da2512d64a8bc545abb392a1f6004b..72ec35e9b72cb6ef6b74670f54e47ac8e924430f 100644 --- a/servers/slapd/back-ldbm/cache.c +++ b/servers/slapd/back-ldbm/cache.c @@ -1,146 +1,309 @@ /* cache.c - routines to maintain an in-core cache of entries */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" + #include "back-ldbm.h" -static int cache_delete_entry_internal(); +/* LDBM backend specific entry info -- visible only to the cache */ +typedef struct ldbm_entry_info { + /* + * These items are specific to the LDBM backend and should + * be hidden. Backend cache lock required to access. + */ + int lei_state; /* for the cache */ +#define CACHE_ENTRY_UNDEFINED 0 +#define CACHE_ENTRY_CREATING 1 +#define CACHE_ENTRY_READY 2 +#define CACHE_ENTRY_DELETED 3 +#define CACHE_ENTRY_COMMITTED 4 + + int lei_refcnt; /* # threads ref'ing this entry */ + Entry *lei_lrunext; /* for cache lru list */ + Entry *lei_lruprev; +} EntryInfo; +#undef LEI +#define LEI(e) ((EntryInfo *) ((e)->e_private)) + +static int cache_delete_entry_internal(Cache *cache, Entry *e); #ifdef LDAP_DEBUG -static void lru_print(); +static void lru_print(Cache *cache); #endif -/* - * the cache has three entry points (ways to find things): - * - * by entry e.g., if you already have an entry from the cache - * and want to delete it. (really by entry ptr) - * by dn e.g., when looking for the base object of a search - * by id e.g., for search candidates - * - * these correspond to three different avl trees that are maintained. - */ - static int -cache_entry_cmp( Entry *e1, Entry *e2 ) +cache_entry_private_init( Entry*e ) { - return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) ); + assert( e->e_private == NULL ); + + if( e->e_private != NULL ) { + /* this should never happen */ + return 1; + } + + e->e_private = ch_calloc(1, sizeof(struct ldbm_entry_info)); + + return 0; } -static int -cache_entrydn_cmp( Entry *e1, Entry *e2 ) +/* + * marks an entry in CREATING state as committed, so it is really returned + * to the cache. Otherwise an entry in CREATING state is removed. + * Makes e_private be destroyed at the following cache_return_entry_w, + * but lets the entry untouched (owned by someone else) + */ +void +cache_entry_commit( Entry *e ) { - return( strcasecmp( e1->e_dn, e2->e_dn ) ); + assert( e ); + assert( e->e_private ); + assert( LEI(e)->lei_state == CACHE_ENTRY_CREATING ); + /* assert( LEI(e)->lei_refcnt == 1 ); */ + + LEI(e)->lei_state = CACHE_ENTRY_COMMITTED; } static int -cache_entryid_cmp( Entry *e1, Entry *e2 ) +cache_entry_private_destroy( Entry*e ) { - return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) ); + assert( e->e_private ); + + free( e->e_private ); + e->e_private = NULL; + return 0; } void -cache_set_state( struct cache *cache, Entry *e, int state ) +cache_return_entry_rw( Cache *cache, Entry *e, int rw ) { - /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + ID id; + int refcnt, freeit = 1; - e->e_state = state; + /* set cache mutex */ + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); - /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); -} + assert( e->e_private ); -void -cache_return_entry( struct cache *cache, Entry *e ) -{ - /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + id = e->e_id; + refcnt = --LEI(e)->lei_refcnt; - if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) { - entry_free( e ); + /* + * if the entry is returned when in CREATING state, it is deleted + * but not freed because it may belong to someone else (do_add, + * for instance) + */ + if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) { + cache_delete_entry_internal( cache, e ); + freeit = 0; + /* now the entry is in DELETED state */ } - /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + if ( LEI(e)->lei_state == CACHE_ENTRY_COMMITTED ) { + LEI(e)->lei_state = CACHE_ENTRY_READY; + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_return_entry_rw: return (%ld):%s, refcnt=%d\n", + id, rw ? "w" : "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_return_entry_%s( %ld ): created (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + } else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) { + if( refcnt > 0 ) { + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_return_entry_rw: %ld, delete pending (%d).\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_return_entry_%s( %ld ): delete pending (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + } else { + cache_entry_private_destroy( e ); + if ( freeit ) { + entry_free( e ); + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_return_entry_rw: (%ld): deleted (%d)\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_return_entry_%s( %ld ): deleted (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + } + + } else { + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_return_entry_rw: ID %ld:%s returned (%d)\n", + id, rw ? "w": "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_return_entry_%s( %ld ): returned (%d)\n", + rw ? "w" : "r", id, refcnt); +#endif + } } -#define LRU_DELETE( cache, e ) { \ - if ( e->e_lruprev != NULL ) { \ - e->e_lruprev->e_lrunext = e->e_lrunext; \ +#define LRU_DELETE( cache, e ) do { \ + if ( LEI(e)->lei_lruprev != NULL ) { \ + LEI(LEI(e)->lei_lruprev)->lei_lrunext = LEI(e)->lei_lrunext; \ } else { \ - cache->c_lruhead = e->e_lrunext; \ + (cache)->c_lruhead = LEI(e)->lei_lrunext; \ } \ - if ( e->e_lrunext != NULL ) { \ - e->e_lrunext->e_lruprev = e->e_lruprev; \ + if ( LEI(e)->lei_lrunext != NULL ) { \ + LEI(LEI(e)->lei_lrunext)->lei_lruprev = LEI(e)->lei_lruprev; \ } else { \ - cache->c_lrutail = e->e_lruprev; \ + (cache)->c_lrutail = LEI(e)->lei_lruprev; \ } \ -} +} while(0) -#define LRU_ADD( cache, e ) { \ - e->e_lrunext = cache->c_lruhead; \ - if ( e->e_lrunext != NULL ) { \ - e->e_lrunext->e_lruprev = e; \ +#define LRU_ADD( cache, e ) do { \ + LEI(e)->lei_lrunext = (cache)->c_lruhead; \ + if ( LEI(e)->lei_lrunext != NULL ) { \ + LEI(LEI(e)->lei_lrunext)->lei_lruprev = (e); \ } \ - cache->c_lruhead = e; \ - e->e_lruprev = NULL; \ - if ( cache->c_lrutail == NULL ) { \ - cache->c_lrutail = e; \ + (cache)->c_lruhead = (e); \ + LEI(e)->lei_lruprev = NULL; \ + if ( (cache)->c_lrutail == NULL ) { \ + (cache)->c_lrutail = (e); \ } \ -} +} while(0) /* - * cache_create_entry_lock - create an entry in the cache, and lock it. + * cache_add_entry_rw - create and lock an entry in the cache * returns: 0 entry has been created and locked * 1 entry already existed * -1 something bad happened */ int -cache_add_entry_lock( - struct cache *cache, +cache_add_entry_rw( + Cache *cache, Entry *e, - int state + int rw ) { int i, rc; Entry *ee; +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "cache_add_entry_rw: add (%s):%s to cache\n", + e->e_dn, rw ? "w" : "r" )); +#endif /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); - if ( avl_insert( &cache->c_dntree, e, cache_entrydn_cmp, avl_dup_error ) - != 0 ) { - Debug( LDAP_DEBUG_TRACE, - "entry %20s id %d already in dn cache\n", e->e_dn, - e->e_id, 0 ); + assert( e->e_private == NULL ); + + if( cache_entry_private_init(e) != 0 ) { + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ERR, + "cache_add_entry_rw: add (%s):%ld private init failed!\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> cache_add_entry( %ld ): \"%s\": private init failed!\n", + e->e_id, e->e_dn, 0 ); +#endif + + return( -1 ); + } + if ( avl_insert( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 ) + { /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_add_entry: (%s):%ld already in cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_add_entry( %ld ): \"%s\": already in dn cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + cache_entry_private_destroy(e); + return( 1 ); } /* id tree */ - if ( avl_insert( &cache->c_idtree, e, cache_entryid_cmp, avl_dup_error ) - != 0 ) { - Debug( LDAP_DEBUG_ANY, "entry %20s id %d already in id cache\n", - e->e_dn, e->e_id, 0 ); + if ( avl_insert( &cache->c_idtree, (caddr_t) e, + (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_add_entry: (%s):%ls already in cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> cache_add_entry( %ld ): \"%s\": already in id cache\n", + e->e_id, e->e_dn, 0 ); +#endif /* delete from dn tree inserted above */ - if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp ) - == NULL ) { - Debug( LDAP_DEBUG_ANY, "can't delete from dn cache\n", + if ( avl_delete( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp ) == NULL ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "cache_add_entry: can't delete (%s) from cache.\n", + e->e_dn )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 ); +#endif } + cache_entry_private_destroy(e); + /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); return( -1 ); } - e->e_state = state; - e->e_refcnt = 1; + /* put the entry into 'CREATING' state */ + /* will be marked after when entry is returned */ + LEI(e)->lei_state = CACHE_ENTRY_CREATING; + LEI(e)->lei_refcnt = 1; /* lru */ LRU_ADD( cache, e ); @@ -151,8 +314,10 @@ cache_add_entry_lock( * first 10 on the tail of the list. */ i = 0; - while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt - != 0 && i < 10 ) { + while ( cache->c_lrutail != NULL && + LEI(cache->c_lrutail)->lei_refcnt != 0 && + i < 10 ) + { /* move this in-use entry to the front of the q */ ee = cache->c_lrutail; LRU_DELETE( cache, ee ); @@ -164,61 +329,225 @@ cache_add_entry_lock( * found at least one to delete - try to get back under * the max cache size. */ - while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt - == 0 && cache->c_cursize > cache->c_maxsize ) { + while ( cache->c_lrutail != NULL && + LEI(cache->c_lrutail)->lei_refcnt == 0 && + cache->c_cursize > cache->c_maxsize ) + { e = cache->c_lrutail; /* delete from cache and lru q */ + /* XXX do we need rc ? */ rc = cache_delete_entry_internal( cache, e ); - + cache_entry_private_destroy( e ); entry_free( e ); } } /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); return( 0 ); } /* - * cache_find_entry_dn - find an entry in the cache, given dn + * cache_update_entry - update a LOCKED entry which has been deleted. + * returns: 0 entry has been created and locked + * 1 entry already existed + * -1 something bad happened */ +int +cache_update_entry( + Cache *cache, + Entry *e +) +{ + int i, rc; + Entry *ee; -Entry * -cache_find_entry_dn( - struct cache *cache, - char *dn + /* set cache mutex */ + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); + + assert( e->e_private ); + + if ( avl_insert( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_update_entry: (%s):%ld already in dn cache\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> cache_update_entry( %ld ): \"%s\": already in dn cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + return( 1 ); + } + + /* id tree */ + if ( avl_insert( &cache->c_idtree, (caddr_t) e, + (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_update_entry: (%s)%ld already in id cache\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, + "====> cache_update_entry( %ld ): \"%s\": already in id cache\n", + e->e_id, e->e_dn, 0 ); +#endif + + /* delete from dn tree inserted above */ + if ( avl_delete( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp ) == NULL ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "cache_update_entry: can't delete (%s)%ld from dn cache.\n", + e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", + 0, 0, 0 ); +#endif + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + return( -1 ); + } + + /* put the entry into 'CREATING' state */ + /* will be marked after when entry is returned */ + LEI(e)->lei_state = CACHE_ENTRY_CREATING; + + /* lru */ + LRU_ADD( cache, e ); + if ( ++cache->c_cursize > cache->c_maxsize ) { + /* + * find the lru entry not currently in use and delete it. + * in case a lot of entries are in use, only look at the + * first 10 on the tail of the list. + */ + i = 0; + while ( cache->c_lrutail != NULL && + LEI(cache->c_lrutail)->lei_refcnt != 0 && + i < 10 ) + { + /* move this in-use entry to the front of the q */ + ee = cache->c_lrutail; + LRU_DELETE( cache, ee ); + LRU_ADD( cache, ee ); + i++; + } + + /* + * found at least one to delete - try to get back under + * the max cache size. + */ + while ( cache->c_lrutail != NULL && + LEI(cache->c_lrutail)->lei_refcnt == 0 && + cache->c_cursize > cache->c_maxsize ) + { + e = cache->c_lrutail; + + /* delete from cache and lru q */ + /* XXX do we need rc ? */ + rc = cache_delete_entry_internal( cache, e ); + cache_entry_private_destroy( e ); + entry_free( e ); + } + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + return( 0 ); +} + +ID +cache_find_entry_ndn2id( + Backend *be, + Cache *cache, + struct berval *ndn ) { Entry e, *ep; + ID id; + int count = 0; + /* this function is always called with normalized DN */ + e.e_nname = *ndn; + +try_again: /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); + + if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e, + (AVL_CMP) entry_dn_cmp )) != NULL ) + { + int state; + count++; + + /* + * ep now points to an unlocked entry + * we do not need to lock the entry if we only + * check the state, refcnt, LRU, and id. + */ + assert( ep->e_private ); + + /* save id */ + id = ep->e_id; + state = LEI(ep)->lei_state; - e.e_dn = dn; - if ( (ep = (Entry *) avl_find( cache->c_dntree, &e, cache_entrydn_cmp )) - != NULL ) { /* * entry is deleted or not fully created yet */ - if ( ep->e_state == ENTRY_STATE_DELETED || - ep->e_state == ENTRY_STATE_CREATING ) - { + if ( state != CACHE_ENTRY_READY ) { + assert(state != CACHE_ENTRY_UNDEFINED); + /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); - return( NULL ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "cache_find_entry_dn2id: (%s) %ld not ready: %d\n", + ndn->bv_val, id, state )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n", + ndn->bv_val, id, state); +#endif + + ldap_pvt_thread_yield(); + goto try_again; } - ep->e_refcnt++; /* lru */ LRU_DELETE( cache, ep ); LRU_ADD( cache, ep ); - } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_find_entry_dn2id: (%s): %ld %d tries\n", + ndn->bv_val, id, count )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n", + ndn->bv_val, id, count); +#endif - /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + } else { + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + id = NOID; + } - return( ep ); + return( id ); } /* @@ -227,40 +556,84 @@ cache_find_entry_dn( Entry * cache_find_entry_id( - struct cache *cache, - ID id + Cache *cache, + ID id, + int rw ) { Entry e; Entry *ep; + int count = 0; + e.e_id = id; + +try_again: /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); + + if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e, + (AVL_CMP) entry_id_cmp )) != NULL ) + { + int state; + ID ep_id; + + count++; + + assert( ep->e_private ); + + ep_id = ep->e_id; + state = LEI(ep)->lei_state; - e.e_id = id; - if ( (ep = (Entry *) avl_find( cache->c_idtree, &e, cache_entryid_cmp )) - != NULL ) { /* * entry is deleted or not fully created yet */ - if ( ep->e_state == ENTRY_STATE_DELETED || - ep->e_state == ENTRY_STATE_CREATING ) - { + if ( state != CACHE_ENTRY_READY ) { + assert(state != CACHE_ENTRY_UNDEFINED); + /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); - return( NULL ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "cache_find_entry_id: (%ld)->%ld not ready (%d).\n", + id, ep_id, state )); + +#else + Debug(LDAP_DEBUG_TRACE, + "====> cache_find_entry_id( %ld ): %ld (not ready) %d\n", + id, ep_id, state); +#endif + + ldap_pvt_thread_yield(); + goto try_again; } - ep->e_refcnt++; /* lru */ LRU_DELETE( cache, ep ); LRU_ADD( cache, ep ); + + LEI(ep)->lei_refcnt++; + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "cache_find_entry_id: %ld -> %s found %d tries.\n", + ep_id, ep->e_dn, count )); +#else + Debug(LDAP_DEBUG_TRACE, + "====> cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n", + ep_id, ep->e_dn, count); +#endif + + return( ep ); } /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); - return( ep ); + return( NULL ); } /* @@ -276,36 +649,56 @@ cache_find_entry_id( */ int cache_delete_entry( - struct cache *cache, + Cache *cache, Entry *e ) { int rc; /* set cache mutex */ - pthread_mutex_lock( &cache->c_mutex ); + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); + + assert( e->e_private ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "cache_delete_entry: delete %ld.\n", e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry( %ld )\n", + e->e_id, 0, 0 ); +#endif rc = cache_delete_entry_internal( cache, e ); /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); return( rc ); } static int cache_delete_entry_internal( - struct cache *cache, + Cache *cache, Entry *e ) { + int rc = 0; /* return code */ + /* dn tree */ - if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp ) == NULL ) { - return( -1 ); + if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp ) + == NULL ) + { + rc = -1; } /* id tree */ - if ( avl_delete( &cache->c_idtree, e, cache_entryid_cmp ) == NULL ) { - return( -1 ); + if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp ) + == NULL ) + { + rc = -1; + } + + if (rc != 0) { + return rc; } /* lru */ @@ -315,28 +708,64 @@ cache_delete_entry_internal( /* * flag entry to be freed later by a call to cache_return_entry() */ - e->e_state = ENTRY_STATE_DELETED; + LEI(e)->lei_state = CACHE_ENTRY_DELETED; return( 0 ); } -#ifdef LDAP_DEBUG +void +cache_release_all( Cache *cache ) +{ + Entry *e; + int rc; + + /* set cache mutex */ + ldap_pvt_thread_mutex_lock( &cache->c_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "cache_release_all: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "====> cache_release_all\n", 0, 0, 0 ); +#endif + + while ( (e = cache->c_lrutail) != NULL && LEI(e)->lei_refcnt == 0 ) { + /* delete from cache and lru q */ + /* XXX do we need rc ? */ + rc = cache_delete_entry_internal( cache, e ); + cache_entry_private_destroy( e ); + entry_free( e ); + } + + if ( cache->c_cursize ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "cache_release_all: Entry cache could not be emptied.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 ); +#endif + } + + /* free cache mutex */ + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); +} + +#ifdef LDAP_DEBUG static void -lru_print( struct cache *cache ) +lru_print( Cache *cache ) { Entry *e; fprintf( stderr, "LRU queue (head to tail):\n" ); - for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) { - fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn, - e->e_id, e->e_refcnt ); + for ( e = cache->c_lruhead; e != NULL; e = LEI(e)->lei_lrunext ) { + fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n", + e->e_dn, e->e_id, LEI(e)->lei_refcnt ); } fprintf( stderr, "LRU queue (tail to head):\n" ); - for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) { - fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn, - e->e_id, e->e_refcnt ); + for ( e = cache->c_lrutail; e != NULL; e = LEI(e)->lei_lruprev ) { + fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n", + e->e_dn, e->e_id, LEI(e)->lei_refcnt ); } } - #endif diff --git a/servers/slapd/back-ldbm/config.c b/servers/slapd/back-ldbm/config.c index d6aca2c413fcd20213bd8f75e8d04b630ee5868f..3c8475024e5621e81739513579404b4ef4e2c1ca 100644 --- a/servers/slapd/back-ldbm/config.c +++ b/servers/slapd/back-ldbm/config.c @@ -1,26 +1,36 @@ /* config.c - ldbm backend configuration file routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/socket.h> +#include <ac/string.h> + #include "slap.h" #include "back-ldbm.h" -ldbm_back_config( +int +ldbm_back_db_config( Backend *be, - char *fname, + const char *fname, int lineno, int argc, char **argv ) { + int rc; struct ldbminfo *li = (struct ldbminfo *) be->be_private; if ( li == NULL ) { - fprintf( stderr, "%s: line %d: ldbm backend info is null!\n", + fprintf( stderr, "%s: line %d: ldbm database info is null!\n", fname, lineno ); - exit( 1 ); + return( 1 ); } /* directory where database files live */ @@ -29,9 +39,11 @@ ldbm_back_config( fprintf( stderr, "%s: line %d: missing dir in \"directory <dir>\" line\n", fname, lineno ); - exit( 1 ); + return( 1 ); } - li->li_directory = strdup( argv[1] ); + if ( li->li_directory ) + free( li->li_directory ); + li->li_directory = ch_strdup( argv[1] ); /* mode with which to create new database files */ } else if ( strcasecmp( argv[0], "mode" ) == 0 ) { @@ -39,7 +51,7 @@ ldbm_back_config( fprintf( stderr, "%s: line %d: missing mode in \"mode <mode>\" line\n", fname, lineno ); - exit( 1 ); + return( 1 ); } li->li_mode = strtol( argv[1], NULL, 0 ); @@ -49,13 +61,15 @@ ldbm_back_config( fprintf( stderr, "%s: line %d: missing attr in \"index <attr> [pres,eq,approx,sub]\" line\n", fname, lineno ); - exit( 1 ); + return( 1 ); } else if ( argc > 3 ) { fprintf( stderr, "%s: line %d: extra junk after \"index <attr> [pres,eq,approx,sub]\" line (ignored)\n", fname, lineno ); } - attr_index_config( li, fname, lineno, argc - 1, &argv[1], 0 ); + rc = attr_index_config( li, fname, lineno, argc - 1, &argv[1] ); + + if( rc != LDAP_SUCCESS ) return 1; /* size of the cache in entries */ } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) { @@ -63,7 +77,7 @@ ldbm_back_config( fprintf( stderr, "%s: line %d: missing size in \"cachesize <size>\" line\n", fname, lineno ); - exit( 1 ); + return( 1 ); } li->li_cache.c_maxsize = atoi( argv[1] ); @@ -73,14 +87,112 @@ ldbm_back_config( fprintf( stderr, "%s: line %d: missing size in \"dbcachesize <size>\" line\n", fname, lineno ); - exit( 1 ); + return( 1 ); } li->li_dbcachesize = atoi( argv[1] ); + /* no locking (not safe) */ + } else if ( strcasecmp( argv[0], "dbnolocking" ) == 0 ) { + li->li_dblocking = 0; + + /* no write sync (not safe) */ + } else if ( ( strcasecmp( argv[0], "dbnosync" ) == 0 ) + || ( strcasecmp( argv[0], "dbcachenowsync" ) == 0 ) ) + { + li->li_dbwritesync = 0; + + /* run sync thread */ + } else if ( strcasecmp( argv[0], "dbsync" ) == 0 ) { +#ifndef NO_THREADS + int i; + if ( argc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "config", LDAP_LEVEL_ERR, "ldbm_back_db_config: %s: " + "line %d: missing frequency value in \"dbsync <frequency> " + "[<wait-times> [wait-interval]]\" line\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing frquency value in \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, 0 ); +#endif + return 1; + } + + i = atoi( argv[1] ); + + if( i < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "config", LDAP_LEVEL_ERR, "ldbm_back_db_config: %s: " + "line %d: frequency value (%d) invalid \"dbsync " + "<frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i ); +#endif + return 1; + } + + li->li_dbsyncfreq = i; + + if ( argc > 2 ) { + i = atoi( argv[2] ); + if ( i < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "config",LDAP_LEVEL_ERR, "ldbm_back_db_config: %s: " + "line %d: frequency value (%d) invalid \"dbsync " + "<frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i ); +#endif + return 1; + } + li ->li_dbsyncwaitn = i; + } + + if ( argc > 3 ) { + i = atoi( argv[3] ); + if ( i <= 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "config",LDAP_LEVEL_ERR, "ldbm_back_db_config: %s: " + "line %d: frequency value (%d) invalid \"dbsync " + "<frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n", + fname, lineno, i ); +#endif + return 1; + } + li ->li_dbsyncwaitinterval = i; + } + + /* turn off writesync when sync policy is in place */ + li->li_dbwritesync = 0; + +#else +#ifdef NEW_LOGGING + LDAP_LOG (( "config",LDAP_LEVEL_ERR, "ldbm_back_db_config: "\"dbsync\"" + " policies not supported in non-threaded environments\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "\"dbsync\" policies not supported in non-threaded environments\n", 0, 0, 0); +#endif + return 1; +#endif + + /* anything else */ } else { fprintf( stderr, "%s: line %d: unknown directive \"%s\" in ldbm database definition (ignored)\n", fname, lineno, argv[0] ); } + + return 0; } diff --git a/servers/slapd/back-ldbm/dbcache.c b/servers/slapd/back-ldbm/dbcache.c index c16c8b160dfdfe210188465c5e9f19fe74636ad4..1cf5bf9bd129513fa49c448866285521dda9d8c9 100644 --- a/servers/slapd/back-ldbm/dbcache.c +++ b/servers/slapd/back-ldbm/dbcache.c @@ -1,153 +1,252 @@ /* ldbmcache.c - maintain a cache of open ldbm files */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/param.h> + +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> #include <sys/stat.h> -#include <errno.h> -#include "portable.h" + #include "slap.h" -#include "ldapconfig.h" #include "back-ldbm.h" -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; -#endif -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; - -struct dbcache * +DBCache * ldbm_cache_open( Backend *be, - char *name, - char *suffix, + const char *name, + const char *suffix, int flags ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int i, lru; - time_t oldtime, curtime; + int i, lru, empty; + time_t oldtime; char buf[MAXPATHLEN]; - LDBM db; +#ifdef HAVE_ST_BLKSIZE struct stat st; +#endif - sprintf( buf, "%s/%s%s", li->li_directory, name, suffix ); + if (li->li_envdirok) + sprintf( buf, "%s%s", name, suffix ); + else + sprintf( buf, "%s" LDAP_DIRSEP "%s%s", + li->li_directory, name, suffix ); + if( li->li_dblocking ) { + flags |= LDBM_LOCKING; + } else { + flags |= LDBM_NOLOCKING; + } + + if( li->li_dbwritesync ) { + flags |= LDBM_SYNC; + } else { + flags |= LDBM_NOSYNC; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY, + "ldbm_cache_open: \"%s\", %d, %o\n", buf, flags, li->li_mode )); +#else Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf, flags, li->li_mode ); +#endif - lru = 0; - pthread_mutex_lock( ¤ttime_mutex ); - curtime = currenttime; - pthread_mutex_unlock( ¤ttime_mutex ); - oldtime = curtime; - - pthread_mutex_lock( &li->li_dbcache_mutex ); - for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL; - i++ ) { - /* already open - return it */ - if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) { - li->li_dbcache[i].dbc_refcnt++; - Debug( LDAP_DEBUG_TRACE, - "<= ldbm_cache_open (cache %d)\n", i, 0, 0 ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); - return( &li->li_dbcache[i] ); - } - /* keep track of lru db */ - if ( li->li_dbcache[i].dbc_lastref < oldtime && - li->li_dbcache[i].dbc_refcnt == 0 ) { - lru = i; - oldtime = li->li_dbcache[i].dbc_lastref; - } - } + empty = MAXDBCACHE; + + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + do { + lru = 0; + oldtime = 1; + for ( i = 0; i < MAXDBCACHE; i++ ) { + /* see if this slot is free */ + if ( li->li_dbcache[i].dbc_name == NULL) { + if (empty == MAXDBCACHE) + empty = i; + continue; + } - /* no empty slots, not already open - close lru and use that slot */ - if ( i == MAXDBCACHE ) { - i = lru; - if ( li->li_dbcache[i].dbc_refcnt != 0 ) { - Debug( LDAP_DEBUG_ANY, - "ldbm_cache_open no unused db to close - waiting\n", - 0, 0, 0 ); - lru = -1; - while ( lru == -1 ) { - pthread_cond_wait( &li->li_dbcache_cv, - &li->li_dbcache_mutex ); - for ( i = 0; i < MAXDBCACHE; i++ ) { - if ( li->li_dbcache[i].dbc_refcnt - == 0 ) { - lru = i; - break; - } + if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) { + /* already open - return it */ + if (li->li_dbcache[i].dbc_flags != flags + && li->li_dbcache[i].dbc_refcnt == 0) + { + /* we don't want to use an open cache with different + * permissions (esp. if we need write but the open + * cache is read-only). So close this one if + * possible, and re-open below. + * + * FIXME: what about the case where the refcount + * is > 0? right now, we're using it anyway and + * just praying. Can there be more than one open + * cache to the same db? + * + * Also, it's really only necessary to compare the + * read-only flag, instead of all of the flags, + * but for now I'm checking all of them. + */ + lru = i; + empty = MAXDBCACHE; + break; } + li->li_dbcache[i].dbc_refcnt++; +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "ldbm_cache_open: cache %d\n", i )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= ldbm_cache_open (cache %d)\n", i, 0, 0 ); +#endif + + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); + return( &li->li_dbcache[i] ); + } + + /* keep track of lru db */ + if (( li->li_dbcache[i].dbc_refcnt == 0 ) && + (( oldtime == 1 ) || + ( li->li_dbcache[i].dbc_lastref < oldtime )) ) + { + lru = i; + oldtime = li->li_dbcache[i].dbc_lastref; } - i = lru; } - ldbm_close( li->li_dbcache[i].dbc_db ); - free( li->li_dbcache[i].dbc_name ); - li->li_dbcache[i].dbc_name = NULL; - } - if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode, - li->li_dbcachesize )) == NULL ) { + i = empty; + if ( i == MAXDBCACHE ) { + /* no empty slots, not already open - close lru and use that slot */ + if ( li->li_dbcache[lru].dbc_refcnt == 0 ) { + i = lru; + ldbm_close( li->li_dbcache[i].dbc_db ); + free( li->li_dbcache[i].dbc_name ); + li->li_dbcache[i].dbc_name = NULL; + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "ldbm_cache_open: no unused db to close - waiting\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "ldbm_cache_open no unused db to close - waiting\n", + 0, 0, 0 ); +#endif + + ldap_pvt_thread_cond_wait( &li->li_dbcache_cv, + &li->li_dbcache_mutex ); + /* after waiting for a free slot, go back to square + * one: look for an open cache for this db, or an + * empty slot, or an unref'ed cache, or wait again. + */ + } + } + } while (i == MAXDBCACHE); + + if ( (li->li_dbcache[i].dbc_db = ldbm_open( li->li_dbenv, buf, flags, li->li_mode, + li->li_dbcachesize )) == NULL ) + { + int err = errno; +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ERR, + "ldbm_cache_open: \"%s\" failed, errono=%d, reason=%s\n", + buf, err, err > -1 && err < sys_nerr ? sys_errlist[err] : + "unknown" )); +#else Debug( LDAP_DEBUG_TRACE, - "<= ldbm_cache_open NULL \"%s\" errno %d reason \"%s\")\n", - buf, errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown" ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); + "<= ldbm_cache_open NULL \"%s\" errno=%d reason=\"%s\")\n", + buf, err, err > -1 && err < sys_nerr ? + sys_errlist[err] : "unknown" ); +#endif + + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); return( NULL ); } - li->li_dbcache[i].dbc_name = strdup( buf ); + li->li_dbcache[i].dbc_name = ch_strdup( buf ); li->li_dbcache[i].dbc_refcnt = 1; - li->li_dbcache[i].dbc_lastref = curtime; + li->li_dbcache[i].dbc_lastref = slap_get_time(); + li->li_dbcache[i].dbc_flags = flags; + li->li_dbcache[i].dbc_dirty = 0; +#ifdef HAVE_ST_BLKSIZE if ( stat( buf, &st ) == 0 ) { li->li_dbcache[i].dbc_blksize = st.st_blksize; - } else { + } else +#endif + { li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE; } li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize / - sizeof(ID)) - 2; - li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS / - li->li_dbcache[i].dbc_maxids) + 1; - + sizeof(ID)) - ID_BLOCK_IDS_OFFSET; + li->li_dbcache[i].dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS / + li->li_dbcache[i].dbc_maxids ) + 1; + + assert( li->li_dbcache[i].dbc_maxindirect < 256 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_ARGS, + "ldbm_cache_open: blksize:%ld maxids:%d maxindirect:%d\n", + li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids, + li->li_dbcache[i].dbc_maxindirect )); +#else Debug( LDAP_DEBUG_ARGS, - "ldbm_cache_open (blksize %d) (maxids %d) (maxindirect %d)\n", + "ldbm_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n", li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids, li->li_dbcache[i].dbc_maxindirect ); +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "<= ldbm_cache_open: (opened %d)\n", i )); +#else Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); +#endif + + ldap_pvt_thread_mutex_init( &li->li_dbcache[i].dbc_write_mutex ); + + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); return( &li->li_dbcache[i] ); } void -ldbm_cache_close( Backend *be, struct dbcache *db ) +ldbm_cache_close( Backend *be, DBCache *db ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - pthread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { - pthread_cond_signal( &li->li_dbcache_cv ); + if( li->li_dbwritesync && db->dbc_dirty ) { + ldbm_sync( db->dbc_db ); + db->dbc_dirty = 0; } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + if ( --db->dbc_refcnt <= 0 ) { + db->dbc_refcnt = 0; + ldap_pvt_thread_cond_signal( &li->li_dbcache_cv ); + } + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } void -ldbm_cache_really_close( Backend *be, struct dbcache *db ) +ldbm_cache_really_close( Backend *be, DBCache *db ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - pthread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { - pthread_cond_signal( &li->li_dbcache_cv ); + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + if ( --db->dbc_refcnt <= 0 ) { + db->dbc_refcnt = 0; + ldap_pvt_thread_cond_signal( &li->li_dbcache_cv ); ldbm_close( db->dbc_db ); free( db->dbc_name ); db->dbc_name = NULL; + ldap_pvt_thread_mutex_destroy( &db->dbc_write_mutex ); } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } void @@ -156,51 +255,88 @@ ldbm_cache_flush_all( Backend *be ) struct ldbminfo *li = (struct ldbminfo *) be->be_private; int i; - pthread_mutex_lock( &li->li_dbcache_mutex ); + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); for ( i = 0; i < MAXDBCACHE; i++ ) { if ( li->li_dbcache[i].dbc_name != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "ldbm_cache_flush_all: flushing db (%s)\n", + li->li_dbcache[i].dbc_name )); +#else Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n", li->li_dbcache[i].dbc_name, 0, 0 ); - pthread_mutex_lock( &li->li_dbcache[i].dbc_mutex ); +#endif + + ldbm_sync( li->li_dbcache[i].dbc_db ); + li->li_dbcache[i].dbc_dirty = 0; + if ( li->li_dbcache[i].dbc_refcnt != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "ldbm_cache_flush_all: couldn't close db (%s), refcnt=%d\n", + li->li_dbcache[i].dbc_name, li->li_dbcache[i].dbc_refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "refcnt = %d, couldn't close db (%s)\n", + li->li_dbcache[i].dbc_refcnt, + li->li_dbcache[i].dbc_name, 0 ); +#endif + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "ldbm_cache_flush_all: ldbm closing db (%s)\n", + li->li_dbcache[i].dbc_name )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm closing db (%s)\n", + li->li_dbcache[i].dbc_name, 0, 0 ); +#endif + + ldap_pvt_thread_cond_signal( &li->li_dbcache_cv ); + ldbm_close( li->li_dbcache[i].dbc_db ); + free( li->li_dbcache[i].dbc_name ); + li->li_dbcache[i].dbc_name = NULL; + } + } + } + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); +} + +void +ldbm_cache_sync( Backend *be ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + int i; + + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + for ( i = 0; i < MAXDBCACHE; i++ ) { + if ( li->li_dbcache[i].dbc_name != NULL && li->li_dbcache[i].dbc_dirty ) { +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_DETAIL1, "ldbm_cache_sync: " + "ldbm syncing db (%s)\n", li->li_dbcache[i].dbc_name )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm syncing db (%s)\n", + li->li_dbcache[i].dbc_name, 0, 0 ); +#endif ldbm_sync( li->li_dbcache[i].dbc_db ); - pthread_mutex_unlock( &li->li_dbcache[i].dbc_mutex ); + li->li_dbcache[i].dbc_dirty = 0; } } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } Datum ldbm_cache_fetch( - struct dbcache *db, + DBCache *db, Datum key ) { - Datum data; - - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* increment reader count */ - db->dbc_readers++ - pthread_mutex_unlock( &db->dbc_mutex ); -#endif - - data = ldbm_fetch( db->dbc_db, key ); - -#ifdef reentrant_database - pthread_mutex_lock( &db->dbc_mutex ); - /* decrement reader count & signal any waiting writers */ - if ( --db->dbc_readers == 0 ) { - pthread_cond_signal( &db->dbc_cv ); - } -#endif - pthread_mutex_unlock( &db->dbc_mutex ); - - return( data ); + return ldbm_fetch( db->dbc_db, key ); } int ldbm_cache_store( - struct dbcache *db, + DBCache *db, Datum key, Datum data, int flags @@ -208,40 +344,92 @@ ldbm_cache_store( { int rc; - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* wait for reader count to drop to zero */ - while ( db->dbc_readers > 0 ) { - pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex ); - } -#endif +#ifdef LDBM_DEBUG + Statslog( LDAP_DEBUG_STATS, + "=> ldbm_cache_store(): key.dptr=%s, key.dsize=%d\n", + key.dptr, key.dsize, 0, 0, 0 ); - rc = ldbm_store( db->dbc_db, key, data, flags ); + Statslog( LDAP_DEBUG_STATS, + "=> ldbm_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n", + key.dptr, data.dptr, 0, 0, 0 ); - pthread_mutex_unlock( &db->dbc_mutex ); + Statslog( LDAP_DEBUG_STATS, + "=> ldbm_cache_store(): data.dptr=%s, data.dsize=%d\n", + data.dptr, data.dsize, 0, 0, 0 ); + + Statslog( LDAP_DEBUG_STATS, + "=> ldbm_cache_store(): flags=0x%08x\n", + flags, 0, 0, 0, 0 ); +#endif /* LDBM_DEBUG */ + + db->dbc_dirty = 1; + rc = ldbm_store( db->dbc_db, key, data, flags ); return( rc ); } int ldbm_cache_delete( - struct dbcache *db, + DBCache *db, Datum key ) { int rc; - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* wait for reader count to drop to zero - then write */ - while ( db->dbc_readers > 0 ) { - pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex ); - } -#endif - + db->dbc_dirty = 1; rc = ldbm_delete( db->dbc_db, key ); - pthread_mutex_unlock( &db->dbc_mutex ); - return( rc ); } + +void * +ldbm_cache_sync_daemon( + void *be_ptr +) +{ + Backend *be = (Backend *)be_ptr; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_ARGS, "ldbm_cache_sync_daemon:" + " synchronizer starting for %s\n", li->li_directory )); +#else + Debug( LDAP_DEBUG_ANY, "synchronizer starting for %s\n", li->li_directory, 0, 0 ); +#endif + + while (!li->li_dbshutdown) { + int i = li->li_dbsyncwaitn; + + sleep( li->li_dbsyncfreq ); + + while (i && ldap_pvt_thread_pool_backload(&connection_pool) != 0) { +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_DETAIL1, "ldbm_cache_sync_daemon:" + " delay syncing %s\n", li->li_directory )); +#else + Debug( LDAP_DEBUG_TRACE, "delay syncing %s\n", li->li_directory, 0, 0 ); +#endif + sleep(li->li_dbsyncwaitinterval); + i--; + } + + if (!li->li_dbshutdown) { +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_DETAIL1, "ldbm_cache_sync_daemon:" + " syncing %s\n", li->li_directory )); +#else + Debug( LDAP_DEBUG_TRACE, "syncing %s\n", li->li_directory, 0, 0 ); +#endif + ldbm_cache_sync( be ); + } + } + +#ifdef NEW_LOGGING + LDAP_LOG (( "dbcache", LDAP_LEVEL_DETAIL1, "ldbm_cache_sync_daemon:" + " synchronizer stopping\n" )); +#else + Debug( LDAP_DEBUG_ANY, "synchronizer stopping\n", 0, 0, 0 ); +#endif + + return NULL; +} diff --git a/servers/slapd/back-ldbm/filterindex.c b/servers/slapd/back-ldbm/filterindex.c index 55aada54e45e9286fa9caf83de36bdb987f9acbd..bc370f239b6916d167899796e692ca9e6c52cf62 100644 --- a/servers/slapd/back-ldbm/filterindex.c +++ b/servers/slapd/back-ldbm/filterindex.c @@ -1,204 +1,727 @@ /* filterindex.c - generate the list of candidate entries from a filter */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -#include "back-ldbm.h" -extern char *first_word(); -extern char *next_word(); -extern char *phonetic(); -extern IDList *index_read(); -extern IDList *idl_intersection(); -extern IDList *idl_union(); -extern IDList *idl_notin(); -extern IDList *idl_allids(); - -static IDList *ava_candidates(); -static IDList *presence_candidates(); -static IDList *approx_candidates(); -static IDList *list_candidates(); -static IDList *substring_candidates(); -static IDList *substring_comp_candidates(); +#include <ac/socket.h> +#include <ac/string.h> -/* - * test_filter - test a filter against a single entry. - * returns 0 filter matched - * -1 filter did not match - * >0 an ldap error code - */ +#include "slap.h" +#include "back-ldbm.h" -IDList * +static ID_BLOCK *presence_candidates( + Backend *be, + AttributeDescription *desc ); +static ID_BLOCK *equality_candidates( + Backend *be, AttributeAssertion *ava ); +static ID_BLOCK *approx_candidates( + Backend *be, AttributeAssertion *ava ); +static ID_BLOCK *substring_candidates( + Backend *be, + SubstringsAssertion *sub ); +static ID_BLOCK *list_candidates( + Backend *be, + Filter *flist, + int ftype ); + +ID_BLOCK * filter_candidates( Backend *be, Filter *f ) { - IDList *result; + ID_BLOCK *result; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, "filter_candidates: enter\n")); +#else Debug( LDAP_DEBUG_TRACE, "=> filter_candidates\n", 0, 0, 0 ); +#endif + result = NULL; switch ( f->f_choice ) { + case SLAPD_FILTER_DN_ONE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: DN ONE (%s)\n", f->f_dn )); +#else + Debug( LDAP_DEBUG_FILTER, "\tDN ONE\n", 0, 0, 0 ); +#endif + + /* an error is treated as an empty list */ + if ( dn2idl( be, f->f_dn, DN_ONE_PREFIX, &result ) != 0 + && result != NULL ) { + idl_free( result ); + result = NULL; + } + break; + + case SLAPD_FILTER_DN_SUBTREE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: DN SUBTREE (%s)\n", f->f_dn )); +#else + Debug( LDAP_DEBUG_FILTER, "\tDN SUBTREE\n", 0, 0, 0 ); +#endif + + /* an error is treated as an empty list */ + if ( dn2idl( be, f->f_dn, DN_SUBTREE_PREFIX, &result ) != 0 + && result != NULL ) { + idl_free( result ); + result = NULL; + } + break; + + case LDAP_FILTER_PRESENT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: Present (%s)\n", f->f_desc->ad_cname.bv_val )); +#else + Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 ); +#endif + + result = presence_candidates( be, f->f_desc ); + break; + case LDAP_FILTER_EQUALITY: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: EQUALITY (%s),(%s)\n", + f->f_ava->aa_desc->ad_cname.bv_val, + f->f_ava->aa_value.bv_val )); +#else Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 ); - result = ava_candidates( be, &f->f_ava, LDAP_FILTER_EQUALITY ); +#endif + + result = equality_candidates( be, f->f_ava ); + break; + + case LDAP_FILTER_APPROX: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: APPROX (%s), (%s)\n", + f->f_ava->aa_desc->ad_cname.bv_val, + f->f_ava->aa_value.bv_val )); +#else + Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 ); +#endif + + result = approx_candidates( be, f->f_ava ); break; case LDAP_FILTER_SUBSTRINGS: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: SUBSTRINGS\n")); +#else Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 ); - result = substring_candidates( be, f ); +#endif + + result = substring_candidates( be, f->f_sub ); break; case LDAP_FILTER_GE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: GE\n")); +#else Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 ); - result = ava_candidates( be, &f->f_ava, LDAP_FILTER_GE ); +#endif + + result = presence_candidates( be, f->f_ava->aa_desc ); break; case LDAP_FILTER_LE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: LE\n" )); +#else Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 ); - result = ava_candidates( be, &f->f_ava, LDAP_FILTER_LE ); - break; +#endif - case LDAP_FILTER_PRESENT: - Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 ); - result = presence_candidates( be, f->f_type ); - break; - - case LDAP_FILTER_APPROX: - Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 ); - result = approx_candidates( be, &f->f_ava ); + result = presence_candidates( be, f->f_ava->aa_desc ); break; case LDAP_FILTER_AND: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: AND\n" )); +#else Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 ); +#endif + result = list_candidates( be, f->f_and, LDAP_FILTER_AND ); break; case LDAP_FILTER_OR: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: OR\n" )); +#else Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 ); +#endif + result = list_candidates( be, f->f_or, LDAP_FILTER_OR ); break; case LDAP_FILTER_NOT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: NOT\n" )); +#else Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 ); - result = idl_notin( be, idl_allids( be ), filter_candidates( be, - f->f_not ) ); +#endif + + /* + * As candidates lists may contain entries which do + * not match the assertion, negation of the inner candidate + * list could result in matching entries be excluded from + * the returned candidate list. + */ + result = idl_allids( be ); + break; + default: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "filter_candidates: UNKNOWN\n" )); +#else + Debug( LDAP_DEBUG_FILTER, "\tUNKNOWN\n", 0, 0, 0 ); +#endif + /* unknown filters must not return NULL, to allow + * extended filter processing to be done later. + */ + result = idl_allids( be ); break; } - Debug( LDAP_DEBUG_TRACE, "<= filter_candidates %d\n", - result ? result->b_nids : 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "filter_candidates: return %ld\n", + result ? ID_BLOCK_NIDS(result) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= filter_candidates %ld\n", + result ? ID_BLOCK_NIDS(result) : 0, 0, 0 ); +#endif + return( result ); } -static IDList * -ava_candidates( +static ID_BLOCK * +presence_candidates( Backend *be, - Ava *ava, - int type + AttributeDescription *desc ) { - IDList *idl; + ID_BLOCK *idl; + DBCache *db; + int rc; + char *dbname; + slap_mask_t mask; + struct berval prefix = {0}; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "presence_candidates: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "=> ava_candidates 0x%x\n", type, 0, 0 ); + idl = idl_allids( be ); - switch ( type ) { - case LDAP_FILTER_EQUALITY: - idl = index_read( be, ava->ava_type, INDEX_EQUALITY, - ava->ava_value.bv_val ); - break; + if( desc == slap_schema.si_ad_objectClass ) { + return idl; + } - case LDAP_FILTER_GE: - idl = idl_allids( be ); - break; + rc = index_param( be, desc, LDAP_FILTER_PRESENT, + &dbname, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "presence_candidates: index_param returned %d\n", + rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= presence_candidates: index_param returned=%d\n", + rc, 0, 0 ); +#endif + + return idl; + } - case LDAP_FILTER_LE: - idl = idl_allids( be ); - break; + if( dbname == NULL ) { + /* not indexed */ +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "presence_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= presense_candidates: not indexed\n", + 0, 0, 0 ); +#endif + + return idl; + } + + db = ldbm_cache_open( be, dbname, LDBM_SUFFIX, LDBM_WRCREAT ); + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "presence_candidates: db open failed (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_ANY, + "<= presense_candidates db open failed (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; + } + + if( prefix.bv_val != NULL ) { + idl_free( idl ); + idl = NULL; + + rc = key_read( be, db, &prefix, &idl ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "presence_candidates: key read failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= presense_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + + + } else if( idl == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "presence_candidates: NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= presense_candidates NULL\n", + 0, 0, 0 ); +#endif + + } } - Debug( LDAP_DEBUG_TRACE, "<= ava_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); + ldbm_cache_close( be, db ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "presence_candidates: return %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= presence_candidates %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 ); +#endif + return( idl ); } -static IDList * -presence_candidates( +static ID_BLOCK * +equality_candidates( Backend *be, - char *type + AttributeAssertion *ava ) { - IDList *idl; + ID_BLOCK *idl; + DBCache *db; + int i; + int rc; + char *dbname; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "equality_candidates: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> equality_candidates\n", 0, 0, 0 ); +#endif + + + idl = idl_allids( be ); + + rc = index_param( be, ava->aa_desc, LDAP_FILTER_EQUALITY, + &dbname, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: index_param returned %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates: index_param returned=%d\n", + rc, 0, 0 ); +#endif + + return idl; + } - Debug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 ); + if( dbname == NULL ) { + /* not indexed */ +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates: not indexed\n", + 0, 0, 0 ); +#endif + + return idl; + } + + mr = ava->aa_desc->ad_type->sat_equality; + if( !mr ) { + return idl; + } - idl = index_read( be, type, 0, "*" ); + if( !mr->smr_filter ) { + return idl; + } + + rc = (mr->smr_filter)( + LDAP_FILTER_EQUALITY, + mask, + ava->aa_desc->ad_type->sat_syntax, + mr, + &prefix, + &ava->aa_value, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: (%s%s) MR filter failed (%d\n", + dbname, LDBM_SUFFIX, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates: (%s%s) MR filter failed (%d)\n", + dbname, LDBM_SUFFIX, rc ); +#endif + + return idl; + } + + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: no keys (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates: no keys (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; + } + + db = ldbm_cache_open( be, dbname, LDBM_SUFFIX, LDBM_WRCREAT ); + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: db open failed (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_ANY, + "<= equality_candidates db open failed (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; + } + + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + ID_BLOCK *save; + ID_BLOCK *tmp; + + rc = key_read( be, db, &keys[i], &tmp ); + + if( rc != LDAP_SUCCESS ) { + idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "equality_candidates: key read failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + + break; + } + + if( tmp == NULL ) { + idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "equality_candidates NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= equality_candidates NULL\n", + 0, 0, 0 ); +#endif + + break; + } + + save = idl; + idl = idl_intersection( be, idl, tmp ); + idl_free( save ); + idl_free( tmp ); + + if( idl == NULL ) break; + } + + ber_bvarray_free( keys ); + + ldbm_cache_close( be, db ); + + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "equality_candidates: return %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= equality_candidates %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "<= presence_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); return( idl ); } -static IDList * +static ID_BLOCK * approx_candidates( Backend *be, - Ava *ava + AttributeAssertion *ava ) { - char *w, *c; - IDList *idl, *tmp; - + ID_BLOCK *idl; + DBCache *db; + int i; + int rc; + char *dbname; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "approx_candidates: enter\n" )); +#else Debug( LDAP_DEBUG_TRACE, "=> approx_candidates\n", 0, 0, 0 ); +#endif - idl = NULL; - for ( w = first_word( ava->ava_value.bv_val ); w != NULL; - w = next_word( w ) ) { - c = phonetic( w ); - if ( (tmp = index_read( be, ava->ava_type, INDEX_APPROX, c )) - == NULL ) { - free( c ); + + idl = idl_allids( be ); + + rc = index_param( be, ava->aa_desc, LDAP_FILTER_APPROX, + &dbname, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "approx_candidates: index_param returned %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= approx_candidates: index_param returned=%d\n", + rc, 0, 0 ); +#endif + + return idl; + } + + if( dbname == NULL ) { + /* not indexed */ +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "approx_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "<= approx_candidates: not indexed\n", + 0, 0, 0 ); +#endif + + return idl; + } + + mr = ava->aa_desc->ad_type->sat_approx; + if( !mr ) { + /* no approx matching rule, try equality matching rule */ + mr = ava->aa_desc->ad_type->sat_equality; + } + + if( !mr ) { + return idl; + } + + if( !mr->smr_filter ) { + return idl; + } + + rc = (mr->smr_filter)( + LDAP_FILTER_APPROX, + mask, + ava->aa_desc->ad_type->sat_syntax, + mr, + &prefix, + &ava->aa_value, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "approx_candidates: (%s%s) MR filter failed (%d)\n", + dbname, LDBM_SUFFIX, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= approx_candidates: (%s%s) MR filter failed (%d)\n", + dbname, LDBM_SUFFIX, rc ); +#endif + + return idl; + } + + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "approx_candidates: no keys (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= approx_candidates: no keys (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; + } + + db = ldbm_cache_open( be, dbname, LDBM_SUFFIX, LDBM_WRCREAT ); + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "approx_candidates db open failed (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_ANY, + "<= approx_candidates db open failed (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; + } + + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + ID_BLOCK *save; + ID_BLOCK *tmp; + + rc = key_read( be, db, &keys[i], &tmp ); + + if( rc != LDAP_SUCCESS ) { + idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "approx_candidates: key read failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= approx_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + + break; + } + + if( tmp == NULL ) { idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "approx_candidates: NULL\n" )); +#else Debug( LDAP_DEBUG_TRACE, "<= approx_candidates NULL\n", 0, 0, 0 ); - return( NULL ); - } - free( c ); +#endif - if ( idl == NULL ) { - idl = tmp; - } else { - idl = idl_intersection( be, idl, tmp ); + break; } + + save = idl; + idl = idl_intersection( be, idl, tmp ); + idl_free( save ); + idl_free( tmp ); + + if( idl == NULL ) break; } - Debug( LDAP_DEBUG_TRACE, "<= approx_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); + ber_bvarray_free( keys ); + + ldbm_cache_close( be, db ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "approx_candidates: return %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= approx_candidates %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 ); +#endif + return( idl ); } -static IDList * +static ID_BLOCK * list_candidates( Backend *be, Filter *flist, int ftype ) { - IDList *idl, *tmp, *tmp2; + ID_BLOCK *idl, *tmp, *tmp2; Filter *f; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "list_candidates: 0x%x\n", ftype )); +#else Debug( LDAP_DEBUG_TRACE, "=> list_candidates 0x%x\n", ftype, 0, 0 ); +#endif + idl = NULL; for ( f = flist; f != NULL; f = f->f_next ) { if ( (tmp = filter_candidates( be, f )) == NULL && ftype == LDAP_FILTER_AND ) { - Debug( LDAP_DEBUG_TRACE, - "<= list_candidates NULL\n", 0, 0, 0 ); - idl_free( idl ); - return( NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "list_candidates: NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= list_candidates NULL\n", 0, 0, 0 ); +#endif + + idl_free( idl ); + return( NULL ); } tmp2 = idl; @@ -215,142 +738,192 @@ list_candidates( } } - Debug( LDAP_DEBUG_TRACE, "<= list_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "list_candidates: return %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= list_candidates %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 ); +#endif + return( idl ); } -static IDList * +static ID_BLOCK * substring_candidates( Backend *be, - Filter *f + SubstringsAssertion *sub ) { - int i; - IDList *idl, *tmp, *tmp2; + ID_BLOCK *idl; + DBCache *db; + int i; + int rc; + char *dbname; + slap_mask_t mask; + struct berval prefix = {0}; + struct berval *keys = NULL; + MatchingRule *mr; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "substrings_candidates: enter\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> substrings_candidates\n", 0, 0, 0 ); +#endif + + + idl = idl_allids( be ); + + rc = index_param( be, sub->sa_desc, LDAP_FILTER_SUBSTRINGS, + &dbname, &mask, &prefix ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: index_param returned %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= substrings_candidates: index_param returned=%d\n", + rc, 0, 0 ); +#endif + + return idl; + } - Debug( LDAP_DEBUG_TRACE, "=> substring_candidates\n", 0, 0, 0 ); + if( dbname == NULL ) { + /* not indexed */ +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: not indexed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "<= substrings_candidates: not indexed\n", + 0, 0, 0 ); +#endif + + return idl; + } - idl = NULL; + mr = sub->sa_desc->ad_type->sat_substr; - /* initial */ - if ( f->f_sub_initial != NULL ) { - if ( (int) strlen( f->f_sub_initial ) < SUBLEN - 1 ) { - idl = idl_allids( be ); - } else if ( (idl = substring_comp_candidates( be, f->f_sub_type, - f->f_sub_initial, '^' )) == NULL ) { - return( NULL ); - } + if( !mr ) { + return idl; } - /* final */ - if ( f->f_sub_final != NULL ) { - if ( (int) strlen( f->f_sub_final ) < SUBLEN - 1 ) { - tmp = idl_allids( be ); - } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type, - f->f_sub_final, '$' )) == NULL ) { - idl_free( idl ); - return( NULL ); - } + if( !mr->smr_filter ) { + return idl; + } - if ( idl == NULL ) { - idl = tmp; - } else { - tmp2 = idl; - idl = idl_intersection( be, idl, tmp ); - idl_free( tmp ); - idl_free( tmp2 ); - } + rc = (mr->smr_filter)( + LDAP_FILTER_SUBSTRINGS, + mask, + sub->sa_desc->ad_type->sat_syntax, + mr, + &prefix, + sub, + &keys ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: (%s%s) MR filter failed (%d)\n", + dbname, LDBM_SUFFIX, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= substrings_candidates: (%s%s) MR filter failed (%d)\n", + dbname, LDBM_SUFFIX, rc ); +#endif + + return idl; } - for ( i = 0; f->f_sub_any != NULL && f->f_sub_any[i] != NULL; i++ ) { - if ( (int) strlen( f->f_sub_any[i] ) < SUBLEN ) { - tmp = idl_allids( be ); - } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type, - f->f_sub_any[i], 0 )) == NULL ) { - idl_free( idl ); - return( NULL ); - } + if( keys == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: (0x%04lx) no keys (%s%s)\n", + mask, dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_TRACE, + "<= substrings_candidates: (0x%04lx) no keys (%s%s)\n", + mask, dbname, LDBM_SUFFIX ); +#endif + + return idl; + } - if ( idl == NULL ) { - idl = tmp; - } else { - tmp2 = idl; - idl = idl_intersection( be, idl, tmp ); - idl_free( tmp ); - idl_free( tmp2 ); - } + db = ldbm_cache_open( be, dbname, LDBM_SUFFIX, LDBM_WRCREAT ); + + if ( db == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: db open failed (%s%s)\n", + dbname, LDBM_SUFFIX )); +#else + Debug( LDAP_DEBUG_ANY, + "<= substrings_candidates db open failed (%s%s)\n", + dbname, LDBM_SUFFIX, 0 ); +#endif + + return idl; } - Debug( LDAP_DEBUG_TRACE, "<= substring_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); - return( idl ); -} + for ( i= 0; keys[i].bv_val != NULL; i++ ) { + ID_BLOCK *save; + ID_BLOCK *tmp; -static IDList * -substring_comp_candidates( - Backend *be, - char *type, - char *val, - int prepost -) -{ - int i, len; - IDList *idl, *tmp, *tmp2; - char *p; - char buf[SUBLEN + 1]; + rc = key_read( be, db, &keys[i], &tmp ); - Debug( LDAP_DEBUG_TRACE, "=> substring_comp_candidates\n", 0, 0, 0 ); + if( rc != LDAP_SUCCESS ) { + idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "substrings_candidates: key read failed (%d)\n", + rc )); +#else + Debug( LDAP_DEBUG_TRACE, "<= substrings_candidates key read failed (%d)\n", + rc, 0, 0 ); +#endif + + break; + } - len = strlen( val ); - idl = NULL; + if( tmp == NULL ) { + idl_free( idl ); + idl = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "substrings_candidates: NULL\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "<= substrings_candidates NULL\n", + 0, 0, 0 ); +#endif - /* prepend ^ for initial substring */ - if ( prepost == '^' ) { - buf[0] = '^'; - for ( i = 0; i < SUBLEN - 1; i++ ) { - buf[i + 1] = val[i]; + break; } - buf[SUBLEN] = '\0'; - if ( (idl = index_read( be, type, INDEX_SUB, buf )) == NULL ) { - return( NULL ); - } - } else if ( prepost == '$' ) { - p = val + len - SUBLEN + 1; - for ( i = 0; i < SUBLEN - 1; i++ ) { - buf[i] = p[i]; - } - buf[SUBLEN - 1] = '$'; - buf[SUBLEN] = '\0'; + save = idl; + idl = idl_intersection( be, idl, tmp ); + idl_free( save ); + idl_free( tmp ); - if ( (idl = index_read( be, type, INDEX_SUB, buf )) == NULL ) { - return( NULL ); - } + if( idl == NULL ) break; } - for ( p = val; p < (val + len - SUBLEN + 1); p++ ) { - for ( i = 0; i < SUBLEN; i++ ) { - buf[i] = p[i]; - } - buf[SUBLEN] = '\0'; + ber_bvarray_free( keys ); - if ( (tmp = index_read( be, type, INDEX_SUB, buf )) == NULL ) { - idl_free( idl ); - return( NULL ); - } + ldbm_cache_close( be, db ); - if ( idl == NULL ) { - idl = tmp; - } else { - tmp2 = idl; - idl = idl_intersection( be, idl, tmp ); - idl_free( tmp ); - idl_free( tmp2 ); - } - } +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "substrings_candidates: return %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0 )); +#else + Debug( LDAP_DEBUG_TRACE, "<= substrings_candidates %ld\n", + idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "<= substring_comp_candidates %d\n", - idl ? idl->b_nids : 0, 0, 0 ); return( idl ); } diff --git a/servers/slapd/back-ldbm/id2children.c b/servers/slapd/back-ldbm/id2children.c index 3b2c55d202170c4f13ef836525b711037b752502..c27496d5730b6f5a47e6370ee3ba6c71239f56a8 100644 --- a/servers/slapd/back-ldbm/id2children.c +++ b/servers/slapd/back-ldbm/id2children.c @@ -1,55 +1,20 @@ /* id2children.c - routines to deal with the id2children index */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -#include "back-ldbm.h" - -struct dbcache *ldbm_cache_open(); -extern Datum ldbm_cache_fetch(); -IDList *idl_fetch(); - -int -id2children_add( - Backend *be, - Entry *p, - Entry *e -) -{ - struct dbcache *db; - Datum key, data; - int len, rc; - IDList *idl; - char buf[20]; - - Debug( LDAP_DEBUG_TRACE, "=> id2children_add( %d, %d )\n", p ? p->e_id - : 0, e->e_id, 0 ); - - if ( (db = ldbm_cache_open( be, "id2children", LDBM_SUFFIX, - LDBM_WRCREAT )) == NULL ) { - Debug( LDAP_DEBUG_ANY, - "<= id2children_add -1 could not open \"id2children%s\"\n", - LDBM_SUFFIX, 0, 0 ); - return( -1 ); - } +#include "portable.h" - sprintf( buf, "%c%d", EQ_PREFIX, p ? p->e_id : 0 ); - key.dptr = buf; - key.dsize = strlen( buf ) + 1; +#include <stdio.h> +#include <ac/string.h> - if ( idl_insert_key( be, db, key, e->e_id ) != 0 ) { - Debug( LDAP_DEBUG_TRACE, "<= id2children_add -1 (idl_insert)\n", - 0, 0, 0 ); - ldbm_cache_close( be, db ); - return( -1 ); - } +#include <ac/socket.h> - ldbm_cache_close( be, db ); +#include "slap.h" +#include "back-ldbm.h" - Debug( LDAP_DEBUG_TRACE, "<= id2children_add 0\n", 0, 0, 0 ); - return( 0 ); -} int has_children( @@ -57,32 +22,59 @@ has_children( Entry *p ) { - struct dbcache *db; + DBCache *db; Datum key; - int rc; - IDList *idl; - char buf[20]; + int rc = 0; + ID_BLOCK *idl; - Debug( LDAP_DEBUG_TRACE, "=> has_children( %d )\n", p->e_id , 0, 0 ); + ldbm_datum_init( key ); - if ( (db = ldbm_cache_open( be, "id2children", LDBM_SUFFIX, +#ifdef NEW_LOGGING + LDAP_LOG(( "id2children", LDAP_LEVEL_ENTRY, + "has_children: enter %ld\n", p->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> has_children( %ld )\n", p->e_id , 0, 0 ); +#endif + + + if ( (db = ldbm_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2children", LDAP_LEVEL_ERR, + "has_children: could not open \"dn2id%s\"\n", + LDBM_SUFFIX )); +#else Debug( LDAP_DEBUG_ANY, - "<= has_children -1 could not open \"id2children%s\"\n", + "<= has_children -1 could not open \"dn2id%s\"\n", LDBM_SUFFIX, 0, 0 ); +#endif + return( 0 ); } - sprintf( buf, "%c%d", EQ_PREFIX, p->e_id ); - key.dptr = buf; - key.dsize = strlen( buf ) + 1; + key.dsize = strlen( p->e_ndn ) + 2; + key.dptr = ch_malloc( key.dsize ); + sprintf( key.dptr, "%c%s", DN_ONE_PREFIX, p->e_ndn ); idl = idl_fetch( be, db, key ); + free( key.dptr ); + ldbm_cache_close( be, db ); - rc = idl ? 1 : 0; - idl_free( idl ); - Debug( LDAP_DEBUG_TRACE, "<= has_children %d\n", rc, 0, 0 ); + if( idl != NULL ) { + idl_free( idl ); + rc = 1; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "id2children", LDAP_LEVEL_ENTRY, + "has_children: id (%ld) %s children.\n", + p->e_id, rc ? "has" : "doesn't have" )); +#else + Debug( LDAP_DEBUG_TRACE, "<= has_children( %ld ): %s\n", + p->e_id, rc ? "yes" : "no", 0 ); +#endif + return( rc ); } diff --git a/servers/slapd/back-ldbm/id2entry.c b/servers/slapd/back-ldbm/id2entry.c index fbda3c9952a9461766d2f4024e072054ca61530a..0bcde14620a4f1e7ffdf4b15c6b32ab39be9702b 100644 --- a/servers/slapd/back-ldbm/id2entry.c +++ b/servers/slapd/back-ldbm/id2entry.c @@ -1,53 +1,88 @@ /* id2entry.c - routines to deal with the id2entry index */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/socket.h> + #include "slap.h" #include "back-ldbm.h" -extern struct dbcache *ldbm_cache_open(); -extern Datum ldbm_cache_fetch(); -extern char *dn_parent(); -extern Entry *str2entry(); -extern Entry *cache_find_entry_id(); -extern char *entry2str(); -extern pthread_mutex_t entry2str_mutex; +/* + * This routine adds (or updates) an entry on disk. + * The cache should already be updated. + */ int id2entry_add( Backend *be, Entry *e ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - struct dbcache *db; + DBCache *db; Datum key, data; - int len, rc; + int len, rc, flags; +#ifndef WORDS_BIGENDIAN + ID id; +#endif + + ldbm_datum_init( key ); + ldbm_datum_init( data ); - Debug( LDAP_DEBUG_TRACE, "=> id2entry_add( %d, \"%s\" )\n", e->e_id, +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_add: (%s)%ld\n", e->e_dn, e->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> id2entry_add( %ld, \"%s\" )\n", e->e_id, e->e_dn, 0 ); +#endif + if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_add: could not open/create id2entry%s\n", + LDBM_SUFFIX )); +#else Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n", LDBM_SUFFIX, 0, 0 ); +#endif + return( -1 ); } +#ifdef WORDS_BIGENDIAN key.dptr = (char *) &e->e_id; +#else + id = htonl(e->e_id); + key.dptr = (char *) &id; +#endif key.dsize = sizeof(ID); - pthread_mutex_lock( &entry2str_mutex ); - data.dptr = entry2str( e, &len, 1 ); + ldap_pvt_thread_mutex_lock( &entry2str_mutex ); + data.dptr = entry2str( e, &len ); data.dsize = len + 1; - /* store it - LDBM_SYNC ensures id2entry is always consistent */ - rc = ldbm_cache_store( db, key, data, LDBM_REPLACE|LDBM_SYNC ); + /* store it */ + flags = LDBM_REPLACE; + rc = ldbm_cache_store( db, key, data, flags ); - pthread_mutex_unlock( &entry2str_mutex ); + ldap_pvt_thread_mutex_unlock( &entry2str_mutex ); ldbm_cache_close( be, db ); - (void) cache_add_entry_lock( &li->li_cache, e, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_add: return %d\n", rc )); +#else Debug( LDAP_DEBUG_TRACE, "<= id2entry_add %d\n", rc, 0, 0 ); +#endif + + return( rc ); } @@ -55,79 +90,216 @@ int id2entry_delete( Backend *be, Entry *e ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - struct dbcache *db; + DBCache *db; Datum key; int rc; +#ifndef WORDS_BIGENDIAN + ID id; +#endif - Debug( LDAP_DEBUG_TRACE, "=> id2entry_delete( %d, \"%s\" )\n", e->e_id, +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_delete: (%s)%ld\n", e->e_dn, e->e_id )); +#else + Debug(LDAP_DEBUG_TRACE, "=> id2entry_delete( %ld, \"%s\" )\n", e->e_id, e->e_dn, 0 ); +#endif + + +#ifdef notdef +#ifdef LDAP_RDWR_DEBUG + /* check for writer lock */ + assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr) == 1); +#endif +#endif + + ldbm_datum_init( key ); if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT )) - == NULL ) { + == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_delete: could not open/create id2entry%s\n", + LDBM_SUFFIX )); +#else Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n", LDBM_SUFFIX, 0, 0 ); +#endif + return( -1 ); } if ( cache_delete_entry( &li->li_cache, e ) != 0 ) { - Debug( LDAP_DEBUG_ANY, "could not delete %d (%s) from cache\n", +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_delete: Could not delete (%s)%ld from cache\n", + e->e_dn, e->e_id )); +#else + Debug(LDAP_DEBUG_ANY, "could not delete %ld (%s) from cache\n", e->e_id, e->e_dn, 0 ); +#endif + } +#ifdef WORDS_BIGENDIAN key.dptr = (char *) &e->e_id; +#else + id = htonl(e->e_id); + key.dptr = (char *) &id; +#endif key.dsize = sizeof(ID); rc = ldbm_cache_delete( db, key ); ldbm_cache_close( be, db ); +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_delete: return %d\n", rc )); +#else Debug( LDAP_DEBUG_TRACE, "<= id2entry_delete %d\n", rc, 0, 0 ); +#endif + return( rc ); } +/* returns entry with reader/writer lock */ Entry * -id2entry( Backend *be, ID id ) +id2entry_rw( Backend *be, ID id, int rw ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - struct dbcache *db; + DBCache *db; Datum key, data; Entry *e; +#ifndef WORDS_BIGENDIAN + ID id2; +#endif + + ldbm_datum_init( key ); + ldbm_datum_init( data ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_rw: %s (%ld)\n", + rw ? "write" : "read", id )); +#else + Debug( LDAP_DEBUG_TRACE, "=> id2entry_%s( %ld )\n", + rw ? "w" : "r", id, 0 ); +#endif - Debug( LDAP_DEBUG_TRACE, "=> id2entry( %ld )\n", id, 0, 0 ); - if ( (e = cache_find_entry_id( &li->li_cache, id )) != NULL ) { - Debug( LDAP_DEBUG_TRACE, "<= id2entry 0x%x (cache)\n", e, 0, - 0 ); + if ( (e = cache_find_entry_id( &li->li_cache, id, rw )) != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_DETAIL1, + "id2entry_rw: %s (%ld) 0x%lx (cache).\n", + rw ? "write" : "read", id, (unsigned long)e )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) 0x%lx (cache)\n", + rw ? "w" : "r", id, (unsigned long) e ); +#endif + return( e ); } if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT )) - == NULL ) { + == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_rw: could not open id2entry%s\n", LDBM_SUFFIX )); +#else Debug( LDAP_DEBUG_ANY, "Could not open id2entry%s\n", LDBM_SUFFIX, 0, 0 ); +#endif + return( NULL ); } +#ifdef WORDS_BIGENDIAN key.dptr = (char *) &id; +#else + id2 = htonl(id); + key.dptr = (char *) &id2; +#endif key.dsize = sizeof(ID); data = ldbm_cache_fetch( db, key ); if ( data.dptr == NULL ) { - Debug( LDAP_DEBUG_TRACE, "<= id2entry( %ld ) not found\n", id, - 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_rw: (%ld) not found\n", id )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) not found\n", + rw ? "w" : "r", id, 0 ); +#endif + ldbm_cache_close( be, db ); return( NULL ); } - if ( (e = str2entry( data.dptr )) != NULL ) { - e->e_id = id; - (void) cache_add_entry_lock( &li->li_cache, e, 0 ); - } - + e = str2entry( data.dptr ); ldbm_datum_free( db->dbc_db, data ); ldbm_cache_close( be, db ); - Debug( LDAP_DEBUG_TRACE, "<= id2entry( %ld ) 0x%x (disk)\n", id, e, 0 ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_rw: %s of %ld failed\n", + rw ? "write" : "read", id )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) (failed)\n", + rw ? "w" : "r", id, 0 ); +#endif + + return( NULL ); + } + + e->e_id = id; + + if( cache_add_entry_rw( &li->li_cache, e, rw ) != 0 ) { + entry_free( e ); + + /* XXX this is a kludge. + * maybe the entry got added underneath us + * There are many underlying race condtions in the cache/disk code. + */ + if ( (e = cache_find_entry_id( &li->li_cache, id, rw )) != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_DETAIL1, + "id2entry_rw: %s of %ld 0x%lx (cache)\n", + rw ? "write" : "read", id, (unsigned long)e )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) 0x%lx (cache)\n", + rw ? "w" : "r", id, (unsigned long) e ); +#endif + + return( e ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ERR, + "id2entry_rw: %s of %ld (cache add failed)\n", + rw ? "write" : "read", id )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) (cache add failed)\n", + rw ? "w" : "r", id, 0 ); +#endif + + return NULL; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "id2entry", LDAP_LEVEL_ENTRY, + "id2entry_rw: %s of %ld 0x%lx (disk)\n", + rw ? "write" : "read", id, (unsigned long)e )); +#else + Debug( LDAP_DEBUG_TRACE, "<= id2entry_%s( %ld ) 0x%lx (disk)\n", + rw ? "w" : "r", id, (unsigned long) e ); +#endif + + /* marks the entry as committed, so it will get added to the cache + * when the lock is released */ + cache_entry_commit( e ); + return( e ); } diff --git a/servers/slapd/back-ldbm/idl.c b/servers/slapd/back-ldbm/idl.c index 60828a26101a23339b5e4807305aa0f9b9147f95..2fe5d6fd04b0dfd5d6cff253961decfbed5a7862 100644 --- a/servers/slapd/back-ldbm/idl.c +++ b/servers/slapd/back-ldbm/idl.c @@ -1,104 +1,192 @@ /* idl.c - ldap id list handling routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" -#include "ldapconfig.h" #include "back-ldbm.h" -extern Datum ldbm_cache_fetch(); +static ID_BLOCK* idl_dup( ID_BLOCK *idl ); + +static void cont_alloc( Datum *cont, Datum *key ) +{ + ldbm_datum_init( *cont ); + cont->dsize = 1 + sizeof(ID) + key->dsize; + cont->dptr = ch_malloc( cont->dsize ); + + * (unsigned char *) cont->dptr = SLAP_INDEX_CONT_PREFIX; + + AC_MEMCPY( &((unsigned char *)cont->dptr)[1 + sizeof(ID)], + key->dptr, key->dsize ); +} + +static void cont_id( Datum *cont, ID id ) +{ + unsigned int i; + + for( i=1; i <= sizeof(id); i++) { + ((unsigned char *)cont->dptr)[i] = (unsigned char)(id & 0xFF); + id >>= 8; + } + +} + +static void cont_free( Datum *cont ) +{ + ch_free( cont->dptr ); +} + +#ifdef LDBM_DEBUG_IDL +static void idl_check(ID_BLOCK *idl) +{ + int i; + ID_BLOCK last; + + if( ID_BLOCK_INDIRECT(idl) || ID_BLOCK_ALLIDS(idl) + || ID_BLOCK_NIDS(idl) <= 1 ) + { + return; + } + + for( last = ID_BLOCK_ID(idl, 0), i = 1; + i < ID_BLOCK_NIDS(idl); + last = ID_BLOCK_ID(idl, i), i++ ) + { + assert (last < ID_BLOCK_ID(idl, i) ); + } +} +#endif -IDList * -idl_alloc( int nids ) +/* Allocate an ID_BLOCK with room for nids ids */ +ID_BLOCK * +idl_alloc( unsigned int nids ) { - IDList *new; + ID_BLOCK *new; /* nmax + nids + space for the ids */ - new = (IDList *) ch_calloc( (2 + nids), sizeof(ID) ); - new->b_nmax = nids; - new->b_nids = 0; + new = (ID_BLOCK *) ch_calloc( (ID_BLOCK_IDS_OFFSET + nids), sizeof(ID) ); + ID_BLOCK_NMAX(new) = nids; + ID_BLOCK_NIDS(new) = 0; return( new ); } -IDList * + +/* Allocate an empty ALLIDS ID_BLOCK */ +ID_BLOCK * idl_allids( Backend *be ) { - IDList *idl; + ID_BLOCK *idl; + ID id; idl = idl_alloc( 0 ); - idl->b_nmax = ALLIDSBLOCK; - idl->b_nids = next_id_get( be ); + ID_BLOCK_NMAX(idl) = ID_BLOCK_ALLIDS_VALUE; + if ( next_id_get( be, &id ) ) { + return NULL; + } + ID_BLOCK_NIDS(idl) = id; return( idl ); } +/* Free an ID_BLOCK */ void -idl_free( IDList *idl ) +idl_free( ID_BLOCK *idl ) { if ( idl == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_free: called with NULL pointer\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "idl_free: called with NULL pointer\n", + 0, 0, 0 ); +#endif + return; } free( (char *) idl ); } -static IDList * + +/* Fetch an single ID_BLOCK from the cache */ +static ID_BLOCK * idl_fetch_one( Backend *be, - struct dbcache *db, + DBCache *db, Datum key ) { - Datum data, k2; - IDList *idl; - IDList **tmp; - char *kstr; - int i, nids; + Datum data; + ID_BLOCK *idl; /* Debug( LDAP_DEBUG_TRACE, "=> idl_fetch_one\n", 0, 0, 0 ); */ data = ldbm_cache_fetch( db, key ); - idl = (IDList *) data.dptr; + if( data.dptr == NULL ) { + return NULL; + } - return( idl ); + idl = (ID_BLOCK *) data.dptr; + if ( ID_BLOCK_ALLIDS(idl) ) { + /* make sure we have the current value of highest id */ + idl = idl_allids( be ); + } else { + idl = idl_dup((ID_BLOCK *) data.dptr); + } + + ldbm_datum_free( db->dbc_db, data ); + + return idl; } -IDList * + +/* Fetch a set of ID_BLOCKs from the cache + * if not INDIRECT + * if block return is an ALLIDS block, + * return an new ALLIDS block + * otherwise + * return block + * construct super block from all blocks referenced by INDIRECT block + * return super block + */ +ID_BLOCK * idl_fetch( Backend *be, - struct dbcache *db, + DBCache *db, Datum key ) { - Datum data, k2; - IDList *idl; - IDList **tmp; - char *kstr; - int i, nids; - - /* Debug( LDAP_DEBUG_TRACE, "=> idl_fetch\n", 0, 0, 0 ); */ + Datum data; + ID_BLOCK *idl; + ID_BLOCK **tmp; + int nids; + unsigned i; - data = ldbm_cache_fetch( db, key ); + idl = idl_fetch_one( be, db, key ); - if ( (idl = (IDList *) data.dptr) == NULL ) { - return( NULL ); + if ( idl == NULL ) { + return NULL; } - /* regular block */ - if ( ! INDIRECT_BLOCK( idl ) ) { - /* - Debug( LDAP_DEBUG_TRACE, "<= idl_fetch %d ids (%d max)\n", - idl->b_nids, idl->b_nmax, 0 ); - */ + if ( ID_BLOCK_ALLIDS(idl) ) { + /* all ids block */ + return( idl ); + } - /* make sure we have the current value of highest id */ - if ( idl->b_nmax == ALLIDSBLOCK ) { - idl_free( idl ); - idl = idl_allids( be ); - } + if ( ! ID_BLOCK_INDIRECT( idl ) ) { + /* regular block */ return( idl ); } @@ -108,33 +196,46 @@ idl_fetch( * a big id list containing all the ids, which we will return. */ +#ifndef USE_INDIRECT_NIDS /* count the number of blocks & allocate space for pointers to them */ - for ( i = 0; idl->b_ids[i] != NOID; i++ ) + for ( i = 0; !ID_BLOCK_NOID(idl, i); i++ ) ; /* NULL */ - tmp = (IDList **) ch_malloc( (i + 1) * sizeof(IDList *) ); +#else + i = ID_BLOCK_NIDS(idl); +#endif + tmp = (ID_BLOCK **) ch_malloc( (i + 1) * sizeof(ID_BLOCK *) ); /* read in all the blocks */ - kstr = (char *) ch_malloc( key.dsize + 20 ); + cont_alloc( &data, &key ); nids = 0; - for ( i = 0; idl->b_ids[i] != NOID; i++ ) { - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, idl->b_ids[i] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; - - if ( (tmp[i] = idl_fetch_one( be, db, k2 )) == NULL ) { +#ifndef USE_INDIRECT_NIDS + for ( i = 0; !ID_BLOCK_NOID(idl, i); i++ ) { +#else + for ( i = 0; i < ID_BLOCK_NIDS(idl); i++ ) { +#endif + cont_id( &data, ID_BLOCK_ID(idl, i) ); + + if ( (tmp[i] = idl_fetch_one( be, db, data )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_fetch: idl_fetch_one returned NULL\n" )); +#else Debug( LDAP_DEBUG_ANY, - "idl_fetch of (%s) returns NULL\n", k2.dptr, 0, 0 ); + "idl_fetch: one returned NULL\n", 0, 0, 0 ); +#endif + continue; } - nids += tmp[i]->b_nids; + nids += ID_BLOCK_NIDS(tmp[i]); } tmp[i] = NULL; + cont_free( &data ); idl_free( idl ); /* allocate space for the big block */ idl = idl_alloc( nids ); - idl->b_nids = nids; + ID_BLOCK_NIDS(idl) = nids; nids = 0; /* copy in all the ids from the component blocks */ @@ -143,94 +244,161 @@ idl_fetch( continue; } - SAFEMEMCPY( (char *) &idl->b_ids[nids], (char *) tmp[i]->b_ids, - tmp[i]->b_nids * sizeof(ID) ); - nids += tmp[i]->b_nids; + AC_MEMCPY( + (char *) &ID_BLOCK_ID(idl, nids), + (char *) &ID_BLOCK_ID(tmp[i], 0), + ID_BLOCK_NIDS(tmp[i]) * sizeof(ID) ); + nids += ID_BLOCK_NIDS(tmp[i]); idl_free( tmp[i] ); } free( (char *) tmp ); - Debug( LDAP_DEBUG_TRACE, "<= idl_fetch %d ids (%d max)\n", idl->b_nids, - idl->b_nmax, 0 ); +#ifdef LDBM_DEBUG_IDL + idl_check(idl); +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ENTRY, + "idl_fetch: %ld ids (%ld max)\n", + ID_BLOCK_NIDS(idl), ID_BLOCK_NMAXN(idl) )); +#else + Debug( LDAP_DEBUG_TRACE, "<= idl_fetch %ld ids (%ld max)\n", + ID_BLOCK_NIDS(idl), ID_BLOCK_NMAXN(idl), 0 ); +#endif + return( idl ); } + +/* store a single block */ static int idl_store( Backend *be, - struct dbcache *db, + DBCache *db, Datum key, - IDList *idl + ID_BLOCK *idl ) { - int rc; + int rc, flags; Datum data; +#ifdef LDBM_DEBUG_IDL + idl_check(idl); +#endif + + ldbm_datum_init( data ); + /* Debug( LDAP_DEBUG_TRACE, "=> idl_store\n", 0, 0, 0 ); */ data.dptr = (char *) idl; - data.dsize = (2 + idl->b_nmax) * sizeof(ID); + data.dsize = (ID_BLOCK_IDS_OFFSET + ID_BLOCK_NMAXN(idl)) * sizeof(ID); + + flags = LDBM_REPLACE; + rc = ldbm_cache_store( db, key, data, flags ); - rc = ldbm_cache_store( db, key, data, LDBM_REPLACE ); +#ifdef LDBM_DEBUG + Statslog( LDAP_DEBUG_STATS, "<= idl_store(): rc=%d\n", + rc, 0, 0, 0, 0 ); +#endif /* Debug( LDAP_DEBUG_TRACE, "<= idl_store %d\n", rc, 0, 0 ); */ return( rc ); } +/* Binary search for id in block, return index + * an index is always returned, even with no match. If no + * match, the returned index is the insertion point. + */ +static unsigned int +idl_find( + ID_BLOCK *b, + ID id +) +{ + int lo=0, hi=ID_BLOCK_NIDS(b)-1, nr=0; + + for (;lo<=hi;) + { + nr = ( lo + hi ) / 2; + if (ID_BLOCK_ID(b, nr) == id) + break; + if (ID_BLOCK_ID(b, nr) > id) + hi = nr - 1; + else + lo = nr + 1; + } + return nr; +} + +/* split the block at id + * locate ID greater than or equal to id. + */ static void idl_split_block( - IDList *b, + ID_BLOCK *b, ID id, - IDList **n1, - IDList **n2 + ID_BLOCK **right, + ID_BLOCK **left ) { - int i; + unsigned int nr, nl; /* find where to split the block */ - for ( i = 0; i < b->b_nids && id > b->b_ids[i]; i++ ) - ; /* NULL */ + nr = idl_find(b, id); + if ( ID_BLOCK_ID(b,nr) < id ) + nr++; + + nl = ID_BLOCK_NIDS(b) - nr; - *n1 = idl_alloc( i == 0 ? 1 : i ); - *n2 = idl_alloc( b->b_nids - i + (i == 0 ? 0 : 1)); + *right = idl_alloc( nr == 0 ? 1 : nr ); + *left = idl_alloc( nl + (nr == 0 ? 0 : 1)); /* * everything before the id being inserted in the first block * unless there is nothing, in which case the id being inserted * goes there. */ - SAFEMEMCPY( (char *) &(*n1)->b_ids[0], (char *) &b->b_ids[0], - i * sizeof(ID) ); - (*n1)->b_nids = (i == 0 ? 1 : i); - - if ( i == 0 ) { - (*n1)->b_ids[0] = id; + if ( nr == 0 ) { + ID_BLOCK_NIDS(*right) = 1; + ID_BLOCK_ID(*right, 0) = id; } else { - (*n2)->b_ids[0] = id; + AC_MEMCPY( + (char *) &ID_BLOCK_ID(*right, 0), + (char *) &ID_BLOCK_ID(b, 0), + nr * sizeof(ID) ); + ID_BLOCK_NIDS(*right) = nr; + ID_BLOCK_ID(*left, 0) = id; } /* the id being inserted & everything after in the second block */ - SAFEMEMCPY( (char *) &(*n2)->b_ids[i == 0 ? 0 : 1], - (char *) &b->b_ids[i], (b->b_nids - i) * sizeof(ID) ); - (*n2)->b_nids = b->b_nids - i + (i == 0 ? 0 : 1); + AC_MEMCPY( + (char *) &ID_BLOCK_ID(*left, (nr == 0 ? 0 : 1)), + (char *) &ID_BLOCK_ID(b, nr), + nl * sizeof(ID) ); + ID_BLOCK_NIDS(*left) = nl + (nr == 0 ? 0 : 1); + +#ifdef LDBM_DEBUG_IDL + idl_check(*right); + idl_check(*left); +#endif } + /* * idl_change_first - called when an indirect block's first key has * changed, meaning it needs to be stored under a new key, and the * header block pointing to it needs updating. */ - static int idl_change_first( Backend *be, - struct dbcache *db, + DBCache *db, Datum hkey, /* header block key */ - IDList *h, /* header block */ + ID_BLOCK *h, /* header block */ int pos, /* pos in h to update */ Datum bkey, /* data block key */ - IDList *b /* data block */ + ID_BLOCK *b /* data block */ ) { int rc; @@ -239,56 +407,80 @@ idl_change_first( /* delete old key block */ if ( (rc = ldbm_cache_delete( db, bkey )) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_change_first: ldbm_cache_delete returned %d\n", rc )); +#else Debug( LDAP_DEBUG_ANY, - "ldbm_delete of (%s) returns %d\n", bkey.dptr, rc, - 0 ); + "idl_change_first: ldbm_cache_delete returned %d\n", + rc, 0, 0 ); +#endif + return( rc ); } /* write block with new key */ - sprintf( bkey.dptr, "%c%s%d", CONT_PREFIX, hkey.dptr, b->b_ids[0] ); - bkey.dsize = strlen( bkey.dptr ) + 1; + cont_id( &bkey, ID_BLOCK_ID(b, 0) ); + if ( (rc = idl_store( be, db, bkey, b )) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_change_first: idl_store returned %d\n", rc )); +#else Debug( LDAP_DEBUG_ANY, - "idl_store of (%s) returns %d\n", bkey.dptr, rc, 0 ); + "idl_change_first: idl_store returned %d\n", rc, 0, 0 ); +#endif + return( rc ); } /* update + write indirect header block */ - h->b_ids[pos] = b->b_ids[0]; + ID_BLOCK_ID(h, pos) = ID_BLOCK_ID(b, 0); if ( (rc = idl_store( be, db, hkey, h )) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_change_first: idl_store returned %s\n", rc )); +#else Debug( LDAP_DEBUG_ANY, - "idl_store of (%s) returns %d\n", hkey.dptr, rc, 0 ); + "idl_change_first: idl_store returned %d\n", rc, 0, 0 ); +#endif + return( rc ); } return( 0 ); } + int idl_insert_key( Backend *be, - struct dbcache *db, + DBCache *db, Datum key, ID id ) { - int i, j, first, rc; - IDList *idl, *tmp, *tmp2, *tmp3; - char *kstr; + int i, j, first, rc = 0; + ID_BLOCK *idl, *tmp, *tmp2, *tmp3; Datum k2; if ( (idl = idl_fetch_one( be, db, key )) == NULL ) { idl = idl_alloc( 1 ); - idl->b_ids[idl->b_nids++] = id; + ID_BLOCK_ID(idl, ID_BLOCK_NIDS(idl)++) = id; rc = idl_store( be, db, key, idl ); idl_free( idl ); return( rc ); } - /* regular block */ - if ( ! INDIRECT_BLOCK( idl ) ) { + if ( ID_BLOCK_ALLIDS( idl ) ) { + /* ALLIDS */ + idl_free( idl ); + return 0; + } + + if ( ! ID_BLOCK_INDIRECT( idl ) ) { + /* regular block */ switch ( idl_insert( &idl, id, db->dbc_maxids ) ) { case 0: /* id inserted - store the updated block */ case 1: @@ -305,41 +497,41 @@ idl_insert_key( idl_free( idl ); idl = idl_allids( be ); rc = idl_store( be, db, key, idl ); - idl_free( idl ); - - return( rc ); + break; } idl_split_block( idl, id, &tmp, &tmp2 ); idl_free( idl ); /* create the header indirect block */ +#ifndef USE_INDIRECT_NIDS idl = idl_alloc( 3 ); - idl->b_nmax = 3; - idl->b_nids = INDBLOCK; - idl->b_ids[0] = tmp->b_ids[0]; - idl->b_ids[1] = tmp2->b_ids[0]; - idl->b_ids[2] = NOID; + ID_BLOCK_NMAX(idl) = 3; + ID_BLOCK_NIDS(idl) = ID_BLOCK_INDIRECT_VALUE; + ID_BLOCK_ID(idl, 0) = ID_BLOCK_ID(tmp, 0); + ID_BLOCK_ID(idl, 1) = ID_BLOCK_ID(tmp2, 0); + ID_BLOCK_ID(idl, 2) = NOID; +#else + idl = idl_alloc( 2 ); + ID_BLOCK_NMAX(idl) = 2 | ID_BLOCK_INDIRECT_VALUE; + ID_BLOCK_NIDS(idl) = 2; + ID_BLOCK_ID(idl, 0) = ID_BLOCK_ID(tmp, 0); + ID_BLOCK_ID(idl, 1) = ID_BLOCK_ID(tmp2, 0); +#endif /* store it */ rc = idl_store( be, db, key, idl ); - /* store the first id block */ - kstr = (char *) ch_malloc( key.dsize + 20 ); - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - tmp->b_ids[0] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_alloc( &k2, &key ); + cont_id( &k2, ID_BLOCK_ID(tmp, 0) ); + rc = idl_store( be, db, k2, tmp ); - /* store the second id block */ - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - tmp2->b_ids[0] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_id( &k2, ID_BLOCK_ID(tmp2, 0) ); rc = idl_store( be, db, k2, tmp2 ); - free( kstr ); + cont_free( &k2 ); + idl_free( tmp ); idl_free( tmp2 ); break; @@ -357,9 +549,16 @@ idl_insert_key( * need to write a new "header" block. */ - /* select the block to try inserting into */ - for ( i = 0; idl->b_ids[i] != NOID && id > idl->b_ids[i]; i++ ) +#ifndef USE_INDIRECT_NIDS + /* select the block to try inserting into *//* XXX linear search XXX */ + for ( i = 0; !ID_BLOCK_NOID(idl, i) && id > ID_BLOCK_ID(idl, i); i++ ) ; /* NULL */ +#else + i = idl_find(idl, id); + if (ID_BLOCK_ID(idl, i) < id) + i++; +#endif + if ( i != 0 ) { i--; first = 0; @@ -368,13 +567,20 @@ idl_insert_key( } /* get the block */ - kstr = (char *) ch_malloc( key.dsize + 20 ); - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, idl->b_ids[i] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_alloc( &k2, &key ); + cont_id( &k2, ID_BLOCK_ID(idl, i) ); + if ( (tmp = idl_fetch_one( be, db, k2 )) == NULL ) { - Debug( LDAP_DEBUG_ANY, "nonexistent continuation block (%s)\n", - k2.dptr, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, + "idl_insert_key: nonexistent continuation block\n" )); +#else + Debug( LDAP_DEBUG_ANY, "idl_insert_key: nonexistent continuation block\n", + 0, 0, 0 ); +#endif + + cont_free( &k2 ); + idl_free( idl ); return( -1 ); } @@ -382,8 +588,14 @@ idl_insert_key( switch ( idl_insert( &tmp, id, db->dbc_maxids ) ) { case 0: /* id inserted ok */ if ( (rc = idl_store( be, db, k2, tmp )) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, + "ids_insert_key: idl_store returned %d\n", rc )); +#else Debug( LDAP_DEBUG_ANY, - "idl_store of (%s) returns %d\n", k2.dptr, rc, 0 ); + "idl_insert_key: idl_store returned %d\n", rc, 0, 0 ); +#endif + } break; @@ -398,7 +610,8 @@ idl_insert_key( rc = idl_change_first( be, db, key, idl, i, k2, tmp ); break; - case 2: /* id not inserted - already there */ + case 2: /* id not inserted - already there, do nothing */ + rc = 0; break; case 3: /* id not inserted - block is full */ @@ -408,18 +621,60 @@ idl_insert_key( * into the beginning of the first block. */ +#ifndef USE_INDIRECT_NIDS /* is there a next block? */ - if ( !first && idl->b_ids[i + 1] != NOID ) { + if ( !first && !ID_BLOCK_NOID(idl, i + 1) ) { +#else + if ( !first && (unsigned long)(i + 1) < ID_BLOCK_NIDS(idl) ) { +#endif /* read it in */ - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - idl->b_ids[i + 1] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_alloc( &k2, &key ); + cont_id( &k2, ID_BLOCK_ID(idl, i) ); if ( (tmp2 = idl_fetch_one( be, db, k2 )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, + "idl_insert_key: idl_fetch_one returned NULL\n")); +#else Debug( LDAP_DEBUG_ANY, - "idl_fetch_one (%s) returns NULL\n", - k2.dptr, 0, 0 ); - break; + "idl_insert_key: idl_fetch_one returned NULL\n", + 0, 0, 0 ); +#endif + + /* split the original block */ + cont_free( &k2 ); + goto split; + } + + /* If the new id is less than the last id in the + * current block, it must not be put into the next + * block. Push the last id of the current block + * into the next block instead. + */ + if (id < ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp) - 1)) { + ID id2 = ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp) - 1); + + --ID_BLOCK_NIDS(tmp); + /* This must succeed since we just popped one + * ID off the end of it. + */ + rc = idl_insert( &tmp, id, db->dbc_maxids ); + + if ( (rc = idl_store( be, db, k2, tmp )) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_ERR, + "idl_insert_key: idl_store returned %d\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "idl_insert_key: idl_store returned %d\n", rc, 0, 0 ); +#endif + + } + + id = id2; + /* This new id will necessarily be inserted + * as the first id of the next block by the + * following switch() statement. + */ } switch ( (rc = idl_insert( &tmp2, id, @@ -430,50 +685,70 @@ idl_insert_key( /* FALL */ case 2: /* id already there - how? */ - case 0: /* id inserted */ + case 0: /* id inserted: this can never be + * the result of idl_insert, because + * we guaranteed that idl_change_first + * will always be called. + */ if ( rc == 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_insert_key: id %ld is already in next block\n", + id )); +#else Debug( LDAP_DEBUG_ANY, - "id %d already in next block\n", + "idl_insert_key: id %ld already in next block\n", id, 0, 0 ); +#endif + } - free( kstr ); + idl_free( tmp ); idl_free( tmp2 ); idl_free( idl ); return( 0 ); case 3: /* split the original block */ - idl_free( tmp2 ); break; } + idl_free( tmp2 ); } +split: /* * must split the block, write both new blocks + update * and write the indirect header block. */ - /* count how many indirect blocks */ - for ( j = 0; idl->b_ids[j] != NOID; j++ ) + rc = 0; /* optimistic */ + + +#ifndef USE_INDIRECT_NIDS + /* count how many indirect blocks *//* XXX linear count XXX */ + for ( j = 0; !ID_BLOCK_NOID(idl, j); j++ ) ; /* NULL */ +#else + j = ID_BLOCK_NIDS(idl); +#endif /* check it against all-id thresholed */ if ( j + 1 > db->dbc_maxindirect ) { /* * we've passed the all-id threshold, meaning * that this set of blocks should be replaced - * by a single "all-id" block. our job: delete + * by a single "all-id" block. our job: delete * all the indirect blocks, and replace the header * block by an all-id block. */ /* delete all indirect blocks */ - for ( j = 0; idl->b_ids[j] != NOID; j++ ) { - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - idl->b_ids[j] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; +#ifndef USE_INDIRECT_NIDS + for ( j = 0; !ID_BLOCK_NOID(idl, j); j++ ) { +#else + for ( j = 0; (unsigned long) j < ID_BLOCK_NIDS(idl); j++ ) { +#endif + cont_id( &k2, ID_BLOCK_ID(idl, j) ); rc = ldbm_cache_delete( db, k2 ); } @@ -483,7 +758,7 @@ idl_insert_key( idl = idl_allids( be ); rc = idl_store( be, db, key, idl ); - free( kstr ); + cont_free( &k2 ); idl_free( idl ); idl_free( tmp ); return( rc ); @@ -493,33 +768,43 @@ idl_insert_key( idl_free( tmp ); /* create a new updated indirect header block */ - tmp = idl_alloc( idl->b_nmax + 1 ); - tmp->b_nids = INDBLOCK; + tmp = idl_alloc( ID_BLOCK_NMAXN(idl) + 1 ); +#ifndef USE_INDIRECT_NIDS + ID_BLOCK_NIDS(tmp) = ID_BLOCK_INDIRECT_VALUE; +#else + ID_BLOCK_NMAX(tmp) |= ID_BLOCK_INDIRECT_VALUE; +#endif /* everything up to the split block */ - SAFEMEMCPY( (char *) tmp->b_ids, (char *) idl->b_ids, + AC_MEMCPY( + (char *) &ID_BLOCK_ID(tmp, 0), + (char *) &ID_BLOCK_ID(idl, 0), i * sizeof(ID) ); /* the two new blocks */ - tmp->b_ids[i] = tmp2->b_ids[0]; - tmp->b_ids[i + 1] = tmp3->b_ids[0]; + ID_BLOCK_ID(tmp, i) = ID_BLOCK_ID(tmp2, 0); + ID_BLOCK_ID(tmp, i + 1) = ID_BLOCK_ID(tmp3, 0); /* everything after the split block */ - SAFEMEMCPY( (char *) &tmp->b_ids[i + 2], (char *) - &idl->b_ids[i + 1], (idl->b_nmax - i - 1) * sizeof(ID) ); +#ifndef USE_INDIRECT_NIDS + AC_MEMCPY( + (char *) &ID_BLOCK_ID(tmp, i + 2), + (char *) &ID_BLOCK_ID(idl, i + 1), + (ID_BLOCK_NMAXN(idl) - i - 1) * sizeof(ID) ); +#else + AC_MEMCPY( + (char *) &ID_BLOCK_ID(tmp, i + 2), + (char *) &ID_BLOCK_ID(idl, i + 1), + (ID_BLOCK_NIDS(idl) - i - 1) * sizeof(ID) ); + ID_BLOCK_NIDS(tmp) = ID_BLOCK_NIDS(idl) + 1; +#endif /* store the header block */ rc = idl_store( be, db, key, tmp ); /* store the first id block */ - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - tmp2->b_ids[0] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_id( &k2, ID_BLOCK_ID(tmp2, 0) ); rc = idl_store( be, db, k2, tmp2 ); /* store the second id block */ - sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, - tmp3->b_ids[0] ); - k2.dptr = kstr; - k2.dsize = strlen( kstr ) + 1; + cont_id( &k2, ID_BLOCK_ID(tmp3, 0) ); rc = idl_store( be, db, k2, tmp3 ); idl_free( tmp2 ); @@ -527,122 +812,278 @@ idl_insert_key( break; } - free( kstr ); + cont_free( &k2 ); idl_free( tmp ); idl_free( idl ); return( rc ); } + /* * idl_insert - insert an id into an id list. - * returns 0 id inserted + * + * returns + * 0 id inserted * 1 id inserted, first id in block has changed * 2 id not inserted, already there * 3 id not inserted, block must be split */ - int -idl_insert( IDList **idl, ID id, int maxids ) +idl_insert( ID_BLOCK **idl, ID id, unsigned int maxids ) { - int i, j; + unsigned int i; - if ( ALLIDS( *idl ) ) { + if ( ID_BLOCK_ALLIDS( *idl ) ) { return( 2 ); /* already there */ } - /* is it already there? XXX bin search XXX */ - for ( i = 0; i < (*idl)->b_nids && id > (*idl)->b_ids[i]; i++ ) { - ; /* NULL */ - } - if ( i < (*idl)->b_nids && (*idl)->b_ids[i] == id ) { + /* is it already there? */ + i = idl_find(*idl, id); + if ( ID_BLOCK_ID(*idl, i) == id ) { return( 2 ); /* already there */ } + if ( ID_BLOCK_NIDS(*idl) && ID_BLOCK_ID(*idl, i) < id ) + i++; /* do we need to make room for it? */ - if ( (*idl)->b_nids == (*idl)->b_nmax ) { + if ( ID_BLOCK_NIDS(*idl) == ID_BLOCK_NMAXN(*idl) ) { /* make room or indicate block needs splitting */ - if ( (*idl)->b_nmax == maxids ) { + if ( ID_BLOCK_NMAXN(*idl) >= maxids ) { return( 3 ); /* block needs splitting */ } - (*idl)->b_nmax *= 2; - if ( (*idl)->b_nmax > maxids ) { - (*idl)->b_nmax = maxids; + ID_BLOCK_NMAX(*idl) *= 2; + if ( ID_BLOCK_NMAXN(*idl) > maxids ) { + ID_BLOCK_NMAX(*idl) = maxids; } - *idl = (IDList *) ch_realloc( (char *) *idl, - ((*idl)->b_nmax + 2) * sizeof(ID) ); + *idl = (ID_BLOCK *) ch_realloc( (char *) *idl, + (ID_BLOCK_NMAXN(*idl) + ID_BLOCK_IDS_OFFSET) * sizeof(ID) ); } /* make a slot for the new id */ - for ( j = (*idl)->b_nids; j != i; j-- ) { - (*idl)->b_ids[j] = (*idl)->b_ids[j-1]; - } - (*idl)->b_ids[i] = id; - (*idl)->b_nids++; - (void) memset( (char *) &(*idl)->b_ids[(*idl)->b_nids], '\0', - ((*idl)->b_nmax - (*idl)->b_nids) * sizeof(ID) ); + AC_MEMCPY( &ID_BLOCK_ID(*idl, i+1), &ID_BLOCK_ID(*idl, i), + (ID_BLOCK_NIDS(*idl) - i) * sizeof(ID) ); + + ID_BLOCK_ID(*idl, i) = id; + ID_BLOCK_NIDS(*idl)++; + (void) memset( + (char *) &ID_BLOCK_ID((*idl), ID_BLOCK_NIDS(*idl)), + '\0', + (ID_BLOCK_NMAXN(*idl) - ID_BLOCK_NIDS(*idl)) * sizeof(ID) ); + +#ifdef LDBM_DEBUG_IDL + idl_check(*idl); +#endif return( i == 0 ? 1 : 0 ); /* inserted - first id changed or not */ } -static IDList * -idl_dup( IDList *idl ) + +int +idl_delete_key ( + Backend *be, + DBCache *db, + Datum key, + ID id +) +{ + Datum data; + ID_BLOCK *idl; + unsigned i; + int j, nids; + + if ( (idl = idl_fetch_one( be, db, key ) ) == NULL ) + { + /* It wasn't found. Hmm... */ + return -1; + } + + if ( ID_BLOCK_ALLIDS( idl ) ) { + idl_free( idl ); + return 0; + } + + if ( ! ID_BLOCK_INDIRECT( idl ) ) { + i = idl_find(idl, id); + if ( ID_BLOCK_ID(idl, i) == id ) { + if( --ID_BLOCK_NIDS(idl) == 0 ) { + ldbm_cache_delete( db, key ); + + } else { + AC_MEMCPY( + &ID_BLOCK_ID(idl, i), + &ID_BLOCK_ID(idl, i+1), + (ID_BLOCK_NIDS(idl)-i) * sizeof(ID) ); + + ID_BLOCK_ID(idl, ID_BLOCK_NIDS(idl)) = NOID; + + idl_store( be, db, key, idl ); + } + + idl_free( idl ); + return 0; + } + /* We didn't find the ID. Hmmm... */ + idl_free( idl ); + return -1; + } + + /* We have to go through an indirect block and find the ID + in the list of IDL's + */ + cont_alloc( &data, &key ); +#ifndef USE_INDIRECT_NIDS + for ( nids = 0; !ID_BLOCK_NOID(idl, nids); nids++ ) + ; /* NULL */ + + for ( j = 0; j<nids; j++ ) +#else + nids = ID_BLOCK_NIDS(idl); + for ( j = idl_find(idl, id); j >= 0; j = -1) /* execute once */ +#endif + { + ID_BLOCK *tmp; + cont_id( &data, ID_BLOCK_ID(idl, j) ); + + if ( (tmp = idl_fetch_one( be, db, data )) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "idl", LDAP_LEVEL_INFO, + "idl_delete_key: idl_fetch_one returned NULL\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "idl_delete_key: idl_fetch of returned NULL\n", 0, 0, 0 ); +#endif + + continue; + } + /* + Now try to find the ID in tmp + */ + + i = idl_find(tmp, id); + if ( ID_BLOCK_ID(tmp, i) == id ) + { + AC_MEMCPY( + &ID_BLOCK_ID(tmp, i), + &ID_BLOCK_ID(tmp, i+1), + (ID_BLOCK_NIDS(tmp)-(i+1)) * sizeof(ID)); + ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp)-1 ) = NOID; + ID_BLOCK_NIDS(tmp)--; + + if ( ID_BLOCK_NIDS(tmp) ) { + idl_store ( be, db, data, tmp ); + + } else { + ldbm_cache_delete( db, data ); + AC_MEMCPY( + &ID_BLOCK_ID(idl, j), + &ID_BLOCK_ID(idl, j+1), + (nids-(j+1)) * sizeof(ID)); + ID_BLOCK_ID(idl, nids-1) = NOID; + nids--; +#ifdef USE_INDIRECT_NIDS + ID_BLOCK_NIDS(idl)--; +#endif + if ( ! nids ) + ldbm_cache_delete( db, key ); + else + idl_store( be, db, key, idl ); + } + idl_free( tmp ); + cont_free( &data ); + idl_free( idl ); + return 0; + } + idl_free( tmp ); + } + + cont_free( &data ); + idl_free( idl ); + return -1; +} + + +/* return a duplicate of a single ID_BLOCK */ +static ID_BLOCK * +idl_dup( ID_BLOCK *idl ) { - IDList *new; + ID_BLOCK *new; if ( idl == NULL ) { return( NULL ); } - new = idl_alloc( idl->b_nmax ); - SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2) - * sizeof(ID) ); + new = idl_alloc( ID_BLOCK_NMAXN(idl) ); + + AC_MEMCPY( + (char *) new, + (char *) idl, + (ID_BLOCK_NMAXN(idl) + ID_BLOCK_IDS_OFFSET) * sizeof(ID) ); + +#ifdef LDBM_DEBUG_IDL + idl_check(new); +#endif return( new ); } -static IDList * -idl_min( IDList *a, IDList *b ) + +/* return the smaller ID_BLOCK */ +static ID_BLOCK * +idl_min( ID_BLOCK *a, ID_BLOCK *b ) { - return( a->b_nids > b->b_nids ? b : a ); + return( ID_BLOCK_NIDS(a) > ID_BLOCK_NIDS(b) ? b : a ); } + /* * idl_intersection - return a intersection b */ - -IDList * +ID_BLOCK * idl_intersection( Backend *be, - IDList *a, - IDList *b + ID_BLOCK *a, + ID_BLOCK *b ) { - int ai, bi, ni; - IDList *n; + unsigned int ai, bi, ni; + ID_BLOCK *n; if ( a == NULL || b == NULL ) { return( NULL ); } - if ( ALLIDS( a ) ) { + if ( ID_BLOCK_ALLIDS( a ) ) { return( idl_dup( b ) ); } - if ( ALLIDS( b ) ) { + if ( ID_BLOCK_ALLIDS( b ) ) { return( idl_dup( a ) ); } n = idl_dup( idl_min( a, b ) ); - for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) { - for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ ) +#ifdef LDBM_DEBUG_IDL + idl_check(a); + idl_check(b); +#endif + + for ( ni = 0, ai = 0, bi = 0; ai < ID_BLOCK_NIDS(a); ai++ ) { + if ( ID_BLOCK_ID(a, ai) < ID_BLOCK_ID(b, bi) ) { + continue; + } + for ( ; + bi < ID_BLOCK_NIDS(b) && ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai); + bi++ ) + { ; /* NULL */ + } - if ( bi == b->b_nids ) { + if ( bi == ID_BLOCK_NIDS(b) ) { break; } - if ( b->b_ids[bi] == a->b_ids[ai] ) { - n->b_ids[ni++] = a->b_ids[ai]; + if ( ID_BLOCK_ID(b, bi) == ID_BLOCK_ID(a, ai) ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai); + bi++; } } @@ -650,24 +1091,28 @@ idl_intersection( idl_free( n ); return( NULL ); } - n->b_nids = ni; + ID_BLOCK_NIDS(n) = ni; + +#ifdef LDBM_DEBUG_IDL + idl_check(n); +#endif return( n ); } + /* * idl_union - return a union b */ - -IDList * +ID_BLOCK * idl_union( Backend *be, - IDList *a, - IDList *b + ID_BLOCK *a, + ID_BLOCK *b ) { - int ai, bi, ni; - IDList *n; + unsigned int ai, bi, ni; + ID_BLOCK *n; if ( a == NULL ) { return( idl_dup( b ) ); @@ -675,86 +1120,99 @@ idl_union( if ( b == NULL ) { return( idl_dup( a ) ); } - if ( ALLIDS( a ) || ALLIDS( b ) ) { + if ( ID_BLOCK_ALLIDS( a ) || ID_BLOCK_ALLIDS( b ) ) { return( idl_allids( be ) ); } - if ( b->b_nids < a->b_nids ) { +#ifdef LDBM_DEBUG_IDL + idl_check(a); + idl_check(b); +#endif + + if ( ID_BLOCK_NIDS(b) < ID_BLOCK_NIDS(a) ) { n = a; a = b; b = n; } - n = idl_alloc( a->b_nids + b->b_nids ); + n = idl_alloc( ID_BLOCK_NIDS(a) + ID_BLOCK_NIDS(b) ); + + for ( ni = 0, ai = 0, bi = 0; + ai < ID_BLOCK_NIDS(a) && bi < ID_BLOCK_NIDS(b); + ) + { + if ( ID_BLOCK_ID(a, ai) < ID_BLOCK_ID(b, bi) ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai++); + + } else if ( ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai) ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(b, bi++); - for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) { - if ( a->b_ids[ai] < b->b_ids[bi] ) { - n->b_ids[ni++] = a->b_ids[ai++]; - } else if ( b->b_ids[bi] < a->b_ids[ai] ) { - n->b_ids[ni++] = b->b_ids[bi++]; } else { - n->b_ids[ni++] = a->b_ids[ai]; + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai); ai++, bi++; } } - for ( ; ai < a->b_nids; ai++ ) { - n->b_ids[ni++] = a->b_ids[ai]; + for ( ; ai < ID_BLOCK_NIDS(a); ai++ ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai); } - for ( ; bi < b->b_nids; bi++ ) { - n->b_ids[ni++] = b->b_ids[bi]; + for ( ; bi < ID_BLOCK_NIDS(b); bi++ ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(b, bi); } - n->b_nids = ni; + ID_BLOCK_NIDS(n) = ni; + +#ifdef LDBM_DEBUG_IDL + idl_check(n); +#endif return( n ); } + /* * idl_notin - return a intersection ~b (or a minus b) */ - -IDList * +ID_BLOCK * idl_notin( Backend *be, - IDList *a, - IDList *b + ID_BLOCK *a, + ID_BLOCK *b ) { - int ni, ai, bi; - IDList *n; + unsigned int ni, ai, bi; + ID_BLOCK *n; if ( a == NULL ) { return( NULL ); } - if ( b == NULL ) { + if ( b == NULL || ID_BLOCK_ALLIDS( b )) { return( idl_dup( a ) ); } - if ( ALLIDS( b ) ) { - return( NULL ); - } - if ( ALLIDS( a ) ) { + if ( ID_BLOCK_ALLIDS( a ) ) { n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS ); ni = 0; - for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax && - bi < b->b_nmax; ai++ ) { - if ( b->b_ids[bi] == ai ) { + for ( ai = 1, bi = 0; + ai < ID_BLOCK_NIDS(a) && ni < ID_BLOCK_NMAXN(n) && bi < ID_BLOCK_NMAXN(b); + ai++ ) + { + if ( ID_BLOCK_ID(b, bi) == ai ) { bi++; } else { - n->b_ids[ni++] = ai; + ID_BLOCK_ID(n, ni++) = ai; } } - for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) { - n->b_ids[ni++] = ai; + for ( ; ai < ID_BLOCK_NIDS(a) && ni < ID_BLOCK_NMAXN(n); ai++ ) { + ID_BLOCK_ID(n, ni++) = ai; } - if ( ni == n->b_nmax ) { + if ( ni == ID_BLOCK_NMAXN(n) ) { idl_free( n ); return( idl_allids( be ) ); } else { - n->b_nids = ni; + ID_BLOCK_NIDS(n) = ni; return( n ); } } @@ -762,60 +1220,82 @@ idl_notin( n = idl_dup( a ); ni = 0; - for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) { - for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; - bi++ ) { + for ( ai = 0, bi = 0; ai < ID_BLOCK_NIDS(a); ai++ ) { + for ( ; + bi < ID_BLOCK_NIDS(b) && ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai); + bi++ ) + { ; /* NULL */ } - if ( bi == b->b_nids ) { + if ( bi == ID_BLOCK_NIDS(b) ) { break; } - if ( b->b_ids[bi] != a->b_ids[ai] ) { - n->b_ids[ni++] = a->b_ids[ai]; + if ( ID_BLOCK_ID(b, bi) != ID_BLOCK_ID(a, ai) ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai); } } - for ( ; ai < a->b_nids; ai++ ) { - n->b_ids[ni++] = a->b_ids[ai]; + for ( ; ai < ID_BLOCK_NIDS(a); ai++ ) { + ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai); } - n->b_nids = ni; + ID_BLOCK_NIDS(n) = ni; + +#ifdef LDBM_DEBUG_IDL + idl_check(n); +#endif return( n ); } +/* return the first ID in the block + * if ALLIDS block + * NIDS > 1 return 1 + * otherwise return NOID + * otherwise return first ID + * + * cursor is set to 1 + */ ID -idl_firstid( IDList *idl ) +idl_firstid( ID_BLOCK *idl, ID *cursor ) { - if ( idl == NULL || idl->b_nids == 0 ) { + *cursor = 1; + + if ( idl == NULL || ID_BLOCK_NIDS(idl) == 0 ) { return( NOID ); } - if ( ALLIDS( idl ) ) { - return( idl->b_nids == 1 ? NOID : 1 ); + if ( ID_BLOCK_ALLIDS( idl ) ) { + return( ID_BLOCK_NIDS(idl) > 1 ? 1 : NOID ); } - return( idl->b_ids[0] ); + return( ID_BLOCK_ID(idl, 0) ); } +/* return next ID + * if ALLIDS block, cursor is id. + * increment id + * if id < NIDS return id + * otherwise NOID. + * otherwise cursor is index into block + * if index < nids + * return id at index then increment + */ ID -idl_nextid( IDList *idl, ID id ) +idl_nextid( ID_BLOCK *idl, ID *cursor ) { - int i; - - if ( ALLIDS( idl ) ) { - return( ++id < idl->b_nids ? id : NOID ); + if ( ID_BLOCK_ALLIDS( idl ) ) { + if( ++(*cursor) < ID_BLOCK_NIDS(idl) ) { + return *cursor; + } else { + return NOID; + } } - for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) { - ; /* NULL */ + if ( *cursor < ID_BLOCK_NIDS(idl) ) { + return( ID_BLOCK_ID(idl, (*cursor)++) ); } - i++; - if ( i >= idl->b_nids ) { - return( NOID ); - } else { - return( idl->b_ids[i] ); - } + return( NOID ); } diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c index b9c5c2f3fa1feac501b93271679a854ce25819ec..ada60432c27dda7052075b41c1d7204e883dfdc3 100644 --- a/servers/slapd/back-ldbm/init.c +++ b/servers/slapd/back-ldbm/init.c @@ -1,25 +1,139 @@ /* init.c - initialize ldbm backend */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" #include "back-ldbm.h" -ldbm_back_init( +#ifdef SLAPD_LDBM_DYNAMIC + +int back_ldbm_LTX_init_module(int argc, char *argv[]) { + BackendInfo bi; + + memset( &bi, '\0', sizeof(bi) ); + bi.bi_type = "ldbm"; + bi.bi_init = ldbm_back_initialize; + + backend_add(&bi); + return 0; +} + +#endif /* SLAPD_LDBM_DYNAMIC */ + +int +ldbm_back_initialize( + BackendInfo *bi +) +{ + static char *controls[] = { + LDAP_CONTROL_MANAGEDSAIT, + NULL + }; + + bi->bi_controls = controls; + + bi->bi_open = ldbm_back_open; + bi->bi_config = NULL; + bi->bi_close = ldbm_back_close; + bi->bi_destroy = ldbm_back_destroy; + + bi->bi_db_init = ldbm_back_db_init; + bi->bi_db_config = ldbm_back_db_config; + bi->bi_db_open = ldbm_back_db_open; + bi->bi_db_close = ldbm_back_db_close; + bi->bi_db_destroy = ldbm_back_db_destroy; + + bi->bi_op_bind = ldbm_back_bind; + bi->bi_op_unbind = 0; + bi->bi_op_search = ldbm_back_search; + bi->bi_op_compare = ldbm_back_compare; + bi->bi_op_modify = ldbm_back_modify; + bi->bi_op_modrdn = ldbm_back_modrdn; + bi->bi_op_add = ldbm_back_add; + bi->bi_op_delete = ldbm_back_delete; + bi->bi_op_abandon = 0; + + bi->bi_extended = ldbm_back_extended; + + bi->bi_entry_release_rw = ldbm_back_entry_release_rw; + bi->bi_acl_group = ldbm_back_group; + bi->bi_acl_attribute = ldbm_back_attribute; + bi->bi_chk_referrals = ldbm_back_referrals; + bi->bi_operational = ldbm_back_operational; + + /* + * hooks for slap tools + */ + bi->bi_tool_entry_open = ldbm_tool_entry_open; + bi->bi_tool_entry_close = ldbm_tool_entry_close; + bi->bi_tool_entry_first = ldbm_tool_entry_first; + bi->bi_tool_entry_next = ldbm_tool_entry_next; + bi->bi_tool_entry_get = ldbm_tool_entry_get; + bi->bi_tool_entry_put = ldbm_tool_entry_put; + bi->bi_tool_entry_reindex = ldbm_tool_entry_reindex; + bi->bi_tool_sync = ldbm_tool_sync; + + bi->bi_connection_init = 0; + bi->bi_connection_destroy = 0; + + return 0; +} + +int +ldbm_back_destroy( + BackendInfo *bi +) +{ + return 0; +} + +int +ldbm_back_open( + BackendInfo *bi +) +{ + int rc; + + /* initialize the underlying database system */ + rc = ldbm_initialize( NULL ); + return rc; +} + +int +ldbm_back_close( + BackendInfo *bi +) +{ + /* terminate the underlying database system */ + ldbm_shutdown(); + return 0; +} + +int +ldbm_back_db_init( Backend *be ) { struct ldbminfo *li; - char *argv[ 4 ]; - int i; - /* allocate backend-specific stuff */ + /* indicate system schema supported */ + be->be_flags |= SLAP_BFLAG_ALIASES|SLAP_BFLAG_REFERRALS; + + /* allocate backend-database-specific stuff */ li = (struct ldbminfo *) ch_calloc( 1, sizeof(struct ldbminfo) ); /* arrange to read nextid later (on first request for it) */ - li->li_nextid = -1; + li->li_nextid = NOID; /* default cache size */ li->li_cache.c_maxsize = DEFAULT_CACHE_SIZE; @@ -27,45 +141,100 @@ ldbm_back_init( /* default database cache size */ li->li_dbcachesize = DEFAULT_DBCACHE_SIZE; + /* default db mode is with locking */ + li->li_dblocking = 1; + + /* default db mode is with write synchronization */ + li->li_dbwritesync = 1; + /* default file creation mode */ - li->li_mode = DEFAULT_MODE; + li->li_mode = SLAPD_DEFAULT_DB_MODE; /* default database directory */ - li->li_directory = DEFAULT_DB_DIRECTORY; - - /* always index dn, id2children, objectclass (used in some searches) */ - argv[ 0 ] = "dn"; - argv[ 1 ] = "dn"; - argv[ 2 ] = NULL; - attr_syntax_config( "ldbm dn initialization", 0, 2, argv ); - argv[ 0 ] = "dn"; - argv[ 1 ] = "sub"; - argv[ 2 ] = "eq"; - argv[ 3 ] = NULL; - attr_index_config( li, "ldbm dn initialization", 0, 3, argv, 1 ); - argv[ 0 ] = "id2children"; - argv[ 1 ] = "eq"; - argv[ 2 ] = NULL; - attr_index_config( li, "ldbm id2children initialization", 0, 2, argv, - 1 ); - argv[ 0 ] = "objectclass"; - argv[ 1 ] = strdup( "pres,eq" ); - argv[ 2 ] = NULL; - attr_index_config( li, "ldbm objectclass initialization", 0, 2, argv, - 1 ); - free( argv[ 1 ] ); + li->li_directory = ch_strdup( SLAPD_DEFAULT_DB_DIR ); + + /* DB_ENV environment pointer for DB3 */ + li->li_dbenv = 0; + + /* envdirok is turned on by ldbm_initialize_env if DB3 */ + li->li_envdirok = 0; + + /* syncfreq is 0 if disabled, or # seconds */ + li->li_dbsyncfreq = 0; + + /* wait up to dbsyncwaitn times if server is busy */ + li->li_dbsyncwaitn = 12; + + /* delay interval */ + li->li_dbsyncwaitinterval = 5; + + /* flag to notify ldbm_cache_sync_daemon to shut down */ + li->li_dbshutdown = 0; /* initialize various mutex locks & condition variables */ - pthread_mutex_init( &li->li_cache.c_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &li->li_nextid_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &li->li_dbcache_mutex, pthread_mutexattr_default ); - pthread_cond_init( &li->li_dbcache_cv, pthread_condattr_default ); - for ( i = 0; i < MAXDBCACHE; i++ ) { - pthread_mutex_init( &li->li_dbcache[i].dbc_mutex, - pthread_mutexattr_default ); - pthread_cond_init( &li->li_dbcache[i].dbc_cv, - pthread_condattr_default ); - } + ldap_pvt_thread_rdwr_init( &li->li_giant_rwlock ); + ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex ); + ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex ); + ldap_pvt_thread_cond_init( &li->li_dbcache_cv ); be->be_private = li; + + return 0; +} + +int +ldbm_back_db_open( + BackendDB *be +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + li->li_dbenv = ldbm_initialize_env( li->li_directory, + li->li_dbcachesize, &li->li_envdirok ); + + /* sync thread */ + if ( li->li_dbsyncfreq > 0 ) + { + int rc; + rc = ldap_pvt_thread_create( &li->li_dbsynctid, + 0, ldbm_cache_sync_daemon, (void*)be ); + + if ( rc != 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG (( "init", LDAP_LEVEL_ERR, "ldbm_back_db_open: sync " + "ldap_pvt_thread_create failed (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "sync ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 ); +#endif + return 1; + } + } + + return 0; +} + +int +ldbm_back_db_destroy( + BackendDB *be +) +{ + /* should free/destroy every in be_private */ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + + if (li->li_dbenv) + ldbm_shutdown_env(li->li_dbenv); + + free( li->li_directory ); + attr_index_destroy( li->li_attrs ); + + ldap_pvt_thread_rdwr_destroy( &li->li_giant_rwlock ); + ldap_pvt_thread_mutex_destroy( &li->li_cache.c_mutex ); + ldap_pvt_thread_mutex_destroy( &li->li_dbcache_mutex ); + ldap_pvt_thread_cond_destroy( &li->li_dbcache_cv ); + + free( be->be_private ); + be->be_private = NULL; + + return 0; } diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 3fa6c61a92cc317e3294b906f70ecaeac9c10002..2dfb9be680593217a56ba282277498279f4fd17e 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -1,216 +1,380 @@ /* modify.c - ldbm backend modify routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -#include "back-ldbm.h" -extern int global_schemacheck; -extern Entry *dn2entry(); -extern Attribute *attr_find(); +#include <ac/string.h> +#include <ac/socket.h> +#include <ac/time.h> -static int add_values(); -static int delete_values(); -static int replace_values(); +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" -int -ldbm_back_modify( +/* We need this function because of LDAP modrdn. If we do not + * add this there would be a bunch of code replication here + * and there and of course the likelihood of bugs increases. + * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99 + */ +int ldbm_modify_internal( Backend *be, Connection *conn, Operation *op, - char *dn, - LDAPMod *mods + const char *dn, + Modifications *modlist, + Entry *e, + const char **text, + char *textbuf, + size_t textlen ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = NULL; - Entry *e; - int i, err, modtype; - LDAPMod *mod; + int rc = LDAP_SUCCESS; + Modification *mod; + Modifications *ml; + Attribute *save_attrs; + Attribute *ap; - if ( (e = dn2entry( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, - NULL ); - if ( matched != NULL ) { - free( matched ); - } - return( -1 ); - } - /* lock entry */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_modify_internal: %s\n", dn )); +#else + Debug(LDAP_DEBUG_TRACE, "ldbm_modify_internal: %s\n", dn, 0, 0); +#endif - if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) { - send_ldap_result( conn, op, err, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + + if ( !acl_check_modlist( be, conn, op, e, modlist )) { + return LDAP_INSUFFICIENT_ACCESS; } - for ( mod = mods; mod != NULL; mod = mod->mod_next ) { - switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) { + save_attrs = e->e_attrs; + e->e_attrs = attrs_dup( e->e_attrs ); + + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + mod = &ml->sml_mod; + + switch ( mod->sm_op ) { case LDAP_MOD_ADD: - err = add_values( e, mod, op->o_dn ); +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_modify_internal: add\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: add\n", 0, 0, 0); +#endif + + rc = modify_add_values( e, mod, text, textbuf, textlen ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_modify_internal: failed %d (%s)\n", + rc, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", + rc, *text, 0); +#endif + } break; case LDAP_MOD_DELETE: - err = delete_values( e, mod, op->o_dn ); +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_modify_internal: delete\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: delete\n", 0, 0, 0); +#endif + + rc = modify_delete_values( e, mod, text, textbuf, textlen ); + assert( rc != LDAP_TYPE_OR_VALUE_EXISTS ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_modify_internal: failed %d (%s)\n", rc, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", + rc, *text, 0); +#endif + } break; case LDAP_MOD_REPLACE: - err = replace_values( e, mod, op->o_dn ); +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_modify_internal: replace\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: replace\n", 0, 0, 0); +#endif + + rc = modify_replace_values( e, mod, text, textbuf, textlen ); + assert( rc != LDAP_TYPE_OR_VALUE_EXISTS ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_modify_internal: failed %d (%s)\n", rc, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", + rc, *text, 0); +#endif + } break; + + case SLAP_MOD_SOFTADD: +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_modify_internal: softadd\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: softadd\n", 0, 0, 0); +#endif + + /* Avoid problems in index_add_mods() + * We need to add index if necessary. + */ + mod->sm_op = LDAP_MOD_ADD; + + rc = modify_add_values( e, mod, text, textbuf, textlen ); + if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + rc = LDAP_SUCCESS; + } + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_modify_internal: failed %d (%s)\n", rc, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", + rc, *text, 0); +#endif + } + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_modify_internal: invalid op %d\n", mod->sm_op )); +#else + Debug(LDAP_DEBUG_ANY, "ldbm_modify_internal: invalid op %d\n", + mod->sm_op, 0, 0); +#endif + + rc = LDAP_OTHER; + *text = "Invalid modify operation"; +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_modify_internal: %d (%s)\n", rc, *text )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", + rc, *text, 0); +#endif } - if ( err != LDAP_SUCCESS ) { - /* unlock entry, delete from cache */ - send_ldap_result( conn, op, err, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + if ( rc != LDAP_SUCCESS ) { + goto exit; } - } - /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); - if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + /* If objectClass was modified, reset the flags */ + if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { + e->e_ocflags = 0; + } + + /* check if modified attribute was indexed */ + rc = index_is_indexed( be, mod->sm_desc ); + if ( rc == LDAP_SUCCESS ) { + ap = attr_find( save_attrs, mod->sm_desc ); + if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL; + + ap = attr_find( e->e_attrs, mod->sm_desc ); + if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD; + } } - pthread_mutex_unlock( &op->o_abandonmutex ); /* check that the entry still obeys the schema */ - if ( global_schemacheck && oc_schema_check( e ) != 0 ) { - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, - NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); - } + rc = entry_schema_check( be, e, save_attrs, text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_modify_internal: entry failed schema check: %s\n", + *text )); +#else + Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", + *text, 0, 0 ); +#endif - /* modify indexes */ - if ( index_add_mods( be, mods, e->e_id ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + goto exit; } /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); - } - pthread_mutex_unlock( &op->o_abandonmutex ); - - /* change the entry itself */ - if ( id2entry_add( be, e ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + rc = SLAPD_ABANDON; + goto exit; } - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); + /* update the indices of the modified attributes */ - return( 0 ); -} + /* start with deleting the old index entries */ + for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { + if ( ap->a_flags & SLAP_ATTR_IXDEL ) { + rc = index_values( be, ap->a_desc, ap->a_vals, e->e_id, + SLAP_INDEX_DELETE_OP ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_modify_internal: Attribute index delete failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "Attribute index delete failure", + 0, 0, 0 ); +#endif + goto exit; + } + ap->a_flags &= ~SLAP_ATTR_IXDEL; + } + } -static int -add_values( - Entry *e, - LDAPMod *mod, - char *dn -) -{ - int i; - Attribute *a; - - /* check if the values we're adding already exist */ - if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) { - for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) { - if ( value_find( a->a_vals, mod->mod_bvalues[i], - a->a_syntax, 3 ) == 0 ) { - return( LDAP_TYPE_OR_VALUE_EXISTS ); + /* add the new index entries */ + for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { + if ( ap->a_flags & SLAP_ATTR_IXADD ) { + rc = index_values( be, ap->a_desc, ap->a_vals, e->e_id, + SLAP_INDEX_ADD_OP ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_modify_internal: Attribute index add failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "Attribute index add failure", + 0, 0, 0 ); +#endif + goto exit; } + ap->a_flags &= ~SLAP_ATTR_IXADD; } } - /* no - add them */ - if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) { - return( LDAP_CONSTRAINT_VIOLATION ); +exit: + if ( rc == LDAP_SUCCESS ) { + attrs_free( save_attrs ); + } else { + for ( ap = save_attrs; ap; ap = ap->a_next ) { + ap->a_flags = 0; + } + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; } - return( LDAP_SUCCESS ); + return rc; } -static int -delete_values( - Entry *e, - LDAPMod *mod, - char *dn +int +ldbm_back_modify( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + Modifications *modlist ) { - int i, j, k, found; - Attribute *a; - - /* delete the entire attribute */ - if ( mod->mod_bvalues == NULL ) { - Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n", - mod->mod_type, 0, 0 ); - return( attr_delete( &e->e_attrs, mod->mod_type ) ? - LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS ); - } + int rc; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *matched; + Entry *e; + int manageDSAit = get_manageDSAit( op ); + const char *text = NULL; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; - /* delete specific values - find the attribute first */ - if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) { - Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n", - mod->mod_type, 0, 0 ); - return( LDAP_NO_SUCH_ATTRIBUTE ); - } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_back_modify: enter\n" )); +#else + Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0); +#endif - /* find each value to delete */ - for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) { - found = 0; - for ( j = 0; a->a_vals[j] != NULL; j++ ) { - if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j], - a->a_syntax, 3 ) != 0 ) { - continue; - } - found = 1; + /* grab giant lock for writing */ + ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock); - /* found a matching value - delete it */ - ber_bvfree( a->a_vals[j] ); - for ( k = j + 1; a->a_vals[k] != NULL; k++ ) { - a->a_vals[k - 1] = a->a_vals[k]; - } - a->a_vals[k - 1] = NULL; - break; - } + /* acquire and lock entry */ + if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) { + char* matched_dn = NULL; + BerVarray refs; - /* looked through them all w/o finding it */ - if ( ! found ) { - Debug( LDAP_DEBUG_ARGS, - "could not find value for attr %s\n", - mod->mod_type, 0, 0 ); - return( LDAP_NO_SUCH_ATTRIBUTE ); + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } + + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( refs ) ber_bvarray_free( refs ); + free( matched_dn ); + + return( -1 ); } - return( LDAP_SUCCESS ); -} + if ( !manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); -static int -replace_values( - Entry *e, - LDAPMod *mod, - char *dn -) -{ - (void) attr_delete( &e->e_attrs, mod->mod_type ); +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modify: entry (%s) is referral\n", ndn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); +#endif + + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); - if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) { - return( LDAP_CONSTRAINT_VIOLATION ); + if ( refs ) ber_bvarray_free( refs ); + + goto error_return; + } + + /* Modify the entry */ + rc = ldbm_modify_internal( be, conn, op, ndn->bv_val, modlist, e, + &text, textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { + if( rc != SLAPD_ABANDON ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + } + + goto error_return; + } + + /* change the entry itself */ + if ( id2entry_add( be, e ) != 0 ) { + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "id2entry failure", NULL, NULL ); + goto error_return; } - return( LDAP_SUCCESS ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + + cache_return_entry_w( &li->li_cache, e ); + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + return( 0 ); + +error_return:; + cache_return_entry_w( &li->li_cache, e ); + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + return( -1 ); } diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index fcd9fcc35a6f6c14ca2444386ed6f2eb48d093fb..59aee6894c5d6a2318369dc978ef29c46b4a4701 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -1,132 +1,812 @@ /* modrdn.c - ldbm backend modrdn routine */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * LDAP v3 newSuperior support. Add new rdn as an attribute. + * (Full support for v2 also used software/ideas contributed + * by Roy Hooper rhooper@cyberus.ca, thanks to him for his + * submission!.) + * + * 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 <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" #include "back-ldbm.h" - -extern Entry *dn2entry(); -extern char *dn_parent(); +#include "proto-back-ldbm.h" int ldbm_back_modrdn( Backend *be, Connection *conn, Operation *op, - char *dn, - char *newrdn, - int deleteoldrdn + struct berval *dn, + struct berval *ndn, + struct berval *newrdn, + struct berval *nnewrdn, + int deleteoldrdn, + struct berval *newSuperior, + struct berval *nnewSuperior ) { + AttributeDescription *children = slap_schema.si_ad_children; struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; - char *pdn, *newdn, *p; - char sep[2]; - Entry *e, *e2; - - matched = NULL; - if ( (e = dn2entry( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); - if ( matched != NULL ) { - free( matched ); + struct berval p_dn, p_ndn; + struct berval new_dn = { 0, NULL}, new_ndn = { 0, NULL }; + Entry *e, *p = NULL; + Entry *matched; + int isroot = -1; +#define CAN_ROLLBACK -1 +#define MUST_DESTROY 1 + int rc = CAN_ROLLBACK; + int rc_id = 0; + ID id = NOID; + const char *text = NULL; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + /* Added to support LDAP v2 correctly (deleteoldrdn thing) */ + LDAPRDN *new_rdn = NULL; + LDAPRDN *old_rdn = NULL; + int a_cnt, d_cnt; + /* Added to support newSuperior */ + Entry *np = NULL; /* newSuperior Entry */ + struct berval *np_ndn = NULL; /* newSuperior ndn */ + struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ + /* Used to interface with ldbm_modify_internal() */ + Modifications *mod = NULL; /* Used to delete old/add new rdn */ + int manageDSAit = get_manageDSAit( op ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_back_modrdn: dn: %s newSuperior=%s\n", + dn->bv_len ? dn->bv_val : "NULL", + ( newSuperior && newSuperior->bv_len ) + ? newSuperior->bv_val : "NULL" )); +#else + Debug( LDAP_DEBUG_TRACE, + "==>ldbm_back_modrdn: dn: %s newSuperior=%s\n", + dn->bv_len ? dn->bv_val : "NULL", + ( newSuperior && newSuperior->bv_len ) + ? newSuperior->bv_val : "NULL", 0 ); +#endif + + /* grab giant lock for writing */ + ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock); + + /* get entry with writer lock */ + if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) { + char* matched_dn = NULL; + BerVarray refs; + + if( matched != NULL ) { + matched_dn = strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } + + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( refs ) ber_bvarray_free( refs ); + free( matched_dn ); + return( -1 ); } - if ( (pdn = dn_parent( be, dn )) != NULL ) { - /* parent + rdn + separator(s) + null */ - newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn ) - + 3 ); - if ( dn_type( dn ) == DN_X500 ) { - strcpy( newdn, newrdn ); - strcat( newdn, ", " ); - strcat( newdn, pdn ); + if (!manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + BerVarray refs = get_entry_referrals( be, + conn, op, e ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "entry %s is referral\n", e->e_dn, + 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + if ( refs ) ber_bvarray_free( refs ); + goto return_results; + } + + if ( has_children( be, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: entry %s has children\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "entry %s has children\n", e->e_dn, + 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, + NULL, "subtree rename not supported", NULL, NULL ); + goto return_results; + } + + if ( be_issuffix( be, &e->e_nname ) ) { + p_ndn = slap_empty_bv ; + } else { + dnParent( &e->e_nname, &p_ndn ); + } + + if ( p_ndn.bv_len != 0 ) { + /* Make sure parent entry exist and we can write its + * children. + */ + + if( (p = dn2entry_w( be, &p_ndn, NULL )) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn )); +#else + Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", + 0, 0, 0); +#endif + + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "parent entry does not exist", NULL, NULL ); + + goto return_results; + } + + /* check parent for "children" acl */ + if ( ! access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: no access to parent of (%s)\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, + 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: wr to children of entry %s OK\n", + p_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: wr to children of entry %s OK\n", + p_ndn.bv_val, 0, 0 ); +#endif + + if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { + p_dn = slap_empty_bv; } else { - strcpy( newdn, newrdn ); - p = strchr( newrdn, '\0' ); - p--; - if ( *p != '.' && *p != '@' ) { - if ( (p = strpbrk( dn, ".@" )) != NULL ) { - sep[0] = *p; - sep[1] = '\0'; - strcat( newdn, sep ); + dnParent( &e->e_name, &p_dn ); + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: parent dn=%s\n", p_dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n", + p_dn.bv_val, 0, 0 ); +#endif + + } else { + /* no parent, must be root to modify rdn */ + isroot = be_isroot( be, &op->o_ndn ); + if ( ! isroot ) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) || be_isupdate( be, &op->o_ndn ) ) { + p = (Entry *)&slap_entry_root; + + rc = access_allowed( be, conn, op, p, + children, NULL, ACL_WRITE, NULL ); + p = NULL; + + /* check parent for "children" acl */ + if ( ! rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_back_modrdn: no access " + "to parent \"\"\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- ldbm_back_modrdn: no " + "access to parent\n", 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; } + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_back_modrdn: (%s) has no " + "parent & not a root.\n", dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- ldbm_back_modrdn: no parent & " + "not root\n", 0, 0, 0); +#endif + + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; } - strcat( newdn, pdn ); } - } else { - newdn = strdup( newrdn ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: no parent, locked root\n", + 0, 0, 0 ); +#endif } - (void) dn_normalize( newdn ); - matched = NULL; - if ( (e2 = dn2entry( be, newdn, &matched )) != NULL ) { - free( newdn ); - free( pdn ); - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL ); - cache_return_entry( &li->li_cache, e2 ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ + + if ( newSuperior != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: new parent \"%s\" requested\n", + newSuperior->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: new parent \"%s\" requested...\n", + newSuperior->bv_val, 0, 0 ); +#endif + + np_ndn = nnewSuperior; + + /* newSuperior == oldParent? */ + if ( dn_match( &p_ndn, np_ndn ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, "ldbm_back_modrdn: " + "new parent\"%s\" seems to be the same as the " + "old parent \"%s\"\n", + newSuperior->bv_val, p_dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: " + "new parent\"%s\" seems to be the same as the " + "old parent \"%s\"\n", + newSuperior->bv_val, p_dn.bv_val, 0 ); +#endif + + newSuperior = NULL; /* ignore newSuperior */ + } } - if ( matched != NULL ) { - free( matched ); + + if ( newSuperior != NULL ) { + /* newSuperior == entry being moved?, if so ==> ERROR */ + /* Get Entry with dn=newSuperior. Does newSuperior exist? */ + + if ( nnewSuperior->bv_len ) { + if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", np_ndn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: newSup(ndn=%s) not here!\n", + np_ndn->bv_val, 0, 0); +#endif + + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "newSuperior not found", NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n", + np, np->e_id )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n", + np, np->e_id, 0 ); +#endif + + /* check newSuperior for "children" acl */ + if ( !access_allowed( be, conn, op, np, children, NULL, + ACL_WRITE, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: no wr to newSup children.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: no wr to newSup children\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + + if ( is_entry_alias( np ) ) { + /* parent is an alias, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 ); +#endif + + + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, "newSuperior is an alias", NULL, NULL ); + + goto return_results; + } + + if ( is_entry_referral( np ) ) { + /* parent is a referral, don't allow add */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: entry (%s) is a referral\n", + np->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n", + np->e_dn, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "newSuperior is a referral", NULL, NULL ); + + goto return_results; + } + + } else { + + /* no parent, must be root to modify newSuperior */ + if ( isroot == -1 ) { + isroot = be_isroot( be, &op->o_ndn ); + } + + if ( ! isroot ) { + if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) || be_isupdate( be, &op->o_ndn ) ) { + np = (Entry *)&slap_entry_root; + + rc = access_allowed( be, conn, op, np, + children, NULL, ACL_WRITE, NULL ); + np = NULL; + + /* check parent for "children" acl */ + if ( ! rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_back_modrdn: no access " + "to new superior \"\"\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- ldbm_back_modrdn: no " + "access to new superior\n", 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "ldbm_back_modrdn: \"\" " + "not allowed as new superior\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "<=- ldbm_back_modrdn: \"\" " + "not allowed as new superior\n", + 0, 0, 0); +#endif + + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + } + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: wr to new parent's children OK.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: wr to new parent's children OK\n", + 0, 0, 0 ); +#endif + + new_parent_dn = newSuperior; } + + /* Build target dn and make sure target entry doesn't exist already. */ + build_new_dn( &new_dn, new_parent_dn, newrdn ); + dnNormalize2( NULL, &new_dn, &new_ndn ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: new ndn=%s\n", new_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n", + new_ndn.bv_val, 0, 0 ); +#endif /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); - free( newdn ); - free( pdn ); - cache_return_entry( &li->li_cache, e2 ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + goto return_results; } - pthread_mutex_unlock( &op->o_abandonmutex ); - /* add new one */ - if ( dn2id_add( be, newdn, e->e_id ) != 0 ) { - free( newdn ); - free( pdn ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + if ( ( rc_id = dn2id ( be, &new_ndn, &id ) ) || id != NOID ) { + /* if (rc_id) something bad happened to ldbm cache */ + send_ldap_result( conn, op, + rc_id ? LDAP_OPERATIONS_ERROR : LDAP_ALREADY_EXISTS, + NULL, NULL, NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: new ndn (%s) does not exist\n", new_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: new ndn=%s does not exist\n", + new_ndn.bv_val, 0, 0 ); +#endif + + + /* Get attribute types and values of our new rdn, we will + * need to add that to our new entry + */ + if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: can't figure out type(s)/value(s) of newrdn\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out type(s)/value(s) of newrdn\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "unable to parse type(s)/value(s) used in RDN", NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", + new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", + new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val, 0 ); +#endif + + /* Retrieve the old rdn from the entry's dn */ + if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: can't figure out the old_rdn type(s)/value(s).\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out the old_rdn type(s)/value(s)\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "unable to parse type(s)/value(s) used in RDN from old DN", NULL, NULL ); + goto return_results; + } + +#if 0 + if ( newSuperior == NULL + && charray_strcasecmp( (const char **)old_rdn_types, (const char **)new_rdn_types ) != 0 ) + { + /* Not a big deal but we may say something */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: old_rdn_type=%s new_rdn_type=%s\n", + old_rdn_types[0], new_rdn_types[0] )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n", + old_rdn_types[0], new_rdn_types[0], 0 ); +#endif + } +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: DN_X500\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n", + 0, 0, 0 ); +#endif + + mod = NULL; + for ( a_cnt = 0; new_rdn[0][a_cnt]; a_cnt++ ) { + int rc; + AttributeDescription *desc = NULL; + Modifications *mod_tmp; + + rc = slap_bv2ad( &new_rdn[0][a_cnt]->la_attr, &desc, &text ); + + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: slap_bv2ad error: %s (%s)\n", + text, new_rdn[0][a_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: %s: %s (new)\n", + text, new_rdn[0][a_cnt]->la_attr.bv_val, 0 ); +#endif + + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + goto return_results; + } + + if ( ! access_allowed( be, conn, op, e, + desc, &new_rdn[0][a_cnt]->la_value, ACL_WRITE, NULL ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: access " + "not allowed to attr \"%s\"\n", + new_rdn[0][a_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: access not allowed " + "to attr \"%s\"\n%s%s", + new_rdn[0][a_cnt]->la_attr.bv_val, "", "" ); +#endif + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + + goto return_results; + } + + mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) + + 2 * sizeof( struct berval ) ); + mod_tmp->sml_desc = desc; + mod_tmp->sml_bvalues = (BerVarray)( mod_tmp + 1 ); + mod_tmp->sml_bvalues[0] = new_rdn[0][a_cnt]->la_value; + mod_tmp->sml_bvalues[1].bv_val = NULL; + mod_tmp->sml_op = SLAP_MOD_SOFTADD; + mod_tmp->sml_next = mod; + mod = mod_tmp; + } + + /* Remove old rdn value if required */ + if ( deleteoldrdn ) { + /* Get value of old rdn */ + if ( old_rdn == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: can't figure out old RDN value(s) from old RDN\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out oldRDN value(s) from old RDN\n", + 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "could not parse value(s) from old RDN", NULL, NULL ); + goto return_results; + } + + for ( d_cnt = 0; old_rdn[0][d_cnt]; d_cnt++ ) { + int rc; + AttributeDescription *desc = NULL; + Modifications *mod_tmp; + + rc = slap_bv2ad( &old_rdn[0][d_cnt]->la_attr, &desc, &text ); + + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: %s: %s (old)\n", + text, old_rdn[0][d_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: %s: %s (old)\n", + text, old_rdn[0][d_cnt]->la_attr.bv_val, 0 ); +#endif + + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + + goto return_results; + } + + if ( ! access_allowed( be, conn, op, e, + desc, &old_rdn[0][d_cnt]->la_value, ACL_WRITE, NULL ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_back_modrdn: access " + "not allowed to attr \"%s\"\n", + old_rdn[0][d_cnt]->la_attr.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: access not allowed " + "to attr \"%s\"\n%s%s", + old_rdn[0][d_cnt]->la_attr.bv_val, "", "" ); +#endif + send_ldap_result( conn, op, + LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + + goto return_results; + } + + /* Remove old value of rdn as an attribute. */ + mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) + + 2 * sizeof( struct berval ) ); + mod_tmp->sml_desc = desc; + mod_tmp->sml_bvalues = (BerVarray)(mod_tmp+1); + mod_tmp->sml_bvalues[0] = old_rdn[0][d_cnt]->la_value; + mod_tmp->sml_bvalues[1].bv_val = NULL; + mod_tmp->sml_op = LDAP_MOD_DELETE; + mod_tmp->sml_next = mod; + mod = mod_tmp; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_modrdn: removing old_rdn_val=%s\n", old_rdn[0][d_cnt]->la_value.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: removing old_rdn_val=%s\n", + old_rdn[0][d_cnt]->la_value.bv_val, 0, 0 ); +#endif + } + } + + + /* check for abandon */ + if ( op->o_abandon ) { + goto return_results; } /* delete old one */ - if ( dn2id_delete( be, dn ) != 0 ) { - free( newdn ); - free( pdn ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - cache_return_entry( &li->li_cache, e ); - return( -1 ); + if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) { + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "DN index delete fail", NULL, NULL ); + goto return_results; } (void) cache_delete_entry( &li->li_cache, e ); + rc = MUST_DESTROY; + + /* XXX: there is no going back! */ + free( e->e_dn ); - e->e_dn = newdn; - - /* XXX - * At some point here we need to update the attribute values in - * the entry itself that were effected by this RDN change - * (respecting the value of the deleteoldrdn parameter). - * - * Since the code to do this has not yet been written, treat this - * omission as a (documented) bug. + free( e->e_ndn ); + e->e_name = new_dn; + e->e_nname = new_ndn; + new_dn.bv_val = NULL; + new_ndn.bv_val = NULL; + + /* add new one */ + if ( dn2id_add( be, &e->e_nname, e->e_id ) != 0 ) { + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "DN index add failed", NULL, NULL ); + goto return_results; + } + + /* modify memory copy of entry */ + rc = ldbm_modify_internal( be, conn, op, dn->bv_val, &mod[0], e, + &text, textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { + if( rc != SLAPD_ABANDON ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + } + + /* here we may try to delete the newly added dn */ + if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) { + /* we already are in trouble ... */ + ; + } + + goto return_results; + } + + (void) cache_update_entry( &li->li_cache, e ); + + /* NOTE: after this you must not free new_dn or new_ndn! + * They are used by cache. */ /* id2entry index */ if ( id2entry_add( be, e ) != 0 ) { - entry_free( e ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "entry update failed", NULL, NULL ); + goto return_results; + } - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); - return( -1 ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + rc = 0; + cache_entry_commit( e ); + +return_results: + if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); + if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); + + /* LDAP v2 supporting correct attribute handling. */ + if( new_rdn ) ldap_rdnfree( new_rdn ); + if( old_rdn ) ldap_rdnfree( old_rdn ); + + if ( mod != NULL ) { + Modifications *tmp; + for (; mod; mod = tmp ) { + tmp = mod->sml_next; + free( mod ); + } + } + + /* LDAP v3 Support */ + if( np != NULL ) { + /* free new parent and writer lock */ + cache_return_entry_w( &li->li_cache, np ); } - free( pdn ); - cache_return_entry( &li->li_cache, e ); - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); - return( 0 ); + if( p != NULL ) { + /* free parent and writer lock */ + cache_return_entry_w( &li->li_cache, p ); + } + + /* free entry and writer lock */ + cache_return_entry_w( &li->li_cache, e ); + if ( rc == MUST_DESTROY ) { + /* if rc == MUST_DESTROY the entry is uncached + * and its private data is destroyed; + * the entry must be freed */ + entry_free( e ); + } + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + return( rc ); } diff --git a/servers/slapd/back-ldbm/passwd.c b/servers/slapd/back-ldbm/passwd.c new file mode 100644 index 0000000000000000000000000000000000000000..ae0f245858baf04814381e36a3d84261622085b1 --- /dev/null +++ b/servers/slapd/back-ldbm/passwd.c @@ -0,0 +1,192 @@ +/* passwd.c - ldbm backend password routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" + +int +ldbm_back_exop_passwd( + Backend *be, + Connection *conn, + Operation *op, + const char *reqoid, + struct berval *reqdata, + char **rspoid, + struct berval **rspdata, + LDAPControl *** rspctrls, + const char **text, + BerVarray *refs +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + int rc; + Entry *e = NULL; + struct berval hash = { 0, NULL }; + + struct berval id = { 0, NULL }; + struct berval new = { 0, NULL }; + + struct berval dn; + struct berval ndn; + + assert( reqoid != NULL ); + assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 ); + + rc = slap_passwd_parse( reqdata, + &id, NULL, &new, text ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_back_exop_passwd: \"%s\"\n", + id.bv_val ? id.bv_val : "" )); +#else + Debug( LDAP_DEBUG_ARGS, "==> ldbm_back_exop_passwd: \"%s\"\n", + id.bv_val ? id.bv_val : "", 0, 0 ); +#endif + + + if( rc != LDAP_SUCCESS ) { + goto done; + } + + if( new.bv_len == 0 ) { + slap_passwd_generate(&new); + + if( new.bv_len == 0 ) { + *text = "password generation failed."; + rc = LDAP_OTHER; + goto done; + } + + *rspdata = slap_passwd_return( &new ); + } + + slap_passwd_hash( &new, &hash ); + + if( hash.bv_len == 0 ) { + *text = "password hash failed"; + rc = LDAP_OTHER; + goto done; + } + + if( id.bv_len ) { + dn = id; + } else { + dn = op->o_dn; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_back_exop_passwd: \"%s\"%s\n", + dn.bv_val, id.bv_len ? " (proxy)" : "" )); +#else + Debug( LDAP_DEBUG_TRACE, "passwd: \"%s\"%s\n", + dn.bv_val, id.bv_len ? " (proxy)" : "", 0 ); +#endif + + if( dn.bv_len == 0 ) { + *text = "No password is associated with the Root DSE"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = dnNormalize2( NULL, &dn, &ndn ); + if( rc != LDAP_SUCCESS ) { + *text = "Invalid DN"; + goto done; + } + + /* grab giant lock for writing */ + ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock); + + e = dn2entry_w( be, &ndn, NULL ); + if( e == NULL ) { + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + *text = "could not locate authorization entry"; + rc = LDAP_NO_SUCH_OBJECT; + goto done; + } + + if( is_entry_alias( e ) ) { + /* entry is an alias, don't allow operation */ + *text = "authorization entry is alias"; + rc = LDAP_ALIAS_PROBLEM; + goto done; + } + + rc = LDAP_OPERATIONS_ERROR; + + if( is_entry_referral( e ) ) { + /* entry is an referral, don't allow operation */ + *text = "authorization entry is referral"; + goto done; + } + + { + Modifications ml; + struct berval vals[2]; + char textbuf[SLAP_TEXT_BUFLEN]; /* non-returnable */ + + vals[0] = hash; + vals[1].bv_val = NULL; + + ml.sml_desc = slap_schema.si_ad_userPassword; + ml.sml_bvalues = vals; + ml.sml_op = LDAP_MOD_REPLACE; + ml.sml_next = NULL; + + rc = ldbm_modify_internal( be, + conn, op, op->o_ndn.bv_val, &ml, e, text, textbuf, + sizeof( textbuf ) ); + + /* FIXME: ldbm_modify_internal may set *text = textbuf, + * which is BAD */ + if ( *text == textbuf ) { + *text = NULL; + } + + if( rc ) { + /* cannot return textbuf */ + *text = "entry modify failed"; + goto done; + } + + /* change the entry itself */ + if( id2entry_add( be, e ) != 0 ) { + *text = "entry update failed"; + rc = LDAP_OTHER; + } + + if( rc == LDAP_SUCCESS ) { + replog( be, op, &e->e_name, &e->e_nname, &ml ); + } + } + +done: + if( e != NULL ) { + cache_return_entry_w( &li->li_cache, e ); + ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock); + } + + if( hash.bv_val != NULL ) { + free( hash.bv_val ); + } + + if( ndn.bv_val != NULL ) { + free( ndn.bv_val ); + } + + return rc; +} diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 6a53be4f112485ab38b91886aafa8f2f438d941c..a82ffe7f90ba8fa805985bee8c543d56a13b9e40 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -1,414 +1,604 @@ /* search.c - ldbm backend search function */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" #include "back-ldbm.h" +#include "proto-back-ldbm.h" + +static ID_BLOCK *base_candidate( + Backend *be, Entry *e ); + +static ID_BLOCK *search_candidates( + Backend *be, Entry *e, Filter *filter, + int scope, int deref, int manageDSAit ); -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; - -extern ID dn2id(); -extern IDList *idl_alloc(); -extern Entry *id2entry(); -extern Entry *dn2entry(); -extern Attribute *attr_find(); -extern IDList *filter_candidates(); -extern char *ch_realloc(); -extern char *dn_parent(); - -static IDList *base_candidates(); -static IDList *onelevel_candidates(); -static IDList *subtree_candidates(); - -#define GRABSIZE BUFSIZ - -#define MAKE_SPACE( n ) { \ - if ( rcur + n > rbuf + rmaxsize ) { \ - int offset = rcur - rbuf; \ - rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \ - rmaxsize += GRABSIZE; \ - rcur = rbuf + offset; \ - } \ -} int ldbm_back_search( Backend *be, Connection *conn, Operation *op, - char *base, + struct berval *base, + struct berval *nbase, int scope, int deref, int slimit, int tlimit, Filter *filter, - char *filterstr, - char **attrs, - int attrsonly -) + struct berval *filterstr, + AttributeName *attrs, + int attrsonly ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int err; + int rc, err; + const char *text = NULL; time_t stoptime; - IDList *candidates; - ID id; + ID_BLOCK *candidates; + ID id, cursor; Entry *e; - Attribute *ref; - char *matched = NULL; - int rmaxsize, nrefs; - char *rbuf, *rcur, *r; + BerVarray v2refs = NULL; + Entry *matched = NULL; + struct berval realbase = { 0, NULL }; int nentries = 0; + int manageDSAit = get_manageDSAit( op ); + int cscope = LDAP_SCOPE_DEFAULT; + + struct slap_limits_set *limit = NULL; + int isroot = 0; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "ldbm_back_search: enter\n" )); +#else + Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0); +#endif + + /* grab giant lock for reading */ + ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock); + + if ( nbase->bv_len == 0 ) { + /* DIT root special case */ + e = (Entry *) &slap_entry_root; + + /* need normalized dn below */ + ber_dupbv( &realbase, &e->e_nname ); + + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); + + goto searchit; + + } else if ( deref & LDAP_DEREF_FINDING ) { + /* deref dn and get entry with reader lock */ + e = deref_dn_r( be, nbase, &err, &matched, &text ); + + if( err == LDAP_NO_SUCH_OBJECT ) err = LDAP_REFERRAL; - if ( tlimit == 0 && be_isroot( be, op->o_dn ) ) { - tlimit = -1; /* allow root to set no limit */ } else { - tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? - be->be_timelimit : tlimit; - stoptime = op->o_time + tlimit; + /* get entry with reader lock */ + e = dn2entry_r( be, nbase, &matched ); + err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL; + text = NULL; } - if ( slimit == 0 && be_isroot( be, op->o_dn ) ) { - slimit = -1; /* allow root to set no limit */ - } else { - slimit = (slimit > be->be_sizelimit || slimit < 1) ? - be->be_sizelimit : slimit; + + if ( e == NULL ) { + struct berval matched_dn = { 0, NULL }; + BerVarray refs = NULL; + + if ( matched != NULL ) { + BerVarray erefs; + ber_dupbv( &matched_dn, &matched->e_name ); + + erefs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + + cache_return_entry_r( &li->li_cache, matched ); + + if( erefs ) { + refs = referral_rewrite( erefs, &matched_dn, + base, scope ); + + ber_bvarray_free( erefs ); + } + + } else { + refs = referral_rewrite( default_referral, + NULL, base, scope ); + } + + ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock); + + send_ldap_result( conn, op, err, matched_dn.bv_val, + text, refs, NULL ); + + ber_bvarray_free( refs ); + ber_memfree( matched_dn.bv_val ); + return 1; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval matched_dn; + BerVarray erefs; + BerVarray refs; + + ber_dupbv( &matched_dn, &e->e_name ); + erefs = get_entry_referrals( be, conn, op, e ); + refs = NULL; + + cache_return_entry_r( &li->li_cache, e ); + ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_search: entry (%s) is a referral.\n", + e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: entry is referral\n", + 0, 0, 0 ); +#endif + + if( erefs ) { + refs = referral_rewrite( erefs, &matched_dn, + base, scope ); + + ber_bvarray_free( erefs ); + } + + if( refs ) { + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn.bv_val, NULL, refs, NULL ); + ber_bvarray_free( refs ); + + } else { + send_ldap_result( conn, op, LDAP_OTHER, + matched_dn.bv_val, + "bad referral object", NULL, NULL ); + } + + ber_memfree( matched_dn.bv_val ); + return 1; } - switch ( scope ) { - case LDAP_SCOPE_BASE: - candidates = base_candidates( be, conn, op, base, filter, - attrs, attrsonly, &matched, &err ); - break; - - case LDAP_SCOPE_ONELEVEL: - candidates = onelevel_candidates( be, conn, op, base, filter, - attrs, attrsonly, &matched, &err ); - break; - - case LDAP_SCOPE_SUBTREE: - candidates = subtree_candidates( be, conn, op, base, filter, - attrs, attrsonly, &matched, NULL, &err, 1 ); - break; - - default: - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "", - "Bad scope" ); - return( -1 ); + if ( is_entry_alias( e ) ) { + /* don't deref */ + deref = LDAP_DEREF_NEVER; } - /* null candidates means we could not find the base object */ + if ( scope == LDAP_SCOPE_BASE ) { + cscope = LDAP_SCOPE_BASE; + candidates = base_candidate( be, e ); + + } else { + cscope = ( scope != LDAP_SCOPE_SUBTREE ) + ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE; + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); + } + + /* need normalized dn below */ + ber_dupbv( &realbase, &e->e_nname ); + + cache_return_entry_r( &li->li_cache, e ); + +searchit: if ( candidates == NULL ) { - send_ldap_result( conn, op, err, matched, "" ); - if ( matched != NULL ) { - free( matched ); + /* no candidates */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_search: no candidates\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm_search: no candidates\n", + 0, 0, 0 ); +#endif + + send_search_result( conn, op, + LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 0 ); + + rc = 1; + goto done; + } + + /* if not root, get appropriate limits */ + if ( be_isroot( be, &op->o_ndn ) ) { + isroot = 1; + } else { + ( void ) get_limits( be, &op->o_ndn, &limit ); + } + + /* if candidates exceed to-be-checked entries, abort */ + if ( !isroot && limit->lms_s_unchecked != -1 ) { + if ( ID_BLOCK_NIDS( candidates ) > (unsigned) limit->lms_s_unchecked ) { + send_search_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto done; + } + } + + /* if root an no specific limit is required, allow unlimited search */ + if ( isroot ) { + if ( tlimit == 0 ) { + tlimit = -1; + } + + if ( slimit == 0 ) { + slimit = -1; + } + + } else { + /* if no limit is required, use soft limit */ + if ( tlimit <= 0 ) { + tlimit = limit->lms_t_soft; + + /* if requested limit higher than hard limit, abort */ + } else if ( tlimit > limit->lms_t_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_t_hard == 0 ) { + tlimit = limit->lms_t_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_t_hard > 0 ) { + send_search_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto done; + } + + /* negative hard limit means no limit */ + } + + /* if no limit is required, use soft limit */ + if ( slimit <= 0 ) { + slimit = limit->lms_s_soft; + + /* if requested limit higher than hard limit, abort */ + } else if ( slimit > limit->lms_s_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_s_hard == 0 ) { + slimit = limit->lms_s_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_s_hard > 0 ) { + send_search_result( conn, op, + LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto done; + } + + /* negative hard limit means no limit */ } - return( -1 ); } - rmaxsize = 0; - nrefs = 0; - rbuf = rcur = NULL; - MAKE_SPACE( sizeof("Referral:") + 1 ); - strcpy( rbuf, "Referral:" ); - rcur = strchr( rbuf, '\0' ); - for ( id = idl_firstid( candidates ); id != NOID; - id = idl_nextid( candidates, id ) ) { + /* compute it anyway; root does not use it */ + stoptime = op->o_time + tlimit; + + for ( id = idl_firstid( candidates, &cursor ); id != NOID; + id = idl_nextid( candidates, &cursor ) ) + { + int scopeok = 0; + /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); - idl_free( candidates ); - free( rbuf ); - return( 0 ); + rc = 0; + goto done; } - pthread_mutex_unlock( &op->o_abandonmutex ); /* check time limit */ - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - if ( tlimit != -1 && currenttime > stoptime ) { - pthread_mutex_unlock( ¤ttime_mutex ); - send_ldap_search_result( conn, op, - LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf : - NULL, nentries ); - idl_free( candidates ); - free( rbuf ); - return( 0 ); + if ( tlimit != -1 && slap_get_time() > stoptime ) { + send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, v2refs, NULL, nentries ); + rc = 0; + goto done; + } + + /* get the entry with reader lock */ + e = id2entry_r( be, id ); + + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "ldbm_search: candidate %ld not found.\n", id )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: candidate %ld not found\n", + id, 0, 0 ); +#endif + + goto loop_continue; } - pthread_mutex_unlock( ¤ttime_mutex ); - /* get the entry */ - if ( (e = id2entry( be, id )) == NULL ) { - Debug( LDAP_DEBUG_ARGS, "candidate %d not found\n", id, - 0, 0 ); - continue; + if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) { + Entry *matched; + int err; + const char *text; + + e = deref_entry_r( be, e, &err, &matched, &text ); + + if( e == NULL ) { + e = matched; + goto loop_continue; + } + + if( e->e_id == id ) { + /* circular loop */ + goto loop_continue; + } + + /* need to skip alias which deref into scope */ + if( scope & LDAP_SCOPE_ONELEVEL ) { + struct berval pdn; + dnParent( &e->e_nname, &pdn ); + if ( ber_bvcmp( &pdn, &realbase ) ) { + goto loop_continue; + } + + } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) { + /* alias is within scope */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "ldbm_search: alias \"%s\" in subtree\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: alias \"%s\" in subtree\n", + e->e_dn, 0, 0 ); +#endif + + goto loop_continue; + } + + scopeok = 1; } /* * if it's a referral, add it to the list of referrals. only do - * this for subtree searches, and don't check the filter explicitly - * here since it's only a candidate anyway. + * this for non-base searches, and don't check the filter + * explicitly here since it's only a candidate anyway. */ - if ( e->e_dn != NULL && strncasecmp( e->e_dn, "ref=", 4 ) - == 0 && (ref = attr_find( e->e_attrs, "ref" )) != NULL && - scope == LDAP_SCOPE_SUBTREE ) + if ( !manageDSAit && scope != LDAP_SCOPE_BASE && + is_entry_referral( e ) ) { - int i, len; + struct berval dn; + + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( !be_issuffix( be, &e->e_nname ) ) { + dnParent( &e->e_nname, &dn ); + scopeok = dn_match( &dn, &realbase ); + } else { + scopeok = (realbase.bv_len == 0); + } + + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + scopeok = dnIsSuffix( &e->e_nname, &realbase ); - if ( ref->a_vals == NULL ) { - Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 0, - 0, 0 ); } else { - for ( i = 0; ref->a_vals[i] != NULL; i++ ) { - /* referral + newline + null */ - MAKE_SPACE( ref->a_vals[i]->bv_len + 2 ); - *rcur++ = '\n'; - strncpy( rcur, ref->a_vals[i]->bv_val, - ref->a_vals[i]->bv_len ); - rcur = rcur + ref->a_vals[i]->bv_len; - *rcur = '\0'; - nrefs++; - } + scopeok = 1; } - /* otherwise it's an entry - see if it matches the filter */ - } else { - /* if it matches the filter and scope, send it */ - if ( test_filter( be, conn, op, e, filter ) == 0 ) { - int scopeok; - char *dn; + if( scopeok ) { + BerVarray erefs = get_entry_referrals( + be, conn, op, e ); + BerVarray refs = referral_rewrite( erefs, + &e->e_name, NULL, + scope == LDAP_SCOPE_SUBTREE + ? LDAP_SCOPE_SUBTREE + : LDAP_SCOPE_BASE ); + + send_search_reference( be, conn, op, + e, refs, NULL, &v2refs ); + + ber_bvarray_free( refs ); + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, + "ldbm_search: candidate referral %ld scope not okay\n", + id )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: candidate referral %ld scope not okay\n", + id, 0, 0 ); +#endif + } + + goto loop_continue; + } + + /* if it matches the filter and scope, send it */ + if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) { + struct berval dn; + + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( !be_issuffix( be, &e->e_nname ) ) { + dnParent( &e->e_nname, &dn ); + scopeok = dn_match( &dn, &realbase ); + } else { + scopeok = (realbase.bv_len == 0); + } - /* check scope */ + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + scopeok = dnIsSuffix( &e->e_nname, &realbase ); + + } else { scopeok = 1; - if ( scope == LDAP_SCOPE_ONELEVEL ) { - if ( (dn = dn_parent( be, e->e_dn )) != NULL ) { - (void) dn_normalize( dn ); - scopeok = (dn == base) ? 1 : (! strcasecmp( dn, base )); - } else { - scopeok = (base == NULL || *base == '\0'); - } - free( dn ); - } else if ( scope == LDAP_SCOPE_SUBTREE ) { - dn = strdup( e->e_dn ); - (void) dn_normalize( dn ); - scopeok = dn_issuffix( dn, base ); - free( dn ); + } + + if ( scopeok ) { + /* check size limit */ + if ( --slimit == -1 ) { + cache_return_entry_r( &li->li_cache, e ); + send_search_result( conn, op, + LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, + v2refs, NULL, nentries ); + rc = 0; + goto done; } - if ( scopeok ) { - /* check size limit */ - if ( --slimit == -1 ) { - cache_return_entry( &li->li_cache, e ); - send_ldap_search_result( conn, op, - LDAP_SIZELIMIT_EXCEEDED, NULL, - nrefs > 0 ? rbuf : NULL, nentries ); - idl_free( candidates ); - free( rbuf ); - return( 0 ); - } + if (e) { + int result = send_search_entry(be, conn, op, + e, attrs, attrsonly, NULL); - switch ( send_search_entry( be, conn, op, e, - attrs, attrsonly ) ) { + switch (result) { case 0: /* entry sent ok */ nentries++; break; case 1: /* entry not sent */ break; case -1: /* connection closed */ - cache_return_entry( &li->li_cache, e ); - idl_free( candidates ); - free( rbuf ); - return( 0 ); + cache_return_entry_r( &li->li_cache, e ); + rc = 0; + goto done; } } + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, + "ldbm_search: candidate entry %ld scope not okay\n", id )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: candidate entry %ld scope not okay\n", + id, 0, 0 ); +#endif } + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, + "ldbm_search: candidate entry %ld does not match filter\n", id )); +#else + Debug( LDAP_DEBUG_TRACE, + "ldbm_search: candidate entry %ld does not match filter\n", + id, 0, 0 ); +#endif } - cache_return_entry( &li->li_cache, e ); +loop_continue: + if( e != NULL ) { + /* free reader lock */ + cache_return_entry_r( &li->li_cache, e ); + } - pthread_yield(); - } - idl_free( candidates ); - if ( nrefs > 0 ) { - send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - rbuf, nentries ); - } else { - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, - nentries ); + ldap_pvt_thread_yield(); } - free( rbuf ); - return( 0 ); -} + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, NULL, nentries ); -static IDList * -base_candidates( - Backend *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int rc; - ID id; - IDList *idl; - Entry *e; + rc = 0; - *err = LDAP_SUCCESS; - if ( (e = dn2entry( be, base, matched )) == NULL ) { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } +done: + ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock); - idl = idl_alloc( 1 ); - idl_insert( &idl, e->e_id, 1 ); + if( candidates != NULL ) + idl_free( candidates ); - cache_return_entry( &li->li_cache, e ); + if( v2refs ) ber_bvarray_free( v2refs ); + if( realbase.bv_val ) free( realbase.bv_val ); - return( idl ); + return rc; } -static IDList * -onelevel_candidates( +static ID_BLOCK * +base_candidate( Backend *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err -) + Entry *e ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e; - Filter *f; - char buf[20]; - IDList *candidates; - - *err = LDAP_SUCCESS; - e = NULL; - /* get the base object */ - if ( base != NULL && *base != '\0' && (e = dn2entry( be, base, - matched )) == NULL ) { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } + ID_BLOCK *idl; - /* - * modify the filter to be something like this: - * - * parent=baseobject & originalfilter - */ - - f = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_next = NULL; - f->f_choice = LDAP_FILTER_AND; - f->f_and = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_and->f_choice = LDAP_FILTER_EQUALITY; - f->f_and->f_ava.ava_type = strdup( "id2children" ); - sprintf( buf, "%d", e != NULL ? e->e_id : 0 ); - f->f_and->f_ava.ava_value.bv_val = strdup( buf ); - f->f_and->f_ava.ava_value.bv_len = strlen( buf ); - f->f_and->f_next = filter; - - /* from here, it's just like subtree_candidates */ - candidates = subtree_candidates( be, conn, op, base, f, attrs, - attrsonly, matched, e, err, 0 ); - - /* free up just the filter stuff we allocated above */ - f->f_and->f_next = NULL; - filter_free( f ); +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "base_candidate: base (%s)\n", e->e_dn )); +#else + Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", + e->e_dn, 0, 0); +#endif - return( candidates ); + + idl = idl_alloc( 1 ); + idl_insert( &idl, e->e_id, 1 ); + + return( idl ); } -static IDList * -subtree_candidates( +static ID_BLOCK * +search_candidates( Backend *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, Entry *e, - int *err, - int lookupbase -) + Filter *filter, + int scope, + int deref, + int manageDSAit ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Filter *f; - IDList *candidates; - - /* - * get the base object - unless we already have it (from one-level). - * also, unless this is a one-level search or a subtree search - * starting at the very top of our subtree, we need to modify the - * filter to be something like this: - * - * dn=*baseobjectdn & (originalfilter | ref=*) - * - * the "objectclass=referral" part is used to select referrals to return - */ - - *err = LDAP_SUCCESS; - f = NULL; - if ( lookupbase ) { - if ( base != NULL && *base != '\0' && (e = dn2entry( be, base, - matched )) == NULL ) { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } - - f = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_next = NULL; - f->f_choice = LDAP_FILTER_OR; - f->f_or = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_or->f_choice = LDAP_FILTER_EQUALITY; - f->f_or->f_avtype = strdup( "objectclass" ); - f->f_or->f_avvalue.bv_val = strdup( "referral" ); - f->f_or->f_avvalue.bv_len = strlen( "referral" ); - f->f_or->f_next = filter; - filter = f; - - if ( ! be_issuffix( be, base ) ) { - f = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_next = NULL; - f->f_choice = LDAP_FILTER_AND; - f->f_and = (Filter *) ch_malloc( sizeof(Filter) ); - f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS; - f->f_and->f_sub_type = strdup( "dn" ); - f->f_and->f_sub_initial = NULL; - f->f_and->f_sub_any = NULL; - f->f_and->f_sub_final = strdup( base ); - value_normalize( f->f_and->f_sub_final, SYNTAX_CIS ); - f->f_and->f_next = filter; - filter = f; - } + ID_BLOCK *candidates; + Filter f, fand, rf, af, xf; + AttributeAssertion aa_ref, aa_alias; + struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" }; + struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" }; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "search_candidates: base (%s) scope %d deref %d\n", + e->e_ndn, scope, deref )); +#else + Debug(LDAP_DEBUG_TRACE, + "search_candidates: base=\"%s\" s=%d d=%d\n", + e->e_ndn, scope, deref ); +#endif + + + xf.f_or = filter; + xf.f_choice = LDAP_FILTER_OR; + xf.f_next = NULL; + + if( !manageDSAit ) { + /* match referrals */ + rf.f_choice = LDAP_FILTER_EQUALITY; + rf.f_ava = &aa_ref; + rf.f_av_desc = slap_schema.si_ad_objectClass; + rf.f_av_value = bv_ref; + rf.f_next = xf.f_or; + xf.f_or = &rf; } - candidates = filter_candidates( be, filter ); - - /* free up just the parts we allocated above */ - if ( f != NULL ) { - f->f_and->f_next = NULL; - filter_free( f ); + if( deref & LDAP_DEREF_SEARCHING ) { + /* match aliases */ + af.f_choice = LDAP_FILTER_EQUALITY; + af.f_ava = &aa_alias; + af.f_av_desc = slap_schema.si_ad_objectClass; + af.f_av_value = bv_alias; + af.f_next = xf.f_or; + xf.f_or = ⁡ } - if ( e != NULL ) { - cache_return_entry( &li->li_cache, e ); - } + f.f_next = NULL; + f.f_choice = LDAP_FILTER_AND; + f.f_and = &fand; + fand.f_choice = scope == LDAP_SCOPE_SUBTREE + ? SLAPD_FILTER_DN_SUBTREE + : SLAPD_FILTER_DN_ONE; + fand.f_dn = &e->e_nname; + fand.f_next = xf.f_or == filter ? filter : &xf ; + + candidates = filter_candidates( be, &f ); return( candidates ); } diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c new file mode 100644 index 0000000000000000000000000000000000000000..185067962836d4f9d35868e1683905f9e730b472 --- /dev/null +++ b/servers/slapd/back-meta/bind.c @@ -0,0 +1,469 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has been developed to fulfill the requirements + * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated + * to the OpenLDAP Foundation in the hope that it may be useful + * to the Open Source community, but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + * + * + * This software is based on the backend back-ldap, implemented + * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence + * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other + * contributors. The contribution of the original software to the present + * implementation is acknowledged in this copyright statement. + * + * A special acknowledgement goes to Howard for the overall architecture + * (and for borrowing large pieces of code), and to Mark, who implemented + * from scratch the attribute/objectclass mapping. + * + * The original copyright statement follows. + * + * 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. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + + +#define AVL_INTERNAL +#include "slap.h" +#include "../back-ldap/back-ldap.h" +#include "back-meta.h" + +int +meta_back_bind( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int method, + struct berval *cred, + struct berval *edn +) +{ + struct metainfo *li = ( struct metainfo * )be->be_private; + struct metaconn *lc; + + int rc = -1, i, gotit = 0, ndnlen, isroot = 0; + int op_type = META_OP_ALLOW_MULTIPLE; + int err = LDAP_SUCCESS; + + struct berval *realdn = dn; + struct berval *realndn = ndn; + struct berval *realcred = cred; + int realmethod = method; + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, + "meta_back_bind: dn: %s.\n", dn->bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "meta_back_bind: dn: %s.\n%s%s", dn->bv_val, "", "" ); +#endif /* !NEW_LOGGING */ + + if ( method == LDAP_AUTH_SIMPLE + && be_isroot_pw( be, conn, ndn, cred ) ) { + isroot = 1; + ber_dupbv( edn, be_root_dn( be ) ); + op_type = META_OP_REQUIRE_ALL; + } + lc = meta_back_getconn( li, conn, op, op_type, ndn, NULL ); + if ( !lc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_NOTICE, + "meta_back_bind: no target for dn %s.\n", + dn->bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "meta_back_bind: no target for dn %s.\n%s%s", + dn->bv_val, "", ""); +#endif /* !NEW_LOGGING */ + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); + return -1; + } + + /* + * Each target is scanned ... + */ + lc->bound_target = META_BOUND_NONE; + ndnlen = ndn->bv_len; + for ( i = 0; i < li->ntargets; i++ ) { + int lerr; + + /* + * Skip non-candidates + */ + if ( lc->conns[ i ]->candidate != META_CANDIDATE ) { + continue; + } + + if ( gotit == 0 ) { + gotit = 1; + } else { + /* + * A bind operation is expected to have + * ONE CANDIDATE ONLY! + */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_WARNING, + "==>meta_back_bind: more than one" + " candidate is attempting to bind" + " ...\n" )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "==>meta_back_bind: more than one" + " candidate is attempting to bind" + " ...\n%s%s%s", + "", "", "" ); +#endif /* !NEW_LOGGING */ + } + + if ( isroot && li->targets[ i ]->pseudorootdn.bv_val != NULL ) { + realdn = &li->targets[ i ]->pseudorootdn; + realndn = &li->targets[ i ]->pseudorootdn; + realcred = &li->targets[ i ]->pseudorootpw; + realmethod = LDAP_AUTH_SIMPLE; + } else { + realdn = dn; + realndn = ndn; + realcred = cred; + realmethod = method; + } + + lerr = meta_back_do_single_bind( li, lc, + realdn, realndn, realcred, realmethod, i ); + if ( lerr != LDAP_SUCCESS ) { + err = lerr; + ( void )meta_clear_one_candidate( lc->conns[ i ], 1 ); + } else { + rc = LDAP_SUCCESS; + } + } + + if ( isroot ) { + lc->bound_target = META_BOUND_ALL; + } + + /* + * rc is LDAP_SUCCESS if at least one bind succeeded, + * err is the last error that occurred during a bind; + * if at least (and at most?) one bind succeedes, fine. + */ + if ( rc != LDAP_SUCCESS /* && err != LDAP_SUCCESS */ ) { + + /* + * deal with bind failure ... + */ + + /* + * no target was found within the naming context, + * so bind must fail with invalid credentials + */ + if ( err == LDAP_SUCCESS && gotit == 0 ) { + err = LDAP_INVALID_CREDENTIALS; + } + + err = ldap_back_map_result( err ); + send_ldap_result( conn, op, err, NULL, NULL, NULL, NULL ); + return -1; + } + + return 0; +} + +/* + * meta_back_do_single_bind + * + * attempts to perform a bind with creds + */ +int +meta_back_do_single_bind( + struct metainfo *li, + struct metaconn *lc, + struct berval *dn, + struct berval *ndn, + struct berval *cred, + int method, + int candidate +) +{ + struct berval mdn = { 0, NULL }; + int rc; + + /* + * Rewrite the bind dn if needed + */ + switch ( rewrite_session( li->targets[ candidate ]->rwinfo, + "bindDn", dn->bv_val, lc->conn, &mdn.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mdn.bv_val == NULL ) { + mdn = *dn; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] bindDn: \"%s\" -> \"%s\"\n", dn->bv_val, mdn.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> bindDn: \"%s\" -> \"%s\"\n%s", + dn->bv_val, mdn.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + return LDAP_UNWILLING_TO_PERFORM; + + case REWRITE_REGEXEC_ERR: + return LDAP_OPERATIONS_ERROR; + } + + rc = ldap_bind_s( lc->conns[ candidate ]->ld, mdn.bv_val, cred->bv_val, method ); + if ( rc != LDAP_SUCCESS ) { + rc = ldap_back_map_result( rc ); + } else { + ber_dupbv( &lc->conns[ candidate ]->bound_dn, dn ); + lc->conns[ candidate ]->bound = META_BOUND; + lc->bound_target = candidate; + + if ( li->cache.ttl != META_DNCACHE_DISABLED + && ndn->bv_len != 0 ) { + ( void )meta_dncache_update_entry( &li->cache, + ndn, candidate ); + } + } + + if ( mdn.bv_val != dn->bv_val ) { + free( mdn.bv_val ); + } + + return rc; +} + +/* + * meta_back_dobind + */ +int +meta_back_dobind( struct metaconn *lc, Operation *op ) +{ + struct metasingleconn **lsc; + int bound = 0, i; + + /* + * all the targets are bound as pseudoroot + */ + if ( lc->bound_target == META_BOUND_ALL ) { + return 1; + } + + for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) { + int rc; + + /* + * Not a candidate or something wrong with this target ... + */ + if ( lsc[ 0 ]->ld == NULL ) { + continue; + } + + /* + * If the target is already bound it is skipped + */ + if ( lsc[ 0 ]->bound == META_BOUND && lc->bound_target == i ) { + ++bound; + continue; + } + + /* + * Otherwise an anonymous bind is performed + * (note: if the target was already bound, the anonymous + * bind clears the previous bind). + */ + if ( lsc[ 0 ]->bound_dn.bv_val ) { + ch_free( lsc[ 0 ]->bound_dn.bv_val ); + lsc[ 0 ]->bound_dn.bv_val = NULL; + lsc[ 0 ]->bound_dn.bv_len = 0; + } + rc = ldap_bind_s( lsc[ 0 ]->ld, 0, NULL, LDAP_AUTH_SIMPLE ); + if ( rc != LDAP_SUCCESS ) { + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_WARNING, + "meta_back_dobind: (anonymous)" + " bind as \"%s\" failed" + " with error \"%s\"\n", + lsc[ 0 ]->bound_dn.bv_val, + ldap_err2string( rc ) )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "==>meta_back_dobind: (anonymous)" + " bind as \"%s\" failed" + " with error \"%s\"\n%s", + lsc[ 0 ]->bound_dn.bv_val, + ldap_err2string( rc ), "" ); +#endif /* !NEW_LOGGING */ + + /* + * null cred bind should always succeed + * as anonymous, so a failure means + * the target is no longer candidate possibly + * due to technical reasons (remote host down?) + * so better clear the handle + */ + ( void )meta_clear_one_candidate( lsc[ 0 ], 1 ); + continue; + } /* else */ + + lsc[ 0 ]->bound = META_ANONYMOUS; + ++bound; + } + + return( bound > 0 ); +} + +/* + * + */ +int +meta_back_is_valid( struct metaconn *lc, int candidate ) +{ + struct metasingleconn **lsc; + int i; + + assert( lc ); + + if ( candidate < 0 ) { + return 0; + } + + for ( i = 0, lsc = lc->conns; + lsc[ 0 ] != NULL && i < candidate; + ++i, ++lsc ); + + if ( lsc[ 0 ] ) { + return( lsc[ 0 ]->ld != NULL ); + } + + return 0; +} + +/* + * FIXME: error return must be handled in a cleaner way ... + */ +int +meta_back_op_result( struct metaconn *lc, Operation *op ) +{ + int i, rerr = LDAP_SUCCESS; + struct metasingleconn **lsc; + char *rmsg = NULL; + char *rmatch = NULL; + + for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) { + int err = LDAP_SUCCESS; + char *msg = NULL; + char *match = NULL; + + ldap_get_option( lsc[ 0 ]->ld, LDAP_OPT_ERROR_NUMBER, &err ); + if ( err != LDAP_SUCCESS ) { + /* + * better check the type of error. In some cases + * (search ?) it might be better to return a + * success if at least one of the targets gave + * positive result ... + */ + ldap_get_option( lsc[ 0 ]->ld, + LDAP_OPT_ERROR_STRING, &msg ); + ldap_get_option( lsc[ 0 ]->ld, + LDAP_OPT_MATCHED_DN, &match ); + err = ldap_back_map_result( err ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_DEBUG_ANY, + "meta_back_op_result: target" + " <%d> sending msg \"%s\"" + " (matched \"%s\")\n", + i, ( msg ? msg : "" ), + ( match ? match : "" ) )); +#else /* !NEW_LOGGING */ + Debug(LDAP_DEBUG_ANY, + "==> meta_back_op_result: target" + " <%d> sending msg \"%s\"" + " (matched \"%s\")\n", + i, ( msg ? msg : "" ), + ( match ? match : "" ) ); +#endif /* !NEW_LOGGING */ + + /* + * FIXME: need to rewrite "match" (need rwinfo) + */ + switch ( err ) { + default: + rerr = err; + rmsg = msg; + msg = NULL; + rmatch = match; + match = NULL; + break; + } + + /* better test the pointers before freeing? */ + if ( match ) { + free( match ); + } + if ( msg ) { + free( msg ); + } + } + } + + send_ldap_result( lc->conn, op, rerr, rmatch, rmsg, NULL, NULL ); + + return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 ); +} + diff --git a/servers/slapd/back-meta/dncache.c b/servers/slapd/back-meta/dncache.c new file mode 100644 index 0000000000000000000000000000000000000000..ff8038522ed689c5a54c848b149a23d1e003a1b0 --- /dev/null +++ b/servers/slapd/back-meta/dncache.c @@ -0,0 +1,290 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has been developed to fulfill the requirements + * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated + * to the OpenLDAP Foundation in the hope that it may be useful + * to the Open Source community, but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + * + * + * This software is based on the backend back-ldap, implemented + * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence + * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other + * contributors. The contribution of the original software to the present + * implementation is acknowledged in this copyright statement. + * + * A special acknowledgement goes to Howard for the overall architecture + * (and for borrowing large pieces of code), and to Mark, who implemented + * from scratch the attribute/objectclass mapping. + * + * The original copyright statement follows. + * + * 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. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include "slap.h" +#include "../back-ldap/back-ldap.h" +#include "back-meta.h" + +/* + * The dncache, at present, maps an entry to the target that holds it. + */ + +struct metadncacheentry { + struct berval dn; + int target; + + time_t lastupdated; +}; + +/* + * meta_dncache_cmp + * + * compares two struct metadncacheentry; used by avl stuff + * FIXME: modify avl stuff to delete an entry based on cmp + * (e.g. when ttl expired?) + */ +int +meta_dncache_cmp( + const void *c1, + const void *c2 +) +{ + struct metadncacheentry *cc1 = ( struct metadncacheentry * )c1; + struct metadncacheentry *cc2 = ( struct metadncacheentry * )c2; + + /* + * case sensitive, because the dn MUST be normalized + */ + return ber_bvcmp( &cc1->dn, &cc2->dn); +} + +/* + * meta_dncache_dup + * + * returns -1 in case a duplicate struct metadncacheentry has been inserted; + * used by avl stuff + */ +int +meta_dncache_dup( + void *c1, + void *c2 +) +{ + struct metadncacheentry *cc1 = ( struct metadncacheentry * )c1; + struct metadncacheentry *cc2 = ( struct metadncacheentry * )c2; + + /* + * case sensitive, because the dn MUST be normalized + */ + return ( ber_bvcmp( &cc1->dn, &cc2->dn ) == 0 ) ? -1 : 0; +} + +/* + * meta_dncache_get_target + * + * returns the target a dn belongs to, or -1 in case the dn is not + * in the cache + */ +int +meta_dncache_get_target( + struct metadncache *cache, + struct berval *ndn +) +{ + struct metadncacheentry tmp_entry, *entry; + time_t curr_time; + int target = -1; + + assert( cache ); + assert( ndn ); + + tmp_entry.dn = *ndn; + ldap_pvt_thread_mutex_lock( &cache->mutex ); + entry = ( struct metadncacheentry * )avl_find( cache->tree, + ( caddr_t )&tmp_entry, meta_dncache_cmp ); + + if ( entry != NULL ) { + + /* + * if cache->ttl < 0, cache never expires; + * if cache->ttl = 0 no cache is used; shouldn't get here + * else, cache is used with ttl + */ + if ( cache->ttl < 0 ) { + target = entry->target; + } else { + + /* + * Need mutex? + */ + curr_time = time( NULL ); + + if ( entry->lastupdated+cache->ttl > curr_time ) { + target = entry->target; + } + } + } + ldap_pvt_thread_mutex_unlock( &cache->mutex ); + + return target; +} + +/* + * meta_dncache_update_entry + * + * updates target and lastupdated of a struct metadncacheentry if exists, + * otherwise it gets created; returns -1 in case of error + */ +int +meta_dncache_update_entry( + struct metadncache *cache, + struct berval *ndn, + int target +) +{ + struct metadncacheentry *entry, tmp_entry; + time_t curr_time = 0L; + int err = 0; + + assert( cache ); + assert( ndn ); + + /* + * if cache->ttl < 0, cache never expires; + * if cache->ttl = 0 no cache is used; shouldn't get here + * else, cache is used with ttl + */ + if ( cache->ttl > 0 ) { + + /* + * Need mutex? + */ + curr_time = time( NULL ); + } + + tmp_entry.dn = *ndn; + + ldap_pvt_thread_mutex_lock( &cache->mutex ); + entry = ( struct metadncacheentry * )avl_find( cache->tree, + ( caddr_t )&tmp_entry, meta_dncache_cmp ); + + if ( entry != NULL ) { + entry->target = target; + entry->lastupdated = curr_time; + } else { + entry = ch_calloc( sizeof( struct metadncacheentry ), 1 ); + if ( entry == NULL ) { + ldap_pvt_thread_mutex_unlock( &cache->mutex ); + return -1; + } + + ber_dupbv( &entry->dn, ndn ); + if ( entry->dn.bv_val == NULL ) { + ldap_pvt_thread_mutex_unlock( &cache->mutex ); + return -1; + } + entry->target = target; + entry->lastupdated = curr_time; + + err = avl_insert( &cache->tree, ( caddr_t )entry, + meta_dncache_cmp, meta_dncache_dup ); + } + ldap_pvt_thread_mutex_unlock( &cache->mutex ); + + return err; +} + +/* + * meta_dncache_update_entry + * + * updates target and lastupdated of a struct metadncacheentry if exists, + * otherwise it gets created; returns -1 in case of error + */ +int +meta_dncache_delete_entry( + struct metadncache *cache, + struct berval *ndn +) +{ + struct metadncacheentry *entry, tmp_entry; + + assert( cache ); + assert( ndn ); + + tmp_entry.dn = *ndn; + + ldap_pvt_thread_mutex_lock( &cache->mutex ); + entry = avl_delete( &cache->tree, ( caddr_t )&tmp_entry, + meta_dncache_cmp ); + ldap_pvt_thread_mutex_unlock( &cache->mutex ); + + if ( entry != NULL ) { + meta_dncache_free( ( void * )entry ); + } + + return 0; +} + +/* + * meta_dncache_free + * + * frees an entry + * + */ +void +meta_dncache_free( + void *e +) +{ + struct metadncacheentry *entry = ( struct metadncacheentry * )e; + + free( entry->dn.bv_val ); +} + diff --git a/servers/slapd/back-meta/group.c b/servers/slapd/back-meta/group.c new file mode 100644 index 0000000000000000000000000000000000000000..53b5ed5aee298853e73f080fe2f80d98ca875eb2 --- /dev/null +++ b/servers/slapd/back-meta/group.c @@ -0,0 +1,292 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has been developed to fulfill the requirements + * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated + * to the OpenLDAP Foundation in the hope that it may be useful + * to the Open Source community, but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + * + * + * This software is based on the backend back-ldap, implemented + * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence + * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other + * contributors. The contribution of the original software to the present + * implementation is acknowledged in this copyright statement. + * + * A special acknowledgement goes to Howard for the overall architecture + * (and for borrowing large pieces of code), and to Mark, who implemented + * from scratch the attribute/objectclass mapping. + * + * The original copyright statement follows. + * + * 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. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" +#include "../back-ldap/back-ldap.h" +#include "back-meta.h" + + +/* return 0 IFF op_dn is a value in group_at (member) attribute + * of entry with gr_dn AND that entry has an objectClass + * value of group_oc (groupOfNames) + */ +int +meta_back_group( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at +) +{ + struct metainfo *li = ( struct metainfo * )be->be_private; + int rc = 1, candidate; + Attribute *attr; + AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; + LDAPMessage *result; + char *gattr[ 2 ]; + char *filter = NULL, *ptr; + LDAP *ld = NULL; + struct berval mop_ndn = { 0, NULL }, mgr_ndn = { 0, NULL }; + + struct berval group_oc_name = { 0, NULL }; + struct berval group_at_name = group_at->ad_cname; + + if ( group_oc->soc_names && group_oc->soc_names[ 0 ] ) { + group_oc_name.bv_val = group_oc->soc_names[ 0 ]; + } else { + group_oc_name.bv_val = group_oc->soc_oid; + } + + if ( group_oc_name.bv_val ) { + group_oc_name.bv_len = strlen( group_oc_name.bv_val ); + } + + if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { + /* we already have a copy of the entry */ + /* attribute and objectclass mapping has already been done */ + + /* + * first we need to check if the objectClass attribute + * has been retrieved; otherwise we need to repeat the search + */ + attr = attr_find( target->e_attrs, ad_objectClass ); + if ( attr != NULL ) { + + /* + * Now we can check for the group objectClass value + */ + if ( !is_entry_objectclass( target, group_oc, 0 ) ) { + return 1; + } + + /* + * This part has been reworked: the group attr compare + * fails only if the attribute is PRESENT but the value + * is NOT PRESENT; if the attribute is NOT PRESENT, the + * search must be repeated as well. + * This may happen if a search for an entry has already + * been performed (target is not null) but the group + * attribute has not been required + */ + attr = attr_find( target->e_attrs, group_at ); + if ( attr != NULL ) { + rc = value_find( group_at, attr->a_vals, + op_ndn ); + if ( rc != LDAP_SUCCESS ) { + return 1; + } + return 0; + } /* else: repeat the search */ + } /* else: repeat the search */ + } /* else: do the search */ + + candidate = meta_back_select_unique_candidate( li, gr_ndn ); + if ( candidate == -1 ) { + goto cleanup; + } + + /* + * Rewrite the op ndn if needed + */ + switch ( rewrite_session( li->targets[ candidate ]->rwinfo, "bindDn", + op_ndn->bv_val, conn, &mop_ndn.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mop_ndn.bv_val != NULL && mop_ndn.bv_val[ 0 ] != '\0' ) { + mop_ndn.bv_len = strlen( mop_ndn.bv_val ); + } else { + mop_ndn = *op_ndn; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] bindDn (op ndn in group):" + " \"%s\" -> \"%s\"\n", + op_ndn->bv_val, mop_ndn.bv_val)); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> bindDn (op ndn in group):" + " \"%s\" -> \"%s\"\n%s", + op_ndn->bv_val, mop_ndn.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + /* continues to next case */ + + case REWRITE_REGEXEC_ERR: + return 1; + } + + /* + * Rewrite the gr ndn if needed + */ + switch ( rewrite_session( li->targets[ candidate ]->rwinfo, + "searchBase", + gr_ndn->bv_val, conn, &mgr_ndn.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mgr_ndn.bv_val != NULL && mgr_ndn.bv_val[ 0 ] != '\0' ) { + mgr_ndn.bv_len = strlen( mgr_ndn.bv_val ); + } else { + mgr_ndn = *gr_ndn; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchBase (gr ndn in group):" + " \"%s\" -> \"%s\"\n", + gr_ndn->bv_val, mgr_ndn.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> searchBase (gr ndn in group):" + " \"%s\" -> \"%s\"\n%s", + gr_ndn->bv_val, mgr_ndn.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + /* continues to next case */ + + case REWRITE_REGEXEC_ERR: + goto cleanup; + } + + ldap_back_map( &li->targets[ candidate ]->oc_map, + &group_oc_name, &group_oc_name, 0 ); + if ( group_oc_name.bv_val == NULL ) { + goto cleanup; + } + ldap_back_map( &li->targets[ candidate ]->at_map, + &group_at_name, &group_at_name, 0 ); + if ( group_at_name.bv_val == NULL ) { + goto cleanup; + } + + filter = ch_malloc( sizeof( "(&(objectclass=)(=))" ) + + group_oc_name.bv_len + + group_at_name.bv_len + + mop_ndn.bv_len + 1 ); + if ( filter == NULL ) { + goto cleanup; + } + + rc = ldap_initialize( &ld, li->targets[ candidate ]->uri ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + + rc = ldap_bind_s( ld, li->targets[ candidate ]->binddn.bv_val, + li->targets[ candidate ]->bindpw.bv_val, + LDAP_AUTH_SIMPLE ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + + ptr = slap_strcopy( filter, "(&(objectclass=" ); + ptr = slap_strcopy( ptr , group_oc_name.bv_val ); + ptr = slap_strcopy( ptr , ")(" ); + ptr = slap_strcopy( ptr , group_at_name.bv_val ); + ptr = slap_strcopy( ptr , "=" ); + ptr = slap_strcopy( ptr , mop_ndn.bv_val ); + strcpy( ptr , "))" ); + + gattr[ 0 ] = "objectclass"; + gattr[ 1 ] = NULL; + rc = 1; + if ( ldap_search_ext_s( ld, mgr_ndn.bv_val, LDAP_SCOPE_BASE, filter, + gattr, 0, NULL, NULL, LDAP_NO_LIMIT, + LDAP_NO_LIMIT, &result ) == LDAP_SUCCESS ) { + if ( ldap_first_entry( ld, result ) != NULL ) { + rc = 0; + } + ldap_msgfree( result ); + } + +cleanup:; + if ( ld != NULL ) { + ldap_unbind( ld ); + } + if ( filter != NULL ) { + ch_free( filter ); + } + if ( mop_ndn.bv_val != op_ndn->bv_val ) { + free( mop_ndn.bv_val ); + } + if ( mgr_ndn.bv_val != gr_ndn->bv_val ) { + free( mgr_ndn.bv_val ); + } + + return rc; +} + diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c new file mode 100644 index 0000000000000000000000000000000000000000..3f9a9f89642862b6c13716615732db3a3d8cdfab --- /dev/null +++ b/servers/slapd/back-meta/init.c @@ -0,0 +1,260 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has been developed to fulfill the requirements + * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated + * to the OpenLDAP Foundation in the hope that it may be useful + * to the Open Source community, but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + * + * + * This software is based on the backend back-ldap, implemented + * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence + * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other + * contributors. The contribution of the original software to the present + * implementation is acknowledged in this copyright statement. + * + * A special acknowledgement goes to Howard for the overall architecture + * (and for borrowing large pieces of code), and to Mark, who implemented + * from scratch the attribute/objectclass mapping. + * + * The original copyright statement follows. + * + * 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. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> + +#include "slap.h" +#include "../back-ldap/back-ldap.h" +#include "back-meta.h" + +#ifdef SLAPD_META_DYNAMIC + +int +back_meta_LTX_init_module( int argc, char *argv[] ) { + BackendInfo bi; + + memset( &bi, '\0', sizeof( bi ) ); + bi.bi_type = "meta"; + bi.bi_init = meta_back_initialize; + + backend_add( &bi ); + return 0; +} + +#endif /* SLAPD_META_DYNAMIC */ + +int +meta_back_initialize( + BackendInfo *bi +) +{ + bi->bi_open = 0; + bi->bi_config = 0; + bi->bi_close = 0; + bi->bi_destroy = 0; + + bi->bi_db_init = meta_back_db_init; + bi->bi_db_config = meta_back_db_config; + bi->bi_db_open = 0; + bi->bi_db_close = 0; + bi->bi_db_destroy = meta_back_db_destroy; + + bi->bi_op_bind = meta_back_bind; + bi->bi_op_unbind = 0; + bi->bi_op_search = meta_back_search; + bi->bi_op_compare = meta_back_compare; + bi->bi_op_modify = meta_back_modify; + bi->bi_op_modrdn = meta_back_modrdn; + bi->bi_op_add = meta_back_add; + bi->bi_op_delete = meta_back_delete; + bi->bi_op_abandon = 0; + + bi->bi_extended = 0; + + bi->bi_acl_group = meta_back_group; + bi->bi_acl_attribute = meta_back_attribute; + bi->bi_chk_referrals = 0; + + bi->bi_connection_init = 0; + bi->bi_connection_destroy = meta_back_conn_destroy; + + return 0; +} + +int +meta_back_db_init( + Backend *be +) +{ + struct metainfo *li; + + li = ch_calloc( 1, sizeof( struct metainfo ) ); + if ( li == NULL ) { + return -1; + } + + /* + * At present the default is no default target; + * this may change + */ + li->defaulttarget = META_DEFAULT_TARGET_NONE; + + ldap_pvt_thread_mutex_init( &li->conn_mutex ); + ldap_pvt_thread_mutex_init( &li->cache.mutex ); + be->be_private = li; + + return 0; +} + +static void +conn_free( + struct metaconn *lc +) +{ + struct metasingleconn **lsc; + + for ( lsc = lc->conns; lsc[ 0 ] != NULL; lsc++ ) { + if ( lsc[ 0 ]->ld != NULL ) { + ldap_unbind( lsc[ 0 ]->ld ); + } + if ( lsc[ 0 ]->bound_dn.bv_val ) { + ber_memfree( lsc[ 0 ]->bound_dn.bv_val ); + } + free( lsc[ 0 ] ); + } + free( lc->conns ); + free( lc ); +} + +static void +target_free( + struct metatarget *lt +) +{ + if ( lt->uri ) { + free( lt->uri ); + } + if ( lt->psuffix.bv_val ) { + free( lt->psuffix.bv_val ); + } + if ( lt->suffix.bv_val ) { + free( lt->suffix.bv_val ); + } + if ( lt->binddn.bv_val ) { + free( lt->binddn.bv_val ); + } + if ( lt->bindpw.bv_val ) { + free( lt->bindpw.bv_val ); + } + if ( lt->pseudorootdn.bv_val ) { + free( lt->pseudorootdn.bv_val ); + } + if ( lt->pseudorootpw.bv_val ) { + free( lt->pseudorootpw.bv_val ); + } + if ( lt->rwinfo ) { + rewrite_info_delete( lt->rwinfo ); + } + avl_free( lt->oc_map.remap, NULL ); + avl_free( lt->oc_map.map, ( AVL_FREE )mapping_free ); + avl_free( lt->at_map.remap, NULL ); + avl_free( lt->at_map.map, ( AVL_FREE )mapping_free ); +} + +int +meta_back_db_destroy( + Backend *be +) +{ + struct metainfo *li; + + if ( be->be_private ) { + int i; + + li = ( struct metainfo * )be->be_private; + + /* + * Destroy the connection tree + */ + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + + if ( li->conntree ) { + avl_free( li->conntree, + ( AVL_FREE )conn_free ); + } + + /* + * Destroy the per-target stuff (assuming there's at + * least one ...) + */ + for ( i = 0; i < li->ntargets; i++ ) { + target_free( li->targets[ i ] ); + free( li->targets[ i ] ); + } + + free( li->targets ); + + ldap_pvt_thread_mutex_lock( &li->cache.mutex ); + if ( li->cache.tree ) { + avl_free( li->cache.tree, + ( AVL_FREE )meta_dncache_free ); + } + + ldap_pvt_thread_mutex_unlock( &li->cache.mutex ); + ldap_pvt_thread_mutex_destroy( &li->cache.mutex ); + + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + ldap_pvt_thread_mutex_destroy( &li->conn_mutex ); + } + + free( be->be_private ); + return 0; +} + diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c new file mode 100644 index 0000000000000000000000000000000000000000..6e8f2def32a9573479f6bc13d6f1eeec418dad25 --- /dev/null +++ b/servers/slapd/back-meta/search.c @@ -0,0 +1,793 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + * + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has been developed to fulfill the requirements + * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated + * to the OpenLDAP Foundation in the hope that it may be useful + * to the Open Source community, but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + * + * + * This software is based on the backend back-ldap, implemented + * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence + * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other + * contributors. The contribution of the original software to the present + * implementation is acknowledged in this copyright statement. + * + * A special acknowledgement goes to Howard for the overall architecture + * (and for borrowing large pieces of code), and to Mark, who implemented + * from scratch the attribute/objectclass mapping. + * + * The original copyright statement follows. + * + * 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. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "slap.h" +#include "../back-ldap/back-ldap.h" +#include "back-meta.h" +#include "ldap_pvt.h" +#undef ldap_debug /* silence a warning in ldap-int.h */ +#include "../../../libraries/libldap/ldap-int.h" + +static void +meta_send_entry( + Backend *be, + Operation *op, + struct metaconn *lc, + int i, + LDAPMessage *e, + AttributeName *attrs, + int attrsonly +); + +static int +is_one_level_rdn( + const char *rdn, + int from +); + +int +meta_back_search( + Backend *be, + Connection *conn, + Operation *op, + struct berval *base, + struct berval *nbase, + int scope, + int deref, + int slimit, + int tlimit, + Filter *filter, + struct berval *filterstr, + AttributeName *attrs, + int attrsonly +) +{ + struct metainfo *li = ( struct metainfo * )be->be_private; + struct metaconn *lc; + struct metasingleconn **lsc; + struct timeval tv; + LDAPMessage *res, *e; + int count, rc = 0, *msgid, sres = LDAP_NO_SUCH_OBJECT; + char *match = NULL, *err = NULL; + char *mbase = NULL, *mmatch = NULL; + struct berval mfilter; + + int i, last = 0, candidates = 0, op_type; + struct slap_limits_set *limit = NULL; + int isroot = 0; + + if ( scope == LDAP_SCOPE_BASE ) { + op_type = META_OP_REQUIRE_SINGLE; + } else { + op_type = META_OP_ALLOW_MULTIPLE; + } + + lc = meta_back_getconn( li, conn, op, op_type, nbase, NULL ); + if ( !lc || !meta_back_dobind( lc, op ) ) { + return -1; + } + + /* + * Array of message id of each target + */ + msgid = ch_calloc( sizeof( int ), li->ntargets ); + if ( msgid == NULL ) { + send_search_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL, 0 ); + return -1; + } + + /* if not root, get appropriate limits */ + if ( be_isroot( be, &op->o_ndn ) ) { + isroot = 1; + } else { + ( void ) get_limits( be, &op->o_ndn, &limit ); + } + + /* if no time limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && tlimit > limit->lms_t_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_t_hard == 0 ) { + tlimit = limit->lms_t_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_t_hard > 0 ) { + send_search_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + /* if no size limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && slimit > limit->lms_s_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_s_hard == 0 ) { + slimit = limit->lms_s_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_s_hard > 0 ) { + send_search_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL, 0 ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + /* + * Inits searches + */ + for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; ++i, ++lsc ) { + char *realbase = ( char * )base->bv_val; + int realscope = scope; + ber_len_t suffixlen; + char *mapped_filter, **mapped_attrs; + + if ( lsc[ 0 ]->candidate != META_CANDIDATE ) { + continue; + } + + if ( deref != -1 ) { + ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_DEREF, + ( void * )&deref); + } + if ( tlimit != -1 ) { + ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_TIMELIMIT, + ( void * )&tlimit); + } + if ( slimit != -1 ) { + ldap_set_option( lsc[ 0 ]->ld, LDAP_OPT_SIZELIMIT, + ( void * )&slimit); + } + + /* + * modifies the base according to the scope, if required + */ + suffixlen = li->targets[ i ]->suffix.bv_len; + if ( suffixlen > nbase->bv_len ) { + switch ( scope ) { + case LDAP_SCOPE_SUBTREE: + /* + * make the target suffix the new base + * FIXME: this is very forgiving, because + * illegal bases may be turned into + * the suffix of the target. + */ + if ( dnIsSuffix( &li->targets[ i ]->suffix, + nbase ) ) { + realbase = li->targets[ i ]->suffix.bv_val; + } else { + /* + * this target is no longer candidate + */ + lsc[ 0 ]->candidate = META_NOT_CANDIDATE; + continue; + } + break; + + case LDAP_SCOPE_ONELEVEL: + if ( is_one_level_rdn( li->targets[ i ]->suffix.bv_val, + suffixlen - nbase->bv_len - 1 ) + && dnIsSuffix( &li->targets[ i ]->suffix, nbase ) ) { + /* + * if there is exactly one level, + * make the target suffix the new + * base, and make scope "base" + */ + realbase = li->targets[ i ]->suffix.bv_val; + realscope = LDAP_SCOPE_BASE; + break; + } /* else continue with the next case */ + + case LDAP_SCOPE_BASE: + /* + * this target is no longer candidate + */ + lsc[ 0 ]->candidate = META_NOT_CANDIDATE; + continue; + } + + } + + /* + * Rewrite the search base, if required + */ + switch ( rewrite_session( li->targets[ i ]->rwinfo, + "searchBase", + realbase, conn, &mbase ) ) { + case REWRITE_REGEXEC_OK: + if ( mbase == NULL ) { + mbase = realbase; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchBase: \"%s\" -> \"%s\"\n", + base->bv_val, mbase )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s", + base->bv_val, mbase, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "Unwilling to perform", + NULL, NULL ); + rc = -1; + goto finish; + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "Operations error", + NULL, NULL ); + rc = -1; + goto finish; + } + + /* + * Rewrite the search filter, if required + */ + switch ( rewrite_session( li->targets[ i ]->rwinfo, + "searchFilter", + filterstr->bv_val, conn, &mfilter.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ] != '\0') { + mfilter.bv_len = strlen( mfilter.bv_val ); + } else { + if ( mfilter.bv_val != NULL ) { + free( mfilter.bv_val ); + } + mfilter = *filterstr; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchFilter: \"%s\" -> \"%s\"\n", + filterstr->bv_val, mfilter.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> searchFilter: \"%s\" -> \"%s\"\n%s", + filterstr->bv_val, mfilter.bv_val, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL ); + rc = -1; + goto finish; + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); + rc = -1; + goto finish; + } + + /* + * Maps attributes in filter + */ + mapped_filter = ldap_back_map_filter( &li->targets[ i ]->at_map, + &li->targets[ i ]->oc_map, &mfilter, 0 ); + if ( mapped_filter == NULL ) { + mapped_filter = ( char * )mfilter.bv_val; + } else { + free( mfilter.bv_val ); + } + mfilter.bv_val = NULL; + mfilter.bv_len = 0; + + /* + * Maps required attributes + */ + mapped_attrs = ldap_back_map_attrs( &li->targets[ i ]->at_map, + attrs, 0 ); + if ( mapped_attrs == NULL && attrs) { + for ( count=0; attrs[ count ].an_name.bv_val; count++ ); + mapped_attrs = ch_malloc( ( count + 1 ) * sizeof(char *)); + for ( count=0; attrs[ count ].an_name.bv_val; count++ ) { + mapped_attrs[ count ] = attrs[ count ].an_name.bv_val; + } + mapped_attrs[ count ] = NULL; + } + + /* + * Starts the search + */ + msgid[ i ] = ldap_search( lsc[ 0 ]->ld, mbase, realscope, + mapped_filter, mapped_attrs, attrsonly ); + if ( msgid[ i ] == -1 ) { + lsc[ 0 ]->candidate = META_NOT_CANDIDATE; + continue; + } + + if ( mapped_attrs ) { + free( mapped_attrs ); + mapped_attrs = NULL; + } + if ( mapped_filter != filterstr->bv_val ) { + free( mapped_filter ); + mapped_filter = NULL; + } + if ( mbase != realbase ) { + free( mbase ); + mbase = NULL; + } + + ++candidates; + } + + /* We pull apart the ber result, stuff it into a slapd entry, and + * let send_search_entry stuff it back into ber format. Slow & ugly, + * but this is necessary for version matching, and for ACL processing. + */ + + + /* + * In case there are no candidates, no cycle takes place... + */ + for ( count = 0, rc = 0; candidates > 0; ) { + int ab, gotit = 0; + + /* check for abandon */ + ab = op->o_abandon; + + for ( i = 0, lsc = lc->conns; lsc[ 0 ] != NULL; lsc++, i++ ) { + if ( lsc[ 0 ]->candidate != META_CANDIDATE ) { + continue; + } + + if ( ab ) { + ldap_abandon( lsc[ 0 ]->ld, msgid[ i ] ); + rc = 0; + break; + } + + if ( slimit > 0 && count == slimit ) { + send_search_result( conn, op, + LDAP_SIZELIMIT_EXCEEDED, + NULL, NULL, NULL, NULL, count ); + goto finish; + } + + rc = ldap_result( lsc[ 0 ]->ld, msgid[ i ], + 0, &tv, &res ); + + if ( rc == 0 ) { + continue; + } else if ( rc == -1 ) { + /* something REALLY bad happened! */ + ( void )meta_clear_unused_candidates( li, + lc, -1, 0 ); + send_search_result( conn, op, + LDAP_OPERATIONS_ERROR, + "", "", NULL, NULL, count ); + + /* anything else needs be done? */ + goto finish; + } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { + e = ldap_first_entry( lsc[ 0 ]->ld, res ); + meta_send_entry(be, op, lc, i, e, attrs, + attrsonly); + count++; + ldap_msgfree( res ); + gotit = 1; + } else { + sres = ldap_result2error( lsc[ 0 ]->ld, + res, 1 ); + sres = ldap_back_map_result( sres ); + if ( err != NULL ) { + free( err ); + } + ldap_get_option( lsc[ 0 ]->ld, + LDAP_OPT_ERROR_STRING, &err ); + if ( match != NULL ) { + free( match ); + } + ldap_get_option( lsc[ 0 ]->ld, + LDAP_OPT_MATCHED_DN, &match ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "meta_back_search [%d]" + " match=\"%s\" err=\"%s\"\n", + i, match, err )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "=>meta_back_search [%d] match=\"%s\" err=\"%s\"\n", + i, match, err ); +#endif /* !NEW_LOGGING */ + + last = i; + rc = 0; + + /* + * When no candidates are left, + * the outer cycle finishes + */ + lsc[ 0 ]->candidate = META_NOT_CANDIDATE; + --candidates; + } + } + + if ( ab ) { + goto finish; + } + + if ( gotit == 0 ) { + tv.tv_sec = 0; + tv.tv_usec = 100000; + ldap_pvt_thread_yield(); + } else { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + } + + if ( rc == -1 ) { + /* + * FIXME: need a strategy to handle errors + */ + rc = meta_back_op_result( lc, op ); + goto finish; + } + + /* + * Rewrite the matched portion of the search base, if required + * + * FIXME: only the last one gets caught! + */ + if ( match != NULL ) { + switch ( rewrite_session( li->targets[ last ]->rwinfo, + "matchedDn", match, conn, &mmatch ) ) { + case REWRITE_REGEXEC_OK: + if ( mmatch == NULL ) { + mmatch = ( char * )match; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] matchedDn: \"%s\" -> \"%s\"\n", + match, mmatch )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:" + " \"%s\" -> \"%s\"\n%s", + match, mmatch, "" ); +#endif /* !NEW_LOGGING */ + break; + + case REWRITE_REGEXEC_UNWILLING: + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, NULL, NULL, NULL ); + rc = -1; + goto finish; + + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); + rc = -1; + goto finish; + } + } + + send_search_result( conn, op, sres, + mmatch, err, NULL, NULL, count ); + +finish:; + if ( match ) { + if ( mmatch != match ) { + free( mmatch ); + } + free(match); + } + + if ( err ) { + free( err ); + } + + if ( msgid ) { + free( msgid ); + } + + return rc; +} + +static void +meta_send_entry( + Backend *be, + Operation *op, + struct metaconn *lc, + int target, + LDAPMessage *e, + AttributeName *attrs, + int attrsonly +) +{ + struct metainfo *li = ( struct metainfo * )be->be_private; + struct berval a, mapped; + Entry ent; + BerElement ber = *e->lm_ber; + Attribute *attr, **attrp; + struct berval dummy = { 0, NULL }; + struct berval *bv, bdn; + const char *text; + + if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) { + return; + } + + /* + * Rewrite the dn of the result, if needed + */ + switch ( rewrite_session( li->targets[ target ]->rwinfo, + "searchResult", bdn.bv_val, lc->conn, &ent.e_name.bv_val ) ) { + case REWRITE_REGEXEC_OK: + if ( ent.e_name.bv_val == NULL ) { + ent.e_name = bdn; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "[rw] searchResult[%d]:" + " \"%s\" -> \"%s\"\n", + target, bdn.bv_val, ent.e_name.bv_val )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\"" + " -> \"%s\"\n", target, bdn.bv_val, ent.e_name.bv_val ); +#endif /* !NEW_LOGGING */ + ent.e_name.bv_len = strlen( ent.e_name.bv_val ); + } + break; + + case REWRITE_REGEXEC_ERR: + case REWRITE_REGEXEC_UNWILLING: + return; + } + + dnNormalize2( NULL, &ent.e_name, &ent.e_nname ); + + /* + * cache dn + */ + if ( li->cache.ttl != META_DNCACHE_DISABLED ) { + ( void )meta_dncache_update_entry( &li->cache, + &ent.e_nname, + target ); + } + + ent.e_id = 0; + ent.e_attrs = 0; + ent.e_private = 0; + attrp = &ent.e_attrs; + + while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { + ldap_back_map( &li->targets[ target ]->at_map, + &a, &mapped, 1 ); + if ( mapped.bv_val == NULL ) { + continue; + } + attr = ( Attribute * )ch_malloc( sizeof( Attribute ) ); + if ( attr == NULL ) { + continue; + } + attr->a_flags = 0; + attr->a_next = 0; + attr->a_desc = NULL; + if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) + != LDAP_SUCCESS) { + if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text ) + != LDAP_SUCCESS) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "slap_bv2undef_ad(%s): " + "%s\n", mapped.bv_val, text )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "slap_bv2undef_ad(%s): " + "%s\n%s", mapped.bv_val, text, "" ); +#endif /* !NEW_LOGGING */ + ch_free( attr ); + continue; + } + } + + /* no subschemaSubentry */ + if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) { + ch_free(attr); + continue; + } + + if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR ) { + attr->a_vals = &dummy; + } else if ( attr->a_desc == slap_schema.si_ad_objectClass + || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { + int i, last; + for ( last = 0; attr->a_vals[ last ].bv_val; ++last ); + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + ldap_back_map( &li->targets[ target]->oc_map, + bv, &mapped, 1 ); + if ( mapped.bv_val == NULL ) { + free( bv->bv_val ); + bv->bv_val = NULL; + if ( --last < 0 ) { + break; + } + *bv = attr->a_vals[ last ]; + attr->a_vals[ last ].bv_val = NULL; + i--; + + } else if ( mapped.bv_val != bv->bv_val ) { + free( bv->bv_val ); + ber_dupbv( bv, &mapped ); + } + } + /* + * It is necessary to try to rewrite attributes with + * dn syntax because they might be used in ACLs as + * members of groups; since ACLs are applied to the + * rewritten stuff, no dn-based subecj clause could + * be used at the ldap backend side (see + * http://www.OpenLDAP.org/faq/data/cache/452.html) + * The problem can be overcome by moving the dn-based + * ACLs to the target directory server, and letting + * everything pass thru the ldap backend. + */ + } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid, + SLAPD_DN_SYNTAX ) == 0 ) { + int i; + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + char *newval; + + switch ( rewrite_session( li->targets[ target ]->rwinfo, + "searchResult", + bv->bv_val, + lc->conn, &newval )) { + case REWRITE_REGEXEC_OK: + /* left as is */ + if ( newval == NULL ) { + break; + } +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", + LDAP_LEVEL_DETAIL1, + "[rw] searchResult on" + " attr=%s:" + " \"%s\" -> \"%s\"\n", + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval )); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "rw> searchResult on attr=%s:" + " \"%s\" -> \"%s\"\n", + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval ); +#endif /* !NEW_LOGGING */ + free( bv->bv_val ); + bv->bv_val = newval; + bv->bv_len = strlen( newval ); + + break; + + case REWRITE_REGEXEC_UNWILLING: + + case REWRITE_REGEXEC_ERR: + /* + * FIXME: better give up, + * skip the attribute + * or leave it untouched? + */ + break; + } + } + } + *attrp = attr; + attrp = &attr->a_next; + } + send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, NULL ); + while ( ent.e_attrs ) { + attr = ent.e_attrs; + ent.e_attrs = attr->a_next; + if ( attr->a_vals != &dummy ) { + ber_bvarray_free( attr->a_vals ); + } + free( attr ); + } + + if ( ent.e_dn && ent.e_dn != bdn.bv_val ) { + free( ent.e_dn ); + } + if ( ent.e_ndn ) { + free( ent.e_ndn ); + } +} + +static int +is_one_level_rdn( + const char *rdn, + int from +) +{ + for ( ; from--; ) { + if ( DN_SEPARATOR( rdn[ from ] ) ) { + return 0; + } + } + + return 1; +} + diff --git a/servers/slapd/back-monitor/README b/servers/slapd/back-monitor/README new file mode 100644 index 0000000000000000000000000000000000000000..24216eba7e5a6ebdf4bca6f189450c3c4d655d42 --- /dev/null +++ b/servers/slapd/back-monitor/README @@ -0,0 +1,227 @@ +MONITOR BACKEND + + NAME: back-monitor + + Backend for monitoring the server's activity. + + + +COMPILE AND CONFIGURATION OPTIONS + +It must be explicitly enabled by configuring with + + --enable-monitor + +set; then it must be activated by placing in slapd.conf the database +configure directive + + database monitor + +The suffix "cn=Monitor" is implicitly activated (it cannot be given +as a suffix of the database as usually done for conventional backends). +Note that the "cn=Monitor" naming context appears in the rootDSE +(FIXME: do we really want this?) + +A bind operation is provided; at present it allows to bind as the +backend rootdn. As a result, the backend supports the rootdn/rootpw +directives (only simple bind at present). + + + +NAMING CONTEXT AND TREE STRUCTURE + +The backend naming context is "cn=Monitor"; the first level entries +represent the monitored subsystems. It is implemented in a modular way, +to ease the addition of new subsystems. + + + +SCHEMA + +All the subsystems get a default "cn" attribute, represented by the +subsystem's name, and they all have "top", "monitor" and "extensibleObject" +objectclasses. +"extensibleObject" is used, and the "description" attribute +is used to hold the monitor information of each entry. + + + +FUNCTIONALITY + +Most of the sybsystems contain an additional depth level, represented +by detailed item monitoring. +All the entries undergo an update operation, if a related method is +defined, prior to being returned. Moreover, there's a mechanism to +allow volatile entries to be defined, and generated on the fly when +requested. As an instance, the connection statistics are updated +at each request, while each active connection data is created on the +fly. + +One nice feature of this solution is that granular ACLs can be applied +to each entry. + + + +OPERATIONS + +The backend currently supports: + + bind + compare + modify + search + + + +SUBSYSTEMS + +Currently some subsystems are partially supported. "Partially" +means their entries are correctly generated, but sometimes only +partially useful information is provided. + +The subsystems are: + + Listener + Databases + Backends + Threads + SASL + TLS + Connections + Read Waiters + Write Waiters + Log + Operations + Statistics + Time + + + +LISTENER SUBSYSTEM + +It contains the description of the devices the server is currently +listening on + + + +DATABASES SUBSYSTEM + +The main entry contains the naming context of each configured database; +the subentries contain, for each database, the type and the naming +context. + + + +BACKENDS SUBSYSTEMS + +The main entry contains the type of backends enabled at compile time; +the subentries, for each backend, contain the type of the backend. +It should also contain the modules that have been loaded if dynamic +backends are enabled. + + + +THREADS SUBSYSTEM + +It contains the maximum number of threads enabled at startup and the +current backload. + + + +SASL + +Currently empty. + + + +TLS + +Currently empty. + + + +CONNECTIONS + +The main entry is empty; it should contain some statistics on the number +of connections. +Dynamic subentries are created for each open connection, with stats on +the activity on that connection (the format will be detailed later). +There are two special subentries that show the number of total and +current connections respectively. + + + +READ WAITERS SUBSYSTEM + +It contains the number of current read waiters. + + + +WRITE WAITERS SUBSYSTEM + +It contains the number of current write waiters. + + + +LOG SUBSYSTEM + +It contains the currently active log items. The "Log" subsystem allows +user modify operations on the "description" attribute, whose values MUST +be in the list of admittable log switches: + + Trace + Packets + Args + Conns + BER + Filter + Config (useless) + ACL + Stats + Stats2 + Shell + Parse + Cache (deprecated) + Index + +These values can be added, replaced or deleted; they affect what +messages are sent to the syslog device. + + + +OPERATIONS SUBSYSTEM + +It shows some statistics on the operations performed by the server: + + Initiated + Completed + + + +SENT SUBSYSTEM + +It shows some statistics on the data sent by the server: + + Bytes + PDU + Referrals + Entries + + + +TIME SUBSISTEM + +It contains two subentries with the start time and the current time +of the server. + + + +NOTES + +This document is in a very early stage of maturity and will +probably be rewritten many times before the monitor backend is released. + + + +AUTHOR: Pierangelo Masarati <ando@OpenLDAP.org> + diff --git a/servers/slapd/back-monitor/back-monitor.h b/servers/slapd/back-monitor/back-monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..511facdd796dc0469c06be124bc4a358bae6c5bd --- /dev/null +++ b/servers/slapd/back-monitor/back-monitor.h @@ -0,0 +1,233 @@ +/* back-monitor.h - ldap monitor back-end header file */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef _BACK_MONITOR_H_ +#define _BACK_MONITOR_H_ + +#include <slap.h> +#include <avl.h> +#include <ldap_pvt.h> +#include <ldap_pvt_thread.h> + +LDAP_BEGIN_DECL + +/* + * The cache maps DNs to Entries. + * Each entry, on turn, holds the list of its children in the e_private field. + * This is used by search operation to perform onelevel and subtree candidate + * selection. + */ +struct monitorcache { + struct berval mc_ndn; + Entry *mc_e; +}; + +struct monitorentrypriv { + ldap_pvt_thread_mutex_t mp_mutex; /* entry mutex */ + Entry *mp_next; /* pointer to next sibling */ + Entry *mp_children; /* pointer to first child */ + struct monitorsubsys *mp_info; /* subsystem info */ +#define mp_type mp_info->mss_type + int mp_flags; /* flags */ + +#define MONITOR_F_NONE 0x00 +#define MONITOR_F_SUB 0x01 /* subentry of subsystem */ +#define MONITOR_F_PERSISTENT 0x10 /* persistent entry */ +#define MONITOR_F_PERSISTENT_CH 0x20 /* subsystem generates + persistent entries */ +#define MONITOR_F_VOLATILE 0x40 /* volatile entry */ +#define MONITOR_F_VOLATILE_CH 0x80 /* subsystem generates + volatile entries */ +}; + +struct monitorinfo { + Avlnode *mi_cache; + ldap_pvt_thread_mutex_t mi_cache_mutex; +}; + +/* + * DNs + */ +#define SLAPD_MONITOR_LISTENER 0 +#define SLAPD_MONITOR_LISTENER_NAME "Listeners" +#define SLAPD_MONITOR_LISTENER_RDN \ + "cn=" SLAPD_MONITOR_LISTENER_NAME +#define SLAPD_MONITOR_LISTENER_DN \ + SLAPD_MONITOR_LISTENER_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_DATABASE 1 +#define SLAPD_MONITOR_DATABASE_NAME "Databases" +#define SLAPD_MONITOR_DATABASE_RDN \ + "cn=" SLAPD_MONITOR_DATABASE_NAME +#define SLAPD_MONITOR_DATABASE_DN \ + SLAPD_MONITOR_DATABASE_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_BACKEND 2 +#define SLAPD_MONITOR_BACKEND_NAME "Backends" +#define SLAPD_MONITOR_BACKEND_RDN \ + "cn=" SLAPD_MONITOR_BACKEND_NAME +#define SLAPD_MONITOR_BACKEND_DN \ + SLAPD_MONITOR_BACKEND_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_THREAD 3 +#define SLAPD_MONITOR_THREAD_NAME "Threads" +#define SLAPD_MONITOR_THREAD_RDN \ + "cn=" SLAPD_MONITOR_THREAD_NAME +#define SLAPD_MONITOR_THREAD_DN \ + SLAPD_MONITOR_THREAD_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_SASL 4 +#define SLAPD_MONITOR_SASL_NAME "SASL" +#define SLAPD_MONITOR_SASL_RDN \ + "cn=" SLAPD_MONITOR_SASL_NAME +#define SLAPD_MONITOR_SASL_DN \ + SLAPD_MONITOR_SASL_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_TLS 5 +#define SLAPD_MONITOR_TLS_NAME "TLS" +#define SLAPD_MONITOR_TLS_RDN \ + "cn=" SLAPD_MONITOR_TLS_NAME +#define SLAPD_MONITOR_TLS_DN \ + SLAPD_MONITOR_TLS_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_CONN 6 +#define SLAPD_MONITOR_CONN_NAME "Connections" +#define SLAPD_MONITOR_CONN_RDN \ + "cn=" SLAPD_MONITOR_CONN_NAME +#define SLAPD_MONITOR_CONN_DN \ + SLAPD_MONITOR_CONN_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_READW 7 +#define SLAPD_MONITOR_READW_NAME "Read Waiters" +#define SLAPD_MONITOR_READW_RDN \ + "cn=" SLAPD_MONITOR_READW_NAME +#define SLAPD_MONITOR_READW_DN \ + SLAPD_MONITOR_READW_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_WRITEW 8 +#define SLAPD_MONITOR_WRITEW_NAME "Write Waiters" +#define SLAPD_MONITOR_WRITEW_RDN \ + "cn=" SLAPD_MONITOR_WRITEW_NAME +#define SLAPD_MONITOR_WRITEW_DN \ + SLAPD_MONITOR_WRITEW_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_LOG 9 +#define SLAPD_MONITOR_LOG_NAME "Log" +#define SLAPD_MONITOR_LOG_RDN \ + "cn=" SLAPD_MONITOR_LOG_NAME +#define SLAPD_MONITOR_LOG_DN \ + SLAPD_MONITOR_LOG_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_OPS 10 +#define SLAPD_MONITOR_OPS_NAME "Operations" +#define SLAPD_MONITOR_OPS_RDN \ + "cn=" SLAPD_MONITOR_OPS_NAME +#define SLAPD_MONITOR_OPS_DN \ + SLAPD_MONITOR_OPS_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_SENT 11 +#define SLAPD_MONITOR_SENT_NAME "Statistics" +#define SLAPD_MONITOR_SENT_RDN \ + "cn=" SLAPD_MONITOR_SENT_NAME +#define SLAPD_MONITOR_SENT_DN \ + SLAPD_MONITOR_SENT_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_TIME 12 +#define SLAPD_MONITOR_TIME_NAME "Time" +#define SLAPD_MONITOR_TIME_RDN \ + "cn=" SLAPD_MONITOR_TIME_NAME +#define SLAPD_MONITOR_TIME_DN \ + SLAPD_MONITOR_TIME_RDN "," SLAPD_MONITOR_DN + +#define SLAPD_MONITOR_OBJECTCLASSES \ + "objectClass: top\n" \ + "objectClass: monitor\n" \ + "objectClass: extensibleObject\n" \ + "structuralObjectClass: monitor\n" + +struct monitorsubsys { + int mss_type; + char *mss_name; + struct berval mss_rdn; + struct berval mss_dn; + struct berval mss_ndn; + int mss_flags; + +#define MONITOR_HAS_VOLATILE_CH( mp ) \ + ( ( mp )->mp_flags & MONITOR_F_VOLATILE_CH ) +#define MONITOR_HAS_CHILDREN( mp ) \ + ( ( mp )->mp_children || MONITOR_HAS_VOLATILE_CH( mp ) ) + + /* initialize entry and subentries */ + int ( *mss_init )( BackendDB * ); + /* update existing dynamic entry and subentries */ + int ( *mss_update )( struct monitorinfo *, Entry * ); + /* create new dynamic subentries */ + int ( *mss_create )( struct monitorinfo *, + struct berval *ndn, Entry *, Entry ** ); + /* modify entry and subentries */ + int ( *mss_modify )( struct monitorinfo *, Entry *, + Modifications *modlist ); +}; + +extern struct monitorsubsys monitor_subsys[]; + +extern AttributeDescription *monitor_ad_desc; +extern BackendDB *be_monitor; + +/* + * cache + */ + +extern int monitor_cache_cmp LDAP_P(( const void *c1, const void *c2 )); +extern int monitor_cache_dup LDAP_P(( void *c1, void *c2 )); +extern int monitor_cache_add LDAP_P(( struct monitorinfo *mi, Entry *e )); +extern int monitor_cache_get LDAP_P(( struct monitorinfo *mi, struct berval *ndn, Entry **ep )); +extern int monitor_cache_dn2entry LDAP_P(( struct monitorinfo *mi, struct berval *ndn, Entry **ep, Entry **matched )); +extern int monitor_cache_lock LDAP_P(( Entry *e )); +extern int monitor_cache_release LDAP_P(( struct monitorinfo *mi, Entry *e )); + +/* + * update + */ + +extern int monitor_entry_update LDAP_P(( struct monitorinfo *mi, Entry *e )); +extern int monitor_entry_create LDAP_P(( struct monitorinfo *mi, struct berval *ndn, Entry *e_parent, Entry **ep )); +extern int monitor_entry_modify LDAP_P(( struct monitorinfo *mi, Entry *e, Modifications *modlist )); + +LDAP_END_DECL + +#include "proto-back-monitor.h" + +#endif /* _back_monitor_h_ */ + diff --git a/servers/slapd/back-monitor/backend.c b/servers/slapd/back-monitor/backend.c new file mode 100644 index 0000000000000000000000000000000000000000..bd65f90639b2b2df3f995200e1137b6583fe763c --- /dev/null +++ b/servers/slapd/back-monitor/backend.c @@ -0,0 +1,153 @@ +/* backend.c - deals with backend subsystem */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + + +#include "portable.h" + +#include <stdio.h> + +#include "slap.h" +#include "back-monitor.h" + +/* + * initializes backend subentries + */ +int +monitor_subsys_backend_init( + BackendDB *be +) +{ + struct monitorinfo *mi; + Entry *e, *e_backend, *e_tmp; + int i; + struct monitorentrypriv *mp; + + mi = ( struct monitorinfo * )be->be_private; + + if ( monitor_cache_get( mi, + &monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn, + &e_backend ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_backend_init: " + "unable to get entry '%s'\n", + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: " + "unable to get entry '%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + e_tmp = NULL; + for ( i = nBackendInfo; i--; ) { + char buf[1024]; + BackendInfo *bi; + struct berval bv[ 2 ]; + + bi = &backendInfo[i]; + + snprintf( buf, sizeof( buf ), + "dn: cn=Backend %d,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: Backend %d\n", + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_dn.bv_val, + i ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_backend_init: " + "unable to create entry 'cn=Backend %d,%s'\n", + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: " + "unable to create entry 'cn=Backend %d,%s'\n%s", + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + bv[0].bv_val = bi->bi_type; + bv[0].bv_len = strlen( bv[0].bv_val ); + bv[1].bv_val = NULL; + + attr_merge( e, monitor_ad_desc, bv ); + attr_merge( e_backend, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_BACKEND]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_BACKEND].mss_flags + | MONITOR_F_SUB; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_backend_init: " + "unable to add entry 'cn=Backend %d,%s'\n", + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: " + "unable to add entry 'cn=Backend %d,%s'\n%s", + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + e_tmp = e; + } + + mp = ( struct monitorentrypriv * )e_backend->e_private; + mp->mp_children = e_tmp; + + monitor_cache_release( mi, e_backend ); + + return( 0 ); +} + diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c new file mode 100644 index 0000000000000000000000000000000000000000..9fc8c941f8a4ae1bf1995d473cde6840614b2fa8 --- /dev/null +++ b/servers/slapd/back-monitor/cache.c @@ -0,0 +1,273 @@ +/* cache.c - routines to maintain an in-core cache of entries */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include <stdio.h> + +#include "slap.h" + +#include "back-monitor.h" + +/* + * compares entries based on the dn + */ +int +monitor_cache_cmp( + const void *c1, + const void *c2 +) +{ + struct monitorcache *cc1 = ( struct monitorcache * )c1; + struct monitorcache *cc2 = ( struct monitorcache * )c2; + + /* + * case sensitive, because the dn MUST be normalized + */ + return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn ); +} + +/* + * checks for duplicate entries + */ +int +monitor_cache_dup( + void *c1, + void *c2 +) +{ + struct monitorcache *cc1 = ( struct monitorcache * )c1; + struct monitorcache *cc2 = ( struct monitorcache * )c2; + + /* + * case sensitive, because the dn MUST be normalized + */ + return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn ) == 0 ? -1 : 0; +} + +/* + * adds an entry to the cache and inits the mutex + */ +int +monitor_cache_add( + struct monitorinfo *mi, + Entry *e +) +{ + struct monitorcache *mc; + struct monitorentrypriv *mp; + int rc; + + assert( mi != NULL ); + assert( e != NULL ); + + mp = ( struct monitorentrypriv *)e->e_private; + ldap_pvt_thread_mutex_init( &mp->mp_mutex ); + + mc = ( struct monitorcache * )ch_malloc( sizeof( struct monitorcache ) ); + mc->mc_ndn = e->e_nname; + mc->mc_e = e; + ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); + rc = avl_insert( &mi->mi_cache, ( caddr_t )mc, + monitor_cache_cmp, monitor_cache_dup ); + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + + return rc; +} + +/* + * locks the entry (no r/w) + */ +int +monitor_cache_lock( + Entry *e +) +{ + struct monitorentrypriv *mp; + + assert( e != NULL ); + assert( e->e_private != NULL ); + + mp = ( struct monitorentrypriv * )e->e_private; + ldap_pvt_thread_mutex_lock( &mp->mp_mutex ); + + return( 0 ); +} + +/* + * gets an entry from the cache based on the normalized dn + * with mutex locked + */ +int +monitor_cache_get( + struct monitorinfo *mi, + struct berval *ndn, + Entry **ep +) +{ + struct monitorcache tmp_mc, *mc; + + assert( mi != NULL ); + assert( ndn != NULL ); + assert( ep != NULL ); + + tmp_mc.mc_ndn = *ndn; + ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); + mc = ( struct monitorcache * )avl_find( mi->mi_cache, + ( caddr_t )&tmp_mc, monitor_cache_cmp ); + + if ( mc != NULL ) { + /* entry is returned with mutex locked */ + monitor_cache_lock( mc->mc_e ); + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + *ep = mc->mc_e; + + return( 0 ); + } + + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + *ep = NULL; + + return( -1 ); +} + +/* + * If the entry exists in cache, it is returned in locked status; + * otherwise, if the parent exists, if it may generate volatile + * descendants an attempt to generate the required entry is + * performed and, if successful, the entry is returned + */ +int +monitor_cache_dn2entry( + struct monitorinfo *mi, + struct berval *ndn, + Entry **ep, + Entry **matched +) +{ + int rc; + + struct berval p_ndn = { 0L, NULL }; + Entry *e_parent; + struct monitorentrypriv *mp; + + assert( mi != NULL ); + assert( ndn != NULL ); + assert( ep != NULL ); + assert( matched != NULL ); + + *matched = NULL; + + rc = monitor_cache_get( mi, ndn, ep ); + if ( !rc && *ep != NULL ) { + return( 0 ); + } + + /* try with parent/ancestors */ + if ( ndn->bv_len ) { + dnParent( ndn, &p_ndn ); + } + + if ( p_ndn.bv_val == NULL ) { + p_ndn.bv_val = ""; + p_ndn.bv_len = 0; + + } else { + p_ndn.bv_len = ndn->bv_len + - ( ber_len_t ) ( p_ndn.bv_val - ndn->bv_val ); + } + + rc = monitor_cache_dn2entry( mi, &p_ndn, &e_parent, matched ); + if ( rc || e_parent == NULL) { + return( -1 ); + } + + mp = ( struct monitorentrypriv * )e_parent->e_private; + rc = -1; + if ( mp->mp_flags & MONITOR_F_VOLATILE_CH ) { + /* parent entry generates volatile children */ + rc = monitor_entry_create( mi, ndn, e_parent, ep ); + } + + if ( !rc ) { + monitor_cache_release( mi, e_parent ); + } else { + *matched = e_parent; + } + + return( rc ); +} + +/* + * releases the lock of the entry; if it is marked as volatile, it is + * destroyed. + */ +int +monitor_cache_release( + struct monitorinfo *mi, + Entry *e +) +{ + struct monitorentrypriv *mp; + + assert( mi != NULL ); + assert( e != NULL ); + assert( e->e_private != NULL ); + + mp = ( struct monitorentrypriv * )e->e_private; + + if ( mp->mp_flags & MONITOR_F_VOLATILE ) { + struct monitorcache *mc, tmp_mc; + + /* volatile entries do not return to cache */ + ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); + tmp_mc.mc_ndn = e->e_nname; + mc = avl_delete( &mi->mi_cache, + ( caddr_t )&tmp_mc, monitor_cache_cmp ); + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + ch_free( mc ); + + ldap_pvt_thread_mutex_unlock( &mp->mp_mutex ); + ldap_pvt_thread_mutex_destroy( &mp->mp_mutex ); + ch_free( mp ); + e->e_private = NULL; + entry_free( e ); + + return( 0 ); + } + + ldap_pvt_thread_mutex_unlock( &mp->mp_mutex ); + + return( 0 ); +} + diff --git a/servers/slapd/back-monitor/conn.c b/servers/slapd/back-monitor/conn.c new file mode 100644 index 0000000000000000000000000000000000000000..ae877020b70893cc627f6a68177bee27697af5c1 --- /dev/null +++ b/servers/slapd/back-monitor/conn.c @@ -0,0 +1,439 @@ +/* conn.c - deal with connection subsystem */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include <stdio.h> + +#include "slap.h" +#include "back-monitor.h" + +#define CONN_CN_PREFIX "Connection" + +int +monitor_subsys_conn_init( + BackendDB *be +) +{ + struct monitorinfo *mi; + + Entry *e, *e_tmp, *e_conn; + struct monitorentrypriv *mp; + char buf[1024]; + struct berval bv[2]; + + assert( be != NULL ); + + mi = ( struct monitorinfo * )be->be_private; + + if ( monitor_cache_get( mi, + &monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn, &e_conn ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_init: " + "unable to get entry '%s'\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_init: " + "unable to get entry '%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + e_tmp = NULL; + + /* + * Total conns + */ + snprintf( buf, sizeof( buf ), + "dn: cn=Total,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: Total\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_dn.bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_init: " + "unable to create entry 'cn=Total,%s'\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_init: " + "unable to create entry 'cn=Total,%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + bv[1].bv_val = NULL; + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_CONN]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_CONN].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + mp->mp_flags &= ~MONITOR_F_VOLATILE_CH; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_init: " + "unable to add entry 'cn=Total,%s'\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_init: " + "unable to add entry 'cn=Total,%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + e_tmp = e; + + /* + * Current conns + */ + snprintf( buf, sizeof( buf ), + "dn: cn=Current,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: Current\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_dn.bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_init: " + "unable to create entry 'cn=Current,%s'\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_init: " + "unable to create entry 'cn=Current,%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + bv[1].bv_val = NULL; + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_CONN]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_CONN].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + mp->mp_flags &= ~MONITOR_F_VOLATILE_CH; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_init: " + "unable to add entry 'cn=Current,%s'\n", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_init: " + "unable to add entry 'cn=Current,%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_CONN].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + e_tmp = e; + + mp = ( struct monitorentrypriv * )e_conn->e_private; + mp->mp_children = e_tmp; + + monitor_cache_release( mi, e_conn ); + + return( 0 ); +} + +int +monitor_subsys_conn_update( + struct monitorinfo *mi, + Entry *e +) +{ + long n = -1; + + assert( mi ); + assert( e ); + + if ( strncasecmp( e->e_ndn, "CN=TOTAL", + sizeof("CN=TOTAL")-1 ) == 0 ) { + n = connections_nextid(); + + } else if ( strncasecmp( e->e_ndn, "CN=CURRENT", + sizeof("CN=CURRENT")-1 ) == 0 ) { + Connection *c; + int connindex; + + for ( n = 0, c = connection_first( &connindex ); + c != NULL; + n++, c = connection_next( c, &connindex ) ) { + /* No Op */ ; + } + connection_done(c); + } + + if ( n != -1 ) { + Attribute *a; + char buf[16]; + + a = attr_find( e->e_attrs, monitor_ad_desc ); + if ( a == NULL ) { + return( -1 ); + } + + snprintf( buf, sizeof( buf ), "%ld", n ); + free( a->a_vals[ 0 ].bv_val ); + ber_str2bv( buf, 0, 1, a->a_vals ); + } + + return( 0 ); +} + +static int +conn_create( + Connection *c, + Entry **ep +) +{ + struct monitorentrypriv *mp; + struct tm *ltm; + char buf[1024]; + char buf2[22]; + char buf3[22]; + + struct berval bv[2]; + + Entry *e; + + assert( c != NULL ); + assert( ep != NULL ); + + snprintf( buf, sizeof( buf ), + "dn: cn=" CONN_CN_PREFIX " %ld,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: " CONN_CN_PREFIX " %ld\n", + c->c_connid, monitor_subsys[SLAPD_MONITOR_CONN].mss_dn.bv_val, + c->c_connid ); + e = str2entry( buf ); + + if ( e == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_conn_create: " + "unable to create entry " + "'cn=" CONN_CN_PREFIX " %ld,%s' entry\n", + c->c_connid, + monitor_subsys[SLAPD_MONITOR_CONN].mss_dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_conn_create: " + "unable to create entry " + "'cn=" CONN_CN_PREFIX " %ld,%s' entry\n", + c->c_connid, + monitor_subsys[SLAPD_MONITOR_CONN].mss_dn.bv_val, 0 ); +#endif + return( -1 ); + } + + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); + + ltm = gmtime( &c->c_starttime ); + strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm ); + + ltm = gmtime( &c->c_activitytime ); + strftime( buf3, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm ); + + ldap_pvt_thread_mutex_unlock( &gmtime_mutex ); + + sprintf( buf, + "%ld : %ld " + ": %ld/%ld/%ld/%ld " + ": %ld/%ld/%ld " + ": %s%s%s%s%s%s " + ": %s : %s : %s " + ": %s : %s : %s : %s", + c->c_connid, + (long) c->c_protocol, + c->c_n_ops_received, c->c_n_ops_executing, + c->c_n_ops_pending, c->c_n_ops_completed, + + /* add low-level counters here */ + c->c_n_get, c->c_n_read, c->c_n_write, + + c->c_currentber ? "r" : "", + c->c_writewaiter ? "w" : "", + LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x", + LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p", + connection_state2str( c->c_conn_state ), + c->c_sasl_bind_in_progress ? "S" : "", + + c->c_cdn.bv_len ? c->c_cdn.bv_val : SLAPD_ANONYMOUS, + + c->c_listener_url.bv_val, + c->c_peer_domain.bv_val, + c->c_peer_name.bv_val, + c->c_sock_name.bv_val, + + buf2, + buf3 + ); + + bv[1].bv_val = NULL; + bv[0].bv_val = buf; + bv[0].bv_len = strlen( buf ); + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_info = &monitor_subsys[ SLAPD_MONITOR_CONN ]; + mp->mp_children = NULL; + mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE; + + *ep = e; + + return( 0 ); +} + +int +monitor_subsys_conn_create( + struct monitorinfo *mi, + struct berval *ndn, + Entry *e_parent, + Entry **ep +) +{ + Connection *c; + int connindex; + struct monitorentrypriv *mp; + + assert( mi != NULL ); + assert( e_parent != NULL ); + assert( ep != NULL ); + + *ep = NULL; + + if ( ndn == NULL ) { + Entry *e, *e_tmp = NULL; + + /* create all the children of e_parent */ + for ( c = connection_first( &connindex ); + c != NULL; + c = connection_next( c, &connindex )) { + if ( conn_create( c, &e ) || e == NULL ) { + connection_done(c); + for ( ; e_tmp != NULL; ) { + mp = ( struct monitorentrypriv * )e_tmp->e_private; + e = mp->mp_next; + + ch_free( mp ); + e_tmp->e_private = NULL; + entry_free( e_tmp ); + + e_tmp = e; + } + return( -1 ); + } + mp = ( struct monitorentrypriv * )e->e_private; + mp->mp_next = e_tmp; + e_tmp = e; + } + connection_done(c); + + *ep = e; + + } else { + LDAPRDN *values = NULL; + const char *text = NULL; + unsigned long connid; + + /* create exactly the required entry */ + + if ( ldap_bv2rdn( ndn, &values, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { + return( -1 ); + } + + assert( values ); + assert( values[ 0 ][ 0 ] ); + + connid = atol( values[ 0 ][ 0 ]->la_value.bv_val + + sizeof( CONN_CN_PREFIX ) ); + + ldap_rdnfree( values ); + + for ( c = connection_first( &connindex ); + c != NULL; + c = connection_next( c, &connindex )) { + if ( c->c_connid == connid ) { + if ( conn_create( c, ep ) || *ep == NULL ) { + connection_done(c); + return( -1 ); + } + + break; + } + } + + connection_done(c); + + } + + return( 0 ); +} + diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c new file mode 100644 index 0000000000000000000000000000000000000000..e855ae1c549e75be8a7ffdda3ed667f20d5354e8 --- /dev/null +++ b/servers/slapd/back-monitor/init.c @@ -0,0 +1,544 @@ +/* init.c - initialize monitor backend */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "slap.h" +#include "back-monitor.h" + +/* + * used by many functions to add description to entries + */ +AttributeDescription *monitor_ad_desc = NULL; +BackendDB *be_monitor = NULL; + +/* + * subsystem data + */ +struct monitorsubsys monitor_subsys[] = { + { + SLAPD_MONITOR_LISTENER, SLAPD_MONITOR_LISTENER_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_listener_init, + NULL, /* update */ + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_DATABASE, SLAPD_MONITOR_DATABASE_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_database_init, + NULL, /* update */ + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_BACKEND, SLAPD_MONITOR_BACKEND_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_backend_init, + NULL, /* update */ + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_THREAD, SLAPD_MONITOR_THREAD_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + monitor_subsys_thread_init, + monitor_subsys_thread_update, + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_SASL, SLAPD_MONITOR_SASL_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + NULL, /* init */ + NULL, /* update */ + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_TLS, SLAPD_MONITOR_TLS_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + NULL, /* init */ + NULL, /* update */ + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_CONN, SLAPD_MONITOR_CONN_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_VOLATILE_CH, + monitor_subsys_conn_init, + monitor_subsys_conn_update, + monitor_subsys_conn_create, + NULL /* modify */ + }, { + SLAPD_MONITOR_READW, SLAPD_MONITOR_READW_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + NULL, /* init */ + monitor_subsys_readw_update, + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_WRITEW, SLAPD_MONITOR_WRITEW_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + NULL, /* init */ + monitor_subsys_writew_update, + NULL, /* create */ + NULL /* modify */ + }, { + SLAPD_MONITOR_LOG, SLAPD_MONITOR_LOG_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_NONE, + monitor_subsys_log_init, + NULL, /* update */ + NULL, /* create */ + monitor_subsys_log_modify + }, { + SLAPD_MONITOR_OPS, SLAPD_MONITOR_OPS_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_ops_init, + monitor_subsys_ops_update, + NULL, /* create */ + NULL, /* modify */ + }, { + SLAPD_MONITOR_SENT, SLAPD_MONITOR_SENT_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_sent_init, + monitor_subsys_sent_update, + NULL, /* create */ + NULL, /* modify */ + }, { + SLAPD_MONITOR_TIME, SLAPD_MONITOR_TIME_NAME, + { 0L, NULL }, { 0L, NULL }, { 0L, NULL }, + MONITOR_F_PERSISTENT_CH, + monitor_subsys_time_init, + monitor_subsys_time_update, + NULL, /* create */ + NULL, /* modify */ + }, { -1, NULL } +}; + +int +monitor_back_initialize( + BackendInfo *bi +) +{ + static char *controls[] = { + LDAP_CONTROL_MANAGEDSAIT, + NULL + }; + + bi->bi_controls = controls; + + bi->bi_init = 0; + bi->bi_open = monitor_back_open; + bi->bi_config = monitor_back_config; + bi->bi_close = 0; + bi->bi_destroy = 0; + + bi->bi_db_init = monitor_back_db_init; + bi->bi_db_config = monitor_back_db_config; + bi->bi_db_open = 0; + bi->bi_db_close = 0; + bi->bi_db_destroy = monitor_back_db_destroy; + + bi->bi_op_bind = monitor_back_bind; + bi->bi_op_unbind = 0; + bi->bi_op_search = monitor_back_search; + bi->bi_op_compare = monitor_back_compare; + bi->bi_op_modify = monitor_back_modify; + bi->bi_op_modrdn = 0; + bi->bi_op_add = 0; + bi->bi_op_delete = 0; + bi->bi_op_abandon = 0; + + bi->bi_extended = 0; + + bi->bi_entry_release_rw = 0; + bi->bi_acl_group = 0; + bi->bi_acl_attribute = 0; + bi->bi_chk_referrals = 0; + bi->bi_operational = monitor_back_operational; + + /* + * hooks for slap tools + */ + bi->bi_tool_entry_open = 0; + bi->bi_tool_entry_close = 0; + bi->bi_tool_entry_first = 0; + bi->bi_tool_entry_next = 0; + bi->bi_tool_entry_get = 0; + bi->bi_tool_entry_put = 0; + bi->bi_tool_entry_reindex = 0; + bi->bi_tool_sync = 0; + + bi->bi_connection_init = 0; + bi->bi_connection_destroy = 0; + + return 0; +} + +int +monitor_back_db_init( + BackendDB *be +) +{ + struct monitorinfo *mi; + Entry *e, *e_tmp; + struct monitorentrypriv *mp; + int i, rc; + char buf[1024], *end_of_line; + struct berval dn, *ndn; + const char *text; + struct berval bv[2]; + + /* + * database monitor can be defined once only + */ + if ( be_monitor ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "only one monitor backend is allowed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "only one monitor backend is allowed\n%s%s%s", + "", "", "" ); +#endif + return( -1 ); + } + be_monitor = be; + + /* indicate system schema supported */ + be->be_flags |= SLAP_BFLAG_MONITOR; + + ndn = NULL; + dn.bv_val = SLAPD_MONITOR_DN; + dn.bv_len = sizeof( SLAPD_MONITOR_DN ) - 1; + + rc = dnNormalize( NULL, &dn, &ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor DN \"" SLAPD_MONITOR_DN "\" backend is allowed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor DN \"" SLAPD_MONITOR_DN "\" backend is allowed\n", + 0, 0, 0 ); +#endif + return -1; + } + + ber_bvecadd( &be->be_suffix, ber_dupbv( NULL, &dn ) ); + ber_bvecadd( &be->be_nsuffix, ndn ); + + mi = ( struct monitorinfo * )ch_calloc( sizeof( struct monitorinfo ), 1 ); + ldap_pvt_thread_mutex_init( &mi->mi_cache_mutex ); + + if ( slap_str2ad( "description", &monitor_ad_desc, &text ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_back_db_init: %s\n", text )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: %s\n%s%s", + text, "", "" ); +#endif + return( -1 ); + } + + /* + * Create all the subsystem specific entries + */ + e_tmp = NULL; + for ( i = 0; monitor_subsys[ i ].mss_name != NULL; i++ ) { + int len = strlen( monitor_subsys[ i ].mss_name ); + struct berval dn; + int rc; + + dn.bv_len = len + sizeof( "cn=" ) - 1; + dn.bv_val = ch_calloc( sizeof( char ), dn.bv_len + 1 ); + strcpy( dn.bv_val, "cn=" ); + strcat( dn.bv_val, monitor_subsys[ i ].mss_name ); + rc = dnPretty2( NULL, &dn, &monitor_subsys[ i ].mss_rdn ); + free( dn.bv_val ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor RDN \"%s\" is invalid\n", + dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor RDN \"%s\" is invalid\n", + dn.bv_val, 0, 0 ); +#endif + return( -1 ); + } + + dn.bv_len += sizeof( SLAPD_MONITOR_DN ); /* 1 for the , */ + dn.bv_val = ch_malloc( dn.bv_len + 1 ); + strcpy( dn.bv_val , monitor_subsys[ i ].mss_rdn.bv_val ); + strcat( dn.bv_val, "," SLAPD_MONITOR_DN ); + rc = dnPrettyNormal( NULL, &dn, &monitor_subsys[ i ].mss_dn, + &monitor_subsys[ i ].mss_ndn ); + free( dn.bv_val ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor DN \"%s\" is invalid\n", + dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor DN \"%s\" is invalid\n", + dn.bv_val, 0, 0 ); +#endif + return( -1 ); + } + + snprintf( buf, sizeof( buf ), + "dn: %s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: %s\n", + monitor_subsys[ i ].mss_dn.bv_val, + monitor_subsys[ i ].mss_name ); + + e = str2entry( buf ); + + if ( e == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to create '%s' entry\n", + monitor_subsys[ i ].mss_dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to create '%s' entry\n", + monitor_subsys[ i ].mss_dn.bv_val, 0, 0 ); +#endif + return( -1 ); + } + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_info = &monitor_subsys[ i ]; + mp->mp_children = NULL; + mp->mp_next = e_tmp; + mp->mp_flags = monitor_subsys[ i ].mss_flags; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to add entry '%s' to cache\n", + monitor_subsys[ i ].mss_dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to add entry '%s' to cache\n", + monitor_subsys[ i ].mss_dn.bv_val, 0, 0 ); +#endif + return -1; + } + + e_tmp = e; + } + + /* + * creates the "cn=Monitor" entry + */ + snprintf( buf, sizeof( buf ), + "dn: " SLAPD_MONITOR_DN "\n" + "objectClass: top\n" + "objectClass: monitor\n" + "objectClass: extensibleObject\n" + "structuralObjectClass: monitor\n" + "cn: Monitor" ); + + e = str2entry( buf ); + if ( e == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to create '%s' entry\n", + SLAPD_MONITOR_DN )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to create '%s' entry\n%s%s", + SLAPD_MONITOR_DN, "", "" ); +#endif + return( -1 ); + } + bv[1].bv_val = NULL; + bv[0].bv_val = (char *) Versionstr; + end_of_line = strchr( Versionstr, '\n' ); + if ( end_of_line ) { + bv[0].bv_len = end_of_line - Versionstr; + } else { + bv[0].bv_len = strlen( Versionstr ); + } + if ( attr_merge( e, monitor_ad_desc, bv ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to add description to '%s' entry\n", + SLAPD_MONITOR_DN )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to add description to '%s' entry\n%s%s", + SLAPD_MONITOR_DN, "", "" ); +#endif + return( -1 ); + } + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + + mp->mp_info = NULL; + mp->mp_children = e_tmp; + mp->mp_next = NULL; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to add entry '%s' to cache\n", + SLAPD_MONITOR_DN )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to add entry '%s' to cache\n%s%s", + SLAPD_MONITOR_DN, "", "" ); +#endif + return -1; + } + + be->be_private = mi; + + return 0; +} + +int +monitor_back_open( + BackendInfo *bi +) +{ + BackendDB *be; + struct monitorsubsys *ms; + struct berval dn = { sizeof(SLAPD_MONITOR_DN)-1, SLAPD_MONITOR_DN }; + struct berval ndn; + int rc; + + /* + * adds the monitor backend + */ + rc = dnNormalize2( NULL, &dn, &ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor DN \"" SLAPD_MONITOR_DN "\" is invalid\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor DN \"" SLAPD_MONITOR_DN "\" is invalid\n", + 0, 0, 0 ); +#endif + return( -1 ); + } + + be = select_backend( &ndn , 0, 0 ); + free( ndn.bv_val ); + + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "unable to get monitor backend\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "unable to get monitor backend\n", 0, 0, 0 ); +#endif + return( -1 ); + } + + for ( ms = monitor_subsys; ms->mss_name != NULL; ms++ ) { + if ( ms->mss_init && ( *ms->mss_init )( be ) ) { + return( -1 ); + } + } + + return( 0 ); +} + +int +monitor_back_config( + BackendInfo *bi, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + /* + * eventually, will hold backend specific configuration parameters + */ + return 0; +} + +int +monitor_back_db_config( + Backend *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_DEBUG_CONFIG, + "line %d of file '%s' will be ignored\n", lineno, fname )); +#else + Debug( LDAP_DEBUG_CONFIG, + "line %d of file '%s' will be ignored\n%s", lineno, fname, "" ); +#endif + return( 0 ); +} + +int +monitor_back_db_destroy( + BackendDB *be +) +{ + /* + * FIXME: destroys all the data + */ + return 0; +} + diff --git a/servers/slapd/back-monitor/log.c b/servers/slapd/back-monitor/log.c new file mode 100644 index 0000000000000000000000000000000000000000..aef5d34caaefb8190be07aeedd64e6bfac728acc --- /dev/null +++ b/servers/slapd/back-monitor/log.c @@ -0,0 +1,480 @@ +/* log.c - deal with log subsystem */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> + +#include "slap.h" +#include "lutil.h" +#include "ldif.h" +#include "back-monitor.h" + +/* + * log mutex + */ +ldap_pvt_thread_mutex_t monitor_log_mutex; + +static struct { + int i; + const char *s; +} int_2_level[] = { + { LDAP_DEBUG_TRACE, "Trace" }, + { LDAP_DEBUG_PACKETS, "Packets" }, + { LDAP_DEBUG_ARGS, "Args" }, + { LDAP_DEBUG_CONNS, "Conns" }, + { LDAP_DEBUG_BER, "BER" }, + { LDAP_DEBUG_FILTER, "Filter" }, + { LDAP_DEBUG_CONFIG, "Config" }, /* useless */ + { LDAP_DEBUG_ACL, "ACL" }, + { LDAP_DEBUG_STATS, "Stats" }, + { LDAP_DEBUG_STATS2, "Stats2" }, + { LDAP_DEBUG_SHELL, "Shell" }, + { LDAP_DEBUG_PARSE, "Parse" }, + { LDAP_DEBUG_CACHE, "Cache" }, + { LDAP_DEBUG_INDEX, "Index" }, + { 0, NULL } +}; + +static int loglevel2int( const char *str ); +static const char * int2loglevel( int n ); + +static int add_values( Entry *e, Modification *mod, int *newlevel ); +static int delete_values( Entry *e, Modification *mod, int *newlevel ); +static int replace_values( Entry *e, Modification *mod, int *newlevel ); + +/* + * initializes log subentry + */ +int +monitor_subsys_log_init( + BackendDB *be +) +{ + struct monitorinfo *mi; + Entry *e; + int i; + struct berval bv[2]; + + ldap_pvt_thread_mutex_init( &monitor_log_mutex ); + + mi = ( struct monitorinfo * )be->be_private; + + if ( monitor_cache_get( mi, &monitor_subsys[SLAPD_MONITOR_LOG].mss_ndn, + &e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_log_init: " + "unable to get entry '%s'\n", + monitor_subsys[SLAPD_MONITOR_LOG].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_log_init: " + "unable to get entry '%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_LOG].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + bv[1].bv_val = NULL; + + /* initialize the debug level */ + for ( i = 0; int_2_level[ i ].i != 0; i++ ) { + if ( int_2_level[ i ].i & ldap_syslog ) { + bv[0].bv_val = ( char * )int_2_level[ i ].s; + bv[0].bv_len = strlen( bv[0].bv_val ); + + attr_merge( e, monitor_ad_desc, bv ); + } + } + + monitor_cache_release( mi, e ); + + return( 0 ); +} + +int +monitor_subsys_log_modify( + struct monitorinfo *mi, + Entry *e, + Modifications *modlist +) +{ + int rc = LDAP_OTHER; + int newlevel = ldap_syslog; + Attribute *save_attrs; + Modifications *ml; + + ldap_pvt_thread_mutex_lock( &monitor_log_mutex ); + + save_attrs = e->e_attrs; + e->e_attrs = attrs_dup( e->e_attrs ); + + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + Modification *mod = &ml->sml_mod; + + /* + * accept all operational attributes + */ + if ( is_at_operational( mod->sm_desc->ad_type ) ) { + ( void ) attr_delete( &e->e_attrs, mod->sm_desc ); + rc = attr_merge( e, mod->sm_desc, mod->sm_bvalues ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + break; + } + continue; + + /* + * only the monitor description attribute can be modified + */ + } else if ( mod->sm_desc != monitor_ad_desc ) { + rc = LDAP_UNWILLING_TO_PERFORM; + break; + } + + switch ( mod->sm_op ) { + case LDAP_MOD_ADD: + rc = add_values( e, mod, &newlevel ); + break; + + case LDAP_MOD_DELETE: + rc = delete_values( e, mod, &newlevel ); + break; + + case LDAP_MOD_REPLACE: + rc = replace_values( e, mod, &newlevel ); + break; + + default: + rc = LDAP_OPERATIONS_ERROR; + break; + } + + if ( rc != LDAP_SUCCESS ) { + break; + } + } + + /* set the new debug level */ + if ( rc == LDAP_SUCCESS ) { + const char *text; + static char textbuf[1024]; + +#if 0 /* need op */ + /* check for abandon */ + if ( op->o_abandon ) { + rc = SLAPD_ABANDON; + + goto cleanup; + } +#endif + + /* check that the entry still obeys the schema */ + rc = entry_schema_check( be_monitor, e, save_attrs, + &text, textbuf, sizeof( textbuf ) ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + + /* + * Do we need to protect this with a mutex? + */ + ldap_syslog = newlevel; + +#if 0 /* debug rather than log */ + slap_debug = newlevel; + lutil_set_debug_level( "slapd", slap_debug ); + ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug); + ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug); + ldif_debug = slap_debug; +#endif + } + +cleanup:; + if ( rc == LDAP_SUCCESS ) { + attrs_free( save_attrs ); + + } else { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; + } + + ldap_pvt_thread_mutex_unlock( &monitor_log_mutex ); + + return( rc ); +} + +static int +loglevel2int( const char *str ) +{ + int i; + + for ( i = 0; int_2_level[ i ].i != 0; i++ ) { + if ( strcasecmp( str, int_2_level[ i ].s ) == 0 ) { + return int_2_level[ i ].i; + } + } + + return 0; +} + +static const char * +int2loglevel( int n ) +{ + int i; + + for ( i = 0; int_2_level[ i ].i != 0; i++ ) { + if ( int_2_level[ i ].i == n ) { + return int_2_level[ i ].s; + } + } + + return NULL; +} + +static int +check_constraints( Modification *mod, int *newlevel ) +{ + int i; + + for ( i = 0; mod->sm_bvalues && mod->sm_bvalues[i].bv_val != NULL; i++ ) { + int l; + const char *s; + ber_len_t len; + + l = loglevel2int( mod->sm_bvalues[i].bv_val ); + if ( !l ) { + return LDAP_CONSTRAINT_VIOLATION; + } + + s = int2loglevel( l ); + len = strlen( s ); + assert( len == mod->sm_bvalues[i].bv_len ); + + AC_MEMCPY( mod->sm_bvalues[i].bv_val, s, len ); + + *newlevel |= l; + } + + return LDAP_SUCCESS; +} + +static int +add_values( Entry *e, Modification *mod, int *newlevel ) +{ + Attribute *a; + int i, rc; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + + rc = check_constraints( mod, newlevel ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + a = attr_find( e->e_attrs, mod->sm_desc ); + + if ( a != NULL ) { + + /* "description" SHOULD have appropriate rules ... */ + if ( mr == NULL || !mr->smr_match ) { + return LDAP_INAPPROPRIATE_MATCHING; + } + + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + int rc; + int j; + const char *text = NULL; + struct berval asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + &mod->sm_bvalues[i], + &asserted, + &text ); + + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + int match; + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &a->a_vals[j], &asserted, &text ); + + if ( rc == LDAP_SUCCESS && match == 0 ) { + free( asserted.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + + free( asserted.bv_val ); + } + } + + /* no - add them */ + if ( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) { + /* this should return result of attr_merge */ + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} + +static int +delete_values( Entry *e, Modification *mod, int *newlevel ) +{ + int i, j, k, found, rc, nl = 0; + Attribute *a; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + + rc = check_constraints( mod, &nl ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + *newlevel &= ~nl; + + /* delete the entire attribute */ + if ( mod->sm_bvalues == NULL ) { + int rc = attr_delete( &e->e_attrs, mod->sm_desc ); + + if ( rc ) { + rc = LDAP_NO_SUCH_ATTRIBUTE; + } else { + *newlevel = 0; + rc = LDAP_SUCCESS; + } + return rc; + } + + if ( mr == NULL || !mr->smr_match ) { + /* disallow specific attributes from being deleted if + * no equality rule */ + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* delete specific values - find the attribute first */ + if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { + return( LDAP_NO_SUCH_ATTRIBUTE ); + } + + /* find each value to delete */ + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + int rc; + const char *text = NULL; + + struct berval asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + &mod->sm_bvalues[i], + &asserted, + &text ); + + if( rc != LDAP_SUCCESS ) return rc; + + found = 0; + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + int match; + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &a->a_vals[j], &asserted, &text ); + + if( rc == LDAP_SUCCESS && match != 0 ) { + continue; + } + + /* found a matching value */ + found = 1; + + /* delete it */ + free( a->a_vals[j].bv_val ); + for ( k = j + 1; a->a_vals[k].bv_val != NULL; k++ ) { + a->a_vals[k - 1] = a->a_vals[k]; + } + a->a_vals[k - 1].bv_val = NULL; + + break; + } + + free( asserted.bv_val ); + + /* looked through them all w/o finding it */ + if ( ! found ) { + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + /* if no values remain, delete the entire attribute */ + if ( a->a_vals[0].bv_val == NULL ) { + /* should already be zero */ + *newlevel = 0; + + if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + return LDAP_SUCCESS; +} + +static int +replace_values( Entry *e, Modification *mod, int *newlevel ) +{ + int rc; + + *newlevel = 0; + rc = check_constraints( mod, newlevel ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + rc = attr_delete( &e->e_attrs, mod->sm_desc ); + + if ( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) { + return rc; + } + + if ( mod->sm_bvalues != NULL && + attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) { + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} + diff --git a/servers/slapd/back-monitor/operation.c b/servers/slapd/back-monitor/operation.c new file mode 100644 index 0000000000000000000000000000000000000000..b8a0ff4fb417004912dc69c27d1a94120de3c38f --- /dev/null +++ b/servers/slapd/back-monitor/operation.c @@ -0,0 +1,449 @@ +/* operation.c - deal with operation subsystem */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it> + * + * This work has beed deveolped for the OpenLDAP Foundation + * in the hope that it may be useful to the Open Source community, + * but WITHOUT ANY WARRANTY. + * + * 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 and SysNet s.n.c. are 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. + * SysNet s.n.c. cannot be responsible for the consequences of the + * alterations. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include <stdio.h> + +#include "slap.h" +#include "back-monitor.h" +#include "lber_pvt.h" + +static struct berval + bv_initiated = BER_BVC( "Initiated" ), + bv_completed = BER_BVC( "Completed" ), + bv_op[] = { + BER_BVC( "Bind" ), + BER_BVC( "Unbind" ), + BER_BVC( "Add" ), + BER_BVC( "Delete" ), + BER_BVC( "Modrdn" ), + BER_BVC( "Modify" ), + BER_BVC( "Compare" ), + BER_BVC( "Search" ), + BER_BVC( "Abandon" ), + BER_BVC( "Extended" ) + }; + +int +monitor_subsys_ops_init( + BackendDB *be +) +{ + struct monitorinfo *mi; + + Entry *e, *e_tmp, *e_op, *e_children; + struct monitorentrypriv *mp; + char buf[1024]; + struct berval bv[2]; + int i; + + assert( be != NULL ); + + mi = ( struct monitorinfo * )be->be_private; + + if ( monitor_cache_get( mi, + &monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn, &e_op ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to get entry '%s'\n", + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to get entry '%s'\n%s%s", + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val, + "", "" ); +#endif + return( -1 ); + } + + e_tmp = NULL; + + /* + * Initiated ops + */ + snprintf( buf, sizeof( buf ), + "dn: cn=%s,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: %s\n", + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_dn.bv_val, + bv_initiated.bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,%s'\n", + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,%s'\n%s", + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + bv[1].bv_val = NULL; + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_OPS]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_OPS].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,%s'\n", + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,%s'\n%s", + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + e_tmp = e; + e_children = NULL; + + for ( i = SLAP_OP_LAST; i-- > 0; ) { + + /* + * Initiated ops + */ + snprintf( buf, sizeof( buf ), + "dn: cn=%s,cn=%s,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: %s\n", + bv_op[ i ].bv_val, + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_dn.bv_val, + bv_op[ i ].bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val ); +#endif + return( -1 ); + } + + bv[1].bv_val = NULL; + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_children; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_OPS]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_OPS].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_initiated.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val ); +#endif + return( -1 ); + } + + e_children = e; + } + + mp = ( struct monitorentrypriv * )e_tmp->e_private; + mp->mp_children = e_children; + + /* + * Completed ops + */ + snprintf( buf, sizeof( buf ), + "dn: cn=%s,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: %s\n", + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_dn.bv_val, + bv_completed.bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,%s'\n", + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,%s'\n%s", + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_OPS]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_OPS].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,%s'\n", + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,%s'\n%s", + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val, + "" ); +#endif + return( -1 ); + } + + e_tmp = e; + e_children = NULL; + + for ( i = SLAP_OP_LAST; i-- > 0; ) { + + /* + * Completed ops + */ + snprintf( buf, sizeof( buf ), + "dn: cn=%s,cn=%s,%s\n" + SLAPD_MONITOR_OBJECTCLASSES + "cn: %s\n", + bv_op[ i ].bv_val, + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_dn.bv_val, + bv_op[ i ].bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to create entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val ); +#endif + return( -1 ); + } + + bv[0].bv_val = "0"; + bv[0].bv_len = 1; + attr_merge( e, monitor_ad_desc, bv ); + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_children; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_OPS]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_OPS].mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + + if ( monitor_cache_add( mi, e ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_ops_init: " + "unable to add entry 'cn=%s,cn=%s,%s'\n", + bv_op[ i ].bv_val, + bv_completed.bv_val, + monitor_subsys[SLAPD_MONITOR_OPS].mss_ndn.bv_val ); +#endif + return( -1 ); + } + + e_children = e; + } + + mp = ( struct monitorentrypriv * )e_tmp->e_private; + mp->mp_children = e_children; + + mp = ( struct monitorentrypriv * )e_op->e_private; + mp->mp_children = e_tmp; + + monitor_cache_release( mi, e_op ); + + return( 0 ); +} + +int +monitor_subsys_ops_update( + struct monitorinfo *mi, + Entry *e +) +{ + long n = -1; + char *dn; + + assert( mi ); + assert( e ); + + dn = e->e_dn + 3; + + if ( strncmp( dn, bv_initiated.bv_val, + bv_initiated.bv_len ) == 0 ) { + ldap_pvt_thread_mutex_lock(&num_ops_mutex); + n = num_ops_initiated; + ldap_pvt_thread_mutex_unlock(&num_ops_mutex); + + } else if ( strncmp( dn, bv_completed.bv_val, + bv_completed.bv_len ) == 0 ) { + ldap_pvt_thread_mutex_lock(&num_ops_mutex); + n = num_ops_completed; + ldap_pvt_thread_mutex_unlock(&num_ops_mutex); + + } else { + int i; + ber_len_t len; + + for (i = 0; i < SLAP_OP_LAST; i++ ) { + len = bv_op[ i ].bv_len; + + if ( strncmp( dn, bv_op[ i ].bv_val, len ) == 0 ) { + break; + } + } + + if ( i == SLAP_OP_LAST ) { + return( 0 ); + } + + dn += len + 3 + 1; + + if ( strncmp( dn, bv_initiated.bv_val, + bv_initiated.bv_len ) == 0 ) { + ldap_pvt_thread_mutex_lock(&num_ops_mutex); + n = num_ops_initiated_[ i ]; + ldap_pvt_thread_mutex_unlock(&num_ops_mutex); + + } else if ( strncmp( dn, bv_completed.bv_val, + bv_completed.bv_len ) == 0 ) { + ldap_pvt_thread_mutex_lock(&num_ops_mutex); + n = num_ops_completed_[ i ]; + ldap_pvt_thread_mutex_unlock(&num_ops_mutex); + + } else { + assert( 0 ); + } + } + + if ( n != -1 ) { + Attribute *a; + char buf[16]; + + a = attr_find( e->e_attrs, monitor_ad_desc ); + if ( a == NULL ) { + return( -1 ); + } + + snprintf( buf, sizeof( buf ), "%ld", n ); + free( a->a_vals[ 0 ].bv_val ); + ber_str2bv( buf, 0, 1, a->a_vals ); + } + + return( 0 ); +} + diff --git a/servers/slapd/back-monitor/time.c b/servers/slapd/back-monitor/time.c index 0c9b8e6bda69658fa2eb8703911ee254ead4a93e..8bd0b8045d4401dbfdc1eb768fd0279b75c19a0c 100644 --- a/servers/slapd/back-monitor/time.c +++ b/servers/slapd/back-monitor/time.c @@ -41,8 +41,10 @@ #include "proto-slap.h" #include "back-monitor.h" +#ifdef HACK_LOCAL_TIME static int local_time( const struct tm *ztm, long delta, char *buf, size_t len ); +#endif /* HACK_LOCAL_TIME */ int monitor_subsys_time_init( @@ -53,8 +55,12 @@ monitor_subsys_time_init( Entry *e, *e_tmp, *e_time; struct monitorentrypriv *mp; - char buf[1024], ztmbuf[20], ltmbuf[20]; - struct tm *ztm, *ltm; + char buf[1024], ztmbuf[20]; + struct tm *ztm; +#ifdef HACK_LOCAL_TIME + struct tm *ltm; + char ltmbuf[20]; +#endif /* * Note: ltmbuf, ltm are used only if HACK_LOCAL_TIME is defined @@ -227,12 +233,18 @@ monitor_subsys_time_update( Entry *e ) { - char ztmbuf[20], ltmbuf[20]; - struct tm *ztm, *ltm; + char ztmbuf[20]; + struct tm *ztm; +#ifdef HACK_LOCAL_TIME + char ltmbuf[20]; + struct tm * +#endif /* HACK_LOCAL_TIME */ time_t currenttime; Attribute *a; +#ifdef HACK_LOCAL_TIME static AttributeDescription *ad_local = NULL; const char *text = NULL; +#endif /* HACK_LOCAL_TIME */ ber_len_t len; static int init_start = 0; @@ -296,6 +308,7 @@ monitor_subsys_time_update( return( 0 ); } +#ifdef HACK_LOCAL_TIME /* * assumes gmtime_mutex is locked */ @@ -323,4 +336,5 @@ local_time( const struct tm *ltm, long delta, char *buf, size_t len ) return 0; } +#endif /* HACK_LOCAL_TIME */ diff --git a/servers/slapd/back-null/Makefile.in b/servers/slapd/back-null/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..7fd3a934f664de48e06b5e247e43bcbbc0bf4eec --- /dev/null +++ b/servers/slapd/back-null/Makefile.in @@ -0,0 +1,26 @@ +SRCS = null.c +OBJS = null.lo + +LDAP_INCDIR= ../../../include +LDAP_LIBDIR= ../../../libraries + +BUILD_OPT = "--enable-null" +BUILD_MOD = @BUILD_NULL@ +BUILD_MOD_DYNAMIC = @BUILD_NULL_DYNAMIC@ + +mod_DEFS = -DSLAPD_IMPORT +MOD_DEFS = $(@BUILD_NULL@_DEFS) + +shared_LDAP_LIBS = $(LDAP_LIBPATH) -lldap_r -llber +NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS) + +LIBBASE = back_null + +XINCPATH = -I.. -I$(srcdir)/.. +XDEFS = $(MODULES_CPPFLAGS) + +all-local-lib: ../.backend + +../.backend: lib$(LIBBASE).a + @touch $@ + diff --git a/servers/slapd/back-null/README b/servers/slapd/back-null/README new file mode 100644 index 0000000000000000000000000000000000000000..a2d8cb11fdbe9aa1903f6088e170c04d15617d92 --- /dev/null +++ b/servers/slapd/back-null/README @@ -0,0 +1,14 @@ +Null Backend Interface for OpenLDAP + +The Null backend is surely the most useful part of slapd: +- Searches return success but no entries. +- Compares return compareFalse. +- Updates return success (unless readonly is on) but do nothing. +- Binds fail unless the database option "bind on" is given. + The "bind" option is "off" by default. +Inspired by the /dev/null device. + +slapd.conf example: + database null + suffix "cn=Nothing" + bind on diff --git a/servers/slapd/back-null/external.h b/servers/slapd/back-null/external.h new file mode 100644 index 0000000000000000000000000000000000000000..8b54f398890a9137ab146ef9ee380141a5608adb --- /dev/null +++ b/servers/slapd/back-null/external.h @@ -0,0 +1,33 @@ +/* + * Copyright 2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +#ifndef _NULL_EXTERNAL_H +#define _NULL_EXTERNAL_H + +LDAP_BEGIN_DECL + +extern BI_init null_back_initialize; + +extern BI_db_init null_back_db_init; +extern BI_db_destroy null_back_db_destroy; + +extern BI_db_config null_back_db_config; + +extern BI_op_bind null_back_bind; + +extern BI_op_search null_back_search; + +extern BI_op_compare null_back_compare; + +extern BI_op_modify null_back_modify; + +extern BI_op_modrdn null_back_modrdn; + +extern BI_op_add null_back_add; + +extern BI_op_delete null_back_delete; + +LDAP_END_DECL + +#endif /* _NULL_EXTERNAL_H */ diff --git a/servers/slapd/back-null/null.c b/servers/slapd/back-null/null.c new file mode 100644 index 0000000000000000000000000000000000000000..8d8127785201b0e2a53d0be60826bc0e71511a7d --- /dev/null +++ b/servers/slapd/back-null/null.c @@ -0,0 +1,236 @@ +/* null.c - the null backend */ +/* + * Copyright 2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "slap.h" +#include "external.h" + +struct null_info { + int bind_allowed; +}; + +int +null_back_bind( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + int method, + struct berval *cred, + struct berval *edn +) +{ + struct null_info *ni = (struct null_info *) be->be_private; + + if( ni->bind_allowed ) + /* front end with send result on success (0) */ + return 0; + send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); + return LDAP_INVALID_CREDENTIALS; +} + +int +null_back_add( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e ) +{ + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); + return 0; +} + +int +null_back_compare( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + AttributeAssertion *ava +) +{ + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, NULL, NULL, NULL, NULL ); + return 0; +} + +int +null_back_delete( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn +) +{ + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); + return 0; +} + +int +null_back_modify( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + Modifications *modlist ) +{ + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); + return 0; +} + +int +null_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 ) +{ + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); + return 0; +} + +int +null_back_search( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *base, + struct berval *nbase, + int scope, + int deref, + int slimit, + int tlimit, + Filter *filter, + struct berval *filterstr, + AttributeName *attrs, + int attrsonly ) +{ + send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL, 0 ); + return 1; +} + + +int +null_back_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + struct null_info *ni = (struct null_info *) be->be_private; + + if ( ni == NULL ) { + fprintf( stderr, "%s: line %d: null database info is null!\n", + fname, lineno ); + return 1; + } + + /* bind requests allowed */ + if ( strcasecmp( argv[0], "bind" ) == 0 ) { + if ( argc < 2 ) { + fprintf( stderr, + "%s: line %d: missing <on/off> in \"bind <on/off>\" line\n", + fname, lineno ); + return 1; + } + ni->bind_allowed = strcasecmp( argv[1], "off" ); + + /* anything else */ + } else { + fprintf( stderr, +"%s: line %d: unknown directive \"%s\" in null database definition (ignored)\n", + fname, lineno, argv[0] ); + } + + return 0; +} + + +int +null_back_db_init( BackendDB *be ) +{ + be->be_private = ch_calloc( 1, sizeof(struct null_info) ); + return 0; +} + +int +null_back_db_destroy( + Backend *be +) +{ + free( be->be_private ); + return 0; +} + + +int +null_back_initialize( + BackendInfo *bi +) +{ + bi->bi_open = 0; + bi->bi_close = 0; + bi->bi_config = 0; + bi->bi_destroy = 0; + + bi->bi_db_init = null_back_db_init; + bi->bi_db_config = null_back_db_config; + bi->bi_db_open = 0; + bi->bi_db_close = 0; + bi->bi_db_destroy = null_back_db_destroy; + + bi->bi_op_bind = null_back_bind; + bi->bi_op_unbind = 0; + bi->bi_op_search = null_back_search; + bi->bi_op_compare = null_back_compare; + bi->bi_op_modify = null_back_modify; + bi->bi_op_modrdn = null_back_modrdn; + bi->bi_op_add = null_back_add; + bi->bi_op_delete = null_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; +} + +#ifdef SLAPD_NULL_DYNAMIC +int back_null_LTX_init_module( + int argc, + char *argv[] ) +{ + BackendInfo bi; + + memset( &bi, '\0', sizeof(bi) ); + bi.bi_type = "null"; + bi.bi_init = null_back_initialize; + + backend_add(&bi); + return 0; +} +#endif /* SLAPD_NULL_DYNAMIC */ diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c index 11c1d8e7192424712a5acd60e0e9f6592fc0a722..2cdeb4c9cf1671c2b1566d3a70f98805ebee3e1f 100644 --- a/servers/slapd/back-passwd/search.c +++ b/servers/slapd/back-passwd/search.c @@ -1,32 +1,40 @@ /* search.c - /etc/passwd backend search function */ +/* $OpenLDAP$ */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/ctype.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include <pwd.h> -#include "portable.h" -#include "slap.h" -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; +#include "slap.h" +#include "external.h" +#include <ldap_pvt.h> -static Entry *pw2entry(); +static Entry *pw2entry( + Backend *be, + struct passwd *pw, + const char **text); int passwd_back_search( Backend *be, Connection *conn, Operation *op, - char *base, + struct berval *base, + struct berval *nbase, int scope, int deref, int slimit, int tlimit, Filter *filter, - char *filterstr, - char **attrs, + struct berval *filterstr, + AttributeName *attrs, int attrsonly ) { @@ -35,119 +43,302 @@ passwd_back_search( char *s; time_t stoptime; + int sent = 0; + int err = LDAP_SUCCESS; + + LDAPRDN *rdn = NULL; + struct berval parent = { 0, NULL }; + char *matched = NULL; + const char *text = NULL; + + AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; + tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? be->be_timelimit : tlimit; stoptime = op->o_time + tlimit; slimit = (slimit > be->be_sizelimit || slimit < 1) ? be->be_sizelimit : slimit; + endpwent(); + #ifdef HAVE_SETPWFILE if ( be->be_private != NULL ) { - endpwent(); (void) setpwfile( (char *) be->be_private ); } #endif /* HAVE_SETPWFILE */ - if ( scope == LDAP_SCOPE_BASE ) { - if ( (s = strchr( base, '@' )) != NULL ) { - *s = '\0'; - } + /* Handle a query for the base of this backend */ + if ( be_issuffix( be, nbase ) ) { + struct berval vals[2]; - if ( (pw = getpwnam( base )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, - s != NULL ? s + 1 : NULL, NULL ); - return( -1 ); - } + vals[1].bv_val = NULL; + + matched = (char *) base; - e = pw2entry( be, pw ); - if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly ); + if( scope != LDAP_SCOPE_ONELEVEL ) { + AttributeDescription *desc = NULL; + + /* Create an entry corresponding to the base DN */ + e = (Entry *) ch_calloc(1, sizeof(Entry)); + e->e_name.bv_val = ch_strdup( base->bv_val ); + e->e_name.bv_len = base->bv_len; + e->e_nname.bv_val = ch_strdup( nbase->bv_val ); + e->e_nname.bv_len = nbase->bv_len; + e->e_attrs = NULL; + e->e_private = NULL; + + /* Use the first attribute of the DN + * as an attribute within the entry itself. + */ + if( ldap_bv2rdn( base, &rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP ) ) + { + err = LDAP_INVALID_DN_SYNTAX; + goto done; + } + + if( slap_bv2ad( &rdn[0][0]->la_attr, &desc, &text )) { + err = LDAP_NO_SUCH_OBJECT; + ldap_rdnfree(rdn); + goto done; + } + + vals[0] = rdn[0][0]->la_value; + attr_merge( e, desc, vals ); + + ldap_rdnfree(rdn); + rdn = NULL; + + /* Every entry needs an objectclass. We don't really + * know if our hardcoded choice here agrees with the + * DN that was configured for this backend, but it's + * better than nothing. + * + * should be a configuratable item + */ + vals[0].bv_val = "organizationalUnit"; + vals[0].bv_len = sizeof("organizationalUnit")-1; + attr_merge( e, ad_objectClass, vals ); + + if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) { + send_search_entry( be, conn, op, + e, attrs, attrsonly, NULL ); + sent++; + } } - entry_free( e ); - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + if ( scope != LDAP_SCOPE_BASE ) { + /* check all our "children" */ - return( 0 ); - } + for ( pw = getpwent(); pw != NULL; pw = getpwent() ) { + /* check for abandon */ + if ( op->o_abandon ) { + endpwent(); + return( -1 ); + } - for ( pw = getpwent(); pw != NULL; pw = getpwent() ) { - /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); - if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); + /* check time limit */ + if ( slap_get_time() > stoptime ) { + send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, NULL, NULL ); + endpwent(); + return( 0 ); + } + + if ( !(e = pw2entry( be, pw, &text )) ) { + err = LDAP_OPERATIONS_ERROR; + endpwent(); + goto done; + } + + if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) { + /* check size limit */ + if ( --slimit == -1 ) { + send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, + NULL, NULL, NULL, NULL ); + endpwent(); + return( 0 ); + } + + send_search_entry( be, conn, op, + e, attrs, attrsonly, NULL ); + sent++; + } + + entry_free( e ); + } endpwent(); - return( -1 ); } - pthread_mutex_unlock( &op->o_abandonmutex ); - /* check size limit */ - if ( --slimit == -1 ) { - send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, - NULL, NULL ); - endpwent(); - return( 0 ); + } else { + if (! be_issuffix( be, nbase ) ) { + dnParent( nbase, &parent ); } - /* check time limit */ - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - if ( currenttime > stoptime ) { - pthread_mutex_unlock( ¤ttime_mutex ); - send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, - NULL, NULL ); - endpwent(); - return( 0 ); + /* This backend is only one layer deep. Don't answer requests for + * anything deeper than that. + */ + if( !be_issuffix( be, &parent ) ) { + int i; + for( i=0; be->be_nsuffix[i] != NULL; i++ ) { + if( dnIsSuffix( nbase, be->be_nsuffix[i] ) ) { + matched = be->be_suffix[i]->bv_val; + break; + } + } + err = LDAP_NO_SUCH_OBJECT; + goto done; } - pthread_mutex_unlock( ¤ttime_mutex ); - e = pw2entry( be, pw ); + if( scope == LDAP_SCOPE_ONELEVEL ) { + goto done; + } - if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly ); + if ( ldap_bv2rdn( base, &rdn, (char **)&text, + LDAP_DN_FORMAT_LDAP )) + { + err = LDAP_OPERATIONS_ERROR; + goto done; + } + + if ( (pw = getpwnam( rdn[0][0]->la_value.bv_val )) == NULL ) { + matched = parent.bv_val; + err = LDAP_NO_SUCH_OBJECT; + goto done; + } + + if ( !(e = pw2entry( be, pw, &text )) ) { + err = LDAP_OPERATIONS_ERROR; + goto done; + } + + if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) { + send_search_entry( be, conn, op, + e, attrs, attrsonly, NULL ); + sent++; } entry_free( e ); } - endpwent(); - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + +done: + send_ldap_result( conn, op, + err, err == LDAP_NO_SUCH_OBJECT ? matched : NULL, text, + NULL, NULL ); + + if( rdn != NULL ) ldap_rdnfree( rdn ); return( 0 ); } static Entry * -pw2entry( Backend *be, struct passwd *pw ) +pw2entry( Backend *be, struct passwd *pw, const char **text ) { + size_t pwlen; Entry *e; - char buf[256]; - struct berval val; - struct berval *vals[2]; + struct berval vals[2]; + struct berval bv; + + int rc; - vals[0] = &val; - vals[1] = NULL; + AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; + AttributeDescription *ad_cn = NULL; + AttributeDescription *ad_sn = NULL; + AttributeDescription *ad_uid = NULL; + AttributeDescription *ad_description = NULL; + + rc = slap_str2ad( "cn", &ad_cn, text ); + if(rc != LDAP_SUCCESS) return NULL; + rc = slap_str2ad( "sn", &ad_sn, text ); + if(rc != LDAP_SUCCESS) return NULL; + rc = slap_str2ad( "uid", &ad_uid, text ); + if(rc != LDAP_SUCCESS) return NULL; + rc = slap_str2ad( "description", &ad_description, text ); + if(rc != LDAP_SUCCESS) return NULL; /* - * from pw we get pw_name and make it uid and cn and sn and - * we get pw_gecos and make it cn and we give it an objectclass - * of person. + * from pw we get pw_name and make it cn + * give it an objectclass of person. */ + pwlen = strlen( pw->pw_name ); + vals[0].bv_len = (sizeof("uid=,")-1) + ( pwlen + be->be_suffix[0]->bv_len ); + vals[0].bv_val = ch_malloc( vals[0].bv_len + 1 ); + + /* rdn attribute type should be a configuratable item */ + sprintf( vals[0].bv_val, "uid=%s,%s", + pw->pw_name, be->be_suffix[0]->bv_val ); + + rc = dnNormalize2( NULL, vals, &bv ); + if( rc != LDAP_SUCCESS ) { + free( vals[0].bv_val ); + return NULL; + } + e = (Entry *) ch_calloc( 1, sizeof(Entry) ); + e->e_name = vals[0]; + e->e_nname = bv; + e->e_attrs = NULL; - sprintf( buf, "%s@%s", pw->pw_name, be->be_suffix[0] ); - e->e_dn = strdup( buf ); - - val.bv_val = pw->pw_name; - val.bv_len = strlen( pw->pw_name ); - attr_merge( e, "cn", vals ); - attr_merge( e, "sn", vals ); - attr_merge( e, "uid", vals ); - val.bv_val = pw->pw_gecos; - val.bv_len = strlen( pw->pw_gecos ); - attr_merge( e, "cn", vals ); - val.bv_val = "person"; - val.bv_len = strlen( val.bv_val ); - attr_merge( e, "objectclass", vals ); + vals[1].bv_val = NULL; + + /* objectclasses should be configurable items */ + vals[0].bv_val = "top"; + vals[0].bv_len = sizeof("top")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = "person"; + vals[0].bv_len = sizeof("person")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = "uidObject"; + vals[0].bv_len = sizeof("uidObject")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = pw->pw_name; + vals[0].bv_len = pwlen; + attr_merge( e, ad_uid, vals ); /* required by uidObject */ + attr_merge( e, ad_cn, vals ); /* required by person */ + attr_merge( e, ad_sn, vals ); /* required by person */ + +#ifdef HAVE_PW_GECOS + /* + * if gecos is present, add it as a cn. first process it + * according to standard BSD usage. If the processed cn has + * a space, use the tail as the surname. + */ + if (pw->pw_gecos[0]) { + char *s; + + vals[0].bv_val = pw->pw_gecos; + vals[0].bv_len = strlen(vals[0].bv_val); + attr_merge(e, ad_description, vals); + + s = strchr(vals[0].bv_val, ','); + if (s) *s = '\0'; + + s = strchr(vals[0].bv_val, '&'); + if (s) { + char buf[256]; + int i = s - vals[0].bv_val; + strncpy(buf, vals[0].bv_val, i); + s = buf+i; + strcpy(s, pw->pw_name); + *s = TOUPPER(*s); + strcat(s, vals[0].bv_val+i+1); + vals[0].bv_val = buf; + } + vals[0].bv_len = strlen(vals[0].bv_val); + if ( strcmp( vals[0].bv_val, pw->pw_name )) + attr_merge( e, ad_cn, vals ); + if ( (s=strrchr(vals[0].bv_val, ' '))) { + vals[0].bv_val = s + 1; + vals[0].bv_len = strlen(vals[0].bv_val); + attr_merge(e, ad_sn, vals); + } + } +#endif return( e ); } diff --git a/servers/slapd/back-shell/abandon.c b/servers/slapd/back-shell/abandon.c index fc9d6a40b6162512a9c620e67aef97f72a87c083..2eccb51f1272b79ef84b50a079454cff120c95e9 100644 --- a/servers/slapd/back-shell/abandon.c +++ b/servers/slapd/back-shell/abandon.c @@ -1,14 +1,21 @@ /* abandon.c - shell backend abandon function */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <signal.h> + +#include <ac/socket.h> +#include <ac/string.h> + #include "slap.h" #include "shell.h" -void +int shell_back_abandon( Backend *be, Connection *conn, @@ -18,34 +25,42 @@ shell_back_abandon( { struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; - int pid; + pid_t pid; Operation *o; /* no abandon command defined - just kill the process handling it */ if ( si->si_abandon == NULL ) { - pthread_mutex_lock( &conn->c_opsmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); pid = -1; - for ( o = conn->c_ops; o != NULL; o = o->o_next ) { + LDAP_STAILQ_FOREACH( o, &conn->c_ops, o_next ) { if ( o->o_msgid == msgid ) { - pid = o->o_private; + pid = (pid_t) o->o_private; break; } } - pthread_mutex_unlock( &conn->c_opsmutex ); + if( pid == -1 ) { + LDAP_STAILQ_FOREACH( o, &conn->c_pending_ops, o_next ) { + if ( o->o_msgid == msgid ) { + pid = (pid_t) o->o_private; + break; + } + } + } + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); if ( pid != -1 ) { - Debug( LDAP_DEBUG_ARGS, "shell killing pid %d\n", pid, - 0, 0 ); + Debug( LDAP_DEBUG_ARGS, "shell killing pid %d\n", + (int) pid, 0, 0 ); kill( pid, SIGTERM ); } else { Debug( LDAP_DEBUG_ARGS, "shell could not find op %d\n", msgid, 0, 0 ); } - return; + return 0; } if ( forkandexec( si->si_abandon, &rfp, &wfp ) == -1 ) { - return; + return 0; } /* write out the request to the abandon process */ @@ -56,4 +71,6 @@ shell_back_abandon( /* no result from abandon */ fclose( rfp ); + + return 0; } diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c index 749b112a9401238704bb7b9c4fc5606483ef1cc7..0c998830718bd69259ee7b6c868bec47440697a9 100644 --- a/servers/slapd/back-shell/search.c +++ b/servers/slapd/back-shell/search.c @@ -1,63 +1,69 @@ /* search.c - shell backend search function */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/socket.h> +#include <ac/string.h> + #include "slap.h" #include "shell.h" -extern Entry *str2entry(); - -void +int shell_back_search( Backend *be, Connection *conn, Operation *op, - char *base, + struct berval *base, + struct berval *nbase, int scope, int deref, int size, int time, Filter *filter, - char *filterstr, - char **attrs, + struct berval *filterstr, + AttributeName *attrs, int attrsonly ) { struct shellinfo *si = (struct shellinfo *) be->be_private; - int i, rc, bsize, len; - int err; - char *matched, *info; + int i; FILE *rfp, *wfp; + AttributeName *an; if ( si->si_search == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "search not implemented" ); - return; + "search not implemented", NULL, NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_search, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_search, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL, NULL ); + return( -1 ); } /* write out the request to the search process */ fprintf( wfp, "SEARCH\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); - fprintf( wfp, "base: %s\n", base ); + fprintf( wfp, "base: %s\n", base->bv_val ); fprintf( wfp, "scope: %d\n", scope ); fprintf( wfp, "deref: %d\n", deref ); fprintf( wfp, "sizelimit: %d\n", size ); fprintf( wfp, "timelimit: %d\n", time ); - fprintf( wfp, "filter: %s\n", filterstr ); + fprintf( wfp, "filter: %s\n", filterstr->bv_val ); fprintf( wfp, "attrsonly: %d\n", attrsonly ? 1 : 0 ); fprintf( wfp, "attrs:%s", attrs == NULL ? " all" : "" ); - for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) { - fprintf( wfp, " %s", attrs[i] ); + for ( an = attrs; an && an->an_name.bv_val; an++ ) { + fprintf( wfp, " %s", an->an_name.bv_val ); } fprintf( wfp, "\n" ); fclose( wfp ); @@ -66,4 +72,5 @@ shell_back_search( read_and_send_results( be, conn, op, rfp, attrs, attrsonly ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c new file mode 100644 index 0000000000000000000000000000000000000000..2dca484832374d894fbdfefd902a7cf738688a0f --- /dev/null +++ b/servers/slapd/back-sql/search.c @@ -0,0 +1,649 @@ +/* + * 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 "slap.h" +#include "back-sql.h" +#include "sql-wrap.h" +#include "schema-map.h" +#include "entry-id.h" +#include "util.h" + +int backsql_attrlist_add(backsql_srch_info *bsi,char *at_name) +{ + char **p=bsi->attrs; + int n_attrs=0; + + if (bsi->attrs==NULL) + return 1; + + while(*p) + { + Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): attribute '%s' is in list\n",*p,0,0); + if (!strcasecmp(*p,at_name)) + return 1; + n_attrs++; + p++; + } + Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): adding '%s' to list\n",at_name,0,0); + bsi->attrs=(char**)ch_realloc(bsi->attrs,(n_attrs+2)*sizeof(char*)); + bsi->attrs[n_attrs]=ch_strdup(at_name); + bsi->attrs[n_attrs+1]=NULL; + return 1; +} + +void backsql_init_search(backsql_srch_info *bsi,backsql_info *bi,char *nbase,int scope, + int slimit,int tlimit,time_t stoptime,Filter *filter, + SQLHDBC dbh,BackendDB *be,Connection *conn,Operation *op,AttributeName *attrs) +{ + AttributeName *p; + bsi->base_dn=nbase; + bsi->scope=scope; + bsi->slimit=slimit; + bsi->tlimit=tlimit; + bsi->filter=filter; + bsi->dbh=dbh; + bsi->be=be; + bsi->conn=conn; + bsi->op=op; + if (attrs!=NULL) + { + bsi->attrs=(char**)ch_calloc(1,sizeof(char*)); + bsi->attrs[0]=NULL; + for(p=attrs;p->an_name.bv_val;p++) + backsql_attrlist_add(bsi,p->an_name.bv_val); + } + else + bsi->attrs=NULL; + bsi->abandon=0; + bsi->id_list=NULL; + bsi->stoptime=stoptime; + bsi->bi=bi; + bsi->sel=NULL; bsi->from=NULL; bsi->join_where=NULL; bsi->flt_where=NULL; + bsi->sel_len=0; bsi->from_len=0; bsi->jwhere_len=0; bsi->fwhere_len=0; +} + +int backsql_process_filter_list(backsql_srch_info *bsi,Filter *f,int op) +{ + char *sub_clause=NULL; + int len=0,res; + + if (!f) + return 0; + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL); + while(1) + { + res=backsql_process_filter(bsi,f); + if (res < 0) + return -1; /* TimesTen : If the query has no answers, + don't bother to run the query. */ + + f=f->f_next; + if (f==NULL) + break; + + switch (op) + { + case LDAP_FILTER_AND: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," AND ",NULL); + break; + case LDAP_FILTER_OR: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," OR ",NULL); + break; + } + } + + + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL); + return 1; +} + +int backsql_process_sub_filter(backsql_srch_info *bsi,Filter *f) +{ + int i; + backsql_at_map_rec *at=backsql_at_with_name(bsi->oc,f->f_sub_desc->ad_cname.bv_val); + + if (!f) + return 0; + + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL); + /* TimesTen*/ + Debug(LDAP_DEBUG_TRACE,"expr: '%s' '%s'\n",at->sel_expr, + at->sel_expr_u?at->sel_expr_u:"<NULL>",0); + if (bsi->bi->upper_func) + { + /* If a pre-upper-cased version of the column exists, use it. */ + if (at->sel_expr_u) { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len, + at->sel_expr_u," LIKE '",NULL); + } + else { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len, + bsi->bi->upper_func,"(",at->sel_expr,")", + " LIKE '",NULL); + } + } + else + { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,at->sel_expr, + " LIKE '",NULL); + } + if (f->f_sub_initial!=NULL) + { + if (bsi->bi->upper_func) + { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_initial->bv_val),NULL); + } + else + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_initial->bv_val,NULL); + } + + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"%",NULL); + + if (f->f_sub_any!=NULL) + for(i=0;f->f_sub_any[i]!=NULL;i++) + { + /*Debug(LDAP_DEBUG_TRACE,"==>backsql_process_sub_filter(): sub_any='%s'\n",f->f_sub_any[i]->bv_val,0,0);*/ + if (bsi->bi->upper_func) + { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_any[i]->bv_val),"%",NULL); + } + else + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_any[i]->bv_val,"%",NULL); + } + + if (f->f_sub_final!=NULL) + if (bsi->bi->upper_func) + { + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_final->bv_val),NULL); + } + else + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_final->bv_val,NULL); + + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"')",NULL); + + return 1; +} + +int backsql_process_filter(backsql_srch_info *bsi,Filter *f) +{ + backsql_at_map_rec *at; + backsql_at_map_rec oc_attr={"objectClass","","",NULL,NULL,NULL,NULL}; + char *at_name=NULL; + int done=0,len=0; + int rc=0; /* TimesTen */ + + Debug(LDAP_DEBUG_TRACE,"==>backsql_process_filter()\n",0,0,0); + if (f==NULL || f->f_choice==SLAPD_FILTER_COMPUTED) + { + return 0; + } + + switch(f->f_choice) + { + case LDAP_FILTER_OR: + rc = backsql_process_filter_list(bsi,f->f_or,LDAP_FILTER_OR); + done=1; + break; + case LDAP_FILTER_AND: + rc = backsql_process_filter_list(bsi,f->f_and,LDAP_FILTER_AND); + done=1; + break; + case LDAP_FILTER_NOT: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",NULL); + rc = backsql_process_filter(bsi,f->f_not); + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL); + done=1; + break; + case LDAP_FILTER_PRESENT: + at_name=f->f_desc->ad_cname.bv_val; + break; + default: + at_name=f->f_av_desc->ad_cname.bv_val; + break; + } + + if (rc == -1) + goto impossible; /* TimesTen : Don't run the query */ + + if (done) + goto done; + + if (strcasecmp(at_name,"objectclass")) + at=backsql_at_with_name(bsi->oc,at_name); + else + { + at=&oc_attr; + at->sel_expr=backsql_strcat(at->sel_expr,&len,"'",bsi->oc->name,"'",NULL); + } + if (at==NULL) + { + Debug(LDAP_DEBUG_TRACE,"backsql_process_filter(): attribute '%s' is not defined for objectclass '%s'\n", + at_name,bsi->oc->name,0); + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," 1=0 ",NULL); + goto impossible; + } + + backsql_merge_from_clause(&bsi->from,&bsi->from_len,at->from_tbls); + /*need to add this attribute to list of attrs to load, so that we could do test_filter() later*/ + backsql_attrlist_add(bsi,at_name); + + if (at->join_where != NULL && strstr(bsi->join_where,at->join_where)==NULL) + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," AND ",at->join_where,NULL); + + /*if (at!=&oc_attr) + bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,",",at->sel_expr," AS ",at->name,NULL); + */ + + switch(f->f_choice) + { + case LDAP_FILTER_EQUALITY: + /*maybe we should check type of at->sel_expr here somehow, + * to know whether upper_func is applicable, but for now + * upper_func stuff is made for Oracle, where UPPER is + * safely applicable to NUMBER etc. + */ + if (bsi->bi->upper_func) { + if (at->sel_expr_u) + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(", + at->sel_expr_u,"='", + ldap_pvt_str2upper(f->f_av_value->bv_val),"')", + NULL); + else + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(", + bsi->bi->upper_func,"(",at->sel_expr,")='", + ldap_pvt_str2upper(f->f_av_value->bv_val),"')",NULL); + } + else + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"='", + f->f_av_value->bv_val,"')",NULL); + + break; + case LDAP_FILTER_GE: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,">=", + f->f_av_value->bv_val,")",NULL); + + break; + case LDAP_FILTER_LE: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"<=", + f->f_av_value->bv_val,")",NULL); + break; + case LDAP_FILTER_PRESENT: + bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",at->sel_expr, + " IS NULL)",NULL); + break; + case LDAP_FILTER_SUBSTRINGS: + backsql_process_sub_filter(bsi,f); + break; + } + +done: + if (oc_attr.sel_expr!=NULL) + free(oc_attr.sel_expr); + Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter()\n",0,0,0); + return 1; + +impossible: + if (oc_attr.sel_expr!=NULL) + free(oc_attr.sel_expr); + Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter() returns -1\n",0,0,0); + return -1; + +} + +char* backsql_srch_query(backsql_srch_info *bsi) +{ + char *query=NULL; + int q_len=0; + int rc; + + Debug(LDAP_DEBUG_TRACE,"==>backsql_srch_query()\n",0,0,0); + bsi->sel=NULL; + bsi->from=NULL; + bsi->join_where=NULL; + bsi->flt_where=NULL; + bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0; + + bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len, + "SELECT DISTINCT ldap_entries.id,",bsi->oc->keytbl,".",bsi->oc->keycol, + ", '",bsi->oc->name,"' AS objectClass", + ", ldap_entries.dn AS dn", + NULL); + bsi->from=backsql_strcat(bsi->from,&bsi->from_len," FROM ldap_entries,",bsi->oc->keytbl,NULL); + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," WHERE ", + bsi->oc->keytbl,".",bsi->oc->keycol,"=ldap_entries.keyval AND ", + "ldap_entries.oc_map_id=? AND ",NULL); + + switch(bsi->scope) + { + case LDAP_SCOPE_BASE: + if (bsi->bi->upper_func) + { + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len, + bsi->bi->upper_func,"(","ldap_entries.dn)=(?)",NULL); + } + else + { + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len, + "ldap_entries.dn=?",NULL); + } + break; + case LDAP_SCOPE_ONELEVEL: + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len, + "ldap_entries.parent=?",NULL); + break; + case LDAP_SCOPE_SUBTREE: + bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len, + bsi->bi->subtree_cond,NULL); + break; + } + + rc = backsql_process_filter(bsi, bsi->filter); + if (rc>0) { + query=backsql_strcat(query,&q_len,bsi->sel,bsi->from,bsi->join_where," AND ",bsi->flt_where,NULL); + } + else if (rc < 0) { + /* Indicates that there's no possible way the filter matches + anything. No need to issue the query. */ + + Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query() returns NULL\n",0,0,0); + free(query); + query = NULL; + } + + free(bsi->sel); + free(bsi->from); + free(bsi->join_where); + free(bsi->flt_where); + bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0; + Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query()\n",0,0,0); + return query; +} + +int backsql_oc_get_candidates(backsql_oc_map_rec *oc,backsql_srch_info *bsi) +{ + char *query=NULL; + SQLHSTMT sth; + RETCODE rc; + backsql_entryID base_id,*res,*c_id; + /*Entry *e;*/ + BACKSQL_ROW_NTS row; + int i; + int j; + char temp_base_dn[BACKSQL_MAX_DN_LEN+1]; /* TimesTen*/ + + Debug(LDAP_DEBUG_TRACE,"==>backsql_oc_get_candidates(): oc='%s'\n",oc->name,0,0); + bsi->oc=oc; + query=backsql_srch_query(bsi); + if (query==NULL) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not construct query for objectclass\n",0,0,0); + return 1; + } + + Debug(LDAP_DEBUG_TRACE,"Constructed query: %s\n",query,0,0); + + if ((rc=backsql_Prepare(bsi->dbh,&sth,query,0)) != SQL_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error preparing query\n",0,0,0); + backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc); + free(query); + return 1; + } + free(query); + + if (backsql_BindParamID(sth,1,&bsi->oc->id) != SQL_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding objectclass id parameter\n",0,0,0); + return 1; + } + switch(bsi->scope) + { + case LDAP_SCOPE_BASE: + if ((rc=backsql_BindParamStr(sth,2,bsi->base_dn,BACKSQL_MAX_DN_LEN)) != SQL_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter\n",0,0,0); + backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc); + return 1; + } + break; + + case LDAP_SCOPE_SUBTREE: + /* Sets the parameters for the SQL built earlier */ + /* NOTE that all the databases could actually use the TimesTen version, + which would be cleaner and would also eliminate the need for the + subtree_cond line in the configuration file. For now, I'm leaving + it the way it is, so non-TimesTen databases use the original code. + But at some point this should get cleaned up. */ + /* If "dn" is being used, do a suffix search. + If "dn_ru" is being used, do a prefix search. */ + + if (bsi->bi->has_ldapinfo_dn_ru) { + temp_base_dn[0] = '\0'; + for ((i=0, j=strlen(bsi->base_dn)-1); j >= 0; (i++, j--)) { + *(temp_base_dn+i) = toupper(*(bsi->base_dn+j)); + } + *(temp_base_dn+i) = '%'; + *(temp_base_dn+i+1) = '\0'; + } + else { + strcpy(temp_base_dn, "%"); + for (i = 0; *(bsi->base_dn+i); i++) { + *(temp_base_dn+i+1) = toupper(*(bsi->base_dn+i)); + } + *(temp_base_dn+i+1) = '\0'; + } + Debug(LDAP_DEBUG_TRACE, "dn '%s'\n", temp_base_dn, 0, 0); + + if ((rc=backsql_BindParamStr(sth,2,temp_base_dn,BACKSQL_MAX_DN_LEN)) != +SQL_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter (2)\n",0,0,0); + backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc); + return 1; + } + break; + + case LDAP_SCOPE_ONELEVEL: + res=backsql_dn2id(bsi->bi,&base_id,bsi->dbh,bsi->base_dn); + if (res==NULL) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not retrieve base_dn id - no such entry\n",0,0,0); + bsi->status=LDAP_NO_SUCH_OBJECT; + return 0; + } + if (backsql_BindParamID(sth,2,&base_id.id) != SQL_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base id parameter\n",0,0,0); + free(base_id.dn); + return 1; + } + free(base_id.dn); + break; + } + + if ((rc=SQLExecute(sth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO) + { + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error executing query\n",0,0,0); + backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc); + SQLFreeStmt(sth,SQL_DROP); + return 1; + } + + backsql_BindRowAsStrings(sth,&row); + while ((rc=SQLFetch(sth)) == SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO) + { + /* + e=(Entry*)ch_calloc(1,sizeof(Entry)); + for (i=1;i<row.ncols;i++) + { + if (row.is_null[i]>0) + { + backsql_entry_addattr(e,row.col_names[i],row.cols[i],row.col_prec[i]); + Debug(LDAP_DEBUG_TRACE,"prec=%d\n",(int)row.col_prec[i],0,0); + } + else + Debug(LDAP_DEBUG_TRACE,"NULL value in this row for attribute '%s'\n",row.col_names[i],0,0); + } + */ + + c_id=(backsql_entryID*)ch_calloc(1,sizeof(backsql_entryID)); + c_id->id=atoi(row.cols[0]); + c_id->keyval=atoi(row.cols[1]); + c_id->oc_id=bsi->oc->id; + c_id->dn=ch_strdup(row.cols[3]); + c_id->next=bsi->id_list; + bsi->id_list=c_id; + Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): added entry id=%d, keyval=%d dn='%s'\n", + c_id->id,c_id->keyval,row.cols[3]); + } + backsql_FreeRow(&row); + SQLFreeStmt(sth,SQL_DROP); + + Debug(LDAP_DEBUG_TRACE,"<==backsql_oc_get_candidates()\n",0,0,0); + return 1; +} + +int backsql_search(BackendDB *be,Connection *conn,Operation *op, + const char *base, const char *nbase, int scope,int deref,int slimit,int tlimit, + Filter *filter, const char *filterstr,AttributeName *attrs,int attrsonly) +{ + backsql_info *bi=(backsql_info*)be->be_private; + SQLHDBC dbh; + int sres; + int nentries; + Entry *entry,*res; + int manageDSAit = get_manageDSAit( op ); + struct berval **v2refs = NULL; + time_t stoptime; + backsql_srch_info srch_info; + backsql_entryID *eid=NULL; + + Debug(LDAP_DEBUG_TRACE,"==>backsql_search(): base='%s', filter='%s', scope=%d,", + nbase,filterstr,scope); + Debug(LDAP_DEBUG_TRACE," deref=%d, attrsonly=%d, attributes to load: %s\n", + deref,attrsonly,attrs==NULL?"all":"custom list"); + dbh=backsql_get_db_conn(be,conn); + + if (!dbh) + { + Debug(LDAP_DEBUG_TRACE,"backsql_search(): could not get connection handle - exiting\n",0,0,0); + send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL); + return 1; + } + + /* TimesTen : Pass it along to the lower level routines */ + srch_info.isTimesTen = bi->isTimesTen; + + if (tlimit == 0 && be_isroot(be,&op->o_ndn)) + { + tlimit = -1; /* allow root to set no limit */ + } + else + { + tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? + be->be_timelimit : tlimit; + stoptime = op->o_time + tlimit; + } + + if (slimit == 0 && be_isroot(be,&op->o_ndn)) + { + slimit = -1; /* allow root to set no limit */ + } + else + { + slimit = (slimit > be->be_sizelimit || slimit < 1) ? + be->be_sizelimit : slimit; + } + + backsql_init_search(&srch_info,bi,(char*)nbase,scope,slimit,tlimit,stoptime,filter,dbh, + be,conn,op,attrs); + + /*for each objectclass we try to construct query which gets IDs + *of entries matching LDAP query filter and scope (or at least candidates), + *and get the IDs +*/ + avl_apply(bi->oc_by_name,(AVL_APPLY)backsql_oc_get_candidates,&srch_info,0,AVL_INORDER); + + nentries=0; + /*now we load candidate entries (only those attrubutes mentioned in attrs and filter), + *test it against full filter and then send to client +*/ + for(eid=srch_info.id_list;eid!=NULL;eid=eid->next) + { + /* check for abandon */ + if (op->o_abandon) + { + break; + } + + /* check time limit */ + if ( tlimit != -1 && slap_get_time() > stoptime) + { + send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, v2refs, NULL, nentries ); + + break; + } + + Debug(LDAP_DEBUG_TRACE,"backsql_search(): loading data for entry id=%d, oc_id=%d, keyval=%d\n", + eid->id,eid->oc_id,eid->keyval); + + entry=(Entry *)ch_calloc(sizeof(Entry),1); + res=backsql_id2entry(&srch_info,entry,eid); + if (res==NULL) + { + Debug(LDAP_DEBUG_TRACE,"backsql_search(): error in backsql_id2entry() - skipping entry\n",0,0,0); + continue; + } + + if ( !manageDSAit && scope != LDAP_SCOPE_BASE && + is_entry_referral( entry ) ) + { + struct berval **refs = get_entry_referrals(be,conn,op,entry); + + send_search_reference( be, conn, op, entry, refs, scope, NULL, &v2refs ); + ber_bvecfree( refs ); + continue; + } + + if (test_filter(be,conn,op,entry,filter)==LDAP_COMPARE_TRUE) + { + if ((sres=send_search_entry(be,conn,op,entry,attrs,attrsonly,NULL))==-1) + { + Debug(LDAP_DEBUG_TRACE,"backsql_search(): connection lost\n",0,0,0); + break; + } + nentries+=!sres; + } + entry_free(entry); + } + + for(eid=srch_info.id_list;eid!=NULL;eid=backsql_free_entryID(eid)); + + charray_free(srch_info.attrs); + + if (nentries>0) + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, NULL, nentries ); + else + send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,NULL,NULL,NULL,0); + + Debug(LDAP_DEBUG_TRACE,"<==backsql_search()\n",0,0,0); + return 0; +} + +#endif /* SLAPD_SQL */ diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 998bfa8c6acc215d0e6a1240cb494210580d55a1..1fbeecde211773ba4f603e6ec1afe732439d09e4 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -1,181 +1,599 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* backend.c - routines for dealing with back-end databases */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include <sys/stat.h> + #include "slap.h" +#include "lutil.h" -#ifdef LDAP_LDBM -extern int ldbm_back_bind(); -extern int ldbm_back_unbind(); -extern int ldbm_back_search(); -extern int ldbm_back_compare(); -extern int ldbm_back_modify(); -extern int ldbm_back_modrdn(); -extern int ldbm_back_add(); -extern int ldbm_back_delete(); -extern int ldbm_back_abandon(); -extern int ldbm_back_config(); -extern int ldbm_back_init(); -extern int ldbm_back_close(); -#endif - -#ifdef LDAP_PASSWD -extern int passwd_back_search(); -extern int passwd_back_config(); -#endif - -#ifdef LDAP_SHELL -extern int shell_back_bind(); -extern int shell_back_unbind(); -extern int shell_back_search(); -extern int shell_back_compare(); -extern int shell_back_modify(); -extern int shell_back_modrdn(); -extern int shell_back_add(); -extern int shell_back_delete(); -extern int shell_back_abandon(); -extern int shell_back_config(); -extern int shell_back_init(); -#endif - -extern int defsize; -extern int deftime; - -#define BACKEND_GRAB_SIZE 10 - -int nbackends; -Backend *backends; -static int maxbackends; +/* + * If a module is configured as dynamic, its header should not + * get included into slapd. While this is a general rule and does + * not have much of an effect in UNIX, this rule should be adhered + * to for Windows, where dynamic object code should not be implicitly + * imported into slapd without appropriate __declspec(dllimport) directives. + */ -Backend * -new_backend( - char *type +#if defined(SLAPD_BDB) && !defined(SLAPD_BDB_DYNAMIC) +#include "back-bdb/external.h" +#endif +#if defined(SLAPD_DNSSRV) && !defined(SLAPD_DNSSRV_DYNAMIC) +#include "back-dnssrv/external.h" +#endif +#if defined(SLAPD_LDAP) && !defined(SLAPD_LDAP_DYNAMIC) +#include "back-ldap/external.h" +#endif +#if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC) +#include "back-ldbm/external.h" +#endif +#if defined(SLAPD_META) && !defined(SLAPD_META_DYNAMIC) +#include "back-meta/external.h" +#endif +#if defined(SLAPD_MONITOR) && !defined(SLAPD_MONITOR_DYNAMIC) +#include "back-monitor/external.h" +#endif +#if defined(SLAPD_NULL) && !defined(SLAPD_NULL_DYNAMIC) +#include "back-null/external.h" +#endif +#if defined(SLAPD_PASSWD) && !defined(SLAPD_PASSWD_DYNAMIC) +#include "back-passwd/external.h" +#endif +#if defined(SLAPD_PERL) && !defined(SLAPD_PERL_DYNAMIC) +#include "back-perl/external.h" +#endif +#if defined(SLAPD_SHELL) && !defined(SLAPD_SHELL_DYNAMIC) +#include "back-shell/external.h" +#endif +#if defined(SLAPD_TCL) && !defined(SLAPD_TCL_DYNAMIC) +#include "back-tcl/external.h" +#endif +#if defined(SLAPD_SQL) && !defined(SLAPD_SQL_DYNAMIC) +#include "back-sql/external.h" +#endif +#if defined(SLAPD_PRIVATE) && !defined(SLAPD_PRIVATE_DYNAMIC) +#include "private/external.h" +#endif + +static BackendInfo binfo[] = { +#if defined(SLAPD_BDB) && !defined(SLAPD_BDB_DYNAMIC) + {"bdb", bdb_initialize}, +#endif +#if defined(SLAPD_DNSSRV) && !defined(SLAPD_DNSSRV_DYNAMIC) + {"dnssrv", dnssrv_back_initialize}, +#endif +#if defined(SLAPD_LDAP) && !defined(SLAPD_LDAP_DYNAMIC) + {"ldap", ldap_back_initialize}, +#endif +#if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC) + {"ldbm", ldbm_back_initialize}, +#endif +#if defined(SLAPD_META) && !defined(SLAPD_META_DYNAMIC) + {"meta", meta_back_initialize}, +#endif +#if defined(SLAPD_MONITOR) && !defined(SLAPD_MONITOR_DYNAMIC) + {"monitor", monitor_back_initialize}, +#endif +#if defined(SLAPD_NULL) && !defined(SLAPD_NULL_DYNAMIC) + {"null", null_back_initialize}, +#endif +#if defined(SLAPD_PASSWD) && !defined(SLAPD_PASSWD_DYNAMIC) + {"passwd", passwd_back_initialize}, +#endif +#if defined(SLAPD_PERL) && !defined(SLAPD_PERL_DYNAMIC) + {"perl", perl_back_initialize}, +#endif +#if defined(SLAPD_SHELL) && !defined(SLAPD_SHELL_DYNAMIC) + {"shell", shell_back_initialize}, +#endif +#if defined(SLAPD_TCL) && !defined(SLAPD_TCL_DYNAMIC) + {"tcl", tcl_back_initialize}, +#endif +#if defined(SLAPD_SQL) && !defined(SLAPD_SQL_DYNAMIC) + {"sql", sql_back_initialize}, +#endif + /* for any private backend */ +#if defined(SLAPD_PRIVATE) && !defined(SLAPD_PRIVATE_DYNAMIC) + {"private", private_back_initialize}, +#endif + {NULL} +}; + +int nBackendInfo = 0; +BackendInfo *backendInfo = NULL; + +int nBackendDB = 0; +BackendDB *backendDB = NULL; + +int backend_init(void) +{ + int rc = -1; + + if((nBackendInfo != 0) || (backendInfo != NULL)) { + /* already initialized */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "backend_init: backend already initialized\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_init: already initialized.\n", 0, 0, 0 ); +#endif + return -1; + } + + for( ; + binfo[nBackendInfo].bi_type != NULL; + nBackendInfo++ ) + { + rc = binfo[nBackendInfo].bi_init( &binfo[nBackendInfo] ); + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "backend_init: initialized for type \"%s\"\n", + binfo[nBackendInfo].bi_type )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_init: initialized for type \"%s\"\n", + binfo[nBackendInfo].bi_type, 0, 0 ); +#endif + /* destroy those we've already inited */ + for( nBackendInfo--; + nBackendInfo >= 0 ; + nBackendInfo-- ) + { + if ( binfo[nBackendInfo].bi_destroy ) { + binfo[nBackendInfo].bi_destroy( + &binfo[nBackendInfo] ); + } + } + return rc; + } + } + + if ( nBackendInfo > 0) { + backendInfo = binfo; + return 0; + } + +#ifdef SLAPD_MODULES + return 0; +#else + +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "backend_init: failed\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_init: failed\n", + 0, 0, 0 ); +#endif + + return rc; +#endif /* SLAPD_MODULES */ +} + +int backend_add(BackendInfo *aBackendInfo) +{ + int rc = 0; + + if ((rc = aBackendInfo->bi_init(aBackendInfo)) != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_ERR, + "backend_add: initialization for type \"%s\" failed\n", + aBackendInfo->bi_type )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_add: initialization for type \"%s\" failed\n", + aBackendInfo->bi_type, 0, 0 ); +#endif + return rc; + } + + /* now add the backend type to the Backend Info List */ + { + BackendInfo *newBackendInfo = 0; + + /* if backendInfo == binfo no deallocation of old backendInfo */ + if (backendInfo == binfo) { + newBackendInfo = ch_calloc(nBackendInfo + 1, sizeof(BackendInfo)); + AC_MEMCPY(newBackendInfo, backendInfo, sizeof(BackendInfo) * + nBackendInfo); + } else { + newBackendInfo = ch_realloc(backendInfo, sizeof(BackendInfo) * + (nBackendInfo + 1)); + } + AC_MEMCPY(&newBackendInfo[nBackendInfo], aBackendInfo, + sizeof(BackendInfo)); + backendInfo = newBackendInfo; + nBackendInfo++; + + return 0; + } +} + +int backend_startup(Backend *be) +{ + int i; + int rc = 0; + + if( ! ( nBackendDB > 0 ) ) { + /* no databases */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_INFO, + "backend_startup: %d databases to startup. \n", + nBackendDB )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_startup: %d databases to startup.\n", + nBackendDB, 0, 0 ); +#endif + return 1; + } + + if(be != NULL) { + /* startup a specific backend database */ +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, + "backend_startup: starting \"%s\"\n", + be->be_suffix[0]->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "backend_startup: starting \"%s\"\n", + be->be_suffix[0]->bv_val, 0, 0 ); +#endif + + if ( be->bd_info->bi_open ) { + rc = be->bd_info->bi_open( be->bd_info ); + } + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_CRIT, + "backend_startup: bi_open failed!\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_startup: bi_open failed!\n", + 0, 0, 0 ); +#endif + + return rc; + } + + if ( be->bd_info->bi_db_open ) { + rc = be->bd_info->bi_db_open( be ); + } + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_CRIT, + "backend_startup: bi_db_open failed! (%d)\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_startup: bi_db_open failed! (%d)\n", + rc, 0, 0 ); +#endif + return rc; + } + + return rc; + } + + /* open each backend type */ + for( i = 0; i < nBackendInfo; i++ ) { + if( backendInfo[i].bi_nDB == 0) { + /* no database of this type, don't open */ + continue; + } + + if( backendInfo[i].bi_open ) { + rc = backendInfo[i].bi_open( + &backendInfo[i] ); + } + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_CRIT, + "backend_startup: bi_open %d failed!\n", i )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_startup: bi_open %d failed!\n", + i, 0, 0 ); +#endif + return rc; + } + } + + /* open each backend database */ + for( i = 0; i < nBackendDB; i++ ) { + /* append global access controls */ + acl_append( &backendDB[i].be_acl, global_acl ); + + if ( backendDB[i].bd_info->bi_db_open ) { + rc = backendDB[i].bd_info->bi_db_open( + &backendDB[i] ); + } + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_CRIT, + "backend_startup: bi_db_open(%d) failed! (%d)\n", + i, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_startup: bi_db_open(%d) failed! (%d)\n", + i, rc, 0 ); +#endif + return rc; + } + } + + return rc; +} + +int backend_num( Backend *be ) +{ + int i; + + if( be == NULL ) return -1; + + for( i = 0; i < nBackendDB; i++ ) { + if( be == &backendDB[i] ) return i; + } + return -1; +} + +int backend_shutdown( Backend *be ) +{ + int i; + int rc = 0; + + if( be != NULL ) { + /* shutdown a specific backend database */ + + if ( be->bd_info->bi_nDB == 0 ) { + /* no database of this type, we never opened it */ + return 0; + } + + if ( be->bd_info->bi_db_close ) { + be->bd_info->bi_db_close( be ); + } + + if( be->bd_info->bi_close ) { + be->bd_info->bi_close( be->bd_info ); + } + + return 0; + } + + /* close each backend database */ + for( i = 0; i < nBackendDB; i++ ) { + if ( backendDB[i].bd_info->bi_db_close ) { + backendDB[i].bd_info->bi_db_close( + &backendDB[i] ); + } + + if(rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_NOTICE, + "backend_shutdown: bi_close %s failed!\n", + backendDB[i].be_type )); +#else + Debug( LDAP_DEBUG_ANY, + "backend_close: bi_close %s failed!\n", + backendDB[i].be_type, 0, 0 ); +#endif + } + } + + /* close each backend type */ + for( i = 0; i < nBackendInfo; i++ ) { + if( backendInfo[i].bi_nDB == 0 ) { + /* no database of this type */ + continue; + } + + if( backendInfo[i].bi_close ) { + backendInfo[i].bi_close( + &backendInfo[i] ); + } + } + + return 0; +} + +int backend_destroy(void) +{ + int i; + BackendDB *bd; + + /* destroy each backend database */ + for( i = 0, bd = backendDB; i < nBackendDB; i++, bd++ ) { + if ( bd->bd_info->bi_db_destroy ) { + bd->bd_info->bi_db_destroy( bd ); + } + ber_bvecfree( bd->be_suffix ); + ber_bvecfree( bd->be_nsuffix ); + if ( bd->be_rootdn.bv_val ) free( bd->be_rootdn.bv_val ); + if ( bd->be_rootndn.bv_val ) free( bd->be_rootndn.bv_val ); + if ( bd->be_rootpw.bv_val ) free( bd->be_rootpw.bv_val ); + acl_destroy( bd->be_acl, global_acl ); + } + free( backendDB ); + + /* destroy each backend type */ + for( i = 0; i < nBackendInfo; i++ ) { + if( backendInfo[i].bi_destroy ) { + backendInfo[i].bi_destroy( + &backendInfo[i] ); + } + } + +#ifdef SLAPD_MODULES + if (backendInfo != binfo) { + free(backendInfo); + } +#endif /* SLAPD_MODULES */ + + nBackendInfo = 0; + backendInfo = NULL; + + return 0; +} + +BackendInfo* backend_info(const char *type) +{ + int i; + + /* search for the backend type */ + for( i = 0; i < nBackendInfo; i++ ) { + if( strcasecmp(backendInfo[i].bi_type, type) == 0 ) { + return &backendInfo[i]; + } + } + + return NULL; +} + + +BackendDB * +backend_db_init( + const char *type ) { Backend *be; - int foundit; + BackendInfo *bi = backend_info(type); + int rc = 0; - if ( nbackends == maxbackends ) { - maxbackends += BACKEND_GRAB_SIZE; - backends = (Backend *) ch_realloc( (char *) backends, - maxbackends * sizeof(Backend) ); - memset( &backends[nbackends], '\0', BACKEND_GRAB_SIZE * - sizeof(Backend) ); + if( bi == NULL ) { + fprintf( stderr, "Unrecognized database type (%s)\n", type ); + return NULL; } + backendDB = (BackendDB *) ch_realloc( + (char *) backendDB, + (nBackendDB + 1) * sizeof(Backend) ); + + memset( &backendDB[nbackends], '\0', sizeof(Backend) ); + be = &backends[nbackends++]; - be->be_sizelimit = defsize; - be->be_timelimit = deftime; - foundit = 0; - -#ifdef LDAP_LDBM - if ( strcasecmp( type, "ldbm" ) == 0 ) { - be->be_bind = ldbm_back_bind; - be->be_unbind = ldbm_back_unbind; - be->be_search = ldbm_back_search; - be->be_compare = ldbm_back_compare; - be->be_modify = ldbm_back_modify; - be->be_modrdn = ldbm_back_modrdn; - be->be_add = ldbm_back_add; - be->be_delete = ldbm_back_delete; - be->be_abandon = ldbm_back_abandon; - be->be_config = ldbm_back_config; - be->be_init = ldbm_back_init; - be->be_close = ldbm_back_close; - be->be_type = "ldbm"; - foundit = 1; - } -#endif - -#ifdef LDAP_PASSWD - if ( strcasecmp( type, "passwd" ) == 0 ) { - be->be_bind = NULL; - be->be_unbind = NULL; - be->be_search = passwd_back_search; - be->be_compare = NULL; - be->be_modify = NULL; - be->be_modrdn = NULL; - be->be_add = NULL; - be->be_delete = NULL; - be->be_abandon = NULL; - be->be_config = passwd_back_config; - be->be_init = NULL; - be->be_close = NULL; - be->be_type = "passwd"; - foundit = 1; - } -#endif - -#ifdef LDAP_SHELL - if ( strcasecmp( type, "shell" ) == 0 ) { - be->be_bind = shell_back_bind; - be->be_unbind = shell_back_unbind; - be->be_search = shell_back_search; - be->be_compare = shell_back_compare; - be->be_modify = shell_back_modify; - be->be_modrdn = shell_back_modrdn; - be->be_add = shell_back_add; - be->be_delete = shell_back_delete; - be->be_abandon = shell_back_abandon; - be->be_config = shell_back_config; - be->be_init = shell_back_init; - be->be_close = NULL; - be->be_type = "shell"; - foundit = 1; - } -#endif - - if ( be->be_init != NULL ) { - (*be->be_init)( be ); - } - - if ( foundit == 0 ) { - fprintf( stderr, "Unrecognized database type (%s)\n", type ); - exit( 1 ); + + be->bd_info = bi; + be->be_def_limit = deflimit; + be->be_dfltaccess = global_default_access; + + be->be_restrictops = global_restrictops; + be->be_requires = global_requires; + be->be_ssf_set = global_ssf_set; + + /* assign a default depth limit for alias deref */ + be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; + + if(bi->bi_db_init) { + rc = bi->bi_db_init( be ); } + if(rc != 0) { + fprintf( stderr, "database init failed (%s)\n", type ); + nbackends--; + return NULL; + } + + bi->bi_nDB++; return( be ); } +void +be_db_close( void ) +{ + int i; + + for ( i = 0; i < nbackends; i++ ) { + if ( backends[i].bd_info->bi_db_close ) { + (*backends[i].bd_info->bi_db_close)( &backends[i] ); + } + } +} + Backend * -select_backend( char * dn ) +select_backend( + struct berval * dn, + int manageDSAit, + int noSubs ) { - int i, j, len, dnlen; + int i, j; + ber_len_t len, dnlen = dn->bv_len; + Backend *be = NULL; - dnlen = strlen( dn ); for ( i = 0; i < nbackends; i++ ) { - for ( j = 0; backends[i].be_suffix != NULL && - backends[i].be_suffix[j] != NULL; j++ ) { - len = strlen( backends[i].be_suffix[j] ); + for ( j = 0; backends[i].be_nsuffix != NULL && + backends[i].be_nsuffix[j] != NULL; j++ ) + { + if (( backends[i].be_flags & SLAP_BFLAG_GLUE_SUBORDINATE ) + && noSubs ) + { + continue; + } + + len = backends[i].be_nsuffix[j]->bv_len; if ( len > dnlen ) { + /* suffix is longer than DN */ continue; } + + /* + * input DN is normalized, so the separator check + * need not look at escaping + */ + if ( len && len < dnlen && + !DN_SEPARATOR( dn->bv_val[(dnlen-len)-1] )) + { + continue; + } + + if ( strcmp( backends[i].be_nsuffix[j]->bv_val, + &dn->bv_val[dnlen-len] ) == 0 ) + { + if( be == NULL ) { + be = &backends[i]; - if ( strcasecmp( backends[i].be_suffix[j], - dn + (dnlen - len) ) == 0 ) { - return( &backends[i] ); + if( manageDSAit && len == dnlen ) { + continue; + } + } else { + be = &backends[i]; + } + return be; } } } - return( NULL ); + return be; } int be_issuffix( Backend *be, - char *suffix + struct berval *bvsuffix ) { int i; - for ( i = 0; be->be_suffix != NULL && be->be_suffix[i] != NULL; i++ ) { - if ( strcasecmp( be->be_suffix[i], suffix ) == 0 ) { + for ( i = 0; be->be_nsuffix != NULL && be->be_nsuffix[i] != NULL; i++ ) { + if ( ber_bvcmp( be->be_nsuffix[i], bvsuffix ) == 0 ) { return( 1 ); } } @@ -184,41 +602,94 @@ be_issuffix( } int -be_isroot( Backend *be, char *dn ) +be_isroot( Backend *be, struct berval *ndn ) { - if ( dn == NULL ) { + if ( !ndn->bv_len ) { return( 0 ); } - return( be->be_rootdn ? strcasecmp( be->be_rootdn, dn ) == 0 - : 0 ); + if ( !be->be_rootndn.bv_len ) { + return( 0 ); + } + + return dn_match( &be->be_rootndn, ndn ); } int -be_isroot_pw( Backend *be, char *dn, struct berval *cred ) +be_isupdate( Backend *be, struct berval *ndn ) { - if ( ! be_isroot( be, dn ) || be->be_rootpw == NULL ) { + if ( !ndn->bv_len ) { return( 0 ); } - return( strcmp( be->be_rootpw, cred->bv_val ) == 0 ); + if ( !be->be_update_ndn.bv_len ) { + return( 0 ); + } + + return dn_match( &be->be_update_ndn, ndn ); } -void -be_close() +struct berval * +be_root_dn( Backend *be ) { - int i; + return &be->be_rootdn; +} - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_close != NULL ) { - (*backends[i].be_close)( &backends[i] ); - } +int +be_isroot_pw( Backend *be, + Connection *conn, + struct berval *ndn, + struct berval *cred ) +{ + int result; + + if ( ! be_isroot( be, ndn ) ) { + return 0; + } + + if( be->be_rootpw.bv_len == 0 ) { + return 0; } + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) + ldap_pvt_thread_mutex_lock( &passwd_mutex ); +#ifdef SLAPD_SPASSWD + lutil_passwd_sasl_conn = conn->c_sasl_context; +#endif +#endif + + result = lutil_passwd( &be->be_rootpw, cred, NULL ); + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) +#ifdef SLAPD_SPASSWD + lutil_passwd_sasl_conn = NULL; +#endif + ldap_pvt_thread_mutex_unlock( &passwd_mutex ); +#endif + + return result == 0; } +int +be_entry_release_rw( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e, + int rw ) +{ + if ( be->be_release ) { + /* free and release entry from backend */ + return be->be_release( be, conn, op, e, rw ); + } else { + /* free entry */ + entry_free( e ); + return 0; + } +} -void -be_unbind( +int +backend_unbind( Connection *conn, Operation *op ) @@ -226,8 +697,406 @@ be_unbind( int i; for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_unbind != NULL ) { + if ( backends[i].be_unbind ) { (*backends[i].be_unbind)( &backends[i], conn, op ); } } + + return 0; +} + +int +backend_connection_init( + Connection *conn +) +{ + int i; + + for ( i = 0; i < nbackends; i++ ) { + if ( backends[i].be_connection_init ) { + (*backends[i].be_connection_init)( &backends[i], conn); + } + } + + return 0; +} + +int +backend_connection_destroy( + Connection *conn +) +{ + int i; + + for ( i = 0; i < nbackends; i++ ) { + if ( backends[i].be_connection_destroy ) { + (*backends[i].be_connection_destroy)( &backends[i], conn); + } + } + + return 0; +} + +static int +backend_check_controls( + Backend *be, + Connection *conn, + Operation *op, + const char **text ) +{ + LDAPControl **ctrls; + ctrls = op->o_ctrls; + if( ctrls == NULL ) { + return LDAP_SUCCESS; + } + + for( ; *ctrls != NULL ; ctrls++ ) { + if( (*ctrls)->ldctl_iscritical && + !charray_inlist( be->be_controls, (*ctrls)->ldctl_oid ) ) + { + *text = "control unavailable in context"; + return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + } + } + + return LDAP_SUCCESS; } + +int +backend_check_restrictions( + Backend *be, + Connection *conn, + Operation *op, + const void *opdata, + const char **text ) +{ + int rc; + slap_mask_t restrictops; + slap_mask_t requires; + slap_mask_t opflag; + slap_ssf_set_t *ssf; + int updateop = 0; + + if( be ) { + rc = backend_check_controls( be, conn, op, text ); + + if( rc != LDAP_SUCCESS ) { + return rc; + } + + restrictops = be->be_restrictops; + requires = be->be_requires; + ssf = &be->be_ssf_set; + + } else { + restrictops = global_restrictops; + requires = global_requires; + ssf = &global_ssf_set; + } + + switch( op->o_tag ) { + case LDAP_REQ_ADD: + opflag = SLAP_RESTRICT_OP_ADD; + updateop++; + break; + case LDAP_REQ_BIND: + opflag = SLAP_RESTRICT_OP_BIND; + break; + case LDAP_REQ_COMPARE: + opflag = SLAP_RESTRICT_OP_COMPARE; + break; + case LDAP_REQ_DELETE: + updateop++; + opflag = SLAP_RESTRICT_OP_DELETE; + break; + case LDAP_REQ_EXTENDED: + opflag = SLAP_RESTRICT_OP_EXTENDED; + break; + case LDAP_REQ_MODIFY: + updateop++; + opflag = SLAP_RESTRICT_OP_MODIFY; + break; + case LDAP_REQ_RENAME: + updateop++; + opflag = SLAP_RESTRICT_OP_RENAME; + break; + case LDAP_REQ_SEARCH: + opflag = SLAP_RESTRICT_OP_SEARCH; + break; + case LDAP_REQ_UNBIND: + opflag = 0; + break; + default: + *text = "restrict operations internal error"; + return LDAP_OTHER; + } + + if ( op->o_tag != LDAP_REQ_EXTENDED + || strcmp( (const char *) opdata, LDAP_EXOP_START_TLS ) ) + { + /* these checks don't apply to StartTLS */ + + if( op->o_tag == LDAP_REQ_EXTENDED ) { + /* threat other extended operations as update ops */ + updateop++; + } + + if( op->o_transport_ssf < ssf->sss_transport ) { + *text = "transport confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_tls_ssf < ssf->sss_tls ) { + *text = "TLS confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_tag != LDAP_REQ_BIND || opdata == NULL ) { + /* these checks don't apply to SASL bind */ + + if( op->o_sasl_ssf < ssf->sss_sasl ) { + *text = "SASL confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_ssf < ssf->sss_ssf ) { + *text = "confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + } + + if( updateop ) { + if( op->o_transport_ssf < ssf->sss_update_transport ) { + *text = "transport update confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_tls_ssf < ssf->sss_update_tls ) { + *text = "TLS update confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_sasl_ssf < ssf->sss_update_sasl ) { + *text = "SASL update confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_ssf < ssf->sss_update_ssf ) { + *text = "update confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + + if( op->o_ndn.bv_len == 0 ) { + *text = "modifications require authentication"; + return LDAP_OPERATIONS_ERROR; + } + } + } + + if ( op->o_tag != LDAP_REQ_BIND && ( op->o_tag != LDAP_REQ_EXTENDED || + strcmp( (const char *) opdata, LDAP_EXOP_START_TLS ) ) ) + { + /* these checks don't apply to Bind or StartTLS */ + + if( requires & SLAP_REQUIRE_STRONG ) { + /* should check mechanism */ + if( op->o_authmech.bv_len == 0 || op->o_dn.bv_len == 0 ) + { + *text = "strong authentication required"; + return LDAP_STRONG_AUTH_REQUIRED; + } + } + + if( requires & SLAP_REQUIRE_SASL ) { + if( op->o_authmech.bv_len == 0 || op->o_dn.bv_len == 0 ) + { + *text = "SASL authentication required"; + return LDAP_STRONG_AUTH_REQUIRED; + } + } + + if( requires & SLAP_REQUIRE_AUTHC ) { + if( op->o_dn.bv_len == 0 ) { + *text = "authentication required"; + return LDAP_UNWILLING_TO_PERFORM; + } + } + + if( requires & SLAP_REQUIRE_BIND ) { + int version; + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + version = conn->c_protocol; + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + if( !version ) { + /* no bind has occurred */ + *text = "BIND required"; + return LDAP_OPERATIONS_ERROR; + } + } + + if( requires & SLAP_REQUIRE_LDAP_V3 ) { + if( op->o_protocol < LDAP_VERSION3 ) { + /* no bind has occurred */ + *text = "operation restricted to LDAPv3 clients"; + return LDAP_OPERATIONS_ERROR; + } + } + } + + if( restrictops & opflag ) { + if( restrictops == SLAP_RESTRICT_OP_READS ) { + *text = "read operations restricted"; + } else { + *text = "operation restricted"; + } + return LDAP_UNWILLING_TO_PERFORM; + } + + return LDAP_SUCCESS; +} + +int backend_check_referrals( + Backend *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn ) +{ + int rc = LDAP_SUCCESS; + + if( be->be_chk_referrals ) { + const char *text; + + rc = be->be_chk_referrals( be, + conn, op, dn, ndn, &text ); + + if( rc != LDAP_SUCCESS && rc != LDAP_REFERRAL ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + } + } + + return rc; +} + +int +backend_group( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at +) +{ + GroupAssertion *g; + + if ( op->o_abandon ) return SLAPD_ABANDON; + + if ( !dn_match( &target->e_nname, gr_ndn ) ) { + /* we won't attempt to send it to a different backend */ + + be = select_backend( gr_ndn, 0, 0 ); + + if (be == NULL) { + return LDAP_NO_SUCH_OBJECT; + } + } + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + for (g = conn->c_groups; g; g=g->ga_next) { + if (g->ga_be != be || g->ga_oc != group_oc || + g->ga_at != group_at || g->ga_len != gr_ndn->bv_len) + continue; + if (strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0) + break; + } + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + if (g) { + return g->ga_res; + } + + if( be->be_group ) { + int res = be->be_group( be, conn, op, + target, gr_ndn, op_ndn, + group_oc, group_at ); + + if (op->o_tag != LDAP_REQ_BIND) { + g = ch_malloc(sizeof(GroupAssertion) + gr_ndn->bv_len); + g->ga_be = be; + g->ga_oc = group_oc; + g->ga_at = group_at; + g->ga_res = res; + g->ga_len = gr_ndn->bv_len; + strcpy(g->ga_ndn, gr_ndn->bv_val); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + g->ga_next = conn->c_groups; + conn->c_groups = g; + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + } + + return res; + } + + return LDAP_UNWILLING_TO_PERFORM; +} + +int +backend_attribute( + Backend *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *edn, + AttributeDescription *entry_at, + BerVarray *vals +) +{ + if ( target == NULL || !dn_match( &target->e_nname, edn ) ) { + /* we won't attempt to send it to a different backend */ + + be = select_backend( edn, 0, 0 ); + + if (be == NULL) { + return LDAP_NO_SUCH_OBJECT; + } + } + + if( be->be_attribute ) { + return be->be_attribute( be, conn, op, target, edn, + entry_at, vals ); + } + + return LDAP_UNWILLING_TO_PERFORM; +} + +Attribute *backend_operational( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + AttributeName *attrs, + int opattrs ) +{ + Attribute *a = NULL, **ap = &a; + +#ifdef SLAPD_SCHEMA_DN + *ap = slap_operational_subschemaSubentry(); + ap = &(*ap)->a_next; +#endif + + /* + * If operational attributes (allegedly) are required, + * and the backend supports specific operational attributes, + * add them to the attribute list + */ + if ( ( opattrs || attrs ) && be && be->be_operational != NULL ) { + ( void )be->be_operational( be, conn, op, e, attrs, opattrs, ap ); + } + + return a; +} + diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c index 4b0b49000f8e2845667a452d7fc704eb00cfd74d..0eccc8b8ac9cf75071e081c456cd9a20f37be7ec 100644 --- a/servers/slapd/backglue.c +++ b/servers/slapd/backglue.c @@ -97,7 +97,7 @@ glue_back_close ( ) { static int glueClosed = 0; - int rc; + int rc = 0; if (glueClosed) return 0; @@ -292,7 +292,7 @@ glue_back_search ( { glueinfo *gi = (glueinfo *)b0->be_private; BackendDB *be; - int i, rc, t2limit = 0, s2limit = 0; + int i, rc = 0, t2limit = 0, s2limit = 0; long stoptime = 0; struct berval bv; glue_state gs = {0}; @@ -327,6 +327,7 @@ glue_back_search ( case LDAP_SCOPE_ONELEVEL: case LDAP_SCOPE_SUBTREE: op->o_callback = &cb; + rc = gs.err = LDAP_UNWILLING_TO_PERFORM; /* * Execute in reverse order, most general first @@ -336,22 +337,23 @@ glue_back_search ( continue; if (tlimit) { t2limit = stoptime - slap_get_time (); - if (t2limit <= 0) + if (t2limit <= 0) { + rc = gs.err = LDAP_TIMELIMIT_EXCEEDED; break; + } } if (slimit) { s2limit = slimit - gs.nentries; - if (s2limit <= 0) + if (s2limit <= 0) { + rc = gs.err = LDAP_SIZELIMIT_EXCEEDED; break; + } } + rc = 0; /* * check for abandon */ - ldap_pvt_thread_mutex_lock (&op->o_abandonmutex); - rc = op->o_abandon; - ldap_pvt_thread_mutex_unlock (&op->o_abandonmutex); - if (rc) { - rc = 0; + if (op->o_abandon) { goto done; } be = gi->n[i].be; @@ -808,7 +810,7 @@ glue_sub_init( ) int i, j; int cont = num_subordinates; BackendDB *b1, *be; - BackendInfo *bi; + BackendInfo *bi = NULL; glueinfo *gi; /* While there are subordinate backends, search backwards through the diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 562ce5b54ab6c08665074201735a7ab76cc798a2..b2b4d32b4a298df0358da2694f1b4db6cba1c30b 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -1,4 +1,9 @@ /* bind.c - decode an ldap bind operation and pass it to a backend db */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. @@ -12,29 +17,61 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -extern Backend *select_backend(); +#include <ac/string.h> +#include <ac/socket.h> -extern char *default_referral; +#include "ldap_pvt.h" +#include "slap.h" -void +int do_bind( Connection *conn, Operation *op ) { - BerElement *ber = op->o_ber; - int version, method, len, rc; - char *dn; - struct berval cred; - Backend *be; + BerElement *ber = op->o_ber; + ber_int_t version; + ber_tag_t method; + struct berval mech = { 0, NULL }; + struct berval dn = { 0, NULL }; + struct berval pdn = { 0, NULL }; + struct berval ndn = { 0, NULL }; + struct berval edn = { 0, NULL }; + ber_tag_t tag; + int rc = LDAP_SUCCESS; + const char *text; + struct berval cred = { 0, NULL }; + Backend *be; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_bind: conn %d\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 ); +#endif + + /* + * Force to connection to "anonymous" until bind succeeds. + */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + connection2anonymous( conn ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + if ( op->o_dn.bv_val != NULL ) { + free( op->o_dn.bv_val ); + op->o_dn.bv_val = ch_strdup( "" ); + op->o_dn.bv_len = 0; + } + + if ( op->o_ndn.bv_val != NULL ) { + free( op->o_ndn.bv_val ); + op->o_ndn.bv_val = ch_strdup( "" ); + op->o_ndn.bv_len = 0; + } /* * Parse the bind request. It looks like this: @@ -45,90 +82,366 @@ do_bind( * authentication CHOICE { * simple [0] OCTET STRING -- passwd * krbv42ldap [1] OCTET STRING - * krbv42dsa [1] OCTET STRING + * krbv42dsa [2] OCTET STRING + * SASL [3] SaslCredentials * } + * } + * + * SaslCredentials ::= SEQUENCE { + * mechanism LDAPString, + * credentials OCTET STRING OPTIONAL * } */ -#ifdef COMPAT30 - /* - * in version 3.0 there is an extra SEQUENCE tag after the - * BindRequest SEQUENCE tag. - */ + tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method ); + + if ( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_bind: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = -1; + goto cleanup; + } + + op->o_protocol = version; + + if( method != LDAP_AUTH_SASL ) { + tag = ber_scanf( ber, /*{*/ "m}", &cred ); - { - BerElement tber; - unsigned long tlen, ttag; - - tber = *op->o_ber; - ttag = ber_skip_tag( &tber, &tlen ); - if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) { - Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n", 0, 0, 0 ); - conn->c_version = 30; - rc = ber_scanf(ber, "{{iato}}", &version, &dn, &method, &cred); } else { - rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred ); + tag = ber_scanf( ber, "{o" /*}*/, &mech ); + + if ( tag != LBER_ERROR ) { + ber_len_t len; + tag = ber_peek_tag( ber, &len ); + + if ( tag == LDAP_TAG_LDAPCRED ) { + tag = ber_scanf( ber, "m", &cred ); + } else { + tag = LDAP_TAG_LDAPCRED; + cred.bv_val = NULL; + cred.bv_len = 0; + } + + if ( tag != LBER_ERROR ) { + tag = ber_scanf( ber, /*{{*/ "}}" ); + } + } + } + + if ( tag == LBER_ERROR ) { + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, + "decoding error" ); + rc = SLAPD_DISCONNECT; + goto cleanup; } + + if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d get_ctrls failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 ); +#endif + goto cleanup; + } + + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d invalid dn (%s)\n", + conn->c_connid, dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n", + dn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto cleanup; } + + if( method == LDAP_AUTH_SASL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_sasl_bind: conn %d dn (%s) mech %s\n", conn->c_connid, + pdn.bv_val, mech.bv_val )); #else - rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred ); + Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n", + pdn.bv_val, mech.bv_val, NULL ); #endif - if ( rc == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, - "decoding error" ); - return; - } -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - switch ( method ) { - case LDAP_AUTH_SIMPLE_30: - method = LDAP_AUTH_SIMPLE; - break; -#ifdef KERBEROS - case LDAP_AUTH_KRBV41_30: - method = LDAP_AUTH_KRBV41; - break; - case LDAP_AUTH_KRBV42_30: - method = LDAP_AUTH_KRBV42; - break; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_bind: conn %d version=%ld dn=\"%s\" method=%ld\n", + conn->c_connid, (unsigned long) version, + pdn.bv_val, (unsigned long)method )); +#else + Debug( LDAP_DEBUG_TRACE, + "do_bind: version=%ld dn=\"%s\" method=%ld\n", + (unsigned long) version, + pdn.bv_val, (unsigned long) method ); #endif - } } -#endif /* compat30 */ - dn_normalize( dn ); - Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n", - conn->c_connid, op->o_opid, dn, method, 0 ); + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu BIND dn=\"%s\" method=%ld\n", + op->o_connid, op->o_opid, pdn.bv_val, (unsigned long) method, 0 ); + + if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d unknown version = %ld\n", + conn->c_connid, (unsigned long)version )); +#else + Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n", + (unsigned long) version, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "requested protocol version not supported", NULL, NULL ); + goto cleanup; + + } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) && + version < LDAP_VERSION3 ) + { + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "requested protocol version not allowed", NULL, NULL ); + goto cleanup; + } + + /* we set connection version regardless of whether bind succeeds + * or not. + */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + conn->c_protocol = version; + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + /* check for inappropriate controls */ + if( get_manageDSAit( op ) == SLAP_CRITICAL_CONTROL ) { + send_ldap_result( conn, op, + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION, + NULL, "manageDSAit control inappropriate", + NULL, NULL ); + goto cleanup; + } + + if ( method == LDAP_AUTH_SASL ) { + slap_ssf_t ssf = 0; + + if ( version < LDAP_VERSION3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d sasl with LDAPv%ld\n", + conn->c_connid, (unsigned long)version )); +#else + Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n", + (unsigned long) version, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } - if ( version != LDAP_VERSION2 ) { - if ( dn != NULL ) { - free( dn ); + if( mech.bv_len == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d no SASL mechanism provided\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "do_bind: no sasl mechanism provided\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, "no SASL mechanism provided", NULL, NULL ); + goto cleanup; } - if ( cred.bv_val != NULL ) { - free( cred.bv_val ); + + /* check restrictions */ + rc = backend_check_restrictions( NULL, conn, op, mech.bv_val, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto cleanup; } - Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, - "version not supported" ); - return; + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + if ( conn->c_sasl_bind_in_progress ) { + if((ber_bvcmp(&conn->c_sasl_bind_mech, &mech) != 0)) { + /* mechanism changed between bind steps */ + slap_sasl_reset(conn); + } + } else { + conn->c_sasl_bind_mech = mech; + mech.bv_val = NULL; + mech.bv_len = 0; + } + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + rc = slap_sasl_bind( conn, op, + &pdn, &ndn, + &cred, &edn, &ssf ); + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + if( rc == LDAP_SUCCESS ) { + conn->c_dn = edn; + if( edn.bv_len != 0 ) { + /* edn is always normalized already */ + ber_dupbv( &conn->c_ndn, &conn->c_dn ); + } + conn->c_authmech = conn->c_sasl_bind_mech; + conn->c_sasl_bind_mech.bv_val = NULL; + conn->c_sasl_bind_mech.bv_len = 0; + conn->c_sasl_bind_in_progress = 0; + + conn->c_sasl_ssf = ssf; + if( ssf > conn->c_ssf ) { + conn->c_ssf = ssf; + } + + if( conn->c_dn.bv_len != 0 ) { + ber_len_t max = sockbuf_max_incoming; + ber_sockbuf_ctrl( conn->c_sb, + LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + + } else if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) { + conn->c_sasl_bind_in_progress = 1; + + } else { + if ( conn->c_sasl_bind_mech.bv_val ) { + free( conn->c_sasl_bind_mech.bv_val ); + conn->c_sasl_bind_mech.bv_val = NULL; + conn->c_sasl_bind_mech.bv_len = 0; + } + conn->c_sasl_bind_in_progress = 0; + } + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + goto cleanup; + + } else { + /* Not SASL, cancel any in-progress bind */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + + if ( conn->c_sasl_bind_mech.bv_val != NULL ) { + free(conn->c_sasl_bind_mech.bv_val); + conn->c_sasl_bind_mech.bv_val = NULL; + conn->c_sasl_bind_mech.bv_len = 0; + } + conn->c_sasl_bind_in_progress = 0; + + slap_sasl_reset( conn ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); } - Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n", - version, dn, method ); + if ( method == LDAP_AUTH_SIMPLE ) { + /* accept "anonymous" binds */ + if ( cred.bv_len == 0 || ndn.bv_len == 0 ) { + rc = LDAP_SUCCESS; + text = NULL; + + if( cred.bv_len && + !( global_allows & SLAP_ALLOW_BIND_ANON_CRED )) + { + /* cred is not empty, disallow */ + rc = LDAP_INVALID_CREDENTIALS; + + } else if ( ndn.bv_len && + !( global_allows & SLAP_ALLOW_BIND_ANON_DN )) + { + /* DN is not empty, disallow */ + rc = LDAP_UNWILLING_TO_PERFORM; + text = "unwilling to allow anonymous bind with non-empty DN"; + + } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) { + /* disallow */ + rc = LDAP_INAPPROPRIATE_AUTH; + text = "anonymous bind disallowed"; + + } else { + rc = backend_check_restrictions( NULL, conn, op, mech.bv_val, &text ); + } + + /* + * we already forced connection to "anonymous", + * just need to send success + */ + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_bind: conn %d v%d anonymous bind\n", + conn->c_connid, version )); +#else + Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n", + version, 0, 0 ); +#endif + goto cleanup; + + } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) { + /* disallow simple authentication */ + rc = LDAP_UNWILLING_TO_PERFORM; + text = "unwilling to perform simple authentication"; - /* accept null binds */ - if ( dn == NULL || *dn == '\0' ) { - if ( dn != NULL ) { - free( dn ); + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %d v%d simple bind(%s) disallowed\n", + conn->c_connid, version, ndn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "do_bind: v%d simple bind(%s) disallowed\n", + version, ndn.bv_val, 0 ); +#endif + goto cleanup; } - if ( cred.bv_val != NULL ) { - free( cred.bv_val ); + +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND + } else if ( method == LDAP_AUTH_KRBV41 || method == LDAP_AUTH_KRBV42 ) { + if ( global_disallows & SLAP_DISALLOW_BIND_KRBV4 ) { + /* disallow simple authentication */ + rc = LDAP_UNWILLING_TO_PERFORM; + text = "unwilling to perform Kerberos V4 bind"; + + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_bind: conn %d v%d Kerberos V4 bind\n", + conn->c_connid, version )); +#else + Debug( LDAP_DEBUG_TRACE, "do_bind: v%d Kerberos V4 bind\n", + version, 0, 0 ); +#endif + goto cleanup; } +#endif + + } else { + rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; + text = "unknown authentication method"; - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); - return; + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_bind: conn %ld v%d unknown authentication method (%ld)\n", + conn->c_connid, version, method )); +#else + Debug( LDAP_DEBUG_TRACE, + "do_bind: v%d unknown authentication method (%ld)\n", + version, method, 0 ); +#endif + goto cleanup; } /* @@ -137,39 +450,102 @@ do_bind( * if we don't hold it. */ - if ( (be = select_backend( dn )) == NULL ) { - free( dn ); - if ( cred.bv_val != NULL ) { - free( cred.bv_val ); - } - if ( cred.bv_len == 0 ) { - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + if ( (be = select_backend( &ndn, 0, 0 )) == NULL ) { + if ( default_referral ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvarray_free( ref ); + } else { - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + /* noSuchObject is not allowed to be returned by bind */ + send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); } - return; + + goto cleanup; } - if ( be->be_bind != NULL ) { - if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) { - pthread_mutex_lock( &conn->c_dnmutex ); - if ( conn->c_dn != NULL ) { - free( conn->c_dn ); + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto cleanup; + } + + conn->c_authz_backend = be; + + if ( be->be_bind ) { + int ret; + + /* deref suffix alias if appropriate */ + suffix_alias( be, &ndn ); + + ret = (*be->be_bind)( be, conn, op, + &pdn, &ndn, method, &cred, &edn ); + + if ( ret == 0 ) { + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + + if(edn.bv_len) { + conn->c_dn = edn; + } else { + ber_dupbv( &conn->c_dn, &pdn ); + } + conn->c_cdn = pdn; + pdn.bv_val = NULL; + pdn.bv_len = 0; + + conn->c_ndn = ndn; + ndn.bv_val = NULL; + ndn.bv_len = 0; + + if( conn->c_dn.bv_len != 0 ) { + ber_len_t max = sockbuf_max_incoming; + ber_sockbuf_ctrl( conn->c_sb, + LBER_SB_OPT_SET_MAX_INCOMING, &max ); } - conn->c_dn = strdup( dn ); - pthread_mutex_unlock( &conn->c_dnmutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_bind: conn %d v%d bind: \"%s\" to \"%s\" \n", + conn->c_connid, version, conn->c_cdn.bv_val, conn->c_dn.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "do_bind: v%d bind: \"%s\" to \"%s\"\n", + version, conn->c_cdn.bv_val, conn->c_dn.bv_val ); +#endif + + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); /* send this here to avoid a race condition */ - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + + } else if (edn.bv_val != NULL) { + free( edn.bv_val ); } + } else { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", + NULL, NULL ); } - free( dn ); - if ( cred.bv_val != NULL ) { - free( cred.bv_val ); +cleanup: + if( pdn.bv_val != NULL ) { + free( pdn.bv_val ); } + if( ndn.bv_val != NULL ) { + free( ndn.bv_val ); + } + if ( mech.bv_val != NULL ) { + free( mech.bv_val ); + } + + return rc; } diff --git a/servers/slapd/charray.c b/servers/slapd/charray.c index 927d7e3ad9896eeb91691e5e9b4dccd2baf0d31e..e8c3dbc048d1f74a11d5f6de7b8334c8bfceef64 100644 --- a/servers/slapd/charray.c +++ b/servers/slapd/charray.c @@ -225,7 +225,7 @@ slap_strcopy( if (!a || !b) return a; - while (*a++ = *b++) ; + while ((*a++ = *b++)) ; return a-1; } diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 248c8b1ec7f9884cb49845af0d65abf065bf84a7..ead4af626e45d00cbc9611d403c19202e12178ff 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -1,3 +1,8 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. @@ -10,28 +15,46 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" +#include <ac/socket.h> -extern Backend *select_backend(); +#include "ldap_pvt.h" +#include "slap.h" -extern char *default_referral; +static int compare_entry( + Connection *conn, + Operation *op, + Entry *e, + AttributeAssertion *ava ); -void +int do_compare( Connection *conn, Operation *op ) { - char *dn; - Ava ava; - int rc; + Entry *entry = NULL; + struct berval dn = { 0, NULL }; + struct berval pdn = { 0, NULL }; + struct berval ndn = { 0, NULL }; + struct berval desc = { 0, NULL }; + struct berval value = { 0, NULL }; + AttributeAssertion ava = { 0 }; Backend *be; + int rc = LDAP_SUCCESS; + const char *text = NULL; + int manageDSAit; - Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 ); + ava.aa_desc = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_compare: conn %d\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 ); +#endif /* * Parse the compare request. It looks like this: * @@ -44,42 +67,247 @@ do_compare( * } */ - if ( ber_scanf( op->o_ber, "{a{ao}}", &dn, &ava.ava_type, - &ava.ava_value ) == LBER_ERROR ) { + if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_compare: conn %d ber_scanf failed\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" ); - return; +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + return SLAPD_DISCONNECT; } - value_normalize( ava.ava_value.bv_val, attr_syntax( ava.ava_type ) ); - dn_normalize( dn ); - Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", - dn, ava.ava_type, ava.ava_value.bv_val ); + if ( ber_scanf( op->o_ber, "{mm}", &desc, &value ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_compare: conn %d get ava failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_compare: get ava failed\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } - Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d CMP dn=\"%s\" attr=\"%s\"\n", - conn->c_connid, op->o_opid, dn, ava.ava_type, 0 ); + if ( ber_scanf( op->o_ber, /*{*/ "}" ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_compare: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } + + if( ( rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_compare: conn %d get_ctrls failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 ); +#endif + goto cleanup; + } + + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_compare: conn %d invalid dn (%s)\n", + conn->c_connid, dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_compare: invalid dn (%s)\n", dn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto cleanup; + } + + rc = slap_bv2ad( &desc, &ava.aa_desc, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + goto cleanup; + } + + rc = value_validate_normalize( ava.aa_desc, SLAP_MR_EQUALITY, + &value, &ava.aa_value, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + goto cleanup; + } + + if( strcasecmp( ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_compare: conn %d dn (%s) attr(%s) value (%s)\n", + conn->c_connid, pdn.bv_val, + ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", + pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); +#endif + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n", + op->o_connid, op->o_opid, pdn.bv_val, + ava.aa_desc->ad_cname.bv_val, 0 ); + + rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + goto cleanup; + } + + rc = root_dse_info( conn, &entry, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + goto cleanup; + } + + } else if ( strcasecmp( ndn.bv_val, SLAPD_SCHEMA_DN ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_compare: conn %d dn (%s) attr(%s) value (%s)\n", + conn->c_connid, pdn.bv_val, ava.aa_desc->ad_cname.bv_val, + ava.aa_value.bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", + pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); +#endif + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n", + op->o_connid, op->o_opid, pdn.bv_val, + ava.aa_desc->ad_cname.bv_val, 0 ); + + rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + rc = 0; + goto cleanup; + } + + rc = schema_info( &entry, &text ); + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + rc = 0; + goto cleanup; + } + } + + if( entry ) { + rc = compare_entry( conn, op, entry, &ava ); + entry_free( entry ); + + send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); + + if( rc == LDAP_COMPARE_TRUE || rc == LDAP_COMPARE_FALSE ) { + rc = 0; + } + + goto cleanup; + } + + manageDSAit = get_manageDSAit( op ); /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - if ( (be = select_backend( dn )) == NULL ) { - free( dn ); - ava_free( &ava, 0 ); + if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); - return; + ber_bvarray_free( ref ); + rc = 0; + goto cleanup; } - if ( be->be_compare != NULL ) { - (*be->be_compare)( be, conn, op, dn, &ava ); + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto cleanup; + } + + /* check for referrals */ + rc = backend_check_referrals( be, conn, op, &pdn, &ndn ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_compare: conn %d dn (%s) attr(%s) value (%s)\n", + conn->c_connid, pdn.bv_val, ava.aa_desc->ad_cname.bv_val, + ava.aa_value.bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", + pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); +#endif + + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n", + op->o_connid, op->o_opid, pdn.bv_val, + ava.aa_desc->ad_cname.bv_val, 0 ); + + + /* deref suffix alias if appropriate */ + suffix_alias( be, &ndn ); + + if ( be->be_compare ) { + (*be->be_compare)( be, conn, op, &pdn, &ndn, &ava ); } else { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", + NULL, NULL ); + } + +cleanup: + free( pdn.bv_val ); + free( ndn.bv_val ); + if ( ava.aa_value.bv_val ) free( ava.aa_value.bv_val ); + + return rc; +} + +static int compare_entry( + Connection *conn, + Operation *op, + Entry *e, + AttributeAssertion *ava ) +{ + int rc = LDAP_NO_SUCH_ATTRIBUTE; + Attribute *a; + + if ( ! access_allowed( NULL, conn, op, e, + ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) ) + { + return LDAP_INSUFFICIENT_ACCESS; + } + + for(a = attrs_find( e->e_attrs, ava->aa_desc ); + a != NULL; + a = attrs_find( a->a_next, ava->aa_desc )) + { + rc = LDAP_COMPARE_FALSE; + + if ( value_find( ava->aa_desc, a->a_vals, &ava->aa_value ) == 0 ) { + rc = LDAP_COMPARE_TRUE; + break; + } } - free( dn ); - ava_free( &ava, 0 ); + return rc; } diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 66050586ab794ac4f4e258306e58de0e293206ac..06016c0a7692d8d1ef159192d59cd77bb6d1acdf 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -1,409 +1,2394 @@ /* config.c - configuration file handling routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -#include "ldapconfig.h" -#define MAXARGS 100 +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/socket.h> +#include <ac/errno.h> + +#include "lutil.h" +#include "ldap_pvt.h" +#include "slap.h" -extern Backend *new_backend(); -extern char *default_referral; -extern int ldap_syslog; -extern int global_schemacheck; +#define MAXARGS 500 /* * defaults for various global variables */ -int defsize = SLAPD_DEFAULT_SIZELIMIT; -int deftime = SLAPD_DEFAULT_TIMELIMIT; -struct acl *global_acl = NULL; -int global_default_access = ACL_READ; +struct slap_limits_set deflimit = { + SLAPD_DEFAULT_TIMELIMIT, /* backward compatible limits */ + 0, + + SLAPD_DEFAULT_SIZELIMIT, /* backward compatible limits */ + 0, + -1 /* no limit on unchecked size */ +}; + +AccessControl *global_acl = NULL; +slap_access_t global_default_access = ACL_READ; +slap_mask_t global_restrictops = 0; +slap_mask_t global_allows = 0; +slap_mask_t global_disallows = 0; +slap_mask_t global_requires = 0; +slap_ssf_set_t global_ssf_set; char *replogfile; -int global_lastmod; +int global_idletimeout = 0; +char *global_host = NULL; +char *global_realm = NULL; char *ldap_srvtab = ""; +char *default_passwd_hash = NULL; +struct berval default_search_base = { 0, NULL }; +struct berval default_search_nbase = { 0, NULL }; +unsigned num_subordinates = 0; -static char *fp_getline(); -static void fp_getline_init(); -static void fp_parse_line(); +ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT; +ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH; -static char *strtok_quote(); +char *slapd_pid_file = NULL; +char *slapd_args_file = NULL; -void -read_config( char *fname, Backend **bep, FILE *pfp ) +int nSaslRegexp = 0; +SaslRegexp_t *SaslRegexp = NULL; +int sasl_external_x509dn_convert; + +#ifdef SLAPD_RLOOKUPS +int use_reverse_lookup = 1; +#else /* !SLAPD_RLOOKUPS */ +int use_reverse_lookup = 0; +#endif /* !SLAPD_RLOOKUPS */ + +static char *fp_getline(FILE *fp, int *lineno); +static void fp_getline_init(int *lineno); +static int fp_parse_line(int lineno, char *line, int *argcp, char **argv); + +static char *strtok_quote(char *line, char *sep); +static int load_ucdata(char *path); + +int +read_config( const char *fname ) { FILE *fp; - char *line, *savefname, *dn; + char *line, *savefname, *saveline; int cargc, savelineno; - char *cargv[MAXARGS]; + char *cargv[MAXARGS+1]; int lineno, i; - Backend *be; + int rc; + struct berval vals[2]; + + static int lastmod = 1; + static BackendInfo *bi = NULL; + static BackendDB *be = NULL; - if ( (fp = pfp) == NULL && (fp = fopen( fname, "r" )) == NULL ) { + vals[1].bv_val = NULL; + + if ( (fp = fopen( fname, "r" )) == NULL ) { ldap_syslog = 1; +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_ENTRY, "read_config: " + "could not open config file \"%s\": %s (%d)\n", + fname, strerror(errno), errno )); +#else Debug( LDAP_DEBUG_ANY, - "could not open config file \"%s\" - absolute path?\n", - fname, 0, 0 ); - perror( fname ); - exit( 1 ); + "could not open config file \"%s\": %s (%d)\n", + fname, strerror(errno), errno ); +#endif + return 1; } +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_ENTRY, + "read_config: reading config file %s\n", fname )); +#else Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 ); - be = *bep; +#endif + + fp_getline_init( &lineno ); + while ( (line = fp_getline( fp, &lineno )) != NULL ) { /* skip comments and blank lines */ if ( line[0] == '#' || line[0] == '\0' ) { continue; } - Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 ); + /* fp_parse_line is destructive, we save a copy */ + saveline = ch_strdup( line ); - fp_parse_line( line, &cargc, cargv ); + if ( fp_parse_line( lineno, line, &cargc, cargv ) != 0 ) { + return( 1 ); + } if ( cargc < 1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: bad config line (ignored)\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: bad config line (ignored)\n", fname, lineno, 0 ); +#endif + continue; } - /* start of a new database definition */ - if ( strcasecmp( cargv[0], "database" ) == 0 ) { + if ( strcasecmp( cargv[0], "backend" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s : line %d: missing type in \"backend\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing type in \"backend <type>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + if( be != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: backend line must appear before any " + "database definition.\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: backend line must appear before any database definition\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + bi = backend_info( cargv[1] ); + + if( bi == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "read_config: backend %s initialization failed.\n", + cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "backend %s initialization failed.\n", + cargv[1], 0, 0 ); +#endif + + return( 1 ); + } + } else if ( strcasecmp( cargv[0], "database" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing type in \"database <type>\" line\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing type in \"database <type>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); + } + + bi = NULL; + be = backend_db_init( cargv[1] ); + + if( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "database %s initialization failed.\n", + cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "database %s initialization failed.\n", + cargv[1], 0, 0 ); +#endif + + return( 1 ); + } + + /* set thread concurrency */ + } else if ( strcasecmp( cargv[0], "concurrency" ) == 0 ) { + int c; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing level in \"concurrency <level\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing level in \"concurrency <level>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + c = atoi( cargv[1] ); + + if( c < 1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: invalid level (%d) in " + "\"concurrency <level>\" line.\n", + fname, lineno, c )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid level (%d) in \"concurrency <level>\" line\n", + fname, lineno, c ); +#endif + + return( 1 ); + } + + ldap_pvt_thread_set_concurrency( c ); + + /* set sockbuf max */ + } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing max in \"sockbuf_max_incoming <bytes>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"sockbuf_max_incoming <bytes>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + max = atol( cargv[1] ); + + if( max < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: invalid max value (%ld) in " + "\"sockbuf_max_incoming <bytes>\" line.\n", + fname, lineno, max )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"sockbuf_max_incoming <bytes>\" line.\n", + fname, lineno, max ); +#endif + + return( 1 ); + } + + sockbuf_max_incoming = max; + + /* set sockbuf max authenticated */ + } else if ( strcasecmp( cargv[0], "sockbuf_max_incoming_auth" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing max in \"sockbuf_max_incoming_auth <bytes>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"sockbuf_max_incoming_auth <bytes>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + max = atol( cargv[1] ); + + if( max < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: invalid max value (%ld) in " + "\"sockbuf_max_incoming_auth <bytes>\" line.\n", + fname, lineno, max )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"sockbuf_max_incoming_auth <bytes>\" line.\n", + fname, lineno, max ); +#endif + + return( 1 ); + } + + sockbuf_max_incoming_auth = max; + + /* default search base */ + } else if ( strcasecmp( cargv[0], "defaultSearchBase" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing dn in \"defaultSearchBase <dn\" " + "line\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "missing dn in \"defaultSearchBase <dn>\" line\n", + fname, lineno, 0 ); +#endif + + return 1; + + } else if ( cargc > 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: extra cruft after <dn> in " + "\"defaultSearchBase %s\" line (ignored)\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "extra cruft after <dn> in \"defaultSearchBase %s\", " + "line (ignored)\n", + fname, lineno, cargv[1] ); +#endif + } + + if ( bi != NULL || be != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: defaultSearchBase line must appear " + "prior to any backend or database definitions\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "defaultSearchBaase line must appear prior to " + "any backend or database definition\n", + fname, lineno, 0 ); +#endif + + return 1; + } + + if ( default_search_nbase.bv_len ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: " + "default search base \"%s\" already defined " + "(discarding old)\n", fname, lineno, + default_search_base.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "default search base \"%s\" already defined " + "(discarding old)\n", + fname, lineno, default_search_base.bv_val ); +#endif + + free( default_search_base.bv_val ); + free( default_search_nbase.bv_val ); + } + + if ( load_ucdata( NULL ) < 0 ) return 1; + + { + struct berval dn; + + dn.bv_val = cargv[1]; + dn.bv_len = strlen( dn.bv_val ); + + rc = dnPrettyNormal( NULL, &dn, + &default_search_base, + &default_search_nbase ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: defaultSearchBase DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: defaultSearchBase DN is invalid\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + } + + /* set maximum threads in thread pool */ + } else if ( strcasecmp( cargv[0], "threads" ) == 0 ) { + int c; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing count in \"threads <count>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing count in \"threads <count>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + c = atoi( cargv[1] ); + + if( c < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: invalid level (%d) in \"threads <count>\"" + "line\n",fname, lineno, c )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid level (%d) in \"threads <count>\" line\n", + fname, lineno, c ); +#endif + + return( 1 ); + } + + ldap_pvt_thread_pool_maxthreads( &connection_pool, c ); + + /* save for later use */ + connection_pool_max = c; + + /* get pid file name */ + } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d missing file name in \"pidfile <file>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing file name in \"pidfile <file>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + slapd_pid_file = ch_strdup( cargv[1] ); + + /* get args file name */ + } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: %d: missing file name in " + "\"argsfile <file>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing file name in \"argsfile <file>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + slapd_args_file = ch_strdup( cargv[1] ); + + /* default password hash */ + } else if ( strcasecmp( cargv[0], "password-hash" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing hash in " + "\"password-hash <hash>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing hash in \"password-hash <hash>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + if ( default_passwd_hash != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: already set default password_hash!\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: already set default password_hash!\n", + fname, lineno, 0 ); +#endif + + return 1; + + } + + if ( lutil_passwd_scheme( cargv[1] ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: password scheme \"%s\" not available\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: password scheme \"%s\" not available\n", + fname, lineno, cargv[1] ); +#endif + return 1; + } + + default_passwd_hash = ch_strdup( cargv[1] ); + + } else if ( strcasecmp( cargv[0], "password-crypt-salt-format" ) == 0 ) + { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing format in " + "\"password-crypt-salt-format <format>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: missing format in " + "\"password-crypt-salt-format <format>\" line\n", + fname, lineno, 0 ); +#endif + + return 1; + } + + lutil_salt_format( cargv[1] ); + + /* set SASL host */ + } else if ( strcasecmp( cargv[0], "sasl-host" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing host in \"sasl-host <host>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing host in \"sasl-host <host>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + if ( global_host != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: already set sasl-host!\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: already set sasl-host!\n", + fname, lineno, 0 ); +#endif + + return 1; + + } else { + global_host = ch_strdup( cargv[1] ); + } + + /* set SASL realm */ + } else if ( strcasecmp( cargv[0], "sasl-realm" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing realm in \"sasl-realm <realm>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing realm in \"sasl-realm <realm>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + if ( global_realm != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: already set sasl-realm!\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: already set sasl-realm!\n", + fname, lineno, 0 ); +#endif + + return 1; + + } else { + global_realm = ch_strdup( cargv[1] ); + } + + } else if ( !strcasecmp( cargv[0], "sasl-regexp" ) + || !strcasecmp( cargv[0], "saslregexp" ) ) + { + int rc; + if ( cargc != 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: need 2 args in " + "\"saslregexp <match> <replace>\"\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: need 2 args in \"saslregexp <match> <replace>\"\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + rc = slap_sasl_regexp_config( cargv[1], cargv[2] ); + if ( rc ) { + return rc; + } + + /* SASL security properties */ + } else if ( strcasecmp( cargv[0], "sasl-secprops" ) == 0 ) { + char *txt; + + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing flags in " + "\"sasl-secprops <properties>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing flags in \"sasl-secprops <properties>\" line\n", + fname, lineno, 0 ); +#endif + + return 1; + } + + txt = slap_sasl_secprops( cargv[1] ); + if ( txt != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d sas-secprops: %s\n", + fname, lineno, txt )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: sasl-secprops: %s\n", + fname, lineno, txt ); +#endif + + return 1; + } + + } else if ( strcasecmp( cargv[0], "sasl-external-x509dn-convert" ) == 0 ) { + sasl_external_x509dn_convert++; + + /* set UCDATA path */ + } else if ( strcasecmp( cargv[0], "ucdata-path" ) == 0 ) { + int err; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing path in " + "\"ucdata-path <path>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing path in \"ucdata-path <path>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + err = load_ucdata( cargv[1] ); + if ( err <= 0 ) { + if ( err == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: ucdata already loaded, ucdata-path " + "must be set earlier in the file and/or be " + "specified only once!\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: ucdata already loaded, ucdata-path must be set earlier in the file and/or be specified only once!\n", + fname, lineno, 0 ); +#endif + + } + return( 1 ); } - *bep = new_backend( cargv[1] ); - be = *bep; /* set size limit */ } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) { + int rc = 0, i; + struct slap_limits_set *lim; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing limit in \"sizelimit <limit>\" line.\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing limit in \"sizelimit <limit>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } + if ( be == NULL ) { - defsize = atoi( cargv[1] ); + lim = &deflimit; } else { - be->be_sizelimit = atoi( cargv[1] ); + lim = &be->be_def_limit; + } + + for ( i = 1; i < cargc; i++ ) { + if ( strncasecmp( cargv[i], "size", 4 ) == 0 ) { + rc = parse_limit( cargv[i], lim ); + } else { + lim->lms_s_soft = atoi( cargv[i] ); + lim->lms_s_hard = 0; + } + + if ( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unable " + "to parse value \"%s\" " + "in \"sizelimit " + "<limit>\" line.\n", + fname, lineno, cargv[i] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unable " + "to parse value \"%s\" " + "in \"sizelimit " + "<limit>\" line\n", + fname, lineno, cargv[i] ); +#endif + } } /* set time limit */ } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) { + int rc = 0, i; + struct slap_limits_set *lim; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d missing limit in \"timelimit <limit>\" line.\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing limit in \"timelimit <limit>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); + } + + if ( be == NULL ) { + lim = &deflimit; + } else { + lim = &be->be_def_limit; + } + + for ( i = 1; i < cargc; i++ ) { + if ( strncasecmp( cargv[i], "time", 4 ) == 0 ) { + rc = parse_limit( cargv[i], lim ); + } else { + lim->lms_t_soft = atoi( cargv[i] ); + lim->lms_t_hard = 0; + } + + if ( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unable " + "to parse value \"%s\" " + "in \"timelimit " + "<limit>\" line.\n", + fname, lineno, cargv[i] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unable " + "to parse value \"%s\" " + "in \"timelimit " + "<limit>\" line\n", + fname, lineno, cargv[i] ); +#endif + } + } + + /* set regex-based limits */ + } else if ( strcasecmp( cargv[0], "limits" ) == 0 ) { + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_WARNING, + "%s: line %d \"limits\" allowed only in database environment.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d \"limits\" allowed only in database environment.\n%s", + fname, lineno, "" ); +#endif + return( 1 ); + } + + if ( parse_limits( be, fname, lineno, cargc, cargv ) ) { + return( 1 ); + } + + /* mark this as a subordinate database */ + } else if ( strcasecmp( cargv[0], "subordinate" ) == 0 ) { + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: " + "subordinate keyword must appear inside a database " + "definition (ignored).\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix line " + "must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); +#endif + } else { + be->be_flags |= SLAP_BFLAG_GLUE_SUBORDINATE; + num_subordinates++; + } + + /* set database suffix */ + } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) { + Backend *tmp_be; + struct berval dn; + struct berval *pdn = NULL; + struct berval *ndn = NULL; + + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing dn in \"suffix <dn>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "missing dn in \"suffix <dn>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + + } else if ( cargc > 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: extra cruft after <dn> in \"suffix %s\"" + " line (ignored).\n", fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: extra cruft " + "after <dn> in \"suffix %s\" line (ignored)\n", + fname, lineno, cargv[1] ); +#endif + } + + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffix line must appear inside a database " + "definition.\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix line " + "must appear inside a database definition\n", + fname, lineno, 0 ); +#endif + return( 1 ); + +#if defined(SLAPD_MONITOR_DN) + /* "cn=Monitor" is reserved for monitoring slap */ + } else if ( strcasecmp( cargv[1], SLAPD_MONITOR_DN ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: \"" + SLAPD_MONITOR_DN "\" is reserved for monitoring slapd\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: \"" + SLAPD_MONITOR_DN "\" is reserved for monitoring slapd\n", + fname, lineno, 0 ); +#endif + return( 1 ); +#endif /* SLAPD_MONITOR_DN */ + } + + if ( load_ucdata( NULL ) < 0 ) return 1; + + dn.bv_val = cargv[1]; + dn.bv_len = strlen( cargv[1] ); + pdn = ch_malloc( sizeof( struct berval )); + ndn = ch_malloc( sizeof( struct berval )); + + rc = dnPrettyNormal( NULL, &dn, pdn, ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: suffix DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: suffix DN is invalid\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + + tmp_be = select_backend( ndn, 0, 0 ); + if ( tmp_be == be ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffix already served by this backend " + "(ignored)\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix " + "already served by this backend (ignored)\n", + fname, lineno, 0 ); +#endif + ber_bvfree( pdn ); + ber_bvfree( ndn ); + + } else if ( tmp_be != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffix already served by a preceding " + "backend \"%s\"\n", fname, lineno, + tmp_be->be_suffix[0]->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix " + "already served by a preceeding backend \"%s\"\n", + fname, lineno, tmp_be->be_suffix[0]->bv_val ); +#endif + ber_bvfree( pdn ); + ber_bvfree( ndn ); + return( 1 ); + + } else if( pdn->bv_len == 0 && default_search_nbase.bv_len ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffix DN empty and default search " + "base provided \"%s\" (assuming okay).\n", + fname, lineno, default_search_base.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "suffix DN empty and default " + "search base provided \"%s\" (assuming okay)\n", + fname, lineno, default_search_base.bv_val ); +#endif + } + + ber_bvecadd( &be->be_suffix, pdn ); + ber_bvecadd( &be->be_nsuffix, ndn ); + + /* set database suffixAlias */ + } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) { + Backend *tmp_be; + struct berval alias, *palias, nalias; + struct berval aliased, *paliased, naliased; + + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing alias and aliased_dn in " + "\"suffixAlias <alias> <aliased_dn>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing alias and aliased_dn in " + "\"suffixAlias <alias> <aliased_dn>\" line.\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } else if ( cargc < 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing aliased_dn in " + "\"suffixAlias <alias> <aliased_dn>\" line\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing aliased_dn in " + "\"suffixAlias <alias> <aliased_dn>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } else if ( cargc > 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: extra cruft in suffixAlias line (ignored)\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: extra cruft in suffixAlias line (ignored)\n", + fname, lineno, 0 ); +#endif + + } + + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffixAlias line must appear inside a " + "database definition (ignored).\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: suffixAlias line" + " must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); +#endif + } + + if ( load_ucdata( NULL ) < 0 ) return 1; + + alias.bv_val = cargv[1]; + alias.bv_len = strlen( cargv[1] ); + palias = ch_malloc(sizeof(struct berval)); + + rc = dnPrettyNormal( NULL, &alias, palias, &nalias ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: alias DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: alias DN is invalid\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + + tmp_be = select_backend( &nalias, 0, 0 ); + free( nalias.bv_val ); + if ( tmp_be && tmp_be != be ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffixAlias served by a preceeding " + "backend \"%s\"\n", + fname, lineno, tmp_be->be_suffix[0]->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: suffixAlias served by" + " a preceeding backend \"%s\"\n", + fname, lineno, tmp_be->be_suffix[0]->bv_val ); +#endif + ber_bvfree( palias ); + return -1; + } + + aliased.bv_val = cargv[2]; + aliased.bv_len = strlen( cargv[2] ); + paliased = ch_malloc(sizeof(struct berval)); + + rc = dnPrettyNormal( NULL, &aliased, paliased, &naliased ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: aliased DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: aliased DN is invalid\n", + fname, lineno, 0 ); +#endif + ber_bvfree( palias ); + return( 1 ); + } + + tmp_be = select_backend( &naliased, 0, 0 ); + free( naliased.bv_val ); + if ( tmp_be && tmp_be != be ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffixAlias derefs to a different backend " + "a preceeding backend \"%s\"\n", + fname, lineno, tmp_be->be_suffix[0]->bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: suffixAlias derefs to differnet backend" + " a preceeding backend \"%s\"\n", + fname, lineno, tmp_be->be_suffix[0]->bv_val ); +#endif + ber_bvfree( palias ); + ber_bvfree( paliased ); + return -1; + } + + ber_bvecadd( &be->be_suffixAlias, palias ); + ber_bvecadd( &be->be_suffixAlias, paliased ); + + /* set max deref depth */ + } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) { + int i; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing depth in \"maxDerefDepth <depth>\"" + " line\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: depth line must appear inside a database " + "definition (ignored)\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: depth line must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); +#endif + + } else if ((i = atoi(cargv[1])) < 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: depth must be positive (ignored).\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: depth must be positive (ignored)\n", + fname, lineno, 0 ); +#endif + + + } else { + be->be_max_deref_depth = i; + } + + + /* set magic "root" dn for this database */ + } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: missing dn in \"rootdn <dn>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing dn in \"rootdn <dn>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); } if ( be == NULL ) { - deftime = atoi( cargv[1] ); +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: rootdn line must appear inside a database " + "definition (ignored).\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: rootdn line must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); +#endif + } else { - be->be_timelimit = atoi( cargv[1] ); + struct berval dn; + + if ( load_ucdata( NULL ) < 0 ) return 1; + + dn.bv_val = cargv[1]; + dn.bv_len = strlen( cargv[1] ); + + rc = dnPrettyNormal( NULL, &dn, + &be->be_rootdn, + &be->be_rootndn ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: rootdn DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: rootdn DN is invalid\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + } + + /* set super-secret magic database password */ + } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing passwd in \"rootpw <passwd>\"" + " line\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: rootpw line must appear inside a database " + "definition (ignored)\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: rootpw line must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); +#endif + + } else { + be->be_rootpw.bv_val = ch_strdup( cargv[1] ); + be->be_rootpw.bv_len = strlen( be->be_rootpw.bv_val ); + } + + /* make this database read-only */ + } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing on|off in \"readonly <on|off>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing on|off in \"readonly <on|off>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + if ( be == NULL ) { + if ( strcasecmp( cargv[1], "on" ) == 0 ) { + global_restrictops |= SLAP_RESTRICT_OP_WRITES; + } else { + global_restrictops &= ~SLAP_RESTRICT_OP_WRITES; + } + } else { + if ( strcasecmp( cargv[1], "on" ) == 0 ) { + be->be_restrictops |= SLAP_RESTRICT_OP_WRITES; + } else { + be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES; + } + } + + + /* allow these features */ + } else if ( strcasecmp( cargv[0], "allows" ) == 0 || + strcasecmp( cargv[0], "allow" ) == 0 ) + { + slap_mask_t allows; + + if ( be != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: allow line must appear prior to " + "database definitions.\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: allow line must appear prior to database definitions\n", + fname, lineno, 0 ); +#endif + } - /* set database suffix */ - } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing feature(s) in \"allow <features>\"" + " line\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing dn in \"suffix <dn>\" line\n", + "%s: line %d: missing feature(s) in \"allow <features>\" line\n", fname, lineno, 0 ); - exit( 1 ); - } else if ( cargc > 2 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n", - fname, lineno, cargv[1] ); +#endif + + return( 1 ); } - if ( be == NULL ) { + + allows = 0; + + for( i=1; i < cargc; i++ ) { + if( strcasecmp( cargv[i], "bind_v2" ) == 0 ) { + allows |= SLAP_ALLOW_BIND_V2; + + } else if( strcasecmp( cargv[i], "bind_anon_cred" ) == 0 ) { + allows |= SLAP_ALLOW_BIND_ANON_CRED; + + } else if( strcasecmp( cargv[i], "bind_anon_dn" ) == 0 ) { + allows |= SLAP_ALLOW_BIND_ANON_DN; + + } else if( strcasecmp( cargv[i], "none" ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unknown feature %s in " + "\"allow <features>\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unknown feature %s in \"allow <features>\" line\n", + fname, lineno, cargv[i] ); +#endif + + return( 1 ); + } + } + + global_allows = allows; + + /* disallow these features */ + } else if ( strcasecmp( cargv[0], "disallows" ) == 0 || + strcasecmp( cargv[0], "disallow" ) == 0 ) + { + slap_mask_t disallows; + + if ( be != NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: disallow line must appear prior to " + "database definitions.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, -"%s: line %d: suffix line must appear inside a database definition (ignored)\n", +"%s: line %d: disallow line must appear prior to database definitions\n", fname, lineno, 0 ); - } else { - dn = strdup( cargv[1] ); - (void) dn_normalize( dn ); - charray_add( &be->be_suffix, dn ); +#endif + } - /* set magic "root" dn for this database */ - } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing feature(s) in \"disallow <features>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing dn in \"rootdn <dn>\" line\n", + "%s: line %d: missing feature(s) in \"disallow <features>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } - if ( be == NULL ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: rootdn line must appear inside a database definition (ignored)\n", - fname, lineno, 0 ); - } else { - dn = strdup( cargv[1] ); - (void) dn_normalize( dn ); - be->be_rootdn = dn; + + disallows = 0; + + for( i=1; i < cargc; i++ ) { + if( strcasecmp( cargv[i], "bind_anon" ) == 0 ) { + disallows |= SLAP_DISALLOW_BIND_ANON; + + } else if( strcasecmp( cargv[i], "bind_simple" ) == 0 ) { + disallows |= SLAP_DISALLOW_BIND_SIMPLE; + + } else if( strcasecmp( cargv[i], "bind_krbv4" ) == 0 ) { + disallows |= SLAP_DISALLOW_BIND_KRBV4; + + } else if( strcasecmp( cargv[i], "tls_2_anon" ) == 0 ) { + disallows |= SLAP_DISALLOW_TLS_2_ANON; + + } else if( strcasecmp( cargv[i], "tls_authc" ) == 0 ) { + disallows |= SLAP_DISALLOW_TLS_AUTHC; + + } else if( strcasecmp( cargv[i], "none" ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unknown feature %s in " + "\"disallow <features>\" line.\n", + fname, lineno, cargv[i] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unknown feature %s in \"disallow <features>\" line\n", + fname, lineno, cargv[i] ); +#endif + + return( 1 ); + } } - /* set super-secret magic database password */ - } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) { + global_disallows = disallows; + + /* require these features */ + } else if ( strcasecmp( cargv[0], "requires" ) == 0 || + strcasecmp( cargv[0], "require" ) == 0 ) + { + slap_mask_t requires; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing feature(s) in " + "\"require <features>\" line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n", + "%s: line %d: missing feature(s) in \"require <features>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); + } + + requires = 0; + + for( i=1; i < cargc; i++ ) { + if( strcasecmp( cargv[i], "bind" ) == 0 ) { + requires |= SLAP_REQUIRE_BIND; + + } else if( strcasecmp( cargv[i], "LDAPv3" ) == 0 ) { + requires |= SLAP_REQUIRE_LDAP_V3; + + } else if( strcasecmp( cargv[i], "authc" ) == 0 ) { + requires |= SLAP_REQUIRE_AUTHC; + + } else if( strcasecmp( cargv[i], "SASL" ) == 0 ) { + requires |= SLAP_REQUIRE_SASL; + + } else if( strcasecmp( cargv[i], "strong" ) == 0 ) { + requires |= SLAP_REQUIRE_STRONG; + + } else if( strcasecmp( cargv[i], "none" ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unknown feature %s in " + "\"require <features>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unknown feature %s in \"require <features>\" line\n", + fname, lineno, cargv[i] ); +#endif + + return( 1 ); + } } + if ( be == NULL ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: rootpw line must appear inside a database definition (ignored)\n", - fname, lineno, 0 ); + global_requires = requires; } else { - be->be_rootpw = strdup( cargv[1] ); + be->be_requires = requires; } - /* make this database read-only */ - } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) { + /* required security factors */ + } else if ( strcasecmp( cargv[0], "security" ) == 0 ) { + slap_ssf_set_t *set; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing factor(s) in \"security <factors>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing on|off in \"readonly <on|off>\" line\n", + "%s: line %d: missing factor(s) in \"security <factors>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } + if ( be == NULL ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: readonly line must appear inside a database definition (ignored)\n", - fname, lineno, 0 ); + set = &global_ssf_set; } else { - if ( strcasecmp( cargv[1], "on" ) == 0 ) { - be->be_readonly = 1; + set = &be->be_ssf_set; + } + + for( i=1; i < cargc; i++ ) { + if( strncasecmp( cargv[i], "ssf=", + sizeof("ssf") ) == 0 ) + { + set->sss_ssf = + atoi( &cargv[i][sizeof("ssf")] ); + + } else if( strncasecmp( cargv[i], "transport=", + sizeof("transport") ) == 0 ) + { + set->sss_transport = + atoi( &cargv[i][sizeof("transport")] ); + + } else if( strncasecmp( cargv[i], "tls=", + sizeof("tls") ) == 0 ) + { + set->sss_tls = + atoi( &cargv[i][sizeof("tls")] ); + + } else if( strncasecmp( cargv[i], "sasl=", + sizeof("sasl") ) == 0 ) + { + set->sss_sasl = + atoi( &cargv[i][sizeof("sasl")] ); + + } else if( strncasecmp( cargv[i], "update_ssf=", + sizeof("update_ssf") ) == 0 ) + { + set->sss_update_ssf = + atoi( &cargv[i][sizeof("update_ssf")] ); + + } else if( strncasecmp( cargv[i], "update_transport=", + sizeof("update_transport") ) == 0 ) + { + set->sss_update_transport = + atoi( &cargv[i][sizeof("update_transport")] ); + + } else if( strncasecmp( cargv[i], "update_tls=", + sizeof("update_tls") ) == 0 ) + { + set->sss_update_tls = + atoi( &cargv[i][sizeof("update_tls")] ); + + } else if( strncasecmp( cargv[i], "update_sasl=", + sizeof("update_sasl") ) == 0 ) + { + set->sss_update_sasl = + atoi( &cargv[i][sizeof("update_sasl")] ); + } else { - be->be_readonly = 0; +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: unknown factor %S in " + "\"security <factors>\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unknown factor %s in \"security <factors>\" line\n", + fname, lineno, cargv[i] ); +#endif + + return( 1 ); } } - /* where to send clients when we don't hold it */ } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing URL in \"referral <URL>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing URL in \"referral <URL>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); + } + + if( validate_global_referral( cargv[1] ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "invalid URL (%s) in \"referral\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "invalid URL (%s) in \"referral\" line.\n", + fname, lineno, cargv[1] ); +#endif + return 1; + } + + vals[0].bv_val = cargv[1]; + vals[0].bv_len = strlen( vals[0].bv_val ); + value_add( &default_referral, vals ); + +#ifdef NEW_LOGGING + } else if ( strcasecmp( cargv[0], "logfile" ) == 0 ) { + FILE *logfile; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: Error in logfile directive, " + "\"logfile <filename>\"\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: Error in logfile directive, \"logfile filename\"\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + logfile = fopen( cargv[1], "w" ); + if ( logfile != NULL ) lutil_debug_file( logfile ); + +#endif + /* start of a new database definition */ + } else if ( strcasecmp( cargv[0], "debug" ) == 0 ) { + int level; + if ( cargc < 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: Error in debug directive, " + "\"debug <subsys> <level>\"\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: Error in debug directive, \"debug subsys level\"\n", + fname, lineno, 0 ); +#endif + + return( 1 ); } - default_referral = (char *) malloc( strlen( cargv[1] ) - + sizeof("Referral:\n") + 1 ); - strcpy( default_referral, "Referral:\n" ); - strcat( default_referral, cargv[1] ); + level = atoi( cargv[2] ); + if ( level <= 0 ) level = lutil_mnem2level( cargv[2] ); + lutil_set_debug_level( cargv[1], level ); + /* specify an Object Identifier macro */ + } else if ( strcasecmp( cargv[0], "objectidentifier" ) == 0 ) { + rc = parse_oidm( fname, lineno, cargc, cargv ); + if( rc ) return rc; /* specify an objectclass */ } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) { - parse_oc( be, fname, lineno, cargc, cargv ); + if ( *cargv[1] == '(' ) { + char * p; + p = strchr(saveline,'('); + rc = parse_oc( fname, lineno, p, cargv ); + if( rc ) return rc; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: old objectclass format not supported\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: old objectclass format not supported.\n", + fname, lineno, 0 ); +#endif + + } + + /* specify an attribute type */ + } else if (( strcasecmp( cargv[0], "attributetype" ) == 0 ) + || ( strcasecmp( cargv[0], "attribute" ) == 0 )) + { + if ( *cargv[1] == '(' ) { + char * p; + p = strchr(saveline,'('); + rc = parse_at( fname, lineno, p, cargv ); + if( rc ) return rc; + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: old attribute type format not supported.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: old attribute type format not supported.\n", + fname, lineno, 0 ); +#endif - /* specify an attribute */ - } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) { - attr_syntax_config( fname, lineno, cargc - 1, - &cargv[1] ); + } /* turn on/off schema checking */ } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing on|off in " + "\"schemacheck <on|off>\" line.\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } - if ( strcasecmp( cargv[1], "on" ) == 0 ) { - global_schemacheck = 1; - } else { + if ( strcasecmp( cargv[1], "off" ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: schema checking disabled! your mileage may vary!\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: schema checking disabled! your mileage may vary!\n", + fname, lineno, 0 ); +#endif global_schemacheck = 0; + } else { + global_schemacheck = 1; } /* specify access control info */ } else if ( strcasecmp( cargv[0], "access" ) == 0 ) { parse_acl( be, fname, lineno, cargc, cargv ); - /* specify default access control info */ - } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) { - if ( cargc < 2 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing limit in \"defaultaccess <access>\" line\n", - fname, lineno, 0 ); - exit( 1 ); - } - if ( be == NULL ) { - if ( (global_default_access = - str2access( cargv[1] )) == -1 ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n", - fname, lineno, cargv[1] ); - exit( 1 ); - } - } else { - if ( (be->be_dfltaccess = - str2access( cargv[1] )) == -1 ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n", - fname, lineno, cargv[1] ); - exit( 1 ); - } - } - /* debug level to log things to syslog */ } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing level in \"loglevel <level>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing level in \"loglevel <level>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); + } + + ldap_syslog = 0; + + for( i=1; i < cargc; i++ ) { + ldap_syslog += atoi( cargv[1] ); } - ldap_syslog = atoi( cargv[1] ); /* list of replicas of the data in this backend (master only) */ } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing host in \"replica " + " <host[:port]\" line\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing host in \"replica <host[:port]>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: replica line must appear inside " + "a database definition (ignored).\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: replica line must appear inside a database definition (ignored)\n", fname, lineno, 0 ); +#endif + } else { + int nr = -1; + for ( i = 1; i < cargc; i++ ) { if ( strncasecmp( cargv[i], "host=", 5 ) == 0 ) { - charray_add( &be->be_replica, - strdup( cargv[i] + 5 ) ); + nr = add_replica_info( be, + cargv[i] + 5 ); break; } } if ( i == cargc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: missing host in \"replica\" " + "line (ignored)\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing host in \"replica\" line (ignored)\n", fname, lineno, 0 ); +#endif + + } else if ( nr == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: unable to add" + " replica \"%s\"" + " (ignored)\n", + fname, lineno, + cargv[i] + 5 )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unable to add replica \"%s\" (ignored)\n", + fname, lineno, cargv[i] + 5 ); +#endif + } else { + for ( i = 1; i < cargc; i++ ) { + if ( strncasecmp( cargv[i], "suffix=", 7 ) == 0 ) { + + switch ( add_replica_suffix( be, nr, cargv[i] + 7 ) ) { + case 1: +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n", + fname, lineno, cargv[i] + 7 )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n", + fname, lineno, cargv[i] + 7 ); +#endif + break; + + case 2: +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: unable to normalize suffix in \"replica\" line (ignored)\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: unable to normalize suffix in \"replica\" line (ignored)\n", + fname, lineno, 0 ); +#endif + break; + } + + } else if ( strncasecmp( cargv[i], "attr", 4 ) == 0 ) { + int exclude = 0; + char *arg = cargv[i] + 4; + + if ( arg[0] == '!' ) { + arg++; + exclude = 1; + } + + if ( arg[0] != '=' ) { + continue; + } + + if ( add_replica_attrs( be, nr, arg + 1, exclude ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: attribute \"%s\" in \"replica\" line is unknown\n", + fname, lineno, arg + 1 )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: attribute \"%s\" in \"replica\" line is unknown\n", + fname, lineno, arg + 1 ); +#endif + return( 1 ); + } + } + } } } /* dn of master entity allowed to write to replica */ } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing dn in \"updatedn <dn>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing dn in \"updatedn <dn>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: updatedn line must appear inside " + "a database definition (ignored)\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: updatedn line must appear inside a database definition (ignored)\n", fname, lineno, 0 ); +#endif + } else { - be->be_updatedn = strdup( cargv[1] ); - (void) dn_normalize( be->be_updatedn ); + struct berval dn; + + if ( load_ucdata( NULL ) < 0 ) return 1; + + dn.bv_val = cargv[1]; + dn.bv_len = strlen( cargv[1] ); + + rc = dnNormalize2( NULL, &dn, &be->be_update_ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: updatedn DN is invalid.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: updatedn DN is invalid\n", + fname, lineno, 0 ); +#endif + return 1; + } + } + + } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "missing url in \"updateref <ldapurl>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "missing url in \"updateref <ldapurl>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + if ( be == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: updateref" + " line must appear inside a database definition\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: updateref" + " line must appear inside a database definition\n", + fname, lineno, 0 ); +#endif + return 1; + + } else if ( !be->be_update_ndn.bv_len ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: " + "updateref line must come after updatedn.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "updateref line must after updatedn.\n", + fname, lineno, 0 ); +#endif + return 1; + } + + if( validate_global_referral( cargv[1] ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "invalid URL (%s) in \"updateref\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "invalid URL (%s) in \"updateref\" line.\n", + fname, lineno, cargv[1] ); +#endif + return 1; } + vals[0].bv_val = cargv[1]; + vals[0].bv_len = strlen( vals[0].bv_val ); + value_add( &be->be_update_refs, vals ); + /* replication log file to which changes are appended */ } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing filename in \"replogfile <filename>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing dn in \"replogfile <filename>\" line\n", + "%s: line %d: missing filename in \"replogfile <filename>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } if ( be ) { - be->be_replogfile = strdup( cargv[1] ); + be->be_replogfile = ch_strdup( cargv[1] ); } else { - replogfile = strdup( cargv[1] ); + replogfile = ch_strdup( cargv[1] ); + } + + /* file from which to read additional rootdse attrs */ + } else if ( strcasecmp( cargv[0], "rootDSE" ) == 0) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "missing filename in \"rootDSE <filename>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "missing filename in \"rootDSE <filename>\" line.\n", + fname, lineno, 0 ); +#endif + return 1; + } + + if( read_root_dse_file( cargv[1] ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "could not read \"rootDSE <filename>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "could not read \"rootDSE <filename>\" line\n", + fname, lineno, 0 ); +#endif + return 1; } /* maintain lastmodified{by,time} attributes */ } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing on|off in \"lastmod <on|off>\"" + " line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } if ( strcasecmp( cargv[1], "on" ) == 0 ) { - if ( be ) - be->be_lastmod = ON; - else - global_lastmod = ON; + if ( be ) { + be->be_flags &= ~SLAP_BFLAG_NOLASTMOD; + } else { + lastmod = 1; + } } else { - if ( be ) - be->be_lastmod = OFF; - else - global_lastmod = OFF; + if ( be ) { + be->be_flags |= SLAP_BFLAG_NOLASTMOD; + } else { + lastmod = 0; + } + } + + /* set idle timeout value */ + } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) { + int i; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing timeout value in " + "\"idletimeout <seconds>\" line.\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + i = atoi( cargv[1] ); + + if( i < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: timeout value (%d) invalid " + "\"idletimeout <seconds>\" line.\n", + fname, lineno, i )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n", + fname, lineno, i ); +#endif + + return( 1 ); } + global_idletimeout = i; + /* include another config file */ } else if ( strcasecmp( cargv[0], "include" ) == 0 ) { 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 ); - exit( 1 ); +#endif + + return( 1 ); } - savefname = strdup( cargv[1] ); + savefname = ch_strdup( cargv[1] ); savelineno = lineno; - read_config( savefname, bep, NULL ); - be = *bep; + + if ( read_config( savefname ) != 0 ) { + return( 1 ); + } + free( savefname ); lineno = savelineno - 1; /* location of kerberos srvtab file */ } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) { if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: missing filename in \"srvtab " + "<filename>\" line.\n", fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, "%s: line %d: missing filename in \"srvtab <filename>\" line\n", fname, lineno, 0 ); - exit( 1 ); +#endif + + return( 1 ); } - ldap_srvtab = strdup( cargv[1] ); + ldap_srvtab = ch_strdup( cargv[1] ); - /* pass anything else to the current backend config routine */ - } else { - if ( be == NULL ) { +#ifdef SLAPD_MODULES + } else if (strcasecmp( cargv[0], "moduleload") == 0 ) { + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: missing filename in \"moduleload " + "<filename>\" line.\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing filename in \"moduleload <filename>\" line\n", + fname, lineno, 0 ); +#endif + + exit( EXIT_FAILURE ); + } + if (module_load(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s: line %d: failed to load or initialize module %s\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: failed to load or initialize module %s\n", + fname, lineno, cargv[1]); +#endif + + exit( EXIT_FAILURE ); + } + } else if (strcasecmp( cargv[0], "modulepath") == 0 ) { + if ( cargc != 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: missing path in \"modulepath <path>\"" + " line\n", fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing path in \"modulepath <path>\" line\n", + fname, lineno, 0 ); +#endif + + exit( EXIT_FAILURE ); + } + if (module_path( cargv[1] )) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cofig", LDAP_LEVEL_CRIT, + "%s: line %d: failed to set module search path to %s.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: failed to set module search path to %s\n", + fname, lineno, cargv[1]); +#endif + + exit( EXIT_FAILURE ); + } + +#endif /*SLAPD_MODULES*/ + +#ifdef HAVE_TLS + } else if ( !strcasecmp( cargv[0], "TLSRandFile" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_RANDOM_FILE, + cargv[1] ); + if ( rc ) + return rc; + + } else if ( !strcasecmp( cargv[0], "TLSCipherSuite" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_CIPHER_SUITE, + cargv[1] ); + if ( rc ) + return rc; + + } else if ( !strcasecmp( cargv[0], "TLSCertificateFile" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_CERTFILE, + cargv[1] ); + if ( rc ) + return rc; + + } else if ( !strcasecmp( cargv[0], "TLSCertificateKeyFile" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_KEYFILE, + cargv[1] ); + if ( rc ) + return rc; + + } else if ( !strcasecmp( cargv[0], "TLSCACertificatePath" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_CACERTDIR, + cargv[1] ); + if ( rc ) + return rc; + + } else if ( !strcasecmp( cargv[0], "TLSCACertificateFile" ) ) { + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_CACERTFILE, + cargv[1] ); + if ( rc ) + return rc; + } else if ( !strcasecmp( cargv[0], "TLSVerifyClient" ) ) { + if ( isdigit( cargv[1][0] ) ) { + i = atoi(cargv[1]); + rc = ldap_pvt_tls_set_option( NULL, + LDAP_OPT_X_TLS_REQUIRE_CERT, + &i ); + } else { + rc = ldap_int_tls_config( NULL, + LDAP_OPT_X_TLS_REQUIRE_CERT, + cargv[1] ); + } + + if ( rc ) + return rc; + +#endif + + } else if ( !strcasecmp( cargv[0], "reverse-lookup" ) ) { +#ifdef SLAPD_RLOOKUPS + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: reverse-lookup: " + "missing \"on\" or \"off\"\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, -"%s: line %d: unknown directive \"%s\" outside database definition (ignored)\n", - fname, lineno, cargv[0] ); - } else if ( be->be_config == NULL ) { +"%s: line %d: reverse-lookup: missing \"on\" or \"off\"\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + + if ( !strcasecmp( cargv[1], "on" ) ) { + use_reverse_lookup = 1; + } else if ( !strcasecmp( cargv[1], "off" ) ) { + use_reverse_lookup = 0; + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: reverse-lookup: " + "must be \"on\" (default) " + "or \"off\"\n", + fname, lineno )); +#else Debug( LDAP_DEBUG_ANY, -"%s: line %d: unknown directive \"%s\" inside database definition (ignored)\n", - fname, lineno, cargv[0] ); +"%s: line %d: reverse-lookup: must be \"on\" (default) or \"off\"\n", + fname, lineno, 0 ); +#endif + return( 1 ); + } + +#else /* !SLAPD_RLOOKUPS */ +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: reverse lookups " + "are not configured (ignored).\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: reverse lookups are not configured (ignored).\n", + fname, lineno, 0 ); +#endif +#endif /* !SLAPD_RLOOKUPS */ + + /* pass anything else to the current backend info/db config routine */ + } else { + if ( bi != NULL ) { + if ( bi->bi_config == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: unknown directive \"%s\" inside " + "backend info definition (ignored).\n", + fname, lineno, cargv[0] )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n", + fname, lineno, cargv[0] ); +#endif + + } else { + if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv ) + != 0 ) + { + return( 1 ); + } + } + } else if ( be != NULL ) { + if ( be->be_config == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: uknown directive \"%s\" inside " + "backend database definition (ignored).\n", + fname, lineno, cargv[0] )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n", + fname, lineno, cargv[0] ); +#endif + + } else { + if ( (*be->be_config)( be, fname, lineno, cargc, cargv ) + != 0 ) + { + return( 1 ); + } + } } else { - (*be->be_config)( be, fname, lineno, cargc, - cargv ); +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_INFO, + "%s: line %d: unknown directive \"%s\" outside backend " + "info and database definitions (ignored).\n", + fname, lineno, cargv[0] )); +#else + Debug( LDAP_DEBUG_ANY, +"%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n", + fname, lineno, cargv[0] ); +#endif + } } + free( saveline ); } fclose( fp ); + + if ( load_ucdata( NULL ) < 0 ) return 1; + return( 0 ); } -static void +static int fp_parse_line( + int lineno, char *line, int *argcp, char **argv ) { char * token; + char * logline; *argcp = 0; - for ( token = strtok_quote( line, " \t" ); token != NULL; - token = strtok_quote( NULL, " \t" ) ) { + token = strtok_quote( line, " \t" ); + + logline = (!token || strcasecmp(token, "rootpw") ? line : "rootpw *"); +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_DETAIL1, + "line %d (%s)\n", lineno, logline )); +#else + Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, logline, 0 ); +#endif + + for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) { if ( *argcp == MAXARGS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "fp_parse_line: too many tokens (%d max).\n", + MAXARGS )); +#else Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n", MAXARGS, 0, 0 ); - exit( 1 ); +#endif + + return( 1 ); } argv[(*argcp)++] = token; } argv[*argcp] = NULL; + return 0; } static char * @@ -434,11 +2419,14 @@ strtok_quote( char *line, char *sep ) } 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: @@ -487,11 +2475,26 @@ fp_getline( FILE *fp, int *lineno ) } while ( fgets( buf, sizeof(buf), fp ) != NULL ) { + /* trim off \r\n or \n */ if ( (p = strchr( buf, '\n' )) != NULL ) { + if( p > buf && p[-1] == '\r' ) --p; *p = '\0'; } - if ( ! isspace( buf[0] ) ) { - return( line ); + + /* trim off trailing \ and append the next line */ + if ( line[ 0 ] != '\0' + && (p = line + strlen( line ) - 1)[ 0 ] == '\\' + && p[ -1 ] != '\\' ) { + p[ 0 ] = '\0'; + lcur--; + + } else { + if ( ! isspace( (unsigned char) buf[0] ) ) { + return( line ); + } + + /* change leading whitespace to a space */ + buf[0] = ' '; } CATLINE( buf ); @@ -508,3 +2511,41 @@ fp_getline_init( int *lineno ) *lineno = -1; buf[0] = '\0'; } + +/* Loads ucdata, returns 1 if loading, 0 if already loaded, -1 on error */ +static int +load_ucdata( char *path ) +{ + static int loaded = 0; + int err; + + if ( loaded ) { + return( 0 ); + } + err = ucdata_load( path ? path : SLAPD_DEFAULT_UCDATA, UCDATA_ALL ); + if ( err ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "load_ucdata: Error %d loading ucdata.\n", err )); +#else + Debug( LDAP_DEBUG_ANY, "error loading ucdata (error %d)\n", + err, 0, 0 ); +#endif + + return( -1 ); + } + loaded = 1; + return( 1 ); +} + +void +config_destroy( ) +{ + ucdata_unload( UCDATA_ALL ); + free( line ); + if ( slapd_args_file ) + free ( slapd_args_file ); + if ( slapd_pid_file ) + free ( slapd_pid_file ); + acl_destroy( global_acl, NULL ); +} diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 5c3ebdf708f7307d78562dee2c30ceaf4f4e567d..41828b6aca36d61430dd6c59c896e6edd6401a4a 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1,215 +1,1630 @@ -#include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <errno.h> -#include <signal.h> +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + #include "portable.h" + +#include <stdio.h> +#include <limits.h> + +#include <ac/socket.h> +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include "ldap_pvt.h" +#include "lutil.h" #include "slap.h" -extern Operation *op_add(); -extern int active_threads; -extern pthread_mutex_t active_threads_mutex; -extern pthread_mutex_t new_conn_mutex; -extern long ops_initiated; -extern long ops_completed; -extern pthread_mutex_t ops_mutex; -extern pthread_t listener_tid; -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; -#endif +/* protected by connections_mutex */ +static ldap_pvt_thread_mutex_t connections_mutex; +static Connection *connections = NULL; +static unsigned long conn_nextid = 0; + +/* structure state (protected by connections_mutex) */ +#define SLAP_C_UNINITIALIZED 0x00 /* MUST BE ZERO (0) */ +#define SLAP_C_UNUSED 0x01 +#define SLAP_C_USED 0x02 + +/* connection state (protected by c_mutex ) */ +#define SLAP_C_INVALID 0x00 /* MUST BE ZERO (0) */ +#define SLAP_C_INACTIVE 0x01 /* zero threads */ +#define SLAP_C_ACTIVE 0x02 /* one or more threads */ +#define SLAP_C_BINDING 0x03 /* binding */ +#define SLAP_C_CLOSING 0x04 /* closing */ + +const char * +connection_state2str( int state ) +{ + switch( state ) { + case SLAP_C_INVALID: return "!"; + case SLAP_C_INACTIVE: return "|"; + case SLAP_C_ACTIVE: return ""; + case SLAP_C_BINDING: return "B"; + case SLAP_C_CLOSING: return "C"; + } + + return "?"; +} + +static Connection* connection_get( ber_socket_t s ); + +static int connection_input( Connection *c ); +static void connection_close( Connection *c ); + +static int connection_op_activate( Connection *conn, Operation *op ); +static int connection_resched( Connection *conn ); +static void connection_abandon( Connection *conn ); +static void connection_destroy( Connection *c ); struct co_arg { Connection *co_conn; Operation *co_op; }; +/* + * Initialize connection management infrastructure. + */ +int connections_init(void) +{ + assert( connections == NULL ); + + if( connections != NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connections_init: already initialized.\n" )); +#else + Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n", + 0, 0, 0 ); +#endif + return -1; + } + + /* should check return of every call */ + ldap_pvt_thread_mutex_init( &connections_mutex ); + + connections = (Connection *) calloc( dtblsize, sizeof(Connection) ); + + if( connections == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connections_init: allocation (%d * %ld) of connection array failed\n", + dtblsize, (long) sizeof(Connection) )); +#else + Debug( LDAP_DEBUG_ANY, + "connections_init: allocation (%d*%ld) of connection array failed\n", + dtblsize, (long) sizeof(Connection), 0 ); +#endif + return -1; + } + + assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED ); + assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED ); + + /* + * per entry initialization of the Connection array initialization + * will be done by connection_init() + */ + + return 0; +} + +/* + * Destroy connection management infrastructure. + */ +int connections_destroy(void) +{ + ber_socket_t i; + + /* should check return of every call */ + + if( connections == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connections_destroy: nothing to destroy.\n")); +#else + Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n", + 0, 0, 0 ); +#endif + return -1; + } + + for ( i = 0; i < dtblsize; i++ ) { + if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) { + ber_sockbuf_free( connections[i].c_sb ); + ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex ); + ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex ); + ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv ); + } + } + + free( connections ); + connections = NULL; + + ldap_pvt_thread_mutex_destroy( &connections_mutex ); + return 0; +} + +/* + * shutdown all connections + */ +int connections_shutdown(void) +{ + ber_socket_t i; + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + for ( i = 0; i < dtblsize; i++ ) { + if( connections[i].c_struct_state != SLAP_C_USED ) { + continue; + } + + ldap_pvt_thread_mutex_lock( &connections[i].c_mutex ); + + /* connections_mutex and c_mutex are locked */ + connection_closing( &connections[i] ); + connection_close( &connections[i] ); + + ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex ); + } + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + + return 0; +} + +/* + * Timeout idle connections. + */ +int connections_timeout_idle(time_t now) +{ + int i = 0; + int connindex; + Connection* c; + + for( c = connection_first( &connindex ); + c != NULL; + c = connection_next( c, &connindex ) ) + { + if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) { + /* close it */ + connection_closing( c ); + connection_close( c ); + i++; + } + } + connection_done( c ); + + return i; +} + +static Connection* connection_get( ber_socket_t s ) +{ + /* connections_mutex should be locked by caller */ + + Connection *c; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ENTRY, + "connection_get: socket %ld\n", (long)s )); +#else + Debug( LDAP_DEBUG_ARGS, + "connection_get(%ld)\n", + (long) s, 0, 0 ); +#endif + + assert( connections != NULL ); + + if(s == AC_SOCKET_INVALID) { + return NULL; + } + +#ifndef HAVE_WINSOCK + c = &connections[s]; + + assert( c->c_struct_state != SLAP_C_UNINITIALIZED ); + +#else + c = NULL; + { + ber_socket_t i, sd; + + for(i=0; i<dtblsize; i++) { + if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) { + assert( connections[i].c_conn_state == SLAP_C_INVALID ); + assert( connections[i].c_sb == 0 ); + break; + } + + ber_sockbuf_ctrl( connections[i].c_sb, + LBER_SB_OPT_GET_FD, &sd ); + + if( connections[i].c_struct_state == SLAP_C_UNUSED ) { + assert( connections[i].c_conn_state == SLAP_C_INVALID ); + assert( sd == AC_SOCKET_INVALID ); + continue; + } + + /* state can actually change from used -> unused by resched, + * so don't assert details here. + */ + + if( sd == s ) { + c = &connections[i]; + break; + } + } + } +#endif + + if( c != NULL ) { + ber_socket_t sd; + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + if( c->c_struct_state != SLAP_C_USED ) { + /* connection must have been closed due to resched */ + + assert( c->c_conn_state == SLAP_C_INVALID ); + assert( sd == AC_SOCKET_INVALID ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ARGS, + "connection_get: connection %d not used\n", s )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_get(%d): connection not used\n", + s, 0, 0 ); +#endif + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + return NULL; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS, + "connection_get: get for %d got connid %lu\n", s, c->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_get(%d): got connid=%lu\n", + s, c->c_connid, 0 ); +#endif + + c->c_n_get++; + + assert( c->c_struct_state == SLAP_C_USED ); + assert( c->c_conn_state != SLAP_C_INVALID ); + assert( sd != AC_SOCKET_INVALID ); + +#ifdef SLAPD_MONITOR + c->c_activitytime = slap_get_time(); +#else + if( global_idletimeout > 0 ) { + c->c_activitytime = slap_get_time(); + } +#endif + } + + return c; +} + +static void connection_return( Connection *c ) +{ + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); +} + +long connection_init( + ber_socket_t s, + const char* url, + const char* dnsname, + const char* peername, + const char* sockname, + int tls_udp_option, + slap_ssf_t ssf, + const char *authid ) +{ + unsigned long id; + Connection *c; + + assert( connections != NULL ); + + assert( dnsname != NULL ); + assert( peername != NULL ); + assert( sockname != NULL ); + +#ifndef HAVE_TLS + assert( tls_udp_option != 1 ); +#endif + + if( s == AC_SOCKET_INVALID ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_init: init of socket %ld invalid.\n", (long)s )); +#else + Debug( LDAP_DEBUG_ANY, + "connection_init(%ld): invalid.\n", + (long) s, 0, 0 ); +#endif + return -1; + } + + assert( s >= 0 ); +#ifndef HAVE_WINSOCK + assert( s < dtblsize ); +#endif + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + +#ifndef HAVE_WINSOCK + c = &connections[s]; + +#else + { + ber_socket_t i; + + c = NULL; + + for( i=0; i < dtblsize; i++) { + ber_socket_t sd; + + if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) { + assert( connections[i].c_sb == 0 ); + c = &connections[i]; + break; + } + + sd = AC_SOCKET_INVALID; + if (connections[i].c_sb != NULL) + ber_sockbuf_ctrl( connections[i].c_sb, LBER_SB_OPT_GET_FD, &sd ); + + if( connections[i].c_struct_state == SLAP_C_UNUSED ) { + assert( sd == AC_SOCKET_INVALID ); + c = &connections[i]; + break; + } + + assert( connections[i].c_struct_state == SLAP_C_USED ); + assert( connections[i].c_conn_state != SLAP_C_INVALID ); + assert( sd != AC_SOCKET_INVALID ); + } + + if( c == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_init: skt %d connection table full (%d/%d)\n", + s, i, dtblsize )); +#else + Debug( LDAP_DEBUG_ANY, + "connection_init(%d): connection table full (%d/%d)\n", + s, i, dtblsize); +#endif + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return -1; + } + } +#endif + + assert( c != NULL ); + + if( c->c_struct_state == SLAP_C_UNINITIALIZED ) { + c->c_authmech.bv_val = NULL; + c->c_authmech.bv_len = 0; + c->c_dn.bv_val = NULL; + c->c_dn.bv_len = 0; + c->c_ndn.bv_val = NULL; + c->c_ndn.bv_len = 0; + c->c_cdn.bv_val = NULL; + c->c_cdn.bv_len = 0; + c->c_groups = NULL; + + c->c_listener_url.bv_val = NULL; + c->c_listener_url.bv_len = 0; + c->c_peer_domain.bv_val = NULL; + c->c_peer_domain.bv_len = 0; + c->c_peer_name.bv_val = NULL; + c->c_peer_name.bv_len = 0; + c->c_sock_name.bv_val = NULL; + c->c_sock_name.bv_len = 0; + + LDAP_STAILQ_INIT(&c->c_ops); + LDAP_STAILQ_INIT(&c->c_pending_ops); + + c->c_sasl_bind_mech.bv_val = NULL; + c->c_sasl_bind_mech.bv_len = 0; + c->c_sasl_context = NULL; + c->c_sasl_extra = NULL; + + c->c_sb = ber_sockbuf_alloc( ); + + { + ber_len_t max = sockbuf_max_incoming; + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + + c->c_currentber = NULL; + + /* should check status of thread calls */ + ldap_pvt_thread_mutex_init( &c->c_mutex ); + ldap_pvt_thread_mutex_init( &c->c_write_mutex ); + ldap_pvt_thread_cond_init( &c->c_write_cv ); + + c->c_struct_state = SLAP_C_UNUSED; + } + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + + assert( c->c_struct_state == SLAP_C_UNUSED ); + assert( c->c_authmech.bv_val == NULL ); + assert( c->c_dn.bv_val == NULL ); + assert( c->c_ndn.bv_val == NULL ); + assert( c->c_cdn.bv_val == NULL ); + assert( c->c_groups == NULL ); + assert( c->c_listener_url.bv_val == NULL ); + assert( c->c_peer_domain.bv_val == NULL ); + assert( c->c_peer_name.bv_val == NULL ); + assert( c->c_sock_name.bv_val == NULL ); + assert( LDAP_STAILQ_EMPTY(&c->c_ops) ); + assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) ); + assert( c->c_sasl_bind_mech.bv_val == NULL ); + assert( c->c_sasl_context == NULL ); + assert( c->c_sasl_extra == NULL ); + assert( c->c_currentber == NULL ); + + ber_str2bv( url, 0, 1, &c->c_listener_url ); + ber_str2bv( dnsname, 0, 1, &c->c_peer_domain ); + ber_str2bv( peername, 0, 1, &c->c_peer_name ); + ber_str2bv( sockname, 0, 1, &c->c_sock_name ); + + c->c_n_ops_received = 0; + c->c_n_ops_executing = 0; + c->c_n_ops_pending = 0; + c->c_n_ops_completed = 0; + + c->c_n_get = 0; + c->c_n_read = 0; + c->c_n_write = 0; + + /* set to zero until bind, implies LDAP_VERSION3 */ + c->c_protocol = 0; + +#ifdef SLAPD_MONITOR + c->c_activitytime = c->c_starttime = slap_get_time(); +#else + if( global_idletimeout > 0 ) { + c->c_activitytime = c->c_starttime = slap_get_time(); + } +#endif + +#ifdef LDAP_CONNECTIONLESS + c->c_is_udp = 0; + if (tls_udp_option == 2) + { + c->c_is_udp = 1; +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" ); +#endif + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_udp, + LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead, + LBER_SBIOD_LEVEL_PROVIDER, NULL ); + } else +#endif + { +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" ); +#endif + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp, + LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); + } + +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, + INT_MAX, (void*)"ldap_" ); +#endif + + if( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_NONBLOCK, + c /* non-NULL */ ) < 0 ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_init: conn %lu set nonblocking failed\n", + c->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "connection_init(%d, %s): set nonblocking failed\n", + s, c->c_peer_name.bv_val, 0 ); +#endif + } + + id = c->c_connid = conn_nextid++; + + c->c_conn_state = SLAP_C_INACTIVE; + c->c_struct_state = SLAP_C_USED; + + c->c_ssf = c->c_transport_ssf = ssf; + c->c_tls_ssf = 0; + +#ifdef HAVE_TLS + if ( tls_udp_option == 1 ) { + c->c_is_tls = 1; + c->c_needs_tls_accept = 1; + } else { + c->c_is_tls = 0; + c->c_needs_tls_accept = 0; + } +#endif + + slap_sasl_open( c ); + slap_sasl_external( c, ssf, authid ); + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + + backend_connection_init(c); + + return id; +} + +void connection2anonymous( Connection *c ) +{ + assert( connections != NULL ); + assert( c != NULL ); + + { + ber_len_t max = sockbuf_max_incoming; + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + + if(c->c_authmech.bv_val != NULL ) { + free(c->c_authmech.bv_val); + c->c_authmech.bv_val = NULL; + } + c->c_authmech.bv_len = 0; + + if(c->c_dn.bv_val != NULL) { + free(c->c_dn.bv_val); + c->c_dn.bv_val = NULL; + } + c->c_dn.bv_len = 0; + if(c->c_ndn.bv_val != NULL) { + free(c->c_ndn.bv_val); + c->c_ndn.bv_val = NULL; + } + c->c_ndn.bv_len = 0; + + if(c->c_cdn.bv_val != NULL) { + free(c->c_cdn.bv_val); + c->c_cdn.bv_val = NULL; + } + c->c_cdn.bv_len = 0; + + c->c_authz_backend = NULL; + + { + GroupAssertion *g, *n; + for (g = c->c_groups; g; g=n) + { + n = g->ga_next; + free(g); + } + c->c_groups = NULL; + } + +} + +static void +connection_destroy( Connection *c ) +{ + /* note: connections_mutex should be locked by caller */ + ber_socket_t sd; + unsigned long connid; + + assert( connections != NULL ); + assert( c != NULL ); + assert( c->c_struct_state != SLAP_C_UNUSED ); + assert( c->c_conn_state != SLAP_C_INVALID ); + assert( LDAP_STAILQ_EMPTY(&c->c_ops) ); + + /* only for stats (print -1 as "%lu" may give unexpected results ;) */ + connid = c->c_connid; + + backend_connection_destroy(c); + + c->c_protocol = 0; + c->c_connid = -1; + + c->c_activitytime = c->c_starttime = 0; + + connection2anonymous( c ); + + if(c->c_listener_url.bv_val != NULL) { + free(c->c_listener_url.bv_val); + c->c_listener_url.bv_val = NULL; + } + c->c_listener_url.bv_len = 0; + + if(c->c_peer_domain.bv_val != NULL) { + free(c->c_peer_domain.bv_val); + c->c_peer_domain.bv_val = NULL; + } + c->c_peer_domain.bv_len = 0; + if(c->c_peer_name.bv_val != NULL) { +#ifdef LDAP_PF_LOCAL + /* + * If peer was a domain socket, unlink. Mind you, + * they may be un-named. Should we leave this to + * the client? + */ + if (strncmp(c->c_peer_name.bv_val, "PATH=", + sizeof("PATH=") - 1) == 0) { + char *path = c->c_peer_name.bv_val + + sizeof("PATH=") - 1; + if (path[0] != '\0') { + (void)unlink(path); + } + } +#endif /* LDAP_PF_LOCAL */ + + free(c->c_peer_name.bv_val); + c->c_peer_name.bv_val = NULL; + } + c->c_peer_name.bv_len = 0; + if(c->c_sock_name.bv_val != NULL) { + free(c->c_sock_name.bv_val); + c->c_sock_name.bv_val = NULL; + } + c->c_sock_name.bv_len = 0; + + c->c_sasl_bind_in_progress = 0; + if(c->c_sasl_bind_mech.bv_val != NULL) { + free(c->c_sasl_bind_mech.bv_val); + c->c_sasl_bind_mech.bv_val = NULL; + } + c->c_sasl_bind_mech.bv_len = 0; + + slap_sasl_close( c ); + + if ( c->c_currentber != NULL ) { + ber_free( c->c_currentber, 1 ); + c->c_currentber = NULL; + } + + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + if ( sd != AC_SOCKET_INVALID ) { + slapd_remove( sd, 0 ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu fd=%d closed\n", + connid, sd, 0, 0, 0 ); + } + + ber_sockbuf_free( c->c_sb ); + + c->c_sb = ber_sockbuf_alloc( ); + + { + ber_len_t max = sockbuf_max_incoming; + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + + c->c_conn_state = SLAP_C_INVALID; + c->c_struct_state = SLAP_C_UNUSED; +} + +int connection_state_closing( Connection *c ) +{ + /* c_mutex must be locked by caller */ + + int state; + assert( c != NULL ); + assert( c->c_struct_state == SLAP_C_USED ); + + state = c->c_conn_state; + + assert( state != SLAP_C_INVALID ); + + return state == SLAP_C_CLOSING; +} + +static void connection_abandon( Connection *c ) +{ + /* c_mutex must be locked by caller */ + + Operation *o; + + LDAP_STAILQ_FOREACH(o, &c->c_ops, o_next) { + o->o_abandon = 1; + } + + /* remove pending operations */ + while ( (o = LDAP_STAILQ_FIRST( &c->c_pending_ops )) != NULL) { + LDAP_STAILQ_REMOVE_HEAD( &c->c_pending_ops, o_next ); + LDAP_STAILQ_NEXT(o, o_next) = NULL; + slap_op_free( o ); + } +} + +void connection_closing( Connection *c ) +{ + assert( connections != NULL ); + assert( c != NULL ); + assert( c->c_struct_state == SLAP_C_USED ); + assert( c->c_conn_state != SLAP_C_INVALID ); + + /* c_mutex must be locked by caller */ + + if( c->c_conn_state != SLAP_C_CLOSING ) { + ber_socket_t sd; + + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_closing: conn %lu readying socket %d for close.\n", + c->c_connid, sd )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_closing: readying conn=%lu sd=%d for close\n", + c->c_connid, sd, 0 ); +#endif + /* update state to closing */ + c->c_conn_state = SLAP_C_CLOSING; + + /* don't listen on this port anymore */ + slapd_clr_read( sd, 1 ); + + /* abandon active operations */ + connection_abandon( c ); + + /* wake write blocked operations */ + slapd_clr_write( sd, 1 ); + ldap_pvt_thread_cond_signal( &c->c_write_cv ); + } +} + +static void connection_close( Connection *c ) +{ + ber_socket_t sd; + + assert( connections != NULL ); + assert( c != NULL ); + assert( c->c_struct_state == SLAP_C_USED ); + assert( c->c_conn_state == SLAP_C_CLOSING ); + + /* note: connections_mutex and c_mutex should be locked by caller */ + + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + if( !LDAP_STAILQ_EMPTY(&c->c_ops) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_close: conn %lu deferring sd %d\n", + c->c_connid, sd )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_close: deferring conn=%lu sd=%d\n", + c->c_connid, sd, 0 ); +#endif + return; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS, + "connection_close: conn %lu sd %d\n", + c->c_connid, sd )); +#else + Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%lu sd=%d\n", + c->c_connid, sd, 0 ); +#endif + connection_destroy( c ); +} + +unsigned long connections_nextid(void) +{ + unsigned long id; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + id = conn_nextid; + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + + return id; +} + +Connection* connection_first( ber_socket_t *index ) +{ + assert( connections != NULL ); + assert( index != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + *index = 0; + + return connection_next(NULL, index); +} + +Connection* connection_next( Connection *c, ber_socket_t *index ) +{ + assert( connections != NULL ); + assert( index != NULL ); + assert( *index <= dtblsize ); + + if( c != NULL ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + } + + c = NULL; + + for(; *index < dtblsize; (*index)++) { + if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) { + assert( connections[*index].c_conn_state == SLAP_C_INVALID ); +#ifndef HAVE_WINSOCK + continue; +#else + break; +#endif + } + + if( connections[*index].c_struct_state == SLAP_C_USED ) { + assert( connections[*index].c_conn_state != SLAP_C_INVALID ); + c = &connections[(*index)++]; + break; + } + + assert( connections[*index].c_struct_state == SLAP_C_UNUSED ); + assert( connections[*index].c_conn_state == SLAP_C_INVALID ); + } + + if( c != NULL ) { + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + } + + return c; +} + +void connection_done( Connection *c ) +{ + assert( connections != NULL ); + + if( c != NULL ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + } + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); +} + /* * connection_activity - handle the request operation op on connection * conn. This routine figures out what kind of operation it is and * calls the appropriate stub to handle it. */ -static void -connection_operation( struct co_arg *arg ) +#ifdef SLAPD_MONITOR +#define INCR_OP(var,index) \ + do { \ + ldap_pvt_thread_mutex_lock( &num_ops_mutex ); \ + (var)[(index)]++; \ + ldap_pvt_thread_mutex_unlock( &num_ops_mutex ); \ + } while (0) +#else /* !SLAPD_MONITOR */ +#define INCR_OP(var,index) +#endif /* !SLAPD_MONITOR */ + +static void * +connection_operation( void *arg_v ) { - unsigned long len; + int rc; + struct co_arg *arg = arg_v; + ber_tag_t tag = arg->co_op->o_tag; +#ifdef SLAPD_MONITOR + ber_tag_t oldtag = tag; +#endif /* SLAPD_MONITOR */ + Connection *conn = arg->co_conn; - pthread_mutex_lock( &arg->co_conn->c_opsmutex ); - arg->co_conn->c_opsinitiated++; - pthread_mutex_unlock( &arg->co_conn->c_opsmutex ); + ldap_pvt_thread_mutex_lock( &num_ops_mutex ); + num_ops_initiated++; + ldap_pvt_thread_mutex_unlock( &num_ops_mutex ); - pthread_mutex_lock( &ops_mutex ); - ops_initiated++; - pthread_mutex_unlock( &ops_mutex ); + if( conn->c_sasl_bind_in_progress && tag != LDAP_REQ_BIND ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_operation: conn %lu SASL bind in progress (tag=%ld).\n", + conn->c_connid, (long)tag )); +#else + Debug( LDAP_DEBUG_ANY, "connection_operation: " + "error: SASL bind in progress (tag=%ld).\n", + (long) tag, 0, 0 ); +#endif + send_ldap_result( conn, arg->co_op, + rc = LDAP_OPERATIONS_ERROR, + NULL, "SASL bind in progress", NULL, NULL ); + goto operations_error; + } - switch ( arg->co_op->o_tag ) { + switch ( tag ) { case LDAP_REQ_BIND: - do_bind( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_BIND); + rc = do_bind( conn, arg->co_op ); break; -#ifdef COMPAT30 - case LDAP_REQ_UNBIND_30: -#endif case LDAP_REQ_UNBIND: - do_unbind( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_UNBIND); + rc = do_unbind( conn, arg->co_op ); break; case LDAP_REQ_ADD: - do_add( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_ADD); + rc = do_add( conn, arg->co_op ); break; -#ifdef COMPAT30 - case LDAP_REQ_DELETE_30: -#endif case LDAP_REQ_DELETE: - do_delete( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_DELETE); + rc = do_delete( conn, arg->co_op ); break; case LDAP_REQ_MODRDN: - do_modrdn( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_MODRDN); + rc = do_modrdn( conn, arg->co_op ); break; case LDAP_REQ_MODIFY: - do_modify( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_MODIFY); + rc = do_modify( conn, arg->co_op ); break; case LDAP_REQ_COMPARE: - do_compare( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_COMPARE); + rc = do_compare( conn, arg->co_op ); break; case LDAP_REQ_SEARCH: - do_search( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_SEARCH); + rc = do_search( conn, arg->co_op ); break; -#ifdef COMPAT30 - case LDAP_REQ_ABANDON_30: -#endif case LDAP_REQ_ABANDON: - do_abandon( arg->co_conn, arg->co_op ); + INCR_OP(num_ops_initiated_, SLAP_OP_ABANDON); + rc = do_abandon( conn, arg->co_op ); + break; + + case LDAP_REQ_EXTENDED: + INCR_OP(num_ops_initiated_, SLAP_OP_EXTENDED); + rc = do_extended( conn, arg->co_op ); break; default: - Debug( LDAP_DEBUG_ANY, "unknown request 0x%x\n", - arg->co_op->o_tag, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_operation: conn %lu unknown LDAP request 0x%lx\n", + conn->c_connid, tag )); +#else + Debug( LDAP_DEBUG_ANY, "unknown LDAP request 0x%lx\n", + tag, 0, 0 ); +#endif + arg->co_op->o_tag = LBER_ERROR; + send_ldap_disconnect( conn, arg->co_op, + LDAP_PROTOCOL_ERROR, "unknown LDAP request" ); + rc = -1; + break; + } + +#ifdef SLAPD_MONITOR + oldtag = tag; +#endif /* SLAPD_MONITOR */ + if( rc == SLAPD_DISCONNECT ) tag = LBER_ERROR; + +operations_error: + ldap_pvt_thread_mutex_lock( &num_ops_mutex ); + num_ops_completed++; +#ifdef SLAPD_MONITOR + switch (oldtag) { + case LDAP_REQ_BIND: + num_ops_completed_[SLAP_OP_BIND]++; + break; + case LDAP_REQ_UNBIND: + num_ops_completed_[SLAP_OP_UNBIND]++; + break; + case LDAP_REQ_ADD: + num_ops_completed_[SLAP_OP_ADD]++; + break; + case LDAP_REQ_DELETE: + num_ops_completed_[SLAP_OP_DELETE]++; + break; + case LDAP_REQ_MODRDN: + num_ops_completed_[SLAP_OP_MODRDN]++; + break; + case LDAP_REQ_MODIFY: + num_ops_completed_[SLAP_OP_MODIFY]++; + break; + case LDAP_REQ_COMPARE: + num_ops_completed_[SLAP_OP_COMPARE]++; + break; + case LDAP_REQ_SEARCH: + num_ops_completed_[SLAP_OP_SEARCH]++; + break; + case LDAP_REQ_ABANDON: + num_ops_completed_[SLAP_OP_ABANDON]++; + break; + case LDAP_REQ_EXTENDED: + num_ops_completed_[SLAP_OP_EXTENDED]++; break; } +#endif /* SLAPD_MONITOR */ + ldap_pvt_thread_mutex_unlock( &num_ops_mutex ); + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - pthread_mutex_lock( &arg->co_conn->c_opsmutex ); - arg->co_conn->c_opscompleted++; - op_delete( &arg->co_conn->c_ops, arg->co_op ); - pthread_mutex_unlock( &arg->co_conn->c_opsmutex ); + conn->c_n_ops_executing--; + conn->c_n_ops_completed++; + LDAP_STAILQ_REMOVE( &conn->c_ops, arg->co_op, slap_op, o_next); + LDAP_STAILQ_NEXT(arg->co_op, o_next) = NULL; + slap_op_free( arg->co_op ); + arg->co_op = NULL; + arg->co_conn = NULL; free( (char *) arg ); + arg = NULL; + + switch( tag ) { + case LBER_ERROR: + case LDAP_REQ_UNBIND: + /* c_mutex is locked */ + connection_closing( conn ); + break; + + case LDAP_REQ_BIND: + conn->c_sasl_bind_in_progress = + rc == LDAP_SASL_BIND_IN_PROGRESS ? 1 : 0; + + if( conn->c_conn_state == SLAP_C_BINDING) { + conn->c_conn_state = SLAP_C_ACTIVE; + } + } + + connection_resched( conn ); + + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + return NULL; +} + +int connection_read(ber_socket_t s) +{ + int rc = 0; + Connection *c; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + /* get (locked) connection */ + c = connection_get( s ); + + if( c == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_read: sock %ld no connection\n", + (long)s )); +#else + Debug( LDAP_DEBUG_ANY, + "connection_read(%ld): no connection!\n", + (long) s, 0, 0 ); +#endif + slapd_remove(s, 0); + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return -1; + } + + c->c_n_read++; - pthread_mutex_lock( &ops_mutex ); - ops_completed++; - pthread_mutex_unlock( &ops_mutex ); + if( c->c_conn_state == SLAP_C_CLOSING ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_read: conn %lu connection closing, ignoring input\n", + c->c_connid)); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): closing, ignoring input for id=%lu\n", + s, c->c_connid, 0 ); +#endif + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_read: conn %lu checking for input.\n", c->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): checking for input on id=%lu\n", + s, c->c_connid, 0 ); +#endif + +#ifdef HAVE_TLS + if ( c->c_is_tls && c->c_needs_tls_accept ) { + rc = ldap_pvt_tls_accept( c->c_sb, NULL ); + if ( rc < 0 ) { +#if 0 /* required by next #if 0 */ + struct timeval tv; + fd_set rfd; +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_read: conn %lu TLS accept error, error %d\n", + c->c_connid, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): TLS accept error " + "error=%d id=%lu, closing\n", + s, rc, c->c_connid ); +#endif + c->c_needs_tls_accept = 0; + /* connections_mutex and c_mutex are locked */ + connection_closing( c ); + +#if 0 + /* Drain input before close, to allow SSL error codes + * to propagate to client. */ + FD_ZERO(&rfd); + FD_SET(s, &rfd); + for (rc=1; rc>0;) + { + tv.tv_sec = 1; + tv.tv_usec = 0; + rc = select(s+1, &rfd, NULL, NULL, &tv); + if (rc == 1) + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DRAIN, + NULL); + } +#endif + connection_close( c ); + + } else if ( rc == 0 ) { + void *ssl; + char *authid; + + c->c_needs_tls_accept = 0; + + /* we need to let SASL know */ + ssl = ldap_pvt_tls_sb_ctx( c->c_sb ); + + c->c_tls_ssf = (slap_ssf_t) ldap_pvt_tls_get_strength( ssl ); + if( c->c_tls_ssf > c->c_ssf ) { + c->c_ssf = c->c_tls_ssf; + } + + authid = (char *)ldap_pvt_tls_get_peer( ssl ); + slap_sasl_external( c, c->c_tls_ssf, authid ); + } + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; + } +#endif + +#ifdef HAVE_CYRUS_SASL + if ( c->c_sasl_layers ) { + c->c_sasl_layers = 0; + + rc = ldap_pvt_sasl_install( c->c_sb, c->c_sasl_context ); + + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_read: conn %lu SASL install error %d, closing\n", + c->c_connid, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): SASL install error " + "error=%d id=%lu, closing\n", + s, rc, c->c_connid ); +#endif + /* connections_mutex and c_mutex are locked */ + connection_closing( c ); + connection_close( c ); + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; + } + } +#endif + +#define CONNECTION_INPUT_LOOP 1 + +#ifdef DATA_READY_LOOP + while( !rc && ber_sockbuf_ctrl( c->c_sb, LBER_SB_DATA_READY, NULL ) ) +#elif CONNECTION_INPUT_LOOP + while(!rc) +#endif + { + /* How do we do this without getting into a busy loop ? */ + rc = connection_input( c ); + } - pthread_mutex_lock( &active_threads_mutex ); - active_threads--; - pthread_mutex_unlock( &active_threads_mutex ); + if( rc < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_read: conn %lu input error %d, closing.\n", + c->c_connid, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): input error=%d id=%lu, closing.\n", + s, rc, c->c_connid ); +#endif + /* connections_mutex and c_mutex are locked */ + connection_closing( c ); + connection_close( c ); + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; + } + + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) { + slapd_set_read( s, 1 ); + } + + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) { + slapd_set_write( s, 1 ); + } + + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; } -void -connection_activity( +static int +connection_input( Connection *conn ) { - pthread_attr_t attr; - struct co_arg *arg; - unsigned long tag, len; - long msgid; + Operation *op; + ber_tag_t tag; + ber_len_t len; + ber_int_t msgid; BerElement *ber; - char *tmpdn; +#ifdef LDAP_CONNECTIONLESS + Sockaddr peeraddr; + char *cdn = NULL; +#endif if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc()) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_input: conn %lu ber_alloc failed.\n", + conn->c_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - return; +#endif + return -1; } errno = 0; - if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber )) - != LDAP_TAG_MESSAGE ) { + +#ifdef LDAP_CONNECTIONLESS + if (conn->c_is_udp) + { + char peername[sizeof("IP=255.255.255.255:65336")]; + len = ber_int_sb_read(conn->c_sb, &peeraddr, + sizeof(struct sockaddr)); + if (len != sizeof(struct sockaddr)) + return 1; + sprintf( peername, "IP=%s:%d", + inet_ntoa( peeraddr.sa_in_addr.sin_addr ), + (unsigned) ntohs( peeraddr.sa_in_addr.sin_port ) ); + Statslog( LDAP_DEBUG_STATS, + "conn=%lu UDP request from %s (%s) accepted.\n", + conn->c_connid, peername, conn->c_sock_name.bv_val, 0, 0 ); + } +#endif + tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ); + if ( tag != LDAP_TAG_MESSAGE ) { + int err = errno; + ber_socket_t sd; + + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_input: conn %lu ber_get_next failed, errno %d (%s).\n", + conn->c_connid, err, sock_errstr(err) )); +#else Debug( LDAP_DEBUG_TRACE, - "ber_get_next on fd %d failed errno %d (%s)\n", - conn->c_sb.sb_sd, errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown" ); - Debug( LDAP_DEBUG_TRACE, "*** got %d of %d so far\n", - conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf, - conn->c_currentber->ber_len, 0 ); - - if ( errno != EWOULDBLOCK && errno != EAGAIN ) { + "ber_get_next on fd %d failed errno=%d (%s)\n", + sd, err, sock_errstr(err) ); +#endif + if ( err != EWOULDBLOCK && err != EAGAIN ) { /* log, close and send error */ ber_free( conn->c_currentber, 1 ); conn->c_currentber = NULL; - close_connection( conn, conn->c_connid, -1 ); + return -2; } - - return; + return 1; } + ber = conn->c_currentber; conn->c_currentber = NULL; if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) { /* log, close and send error */ - Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%x\n", tag, 0, +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_input: conn %lu ber_get_int returns 0x%lx.\n", + conn->c_connid, tag )); +#else + Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0, 0 ); +#endif ber_free( ber, 1 ); - - close_connection( conn, conn->c_connid, -1 ); - return; + return -1; } if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { /* log, close and send error */ - Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%x\n", tag, 0, +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_input: conn %lu ber_peek_tag returns 0x%lx.\n", + conn->c_connid, tag )); +#else + Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0, 0 ); +#endif ber_free( ber, 1 ); - close_connection( conn, conn->c_connid, -1 ); - return; + return -1; } -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - (void) ber_skip_tag( ber, &len ); +#ifdef LDAP_CONNECTIONLESS + if (conn->c_is_udp) { + if (tag == LBER_OCTETSTRING) { + ber_get_stringa( ber, &cdn ); + tag = ber_peek_tag(ber, &len); + } + if (tag != LDAP_REQ_ABANDON && tag != LDAP_REQ_SEARCH) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_input: conn %lu invalid req for UDP 0x%lx.\n", + conn->c_connid, tag )); +#else + Debug( LDAP_DEBUG_ANY, "invalid req for UDP 0x%lx\n", tag, 0, + 0 ); +#endif + ber_free( ber, 1 ); + return 0; + } } #endif + if(tag == LDAP_REQ_BIND) { + /* immediately abandon all exiting operations upon BIND */ + connection_abandon( conn ); + } + + op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ ); + + op->o_pagedresults_state = conn->c_pagedresults_state; + +#ifdef LDAP_CONNECTIONLESS + op->o_peeraddr = peeraddr; + if (cdn) { + ber_str2bv( cdn, 0, 1, &op->o_dn ); + op->o_protocol = LDAP_VERSION2; + } +#endif + if ( conn->c_conn_state == SLAP_C_BINDING + || conn->c_conn_state == SLAP_C_CLOSING ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_input: conn %lu deferring operation\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 ); +#endif + conn->c_n_ops_pending++; + LDAP_STAILQ_INSERT_TAIL( &conn->c_pending_ops, op, o_next ); + + } else { + conn->c_n_ops_executing++; + connection_op_activate( conn, op ); + } + +#ifdef NO_THREADS + if ( conn->c_struct_state != SLAP_C_USED ) { + /* connection must have got closed underneath us */ + return 1; + } +#endif + assert( conn->c_struct_state == SLAP_C_USED ); + + return 0; +} + +static int +connection_resched( Connection *conn ) +{ + Operation *op; + + if( conn->c_conn_state == SLAP_C_CLOSING ) { + int rc; + ber_socket_t sd; + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); + + /* us trylock to avoid possible deadlock */ + rc = ldap_pvt_thread_mutex_trylock( &connections_mutex ); + + if( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_resched: conn %lu reaquiring locks.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_resched: reaquiring locks conn=%lu sd=%d\n", + conn->c_connid, sd, 0 ); +#endif + /* + * reaquire locks in the right order... + * this may allow another thread to close this connection, + * so recheck state below. + */ + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_lock( &connections_mutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + } + + if( conn->c_conn_state != SLAP_C_CLOSING ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "connection_resched: conn %lu closed by other thread.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "connection_resched: " + "closed by other thread conn=%lu sd=%d\n", + conn->c_connid, sd, 0 ); +#endif + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_resched: conn %lu attempting closing.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "connection_resched: " + "attempting closing conn=%lu sd=%d\n", + conn->c_connid, sd, 0 ); +#endif + connection_close( conn ); + } + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; + } + + if( conn->c_conn_state != SLAP_C_ACTIVE ) { + /* other states need different handling */ + return 0; + } + + while ((op = LDAP_STAILQ_FIRST( &conn->c_pending_ops )) != NULL) { + LDAP_STAILQ_REMOVE_HEAD( &conn->c_pending_ops, o_next ); + LDAP_STAILQ_NEXT(op, o_next) = NULL; + /* pending operations should not be marked for abandonment */ + assert(!op->o_abandon); + + conn->c_n_ops_pending--; + conn->c_n_ops_executing++; + + connection_op_activate( conn, op ); + + if ( conn->c_conn_state == SLAP_C_BINDING ) { + break; + } + } + return 0; +} + +static int connection_op_activate( Connection *conn, Operation *op ) +{ + struct co_arg *arg; + int status; + ber_tag_t tag = op->o_tag; + + if(tag == LDAP_REQ_BIND) { + conn->c_conn_state = SLAP_C_BINDING; + } arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) ); arg->co_conn = conn; + arg->co_op = op; - pthread_mutex_lock( &conn->c_dnmutex ); - if ( conn->c_dn != NULL ) { - tmpdn = strdup( conn->c_dn ); - } else { - tmpdn = NULL; + if (!arg->co_op->o_dn.bv_len) { + arg->co_op->o_authz = conn->c_authz; + arg->co_op->o_dn.bv_val = ch_strdup( conn->c_dn.bv_val ? + conn->c_dn.bv_val : "" ); + arg->co_op->o_ndn.bv_val = ch_strdup( conn->c_ndn.bv_val ? + conn->c_ndn.bv_val : "" ); } - pthread_mutex_unlock( &conn->c_dnmutex ); + arg->co_op->o_authtype = conn->c_authtype; + ber_dupbv( &arg->co_op->o_authmech, &conn->c_authmech ); + + if (!arg->co_op->o_protocol) { + arg->co_op->o_protocol = conn->c_protocol + ? conn->c_protocol : LDAP_VERSION3; + } + arg->co_op->o_connid = conn->c_connid; + + LDAP_STAILQ_INSERT_TAIL( &conn->c_ops, arg->co_op, o_next ); - pthread_mutex_lock( &conn->c_opsmutex ); - arg->co_op = op_add( &conn->c_ops, ber, msgid, tag, tmpdn, - conn->c_opsinitiated, conn->c_connid ); - pthread_mutex_unlock( &conn->c_opsmutex ); + status = ldap_pvt_thread_pool_submit( &connection_pool, + connection_operation, (void *) arg ); - if ( tmpdn != NULL ) { - free( tmpdn ); + if ( status != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_op_activate: conn %lu thread pool submit failed.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "ldap_pvt_thread_pool_submit failed (%d)\n", status, 0, 0 ); +#endif + /* should move op to pending list */ } - pthread_attr_init( &attr ); - pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); - if ( pthread_create( &arg->co_op->o_tid, attr, - (void *) connection_operation, (void *) arg ) != 0 ) { - Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 ); - } else { - pthread_mutex_lock( &active_threads_mutex ); - active_threads++; - pthread_mutex_unlock( &active_threads_mutex ); + return status; +} + +int connection_write(ber_socket_t s) +{ + Connection *c; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + c = connection_get( s ); + + slapd_clr_write( s, 0); + + if( c == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "connection_write: sock %ld no connection!\n",(long)s)); +#else + Debug( LDAP_DEBUG_ANY, + "connection_write(%ld): no connection!\n", + (long) s, 0, 0 ); +#endif + slapd_remove(s, 0); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return -1; } - pthread_attr_destroy( &attr ); + + c->c_n_write++; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "connection_write conn %lu waking output.\n", + c->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, + "connection_write(%d): waking output for id=%lu\n", + s, c->c_connid, 0 ); +#endif + ldap_pvt_thread_cond_signal( &c->c_write_cv ); + + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) + slapd_set_read( s, 1 ); + if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) + slapd_set_write( s, 1 ); + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; } + diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 7c3bf61b6bdab7126c06800d4b3bb505e0849906..b475dd1af44ef3789ebc49bfebbf9bf95934b67d 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -46,6 +46,7 @@ typedef int (SLAP_CTRL_PARSE_FN) LDAP_P(( static SLAP_CTRL_PARSE_FN parseManageDSAit; static SLAP_CTRL_PARSE_FN parseSubentries; static SLAP_CTRL_PARSE_FN parseNoOp; +static SLAP_CTRL_PARSE_FN parsePagedResults; static struct slap_control { char *sc_oid; @@ -66,6 +67,11 @@ static struct slap_control { { LDAP_CONTROL_NOOP, SLAP_CTRL_UPDATE, NULL, parseNoOp }, +#endif +#ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST + { LDAP_CONTROL_PAGEDRESULTS_REQUEST, + SLAP_CTRL_SEARCH, NULL, + parsePagedResults }, #endif { NULL } }; @@ -93,7 +99,7 @@ int get_ctrls( Operation *op, int sendres ) { - int nctrls; + int nctrls = 0; ber_tag_t tag; ber_len_t len; char *opaque; @@ -121,7 +127,7 @@ int get_ctrls( #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, - "get_ctrls: conn %d\n", conn->c_connid )); + "get_ctrls: conn %lu\n", conn->c_connid )); #else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 ); #endif @@ -142,7 +148,7 @@ int get_ctrls( } #endif - op->o_ctrls[nctrls=0] = NULL; + op->o_ctrls[nctrls] = NULL; /* step through each element */ for( tag = ber_first_element( ber, &len, &opaque ); @@ -192,7 +198,7 @@ int get_ctrls( if( tag == LBER_ERROR ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_INFO, - "get_ctrls: conn %d get OID failed.\n", + "get_ctrls: conn %lu get OID failed.\n", conn->c_connid )); #else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n", @@ -214,7 +220,7 @@ int get_ctrls( if( tag == LBER_ERROR ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_INFO, - "get_ctrls: conn %d get crit failed.\n", + "get_ctrls: conn %lu get crit failed.\n", conn->c_connid )); #else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n", @@ -236,13 +242,13 @@ int get_ctrls( if( tag == LBER_ERROR ) { #ifdef NEW_LOGGING - LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "get_ctrls: conn %d: " + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "get_ctrls: conn %lu: " "%s (%scritical): get value failed.\n", conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)", c->ldctl_iscritical ? "" : "non" )); #else - Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %d: " + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: " "%s (%scritical): get value failed.\n", conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)", @@ -258,7 +264,7 @@ int get_ctrls( #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_INFO, - "get_ctrls: conn %d oid=\"%s\" (%scritical)\n", + "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n", conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)", c->ldctl_iscritical ? "" : "non" )); @@ -344,7 +350,7 @@ int get_ctrls( return_results: #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_RESULTS, - "get_ctrls: conn=%d n=%d rc=%d err=%s\n", + "get_ctrls: conn=%lu n=%d rc=%d err=%s\n", conn->c_connid, nctrls, rc, errmsg ? errmsg : "" )); #else Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: n=%d rc=%d err=%s\n", @@ -442,3 +448,82 @@ static int parseNoOp ( } #endif +#ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST +static int parsePagedResults ( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text ) +{ + ber_tag_t tag; + ber_int_t size; + BerElement *ber; + struct berval cookie = { 0, NULL }; + + if ( op->o_pagedresults != SLAP_NO_CONTROL ) { + *text = "paged results control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len == 0 ) { + *text = "paged results control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + + /* Parse the control value + * realSearchControlValue ::= SEQUENCE { + * size INTEGER (0..maxInt), + * -- requested page size from client + * -- result set size estimate from server + * cookie OCTET STRING + */ + ber = ber_init( &ctrl->ldctl_value ); + if( ber == NULL ) { + *text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_scanf( ber, "{im}", &size, &cookie ); + (void) ber_free( ber, 1 ); + + if( tag == LBER_ERROR ) { + *text = "paged results control could not be decoded"; + return LDAP_PROTOCOL_ERROR; + } + + if( size <= 0 ) { + *text = "paged results control size invalid"; + return LDAP_PROTOCOL_ERROR; + } + + if( cookie.bv_len ) { + PagedResultsCookie reqcookie; + if( cookie.bv_len != sizeof( reqcookie ) ) { + /* bad cookie */ + *text = "paged results cookie is invalid"; + return LDAP_PROTOCOL_ERROR; + } + + AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + + if( reqcookie > op->o_pagedresults_state.ps_cookie ) { + /* bad cookie */ + *text = "paged results cookie is invalid"; + return LDAP_PROTOCOL_ERROR; + + } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) { + *text = "paged results cookie is invalid or old"; + return LDAP_UNWILLING_TO_PERFORM; + } + } + + op->o_pagedresults_state.ps_cookie = op->o_opid; + op->o_pagedresults_size = size; + + op->o_pagedresults = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + return LDAP_SUCCESS; +} +#endif diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 161fb79cf0e2bf6ce67b05be0ff4d7efba0a67ab..2ab0fa769ff440d01a274ad3dab7c4eb701dc4e1 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -1,363 +1,1890 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <errno.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <signal.h> -#ifdef _AIX -#include <sys/select.h> -#endif + +#include <ac/ctype.h> +#include <ac/errno.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include "ldap_pvt.h" +#include "ldap_pvt_thread.h" +#include "lutil.h" #include "slap.h" -#include "portable.h" -#include "ldapconfig.h" -#ifdef NEED_FILIO -#include <sys/filio.h> -#else /* NEED_FILIO */ -#include <sys/ioctl.h> -#endif /* NEED_FILIO */ -#ifdef USE_SYSCONF -#include <unistd.h> -#endif /* USE_SYSCONF */ - -extern Operation *op_add(); - -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; -#endif -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; -extern int active_threads; -extern pthread_mutex_t active_threads_mutex; -extern pthread_mutex_t new_conn_mutex; -extern int slapd_shutdown; -extern pthread_t listener_tid; -extern int num_conns; -extern pthread_mutex_t ops_mutex; -extern int g_argc; -extern char **g_argv; - -int dtblsize; -Connection *c; - -static void set_shutdown(); -static void do_nothing(); - -void -daemon( - int port + +#ifdef HAVE_TCPD +#include <tcpd.h> + +int allow_severity = LOG_INFO; +int deny_severity = LOG_NOTICE; +#endif /* TCP Wrappers */ + +#ifdef LDAP_PF_LOCAL +#include <sys/stat.h> +/* this should go in <ldap.h> as soon as it is accepted */ +#define LDAPI_MOD_URLEXT "x-mod" +#endif /* LDAP_PF_LOCAL */ + +/* globals */ +time_t starttime; +ber_socket_t dtblsize; + +Listener **slap_listeners = NULL; + +#define SLAPD_LISTEN 10 + +static ber_socket_t wake_sds[2]; + +#ifdef NO_THREADS +static int waking; +#define WAKE_LISTENER(w) \ +((w && !waking) ? tcp_write( wake_sds[1], "0", 1 ), waking=1 : 0) +#else +#define WAKE_LISTENER(w) \ +do { if (w) tcp_write( wake_sds[1], "0", 1 ); } while(0) +#endif + +#ifndef HAVE_WINSOCK +static +#endif +volatile sig_atomic_t slapd_shutdown = 0; + +static struct slap_daemon { + ldap_pvt_thread_mutex_t sd_mutex; + + int sd_nactives; + +#ifndef HAVE_WINSOCK + /* In winsock, accept() returns values higher than dtblsize + so don't bother with this optimization */ + int sd_nfds; +#endif + + fd_set sd_actives; + fd_set sd_readers; + fd_set sd_writers; +} slap_daemon; + + + +#ifdef HAVE_SLP +/* + * SLP related functions + */ +#include <slp.h> + +#define LDAP_SRVTYPE_PREFIX "service:ldap://" +#define LDAPS_SRVTYPE_PREFIX "service:ldaps://" +static char** slapd_srvurls = NULL; +static SLPHandle slapd_hslp = 0; + +void slapd_slp_init( const char* urls ) { + int i; + + slapd_srvurls = str2charray( urls, " " ); + + if( slapd_srvurls == NULL ) return; + + /* find and expand INADDR_ANY URLs */ + for( i=0; slapd_srvurls[i] != NULL; i++ ) { + if( strcmp( slapd_srvurls[i], "ldap:///" ) == 0) { + char *host = ldap_pvt_get_fqdn( NULL ); + if ( host != NULL ) { + slapd_srvurls[i] = (char *) realloc( slapd_srvurls[i], + strlen( host ) + + sizeof( LDAP_SRVTYPE_PREFIX ) ); + strcpy( slap_strcopy(slapd_srvurls[i], + LDAP_SRVTYPE_PREFIX ), host ); + + ch_free( host ); + } + + } else if ( strcmp( slapd_srvurls[i], "ldaps:///" ) == 0) { + char *host = ldap_pvt_get_fqdn( NULL ); + if ( host != NULL ) { + slapd_srvurls[i] = (char *) realloc( slapd_srvurls[i], + strlen( host ) + + sizeof( LDAPS_SRVTYPE_PREFIX ) ); + strcpy( slap_strcopy(slapd_srvurls[i], + LDAPS_SRVTYPE_PREFIX ), host ); + + ch_free( host ); + } + } + } + + /* open the SLP handle */ + SLPOpen( "en", 0, &slapd_hslp ); +} + +void slapd_slp_deinit() { + if( slapd_srvurls == NULL ) return; + + charray_free( slapd_srvurls ); + slapd_srvurls = NULL; + + /* close the SLP handle */ + SLPClose( slapd_hslp ); +} + +void slapd_slp_regreport( + SLPHandle hslp, + SLPError errcode, + void* cookie ) +{ + /* empty report */ +} + +void slapd_slp_reg() { + int i; + + for( i=0; slapd_srvurls[i] != NULL; i++ ) { + if( strncmp( slapd_srvurls[i], LDAP_SRVTYPE_PREFIX, + sizeof( LDAP_SRVTYPE_PREFIX ) - 1 ) == 0 || + strncmp( slapd_srvurls[i], LDAPS_SRVTYPE_PREFIX, + sizeof( LDAPS_SRVTYPE_PREFIX ) - 1 ) == 0 ) + { + SLPReg( slapd_hslp, + slapd_srvurls[i], + SLP_LIFETIME_MAXIMUM, + "ldap", + "", + 1, + slapd_slp_regreport, + NULL ); + } + } +} + +void slapd_slp_dereg() { + int i; + + for( i=0; slapd_srvurls[i] != NULL; i++ ) { + SLPDereg( slapd_hslp, + slapd_srvurls[i], + slapd_slp_regreport, + NULL ); + } +} +#endif /* HAVE_SLP */ + +/* + * Add a descriptor to daemon control + */ +static void slapd_add(ber_socket_t s) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( !FD_ISSET( s, &slap_daemon.sd_actives )); + assert( !FD_ISSET( s, &slap_daemon.sd_readers )); + assert( !FD_ISSET( s, &slap_daemon.sd_writers )); + +#ifndef HAVE_WINSOCK + if (s >= slap_daemon.sd_nfds) { + slap_daemon.sd_nfds = s + 1; + } +#endif + + FD_SET( s, &slap_daemon.sd_actives ); + FD_SET( s, &slap_daemon.sd_readers ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slapd_add: added %ld%s%s\n", + (long)s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: added %ld%s%s\n", + (long) s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); +#endif + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + +/* + * Remove the descriptor from daemon control + */ +void slapd_remove(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slapd_remove: removing %ld%s%s\n", + (long) s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: removing %ld%s%s\n", + (long) s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); +#endif + FD_CLR( s, &slap_daemon.sd_actives ); + FD_CLR( s, &slap_daemon.sd_readers ); + FD_CLR( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); +} + +void slapd_clr_write(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_CLR( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); +} + +void slapd_set_write(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + if (!FD_ISSET(s, &slap_daemon.sd_writers)) + FD_SET( (unsigned) s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); +} + +void slapd_clr_read(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_CLR( s, &slap_daemon.sd_readers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); +} + +void slapd_set_read(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + if (!FD_ISSET(s, &slap_daemon.sd_readers)) + FD_SET( s, &slap_daemon.sd_readers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); +} + +static void slapd_close(ber_socket_t s) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slapd_close: closing %ld\n", (long)s )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n", + (long) s, 0, 0 ); +#endif + tcp_close(s); +} + +static void slap_free_listener_addresses(struct sockaddr **sal) +{ + struct sockaddr **sap; + + if (sal == NULL) { + return; + } + + for (sap = sal; *sap != NULL; sap++) { + ch_free(*sap); + } + + ch_free(sal); +} + +#ifdef LDAP_PF_LOCAL +static int get_url_perms( + char **exts, + mode_t *perms, + int *crit ) +{ + int i; + + assert( exts ); + assert( perms ); + assert( crit ); + + *crit = 0; + for ( i = 0; exts[ i ]; i++ ) { + char *type = exts[ i ]; + int c = 0; + + if ( type[ 0 ] == '!' ) { + c = 1; + type++; + } + + if ( strncasecmp( type, LDAPI_MOD_URLEXT "=", sizeof(LDAPI_MOD_URLEXT "=") - 1 ) == 0 ) { + char *value = type + sizeof(LDAPI_MOD_URLEXT "=") - 1; + mode_t p = 0; + int j; + + if ( strlen(value) != 3 ) { + return LDAP_OTHER; + } + + for ( j = 0; j < 3; j++ ) { + static mode_t m[ 3 ] + = { S_IRWXU, S_IRWXG, S_IRWXO }; + + switch ( value[ j ] ) { + case 'w': + p |= m[ j ]; + break; + case '-': + break; + default: + return LDAP_OTHER; + } + } + + *crit = c; + *perms = p; + + return LDAP_SUCCESS; + } + } + + return LDAP_OTHER; +} +#endif /* LDAP_PF_LOCAL */ + +/* port = 0 indicates AF_LOCAL */ +static int slap_get_listener_addresses( + const char *host, + unsigned short port, + struct sockaddr ***sal) +{ + struct sockaddr **sap; + +#ifdef LDAP_PF_LOCAL + if ( port == 0 ) { + *sal = ch_malloc(2 * sizeof(void *)); + if (*sal == NULL) { + return -1; + } + + sap = *sal; + *sap = ch_malloc(sizeof(struct sockaddr_un)); + if (*sap == NULL) + goto errexit; + sap[1] = NULL; + + if ( strlen(host) > + (sizeof(((struct sockaddr_un *)*sap)->sun_path) - 1) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_get_listener_addresses: domain socket path (%s) too long in URL\n", + host )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: domain socket path (%s) too long in URL", + host, 0, 0); +#endif + goto errexit; + } + + (void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_un) ); + (*sap)->sa_family = AF_LOCAL; + strcpy( ((struct sockaddr_un *)*sap)->sun_path, host ); + } else +#endif + { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res, *sai; + int n, err; + char serv[7]; + + memset( &hints, '\0', sizeof(hints) ); + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + snprintf(serv, sizeof serv, "%d", port); + + if ( (err = getaddrinfo(host, serv, &hints, &res)) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_get_listener_addresses: getaddrinfo failed: %s\n", + AC_GAI_STRERROR(err) )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: getaddrinfo failed: %s\n", + AC_GAI_STRERROR(err), 0, 0); +#endif + return -1; + } + + sai = res; + for (n=2; (sai = sai->ai_next) != NULL; n++) { + /* EMPTY */ ; + } + *sal = ch_calloc(n, sizeof(void *)); + if (*sal == NULL) { + return -1; + } + + sap = *sal; + *sap = NULL; + + for ( sai=res; sai; sai=sai->ai_next ) { + if( sai->ai_addr == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_get_listener_addresses: " + "getaddrinfo ai_addr is NULL?\n" )); +#else + Debug( LDAP_DEBUG_ANY, "slap_get_listener_addresses: " + "getaddrinfo ai_addr is NULL?\n", 0, 0, 0 ); +#endif + freeaddrinfo(res); + goto errexit; + } + + switch (sai->ai_family) { +# ifdef LDAP_PF_INET6 + case AF_INET6: + *sap = ch_malloc(sizeof(struct sockaddr_in6)); + if (*sap == NULL) { + freeaddrinfo(res); + goto errexit; + } + *(struct sockaddr_in6 *)*sap = + *((struct sockaddr_in6 *)sai->ai_addr); + break; +# endif + case AF_INET: + *sap = ch_malloc(sizeof(struct sockaddr_in)); + if (*sap == NULL) { + freeaddrinfo(res); + goto errexit; + } + *(struct sockaddr_in *)*sap = + *((struct sockaddr_in *)sai->ai_addr); + break; + default: + *sap = NULL; + break; + } + + if (*sap != NULL) { + (*sap)->sa_family = sai->ai_family; + sap++; + *sap = NULL; + } + } + + freeaddrinfo(res); +#else + struct in_addr in; + + if ( host == NULL ) { + in.s_addr = htonl(INADDR_ANY); + + } else if ( !inet_aton( host, &in ) ) { + struct hostent *he = gethostbyname( host ); + if( he == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_get_listener_addresses: invalid host %s\n", + host )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: invalid host %s", host, 0, 0); +#endif + return -1; + } + AC_MEMCPY( &in, he->h_addr, sizeof( in ) ); + } + + *sal = ch_malloc(2 * sizeof(void *)); + if (*sal == NULL) { + return -1; + } + + sap = *sal; + *sap = ch_malloc(sizeof(struct sockaddr_in)); + if (*sap == NULL) { + goto errexit; + } + sap[1] = NULL; + + (void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_in) ); + (*sap)->sa_family = AF_INET; + ((struct sockaddr_in *)*sap)->sin_port = htons(port); + ((struct sockaddr_in *)*sap)->sin_addr = in; +#endif + } + + return 0; + +errexit: + slap_free_listener_addresses(*sal); + return -1; +} + +static Listener * slap_open_listener( + const char* url ) +{ + int tmp, rc; + Listener l; + Listener *li; + LDAPURLDesc *lud; + unsigned short port; + int err, addrlen = 0; + struct sockaddr **sal, **psal; + int socktype = SOCK_STREAM; /* default to COTS */ +#ifdef LDAP_PF_LOCAL + mode_t perms = S_IRWXU; + int crit = 1; +#endif + + rc = ldap_url_parse( url, &lud ); + + if( rc != LDAP_URL_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slap_open_listener: listen URL \"%s\" parse error %d\n", + url, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: listen URL \"%s\" parse error=%d\n", + url, rc, 0 ); +#endif + return NULL; + } + +#ifndef HAVE_TLS + if( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: TLS is not supported (%s)\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: TLS not supported (%s)\n", + url, 0, 0 ); +#endif + ldap_free_urldesc( lud ); + return NULL; + } + + if(! lud->lud_port ) { + lud->lud_port = LDAP_PORT; + } + +#else + l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme ); + + if(! lud->lud_port ) { + lud->lud_port = l.sl_is_tls ? LDAPS_PORT : LDAP_PORT; + } +#endif + + port = (unsigned short) lud->lud_port; + + tmp = ldap_pvt_url_scheme2proto(lud->lud_scheme); + if ( tmp == LDAP_PROTO_IPC ) { +#ifdef LDAP_PF_LOCAL + if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) { + err = slap_get_listener_addresses(LDAPI_SOCK, 0, &sal); + } else { + err = slap_get_listener_addresses(lud->lud_host, 0, &sal); + } + + if ( lud->lud_exts ) { + err = get_url_perms( lud->lud_exts, &perms, &crit ); + } +#else + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: URL scheme is not supported: %s\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: URL scheme not supported: %s", + url, 0, 0); +#endif + ldap_free_urldesc( lud ); + return NULL; +#endif + } else { +#ifdef LDAP_CONNECTIONLESS + l.sl_is_udp = ( tmp == LDAP_PROTO_UDP ); +#endif + if( lud->lud_host == NULL || lud->lud_host[0] == '\0' + || strcmp(lud->lud_host, "*") == 0 ) + { + err = slap_get_listener_addresses(NULL, port, &sal); + } else { + err = slap_get_listener_addresses(lud->lud_host, port, &sal); + } + } + + ldap_free_urldesc( lud ); + if ( err ) { + return NULL; + } + + psal = sal; + while ( *sal != NULL ) { + switch( (*sal)->sa_family ) { + case AF_INET: +#ifdef LDAP_PF_INET6 + case AF_INET6: +#endif +#ifdef LDAP_PF_LOCAL + case AF_LOCAL: +#endif + break; + default: + sal++; + continue; + } +#ifdef LDAP_CONNECTIONLESS + if (l.sl_is_udp) + socktype = SOCK_DGRAM; +#endif + l.sl_sd = socket( (*sal)->sa_family, socktype, 0); + if ( l.sl_sd == AC_SOCKET_INVALID ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slap_open_listener: socket() failed errno=%d (%s)\n", + err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: socket() failed errno=%d (%s)\n", err, + sock_errstr(err), 0 ); +#endif + sal++; + continue; + } +#ifndef HAVE_WINSOCK + if ( l.sl_sd >= dtblsize ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slap_open_listener: listener descriptor %ld is too great %ld\n", + (long)l.sl_sd, (long)dtblsize )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: listener descriptor %ld is too great %ld\n", + (long) l.sl_sd, (long) dtblsize, 0 ); +#endif + tcp_close( l.sl_sd ); + sal++; + continue; + } +#endif +#ifdef LDAP_PF_LOCAL + if ( (*sal)->sa_family == AF_LOCAL ) { + unlink ( ((struct sockaddr_un *)*sal)->sun_path ); + } else +#endif + { +#ifdef SO_REUSEADDR + /* enable address reuse */ + tmp = 1; + rc = setsockopt( l.sl_sd, SOL_SOCKET, SO_REUSEADDR, + (char *) &tmp, sizeof(tmp) ); + if ( rc == AC_SOCKET_ERROR ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: setsockopt( %ld, SO_REUSEADDR ) failed errno %d (%s)\n", + (long)l.sl_sd, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "slapd(%ld): setsockopt(SO_REUSEADDR) failed errno=%d (%s)\n", + (long) l.sl_sd, err, sock_errstr(err) ); +#endif + } +#endif + } + + switch( (*sal)->sa_family ) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; +#ifdef LDAP_PF_INET6 + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; +#endif +#ifdef LDAP_PF_LOCAL + case AF_LOCAL: + addrlen = sizeof(struct sockaddr_un); + break; +#endif + } + + if (!bind(l.sl_sd, *sal, addrlen)) + break; + err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: bind(%ld) failed errno=%d (%s)\n", + (long)l.sl_sd, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n", + (long) l.sl_sd, err, sock_errstr(err) ); +#endif + tcp_close( l.sl_sd ); + sal++; + } /* while ( *sal != NULL ) */ + + if ( *sal == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: bind(%ld) failed.\n", (long)l.sl_sd )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed\n", + (long) l.sl_sd, 0, 0 ); +#endif + slap_free_listener_addresses(psal); + return NULL; + } + + switch ( (*sal)->sa_family ) { +#ifdef LDAP_PF_LOCAL + case AF_LOCAL: { + char *addr = ((struct sockaddr_un *)*sal)->sun_path; + if ( chmod( addr, perms ) < 0 && crit ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: fchmod(%ld) failed errno=%d (%s)\n", + (long)l.sl_sd, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: fchmod(%ld) failed errno=%d (%s)", + (long) l.sl_sd, err, sock_errstr(err) ); +#endif + tcp_close( l.sl_sd ); + slap_free_listener_addresses(psal); + return NULL; + } + l.sl_name = ch_malloc( strlen(addr) + sizeof("PATH=") ); + sprintf( l.sl_name, "PATH=%s", addr ); + } break; +#endif /* LDAP_PF_LOCAL */ + + case AF_INET: { + char *s; +#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) + char addr[INET_ADDRSTRLEN]; + inet_ntop( AF_INET, &((struct sockaddr_in *)*sal)->sin_addr, + addr, sizeof(addr) ); + s = addr; +#else + s = inet_ntoa( ((struct sockaddr_in *) *sal)->sin_addr ); +#endif + port = ntohs( ((struct sockaddr_in *)*sal) ->sin_port ); + l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65535") ); + sprintf( l.sl_name, "IP=%s:%d", + s != NULL ? s : "unknown" , port ); + } break; + +#ifdef LDAP_PF_INET6 + case AF_INET6: { + char addr[INET6_ADDRSTRLEN]; + inet_ntop( AF_INET6, &((struct sockaddr_in6 *)*sal)->sin6_addr, + addr, sizeof addr); + port = ntohs( ((struct sockaddr_in6 *)*sal)->sin6_port ); + l.sl_name = ch_malloc( strlen(addr) + sizeof("IP= 65535") ); + sprintf( l.sl_name, "IP=%s %d", addr, port ); + } break; +#endif /* LDAP_PF_INET6 */ + + default: +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_open_listener: unsupported address family (%d)\n", + (int)(*sal)->sa_family )); +#else + Debug( LDAP_DEBUG_ANY, "daemon: unsupported address family (%d)\n", + (int) (*sal)->sa_family, 0, 0 ); +#endif + break; + } + + slap_free_listener_addresses(psal); + + l.sl_url = ch_strdup( url ); + li = ch_malloc( sizeof( Listener ) ); + *li = l; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS, + "slap_open_listener: daemon initialzed %s\n", l.sl_url )); +#else + Debug( LDAP_DEBUG_TRACE, "daemon: initialized %s\n", + l.sl_url, 0, 0 ); +#endif + return li; +} + +static int sockinit(void); +static int sockdestroy(void); + +int slapd_daemon_init( const char *urls ) +{ + int i, rc; + char **u; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ARGS, + "slapd_daemon_init: %s\n", + urls ? urls : "<null>" )); +#else + Debug( LDAP_DEBUG_ARGS, "daemon_init: %s\n", + urls ? urls : "<null>", 0, 0 ); +#endif + if( (rc = sockinit()) != 0 ) { + return rc; + } + +#ifdef HAVE_SYSCONF + dtblsize = sysconf( _SC_OPEN_MAX ); +#elif HAVE_GETDTABLESIZE + dtblsize = getdtablesize(); +#else + dtblsize = FD_SETSIZE; +#endif + +#ifdef FD_SETSIZE + if(dtblsize > FD_SETSIZE) { + dtblsize = FD_SETSIZE; + } +#endif /* !FD_SETSIZE */ + + /* open a pipe (or something equivalent connected to itself). + * we write a byte on this fd whenever we catch a signal. The main + * loop will be select'ing on this socket, and will wake up when + * this byte arrives. + */ + if( (rc = lutil_pair( wake_sds )) < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slap_daemon_init: lutil_pair() failed rc=%d\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: lutil_pair() failed rc=%d\n", rc, 0, 0 ); +#endif + return rc; + } + + FD_ZERO( &slap_daemon.sd_readers ); + FD_ZERO( &slap_daemon.sd_writers ); + + if( urls == NULL ) { + urls = "ldap:///"; + } + + u = str2charray( urls, " " ); + + if( u == NULL || u[0] == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slap_daemon_init: no urls (%s) provided.\n", urls )); +#else + Debug( LDAP_DEBUG_ANY, "daemon_init: no urls (%s) provided.\n", + urls, 0, 0 ); +#endif + return -1; + } + + for( i=0; u[i] != NULL; i++ ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slap_daemon_init: listen on %s\n.", u[i] )); +#else + Debug( LDAP_DEBUG_TRACE, "daemon_init: listen on %s\n", + u[i], 0, 0 ); +#endif + } + + if( i == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_daemon_init: no listeners to open (%s)\n", urls )); +#else + Debug( LDAP_DEBUG_ANY, "daemon_init: no listeners to open (%s)\n", + urls, 0, 0 ); +#endif + charray_free( u ); + return -1; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slap_daemon_init: %d listeners to open...\n", i )); +#else + Debug( LDAP_DEBUG_TRACE, "daemon_init: %d listeners to open...\n", + i, 0, 0 ); +#endif + slap_listeners = ch_malloc( (i+1)*sizeof(Listener *) ); + + for(i = 0; u[i] != NULL; i++ ) { + slap_listeners[i] = slap_open_listener( u[i] ); + + if( slap_listeners[i] == NULL ) { + charray_free( u ); + return -1; + } + } + slap_listeners[i] = NULL; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slap_daemon_init: %d listeners opened\n", i )); +#else + Debug( LDAP_DEBUG_TRACE, "daemon_init: %d listeners opened\n", + i, 0, 0 ); +#endif + +#ifdef HAVE_SLP + slapd_slp_init( urls ); + slapd_slp_reg(); +#endif + + charray_free( u ); + ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex ); + return !i; +} + + +int +slapd_daemon_destroy(void) +{ + connections_destroy(); + tcp_close( wake_sds[1] ); + tcp_close( wake_sds[0] ); + sockdestroy(); + +#ifdef HAVE_SLP + slapd_slp_dereg(); + slapd_slp_deinit(); +#endif + + return 0; +} + + +static void * +slapd_daemon_task( + void *ptr ) { - Operation *o; - BerElement ber; - unsigned long len, tag, msgid; - int i; - int tcps, ns; - struct sockaddr_in addr; - fd_set readfds; - fd_set writefds; - FILE *fp; - int on = 1; - -#ifdef USE_SYSCONF - dtblsize = sysconf( _SC_OPEN_MAX ); -#else /* USE_SYSCONF */ - dtblsize = getdtablesize(); -#endif /* USE_SYSCONF */ - - c = (Connection *) ch_calloc( 1, dtblsize * sizeof(Connection) ); - - for ( i = 0; i < dtblsize; i++ ) { - c[i].c_dn = NULL; - c[i].c_addr = NULL; - c[i].c_domain = NULL; - c[i].c_ops = NULL; - c[i].c_sb.sb_sd = -1; - c[i].c_sb.sb_options = LBER_NO_READ_AHEAD; - c[i].c_sb.sb_naddr = 0; - c[i].c_sb.sb_ber.ber_buf = NULL; - c[i].c_sb.sb_ber.ber_ptr = NULL; - c[i].c_sb.sb_ber.ber_end = NULL; - c[i].c_writewaiter = 0; - c[i].c_connid = 0; - pthread_mutex_init( &c[i].c_dnmutex, - pthread_mutexattr_default ); - pthread_mutex_init( &c[i].c_opsmutex, - pthread_mutexattr_default ); - pthread_mutex_init( &c[i].c_pdumutex, - pthread_mutexattr_default ); - pthread_cond_init( &c[i].c_wcv, pthread_condattr_default ); - } - - if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) { - Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } - - i = 1; - if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i, - sizeof(i) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - } - - (void) memset( (void *) &addr, '\0', sizeof(addr) ); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons( port ); - if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } - - if ( listen( tcps, 5 ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } - - (void) SIGNAL( SIGPIPE, SIG_IGN ); - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); - (void) SIGNAL( SIGUSR2, (void *) set_shutdown ); - (void) SIGNAL( SIGTERM, (void *) set_shutdown ); - (void) SIGNAL( SIGHUP, (void *) set_shutdown ); - - Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 ); -#ifdef SLAPD_PIDFILE - if ( (fp = fopen( SLAPD_PIDFILE, "w" )) != NULL ) { - fprintf( fp, "%d\n", getpid() ); - fclose( fp ); - } -#endif -#ifdef SLAPD_ARGSFILE - if ( (fp = fopen( SLAPD_ARGSFILE, "w" )) != NULL ) { - for ( i = 0; i < g_argc; i++ ) { - fprintf( fp, "%s ", g_argv[i] ); - } - fprintf( fp, "\n" ); - fclose( fp ); + int l; + time_t last_idle_check = 0; + time( &starttime ); + + if ( global_idletimeout > 0 ) { + last_idle_check = slap_get_time(); + } + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ) + continue; +#ifdef LDAP_CONNECTIONLESS + /* Since this is connectionless, the data port is the + * listening port. The listen() and accept() calls + * are unnecessary. + */ + if ( slap_listeners[l]->sl_is_udp ) + { + slapd_add( slap_listeners[l]->sl_sd ); + continue; + } +#endif + + if ( listen( slap_listeners[l]->sl_sd, SLAPD_LISTEN ) == -1 ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon_task: listen( %s, 5 ) failed errno=%d (%s)\n", + slap_listeners[l]->sl_url, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: listen(%s, 5) failed errno=%d (%s)\n", + slap_listeners[l]->sl_url, err, + sock_errstr(err) ); +#endif + return( (void*)-1 ); + } + + slapd_add( slap_listeners[l]->sl_sd ); + } + +#ifdef HAVE_NT_SERVICE_MANAGER + if ( started_event != NULL ) { + ldap_pvt_thread_cond_signal( &started_event ); } #endif + /* initialization complete. Here comes the loop. */ while ( !slapd_shutdown ) { - struct sockaddr_in from; + ber_socket_t i; + int ns; + int at; + ber_socket_t nfds; +#define SLAPD_EBADF_LIMIT 16 + int ebadf = 0; + int emfile = 0; + +#define SLAPD_IDLE_CHECK_LIMIT 4 + time_t now; + + + fd_set readfds; + fd_set writefds; + Sockaddr from; + +#if defined(SLAPD_RLOOKUPS) struct hostent *hp; +#endif struct timeval zero; struct timeval *tvp; - int len, pid; - FD_ZERO( &writefds ); - FD_ZERO( &readfds ); - FD_SET( tcps, &readfds ); - - pthread_mutex_lock( &active_threads_mutex ); - Debug( LDAP_DEBUG_CONNS, - "listening for connections on %d, activity on:", - tcps, 0, 0 ); - for ( i = 0; i < dtblsize; i++ ) { - if ( c[i].c_sb.sb_sd != -1 ) { - FD_SET( c[i].c_sb.sb_sd, &readfds ); - - if ( c[i].c_writewaiter ) { - FD_SET( c[i].c_sb.sb_sd, &writefds ); - } - Debug( LDAP_DEBUG_CONNS, " %dr%s", i, - c[i].c_writewaiter ? "w" : "", 0 ); + if( emfile ) { + now = slap_get_time(); + connections_timeout_idle( now ); + } + else if ( global_idletimeout > 0 ) { + now = slap_get_time(); + if ( difftime( last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) { + connections_timeout_idle( now ); } } - Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); + + FD_ZERO( &writefds ); + FD_ZERO( &readfds ); zero.tv_sec = 0; zero.tv_usec = 0; - Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n", - active_threads, 0, 0 ); -#ifdef PTHREAD_PREEMPTIVE + + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + +#ifdef FD_SET_MANUAL_COPY + for( s = 0; s < nfds; s++ ) { + if(FD_ISSET( &slap_sd_readers, s )) { + FD_SET( s, &readfds ); + } + if(FD_ISSET( &slap_sd_writers, s )) { + FD_SET( s, &writefds ); + } + } +#else + AC_MEMCPY( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) ); + AC_MEMCPY( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) ); +#endif + assert(!FD_ISSET(wake_sds[0], &readfds)); + FD_SET( wake_sds[0], &readfds ); + + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ) + continue; + if (!FD_ISSET(slap_listeners[l]->sl_sd, &readfds)) + FD_SET( slap_listeners[l]->sl_sd, &readfds ); + } + +#ifndef HAVE_WINSOCK + nfds = slap_daemon.sd_nfds; +#else + nfds = dtblsize; +#endif + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + at = ldap_pvt_thread_pool_backload(&connection_pool); + +#if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS ) tvp = NULL; #else - tvp = active_threads ? &zero : NULL; + tvp = at ? &zero : NULL; #endif - pthread_mutex_unlock( &active_threads_mutex ); - switch ( select( dtblsize, &readfds, &writefds, 0, tvp ) ) { - case -1: /* failure - try again */ + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ) + continue; + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slapd_daemon_task: select: listen=%d active_threads=%d tvp=%s\n", + slap_listeners[l]->sl_sd, at, tvp == NULL ? "NULL" : "zero" )); +#else Debug( LDAP_DEBUG_CONNS, - "select failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); + "daemon: select: listen=%d active_threads=%d tvp=%s\n", + slap_listeners[l]->sl_sd, at, + tvp == NULL ? "NULL" : "zero" ); +#endif + } + + switch(ns = select( nfds, &readfds, +#ifdef HAVE_WINSOCK + /* don't pass empty fd_set */ + ( writefds.fd_count > 0 ? &writefds : NULL ), +#else + &writefds, +#endif + NULL, tvp )) + { + case -1: { /* failure - try again */ + int err = sock_errno(); + + if( err == EBADF +#ifdef WSAENOTSOCK + /* you'd think this would be EBADF */ + || err == WSAENOTSOCK +#endif + ) { + if (++ebadf < SLAPD_EBADF_LIMIT) + continue; + } + + if( err != EINTR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slapd_daemon_task: select failed (%d): %s\n", + err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_CONNS, + "daemon: select failed (%d): %s\n", + err, sock_errstr(err), 0 ); +#endif + slapd_shutdown = 2; + } + } continue; case 0: /* timeout - let threads run */ - Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n", + ebadf = 0; +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + "slapd_daemon_task: select timeout - yielding\n" )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n", 0, 0, 0 ); - pthread_yield(); +#endif + ldap_pvt_thread_yield(); continue; default: /* something happened - deal with it */ - Debug( LDAP_DEBUG_CONNS, "select activity\n", 0, 0, 0 ); - ; /* FALL */ - } - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - pthread_mutex_unlock( ¤ttime_mutex ); - - /* new connection */ - pthread_mutex_lock( &new_conn_mutex ); - if ( FD_ISSET( tcps, &readfds ) ) { - len = sizeof(from); - if ( (ns = accept( tcps, (struct sockaddr *) &from, - &len )) == -1 ) { - Debug( LDAP_DEBUG_ANY, - "accept() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); - pthread_mutex_unlock( &new_conn_mutex ); + if( slapd_shutdown ) continue; + + ebadf = 0; +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + "slapd_daemon_task: activity on %d descriptors\n", ns )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n", + ns, 0, 0 ); +#endif + /* FALL THRU */ + } + + if( FD_ISSET( wake_sds[0], &readfds ) ) { + char c[BUFSIZ]; + tcp_read( wake_sds[0], c, sizeof(c) ); +#ifdef NO_THREADS + waking = 0; +#endif + continue; + } + + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + ber_socket_t s; + socklen_t len = sizeof(from); + long id; + slap_ssf_t ssf = 0; + char *authid = NULL; + + char *dnsname = NULL; + char *peeraddr; +#ifdef LDAP_PF_LOCAL + char peername[MAXPATHLEN + sizeof("PATH=")]; +#elif defined(LDAP_PF_INET6) + char peername[sizeof("IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535")]; +#else + char peername[sizeof("IP=255.255.255.255:65336")]; +#endif /* LDAP_PF_LOCAL */ + + peername[0] = '\0'; + + if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ) + continue; + + if ( !FD_ISSET( slap_listeners[l]->sl_sd, &readfds ) ) + continue; + +#ifdef LDAP_CONNECTIONLESS + if ( slap_listeners[l]->sl_is_udp ) + { + /* The first time we receive a query, we set this + * up as a "connection". It remains open for the life + * of the slapd. + */ + if ( slap_listeners[l]->sl_is_udp < 2 ) + { + id = connection_init( + slap_listeners[l]->sl_sd, + slap_listeners[l]->sl_url, "", "", + slap_listeners[l]->sl_name, + 2, ssf, authid ); + slap_listeners[l]->sl_is_udp++; + } + continue; + } +#endif + + s = accept( slap_listeners[l]->sl_sd, + (struct sockaddr *) &from, &len ); + if ( s == AC_SOCKET_INVALID ) { + int err = sock_errno(); + +#ifdef EMFILE + if( err == EMFILE ) { + emfile++; + } else +#endif +#ifdef ENFILE + if( err == ENFILE ) { + emfile++; + } else +#endif + { + emfile=0; + } + + if( emfile < 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon_task: accept(%ld) failed errno=%d (%s)\n", + (long)slap_listeners[l]->sl_sd, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: accept(%ld) failed errno=%d (%s)\n", + (long) slap_listeners[l]->sl_sd, err, + sock_errstr(err) ); +#endif + } else { + /* prevent busy loop */ +# ifdef HAVE_USLEEP + if( emfile % 4 == 3 ) usleep( 250 ); +# else + if( emfile % 8 == 7 ) sleep( 1 ); +# endif + } + + ldap_pvt_thread_yield(); continue; } - if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) { + emfile = 0; + +#ifndef HAVE_WINSOCK + /* make sure descriptor number isn't too great */ + if ( s >= dtblsize ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon_task: %ld beyond descriptor table size %ld\n", + (long)s, (long)dtblsize )); +#else Debug( LDAP_DEBUG_ANY, - "FIONBIO ioctl on %d faled\n", ns, 0, 0 ); + "daemon: %ld beyond descriptor table size %ld\n", + (long) s, (long) dtblsize, 0 ); +#endif + + slapd_close(s); + ldap_pvt_thread_yield(); + continue; } - c[ns].c_sb.sb_sd = ns; - Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns, - 0, 0 ); - - pthread_mutex_lock( &ops_mutex ); - c[ns].c_connid = num_conns++; - pthread_mutex_unlock( &ops_mutex ); - len = sizeof(from); - if ( getpeername( ns, (struct sockaddr *) &from, &len ) - == 0 ) { - char *s; -#ifdef REVERSE_LOOKUP - hp = gethostbyaddr( (char *) - &(from.sin_addr.s_addr), - sizeof(from.sin_addr.s_addr), AF_INET ); -#else - hp = NULL; -#endif - - Statslog( LDAP_DEBUG_STATS, - "conn=%d fd=%d connection from %s (%s)\n", - c[ns].c_connid, ns, hp == NULL ? "unknown" - : hp->h_name, inet_ntoa( from.sin_addr ), - 0 ); - - if ( c[ns].c_addr != NULL ) { - free( c[ns].c_addr ); - } - c[ns].c_addr = strdup( inet_ntoa( - from.sin_addr ) ); - if ( c[ns].c_domain != NULL ) { - free( c[ns].c_domain ); +#endif + +#ifdef LDAP_DEBUG + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + /* newly accepted stream should not be in any of the FD SETS */ + assert( !FD_ISSET( s, &slap_daemon.sd_actives) ); + assert( !FD_ISSET( s, &slap_daemon.sd_readers) ); + assert( !FD_ISSET( s, &slap_daemon.sd_writers) ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +#endif + +#if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY ) +#ifdef LDAP_PF_LOCAL + /* for IPv4 and IPv6 sockets only */ + if ( from.sa_addr.sa_family != AF_LOCAL ) +#endif /* LDAP_PF_LOCAL */ + { + int rc; + int tmp; +#ifdef SO_KEEPALIVE + /* enable keep alives */ + tmp = 1; + rc = setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, + (char *) &tmp, sizeof(tmp) ); + if ( rc == AC_SOCKET_ERROR ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon_task: setsockopt( %ld, SO_KEEPALIVE) failed errno=%d (%s)\n", + (long)s, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "slapd(%ld): setsockopt(SO_KEEPALIVE) failed " + "errno=%d (%s)\n", (long) s, err, sock_errstr(err) ); +#endif } - c[ns].c_domain = strdup( hp == NULL ? "" : - hp->h_name ); - /* normalize the domain */ - for ( s = c[ns].c_domain; *s; s++ ) { - *s = TOLOWER( *s ); +#endif +#ifdef TCP_NODELAY + /* enable no delay */ + tmp = 1; + rc = setsockopt( s, IPPROTO_TCP, TCP_NODELAY, + (char *)&tmp, sizeof(tmp) ); + if ( rc == AC_SOCKET_ERROR ) { + int err = sock_errno(); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon_task: setsockopt( %ld, TCP_NODELAY) failed errno=%d (%s)\n", + (long)s, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_ANY, + "slapd(%ld): setsockopt(TCP_NODELAY) failed " + "errno=%d (%s)\n", (long) s, err, sock_errstr(err) ); +#endif } +#endif + } +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, + "slapd_daemon_task: new connection on %ld\n", (long)s )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n", + (long) s, 0, 0 ); +#endif + switch ( from.sa_addr.sa_family ) { +# ifdef LDAP_PF_LOCAL + case AF_LOCAL: + sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path ); + ssf = LDAP_PVT_SASL_LOCAL_SSF; + dnsname = "local"; + break; +#endif /* LDAP_PF_LOCAL */ + +# ifdef LDAP_PF_INET6 + case AF_INET6: + if ( IN6_IS_ADDR_V4MAPPED(&from.sa_in6_addr.sin6_addr) ) { + peeraddr = inet_ntoa( *((struct in_addr *) + &from.sa_in6_addr.sin6_addr.s6_addr[12]) ); + sprintf( peername, "IP=%s:%d", + peeraddr != NULL ? peeraddr : "unknown", + (unsigned) ntohs( from.sa_in6_addr.sin6_port ) ); } else { - Statslog( LDAP_DEBUG_STATS, - "conn=%d fd=%d connection from unknown\n", - c[ns].c_connid, ns, 0, 0, 0 ); + char addr[INET6_ADDRSTRLEN]; + sprintf( peername, "IP=%s %d", + inet_ntop( AF_INET6, + &from.sa_in6_addr.sin6_addr, + addr, sizeof addr) ? addr : "unknown", + (unsigned) ntohs( from.sa_in6_addr.sin6_port ) ); + } + break; +# endif /* LDAP_PF_INET6 */ + + case AF_INET: + peeraddr = inet_ntoa( from.sa_in_addr.sin_addr ); + sprintf( peername, "IP=%s:%d", + peeraddr != NULL ? peeraddr : "unknown", + (unsigned) ntohs( from.sa_in_addr.sin_port ) ); + break; + + default: + slapd_close(s); + continue; + } + + if ( ( from.sa_addr.sa_family == AF_INET ) +#ifdef LDAP_PF_INET6 + || ( from.sa_addr.sa_family == AF_INET6 ) +#endif + ) { +#ifdef SLAPD_RLOOKUPS + if ( use_reverse_lookup ) { +# ifdef LDAP_PF_INET6 + if ( from.sa_addr.sa_family == AF_INET6 ) + hp = gethostbyaddr( + (char *)&(from.sa_in6_addr.sin6_addr), + sizeof(from.sa_in6_addr.sin6_addr), + AF_INET6 ); + else +# endif /* LDAP_PF_INET6 */ + hp = gethostbyaddr( + (char *) &(from.sa_in_addr.sin_addr), + sizeof(from.sa_in_addr.sin_addr), + AF_INET ); + dnsname = hp ? ldap_pvt_str2lower( hp->h_name ) : NULL; + } +#else + dnsname = NULL; +#endif /* SLAPD_RLOOKUPS */ + +#ifdef HAVE_TCPD + if ( !hosts_ctl("slapd", + dnsname != NULL ? dnsname : STRING_UNKNOWN, + peeraddr != NULL ? peeraddr : STRING_UNKNOWN, + STRING_UNKNOWN )) + { + /* DENY ACCESS */ + Statslog( LDAP_DEBUG_ANY, + "fd=%ld host access from %s (%s) denied.\n", + (long) s, + dnsname != NULL ? dnsname : "unknown", + peeraddr != NULL ? peeraddr : "unknown", + 0, 0 ); + slapd_close(s); + continue; + } +#endif /* HAVE_TCPD */ } - pthread_mutex_lock( &c[ns].c_dnmutex ); - if ( c[ns].c_dn != NULL ) { - free( c[ns].c_dn ); - c[ns].c_dn = NULL; + + id = connection_init(s, + slap_listeners[l]->sl_url, + dnsname != NULL ? dnsname : "unknown", + peername, + slap_listeners[l]->sl_name, +#ifdef HAVE_TLS + slap_listeners[l]->sl_is_tls, +#else + 0, +#endif + ssf, + authid ); + + if( authid ) ch_free(authid); + + if( id < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_INFO, + "slapd_daemon_task: connection_init(%ld, %s, %s) failed.\n", + (long)s, peername, slap_listeners[l]->sl_name )); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: connection_init(%ld, %s, %s) failed.\n", + (long) s, + peername, + slap_listeners[l]->sl_name ); +#endif + slapd_close(s); + continue; } - pthread_mutex_unlock( &c[ns].c_dnmutex ); - c[ns].c_starttime = currenttime; - c[ns].c_opsinitiated = 0; - c[ns].c_opscompleted = 0; + + Statslog( LDAP_DEBUG_STATS, + "daemon: conn=%ld fd=%ld connection from %s (%s) accepted.\n", + id, (long) s, + peername, + slap_listeners[l]->sl_name, + 0 ); + + slapd_add( s ); + continue; + } + +#ifdef LDAP_DEBUG +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + "slapd_daemon_task: activity on " )); +#else + Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 ); +#endif +#ifdef HAVE_WINSOCK + for ( i = 0; i < readfds.fd_count; i++ ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + " %d%s", readfds.fd_array[i], "r", 0 )); +#else + Debug( LDAP_DEBUG_CONNS, " %d%s", + readfds.fd_array[i], "r", 0 ); +#endif + } + for ( i = 0; i < writefds.fd_count; i++ ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + " %d%s", writefds.fd_array[i], "w" )); +#else + Debug( LDAP_DEBUG_CONNS, " %d%s", + writefds.fd_array[i], "w", 0 ); +#endif } - pthread_mutex_unlock( &new_conn_mutex ); - Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 ); - for ( i = 0; i < dtblsize; i++ ) { +#else + for ( i = 0; i < nfds; i++ ) { int r, w; + int is_listener = 0; + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( i == slap_listeners[l]->sl_sd ) { +#ifdef LDAP_CONNECTIONLESS + /* The listener is the data port. Don't + * skip it. + */ + if (slap_listeners[l]->sl_is_udp) + continue; +#endif + is_listener = 1; + break; + } + } + if ( is_listener ) { + continue; + } r = FD_ISSET( i, &readfds ); w = FD_ISSET( i, &writefds ); - if ( i != tcps && (r || w) ) { + if ( r || w ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + " %d%s%s", i, + r ? "r" : "", w ? "w" : "" )); +#else Debug( LDAP_DEBUG_CONNS, " %d%s%s", i, r ? "r" : "", w ? "w" : "" ); +#endif } } +#endif +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, "\n" )); +#else Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); +#endif + +#endif + + /* loop through the writers */ +#ifdef HAVE_WINSOCK + for ( i = 0; i < writefds.fd_count; i++ ) +#else + for ( i = 0; i < nfds; i++ ) +#endif + { + ber_socket_t wd; + int is_listener = 0; +#ifdef HAVE_WINSOCK + wd = writefds.fd_array[i]; +#else + if( ! FD_ISSET( i, &writefds ) ) { + continue; + } + wd = i; +#endif - for ( i = 0; i < dtblsize; i++ ) { - if ( i == tcps || (! FD_ISSET( i, &readfds ) && - ! FD_ISSET( i, &writefds )) ) { + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( i == slap_listeners[l]->sl_sd ) { +#ifdef LDAP_CONNECTIONLESS + if (slap_listeners[l]->sl_is_udp) + continue; +#endif + is_listener = 1; + break; + } + } + if ( is_listener ) { continue; } +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + "slapd_daemon_task: write active on %d\n", wd )); +#else + Debug( LDAP_DEBUG_CONNS, + "daemon: write active on %d\n", + wd, 0, 0 ); +#endif + /* + * NOTE: it is possible that the connection was closed + * and that the stream is now inactive. + * connection_write() must valid the stream is still + * active. + */ + + if ( connection_write( wd ) < 0 ) { + FD_CLR( (unsigned) wd, &readfds ); + slapd_close( wd ); + } + } + +#ifdef HAVE_WINSOCK + for ( i = 0; i < readfds.fd_count; i++ ) +#else + for ( i = 0; i < nfds; i++ ) +#endif + { + ber_socket_t rd; + int is_listener = 0; - if ( FD_ISSET( i, &writefds ) ) { - Debug( LDAP_DEBUG_CONNS, - "signaling write waiter on %d\n", i, 0, 0 ); +#ifdef HAVE_WINSOCK + rd = readfds.fd_array[i]; +#else + if( ! FD_ISSET( i, &readfds ) ) { + continue; + } + rd = i; +#endif - pthread_mutex_lock( &active_threads_mutex ); - pthread_cond_signal( &c[i].c_wcv ); - c[i].c_writewaiter = 0; - active_threads++; - pthread_mutex_unlock( &active_threads_mutex ); + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( rd == slap_listeners[l]->sl_sd ) { +#ifdef LDAP_CONNECTIONLESS + if (slap_listeners[l]->sl_is_udp) + continue; +#endif + is_listener = 1; + break; + } + } + if ( is_listener ) { + continue; } - if ( FD_ISSET( i, &readfds ) ) { - Debug( LDAP_DEBUG_CONNS, - "read activity on %d\n", i, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL2, + "slapd_daemon_task: read activity on %d\n", rd )); +#else + Debug ( LDAP_DEBUG_CONNS, + "daemon: read activity on %d\n", rd, 0, 0 ); +#endif + /* + * NOTE: it is possible that the connection was closed + * and that the stream is now inactive. + * connection_read() must valid the stream is still + * active. + */ - connection_activity( &c[i] ); + if ( connection_read( rd ) < 0 ) { + slapd_close( rd ); } } + ldap_pvt_thread_yield(); + } + + if( slapd_shutdown == 1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slapd_daemon_task: shutdown requested and initiated.\n")); +#else + Debug( LDAP_DEBUG_TRACE, + "daemon: shutdown requested and initiated.\n", + 0, 0, 0 ); +#endif + + } else if ( slapd_shutdown == 2 ) { +#ifdef HAVE_NT_SERVICE_MANAGER +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slapd_daemon_task: shutdown initiated by Service Manager.\n")); +#else + Debug( LDAP_DEBUG_TRACE, + "daemon: shutdown initiated by Service Manager.\n", + 0, 0, 0); +#endif +#else /* !HAVE_NT_SERVICE_MANAGER */ +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slapd_daemon_task: abnormal condition, shutdown initiated.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "daemon: abnormal condition, shutdown initiated.\n", + 0, 0, 0 ); +#endif +#endif /* !HAVE_NT_SERVICE_MANAGER */ + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slapd_daemon_task: no active streams, shutdown initiated.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "daemon: no active streams, shutdown initiated.\n", + 0, 0, 0 ); +#endif + } - pthread_yield(); + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) { +#ifdef LDAP_PF_LOCAL + if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_LOCAL ) { + unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path ); + } +#endif /* LDAP_PF_LOCAL */ + slapd_close( slap_listeners[l]->sl_sd ); + } + if ( slap_listeners[l]->sl_url ) + free ( slap_listeners[l]->sl_url ); + if ( slap_listeners[l]->sl_name ) + free ( slap_listeners[l]->sl_name ); + free ( slap_listeners[l] ); } + free ( slap_listeners ); + slap_listeners = NULL; - close( tcps ); - pthread_mutex_lock( &active_threads_mutex ); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slapd_daemon_task: shutdown waiting for %d threads to terminate.\n", + ldap_pvt_thread_pool_backload(&connection_pool) )); +#else Debug( LDAP_DEBUG_ANY, - "slapd shutting down - waiting for %d threads to terminate\n", - active_threads, 0, 0 ); - while ( active_threads > 0 ) { - pthread_mutex_unlock( &active_threads_mutex ); - pthread_yield(); - pthread_mutex_lock( &active_threads_mutex ); - } - pthread_mutex_unlock( &active_threads_mutex ); - - /* let backends do whatever cleanup they need to do */ - Debug( LDAP_DEBUG_TRACE, - "slapd shutting down - waiting for backends to close down\n", 0, 0, - 0 ); - be_close(); - Debug( LDAP_DEBUG_ANY, "slapd stopping\n", 0, 0, 0 ); + "slapd shutdown: waiting for %d threads to terminate\n", + ldap_pvt_thread_pool_backload(&connection_pool), 0, 0 ); +#endif + ldap_pvt_thread_pool_destroy(&connection_pool, 1); + + return NULL; +} + + +int slapd_daemon( void ) +{ + int rc; + + connections_init(); + +#define SLAPD_LISTENER_THREAD 1 +#if defined( SLAPD_LISTENER_THREAD ) + { + ldap_pvt_thread_t listener_tid; + + /* listener as a separate THREAD */ + rc = ldap_pvt_thread_create( &listener_tid, + 0, slapd_daemon_task, NULL ); + + if ( rc != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_ERR, + "slapd_daemon: listener ldap_pvt_thread_create failed (%d).\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 ); +#endif + return rc; + } + + /* wait for the listener thread to complete */ + ldap_pvt_thread_join( listener_tid, (void *) NULL ); + } +#else + /* experimental code */ + slapd_daemon_task( NULL ); +#endif + + return 0; + +} + +int sockinit(void) +{ +#if defined( HAVE_WINSOCK2 ) + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + return -1; + } + + /* Confirm that the WinSock DLL supports 2.0.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.0 in addition to 2.0, it will still return */ + /* 2.0 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 0 ) + { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + WSACleanup(); + return -1; + } + + /* The WinSock DLL is acceptable. Proceed. */ +#elif defined( HAVE_WINSOCK ) + WSADATA wsaData; + if ( WSAStartup( 0x0101, &wsaData ) != 0 ) { + return -1; + } +#endif + return 0; +} + +int sockdestroy(void) +{ +#if defined( HAVE_WINSOCK2 ) || defined( HAVE_WINSOCK ) + WSACleanup(); +#endif + return 0; } -static void -set_shutdown() +RETSIGTYPE +slap_sig_shutdown( int sig ) { - Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slap_sig_shutdown: signal %d\n", sig )); +#else + Debug(LDAP_DEBUG_TRACE, "slap_sig_shutdown: signal %d\n", sig, 0, 0); +#endif + + /* + * If the NT Service Manager is controlling the server, we don't + * want SIGBREAK to kill the server. For some strange reason, + * SIGBREAK is generated when a user logs out. + */ + +#if HAVE_NT_SERVICE_MANAGER && SIGBREAK + if (is_NT_Service && sig == SIGBREAK) +#ifdef NEW_LOGGING + LDAP_LOG(( "connection", LDAP_LEVEL_CRIT, + "slap_sig_shutdown: SIGBREAK ignored.\n" )); +#else + Debug(LDAP_DEBUG_TRACE, "slap_sig_shutdown: SIGBREAK ignored.\n", + 0, 0, 0); +#endif + else +#endif slapd_shutdown = 1; - pthread_kill( listener_tid, SIGUSR1 ); - (void) SIGNAL( SIGUSR2, (void *) set_shutdown ); - (void) SIGNAL( SIGTERM, (void *) set_shutdown ); - (void) SIGNAL( SIGHUP, (void *) set_shutdown ); + + WAKE_LISTENER(1); + + /* reinstall self */ + (void) SIGNAL_REINSTALL( sig, slap_sig_shutdown ); } -static void -do_nothing() +RETSIGTYPE +slap_sig_wake( int sig ) { - Debug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 ); - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); + WAKE_LISTENER(1); + + /* reinstall self */ + (void) SIGNAL_REINSTALL( sig, slap_sig_wake ); +} + + +void slapd_add_internal(ber_socket_t s) { + slapd_add(s); +} + +Listener ** slapd_get_listeners(void) { + return slap_listeners; } diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index bbab47806c0d7d24d7181125d39cfc485bdc898f..38324be6eafd713367f1ce0d479e4c0d06bf770b 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -1,3 +1,8 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. @@ -10,26 +15,36 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -extern Backend *select_backend(); +#include <ac/string.h> +#include <ac/socket.h> -extern char *default_referral; +#include "ldap_pvt.h" +#include "slap.h" -void +int do_delete( Connection *conn, Operation *op ) { - char *dn, *odn; + struct berval dn = { 0, NULL }; + struct berval pdn = { 0, NULL }; + struct berval ndn = { 0, NULL }; + const char *text; Backend *be; + int rc; + int manageDSAit; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_delete: conn %d\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 ); +#endif /* * Parse the delete request. It looks like this: @@ -37,53 +52,152 @@ do_delete( * DelRequest := DistinguishedName */ - if ( ber_scanf( op->o_ber, "a", &dn ) == LBER_ERROR ) { + if ( ber_scanf( op->o_ber, "m", &dn ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_delete: conn: %d ber_scanf failed\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" ); - return; +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + return SLAPD_DISCONNECT; + } + + if( ( rc = get_ctrls( conn, op, 1 ) ) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "oepration", LDAP_LEVEL_ERR, + "do_delete: conn %d get_ctrls failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_delete: get_ctrls failed\n", 0, 0, 0 ); +#endif + goto cleanup; + } + + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_delete: conn %d invalid dn (%s)\n", + conn->c_connid, dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_delete: invalid dn (%s)\n", dn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto cleanup; } - odn = strdup( dn ); - dn_normalize( dn ); - Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 ); + if( ndn.bv_len == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "do_delete: conn %d: " + "Attempt to delete root DSE.\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_delete: root dse!\n", 0, 0, 0 ); +#endif + /* protocolError would likely be a more appropriate error */ + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "cannot delete the root DSE", NULL, NULL ); + goto cleanup; + +#ifdef SLAPD_SCHEMA_DN + + } else if ( strcasecmp( ndn.bv_val, SLAPD_SCHEMA_DN ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "do_delete: conn %d: " + "Attempt to delete subschema subentry.\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_delete: subschema subentry!\n", 0, 0, 0 ); +#endif + /* protocolError would likely be a more appropriate error */ + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "cannot delete the root DSE", NULL, NULL ); + goto cleanup; + +#endif + } - Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", dn, 0, 0 ); + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu DEL dn=\"%s\"\n", + op->o_connid, op->o_opid, pdn.bv_val, 0, 0 ); + + manageDSAit = get_manageDSAit( op ); /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - if ( (be = select_backend( dn )) == NULL ) { - free( dn ); - free( odn ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); - return; + if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvarray_free( ref ); + goto cleanup; } + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto cleanup; + } + + /* check for referrals */ + rc = backend_check_referrals( be, conn, op, &pdn, &ndn ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + + /* deref suffix alias if appropriate */ + suffix_alias( be, &ndn ); + /* * do the delete if 1 && (2 || 3) * 1) there is a delete function implemented in this backend; * 2) this backend is master for what it holds; - * 3) it's a replica and the dn supplied is the updatedn. + * 3) it's a replica and the dn supplied is the update_ndn. */ - if ( be->be_delete != NULL ) { + if ( be->be_delete ) { /* do the update here */ - if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn, - op->o_dn ) == 0 ) { - if ( (*be->be_delete)( be, conn, op, dn ) == 0 ) { - replog( be, LDAP_REQ_DELETE, odn, NULL, 0 ); + int repl_user = be_isupdate( be, &op->o_ndn ); +#ifndef SLAPD_MULTIMASTER + if ( !be->be_update_ndn.bv_len || repl_user ) +#endif + { + if ( (*be->be_delete)( be, conn, op, &pdn, &ndn ) == 0 ) { +#ifdef SLAPD_MULTIMASTER + if ( !be->be_update_ndn.bv_len || !repl_user ) +#endif + { + replog( be, op, &pdn, &ndn, NULL ); + } } +#ifndef SLAPD_MULTIMASTER } else { - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + BerVarray defref = be->be_update_refs + ? be->be_update_refs : default_referral; + BerVarray ref = referral_rewrite( default_referral, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + ref ? ref : defref, NULL ); + + ber_bvarray_free( ref ); +#endif } + } else { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", NULL, NULL ); } - free( dn ); - free( odn ); +cleanup: + free( pdn.bv_val ); + free( ndn.bv_val ); + return rc; } diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 226937efa99f521a9c0cf0d6ef98deeb631f7fe7..450691d326a5c076b48dfc116a07b0e8f5f409b5 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -1,262 +1,831 @@ /* dn.c - routines for dealing with distinguished names */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> #include "portable.h" + +#include <stdio.h> + +#include <ac/ctype.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap_pvt.h" + #include "slap.h" -static char **dn_explode(); +const struct berval slap_empty_bv = { 0, "" }; -#define DNSEPARATOR(c) (c == ',' || c == ';') -#define SEPARATOR(c) (c == ',' || c == ';' || c == '+') -#define SPACE(c) (c == ' ' || c == '\n') -#define NEEDSESCAPE(c) (c == '\\' || c == '"') -#define B4TYPE 0 -#define INTYPE 1 -#define B4EQUAL 2 -#define B4VALUE 3 -#define INVALUE 4 -#define INQUOTEDVALUE 5 -#define B4SEPARATOR 6 +#define SLAP_LDAPDN_PRETTY 0x1 + +#define SLAP_LDAPDN_MAXLEN 8192 /* - * dn_normalize - put dn into a canonical format. the dn is - * normalized in place, as well as returned. + * The DN syntax-related functions take advantage of the dn representation + * handling functions ldap_str2dn/ldap_dn2str. The latter are not schema- + * aware, so the attributes and their values need be validated (and possibly + * normalized). In the current implementation the required validation/nor- + * malization/"pretty"ing are done on newly created DN structural represen- + * tations; however the idea is to move towards DN handling in structural + * representation instead of the current string representation. To this + * purpose, we need to do only the required operations and keep track of + * what has been done to minimize their impact on performances. + * + * Developers are strongly encouraged to use this feature, to speed-up + * its stabilization. */ -char * -dn_normalize( char *dn ) +#define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private ) + +/* + * In-place, schema-aware validation of the + * structural representation of a distinguished name. + */ +static int +LDAPDN_validate( LDAPDN *dn ) { - char *d, *s; - int state, gotesc; - - /* Debug( LDAP_DEBUG_TRACE, "=> dn_normalize \"%s\"\n", dn, 0, 0 ); */ - - gotesc = 0; - state = B4TYPE; - for ( d = s = dn; *s; s++ ) { - switch ( state ) { - case B4TYPE: - if ( ! SPACE( *s ) ) { - state = INTYPE; - *d++ = *s; + int iRDN; + int rc; + + assert( dn ); + + for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + LDAPRDN *rdn = dn[ 0 ][ iRDN ]; + int iAVA; + + assert( rdn ); + + for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + AttributeDescription *ad; + slap_syntax_validate_func *validate = NULL; + + assert( ava ); + + if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) { + const char *text = NULL; + + rc = slap_bv2ad( &ava->la_attr, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + ava->la_private = ( void * )ad; } - break; - case INTYPE: - if ( *s == '=' ) { - state = B4VALUE; - *d++ = *s; - } else if ( SPACE( *s ) ) { - state = B4EQUAL; - } else { - *d++ = *s; + + /* + * Replace attr oid/name with the canonical name + */ + ava->la_attr = ad->ad_cname; + + validate = ad->ad_type->sat_syntax->ssyn_validate; + + if ( validate ) { + /* + * validate value by validate function + */ + rc = ( *validate )( ad->ad_type->sat_syntax, + &ava->la_value ); + + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } } + } + } + + return LDAP_SUCCESS; +} + +/* + * dn validate routine + */ +int +dnValidate( + Syntax *syntax, + struct berval *in ) +{ + int rc; + LDAPDN *dn = NULL; + + assert( in ); + + if ( in->bv_len == 0 ) { + return LDAP_SUCCESS; + + } else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) { + return LDAP_INVALID_SYNTAX; + } + + rc = ldap_bv2dn( in, &dn, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + assert( strlen( in->bv_val ) == in->bv_len ); + + /* + * Schema-aware validate + */ + rc = LDAPDN_validate( dn ); + ldap_dnfree( dn ); + + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + return LDAP_SUCCESS; +} + +/* + * AVA sorting inside a RDN + * + * rule: sort attributeTypes in alphabetical order; in case of multiple + * occurrences of the same attributeType, sort values in byte order + * (use memcmp, which implies alphabetical order in case of IA5 value; + * this should guarantee the repeatability of the operation). + * + * Note: the sorting can be slightly improved by sorting first + * by attribute type length, then by alphabetical order. + * + * uses a linear search; should be fine since the number of AVAs in + * a RDN should be limited. + */ +static void +AVA_Sort( LDAPRDN *rdn, int iAVA ) +{ + int i; + LDAPAVA *ava_in = rdn[ 0 ][ iAVA ]; + + assert( rdn ); + assert( ava_in ); + + for ( i = 0; i < iAVA; i++ ) { + LDAPAVA *ava = rdn[ 0 ][ i ]; + int a, j; + + assert( ava ); + + a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val ); + + if ( a > 0 ) { break; - case B4EQUAL: - if ( *s == '=' ) { - state = B4VALUE; - *d++ = *s; - } else if ( ! SPACE( *s ) ) { - /* not a valid dn - but what can we do here? */ - *d++ = *s; + } + + while ( a == 0 ) { + int v, d; + + d = ava_in->la_value.bv_len - ava->la_value.bv_len; + + v = memcmp( ava_in->la_value.bv_val, + ava->la_value.bv_val, + d <= 0 ? ava_in->la_value.bv_len + : ava->la_value.bv_len ); + + if ( v == 0 && d != 0 ) { + v = d; } - break; - case B4VALUE: - if ( *s == '"' ) { - state = INQUOTEDVALUE; - *d++ = *s; - } else if ( ! SPACE( *s ) ) { - state = INVALUE; - *d++ = *s; + + if ( v <= 0 ) { + /* + * got it! + */ + break; } - break; - case INVALUE: - if ( !gotesc && SEPARATOR( *s ) ) { - while ( SPACE( *(d - 1) ) ) - d--; - state = B4TYPE; - if ( *s == '+' ) { - *d++ = *s; - } else { - *d++ = ','; + + if ( ++i == iAVA ) { + /* + * already sorted + */ + return; + } + + ava = rdn[ 0 ][ i ]; + a = strcmp( ava_in->la_attr.bv_val, + ava->la_attr.bv_val ); + } + + /* + * move ahead + */ + for ( j = iAVA; j > i; j-- ) { + rdn[ 0 ][ j ] = rdn[ 0 ][ j - 1 ]; + } + rdn[ 0 ][ i ] = ava_in; + + return; + } +} + +/* + * In-place, schema-aware normalization / "pretty"ing of the + * structural representation of a distinguished name. + */ +static int +LDAPDN_rewrite( LDAPDN *dn, unsigned flags ) +{ + int iRDN; + int rc; + + assert( dn ); + + for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) { + LDAPRDN *rdn = dn[ 0 ][ iRDN ]; + int iAVA; + + assert( rdn ); + + for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ 0 ][ iAVA ]; + AttributeDescription *ad; + slap_syntax_validate_func *validf = NULL; + slap_syntax_transform_func *transf = NULL; + MatchingRule *mr; + struct berval bv = { 0, NULL }; + int do_sort = 0; + + assert( ava ); + + if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) { + const char *text = NULL; + + rc = slap_bv2ad( &ava->la_attr, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; } - } else if ( gotesc && !NEEDSESCAPE( *s ) && - !SEPARATOR( *s ) ) { - *--d = *s; - d++; - } else { - *d++ = *s; + + ava->la_private = ( void * )ad; + do_sort = 1; } - break; - case INQUOTEDVALUE: - if ( !gotesc && *s == '"' ) { - state = B4SEPARATOR; - *d++ = *s; - } else if ( gotesc && !NEEDSESCAPE( *s ) ) { - *--d = *s; - d++; + + /* + * Replace attr oid/name with the canonical name + */ + ava->la_attr = ad->ad_cname; + + if( ava->la_flags & LDAP_AVA_BINARY ) { + /* AVA is binary encoded, don't muck with it */ + validf = NULL; + transf = NULL; + mr = NULL; + } else if( flags & SLAP_LDAPDN_PRETTY ) { + validf = NULL; + transf = ad->ad_type->sat_syntax->ssyn_pretty; + mr = NULL; } else { - *d++ = *s; + validf = ad->ad_type->sat_syntax->ssyn_validate; + transf = ad->ad_type->sat_syntax->ssyn_normalize; + mr = ad->ad_type->sat_equality; } - break; - case B4SEPARATOR: - if ( SEPARATOR( *s ) ) { - state = B4TYPE; - *d++ = *s; + + if ( validf ) { + /* validate value before normalization */ + rc = ( *validf )( ad->ad_type->sat_syntax, + ava->la_value.bv_len + ? &ava->la_value + : (struct berval *) &slap_empty_bv ); + + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } } - break; - default: - Debug( LDAP_DEBUG_ANY, - "dn_normalize - unknown state %d\n", state, 0, 0 ); - break; - } - if ( *s == '\\' ) { - gotesc = 1; - } else { - gotesc = 0; + + if ( transf ) { + /* + * transform value by normalize/pretty function + * if value is empty, use empty_bv + */ + rc = ( *transf )( ad->ad_type->sat_syntax, + ava->la_value.bv_len + ? &ava->la_value + : (struct berval *) &slap_empty_bv, + &bv ); + + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + } + + if( mr && ( mr->smr_usage & SLAP_MR_DN_FOLD ) ) { + char *s = bv.bv_val; + + if ( UTF8bvnormalize( &bv, &bv, + LDAP_UTF8_CASEFOLD ) == NULL ) { + return LDAP_INVALID_SYNTAX; + } + free( s ); + } + + if( bv.bv_val ) { + free( ava->la_value.bv_val ); + ava->la_value = bv; + } + + if( do_sort ) AVA_Sort( rdn, iAVA ); } } - *d = '\0'; - /* Debug( LDAP_DEBUG_TRACE, "<= dn_normalize \"%s\"\n", dn, 0, 0 ); */ - return( dn ); + return LDAP_SUCCESS; } /* - * dn_normalize_case - put dn into a canonical form suitable for storing - * in a hash database. this involves normalizing the case as well as - * the format. the dn is normalized in place as well as returned. + * dn normalize routine */ +int +dnNormalize( + Syntax *syntax, + struct berval *val, + struct berval **normalized ) +{ + struct berval *out; + int rc; + + assert( normalized && *normalized == NULL ); + + out = ch_malloc( sizeof( struct berval ) ); + rc = dnNormalize2( syntax, val, out ); + if ( rc != LDAP_SUCCESS ) + free( out ); + else + *normalized = out; + return rc; +} -char * -dn_normalize_case( char *dn ) +int +dnNormalize2( + Syntax *syntax, + struct berval *val, + struct berval *out ) { - char *s; + assert( val ); + assert( out ); + + Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 ); - /* normalize format */ - dn_normalize( dn ); + if ( val->bv_len != 0 ) { + LDAPDN *dn = NULL; + int rc; + + /* + * Go to structural representation + */ + rc = ldap_bv2dn( val, &dn, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } - /* normalize case */ - for ( s = dn; *s; s++ ) { - *s = TOUPPER( *s ); + assert( strlen( val->bv_val ) == val->bv_len ); + + /* + * 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 ) { + return LDAP_INVALID_SYNTAX; + } + } else { + ber_dupbv( out, val ); } - return( dn ); + Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 ); + + return LDAP_SUCCESS; } /* - * dn_parent - return a copy of the dn of dn's parent + * dn "pretty"ing routine */ +int +dnPretty( + Syntax *syntax, + struct berval *val, + struct berval **pretty) +{ + struct berval *out; + int rc; + + assert( pretty && *pretty == NULL ); + + out = ch_malloc( sizeof( struct berval ) ); + rc = dnPretty2( syntax, val, out ); + if ( rc != LDAP_SUCCESS ) + free( out ); + else + *pretty = out; + return rc; +} -char * -dn_parent( - Backend *be, - char *dn -) +int +dnPretty2( + Syntax *syntax, + struct berval *val, + struct berval *out) { - char *s; - int inquote, gotesc; + assert( val ); + assert( out ); - if ( dn == NULL || *dn == '\0' || be_issuffix( be, dn ) ) { - return( NULL ); - } + Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 ); - /* - * no =, assume it is a dns name, like blah@some.domain.name - * if the blah@ part is there, return some.domain.name. if - * it's just some.domain.name, return domain.name. - */ - if ( strchr( dn, '=' ) == NULL ) { - if ( (s = strchr( dn, '@' )) == NULL ) { - if ( (s = strchr( dn, '.' )) == NULL ) { - return( NULL ); - } + if ( val->bv_len == 0 ) { + ber_dupbv( out, val ); + + } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) { + return LDAP_INVALID_SYNTAX; + + } else { + LDAPDN *dn = NULL; + int rc; + + /* FIXME: should be liberal in what we accept */ + rc = ldap_bv2dn( val, &dn, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; } - if ( *(s + 1) == '\0' ) { - return( NULL ); - } else { - return( strdup( s + 1 ) ); + + assert( strlen( val->bv_val ) == val->bv_len ); + + /* + * Schema-aware rewrite + */ + if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) { + ldap_dnfree( dn ); + return LDAP_INVALID_SYNTAX; + } + + /* FIXME: not sure why the default isn't pretty */ + /* RE: the default is the form that is used as + * an internal representation; the pretty form + * is a variant */ + rc = ldap_dn2bv( dn, out, + LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY ); + + ldap_dnfree( dn ); + + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; } } - /* - * else assume it is an X.500-style name, which looks like - * foo=bar,sha=baz,... - */ + Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 ); + + return LDAP_SUCCESS; +} + +/* + * Combination of both dnPretty and dnNormalize + */ +int +dnPrettyNormal( + Syntax *syntax, + struct berval *val, + struct berval *pretty, + struct berval *normal) +{ + Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 ); + + assert( val ); + assert( pretty ); + assert( normal ); + + if ( val->bv_len == 0 ) { + ber_dupbv( pretty, val ); + ber_dupbv( normal, val ); + + } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) { + /* too big */ + return LDAP_INVALID_SYNTAX; - inquote = 0; - for ( s = dn; *s; s++ ) { - if ( *s == '\\' ) { - if ( *(s + 1) ) - s++; - continue; + } else { + LDAPDN *dn = NULL; + int rc; + + pretty->bv_val = NULL; + normal->bv_val = NULL; + pretty->bv_len = 0; + normal->bv_len = 0; + + /* FIXME: should be liberal in what we accept */ + rc = ldap_bv2dn( val, &dn, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + assert( strlen( val->bv_val ) == val->bv_len ); + + /* + * Schema-aware rewrite + */ + if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) { + ldap_dnfree( dn ); + return LDAP_INVALID_SYNTAX; } - if ( inquote ) { - if ( *s == '"' ) - inquote = 0; - } else { - if ( *s == '"' ) - inquote = 1; - else if ( DNSEPARATOR( *s ) ) - return( strdup( s + 1 ) ); + + rc = ldap_dn2bv( dn, pretty, + LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY ); + + if ( rc != LDAP_SUCCESS ) { + ldap_dnfree( dn ); + return LDAP_INVALID_SYNTAX; } + + if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) { + ldap_dnfree( dn ); + free( pretty->bv_val ); + pretty->bv_val = NULL; + pretty->bv_len = 0; + return LDAP_INVALID_SYNTAX; + } + + rc = ldap_dn2bv( dn, normal, LDAP_DN_FORMAT_LDAPV3 ); + + ldap_dnfree( dn ); + if ( rc != LDAP_SUCCESS ) { + free( pretty->bv_val ); + pretty->bv_val = NULL; + pretty->bv_len = 0; + return LDAP_INVALID_SYNTAX; + } + } + + Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n", + pretty->bv_val, normal->bv_val, 0 ); + + return LDAP_SUCCESS; +} + +/* + * dnMatch routine + */ +int +dnMatch( + int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue ) +{ + int match; + struct berval *asserted = (struct berval *) assertedValue; + + assert( matchp ); + assert( value ); + assert( assertedValue ); + + match = value->bv_len - asserted->bv_len; + + if ( match == 0 ) { + match = memcmp( value->bv_val, asserted->bv_val, + value->bv_len ); } - return( NULL ); +#ifdef NEW_LOGGING + LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY, + "dnMatch: %d\n %s\n %s\n", match, + value->bv_val, asserted->bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n", + match, value->bv_val, asserted->bv_val ); +#endif + + *matchp = match; + return( LDAP_SUCCESS ); } /* - * dn_issuffix - tells whether suffix is a suffix of dn. both dn - * and suffix must be normalized. + * dnParent - dn's parent, in-place + * + * note: the incoming dn is assumed to be normalized/prettyfied, + * so that escaped rdn/ava separators are in '\'+hexpair form */ +void +dnParent( + struct berval *dn, + struct berval *pdn ) +{ + char *p; + + p = strchr( dn->bv_val, ',' ); + + /* one-level dn */ + if ( p == NULL ) { + *pdn = slap_empty_bv; + return; + } + + assert( DN_SEPARATOR( p[ 0 ] ) ); + p++; + + assert( ATTR_LEADCHAR( p[ 0 ] ) ); + pdn->bv_val = p; + pdn->bv_len = dn->bv_len - (p - dn->bv_val); + + return; +} int -dn_issuffix( - char *dn, - char *suffix -) +dnExtractRdn( + struct berval *dn, + struct berval *rdn ) { - int dnlen, suffixlen; + LDAPRDN *tmpRDN; + const char *p; + int rc; - if ( dn == NULL ) { - return( 0 ); + assert( dn ); + assert( rdn ); + + if( dn->bv_len == 0 ) { + return LDAP_OTHER; } - suffixlen = strlen( suffix ); - dnlen = strlen( dn ); + rc = ldap_bv2rdn( dn, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } - if ( suffixlen > dnlen ) { - return( 0 ); + rc = ldap_rdn2bv( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 ); + ldap_rdnfree( tmpRDN ); + if ( rc != LDAP_SUCCESS ) { + return rc; } - return( strcasecmp( dn + dnlen - suffixlen, suffix ) == 0 ); + return LDAP_SUCCESS; } /* - * dn_type - tells whether the given dn is an X.500 thing or DNS thing - * returns (defined in slap.h): DN_DNS dns-style thing - * DN_X500 x500-style thing + * We can assume the input is a prettied or normalized DN */ +int +dn_rdnlen( + Backend *be, + struct berval *dn_in ) +{ + const char *p; + + assert( dn_in ); + + if ( dn_in == NULL ) { + return 0; + } + + if ( !dn_in->bv_len ) { + return 0; + } + + if ( be != NULL && be_issuffix( be, dn_in ) ) { + return 0; + } + + p = strchr( dn_in->bv_val, ',' ); + + return p ? p - dn_in->bv_val : dn_in->bv_len; +} + +/* rdnValidate: + * + * LDAP_SUCCESS if rdn is a legal rdn; + * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns) + */ int -dn_type( char *dn ) +rdnValidate( struct berval *rdn ) { - return( strchr( dn, '=' ) == NULL ? DN_DNS : DN_X500 ); +#if 1 + /* Major cheat! + * input is a pretty or normalized DN + * hence, we can just search for ',' + */ + if( rdn == NULL || rdn->bv_len == 0 || + rdn->bv_len > SLAP_LDAPDN_MAXLEN ) + { + return LDAP_INVALID_SYNTAX; + } + + return strchr( rdn->bv_val, ',' ) == NULL + ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX; + +#else + LDAPRDN *RDN, **DN[ 2 ] = { &RDN, NULL }; + const char *p; + int rc; + + /* + * must be non-empty + */ + if ( rdn == NULL || rdn == '\0' ) { + return 0; + } + + /* + * must be parsable + */ + rc = ldap_bv2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + /* + * Must be one-level + */ + if ( p[ 0 ] != '\0' ) { + return 0; + } + + /* + * Schema-aware validate + */ + if ( rc == LDAP_SUCCESS ) { + rc = LDAPDN_validate( DN ); + } + ldap_rdnfree( RDN ); + + /* + * Must validate (there's a repeated parsing ...) + */ + return ( rc == LDAP_SUCCESS ); +#endif +} + + +/* build_new_dn: + * + * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being + * renamed. + * + * new_dn = parent (p_dn) + separator + rdn (newrdn) + null. + */ + +void +build_new_dn( struct berval * new_dn, + struct berval * parent_dn, + struct berval * newrdn ) +{ + char *ptr; + + if ( parent_dn == NULL ) { + ber_dupbv( new_dn, newrdn ); + return; + } + + new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1; + new_dn->bv_val = (char *) ch_malloc( new_dn->bv_len + 1 ); + + ptr = slap_strcopy( new_dn->bv_val, newrdn->bv_val ); + *ptr++ = ','; + strcpy( ptr, parent_dn->bv_val ); } -char * -dn_upcase( char *dn ) + +/* + * dnIsSuffix - tells whether suffix is a suffix of dn. + * Both dn and suffix must be normalized. + */ +int +dnIsSuffix( + const struct berval *dn, + const struct berval *suffix ) { - char *s; + int d = dn->bv_len - suffix->bv_len; + + assert( dn ); + assert( suffix ); + + /* empty suffix matches any dn */ + if ( suffix->bv_len == 0 ) { + return 1; + } + + /* suffix longer than dn */ + if ( d < 0 ) { + return 0; + } + + /* no rdn separator or escaped rdn separator */ + if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) { + return 0; + } - /* normalize case */ - for ( s = dn; *s; s++ ) { - *s = TOUPPER( *s ); + /* no possible match or malformed dn */ + if ( d == 1 ) { + return 0; } - return( dn ); + /* compare */ + return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 ); } diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c index 8094a09e8b841daf31edab5d3af15a1973fb224c..48afbf5d9d3e99724999f9246196f253e7e1af56 100644 --- a/servers/slapd/entry.c +++ b/servers/slapd/entry.c @@ -589,7 +589,7 @@ int entry_decode(struct berval *bv, Entry **e) bptr = (BerVarray)x->e_attrs; a = NULL; - while (i = entry_getlen(&ptr)) { + while ((i = entry_getlen(&ptr))) { struct berval bv; bv.bv_len = i; bv.bv_val = ptr; diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c new file mode 100644 index 0000000000000000000000000000000000000000..64e8cc2df41738267f63169d682c2a76e2d05a47 --- /dev/null +++ b/servers/slapd/extended.c @@ -0,0 +1,334 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1999-2002 The OpenLDAP Foundation. + * 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. + */ + +/* + * LDAPv3 Extended Operation Request + * ExtendedRequest ::= [APPLICATION 23] SEQUENCE { + * requestName [0] LDAPOID, + * requestValue [1] OCTET STRING OPTIONAL + * } + * + * LDAPv3 Extended Operation Response + * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { + * COMPONENTS OF LDAPResult, + * responseName [10] LDAPOID OPTIONAL, + * response [11] OCTET STRING OPTIONAL + * } + * + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/socket.h> +#include <ac/string.h> + +#include "slap.h" + +static struct extop_list { + struct extop_list *next; + struct berval oid; + SLAP_EXTOP_MAIN_FN *ext_main; +} *supp_ext_list = NULL; + +static SLAP_EXTOP_MAIN_FN whoami_extop; + +/* BerVal Constant initializer */ + +#define BVC(x) {sizeof(x)-1, x} + +/* this list of built-in extops is for extops that are not part + * of backends or in external modules. essentially, this is + * just a way to get built-in extops onto the extop list without + * having a separate init routine for each built-in extop. + */ +static struct { + struct berval oid; + SLAP_EXTOP_MAIN_FN *ext_main; +} builtin_extops[] = { +#ifdef HAVE_TLS + { BVC(LDAP_EXOP_START_TLS), starttls_extop }, +#endif + { BVC(LDAP_EXOP_MODIFY_PASSWD), passwd_extop }, + { BVC(LDAP_EXOP_X_WHO_AM_I), whoami_extop }, + { {0,NULL}, NULL } +}; + + +static struct extop_list *find_extop( + struct extop_list *list, struct berval *oid ); + +struct berval * +get_supported_extop (int index) +{ + struct extop_list *ext; + + /* linear scan is slow, but this way doesn't force a + * big change on root_dse.c, where this routine is used. + */ + for (ext = supp_ext_list; ext != NULL && --index >= 0; ext = ext->next) { + ; /* empty */ + } + + if (ext == NULL) return NULL; + + return &ext->oid ; +} + +int +do_extended( + Connection *conn, + Operation *op +) +{ + int rc = LDAP_SUCCESS; + struct berval reqoid = {0, NULL}; + struct berval reqdata = {0, NULL}; + ber_tag_t tag; + ber_len_t len; + struct extop_list *ext; + const char *text; + BerVarray refs; + char *rspoid; + struct berval *rspdata; + LDAPControl **rspctrls; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_extended: conn %d\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 ); +#endif + + if( op->o_protocol < LDAP_VERSION3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_extended: protocol version (%d) too low.\n", + op->o_protocol )); +#else + Debug( LDAP_DEBUG_ANY, + "do_extended: protocol version (%d) too low\n", + op->o_protocol, 0 ,0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "requires LDAPv3" ); + rc = -1; + goto done; + } + + if ( ber_scanf( op->o_ber, "{m" /*}*/, &reqoid ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_extended: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = -1; + goto done; + } + + if( !(ext = find_extop(supp_ext_list, &reqoid)) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_extended: conn %d unsupported operation \"%s\"\n", + conn->c_connid, reqoid.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n", + reqoid.bv_val, 0 ,0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "unsupported extended operation", NULL, NULL ); + goto done; + } + + tag = ber_peek_tag( op->o_ber, &len ); + + if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) { + if( ber_scanf( op->o_ber, "m", &reqdata ) == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_extended: conn %d ber_scanf failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); +#endif + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = -1; + goto done; + } + } + + if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_extended: conn %d get_ctrls failed\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 ); +#endif + return rc; + } + + /* check for controls inappropriate for all extended operations */ + if( get_manageDSAit( op ) == SLAP_CRITICAL_CONTROL ) { + send_ldap_result( conn, op, + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION, + NULL, "manageDSAit control inappropriate", + NULL, NULL ); + goto done; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "do_extended: conn %d oid=%d\n.", conn->c_connid, reqoid.bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", reqoid.bv_val, 0 ,0 ); +#endif + + rspoid = NULL; + rspdata = NULL; + rspctrls = NULL; + text = NULL; + refs = NULL; + + rc = (ext->ext_main)( conn, op, + reqoid.bv_val, reqdata.bv_val ? &reqdata : NULL, + &rspoid, &rspdata, &rspctrls, &text, &refs ); + + if( rc != SLAPD_ABANDON ) { + if ( rc == LDAP_REFERRAL && refs == NULL ) { + refs = referral_rewrite( default_referral, + NULL, NULL, LDAP_SCOPE_DEFAULT ); + } + + send_ldap_extended( conn, op, rc, NULL, text, refs, + rspoid, rspdata, rspctrls ); + + ber_bvarray_free( refs ); + } + + if ( rspoid != NULL ) { + free( rspoid ); + } + + if ( rspdata != NULL ) { + ber_bvfree( rspdata ); + } + +done: + return rc; +} + +int +load_extop( + const char *ext_oid, + SLAP_EXTOP_MAIN_FN *ext_main ) +{ + struct extop_list *ext; + + if( ext_oid == NULL || *ext_oid == '\0' ) return -1; + if(!ext_main) return -1; + + ext = ch_calloc(1, sizeof(struct extop_list)); + if (ext == NULL) + return(-1); + + ber_str2bv( ext_oid, 0, 1, &ext->oid ); + if (ext->oid.bv_val == NULL) { + free(ext); + return(-1); + } + + ext->ext_main = ext_main; + ext->next = supp_ext_list; + + supp_ext_list = ext; + + return(0); +} + +int +extops_init (void) +{ + int i; + + for (i = 0; builtin_extops[i].oid.bv_val != NULL; i++) { + load_extop(builtin_extops[i].oid.bv_val, builtin_extops[i].ext_main); + } + return(0); +} + +int +extops_kill (void) +{ + struct extop_list *ext; + + /* we allocated the memory, so we have to free it, too. */ + while ((ext = supp_ext_list) != NULL) { + supp_ext_list = ext->next; + if (ext->oid.bv_val != NULL) + ch_free(ext->oid.bv_val); + ch_free(ext); + } + return(0); +} + +static struct extop_list * +find_extop( struct extop_list *list, struct berval *oid ) +{ + struct extop_list *ext; + + for (ext = list; ext; ext = ext->next) { + if (ber_bvcmp(&ext->oid, oid) == 0) + return(ext); + } + return(NULL); +} + + +static int +whoami_extop ( + Connection *conn, + Operation *op, + const char * reqoid, + struct berval * reqdata, + char ** rspoid, + struct berval ** rspdata, + LDAPControl ***rspctrls, + const char ** text, + BerVarray * refs ) +{ + struct berval *bv; + + if ( reqdata != NULL ) { + /* no request data should be provided */ + *text = "no request data expected"; + return LDAP_PROTOCOL_ERROR; + } + + bv = (struct berval *) ch_malloc( sizeof(struct berval) ); + if( op->o_dn.bv_len ) { + bv->bv_len = op->o_dn.bv_len + sizeof("dn:")-1; + bv->bv_val = ch_malloc( bv->bv_len + 1 ); + AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:")-1 ); + AC_MEMCPY( &bv->bv_val[sizeof("dn:")-1], op->o_dn.bv_val, + op->o_dn.bv_len ); + bv->bv_val[bv->bv_len] = '\0'; + + } else { + bv->bv_len = 0; + bv->bv_val = NULL; + } + + *rspdata = bv; + return LDAP_SUCCESS; +} diff --git a/servers/slapd/filter.c b/servers/slapd/filter.c index 8d990b361d4b42ce5f137437199b1acb78858d97..16124c0c31bc588670946ab4a706ca3aef10a650 100644 --- a/servers/slapd/filter.c +++ b/servers/slapd/filter.c @@ -1,28 +1,53 @@ /* filter.c - routines for parsing and dealing with filters */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/socket.h> +#include <ac/string.h> + #include "slap.h" -static int get_filter_list(); -static int get_substring_filter(); +static int get_filter_list( + Connection *conn, + BerElement *ber, + Filter **f, + const char **text ); -extern int get_ava(); -extern char *ch_malloc(); -extern char *ch_realloc(); +static int get_substring_filter( + Connection *conn, + BerElement *ber, + Filter *f, + const char **text ); + +static int filter_escape_value( + struct berval *in, + struct berval *out ); int -get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr ) +get_filter( + Connection *conn, + BerElement *ber, + Filter **filt, + const char **text ) { - unsigned long tag, len; + ber_tag_t tag; + ber_len_t len; int err; Filter *f; - char *ftmp; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, "get_filter: conn %d\n", + conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 ); - +#endif /* * A filter looks like this coming in: * Filter ::= CHOICE { @@ -35,292 +60,459 @@ get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr ) * lessOrEqual [6] AttributeValueAssertion, * present [7] AttributeType,, * approxMatch [8] AttributeValueAssertion + * extensibleMatch [9] MatchingRuleAssertion * } * * SubstringFilter ::= SEQUENCE { - * type AttributeType, + * type AttributeType, * SEQUENCE OF CHOICE { - * initial [0] IA5String, - * any [1] IA5String, - * final [2] IA5String + * initial [0] IA5String, + * any [1] IA5String, + * final [2] IA5String * } * } + * + * MatchingRuleAssertion ::= SEQUENCE { + * matchingRule [1] MatchingRuleId OPTIONAL, + * type [2] AttributeDescription OPTIONAL, + * matchValue [3] AssertionValue, + * dnAttributes [4] BOOLEAN DEFAULT FALSE + * } + * */ + tag = ber_peek_tag( ber, &len ); + + if( tag == LBER_ERROR ) { + *text = "error decoding filter"; + return SLAPD_DISCONNECT; + } + f = (Filter *) ch_malloc( sizeof(Filter) ); - *filt = f; f->f_next = NULL; - err = 0; - *fstr = NULL; - f->f_choice = ber_peek_tag( ber, &len ); -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - switch ( f->f_choice ) { - case LDAP_FILTER_EQUALITY: - case LDAP_FILTER_GE: - case LDAP_FILTER_LE: - case LDAP_FILTER_PRESENT: - case LDAP_FILTER_PRESENT_30: - case LDAP_FILTER_APPROX: - (void) ber_skip_tag( ber, &len ); - if ( f->f_choice == LDAP_FILTER_PRESENT_30 ) { - f->f_choice = LDAP_FILTER_PRESENT; - } - break; - default: - break; - } - } -#endif + err = LDAP_SUCCESS; + f->f_choice = tag; + switch ( f->f_choice ) { case LDAP_FILTER_EQUALITY: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2, + "get_filter: conn %d EQUALITY\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 ); - if ( (err = get_ava( ber, &f->f_ava )) == 0 ) { - *fstr = ch_malloc(4 + strlen( f->f_avtype ) + - f->f_avvalue.bv_len); - sprintf( *fstr, "(%s=%s)", f->f_avtype, - f->f_avvalue.bv_val ); +#endif + err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text ); + if ( err != LDAP_SUCCESS ) { + break; } + + assert( f->f_ava != NULL ); break; case LDAP_FILTER_SUBSTRINGS: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d SUBSTRINGS\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 ); - err = get_substring_filter( conn, ber, f, fstr ); +#endif + err = get_substring_filter( conn, ber, f, text ); break; case LDAP_FILTER_GE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d GE\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 ); - if ( (err = get_ava( ber, &f->f_ava )) == 0 ) { - *fstr = ch_malloc(5 + strlen( f->f_avtype ) + - f->f_avvalue.bv_len); - sprintf( *fstr, "(%s>=%s)", f->f_avtype, - f->f_avvalue.bv_val ); +#endif + err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; case LDAP_FILTER_LE: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d LE\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 ); - if ( (err = get_ava( ber, &f->f_ava )) == 0 ) { - *fstr = ch_malloc(5 + strlen( f->f_avtype ) + - f->f_avvalue.bv_len); - sprintf( *fstr, "(%s<=%s)", f->f_avtype, - f->f_avvalue.bv_val ); +#endif + err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; - case LDAP_FILTER_PRESENT: + case LDAP_FILTER_PRESENT: { + struct berval type; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d PRESENT\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 ); - if ( ber_scanf( ber, "a", &f->f_type ) == LBER_ERROR ) { - err = LDAP_PROTOCOL_ERROR; - } else { +#endif + if ( ber_scanf( ber, "m", &type ) == LBER_ERROR ) { + err = SLAPD_DISCONNECT; + *text = "error decoding filter"; + break; + } + + f->f_desc = NULL; + err = slap_bv2ad( &type, &f->f_desc, text ); + + if( err != LDAP_SUCCESS ) { + /* unrecognized attribute description or other error */ + f->f_choice = SLAPD_FILTER_COMPUTED; + f->f_result = LDAP_COMPARE_FALSE; err = LDAP_SUCCESS; - attr_normalize( f->f_type ); - *fstr = ch_malloc( 5 + strlen( f->f_type ) ); - sprintf( *fstr, "(%s=*)", f->f_type ); + break; } - break; + } break; case LDAP_FILTER_APPROX: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d APPROX\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 ); - if ( (err = get_ava( ber, &f->f_ava )) == 0 ) { - *fstr = ch_malloc(5 + strlen( f->f_avtype ) + - f->f_avvalue.bv_len); - sprintf( *fstr, "(%s~=%s)", f->f_avtype, - f->f_avvalue.bv_val ); +#endif + err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; case LDAP_FILTER_AND: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d AND\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 ); - if ( (err = get_filter_list( conn, ber, &f->f_and, &ftmp )) - == 0 ) { - *fstr = ch_malloc( 4 + strlen( ftmp ) ); - sprintf( *fstr, "(&%s)", ftmp ); - free( ftmp ); +#endif + err = get_filter_list( conn, ber, &f->f_and, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; case LDAP_FILTER_OR: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d OR\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 ); - if ( (err = get_filter_list( conn, ber, &f->f_or, &ftmp )) - == 0 ) { - *fstr = ch_malloc( 4 + strlen( ftmp ) ); - sprintf( *fstr, "(|%s)", ftmp ); - free( ftmp ); +#endif + err = get_filter_list( conn, ber, &f->f_or, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; case LDAP_FILTER_NOT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d NOT\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 ); +#endif (void) ber_skip_tag( ber, &len ); - if ( (err = get_filter( conn, ber, &f->f_not, &ftmp )) == 0 ) { - *fstr = ch_malloc( 4 + strlen( ftmp ) ); - sprintf( *fstr, "(!%s)", ftmp ); - free( ftmp ); + err = get_filter( conn, ber, &f->f_not, text ); + if ( err != LDAP_SUCCESS ) { + break; } break; + case LDAP_FILTER_EXT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_filter: conn %d EXTENSIBLE\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 ); +#endif + + err = get_mra( ber, &f->f_mra, text ); + if ( err != LDAP_SUCCESS ) { + break; + } + + assert( f->f_mra != NULL ); + break; + default: - Debug( LDAP_DEBUG_ANY, "unknown filter type %d\n", f->f_choice, - 0, 0 ); - err = LDAP_PROTOCOL_ERROR; + (void) ber_scanf( ber, "x" ); /* skip the element */ +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "get_filter: conn %d unknown filter type=%lu\n", + conn->c_connid, f->f_choice )); +#else + Debug( LDAP_DEBUG_ANY, "get_filter: unknown filter type=%lu\n", + f->f_choice, 0, 0 ); +#endif + f->f_choice = SLAPD_FILTER_COMPUTED; + f->f_result = SLAPD_COMPARE_UNDEFINED; break; } - if ( err != 0 ) { - free( (char *) f ); - if ( *fstr != NULL ) { - free( *fstr ); + if ( err != LDAP_SUCCESS ) { + if( err != SLAPD_DISCONNECT ) { + /* ignore error */ + f->f_choice = SLAPD_FILTER_COMPUTED; + f->f_result = SLAPD_COMPARE_UNDEFINED; + err = LDAP_SUCCESS; + *filt = f; + + } else { + free(f); } + + } else { + *filt = f; } +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2, + "get_filter: conn %d exit\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 ); +#endif return( err ); } static int -get_filter_list( Connection *conn, BerElement *ber, Filter **f, char **fstr ) +get_filter_list( Connection *conn, BerElement *ber, + Filter **f, + const char **text ) { Filter **new; int err; - unsigned long tag, len; - char *last, *ftmp; - + ber_tag_t tag; + ber_len_t len; + char *last; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "get_filter_list: conn %d start\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 ); - -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - (void) ber_skip_tag( ber, &len ); - } #endif - *fstr = NULL; new = f; for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT; - tag = ber_next_element( ber, &len, last ) ) { - if ( (err = get_filter( conn, ber, new, &ftmp )) != 0 ) + tag = ber_next_element( ber, &len, last ) ) + { + err = get_filter( conn, ber, new, text ); + if ( err != LDAP_SUCCESS ) return( err ); - if ( *fstr == NULL ) { - *fstr = ftmp; - } else { - *fstr = ch_realloc( *fstr, strlen( *fstr ) + - strlen( ftmp ) + 1 ); - strcat( *fstr, ftmp ); - free( ftmp ); - } new = &(*new)->f_next; } *new = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "get_filter_list: conn %d exit\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 ); - return( 0 ); +#endif + return( LDAP_SUCCESS ); } static int get_substring_filter( - Connection *conn, - BerElement *ber, - Filter *f, - char **fstr -) + Connection *conn, + BerElement *ber, + Filter *f, + const char **text ) { - unsigned long tag, len, rc; - char *val, *last; - int syntax; - + ber_tag_t tag; + ber_len_t len; + ber_tag_t rc; + struct berval value; + char *last; + struct berval bv; + *text = "error decoding filter"; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "get_substring_filter: conn %d begin\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 ); - -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - (void) ber_skip_tag( ber, &len ); - } #endif - if ( ber_scanf( ber, "{a", &f->f_sub_type ) == LBER_ERROR ) { - return( LDAP_PROTOCOL_ERROR ); + if ( ber_scanf( ber, "{m" /*}*/, &bv ) == LBER_ERROR ) { + return SLAPD_DISCONNECT; } - attr_normalize( f->f_sub_type ); - syntax = attr_syntax( f->f_sub_type ); - f->f_sub_initial = NULL; + + f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) ); + f->f_sub_desc = NULL; + rc = slap_bv2ad( &bv, &f->f_sub_desc, text ); + + if( rc != LDAP_SUCCESS ) { + text = NULL; + ch_free( f->f_sub ); + f->f_choice = SLAPD_FILTER_COMPUTED; + f->f_result = SLAPD_COMPARE_UNDEFINED; + return LDAP_SUCCESS; + } + + f->f_sub_initial.bv_val = NULL; f->f_sub_any = NULL; - f->f_sub_final = NULL; + f->f_sub_final.bv_val = NULL; - *fstr = ch_malloc( strlen( f->f_sub_type ) + 3 ); - sprintf( *fstr, "(%s=", f->f_sub_type ); for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT; - tag = ber_next_element( ber, &len, last ) ) { -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - rc = ber_scanf( ber, "{a}", &val ); - } else -#endif - rc = ber_scanf( ber, "a", &val ); + tag = ber_next_element( ber, &len, last ) ) + { + unsigned usage; + + rc = ber_scanf( ber, "m", &value ); if ( rc == LBER_ERROR ) { - return( LDAP_PROTOCOL_ERROR ); - } - if ( val == NULL || *val == '\0' ) { - if ( val != NULL ) { - free( val ); - } - return( LDAP_INVALID_SYNTAX ); + rc = SLAPD_DISCONNECT; + goto return_error; } - value_normalize( val, syntax ); + + if ( value.bv_val == NULL || value.bv_len == 0 ) { + rc = LDAP_INVALID_SYNTAX; + goto return_error; + } switch ( tag ) { -#ifdef COMPAT30 - case LDAP_SUBSTRING_INITIAL_30: + case LDAP_SUBSTRING_INITIAL: + usage = SLAP_MR_SUBSTR_INITIAL; + break; + + case LDAP_SUBSTRING_ANY: + usage = SLAP_MR_SUBSTR_ANY; + break; + + case LDAP_SUBSTRING_FINAL: + usage = SLAP_MR_SUBSTR_FINAL; + break; + + default: + rc = LDAP_PROTOCOL_ERROR; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "get_filter_substring: conn %d unknown substring choice=%ld\n", + conn->c_connid, (long)tag )); +#else + Debug( LDAP_DEBUG_FILTER, + " unknown substring choice=%ld\n", + (long) tag, 0, 0 ); #endif + goto return_error; + } + + /* valiate using equality matching rule validator! */ + rc = value_validate( f->f_sub_desc->ad_type->sat_equality, + &value, text ); + if( rc != LDAP_SUCCESS ) { + goto return_error; + } + + rc = value_normalize( f->f_sub_desc, usage, + &value, &bv, text ); + if( rc != LDAP_SUCCESS ) { + goto return_error; + } + + value = bv; + + rc = LDAP_PROTOCOL_ERROR; + + switch ( tag ) { case LDAP_SUBSTRING_INITIAL: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_substring_filter: conn %d INITIAL\n", + conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, " INITIAL\n", 0, 0, 0 ); - if ( f->f_sub_initial != NULL ) { - return( LDAP_PROTOCOL_ERROR ); +#endif + + if ( f->f_sub_initial.bv_val != NULL + || f->f_sub_any != NULL + || f->f_sub_final.bv_val != NULL ) + { + free( value.bv_val ); + goto return_error; } - f->f_sub_initial = val; - *fstr = ch_realloc( *fstr, strlen( *fstr ) + - strlen( val ) + 1 ); - strcat( *fstr, val ); + + f->f_sub_initial = value; break; -#ifdef COMPAT30 - case LDAP_SUBSTRING_ANY_30: -#endif case LDAP_SUBSTRING_ANY: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_substring_filter: conn %d ANY\n", + conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, " ANY\n", 0, 0, 0 ); - charray_add( &f->f_sub_any, val ); - *fstr = ch_realloc( *fstr, strlen( *fstr ) + - strlen( val ) + 2 ); - strcat( *fstr, "*" ); - strcat( *fstr, val ); +#endif + + if ( f->f_sub_final.bv_val != NULL ) { + free( value.bv_val ); + goto return_error; + } + + ber_bvarray_add( &f->f_sub_any, &value ); break; -#ifdef COMPAT30 - case LDAP_SUBSTRING_FINAL_30: -#endif case LDAP_SUBSTRING_FINAL: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "get_substring_filter: conn %d FINAL\n", + conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, " FINAL\n", 0, 0, 0 ); - if ( f->f_sub_final != NULL ) { - return( LDAP_PROTOCOL_ERROR ); +#endif + + if ( f->f_sub_final.bv_val != NULL ) { + free( value.bv_val ); + goto return_error; } - f->f_sub_final = val; - *fstr = ch_realloc( *fstr, strlen( *fstr ) + - strlen( val ) + 2 ); - strcat( *fstr, "*" ); - strcat( *fstr, val ); + + f->f_sub_final = value; break; default: - Debug( LDAP_DEBUG_FILTER, " unknown type\n", tag, 0, - 0 ); - return( LDAP_PROTOCOL_ERROR ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "get_substring_filter: conn %d unknown substring type %ld\n", + conn->c_connid, (long)tag )); +#else + Debug( LDAP_DEBUG_FILTER, + " unknown substring type=%ld\n", + (long) tag, 0, 0 ); +#endif + + free( value.bv_val ); + +return_error: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "get_substring_filter: conn %d error %ld\n", + conn->c_connid, (long)rc )); +#else + Debug( LDAP_DEBUG_FILTER, " error=%ld\n", + (long) rc, 0, 0 ); +#endif + free( f->f_sub_initial.bv_val ); + ber_bvarray_free( f->f_sub_any ); + free( f->f_sub_final.bv_val ); + ch_free( f->f_sub ); + return rc; } } - *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 ); - if ( f->f_sub_final == NULL ) { - strcat( *fstr, "*" ); - } - strcat( *fstr, ")" ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "get_substring_filter: conn %d exit\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 ); - return( 0 ); +#endif + return( LDAP_SUCCESS ); } void @@ -333,30 +525,25 @@ filter_free( Filter *f ) } switch ( f->f_choice ) { + case LDAP_FILTER_PRESENT: + break; + case LDAP_FILTER_EQUALITY: case LDAP_FILTER_GE: case LDAP_FILTER_LE: case LDAP_FILTER_APPROX: - ava_free( &f->f_ava, 0 ); + ava_free( f->f_ava, 1 ); break; case LDAP_FILTER_SUBSTRINGS: - if ( f->f_sub_type != NULL ) { - free( f->f_sub_type ); - } - if ( f->f_sub_initial != NULL ) { - free( f->f_sub_initial ); - } - charray_free( f->f_sub_any ); - if ( f->f_sub_final != NULL ) { - free( f->f_sub_final ); + if ( f->f_sub_initial.bv_val != NULL ) { + free( f->f_sub_initial.bv_val ); } - break; - - case LDAP_FILTER_PRESENT: - if ( f->f_type != NULL ) { - free( f->f_type ); + ber_bvarray_free( f->f_sub_any ); + if ( f->f_sub_final.bv_val != NULL ) { + free( f->f_sub_final.bv_val ); } + ch_free( f->f_sub ); break; case LDAP_FILTER_AND: @@ -368,82 +555,244 @@ filter_free( Filter *f ) } break; + case LDAP_FILTER_EXT: + mra_free( f->f_mra, 1 ); + break; + + case SLAPD_FILTER_COMPUTED: + break; + default: - Debug( LDAP_DEBUG_ANY, "unknown filter type %d\n", f->f_choice, - 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ERR, + "filter_free: unknown filter type %lu\n", f->f_choice )); +#else + Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n", + f->f_choice, 0, 0 ); +#endif break; } + free( f ); } -#ifdef LDAP_DEBUG - void -filter_print( Filter *f ) +filter2bv( Filter *f, struct berval *fstr ) { int i; Filter *p; + struct berval tmp; + ber_len_t len; if ( f == NULL ) { - printf( "NULL" ); + ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr ); + return; } switch ( f->f_choice ) { case LDAP_FILTER_EQUALITY: - printf( "(%s=%s)", f->f_ava.ava_type, - f->f_ava.ava_value.bv_val ); + filter_escape_value( &f->f_av_value, &tmp ); + + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + + tmp.bv_len + ( sizeof("(=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", + f->f_av_desc->ad_cname.bv_val, + tmp.bv_val ); + + ber_memfree( tmp.bv_val ); break; case LDAP_FILTER_GE: - printf( "(%s>=%s)", f->f_ava.ava_type, - f->f_ava.ava_value.bv_val ); + filter_escape_value( &f->f_av_value, &tmp ); + + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + + tmp.bv_len + ( sizeof("(>=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", + f->f_av_desc->ad_cname.bv_val, + tmp.bv_val ); + + ber_memfree( tmp.bv_val ); break; case LDAP_FILTER_LE: - printf( "(%s<=%s)", f->f_ava.ava_type, - f->f_ava.ava_value.bv_val ); + filter_escape_value( &f->f_av_value, &tmp ); + + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + + tmp.bv_len + ( sizeof("(<=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", + f->f_av_desc->ad_cname.bv_val, + tmp.bv_val ); + + ber_memfree( tmp.bv_val ); break; case LDAP_FILTER_APPROX: - printf( "(%s~=%s)", f->f_ava.ava_type, - f->f_ava.ava_value.bv_val ); + filter_escape_value( &f->f_av_value, &tmp ); + + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + + tmp.bv_len + ( sizeof("(~=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", + f->f_av_desc->ad_cname.bv_val, + tmp.bv_val ); + ber_memfree( tmp.bv_val ); break; case LDAP_FILTER_SUBSTRINGS: - printf( "(%s=", f->f_sub_type ); - if ( f->f_sub_initial != NULL ) { - printf( "%s", f->f_sub_initial ); + fstr->bv_len = f->f_sub_desc->ad_cname.bv_len + + ( sizeof("(=*)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 128 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + f->f_sub_desc->ad_cname.bv_val ); + + if ( f->f_sub_initial.bv_val != NULL ) { + len = fstr->bv_len; + + filter_escape_value( &f->f_sub_initial, &tmp ); + + fstr->bv_len += tmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len-2], tmp.bv_len+3, + /* "(attr=" */ "%s*)", + tmp.bv_val ); + + ber_memfree( tmp.bv_val ); } + if ( f->f_sub_any != NULL ) { - for ( i = 0; f->f_sub_any[i] != NULL; i++ ) { - printf( "*%s", f->f_sub_any[i] ); + for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) { + len = fstr->bv_len; + filter_escape_value( &f->f_sub_any[i], &tmp ); + + fstr->bv_len += tmp.bv_len + 1; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len-1], tmp.bv_len+3, + /* "(attr=[init]*[any*]" */ "%s*)", + tmp.bv_val ); + ber_memfree( tmp.bv_val ); } } - charray_free( f->f_sub_any ); - if ( f->f_sub_final != NULL ) { - printf( "*%s", f->f_sub_final ); + + if ( f->f_sub_final.bv_val != NULL ) { + len = fstr->bv_len; + + filter_escape_value( &f->f_sub_final, &tmp ); + + fstr->bv_len += tmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len-1], tmp.bv_len+3, + /* "(attr=[init*][any*]" */ "%s)", + tmp.bv_val ); + + ber_memfree( tmp.bv_val ); } + break; case LDAP_FILTER_PRESENT: - printf( "%s=*", f->f_type ); + fstr->bv_len = f->f_desc->ad_cname.bv_len + + ( sizeof("(=*)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + f->f_desc->ad_cname.bv_val ); break; case LDAP_FILTER_AND: case LDAP_FILTER_OR: case LDAP_FILTER_NOT: - printf( "(%c", f->f_choice == LDAP_FILTER_AND ? '&' : - f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); + fstr->bv_len = sizeof("(%)") - 1; + fstr->bv_val = malloc( fstr->bv_len + 128 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", + f->f_choice == LDAP_FILTER_AND ? '&' : + f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); + for ( p = f->f_list; p != NULL; p = p->f_next ) { - filter_print( p ); + len = fstr->bv_len; + + filter2bv( p, &tmp ); + + fstr->bv_len += tmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len-1], tmp.bv_len + 2, + /*"("*/ "%s)", tmp.bv_val ); + + ch_free( tmp.bv_val ); } - printf( ")" ); + + break; + + case LDAP_FILTER_EXT: + filter_escape_value( &f->f_mr_value, &tmp ); + + fstr->bv_len = f->f_mr_desc->ad_cname.bv_len + + ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) + + ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) + + tmp.bv_len + ( sizeof("(:=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", + f->f_mr_desc->ad_cname.bv_val, + f->f_mr_dnattrs ? ":dn" : "", + f->f_mr_rule_text.bv_len ? ":" : "", + f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "", + tmp.bv_val ); + ber_memfree( tmp.bv_val ); + break; + + case SLAPD_FILTER_COMPUTED: + ber_str2bv( + f->f_result == LDAP_COMPARE_FALSE ? "(?=false)" : + f->f_result == LDAP_COMPARE_TRUE ? "(?=true)" : + f->f_result == SLAPD_COMPARE_UNDEFINED ? "(?=undefined)" : + "(?=error)", + f->f_result == LDAP_COMPARE_FALSE ? sizeof("(?=false)")-1 : + f->f_result == LDAP_COMPARE_TRUE ? sizeof("(?=true)")-1 : + f->f_result == SLAPD_COMPARE_UNDEFINED ? sizeof("(?=undefined)")-1 : + sizeof("(?=error)")-1, + 1, fstr ); break; default: - printf( "unknown type %d", f->f_choice ); + ber_str2bv( "(?=unknown)", sizeof("(?=unknown)")-1, 1, fstr ); break; } } -#endif /* ldap_debug */ +static int filter_escape_value( + struct berval *in, + struct berval *out ) +{ + ber_len_t i; + assert( in ); + assert( out ); + + out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 ); + out->bv_len = 0; + + for( i=0; i < in->bv_len ; i++ ) { + if( FILTER_ESCAPE(in->bv_val[i]) ) { + out->bv_val[out->bv_len++] = SLAP_ESCAPE_CHAR; + out->bv_val[out->bv_len++] = SLAP_ESCAPE_HI( in->bv_val[i] ); + out->bv_val[out->bv_len++] = SLAP_ESCAPE_LO( in->bv_val[i] ); + } else { + out->bv_val[out->bv_len++] = in->bv_val[i]; + } + } + + out->bv_val[out->bv_len] = '\0'; + return LDAP_SUCCESS; +} diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c index 712ff22e2e1751ede97126547147dc6d3c796776..af513e29c565ca7035d0529a0ca3db57d1ab9c12 100644 --- a/servers/slapd/filterentry.c +++ b/servers/slapd/filterentry.c @@ -1,37 +1,47 @@ /* filterentry.c - apply a filter to an entry */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#ifdef sunos5 -#include "regexpr.h" -#else -#include "regex.h" -#endif -#include "slap.h" -extern Attribute *attr_find(); -extern char *first_word(); -extern char *next_word(); -extern char *phonetic(); -extern char *re_comp(); +#include <ac/socket.h> +#include <ac/string.h> -#ifndef sunos5 -extern pthread_mutex_t regex_mutex; -#endif -static int test_filter_list(); -static int test_substring_filter(); -static int test_ava_filter(); -static int test_approx_filter(); -static int test_presence_filter(); +#include "slap.h" + +static int test_filter_and( Backend *be, + Connection *conn, Operation *op, + Entry *e, Filter *flist ); +static int test_filter_or( Backend *be, + Connection *conn, Operation *op, + Entry *e, Filter *flist ); +static int test_substrings_filter( Backend *be, + Connection *conn, Operation *op, + Entry *e, Filter *f); +static int test_ava_filter( Backend *be, + Connection *conn, Operation *op, + Entry *e, AttributeAssertion *ava, int type ); +static int test_mra_filter( Backend *be, + Connection *conn, Operation *op, + Entry *e, MatchingRuleAssertion *mra ); +static int test_presence_filter( Backend *be, + Connection *conn, Operation *op, + Entry *e, AttributeDescription *desc ); + /* * test_filter - test a filter against a single entry. - * returns 0 filter matched - * -1 filter did not match - * >0 an ldap error code + * returns: + * LDAP_COMPARE_TRUE filter matched + * LDAP_COMPARE_FALSE filter did not match + * SLAPD_COMPARE_UNDEFINED filter is undefined + * or an ldap result code indicating error */ int @@ -45,270 +55,413 @@ test_filter( { int rc; +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter: begin\n" )); +#else Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 ); +#endif + switch ( f->f_choice ) { + case SLAPD_FILTER_COMPUTED: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: COMPUTED %s (%d)\n", + f->f_result == LDAP_COMPARE_FALSE ? "false" : + f->f_result == LDAP_COMPARE_TRUE ? "true" : + f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : + "error", + f->f_result )); +#else + Debug( LDAP_DEBUG_FILTER, " COMPUTED %s (%d)\n", + f->f_result == LDAP_COMPARE_FALSE ? "false" : + f->f_result == LDAP_COMPARE_TRUE ? "true" : + f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error", + f->f_result, 0 ); +#endif + + rc = f->f_result; + break; + case LDAP_FILTER_EQUALITY: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: EQUALITY\n" )); +#else Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 ); - rc = test_ava_filter( be, conn, op, e, &f->f_ava, +#endif + + rc = test_ava_filter( be, conn, op, e, f->f_ava, LDAP_FILTER_EQUALITY ); break; case LDAP_FILTER_SUBSTRINGS: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter SUBSTRINGS\n" )); +#else Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 ); - rc = test_substring_filter( be, conn, op, e, f ); +#endif + + rc = test_substrings_filter( be, conn, op, e, f ); break; case LDAP_FILTER_GE: - Debug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 ); - rc = test_ava_filter( be, conn, op, e, &f->f_ava, + rc = test_ava_filter( be, conn, op, e, f->f_ava, LDAP_FILTER_GE ); break; case LDAP_FILTER_LE: - Debug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 ); - rc = test_ava_filter( be, conn, op, e, &f->f_ava, + rc = test_ava_filter( be, conn, op, e, f->f_ava, LDAP_FILTER_LE ); break; case LDAP_FILTER_PRESENT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: PRESENT\n" )); +#else Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 ); - rc = test_presence_filter( be, conn, op, e, f->f_type ); +#endif + + rc = test_presence_filter( be, conn, op, e, f->f_desc ); break; case LDAP_FILTER_APPROX: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: APPROX\n" )); +#else Debug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 ); - rc = test_approx_filter( be, conn, op, e, &f->f_ava ); +#endif + rc = test_ava_filter( be, conn, op, e, f->f_ava, + LDAP_FILTER_APPROX ); break; case LDAP_FILTER_AND: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: AND\n" )); +#else Debug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 ); - rc = test_filter_list( be, conn, op, e, f->f_and, - LDAP_FILTER_AND ); +#endif + + rc = test_filter_and( be, conn, op, e, f->f_and ); break; case LDAP_FILTER_OR: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: OR\n" )); +#else Debug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 ); - rc = test_filter_list( be, conn, op, e, f->f_or, - LDAP_FILTER_OR ); +#endif + + rc = test_filter_or( be, conn, op, e, f->f_or ); break; case LDAP_FILTER_NOT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: NOT\n" )); +#else Debug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 ); - rc = (! test_filter( be, conn, op, e, f->f_not ) ); +#endif + + rc = test_filter( be, conn, op, e, f->f_not ); + + /* Flip true to false and false to true + * but leave Undefined alone. + */ + switch( rc ) { + case LDAP_COMPARE_TRUE: + rc = LDAP_COMPARE_FALSE; + break; + case LDAP_COMPARE_FALSE: + rc = LDAP_COMPARE_TRUE; + break; + } + break; + + case LDAP_FILTER_EXT: +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1, + "test_filter: EXT\n" )); +#else + Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 ); +#endif + + rc = test_mra_filter( be, conn, op, e, f->f_mra ); break; default: - Debug( LDAP_DEBUG_ANY, " unknown filter type %d\n", +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_INFO, + "test_filter: unknown filter type %lu\n", + f->f_choice )); +#else + Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n", f->f_choice, 0, 0 ); - rc = -1; +#endif + + rc = LDAP_PROTOCOL_ERROR; } +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter: return=%d\n", rc )); +#else Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 ); +#endif + return( rc ); } +static int test_mra_filter( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + MatchingRuleAssertion *mra ) +{ + Attribute *a; + + if( !access_allowed( be, conn, op, e, + mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) ) + { + return LDAP_INSUFFICIENT_ACCESS; + } + + for(a = attrs_find( e->e_attrs, mra->ma_desc ); + a != NULL; + a = attrs_find( a->a_next, mra->ma_desc ) ) + { + struct berval *bv; + for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) { + int ret; + int rc; + const char *text; + + rc = value_match( &ret, a->a_desc, mra->ma_rule, + SLAP_MR_ASSERTION_SYNTAX_MATCH, + bv, &mra->ma_value, + &text ); + + if( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( ret == 0 ) { + return LDAP_COMPARE_TRUE; + } + } + } + + return LDAP_COMPARE_FALSE; +} + static int test_ava_filter( Backend *be, Connection *conn, Operation *op, Entry *e, - Ava *ava, + AttributeAssertion *ava, int type ) { - int i, rc; Attribute *a; - if ( be != NULL && ! access_allowed( be, conn, op, e, ava->ava_type, - &ava->ava_value, op->o_dn, ACL_SEARCH ) ) { - return( -2 ); + if ( !access_allowed( be, conn, op, e, + ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) ) + { + return LDAP_INSUFFICIENT_ACCESS; } - if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) { - return( -1 ); - } - - if ( a->a_syntax == 0 ) { - a->a_syntax = attr_syntax( ava->ava_type ); - } - for ( i = 0; a->a_vals[i] != NULL; i++ ) { - rc = value_cmp( a->a_vals[i], &ava->ava_value, a->a_syntax, - 3 ); + for(a = attrs_find( e->e_attrs, ava->aa_desc ); + a != NULL; + a = attrs_find( a->a_next, ava->aa_desc ) ) + { + MatchingRule *mr; + struct berval *bv; switch ( type ) { + case LDAP_FILTER_APPROX: + mr = a->a_desc->ad_type->sat_approx; + if( mr != NULL ) break; + + /* use EQUALITY matching rule if no APPROX rule */ + case LDAP_FILTER_EQUALITY: - if ( rc == 0 ) { - return( 0 ); - } + mr = a->a_desc->ad_type->sat_equality; break; case LDAP_FILTER_GE: - if ( rc > 0 ) { - return( 0 ); - } + case LDAP_FILTER_LE: + mr = a->a_desc->ad_type->sat_ordering; break; - case LDAP_FILTER_LE: - if ( rc < 0 ) { - return( 0 ); + default: + mr = NULL; + } + + if( mr == NULL ) { + continue; + } + + for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) { + int ret; + int rc; + const char *text; + + rc = value_match( &ret, a->a_desc, mr, + SLAP_MR_ASSERTION_SYNTAX_MATCH, + bv, &ava->aa_value, &text ); + + if( rc != LDAP_SUCCESS ) { + return rc; + } + + switch ( type ) { + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_APPROX: + if ( ret == 0 ) { + return LDAP_COMPARE_TRUE; + } + break; + + case LDAP_FILTER_GE: + if ( ret >= 0 ) { + return LDAP_COMPARE_TRUE; + } + break; + + case LDAP_FILTER_LE: + if ( ret <= 0 ) { + return LDAP_COMPARE_TRUE; + } + break; } - break; } } - return( 1 ); + return( LDAP_COMPARE_FALSE ); } + static int test_presence_filter( Backend *be, Connection *conn, Operation *op, Entry *e, - char *type + AttributeDescription *desc ) { - if ( be != NULL && ! access_allowed( be, conn, op, e, type, NULL, - op->o_dn, ACL_SEARCH ) ) { - return( -2 ); + if ( !access_allowed( be, conn, op, e, desc, NULL, ACL_SEARCH, NULL ) ) + { + return LDAP_INSUFFICIENT_ACCESS; } - return( attr_find( e->e_attrs, type ) != NULL ? 0 : -1 ); + return attrs_find( e->e_attrs, desc ) != NULL + ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; } + static int -test_approx_filter( +test_filter_and( Backend *be, Connection *conn, Operation *op, Entry *e, - Ava *ava + Filter *flist ) { - char *w1, *w2, *c1, *c2; - int i, rc, match; - Attribute *a; - - if ( be != NULL && ! access_allowed( be, conn, op, e, ava->ava_type, - NULL, op->o_dn, ACL_SEARCH ) ) { - return( -2 ); - } + Filter *f; + int rtn = LDAP_COMPARE_TRUE; /* True if empty */ - if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) { - return( -1 ); - } +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter_and: begin\n" )); +#else + Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 ); +#endif - /* for each value in the attribute */ - for ( i = 0; a->a_vals[i] != NULL; i++ ) { - /* - * try to match words in the filter value in order - * in the attribute value. - */ - w2 = a->a_vals[i]->bv_val; - /* for each word in the filter value */ - for ( w1 = first_word( ava->ava_value.bv_val ); w1 != NULL; - w1 = next_word( w1 ) ) { - if ( (c1 = phonetic( w1 )) == NULL ) { - break; - } + for ( f = flist; f != NULL; f = f->f_next ) { + int rc = test_filter( be, conn, op, e, f ); - /* - * for each word in the attribute value from - * where we left off... - */ - for ( w2 = first_word( w2 ); w2 != NULL; - w2 = next_word( w2 ) ) { - c2 = phonetic( w2 ); - if ( strcmp( c1, c2 ) == 0 ) { - break; - } - } - free( c1 ); - free( c2 ); - - /* - * if we stopped because we ran out of words - * before making a match, go on to the next - * value. otherwise try to keep matching - * words in this value from where we left off. - */ - if ( w2 == NULL ) { - break; - } else { - w2 = next_word( w2 ); - } + if ( rc == LDAP_COMPARE_FALSE ) { + /* filter is False */ + rtn = rc; + break; } - /* - * if we stopped because we ran out of words we - * have a match. - */ - if ( w1 == NULL ) { - return( 0 ); + + if ( rc != LDAP_COMPARE_TRUE ) { + /* filter is Undefined unless later elements are False */ + rtn = rc; } } - return( 1 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter_and: rc=%d\n", rtn )); +#else + Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 ); +#endif + + return rtn; } static int -test_filter_list( +test_filter_or( Backend *be, Connection *conn, Operation *op, Entry *e, - Filter *flist, - int ftype + Filter *flist ) { - int rc, nomatch; Filter *f; + int rtn = LDAP_COMPARE_FALSE; /* False if empty */ + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter_or: begin\n" )); +#else + Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_FILTER, "=> test_filter_list\n", 0, 0, 0 ); - nomatch = 1; for ( f = flist; f != NULL; f = f->f_next ) { - if ( test_filter( be, conn, op, e, f ) != 0 ) { - if ( ftype == LDAP_FILTER_AND ) { - Debug( LDAP_DEBUG_FILTER, - "<= test_filter_list 1\n", 0, 0, 0 ); - return( 1 ); - } - } else { - nomatch = 0; - } - } + int rc = test_filter( be, conn, op, e, f ); - Debug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 ); - return( nomatch ); -} + if ( rc == LDAP_COMPARE_TRUE ) { + /* filter is True */ + rtn = rc; + break; + } -static void -strcpy_special( char *d, char *s ) -{ - for ( ; *s; s++ ) { - switch ( *s ) { - case '.': - case '\\': - case '[': - case ']': - case '*': - case '+': - case '^': - case '$': - *d++ = '\\'; - /* FALL */ - default: - *d++ = *s; + if ( rc != LDAP_COMPARE_FALSE ) { + /* filter is Undefined unless later elements are True */ + rtn = rc; } } - *d = '\0'; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_filter_or: result=%d\n", rtn )); +#else + Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 ); +#endif + + return rtn; } + static int -test_substring_filter( +test_substrings_filter( Backend *be, Connection *conn, Operation *op, @@ -317,130 +470,57 @@ test_substring_filter( ) { Attribute *a; - int i, rc; - char *p, *end, *realval, *tmp; - char pat[BUFSIZ]; - char buf[BUFSIZ]; - struct berval *val; - Debug( LDAP_DEBUG_FILTER, "begin test_substring_filter\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_substrings_filter: begin\n" )); +#else + Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 ); +#endif - if ( be != NULL && ! access_allowed( be, conn, op, e, f->f_sub_type, - NULL, op->o_dn, ACL_SEARCH ) ) { - return( -2 ); - } - if ( (a = attr_find( e->e_attrs, f->f_sub_type )) == NULL ) { - return( -1 ); + if ( !access_allowed( be, conn, op, e, + f->f_sub_desc, NULL, ACL_SEARCH, NULL ) ) + { + return LDAP_INSUFFICIENT_ACCESS; } - if ( a->a_syntax & SYNTAX_BIN ) { - Debug( LDAP_DEBUG_FILTER, "test_substring_filter bin attr\n", - 0, 0, 0 ); - return( -1 ); - } + for(a = attrs_find( e->e_attrs, f->f_sub_desc ); + a != NULL; + a = attrs_find( a->a_next, f->f_sub_desc ) ) + { + MatchingRule *mr = a->a_desc->ad_type->sat_substr; + struct berval *bv; - /* - * construct a regular expression corresponding to the - * filter and let regex do the work - */ - - pat[0] = '\0'; - p = pat; - end = pat + sizeof(pat) - 2; /* leave room for null */ - if ( f->f_sub_initial != NULL ) { - strcpy( p, "^" ); - p = strchr( p, '\0' ); - /* 2 * in case every char is special */ - if ( p + 2 * strlen( f->f_sub_initial ) > end ) { - Debug( LDAP_DEBUG_ANY, "not enough pattern space\n", - 0, 0, 0 ); - return( -1 ); - } - strcpy_special( p, f->f_sub_initial ); - p = strchr( p, '\0' ); - } - if ( f->f_sub_any != NULL ) { - for ( i = 0; f->f_sub_any[i] != NULL; i++ ) { - /* ".*" + value */ - if ( p + 2 * strlen( f->f_sub_any[i] ) + 2 > end ) { - Debug( LDAP_DEBUG_ANY, - "not enough pattern space\n", 0, 0, 0 ); - return( -1 ); - } - strcpy( p, ".*" ); - p = strchr( p, '\0' ); - strcpy_special( p, f->f_sub_any[i] ); - p = strchr( p, '\0' ); + if( mr == NULL ) { + continue; } - } - if ( f->f_sub_final != NULL ) { - /* ".*" + value */ - if ( p + 2 * strlen( f->f_sub_final ) + 2 > end ) { - Debug( LDAP_DEBUG_ANY, "not enough pattern space\n", - 0, 0, 0 ); - return( -1 ); - } - strcpy( p, ".*" ); - p = strchr( p, '\0' ); - strcpy_special( p, f->f_sub_final ); - p = strchr( p, '\0' ); - strcpy( p, "$" ); - } - /* compile the regex */ -#ifdef sunos5 - if ( (p = compile( pat, NULL, NULL )) == NULL ) { - Debug( LDAP_DEBUG_ANY, "compile failed (%s)\n", p, 0, 0 ); - return( -1 ); - } -#else /* sunos5 */ - pthread_mutex_lock( ®ex_mutex ); - if ( (p = re_comp( pat )) != 0 ) { - Debug( LDAP_DEBUG_ANY, "re_comp failed (%s)\n", p, 0, 0 ); - pthread_mutex_unlock( ®ex_mutex ); - return( -1 ); - } -#endif /* sunos5 */ - - /* for each value in the attribute see if regex matches */ - for ( i = 0; a->a_vals[i] != NULL; i++ ) { - val = a->a_vals[i]; - tmp = NULL; - if ( val->bv_len < sizeof(buf) ) { - strcpy( buf, val->bv_val ); - realval = buf; - } else { - tmp = (char *) ch_malloc( val->bv_len + 1 ); - strcpy( tmp, val->bv_val ); - realval = tmp; - } - value_normalize( realval, a->a_syntax ); + for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) { + int ret; + int rc; + const char *text; -#ifdef sunos5 - rc = step( realval, p ); -#else /* sunos5 */ - rc = re_exec( realval ); -#endif /* sunos5 */ + rc = value_match( &ret, a->a_desc, mr, + SLAP_MR_ASSERTION_SYNTAX_MATCH, + bv, f->f_sub, &text ); - if ( tmp != NULL ) { - free( tmp ); - } - if ( rc == 1 ) { -#ifdef sunos5 - free( p ); -#else /* sunos5 */ - pthread_mutex_unlock( ®ex_mutex ); -#endif /* sunos5 */ - return( 0 ); + if( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( ret == 0 ) { + return LDAP_COMPARE_TRUE; + } } } -#ifdef sunos5 - free( p ); -#else /* sunos5 */ - pthread_mutex_unlock( ®ex_mutex ); -#endif /* sunos5 */ - - Debug( LDAP_DEBUG_FILTER, "end test_substring_filter 1\n", 0, 0, 0 ); - return( 1 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "test_substrings_filter: return FALSE\n" )); +#else + Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter 1\n", 0, 0, 0 ); +#endif + + return LDAP_COMPARE_FALSE; } diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 03dd850f0e86c8e92e6fa4371741334114c32e9f..c96040e39238a078aa15826e4bc684b6a4e67ec3 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -1,37 +1,220 @@ /* init.c - initialize various things */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ -#include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> #include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include "slap.h" -extern pthread_mutex_t active_threads_mutex; -extern pthread_mutex_t new_conn_mutex; -extern pthread_mutex_t currenttime_mutex; -extern pthread_mutex_t entry2str_mutex; -extern pthread_mutex_t replog_mutex; -extern pthread_mutex_t ops_mutex; -extern pthread_mutex_t num_sent_mutex; -#ifndef sunos5 -extern pthread_mutex_t regex_mutex; +/* + * read-only global variables or variables only written by the listener + * thread (after they are initialized) - no need to protect them with a mutex. + */ +int slap_debug = 0; + +#ifdef LDAP_DEBUG +int ldap_syslog = LDAP_DEBUG_STATS; +#else +int ldap_syslog; +#endif + +#ifdef LOG_DEBUG +int ldap_syslog_level = LOG_DEBUG; #endif -init() +BerVarray default_referral = NULL; + +/* + * global variables that need mutex protection + */ +ldap_pvt_thread_pool_t connection_pool; +int connection_pool_max = SLAP_MAX_WORKER_THREADS; +ldap_pvt_thread_mutex_t gmtime_mutex; +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) +ldap_pvt_thread_mutex_t passwd_mutex; +#endif + +unsigned long num_ops_initiated = 0; +unsigned long num_ops_completed = 0; +#ifdef SLAPD_MONITOR +unsigned long num_ops_initiated_[SLAP_OP_LAST]; +unsigned long num_ops_completed_[SLAP_OP_LAST]; +#endif /* SLAPD_MONITOR */ +ldap_pvt_thread_mutex_t num_ops_mutex; + +unsigned long num_entries_sent; +unsigned long num_refs_sent; +unsigned long num_bytes_sent; +unsigned long num_pdu_sent; +ldap_pvt_thread_mutex_t num_sent_mutex; +/* + * these mutexes must be used when calling the entry2str() + * routine since it returns a pointer to static data. + */ +ldap_pvt_thread_mutex_t entry2str_mutex; +ldap_pvt_thread_mutex_t replog_mutex; + +static const char* slap_name = NULL; +int slapMode = SLAP_UNDEFINED_MODE; + +int +slap_init( int mode, const char *name ) { - pthread_mutex_init( &active_threads_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &new_conn_mutex, pthread_mutexattr_default ); - pthread_mutex_init( ¤ttime_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &entry2str_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &replog_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &ops_mutex, pthread_mutexattr_default ); - pthread_mutex_init( &num_sent_mutex, pthread_mutexattr_default ); -#ifndef sunos5 - pthread_mutex_init( ®ex_mutex, pthread_mutexattr_default ); + int rc; + + assert( mode ); + + if( slapMode != SLAP_UNDEFINED_MODE ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "init: %s init called twice (old=%d, new=%d)\n", + name, slapMode, mode )); +#else + Debug( LDAP_DEBUG_ANY, + "%s init: init called twice (old=%d, new=%d)\n", + name, slapMode, mode ); #endif + + return 1; + } + + slapMode = mode; + + switch ( slapMode & SLAP_MODE ) { + case SLAP_SERVER_MODE: + case SLAP_TOOL_MODE: +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_DETAIL1, + "init: %s initiation, initiated %s.\n", + name, (mode & SLAP_MODE) == SLAP_TOOL_MODE ? "tool" : "server" )); +#else + Debug( LDAP_DEBUG_TRACE, + "%s init: initiated %s.\n", name, + (mode & SLAP_MODE) == SLAP_TOOL_MODE ? "tool" : "server", + 0 ); +#endif + + + slap_name = name; + + (void) ldap_pvt_thread_initialize(); + + ldap_pvt_thread_pool_init(&connection_pool, connection_pool_max, 0); + + ldap_pvt_thread_mutex_init( &entry2str_mutex ); + ldap_pvt_thread_mutex_init( &replog_mutex ); + ldap_pvt_thread_mutex_init( &num_ops_mutex ); + ldap_pvt_thread_mutex_init( &num_sent_mutex ); + +#ifdef SLAPD_MONITOR + { + int i; + for ( i = 0; i < SLAP_OP_LAST; i++ ) { + num_ops_initiated_[ i ] = 0; + num_ops_completed_[ i ] = 0; + } + } +#endif + + ldap_pvt_thread_mutex_init( &gmtime_mutex ); +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) + ldap_pvt_thread_mutex_init( &passwd_mutex ); +#endif + + rc = slap_sasl_init(); + + if( rc == 0 ) { + rc = backend_init( ); + } + break; + + default: +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "init: %s init, undefined mode (%d).\n", name, mode )); +#else + Debug( LDAP_DEBUG_ANY, + "%s init: undefined mode (%d).\n", name, mode, 0 ); +#endif + + rc = 1; + break; + } + + return rc; +} + +int slap_startup( Backend *be ) +{ + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "slap_startup: %s started\n", slap_name )); +#else + Debug( LDAP_DEBUG_TRACE, + "%s startup: initiated.\n", + slap_name, 0, 0 ); +#endif + + + rc = backend_startup( be ); + + return rc; +} + +int slap_shutdown( Backend *be ) +{ + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "slap_shutdown: %s shutdown initiated.\n", slap_name)); +#else + Debug( LDAP_DEBUG_TRACE, + "%s shutdown: initiated\n", + slap_name, 0, 0 ); +#endif + + + slap_sasl_destroy(); + + /* let backends do whatever cleanup they need to do */ + rc = backend_shutdown( be ); + + return rc; +} + +int slap_destroy(void) +{ + int rc; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "slap_destroy: %s freeing system resources.\n", + slap_name )); +#else + Debug( LDAP_DEBUG_TRACE, + "%s shutdown: freeing system resources.\n", + slap_name, 0, 0 ); +#endif + + + rc = backend_destroy(); + + entry_destroy(); + + ldap_pvt_thread_destroy(); + + /* should destory the above mutex */ + return rc; } diff --git a/servers/slapd/limits.c b/servers/slapd/limits.c new file mode 100644 index 0000000000000000000000000000000000000000..01011a7250aeb9ce02ef2a83a89510d231c6505e --- /dev/null +++ b/servers/slapd/limits.c @@ -0,0 +1,484 @@ +/* limits.c - routines to handle regex-based size and time limits */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/regex.h> +#include <ac/string.h> + +#include "slap.h" + +int +get_limits( + Backend *be, + struct berval *ndn, + struct slap_limits_set **limit +) +{ + struct slap_limits **lm; + + assert( be ); + assert( limit ); + + /* + * default values + */ + *limit = &be->be_def_limit; + + if ( be->be_limits == NULL ) { + return( 0 ); + } + + for ( lm = be->be_limits; lm[0] != NULL; lm++ ) { + switch ( lm[0]->lm_type ) { + case SLAP_LIMITS_EXACT: + if ( ndn->bv_len == 0 ) { + break; + } + if ( dn_match( &lm[0]->lm_dn_pat, ndn ) ) { + *limit = &lm[0]->lm_limits; + return( 0 ); + } + break; + + case SLAP_LIMITS_ONE: + case SLAP_LIMITS_SUBTREE: + case SLAP_LIMITS_CHILDREN: { + size_t d; + + if ( ndn->bv_len == 0 ) { + break; + } + + /* ndn shorter than dn_pat */ + if ( ndn->bv_len < lm[0]->lm_dn_pat.bv_len ) { + break; + } + d = ndn->bv_len - lm[0]->lm_dn_pat.bv_len; + + /* allow exact match for SUBTREE only */ + if ( d == 0 ) { + if ( lm[0]->lm_type != SLAP_LIMITS_SUBTREE ) { + break; + } + } else { + /* check for unescaped rdn separator */ + if ( !DN_SEPARATOR( ndn->bv_val[d-1] ) ) { + break; + } + } + + /* in case of (sub)match ... */ + if ( lm[0]->lm_dn_pat.bv_len == ( ndn->bv_len - d ) + && strcmp( lm[0]->lm_dn_pat.bv_val, &ndn->bv_val[d] ) == 0 ) { + /* check for exactly one rdn in case of ONE */ + if ( lm[0]->lm_type == SLAP_LIMITS_ONE ) { + /* + * if ndn is more that one rdn + * below dn_pat, continue + */ + if ( (size_t) dn_rdnlen( NULL, ndn ) != d - 1 ) { + break; + } + } + + *limit = &lm[0]->lm_limits; + return( 0 ); + } + + break; + } + + case SLAP_LIMITS_REGEX: + if ( ndn->bv_len == 0 ) { + break; + } + if ( regexec( &lm[0]->lm_dn_regex, ndn->bv_val, 0, NULL, 0 ) + == 0 ) + { + *limit = &lm[0]->lm_limits; + return( 0 ); + } + break; + + case SLAP_LIMITS_ANONYMOUS: + if ( ndn->bv_len == 0 ) { + *limit = &lm[0]->lm_limits; + return( 0 ); + } + break; + + case SLAP_LIMITS_USERS: + if ( ndn->bv_len != 0 ) { + *limit = &lm[0]->lm_limits; + return( 0 ); + } + break; + + default: + assert( 0 ); /* unreachable */ + return( -1 ); + } + } + + return( 0 ); +} + +static int +add_limits( + Backend *be, + int type, + const char *pattern, + struct slap_limits_set *limit +) +{ + int i; + struct slap_limits *lm; + + assert( be ); + assert( limit ); + + lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 ); + + switch ( type ) { + case SLAP_LIMITS_EXACT: + case SLAP_LIMITS_ONE: + case SLAP_LIMITS_SUBTREE: + case SLAP_LIMITS_CHILDREN: + lm->lm_type = type; + { + int rc; + struct berval bv; + bv.bv_val = (char *) pattern; + bv.bv_len = strlen( pattern ); + + rc = dnNormalize2( NULL, &bv, &lm->lm_dn_pat ); + if ( rc != LDAP_SUCCESS ) { + ch_free( lm ); + return( -1 ); + } + } + break; + + case SLAP_LIMITS_REGEX: + case SLAP_LIMITS_UNDEFINED: + lm->lm_type = SLAP_LIMITS_REGEX; + ber_str2bv( pattern, 0, 1, &lm->lm_dn_pat ); + if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat.bv_val, + REG_EXTENDED | REG_ICASE ) ) { + free( lm->lm_dn_pat.bv_val ); + ch_free( lm ); + return( -1 ); + } + break; + + case SLAP_LIMITS_ANONYMOUS: + case SLAP_LIMITS_USERS: + lm->lm_type = type; + lm->lm_dn_pat.bv_val = NULL; + lm->lm_dn_pat.bv_len = 0; + break; + } + + lm->lm_limits = *limit; + + i = 0; + if ( be->be_limits != NULL ) { + for ( ; be->be_limits[i]; i++ ); + } + + be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits, + sizeof( struct slap_limits * ) * ( i + 2 ) ); + be->be_limits[i] = lm; + be->be_limits[i+1] = NULL; + + return( 0 ); +} + +int +parse_limits( + Backend *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + int type = SLAP_LIMITS_UNDEFINED; + char *pattern; + struct slap_limits_set limit; + int i; + + assert( be ); + + if ( argc < 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s : line %d: missing arg(s) in " + "\"limits <pattern> <limits>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s : line %d: missing arg(s) in " + "\"limits <pattern> <limits>\" line.\n%s", + fname, lineno, "" ); +#endif + return( -1 ); + } + + limit = be->be_def_limit; + + /* + * syntax: + * + * "limits" <pattern> <limit> [ ... ] + * + * + * <pattern>: + * + * "anonymous" + * "users" + * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" + * | "regex" | "anonymous" } ] "=" ] <dn pattern> + * + * Note: + * "exact" and "base" are the same (exact match); + * "one" means exactly one rdn below, NOT including the pattern + * "sub" means any rdn below, including the pattern + * "children" means any rdn below, NOT including the pattern + * + * "anonymous" may be deprecated in favour + * of the pattern = "anonymous" form + * + * + * <limit>: + * + * "time" [ "." { "soft" | "hard" } ] "=" <integer> + * + * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer> + */ + + pattern = argv[1]; + if ( strcasecmp( pattern, "anonymous" ) == 0 ) { + type = SLAP_LIMITS_ANONYMOUS; + + } else if ( strcasecmp( pattern, "users" ) == 0 ) { + type = SLAP_LIMITS_USERS; + + } else if ( strncasecmp( pattern, "dn", 2 ) == 0 ) { + pattern += 2; + if ( pattern[0] == '.' ) { + pattern++; + if ( strncasecmp( pattern, "exact", 5 ) == 0 ) { + type = SLAP_LIMITS_EXACT; + pattern += 5; + + } else if ( strncasecmp( pattern, "base", 4 ) == 0 ) { + type = SLAP_LIMITS_BASE; + pattern += 4; + + } else if ( strncasecmp( pattern, "one", 3 ) == 0 ) { + type = SLAP_LIMITS_ONE; + pattern += 3; + + } else if ( strncasecmp( pattern, "subtree", 7 ) == 0 ) { + type = SLAP_LIMITS_SUBTREE; + pattern += 7; + + } else if ( strncasecmp( pattern, "children", 8 ) == 0 ) { + type = SLAP_LIMITS_CHILDREN; + pattern += 8; + + } else if ( strncasecmp( pattern, "regex", 5 ) == 0 ) { + type = SLAP_LIMITS_REGEX; + pattern += 5; + + /* + * this could be deprecated in favour + * of the pattern = "anonymous" form + */ + } else if ( strncasecmp( pattern, "anonymous", 9 ) == 0 ) { + type = SLAP_LIMITS_ANONYMOUS; + pattern = NULL; + } + } + + /* pre-check the data */ + switch ( type ) { + case SLAP_LIMITS_ANONYMOUS: + case SLAP_LIMITS_USERS: + + /* no need for pattern */ + pattern = NULL; + break; + + default: + if ( pattern[0] != '=' ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s : line %d: missing '=' in " + "\"dn[.{exact|base|one|subtree" + "|children|regex|anonymous}]" + "=<pattern>\" in " + "\"limits <pattern> <limits>\" line.\n", + fname, lineno )); +#else + Debug( LDAP_DEBUG_ANY, + "%s : line %d: missing '=' in " + "\"dn[.{exact|base|one|subtree" + "|children|regex|anonymous}]" + "=<pattern>\" in " + "\"limits <pattern> <limits>\" " + "line.\n%s", + fname, lineno, "" ); +#endif + return( -1 ); + } + + /* skip '=' (required) */ + pattern++; + } + } + + /* get the limits */ + for ( i = 2; i < argc; i++ ) { + if ( parse_limit( argv[i], &limit ) ) { + +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "%s : line %d: unknown limit type \"%s\" in " + "\"limits <pattern> <limits>\" line.\n", + fname, lineno, argv[i] )); +#else + Debug( LDAP_DEBUG_ANY, + "%s : line %d: unknown limit type \"%s\" in " + "\"limits <pattern> <limits>\" line.\n", + fname, lineno, argv[i] ); +#endif + + return( 1 ); + } + } + + /* + * sanity checks ... + */ + if ( limit.lms_t_hard > 0 && limit.lms_t_hard < limit.lms_t_soft ) { + limit.lms_t_hard = limit.lms_t_soft; + } + + if ( limit.lms_s_hard > 0 && limit.lms_s_hard < limit.lms_s_soft ) { + limit.lms_s_hard = limit.lms_s_soft; + } + + return( add_limits( be, type, pattern, &limit ) ); +} + +int +parse_limit( + const char *arg, + struct slap_limits_set *limit +) +{ + assert( arg ); + assert( limit ); + + if ( strncasecmp( arg, "time", 4 ) == 0 ) { + arg += 4; + + if ( arg[0] == '.' ) { + arg++; + if ( strncasecmp( arg, "soft", 4 ) == 0 ) { + arg += 4; + if ( arg[0] != '=' ) { + return( 1 ); + } + arg++; + limit->lms_t_soft = atoi( arg ); + + } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) { + arg += 4; + if ( arg[0] != '=' ) { + return( 1 ); + } + arg++; + if ( strcasecmp( arg, "soft" ) == 0 ) { + limit->lms_t_hard = 0; + } else if ( strcasecmp( arg, "none" ) == 0 ) { + limit->lms_t_hard = -1; + } else { + limit->lms_t_hard = atoi( arg ); + } + + } else { + return( 1 ); + } + + } else if ( arg[0] == '=' ) { + limit->lms_t_soft = atoi( arg ); + limit->lms_t_hard = 0; + + } else { + return( 1 ); + } + + } else if ( strncasecmp( arg, "size", 4 ) == 0 ) { + arg += 4; + + if ( arg[0] == '.' ) { + arg++; + if ( strncasecmp( arg, "soft", 4 ) == 0 ) { + arg += 4; + if ( arg[0] != '=' ) { + return( 1 ); + } + arg++; + limit->lms_s_soft = atoi( arg ); + + } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) { + arg += 4; + if ( arg[0] != '=' ) { + return( 1 ); + } + arg++; + if ( strcasecmp( arg, "soft" ) == 0 ) { + limit->lms_s_hard = 0; + } else if ( strcasecmp( arg, "none" ) == 0 ) { + limit->lms_s_hard = -1; + } else { + limit->lms_s_hard = atoi( arg ); + } + + } else if ( strncasecmp( arg, "unchecked", 9 ) == 0 ) { + arg += 9; + if ( arg[0] != '=' ) { + return( 1 ); + } + arg++; + if ( strcasecmp( arg, "none" ) == 0 ) { + limit->lms_s_unchecked = -1; + } else { + limit->lms_s_unchecked = atoi( arg ); + } + + } else { + return( 1 ); + } + + } else if ( arg[0] == '=' ) { + limit->lms_s_soft = atoi( arg ); + limit->lms_s_hard = 0; + + } else { + return( 1 ); + } + } + + return 0; +} + diff --git a/servers/slapd/main.c b/servers/slapd/main.c index 01930b970910c9c1ad6cd9a8bf6939af58baed05..fa1bb4916d5b4800840461b1dd2c214628f4278b 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -1,273 +1,625 @@ -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ #include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> +#include <ac/unistd.h> +#include <ac/wait.h> +#include <ac/errno.h> + +#include "ldap_pvt.h" + #include "slap.h" -#include "ldapconfig.h" +#include "lutil.h" +#include "ldif.h" -extern void daemon(); -extern int lber_debug; +#ifdef LDAP_SIGCHLD +static RETSIGTYPE wait4child( int sig ); +#endif -extern char Versionstr[]; +#ifdef HAVE_NT_SERVICE_MANAGER +#define MAIN_RETURN(x) return +static struct sockaddr_in bind_addr; + +void CommenceStartupProcessing( LPCTSTR serverName, + void(*stopper)(int)); +void ReportSlapdShutdownComplete( void ); +void *getRegParam( char *svc, char *value ); + +#define SERVICE_EXIT( e, n ) do { \ + if ( is_NT_Service ) { \ + SLAPDServiceStatus.dwWin32ExitCode = (e); \ + SLAPDServiceStatus.dwServiceSpecificExitCode = (n); \ + } \ +} while ( 0 ) -/* - * read-only global variables or variables only written by the listener - * thread (after they are initialized) - no need to protect them with a mutex. - */ -int ldap_debug; -#ifdef LDAP_DEBUG -int ldap_syslog = LDAP_DEBUG_STATS; #else -int ldap_syslog; -#endif -int ldap_syslog_level = LOG_DEBUG; -int udp; -int slapd_shutdown; -char *default_referral; -char *configfile; -time_t starttime; -pthread_t listener_tid; -int g_argc; -char **g_argv; -/* - * global variables that need mutex protection - */ -time_t currenttime; -pthread_mutex_t currenttime_mutex; -int active_threads; -pthread_mutex_t active_threads_mutex; -pthread_mutex_t new_conn_mutex; -long ops_initiated; -long ops_completed; -int num_conns; -pthread_mutex_t ops_mutex; -long num_entries_sent; -long num_bytes_sent; -pthread_mutex_t num_sent_mutex; +#define SERVICE_EXIT( e, n ) +#define MAIN_RETURN(x) return(x) +#endif + +#ifdef HAVE_NT_EVENT_LOG +void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, char *urls ); +void LogSlapdStoppedEvent( char *svc ); +#endif + /* - * these mutexes must be used when calling the entry2str() - * routine since it returns a pointer to static data. + * when more than one slapd is running on one machine, each one might have + * it's own LOCAL for syslogging and must have its own pid/args files */ -pthread_mutex_t entry2str_mutex; -pthread_mutex_t replog_mutex; -#ifndef sunos5 -pthread_mutex_t regex_mutex; + +#ifndef HAVE_MKVERSION +const char Versionstr[] = + OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)"; #endif -static -usage( name ) - char *name; +#ifdef LOG_LOCAL4 + +#define DEFAULT_SYSLOG_USER LOG_LOCAL4 + +typedef struct _str2intDispatch { + char *stringVal; + int abbr; + int intVal; +} STRDISP, *STRDISP_P; + + +/* table to compute syslog-options to integer */ +static STRDISP syslog_types[] = { + { "LOCAL0", sizeof("LOCAL0"), LOG_LOCAL0 }, + { "LOCAL1", sizeof("LOCAL1"), LOG_LOCAL1 }, + { "LOCAL2", sizeof("LOCAL2"), LOG_LOCAL2 }, + { "LOCAL3", sizeof("LOCAL3"), LOG_LOCAL3 }, + { "LOCAL4", sizeof("LOCAL4"), LOG_LOCAL4 }, + { "LOCAL5", sizeof("LOCAL5"), LOG_LOCAL5 }, + { "LOCAL6", sizeof("LOCAL6"), LOG_LOCAL6 }, + { "LOCAL7", sizeof("LOCAL7"), LOG_LOCAL7 }, + { NULL } +}; + +static int cnvt_str2int( char *, STRDISP_P, int ); + +#endif /* LOG_LOCAL4 */ + + +static void +usage( char *name ) { - fprintf( stderr, "usage: %s [-d debuglevel] [-f configfile] [-p portnumber] [-s sysloglevel]\n", name ); + fprintf( stderr, + "usage: %s options\n", name ); + fprintf( stderr, + "\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" +#ifdef LOG_LOCAL4 + "\t-l sysloguser\tSyslog User (default: LOCAL4)\n" +#endif + "\t-n serverName\tservice name\n" +#ifdef HAVE_CHROOT + "\t-r directory\n" +#endif + "\t-s level\tSyslog Level\n" +#if defined(HAVE_SETUID) && defined(HAVE_SETGID) + "\t-u user\tUser (id or name) to run as\n" +#endif + ); } -main( argc, argv ) - int argc; - char **argv; +#ifdef HAVE_NT_SERVICE_MANAGER +void WINAPI ServiceMain( DWORD argc, LPTSTR *argv ) +#else +int main( int argc, char **argv ) +#endif { - int i; - int inetd = 0; - int port; - char *myname; - Backend *be = NULL; - FILE *fp = NULL; - extern char *optarg; - - configfile = SLAPD_DEFAULT_CONFIGFILE; - port = LDAP_PORT; - g_argc = argc; - g_argv = argv; - - while ( (i = getopt( argc, argv, "d:f:ip:s:u" )) != EOF ) { + int i, no_detach = 0; + int rc = 1; + char *urls = NULL; +#if defined(HAVE_SETUID) && defined(HAVE_SETGID) + char *username = NULL; + char *groupname = NULL; +#endif +#if defined(HAVE_CHROOT) + char *sandbox = NULL; +#endif +#ifdef LOG_LOCAL4 + int syslogUser = DEFAULT_SYSLOG_USER; +#endif + + int g_argc = argc; + char **g_argv = argv; + +#ifdef HAVE_NT_SERVICE_MANAGER + char *configfile = ".\\slapd.conf"; +#else + char *configfile = SLAPD_DEFAULT_CONFIGFILE; +#endif + char *serverName = NULL; + int serverMode = SLAP_SERVER_MODE; + +#ifdef CSRIMALLOC + FILE *leakfile; + if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) { + leakfile = stderr; + } +#endif + + +#ifdef HAVE_NT_SERVICE_MANAGER + { + int *i; + char *newConfigFile; + char *newUrls; + char *regService = NULL; + + if ( is_NT_Service ) { + serverName = argv[0]; + CommenceStartupProcessing( serverName, slap_sig_shutdown ); + if ( strcmp(serverName, SERVICE_NAME) ) + regService = serverName; + } + + i = (int*)getRegParam( regService, "DebugLevel" ); + if ( i != NULL ) + { + slap_debug = *i; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "main: new debug level from registry is: %d\n", slap_debug )); +#else + Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", slap_debug, 0, 0 ); +#endif + } + + newUrls = (char *) getRegParam(regService, "Urls"); + if (newUrls) + { + if (urls) + ch_free(urls); + + urls = ch_strdup(newUrls); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "main: new urls from registry: %s\n", urls )); +#else + Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n", + urls, 0, 0); +#endif + + } + + newConfigFile = (char*)getRegParam( regService, "ConfigFile" ); + if ( newConfigFile != NULL ) + { + configfile = newConfigFile; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "main: new config file from registry is: %s\n", configfile )); +#else + Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 ); +#endif + + } + } +#endif + + while ( (i = getopt( argc, argv, + "d:f:h:s:n:" +#ifdef HAVE_CHROOT + "r:" +#endif +#ifdef LOG_LOCAL4 + "l:" +#endif +#if defined(HAVE_SETUID) && defined(HAVE_SETGID) + "u:g:" +#endif + )) != EOF ) { switch ( i ) { + case 'h': /* listen URLs */ + if ( urls != NULL ) free( urls ); + urls = ch_strdup( optarg ); + break; + + case 'd': /* set debug level and 'do not detach' flag */ + no_detach = 1; #ifdef LDAP_DEBUG - case 'd': /* turn on debugging */ - if ( optarg[0] == '?' ) { - printf( "Debug levels:\n" ); - printf( "\tLDAP_DEBUG_TRACE\t%d\n", - LDAP_DEBUG_TRACE ); - printf( "\tLDAP_DEBUG_PACKETS\t%d\n", - LDAP_DEBUG_PACKETS ); - printf( "\tLDAP_DEBUG_ARGS\t\t%d\n", - LDAP_DEBUG_ARGS ); - printf( "\tLDAP_DEBUG_CONNS\t%d\n", - LDAP_DEBUG_CONNS ); - printf( "\tLDAP_DEBUG_BER\t\t%d\n", - LDAP_DEBUG_BER ); - printf( "\tLDAP_DEBUG_FILTER\t%d\n", - LDAP_DEBUG_FILTER ); - printf( "\tLDAP_DEBUG_CONFIG\t%d\n", - LDAP_DEBUG_CONFIG ); - printf( "\tLDAP_DEBUG_ACL\t\t%d\n", - LDAP_DEBUG_ACL ); - printf( "\tLDAP_DEBUG_STATS\t\t%d\n", - LDAP_DEBUG_STATS ); - printf( "\tLDAP_DEBUG_STATS2\t\t%d\n", - LDAP_DEBUG_STATS2 ); - printf( "\tLDAP_DEBUG_SHELL\t\t%d\n", - LDAP_DEBUG_SHELL ); - printf( "\tLDAP_DEBUG_PARSE\t\t%d\n", - LDAP_DEBUG_PARSE ); - printf( "\tLDAP_DEBUG_ANY\t\t%d\n", - LDAP_DEBUG_ANY ); - exit( 0 ); - } else { - ldap_debug = atoi( optarg ); - lber_debug = (ldap_debug & LDAP_DEBUG_BER); - } - break; + slap_debug |= atoi( optarg ); #else - case 'd': /* turn on debugging */ - fprintf( stderr, - "must compile with LDAP_DEBUG for debugging\n" ); - break; + if ( atoi( optarg ) != 0 ) + fputs( "must compile with LDAP_DEBUG for debugging\n", + stderr ); #endif + break; case 'f': /* read config file */ - configfile = strdup( optarg ); + configfile = ch_strdup( optarg ); break; - case 'i': /* run from inetd */ - inetd = 1; + case 's': /* set syslog level */ + ldap_syslog = atoi( optarg ); break; - case 'p': /* port on which to listen */ - port = atoi( optarg ); +#ifdef LOG_LOCAL4 + case 'l': /* set syslog local user */ + syslogUser = cnvt_str2int( optarg, + syslog_types, DEFAULT_SYSLOG_USER ); break; +#endif - case 's': /* set syslog level */ - ldap_syslog = atoi( optarg ); +#ifdef HAVE_CHROOT + case 'r': + if( sandbox ) free(sandbox); + sandbox = ch_strdup( optarg ); break; +#endif - case 'u': /* do udp */ - udp = 1; +#if defined(HAVE_SETUID) && defined(HAVE_SETGID) + case 'u': /* user name */ + if( username ) free(username); + username = ch_strdup( optarg ); + break; + + case 'g': /* group name */ + if( groupname ) free(groupname); + groupname = ch_strdup( optarg ); + break; +#endif /* SETUID && GETUID */ + + case 'n': /* NT service name */ + if( serverName != NULL ) free( serverName ); + serverName = ch_strdup( optarg ); break; default: usage( argv[0] ); - exit( 1 ); + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 ); + goto stop; } } +#ifdef NEW_LOGGING + lutil_log_initialize( argc, argv ); +#endif + + lutil_set_debug_level( "slapd", slap_debug ); + ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug); + ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug); + ldif_debug = slap_debug; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "%s", Versionstr )); +#else Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 ); +#endif - if ( (myname = strrchr( argv[0], '/' )) == NULL ) { - myname = strdup( argv[0] ); - } else { - myname = strdup( myname + 1 ); - } - if ( ! inetd ) { - /* pre-open config file before detach in case it is a relative path */ - fp = fopen( configfile, "r" ); - detach(); + if( serverName == NULL ) { + if ( (serverName = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) { + serverName = argv[0]; + } else { + serverName = serverName + 1; + } } + #ifdef LOG_LOCAL4 - openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 ); + openlog( serverName, OPENLOG_OPTIONS, syslogUser ); +#elif LOG_DEBUG + openlog( serverName, OPENLOG_OPTIONS ); +#endif + + if( slapd_daemon_init( urls ) != 0 ) { + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 ); + goto stop; + } + +#if defined(HAVE_CHROOT) + if ( sandbox ) { + if ( chdir( sandbox ) ) { + perror("chdir"); + rc = 1; + goto stop; + } + if ( chroot( sandbox ) ) { + perror("chroot"); + rc = 1; + goto stop; + } + } +#endif + +#if defined(HAVE_SETUID) && defined(HAVE_SETGID) + if ( username != NULL || groupname != NULL ) { + slap_init_user( username, groupname ); + } +#endif + + extops_init(); + +#ifdef SLAPD_MODULES + if ( module_init() != 0 ) { + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 17 ); + goto destroy; + } +#endif + + if ( slap_init( serverMode, serverName ) != 0 ) { + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 ); + goto destroy; + } + + if ( slap_schema_init( ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: schema initialization error\n" )); #else - openlog( myname, OPENLOG_OPTIONS ); + Debug( LDAP_DEBUG_ANY, + "schema initialization error\n", + 0, 0, 0 ); #endif - init(); - read_config( configfile, &be, fp ); + goto destroy; + } - if ( ! inetd ) { - pthread_attr_t attr; - int status; + if ( read_config( configfile ) != 0 ) { + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 ); + goto destroy; + } - time( &starttime ); - pthread_attr_init( &attr ); - pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); + if ( glue_sub_init( ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: subordinate config error\n")); +#else + Debug( LDAP_DEBUG_ANY, + "subordinate config error\n", + 0, 0, 0 ); +#endif + goto destroy; + } - if ( pthread_create( &listener_tid, attr, (void *) daemon, - (void *) port ) != 0 ) { - Debug( LDAP_DEBUG_ANY, - "listener pthread_create failed\n", 0, 0, 0 ); - exit( 1 ); - } - pthread_attr_destroy( &attr ); - pthread_join( listener_tid, (void *) &status ); - pthread_exit( 0 ); - } else { - Connection c; - Operation *o; - BerElement ber; - unsigned long len, tag; - long msgid; - int flen; - struct sockaddr_in from; - struct hostent *hp; - - c.c_dn = NULL; - c.c_ops = NULL; - c.c_sb.sb_sd = 0; - c.c_sb.sb_options = 0; - c.c_sb.sb_naddr = udp ? 1 : 0; - c.c_sb.sb_ber.ber_buf = NULL; - c.c_sb.sb_ber.ber_ptr = NULL; - c.c_sb.sb_ber.ber_end = NULL; - pthread_mutex_init( &c.c_dnmutex, pthread_mutexattr_default ); - pthread_mutex_init( &c.c_opsmutex, pthread_mutexattr_default ); - pthread_mutex_init( &c.c_pdumutex, pthread_mutexattr_default ); -#ifdef notdefcldap - c.c_sb.sb_addrs = (void **) saddrlist; - c.c_sb.sb_fromaddr = &faddr; - c.c_sb.sb_useaddr = saddrlist[ 0 ] = &saddr; -#endif - flen = sizeof(from); - if ( getpeername( 0, (struct sockaddr *) &from, &flen ) == 0 ) { -#ifdef REVERSE_LOOKUP - hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr), - sizeof(from.sin_addr.s_addr), AF_INET ); + if ( slap_schema_check( ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: schema prep error\n")); #else - hp = NULL; + Debug( LDAP_DEBUG_ANY, + "schema prep error\n", + 0, 0, 0 ); #endif - Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n", - hp == NULL ? "unknown" : hp->h_name, - inet_ntoa( from.sin_addr ), 0 ); + goto destroy; + } - c.c_addr = inet_ntoa( from.sin_addr ); - c.c_domain = strdup( hp == NULL ? "" : hp->h_name ); - } else { - Debug( LDAP_DEBUG_ARGS, "connection from unknown\n", - 0, 0, 0 ); +#ifdef HAVE_TLS + rc = ldap_pvt_tls_init(); + if( rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: tls init failed: %d\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "main: TLS init failed: %d\n", + 0, 0, 0 ); +#endif + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); + goto destroy; + } + + rc = ldap_pvt_tls_init_def_ctx(); + if( rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: tls init def ctx failed: %d\n", rc )); +#else + Debug( LDAP_DEBUG_ANY, + "main: TLS init def ctx failed: %d\n", + 0, 0, 0 ); +#endif + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); + goto destroy; + } +#endif + + (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake ); + (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown ); + +#ifdef SIGPIPE + (void) SIGNAL( SIGPIPE, SIG_IGN ); +#endif +#ifdef SIGHUP + (void) SIGNAL( SIGHUP, slap_sig_shutdown ); +#endif + (void) SIGNAL( SIGINT, slap_sig_shutdown ); + (void) SIGNAL( SIGTERM, slap_sig_shutdown ); +#ifdef LDAP_SIGCHLD + (void) SIGNAL( LDAP_SIGCHLD, wait4child ); +#endif +#ifdef SIGBREAK + /* SIGBREAK is generated when Ctrl-Break is pressed. */ + (void) SIGNAL( SIGBREAK, slap_sig_shutdown ); +#endif + +#ifndef HAVE_WINSOCK + lutil_detach( no_detach, 0 ); +#endif /* HAVE_WINSOCK */ + +#ifdef CSRIMALLOC + mal_leaktrace(1); +#endif + + if ( slap_startup( NULL ) != 0 ) { + rc = 1; + SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 ); + goto shutdown; + } + + { + FILE *fp; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "main: slapd starting.\n" )); +#else + Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 ); +#endif + + + if (( slapd_pid_file != NULL ) && + (( fp = fopen( slapd_pid_file, "w" )) != NULL )) + { + fprintf( fp, "%d\n", (int) getpid() ); + fclose( fp ); } - ber_init( &ber, 0 ); - while ( (tag = ber_get_next( &c.c_sb, &len, &ber )) - == LDAP_TAG_MESSAGE ) { - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - pthread_mutex_unlock( ¤ttime_mutex ); - - if ( (tag = ber_get_int( &ber, &msgid )) - != LDAP_TAG_MSGID ) { - /* log and send error */ - Debug( LDAP_DEBUG_ANY, - "ber_get_int returns 0x%x\n", tag, 0, 0 ); - return; + if (( slapd_args_file != NULL ) && + (( fp = fopen( slapd_args_file, "w" )) != NULL )) + { + for ( i = 0; i < g_argc; i++ ) { + fprintf( fp, "%s ", g_argv[i] ); } + fprintf( fp, "\n" ); + fclose( fp ); + } + } - if ( (tag = ber_peek_tag( &ber, &len )) - == LBER_ERROR ) { - /* log, close and send error */ - Debug( LDAP_DEBUG_ANY, - "ber_peek_tag returns 0x%x\n", tag, 0, 0 ); - ber_free( &ber, 1 ); - close( c.c_sb.sb_sd ); - c.c_sb.sb_sd = -1; - return; - } +#ifdef HAVE_NT_EVENT_LOG + if (is_NT_Service) + LogSlapdStartedEvent( serverName, slap_debug, configfile, urls ); +#endif - connection_activity( &c ); + rc = slapd_daemon(); + +#ifdef HAVE_NT_SERVICE_MANAGER + /* Throw away the event that we used during the startup process. */ + if ( is_NT_Service ) + ldap_pvt_thread_cond_destroy( &started_event ); +#endif + +shutdown: + /* remember an error during shutdown */ + rc |= slap_shutdown( NULL ); + +destroy: + /* remember an error during destroy */ + rc |= slap_destroy(); + +#ifdef SLAPD_MODULES + module_kill(); +#endif + + extops_kill(); + +stop: +#ifdef HAVE_NT_EVENT_LOG + if (is_NT_Service) + LogSlapdStoppedEvent( serverName ); +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_CRIT, + "main: slapd stopped.\n" )); +#else + Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 ); +#endif + + +#ifdef HAVE_NT_SERVICE_MANAGER + ReportSlapdShutdownComplete(); +#endif + +#ifdef LOG_DEBUG + closelog(); +#endif + slapd_daemon_destroy(); + + schema_destroy(); + +#ifdef HAVE_TLS + ldap_pvt_tls_destroy(); +#endif + + config_destroy(); + +#ifdef CSRIMALLOC + mal_dumpleaktrace( leakfile ); +#endif + + MAIN_RETURN(rc); +} + + +#ifdef LDAP_SIGCHLD + +/* + * Catch and discard terminated child processes, to avoid zombies. + */ + +static RETSIGTYPE +wait4child( int sig ) +{ + int save_errno = errno; + +#ifdef WNOHANG + errno = 0; +#ifdef HAVE_WAITPID + while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR ) + ; /* NULL */ +#else + while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR ) + ; /* NULL */ +#endif +#else + (void) wait( NULL ); +#endif + (void) SIGNAL_REINSTALL( sig, wait4child ); + errno = save_errno; +} + +#endif /* SIGCHLD || SIGCLD */ + + +#ifdef LOG_LOCAL4 + +/* + * Convert a string to an integer by means of a dispatcher table + * if the string is not in the table return the default + */ + +static int +cnvt_str2int( char *stringVal, STRDISP_P dispatcher, int defaultVal ) +{ + int retVal = defaultVal; + STRDISP_P disp; + + for (disp = dispatcher; disp->stringVal; disp++) { + + if (!strncasecmp (stringVal, disp->stringVal, disp->abbr)) { + + retVal = disp->intVal; + break; - ber_free( &ber, 1 ); - } } + } + + return (retVal); } + +#endif /* LOG_LOCAL4 */ diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index dc5ff605d7ac1736c2208de36baaafb45e1edca6..8e6249fcc5cdb4f6f4560ccd26c944e95545aaf2 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -278,7 +278,7 @@ do_modify( } #endif - Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d MOD dn=\"%s\"\n", + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD dn=\"%s\"\n", op->o_connid, op->o_opid, dn.bv_val, 0, 0 ); manageDSAit = get_manageDSAit( op ); diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 802dda55acb4cf4f20fe02cde7a5b0ce69cd4d9e..eca68cace571f2fd5b35d3499c6d871b367853f2 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -1,3 +1,8 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. @@ -10,27 +15,62 @@ * is provided ``as is'' without express or implied warranty. */ +/* + * 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 <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -extern Backend *select_backend(); +#include <ac/socket.h> +#include <ac/string.h> -extern char *default_referral; +#include "ldap_pvt.h" +#include "slap.h" -void +int do_modrdn( Connection *conn, Operation *op ) { - char *dn, *odn, *newrdn; - int deloldrdn; + struct berval dn = { 0, NULL }; + struct berval newrdn = { 0, NULL }; + struct berval newSuperior = { 0, NULL }; + ber_int_t deloldrdn; + + struct berval pdn = { 0, NULL }; + struct berval pnewrdn = { 0, NULL }; + struct berval pnewSuperior = { 0, NULL }, *pnewS = NULL; + + struct berval ndn = { 0, NULL }; + struct berval nnewrdn = { 0, NULL }; + struct berval nnewSuperior = { 0, NULL }, *nnewS = NULL; + Backend *be; + Backend *newSuperior_be = NULL; + ber_len_t length; + int rc; + const char *text; + int manageDSAit; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_modrdn: begin\n" )); +#else Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 ); +#endif + /* * Parse the modrdn request. It looks like this: @@ -38,65 +78,311 @@ do_modrdn( * ModifyRDNRequest := SEQUENCE { * entry DistinguishedName, * newrdn RelativeDistinguishedName + * deleteoldrdn BOOLEAN, + * newSuperior [0] LDAPDN OPTIONAL (v3 Only!) * } */ - if ( ber_scanf( op->o_ber, "{aab}", &dn, &newrdn, &deloldrdn ) - == LBER_ERROR ) { + if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn ) + == LBER_ERROR ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: ber_scanf failed\n" )); +#else Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" ); - return; +#endif + + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + return SLAPD_DISCONNECT; } - odn = strdup( dn ); - dn_normalize( dn ); + /* Check for newSuperior parameter, if present scan it */ + + if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) { + if ( op->o_protocol < LDAP_VERSION3 ) { + /* Conection record indicates v2 but field + * newSuperior is present: report error. + */ +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: (v2) invalid field newSuperior.\n" )); +#else + Debug( LDAP_DEBUG_ANY, + "modrdn(v2): invalid field newSuperior!\n", + 0, 0, 0 ); +#endif + + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } + + if ( ber_scanf( op->o_ber, "m", &newSuperior ) + == LBER_ERROR ) { + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: ber_scanf(\"m\") failed\n" )); +#else + Debug( LDAP_DEBUG_ANY, "ber_scanf(\"m\") failed\n", + 0, 0, 0 ); +#endif + + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } + pnewS = &pnewSuperior; + nnewS = &nnewSuperior; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_modrdn: dn (%s) newrdn (%s) newsuperior(%s)\n", + dn.bv_val, newrdn.bv_val, + newSuperior.bv_len ? newSuperior.bv_val : "" )); +#else Debug( LDAP_DEBUG_ARGS, - "do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn, - deloldrdn ); + "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n", + dn.bv_val, newrdn.bv_val, + newSuperior.bv_len ? newSuperior.bv_val : "" ); +#endif + + if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: ber_scanf failed\n" )); +#else + Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 ); +#endif + + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = SLAPD_DISCONNECT; + goto cleanup; + } + + if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: get_ctrls failed\n" )); +#else + Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 ); +#endif + + /* get_ctrls has sent results. Now clean up. */ + goto cleanup; + } + + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_modrdn: conn %d invalid dn (%s)\n", + conn->c_connid, dn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_modrdn: invalid dn (%s)\n", dn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto cleanup; + } + + if( ndn.bv_len == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: attempt to modify root DSE.\n" )); +#else + Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 ); +#endif - Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MODRDN dn=\"%s\"\n", - conn->c_connid, op->o_opid, dn, 0, 0 ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "cannot rename the root DSE", NULL, NULL ); + goto cleanup; + +#ifdef SLAPD_SCHEMA_DN + } else if ( strcasecmp( ndn.bv_val, SLAPD_SCHEMA_DN ) == 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: attempt to modify subschema subentry\n" )); +#else + Debug( LDAP_DEBUG_ANY, "do_modrdn: subschema subentry!\n", 0, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "cannot rename subschema subentry", NULL, NULL ); + goto cleanup; +#endif + } + + /* FIXME: should have/use rdnPretty / rdnNormalize routines */ + + rc = dnPrettyNormal( NULL, &newrdn, &pnewrdn, &nnewrdn ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_modrdn: conn %d invalid newrdn (%s)\n", + conn->c_connid, newrdn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_modrdn: invalid newrdn (%s)\n", newrdn.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid new RDN", NULL, NULL ); + goto cleanup; + } + + if( rdnValidate( &pnewrdn ) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "do_modrdn: invalid rdn (%s).\n", pnewrdn.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid rdn (%s)\n", + pnewrdn.bv_val, 0, 0 ); +#endif + + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid new RDN", NULL, NULL ); + goto cleanup; + } + + if( pnewS ) { + rc = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior, + &nnewSuperior ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_modrdn: conn %d invalid newSuperior (%s)\n", + conn->c_connid, newSuperior.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_modrdn: invalid newSuperior (%s)\n", + newSuperior.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid newSuperior", NULL, NULL ); + goto cleanup; + } + } + + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MODRDN dn=\"%s\"\n", + op->o_connid, op->o_opid, pdn.bv_val, 0, 0 ); + + manageDSAit = get_manageDSAit( op ); /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ + if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvarray_free( ref ); + goto cleanup; + } + + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto cleanup; + } + + /* check for referrals */ + rc = backend_check_referrals( be, conn, op, &pdn, &ndn ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + + /* Make sure that the entry being changed and the newSuperior are in + * the same backend, otherwise we return an error. + */ + if( pnewS ) { + newSuperior_be = select_backend( &nnewSuperior, 0, 0 ); + + if ( newSuperior_be != be ) { + /* newSuperior is in same backend */ + rc = LDAP_AFFECTS_MULTIPLE_DSAS; - if ( (be = select_backend( dn )) == NULL ) { - free( dn ); - free( odn ); - free( newrdn ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); - return; + send_ldap_result( conn, op, rc, + NULL, "cannot rename between DSAa", NULL, NULL ); + + goto cleanup; + } + + /* deref suffix alias if appropriate */ + suffix_alias( be, &nnewSuperior ); } + /* deref suffix alias if appropriate */ + suffix_alias( be, &ndn ); + /* * do the add if 1 && (2 || 3) * 1) there is an add function implemented in this backend; * 2) this backend is master for what it holds; - * 3) it's a replica and the dn supplied is the updatedn. + * 3) it's a replica and the dn supplied is the update_ndn. */ - if ( be->be_modrdn != NULL ) { + if ( be->be_modrdn ) { /* do the update here */ - if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn, - op->o_dn ) == 0 ) { - if ( (*be->be_modrdn)( be, conn, op, dn, newrdn, - deloldrdn ) == 0 ) { - replog( be, LDAP_REQ_MODRDN, odn, newrdn, - deloldrdn ); + int repl_user = be_isupdate( be, &op->o_ndn ); +#ifndef SLAPD_MULTIMASTER + if ( !be->be_update_ndn.bv_len || repl_user ) +#endif + { + if ( (*be->be_modrdn)( be, conn, op, &pdn, &ndn, + &pnewrdn, &nnewrdn, deloldrdn, + pnewS, nnewS ) == 0 +#ifdef SLAPD_MULTIMASTER + && ( !be->be_update_ndn.bv_len || !repl_user ) +#endif + ) { + struct slap_replog_moddn moddn; + moddn.newrdn = &pnewrdn; + moddn.deloldrdn = deloldrdn; + moddn.newsup = &pnewSuperior; + + replog( be, op, &pdn, &ndn, &moddn ); } +#ifndef SLAPD_MULTIMASTER } else { - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + BerVarray defref = be->be_update_refs + ? be->be_update_refs : default_referral; + BerVarray ref = referral_rewrite( defref, + NULL, &pdn, LDAP_SCOPE_DEFAULT ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + ref ? ref : defref, NULL ); + + ber_bvarray_free( ref ); +#endif } } else { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", + NULL, NULL ); } - free( dn ); - free( odn ); - free( newrdn ); +cleanup: + free( pdn.bv_val ); + free( ndn.bv_val ); + + free( pnewrdn.bv_val ); + free( nnewrdn.bv_val ); + + if ( pnewSuperior.bv_val ) free( pnewSuperior.bv_val ); + if ( nnewSuperior.bv_val ) free( nnewSuperior.bv_val ); + + return rc; } diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c new file mode 100644 index 0000000000000000000000000000000000000000..529b4e74b2314e8f4a496c57d0c5d45a4aac9823 --- /dev/null +++ b/servers/slapd/mods.c @@ -0,0 +1,324 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright (c) 1995 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. + */ + +#include "portable.h" + +#include "slap.h" + +int +modify_add_values( + Entry *e, + Modification *mod, + const char **text, + char *textbuf, size_t textlen +) +{ + int i, j; + Attribute *a; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + const char *op; + + switch( mod->sm_op ) { + case LDAP_MOD_ADD: + op = "add"; + break; + case LDAP_MOD_REPLACE: + op = "replace"; + break; + default: + op = "?"; + assert( 0 ); + } + + a = attr_find( e->e_attrs, mod->sm_desc ); + + /* check if the values we're adding already exist */ + if( mr == NULL || !mr->smr_match ) { + if ( a != NULL ) { + /* do not allow add of additional attribute + if no equality rule exists */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: no equality matching rule", + op, mod->sm_desc->ad_cname.bv_val ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + /* test asserted values against existing values */ + if( a ) { + for( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + int rc = ber_bvcmp( &mod->sm_bvalues[i], + &a->a_vals[j] ); + + if( rc == 0 ) { + /* value exists already */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: value #%i already exists", + op, mod->sm_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + } + + /* test asserted values against themselves */ + for( j = 0; j < i; j++ ) { + int rc = ber_bvcmp( &mod->sm_bvalues[i], + &mod->sm_bvalues[j] ); + + if( rc == 0 ) { + /* value exists already */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: value #%i already exists", + op, mod->sm_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + } + + } else { + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + int rc, match; + struct berval asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + &mod->sm_bvalues[i], + &asserted, + text ); + + if( rc != LDAP_SUCCESS ) return rc; + + if( a ) { + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &a->a_vals[j], &asserted, text ); + + if( rc == LDAP_SUCCESS && match == 0 ) { + free( asserted.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + } + + for ( j = 0; j < i; j++ ) { + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &mod->sm_bvalues[j], &asserted, text ); + + if( rc == LDAP_SUCCESS && match == 0 ) { + free( asserted.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + + free( asserted.bv_val ); + } + } + + /* no - add them */ + if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) { + /* this should return result of attr_merge */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: merge error", + op, mod->sm_desc->ad_cname.bv_val ); + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} + +int +modify_delete_values( + Entry *e, + Modification *mod, + const char **text, + char *textbuf, size_t textlen +) +{ + int i, j, k, found; + Attribute *a; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + + /* delete the entire attribute */ + if ( mod->sm_bvalues == NULL ) { + int rc = attr_delete( &e->e_attrs, mod->sm_desc ); + + if( rc != LDAP_SUCCESS ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + rc = LDAP_NO_SUCH_ATTRIBUTE; + } + return rc; + } + + if( mr == NULL || !mr->smr_match ) { + /* disallow specific attributes from being deleted if + no equality rule */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no equality matching rule", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* delete specific values - find the attribute first */ + if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + + /* find each value to delete */ + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + int rc; + struct berval asserted; + + rc = value_normalize( mod->sm_desc, + SLAP_MR_EQUALITY, + &mod->sm_bvalues[i], + &asserted, + text ); + + if( rc != LDAP_SUCCESS ) return rc; + + found = 0; + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + int match; + int rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_VALUE_SYNTAX_MATCH, + &a->a_vals[j], &asserted, text ); + + if( rc == LDAP_SUCCESS && match != 0 ) { + continue; + } + + /* found a matching value */ + found = 1; + + /* delete it */ + free( a->a_vals[j].bv_val ); + for ( k = j + 1; a->a_vals[k].bv_val != NULL; k++ ) { + a->a_vals[k - 1] = a->a_vals[k]; + } + a->a_vals[k - 1].bv_val = NULL; + a->a_vals[k - 1].bv_len = 0; + + break; + } + + free( asserted.bv_val ); + + /* looked through them all w/o finding it */ + if ( ! found ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such value", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + /* if no values remain, delete the entire attribute */ + if ( a->a_vals[0].bv_val == NULL ) { + if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + return LDAP_SUCCESS; +} + +int +modify_replace_values( + Entry *e, + Modification *mod, + const char **text, + char *textbuf, size_t textlen +) +{ + (void) attr_delete( &e->e_attrs, mod->sm_desc ); + + if ( mod->sm_bvalues ) { + return modify_add_values( e, mod, text, textbuf, textlen ); + } + + return LDAP_SUCCESS; +} + +void +slap_mod_free( + Modification *mod, + int freeit +) +{ +#if 0 + if ( mod->sm_type.bv_val) + free( mod->sm_type.bv_val ); +#endif + if ( mod->sm_bvalues != NULL ) + ber_bvarray_free( mod->sm_bvalues ); + + if( freeit ) + free( mod ); +} + +void +slap_mods_free( + Modifications *ml +) +{ + Modifications *next; + + for ( ; ml != NULL; ml = next ) { + next = ml->sml_next; + + slap_mod_free( &ml->sml_mod, 0 ); + free( ml ); + } +} + +void +slap_modlist_free( + LDAPModList *ml +) +{ + LDAPModList *next; + + for ( ; ml != NULL; ml = next ) { + next = ml->ml_next; + + if (ml->ml_type) + free( ml->ml_type ); + + if ( ml->ml_bvalues != NULL ) + ber_bvecfree( ml->ml_bvalues ); + + free( ml ); + } +} diff --git a/servers/slapd/module.c b/servers/slapd/module.c new file mode 100644 index 0000000000000000000000000000000000000000..4a58714d5f0a20b385f8f1cdbfe53c88a099f73c --- /dev/null +++ b/servers/slapd/module.c @@ -0,0 +1,300 @@ +/* $OpenLDAP$ */ +#include "portable.h" +#include <stdio.h> +#include "slap.h" + +#ifdef SLAPD_MODULES + +#include <ltdl.h> + +typedef int (*MODULE_INIT_FN)( + int argc, + char *argv[]); +typedef int (*MODULE_LOAD_FN)( + const void *module, + const char *filename); +typedef int (*MODULE_TERM_FN)(void); + + +struct module_regtable_t { + char *type; + MODULE_LOAD_FN proc; +} module_regtable[] = { + { "null", load_null_module }, +#ifdef SLAPD_EXTERNAL_EXTENSIONS + { "extension", load_extop_module }, +#endif + { NULL, NULL } +}; + +typedef struct module_loaded_t { + struct module_loaded_t *next; + lt_dlhandle lib; +} module_loaded_t; + +module_loaded_t *module_list = NULL; + +static int module_unload (module_loaded_t *module); + +int module_init (void) +{ + if (lt_dlinit()) { + const char *error = lt_dlerror(); +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_CRIT, + "module_init: lt_ldinit failed: %s\n", error )); +#else + Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0); +#endif + + return -1; + } + return 0; +} + +int module_kill (void) +{ + /* unload all modules before shutdown */ + while (module_list != NULL) { + module_unload(module_list); + } + + if (lt_dlexit()) { + const char *error = lt_dlerror(); +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_CRIT, + "module_kill: lt_dlexit failed: %s\n", error )); +#else + Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0); +#endif + + return -1; + } + return 0; +} + +int module_load(const char* file_name, int argc, char *argv[]) +{ + module_loaded_t *module = NULL; + const char *error; + int rc; + MODULE_INIT_FN initialize; + + module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t)); + if (module == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_CRIT, + "module_load: (%s) out of memory.\n", file_name )); +#else + Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name, + 0, 0); +#endif + + return -1; + } + + /* + * The result of lt_dlerror(), when called, must be cached prior + * to calling Debug. This is because Debug is a macro that expands + * into multiple function calls. + */ + if ((module->lib = lt_dlopen(file_name)) == NULL) { + error = lt_dlerror(); +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_CRIT, + "module_load: lt_dlopen failed: (%s) %s.\n", + file_name, error )); +#else + Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name, + error, 0); +#endif + + ch_free(module); + return -1; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_INFO, + "module_load: loaded module %s\n", file_name )); +#else + Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0); +#endif + + + if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) { +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_ERR, + "module_load: module %s : no init_module() function found\n", + file_name )); +#else + Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n", + file_name, 0, 0); +#endif + + lt_dlclose(module->lib); + ch_free(module); + return -1; + } + + /* The imported init_module() routine passes back the type of + * module (i.e., which part of slapd it should be hooked into) + * or -1 for error. If it passes back 0, then you get the + * old behavior (i.e., the library is loaded and not hooked + * into anything). + * + * It might be better if the conf file could specify the type + * of module. That way, a single module could support multiple + * type of hooks. This could be done by using something like: + * + * moduleload extension /usr/local/openldap/whatever.so + * + * then we'd search through module_regtable for a matching + * module type, and hook in there. + */ + rc = initialize(argc, argv); + if (rc == -1) { +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_ERR, + "module_load: module %s init_module() failed\n", file_name)); +#else + Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n", + file_name, 0, 0); +#endif + + lt_dlclose(module->lib); + ch_free(module); + return rc; + } + + if (rc >= (int)(sizeof(module_regtable) / sizeof(struct module_regtable_t)) + || module_regtable[rc].proc == NULL) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_ERR, + "module_load: module %s: unknown registration type (%d).\n", file_name)); +#else + Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n", + file_name, rc, 0); +#endif + + module_unload(module); + return -1; + } + + rc = (module_regtable[rc].proc)(module, file_name); + if (rc != 0) { +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_ERR, + "module_load: module %s:%s could not be registered.\n", + file_name, module_regtable[rc].type )); +#else + Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n", + file_name, module_regtable[rc].type, 0); +#endif + + module_unload(module); + return rc; + } + + module->next = module_list; + module_list = module; + +#ifdef NEW_LOGGING + LDAP_LOG(( "module", LDAP_LEVEL_INFO, + "module_load: module %s:%s registered\n", file_name, + module_regtable[rc].type )); +#else + Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n", + file_name, module_regtable[rc].type, 0); +#endif + + return 0; +} + +int module_path(const char *path) +{ + return lt_dlsetsearchpath( path ); +} + +void *module_resolve (const void *module, const char *name) +{ + if (module == NULL || name == NULL) + return(NULL); + return(lt_dlsym(((module_loaded_t *)module)->lib, name)); +} + +static int module_unload (module_loaded_t *module) +{ + module_loaded_t *mod; + MODULE_TERM_FN terminate; + + if (module != NULL) { + /* remove module from tracking list */ + if (module_list == module) { + module_list = module->next; + } else { + for (mod = module_list; mod; mod = mod->next) { + if (mod->next == module) { + mod->next = module->next; + break; + } + } + } + + /* call module's terminate routine, if present */ + if (terminate = lt_dlsym(module->lib, "term_module")) { + terminate(); + } + + /* close the library and free the memory */ + lt_dlclose(module->lib); + ch_free(module); + } + return 0; +} + +int load_null_module (const void *module, const char *file_name) +{ + return 0; +} + +#ifdef SLAPD_EXTERNAL_EXTENSIONS +int +load_extop_module ( + const void *module, + const char *file_name +) +{ + SLAP_EXTOP_MAIN_FN *ext_main; + int (*ext_getoid)(int index, char *oid, int blen); + char *oid; + int rc; + + ext_main = (SLAP_EXTOP_MAIN_FN *)module_resolve(module, "ext_main"); + if (ext_main == NULL) { + return(-1); + } + + ext_getoid = module_resolve(module, "ext_getoid"); + if (ext_getoid == NULL) { + return(-1); + } + + oid = ch_malloc(256); + rc = (ext_getoid)(0, oid, 256); + if (rc != 0) { + ch_free(oid); + return(rc); + } + if (*oid == 0) { + free(oid); + return(-1); + } + + rc = load_extop( oid, ext_main ); + free(oid); + return rc; +} +#endif /* SLAPD_EXTERNAL_EXTENSIONS */ +#endif /* SLAPD_MODULES */ + diff --git a/servers/slapd/mr.c b/servers/slapd/mr.c new file mode 100644 index 0000000000000000000000000000000000000000..e1af29d0c88fbee2205347a255571b63422f67a5 --- /dev/null +++ b/servers/slapd/mr.c @@ -0,0 +1,311 @@ +/* mr.c - routines to manage matching rule definitions */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "ldap_pvt.h" + + +struct mindexrec { + struct berval mir_name; + MatchingRule *mir_mr; +}; + +static Avlnode *mr_index = NULL; +static MatchingRule *mr_list = NULL; + +static int +mr_index_cmp( + struct mindexrec *mir1, + struct mindexrec *mir2 +) +{ + int i = mir1->mir_name.bv_len - mir2->mir_name.bv_len; + if (i) return i; + return (strcmp( mir1->mir_name.bv_val, mir2->mir_name.bv_val )); +} + +static int +mr_index_name_cmp( + struct berval *name, + struct mindexrec *mir +) +{ + int i = name->bv_len - mir->mir_name.bv_len; + if (i) return i; + return (strncmp( name->bv_val, mir->mir_name.bv_val, name->bv_len )); +} + +MatchingRule * +mr_find( const char *mrname ) +{ + struct berval bv; + + bv.bv_val = (char *)mrname; + bv.bv_len = strlen( mrname ); + return mr_bvfind( &bv ); +} + +MatchingRule * +mr_bvfind( struct berval *mrname ) +{ + struct mindexrec *mir = NULL; + + if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname, + (AVL_CMP) mr_index_name_cmp )) != NULL ) { + return( mir->mir_mr ); + } + return( NULL ); +} + +void +mr_destroy( void ) +{ + MatchingRule *m, *n; + + avl_free(mr_index, ldap_memfree); + for (m=mr_list; m; m=n) { + n = m->smr_next; + ldap_matchingrule_free((LDAPMatchingRule *)m); + } +} + +static int +mr_insert( + MatchingRule *smr, + const char **err +) +{ + MatchingRule **mrp; + struct mindexrec *mir; + char **names; + + mrp = &mr_list; + while ( *mrp != NULL ) { + mrp = &(*mrp)->smr_next; + } + *mrp = smr; + + if ( smr->smr_oid ) { + mir = (struct mindexrec *) + ch_calloc( 1, sizeof(struct mindexrec) ); + mir->mir_name.bv_val = smr->smr_oid; + mir->mir_name.bv_len = strlen( smr->smr_oid ); + mir->mir_mr = smr; + if ( avl_insert( &mr_index, (caddr_t) mir, + (AVL_CMP) mr_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = smr->smr_oid; + ldap_memfree(mir); + return SLAP_SCHERR_DUP_RULE; + } + /* FIX: temporal consistency check */ + mr_bvfind(&mir->mir_name); + } + if ( (names = smr->smr_names) ) { + while ( *names ) { + mir = (struct mindexrec *) + ch_calloc( 1, sizeof(struct mindexrec) ); + mir->mir_name.bv_val = *names; + mir->mir_name.bv_len = strlen( *names ); + mir->mir_mr = smr; + if ( avl_insert( &mr_index, (caddr_t) mir, + (AVL_CMP) mr_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = *names; + ldap_memfree(mir); + return SLAP_SCHERR_DUP_RULE; + } + /* FIX: temporal consistency check */ + mr_bvfind(&mir->mir_name); + names++; + } + } + return 0; +} + +int +mr_add( + LDAPMatchingRule *mr, + unsigned usage, + slap_mr_convert_func *convert, + slap_mr_normalize_func *normalize, + slap_mr_match_func *match, + slap_mr_indexer_func *indexer, + slap_mr_filter_func *filter, + MatchingRule *amr, + const char **err +) +{ + MatchingRule *smr; + Syntax *syn; + int code; + + smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) ); + AC_MEMCPY( &smr->smr_mrule, mr, sizeof(LDAPMatchingRule)); + + smr->smr_oidlen = strlen( mr->mr_oid ); + smr->smr_usage = usage; + smr->smr_convert = convert; + smr->smr_normalize = normalize; + smr->smr_match = match; + smr->smr_indexer = indexer; + smr->smr_filter = filter; + smr->smr_associated = amr; + + if ( smr->smr_syntax_oid ) { + if ( (syn = syn_find(smr->smr_syntax_oid)) ) { + smr->smr_syntax = syn; + } else { + *err = smr->smr_syntax_oid; + return SLAP_SCHERR_SYN_NOT_FOUND; + } + } else { + *err = ""; + return SLAP_SCHERR_MR_INCOMPLETE; + } + code = mr_insert(smr,err); + return code; +} + + +int +register_matching_rule( + const char * desc, + unsigned usage, + slap_mr_convert_func *convert, + slap_mr_normalize_func *normalize, + slap_mr_match_func *match, + slap_mr_indexer_func *indexer, + slap_mr_filter_func *filter, + const char* associated ) +{ + LDAPMatchingRule *mr; + MatchingRule *amr = NULL; + int code; + const char *err; + + if( usage == SLAP_MR_NONE ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "register_matching_rule: %s not usable\n", desc )); +#else + Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n", + desc, 0, 0 ); +#endif + + return -1; + } + + if( associated != NULL ) { + amr = mr_find( associated ); + +#if 0 + /* ignore for now */ + + if( amr == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "register_matching_rule: could not locate associated matching rule %s for %s\n", + associated, desc )); +#else + Debug( LDAP_DEBUG_ANY, "register_matching_rule: could not locate " + "associated matching rule %s for %s\n", + associated, desc, 0 ); +#endif + + return -1; + } +#endif + + } + + mr = ldap_str2matchingrule( desc, &code, &err, LDAP_SCHEMA_ALLOW_ALL); + if ( !mr ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "register_matching_rule: %s before %s in %s.\n", + ldap_scherr2str(code), err, desc )); +#else + Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n", + ldap_scherr2str(code), err, desc ); +#endif + + return( -1 ); + } + + code = mr_add( mr, usage, + convert, normalize, match, indexer, filter, amr, + &err ); + + ldap_memfree( mr ); + + if ( code ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "register_matching_rule: %s for %s in %s.\n", + scherr2str(code), err, desc )); +#else + Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s for %s in %s\n", + scherr2str(code), err, desc ); +#endif + + return( -1 ); + } + + return( 0 ); +} + + +#if defined( SLAPD_SCHEMA_DN ) + +int mr_schema_info( Entry *e ) +{ + struct berval vals[2]; + MatchingRule *mr; + + AttributeDescription *ad_matchingRules = slap_schema.si_ad_matchingRules; + + vals[1].bv_val = NULL; + + for ( mr = mr_list; mr; mr = mr->smr_next ) { + if ( mr->smr_usage & SLAP_MR_HIDE ) { + /* skip hidden rules */ + continue; + } + + if ( ! mr->smr_match ) { + /* skip rules without matching functions */ + continue; + } + + if ( ldap_matchingrule2bv( &mr->smr_mrule, vals ) == NULL ) { + return -1; + } +#if 0 + Debug( LDAP_DEBUG_TRACE, "Merging mr [%ld] %s\n", + (long) vals[0].bv_len, vals[0].bv_val, 0 ); +#endif + attr_merge( e, ad_matchingRules, vals ); + ldap_memfree( vals[0].bv_val ); + } + return 0; +} + +int mru_schema_info( Entry *e ) +{ + return 0; +} + +#endif diff --git a/servers/slapd/mra.c b/servers/slapd/mra.c new file mode 100644 index 0000000000000000000000000000000000000000..81db86ae7687473872714cc5460984a353f91f45 --- /dev/null +++ b/servers/slapd/mra.c @@ -0,0 +1,240 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* mra.c - routines for dealing with extensible matching rule assertions */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" + + +void +mra_free( + MatchingRuleAssertion *mra, + int freeit +) +{ + ch_free( mra->ma_value.bv_val ); + if ( freeit ) { + ch_free( (char *) mra ); + } +} + +int +get_mra( + BerElement *ber, + MatchingRuleAssertion **mra, + const char **text +) +{ + int rc; + ber_tag_t tag, rtag; + ber_len_t length; + struct berval type = { 0, NULL }, value; + MatchingRuleAssertion *ma; + + ma = ch_malloc( sizeof( MatchingRuleAssertion ) ); + ma->ma_rule = NULL; + ma->ma_rule_text.bv_len = 0; + ma->ma_rule_text.bv_val = NULL; + ma->ma_desc = NULL; + ma->ma_dnattrs = 0; + ma->ma_value.bv_len = 0; + ma->ma_value.bv_val = NULL; + + rtag = ber_scanf( ber, "{t", &tag ); + + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf (\"{t\") failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); +#endif + + *text = "Error parsing matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + + if ( tag == LDAP_FILTER_EXT_OID ) { + rtag = ber_scanf( ber, "m", &ma->ma_rule_text ); + if ( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf(\"o\") failure.\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf for mr\n", 0, 0, 0 ); +#endif + + *text = "Error parsing matching rule in matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + + rtag = ber_scanf( ber, "t", &tag ); + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf (\"t\") failure\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); +#endif + + *text = "Error parsing matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + } + + if ( tag == LDAP_FILTER_EXT_TYPE ) { + rtag = ber_scanf( ber, "m", &type ); + if ( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf (\"o\") failure.\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf for ad\n", 0, 0, 0 ); +#endif + + *text = "Error parsing attribute description in matching rule assertion"; + return SLAPD_DISCONNECT; + } + + rtag = ber_scanf( ber, "t", &tag ); + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf (\"t\") failure.\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); +#endif + + *text = "Error parsing matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + } + + if ( tag != LDAP_FILTER_EXT_VALUE ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf missing value\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf missing value\n", 0, 0, 0 ); +#endif + + *text = "Missing value in matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + + rtag = ber_scanf( ber, "m", &value ); + + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf (\"o\") failure.\n" )); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); +#endif + + *text = "Error decoding value in matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + + tag = ber_peek_tag( ber, &length ); + + if ( tag == LDAP_FILTER_EXT_DNATTRS ) { + rtag = ber_scanf( ber, "b}", &ma->ma_dnattrs ); + } else { + rtag = ber_scanf( ber, "}" ); + } + + if( rtag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "get_mra: ber_scanf failure\n")); +#else + Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); +#endif + + *text = "Error decoding dnattrs matching rule assertion"; + mra_free( ma, 1 ); + return SLAPD_DISCONNECT; + } + + if( ma->ma_dnattrs ) { + *text = "matching with \":dn\" not supported"; + return LDAP_INAPPROPRIATE_MATCHING; + } + + if( type.bv_val != NULL ) { + rc = slap_bv2ad( &type, &ma->ma_desc, text ); + if( rc != LDAP_SUCCESS ) { + mra_free( ma, 1 ); + return rc; + } + + } else { + *text = "matching without attribute description rule not supported"; + return LDAP_INAPPROPRIATE_MATCHING; + } + + if( ma->ma_rule_text.bv_val != NULL ) { + ma->ma_rule = mr_bvfind( &ma->ma_rule_text ); + if( ma->ma_rule == NULL ) { + mra_free( ma, 1 ); + *text = "matching rule not recognized"; + return LDAP_INAPPROPRIATE_MATCHING; + } + } + + if( ma->ma_desc != NULL && + ma->ma_desc->ad_type->sat_equality != NULL && + ma->ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT ) + { + /* no matching rule was provided, use the attribute's + equality rule if it supports extensible matching. */ + ma->ma_rule = ma->ma_desc->ad_type->sat_equality; + + } else { + mra_free( ma, 1 ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* check to see if the matching rule is appropriate for + the syntax of the attribute. This check will need + to be extended to support other kinds of extensible + matching rules */ + if( strcmp( ma->ma_rule->smr_syntax->ssyn_oid, + ma->ma_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) + { + mra_free( ma, 1 ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* + * OK, if no matching rule, normalize for equality, otherwise + * normalize for the matching rule. + */ + rc = value_validate_normalize( ma->ma_desc, SLAP_MR_EQUALITY, + &value, &ma->ma_value, text ); + + if( rc != LDAP_SUCCESS ) { + mra_free( ma, 1 ); + return rc; + } + + *mra = ma; + return LDAP_SUCCESS; +} + diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index 0c62e219ece0041aede5f999440faa54f87664e2..49c1a7b58c50815c7506a5fef15d79119f1d3c93 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -1,74 +1,62 @@ /* operation.c - routines to deal with pending ldap operations */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; void -op_free( Operation *op ) +slap_op_free( Operation *op ) { - if ( op->o_ber != NULL ) + assert( LDAP_STAILQ_NEXT(op, o_next) == NULL ); + + if ( op->o_ber != NULL ) { ber_free( op->o_ber, 1 ); - if ( op->o_dn != NULL ) { - free( op->o_dn ); } - /* pthread_mutex_destroy( &op->o_abandonmutex ); */ + if ( op->o_dn.bv_val != NULL ) { + free( op->o_dn.bv_val ); + } + if ( op->o_ndn.bv_val != NULL ) { + free( op->o_ndn.bv_val ); + } + if ( op->o_authmech.bv_val != NULL ) { + free( op->o_authmech.bv_val ); + } + if ( op->o_ctrls != NULL ) { + ldap_controls_free( op->o_ctrls ); + } + free( (char *) op ); } Operation * -op_add( - Operation **olist, +slap_op_alloc( BerElement *ber, - unsigned long msgid, - unsigned long tag, - char *dn, - int id, - int connid + ber_int_t msgid, + ber_tag_t tag, + ber_int_t id ) { - Operation **tmp; - - for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next ) - ; /* NULL */ - - *tmp = (Operation *) calloc( 1, sizeof(Operation) ); - pthread_mutex_init( &(*tmp)->o_abandonmutex, - pthread_mutexattr_default ); - (*tmp)->o_ber = ber; - (*tmp)->o_msgid = msgid; - (*tmp)->o_tag = tag; - (*tmp)->o_abandon = 0; - (*tmp)->o_dn = strdup( dn != NULL ? dn : "" ); - pthread_mutex_lock( ¤ttime_mutex ); - (*tmp)->o_time = currenttime; - pthread_mutex_unlock( ¤ttime_mutex ); - (*tmp)->o_opid = id; - (*tmp)->o_connid = connid; - (*tmp)->o_next = NULL; - - return( *tmp ); -} + Operation *op; -void -op_delete( Operation **olist, Operation *op ) -{ - Operation **tmp; + op = (Operation *) ch_calloc( 1, sizeof(Operation) ); - for ( tmp = olist; *tmp != NULL && *tmp != op; tmp = &(*tmp)->o_next ) - ; /* NULL */ + op->o_ber = ber; + op->o_msgid = msgid; + op->o_tag = tag; - if ( *tmp == NULL ) { - Debug( LDAP_DEBUG_ANY, "op_delete: can't find op %d\n", - op->o_msgid, 0, 0 ); - return; - } + op->o_time = slap_get_time(); + op->o_opid = id; - *tmp = (*tmp)->o_next; - op_free( op ); + return( op ); } diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c new file mode 100644 index 0000000000000000000000000000000000000000..8382f284aec89f51f88501c72564b4787f2fba81 --- /dev/null +++ b/servers/slapd/passwd.c @@ -0,0 +1,326 @@ +/* bind.c - ldbm backend bind and unbind routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/krb.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include "slap.h" + +#include <lutil.h> + +int passwd_extop( + Connection *conn, Operation *op, + const char *reqoid, + struct berval *reqdata, + char **rspoid, + struct berval **rspdata, + LDAPControl ***rspctrls, + const char **text, + BerVarray *refs ) +{ + int rc; + + assert( reqoid != NULL ); + assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 ); + + if( op->o_dn.bv_len == 0 ) { + *text = "only authenticated users may change passwords"; + return LDAP_STRONG_AUTH_REQUIRED; + } + + if( conn->c_authz_backend != NULL && conn->c_authz_backend->be_extended ) { + if( conn->c_authz_backend->be_restrictops & SLAP_RESTRICT_OP_MODIFY ) { + *text = "authorization database is read only"; + rc = LDAP_UNWILLING_TO_PERFORM; + + } else if( conn->c_authz_backend->be_update_ndn.bv_len ) { + /* we SHOULD return a referral in this case */ + *refs = referral_rewrite( conn->c_authz_backend->be_update_refs, + NULL, NULL, LDAP_SCOPE_DEFAULT ); + rc = LDAP_REFERRAL; + + } else { + rc = conn->c_authz_backend->be_extended( + conn->c_authz_backend, conn, op, + reqoid, reqdata, + rspoid, rspdata, rspctrls, + text, refs ); + } + + } else { + *text = "operation not supported for current user"; + rc = LDAP_UNWILLING_TO_PERFORM; + } + + return rc; +} + +int slap_passwd_parse( struct berval *reqdata, + struct berval *id, + struct berval *oldpass, + struct berval *newpass, + const char **text ) +{ + int rc = LDAP_SUCCESS; + ber_tag_t tag; + ber_len_t len; + char berbuf[256]; + BerElement *ber = (BerElement *)berbuf; + + if( reqdata == NULL ) { + return LDAP_SUCCESS; + } + + /* ber_init2 uses reqdata directly, doesn't allocate new buffers */ + ber_init2( ber, reqdata, 0 ); + + tag = ber_scanf( ber, "{" /*}*/ ); + + if( tag != LBER_ERROR ) { + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) { + if( id == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: ID not allowed.\n")); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID not allowed.\n", + 0, 0, 0 ); +#endif + + *text = "user must change own password"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + tag = ber_scanf( ber, "m", id ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: ID parse failed.\n")); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n", + 0, 0, 0 ); +#endif + + goto decoding_error; + } + + tag = ber_peek_tag( ber, &len); + } + + if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ) { + if( oldpass == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: OLD not allowed.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD not allowed.\n", + 0, 0, 0 ); +#endif + + *text = "use bind to verify old password"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + tag = ber_scanf( ber, "m", oldpass ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: ID parse failed.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n", + 0, 0, 0 ); +#endif + + goto decoding_error; + } + + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ) { + if( newpass == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: NEW not allowed.\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW not allowed.\n", + 0, 0, 0 ); +#endif + + *text = "user specified passwords disallowed"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + tag = ber_scanf( ber, "m", newpass ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: OLD parse failed.\n")); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD parse failed.\n", + 0, 0, 0 ); +#endif + + goto decoding_error; + } + + tag = ber_peek_tag( ber, &len ); + } + + if( len != 0 ) { +decoding_error: +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "slap_passwd_parse: decoding error, len=%ld\n", (long)len )); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_passwd_parse: decoding error, len=%ld\n", + (long) len, 0, 0 ); +#endif + + + *text = "data decoding error"; + rc = LDAP_PROTOCOL_ERROR; + } + +done: + return rc; +} + +struct berval * slap_passwd_return( + struct berval *cred ) +{ + int rc; + struct berval *bv = NULL; + char berbuf[256]; + /* opaque structure, size unknown but smaller than berbuf */ + BerElement *ber = (BerElement *)berbuf; + + assert( cred != NULL ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "slap_passwd_return: %ld\n",(long)cred->bv_len )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_return: %ld\n", + (long) cred->bv_len, 0, 0 ); +#endif + + ber_init_w_nullc( ber, LBER_USE_DER ); + + rc = ber_printf( ber, "{tON}", + LDAP_TAG_EXOP_MODIFY_PASSWD_GEN, cred ); + + if( rc >= 0 ) { + (void) ber_flatten( ber, &bv ); + } + + ber_free_buf( ber ); + + return bv; +} + +int +slap_passwd_check( + Connection *conn, + Attribute *a, + struct berval *cred ) +{ + int result = 1; + struct berval *bv; + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) + ldap_pvt_thread_mutex_lock( &passwd_mutex ); +#ifdef SLAPD_SPASSWD + lutil_passwd_sasl_conn = conn->c_sasl_context; +#endif +#endif + + for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) { + if( !lutil_passwd( bv, cred, NULL ) ) { + result = 0; + break; + } + } + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) +#ifdef SLAPD_SPASSWD + lutil_passwd_sasl_conn = NULL; +#endif + ldap_pvt_thread_mutex_unlock( &passwd_mutex ); +#endif + + return result; +} + +void +slap_passwd_generate( struct berval *pass ) +{ + struct berval *tmp; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "slap_passwd_generate: begin\n" )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_passwd_generate\n", 0, 0, 0 ); +#endif + /* + * generate passwords of only 8 characters as some getpass(3) + * implementations truncate at 8 characters. + */ + tmp = lutil_passwd_generate( 8 ); + if (tmp) { + *pass = *tmp; + free(tmp); + } else { + pass->bv_val = NULL; + pass->bv_len = 0; + } +} + +void +slap_passwd_hash( + struct berval * cred, + struct berval * new ) +{ + struct berval *tmp; +#ifdef LUTIL_SHA1_BYTES + char* hash = default_passwd_hash ? default_passwd_hash : "{SSHA}"; +#else + char* hash = default_passwd_hash ? default_passwd_hash : "{SMD5}"; +#endif + + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) + ldap_pvt_thread_mutex_lock( &passwd_mutex ); +#endif + + tmp = lutil_passwd_hash( cred , hash ); + assert( tmp != NULL ); + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) + ldap_pvt_thread_mutex_unlock( &passwd_mutex ); +#endif + *new = *tmp; + free( tmp ); + + return; +} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index a1ff6e5e755cb202ec1fb25028591eb53c45af47..f3d6a8b0b346478505805e4e893fbcae63879699 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1,202 +1,1065 @@ -#ifndef _PROTO_SLAP -#define _PROTO_SLAP +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +#ifndef PROTO_SLAP_H +#define PROTO_SLAP_H + +#include <ldap_cdefs.h> + +LDAP_BEGIN_DECL /* * acl.c */ +LDAP_SLAPD_F (int) access_allowed LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, AttributeDescription *desc, struct berval *val, + slap_access_t access, + AccessControlState *state )); +LDAP_SLAPD_F (int) acl_check_modlist LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, Modifications *ml )); -int access_allowed( Backend *be, Connection *conn, Operation *op, Entry *e, - char *attr, struct berval *val, char *dn, int access ); -struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e, - char *attr ); -int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e, - struct berval *val, Operation *op, int access ); -int acl_check_mods( Backend *be, Connection *conn, Operation *op, Entry *e, - LDAPMod *mods ); +LDAP_SLAPD_F (void) acl_append( AccessControl **l, AccessControl *a ); /* * aclparse.c */ +LDAP_SLAPD_F (void) parse_acl LDAP_P(( Backend *be, + const char *fname, int lineno, + int argc, char **argv )); -void parse_acl( Backend *be, char *fname, int lineno, int argc, char **argv ); -char * access2str( int access ); -int str2access( char *str ); +LDAP_SLAPD_F (char *) access2str LDAP_P(( slap_access_t access )); +LDAP_SLAPD_F (slap_access_t) str2access LDAP_P(( const char *str )); + +#define ACCESSMASK_MAXLEN sizeof("unknown (+wrscan)") +LDAP_SLAPD_F (char *) accessmask2str LDAP_P(( slap_mask_t mask, char* )); +LDAP_SLAPD_F (slap_mask_t) str2accessmask LDAP_P(( const char *str )); +LDAP_SLAPD_F (void) acl_destroy LDAP_P(( AccessControl*, AccessControl* )); +LDAP_SLAPD_F (void) acl_free LDAP_P(( AccessControl *a )); + +/* + * ad.c + */ +LDAP_SLAPD_F (int) slap_str2ad LDAP_P(( + const char *, + AttributeDescription **ad, + const char **text )); + +LDAP_SLAPD_F (int) slap_bv2ad LDAP_P(( + struct berval *bv, + AttributeDescription **ad, + const char **text )); + +LDAP_SLAPD_F (void) ad_destroy LDAP_P(( AttributeDescription * )); + +#define ad_cmp(l,r) (((l)->ad_cname.bv_len < (r)->ad_cname.bv_len) \ + ? -1 : (((l)->ad_cname.bv_len > (r)->ad_cname.bv_len) \ + ? 1 : strcasecmp((l)->ad_cname.bv_val, (r)->ad_cname.bv_val ))) + +LDAP_SLAPD_F (int) is_ad_subtype LDAP_P(( + AttributeDescription *sub, + AttributeDescription *super )); + +LDAP_SLAPD_F (int) ad_inlist LDAP_P(( + AttributeDescription *desc, + AttributeName *attrs )); + +LDAP_SLAPD_F (int) slap_str2undef_ad LDAP_P(( + const char *, + AttributeDescription **ad, + const char **text )); + +LDAP_SLAPD_F (int) slap_bv2undef_ad LDAP_P(( + struct berval *bv, + AttributeDescription **ad, + const char **text )); + +LDAP_SLAPD_F (AttributeDescription *) ad_find_lang LDAP_P(( + AttributeType *type, + struct berval *lang )); + +LDAP_SLAPD_F (AttributeName *) str2anlist LDAP_P(( AttributeName *an, + char *str, const char *brkstr )); +LDAP_SLAPD_F (int) an_find LDAP_P(( AttributeName *a, struct berval *s )); + +/* + * at.c + */ +LDAP_SLAPD_F (void) at_config LDAP_P(( + const char *fname, int lineno, + int argc, char **argv )); +LDAP_SLAPD_F (AttributeType *) at_find LDAP_P(( + const char *name )); +LDAP_SLAPD_F (AttributeType *) at_bvfind LDAP_P(( + struct berval *name )); +LDAP_SLAPD_F (int) at_find_in_list LDAP_P(( + AttributeType *sat, AttributeType **list )); +LDAP_SLAPD_F (int) at_append_to_list LDAP_P(( + AttributeType *sat, AttributeType ***listp )); +LDAP_SLAPD_F (int) at_delete_from_list LDAP_P(( + int pos, AttributeType ***listp )); +LDAP_SLAPD_F (int) at_schema_info LDAP_P(( Entry *e )); +LDAP_SLAPD_F (int) at_add LDAP_P(( + LDAPAttributeType *at, const char **err )); +LDAP_SLAPD_F (void) at_destroy LDAP_P(( void )); + +LDAP_SLAPD_F (int) is_at_subtype LDAP_P(( + AttributeType *sub, + AttributeType *super )); + +LDAP_SLAPD_F (int) is_at_syntax LDAP_P(( + AttributeType *at, + const char *oid )); /* * attr.c */ +LDAP_SLAPD_F (void) attr_free LDAP_P(( Attribute *a )); +LDAP_SLAPD_F (Attribute *) attr_dup LDAP_P(( Attribute *a )); + +LDAP_SLAPD_F (int) attr_merge LDAP_P(( Entry *e, + AttributeDescription *desc, + BerVarray vals )); +LDAP_SLAPD_F (Attribute *) attrs_find LDAP_P(( + Attribute *a, AttributeDescription *desc )); +LDAP_SLAPD_F (Attribute *) attr_find LDAP_P(( + Attribute *a, AttributeDescription *desc )); +LDAP_SLAPD_F (int) attr_delete LDAP_P(( + Attribute **attrs, AttributeDescription *desc )); + +LDAP_SLAPD_F (void) attrs_free LDAP_P(( Attribute *a )); +LDAP_SLAPD_F (Attribute *) attrs_dup LDAP_P(( Attribute *a )); -void attr_free( Attribute *a ); -char * attr_normalize( char *s ); -int attr_merge_fast( Entry *e, char *type, struct berval **vals, int nvals, - int naddvals, int *maxvals, Attribute ***a ); -int attr_merge( Entry *e, char *type, struct berval **vals ); -Attribute * attr_find( Attribute *a, char *type ); -int attr_delete( Attribute **attrs, char *type ); -int attr_syntax( char *type ); -void attr_syntax_config( char *fname, int lineno, int argc, char **argv ); /* * ava.c */ - -int get_ava( BerElement *ber, Ava *ava ); -void ava_free( Ava *ava, int freeit ); +LDAP_SLAPD_F (int) get_ava LDAP_P(( + BerElement *ber, + AttributeAssertion **ava, + unsigned usage, + const char **text )); +LDAP_SLAPD_F (void) ava_free LDAP_P(( + AttributeAssertion *ava, + int freeit )); /* * backend.c */ +LDAP_SLAPD_F (int) backend_init LDAP_P((void)); +LDAP_SLAPD_F (int) backend_add LDAP_P((BackendInfo *aBackendInfo)); +LDAP_SLAPD_F (int) backend_num LDAP_P((Backend *be)); +LDAP_SLAPD_F (int) backend_startup LDAP_P((Backend *be)); +LDAP_SLAPD_F (int) backend_sync LDAP_P((Backend *be)); +LDAP_SLAPD_F (int) backend_shutdown LDAP_P((Backend *be)); +LDAP_SLAPD_F (int) backend_destroy LDAP_P((void)); -Backend * new_backend( char *type ); -Backend * select_backend( char * dn ); -int be_issuffix( Backend *be, char *suffix ); -int be_isroot( Backend *be, char *dn ); -int be_isroot_pw( Backend *be, char *dn, struct berval *cred ); -void be_close(); +LDAP_SLAPD_F (BackendInfo *) backend_info LDAP_P(( const char *type )); +LDAP_SLAPD_F (BackendDB *) backend_db_init LDAP_P(( const char *type )); + +LDAP_SLAPD_F (BackendDB *) select_backend LDAP_P(( + struct berval * dn, + int manageDSAit, + int noSubordinates )); + +LDAP_SLAPD_F (int) be_issuffix LDAP_P(( Backend *be, + struct berval *suffix )); +LDAP_SLAPD_F (int) be_isroot LDAP_P(( Backend *be, + struct berval *ndn )); +LDAP_SLAPD_F (int) be_isroot_pw LDAP_P(( Backend *be, + Connection *conn, struct berval *ndn, struct berval *cred )); +LDAP_SLAPD_F (int) be_isupdate LDAP_P(( Backend *be, struct berval *ndn )); +LDAP_SLAPD_F (struct berval *) be_root_dn LDAP_P(( Backend *be )); +LDAP_SLAPD_F (int) be_entry_release_rw LDAP_P(( + BackendDB *be, Connection *c, Operation *o, Entry *e, int rw )); +#define be_entry_release_r( be, c, o, e ) be_entry_release_rw( be, c, o, e, 0 ) +#define be_entry_release_w( be, c, o, e ) be_entry_release_rw( be, c, o, e, 1 ) + +LDAP_SLAPD_F (int) backend_unbind LDAP_P((Connection *conn, Operation *op)); + +LDAP_SLAPD_F( int ) backend_check_restrictions LDAP_P(( + BackendDB *be, + Connection *conn, + Operation *op, + const void *opdata, + const char **text )); + +LDAP_SLAPD_F( int ) backend_check_referrals LDAP_P(( + BackendDB *be, + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn )); + +LDAP_SLAPD_F (int) backend_connection_init LDAP_P((Connection *conn)); +LDAP_SLAPD_F (int) backend_connection_destroy LDAP_P((Connection *conn)); + +LDAP_SLAPD_F (int) backend_group LDAP_P((BackendDB *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at +)); + +LDAP_SLAPD_F (int) backend_attribute LDAP_P((BackendDB *be, + Connection *conn, + Operation *op, + Entry *target, + struct berval *entry_ndn, + AttributeDescription *entry_at, + BerVarray *vals +)); + +LDAP_SLAPD_F (Attribute *) backend_operational( + BackendDB *, + Connection *conn, + Operation *op, + Entry *e, + AttributeName *attrs, + int opattrs ); + +/* + * backglue.c + */ + +LDAP_SLAPD_F (int) glue_back_initialize( BackendInfo *bi ); +LDAP_SLAPD_F (int) glue_sub_init( void ); /* * ch_malloc.c */ +#ifdef CSRIMALLOC +#define ch_malloc malloc +#define ch_realloc realloc +#define ch_calloc calloc +#define ch_strdup strdup +#define ch_free free + +#else +LDAP_SLAPD_F (void *) ch_malloc LDAP_P(( ber_len_t size )); +LDAP_SLAPD_F (void *) ch_realloc LDAP_P(( void *block, ber_len_t size )); +LDAP_SLAPD_F (void *) ch_calloc LDAP_P(( ber_len_t nelem, ber_len_t size )); +LDAP_SLAPD_F (char *) ch_strdup LDAP_P(( const char *string )); +LDAP_SLAPD_F (void) ch_free LDAP_P(( void * )); -char * ch_malloc( unsigned long size ); -char * ch_realloc( char *block, unsigned long size ); -char * ch_calloc( unsigned long nelem, unsigned long size ); +#ifndef CH_FREE +#undef free +#define free ch_free +#endif +#endif /* * charray.c */ +LDAP_SLAPD_F (void) charray_add LDAP_P(( char ***a, const char *s )); +LDAP_SLAPD_F (void) charray_add_n LDAP_P(( char ***a, const char *s, int l )); +LDAP_SLAPD_F (void) charray_merge LDAP_P(( char ***a, char **s )); +LDAP_SLAPD_F (void) charray_free LDAP_P(( char **array )); +LDAP_SLAPD_F (int) charray_inlist LDAP_P(( char **a, const char *s )); +LDAP_SLAPD_F (char **) charray_dup LDAP_P(( char **a )); +LDAP_SLAPD_F (char **) str2charray LDAP_P(( const char *str, const char *brkstr )); +LDAP_SLAPD_F (int) charray_strcmp LDAP_P(( const char **a1, const char **a2 )); +LDAP_SLAPD_F (int) charray_strcasecmp LDAP_P(( const char **a1, const char **a2 )); -void charray_add( char ***a, char *s ); -void charray_merge( char ***a, char **s ); -void charray_free( char **array ); -int charray_inlist( char **a, char *s ); -char ** charray_dup( char **a ); -char ** str2charray( char *str, char *brkstr ); +LDAP_SLAPD_F (char *) slap_strcopy LDAP_P(( + char *dst, const char *src )); +LDAP_SLAPD_F (char *) slap_strncopy LDAP_P(( + char *dst, const char *src, size_t n )); /* - * config.c + * controls.c */ +LDAP_SLAPD_F (int) get_ctrls LDAP_P(( + Connection *co, + Operation *op, + int senderrors )); -void read_config( char *fname, Backend **bep, FILE *pfp ); +LDAP_SLAPD_F (char *) get_supported_ctrl LDAP_P((int index)); + +/* + * config.c + */ +LDAP_SLAPD_F (int) read_config LDAP_P(( const char *fname )); +LDAP_SLAPD_F (void) config_destroy LDAP_P ((void)); /* * connection.c */ +LDAP_SLAPD_F (int) connections_init LDAP_P((void)); +LDAP_SLAPD_F (int) connections_shutdown LDAP_P((void)); +LDAP_SLAPD_F (int) connections_destroy LDAP_P((void)); +LDAP_SLAPD_F (int) connections_timeout_idle LDAP_P((time_t)); + +LDAP_SLAPD_F (long) connection_init LDAP_P(( + ber_socket_t s, + const char* url, + const char* dnsname, + const char* peername, + const char* sockname, + int use_tls, + slap_ssf_t ssf, + const char *id )); + +LDAP_SLAPD_F (void) connection_closing LDAP_P(( Connection *c )); +LDAP_SLAPD_F (int) connection_state_closing LDAP_P(( Connection *c )); +LDAP_SLAPD_F (const char *) connection_state2str LDAP_P(( int state )) + LDAP_GCCATTR((const)); + +LDAP_SLAPD_F (int) connection_write LDAP_P((ber_socket_t s)); +LDAP_SLAPD_F (int) connection_read LDAP_P((ber_socket_t s)); + +LDAP_SLAPD_F (unsigned long) connections_nextid(void); + +LDAP_SLAPD_F (Connection *) connection_first LDAP_P(( ber_socket_t * )); +LDAP_SLAPD_F (Connection *) connection_next LDAP_P(( + Connection *, ber_socket_t *)); +LDAP_SLAPD_F (void) connection_done LDAP_P((Connection *)); + +LDAP_SLAPD_F (void) connection2anonymous LDAP_P((Connection *)); + +/* + * daemon.c + */ +LDAP_SLAPD_F (void) slapd_add_internal(ber_socket_t s); +LDAP_SLAPD_F (int) slapd_daemon_init( const char *urls ); +LDAP_SLAPD_F (int) slapd_daemon_destroy(void); +LDAP_SLAPD_F (int) slapd_daemon(void); +LDAP_SLAPD_F (Listener **) slapd_get_listeners LDAP_P((void)); +LDAP_SLAPD_F (void) slapd_remove LDAP_P((ber_socket_t s, int wake)); -void connection_activity( Connection *conn ); +LDAP_SLAPD_F (RETSIGTYPE) slap_sig_shutdown LDAP_P((int sig)); +LDAP_SLAPD_F (RETSIGTYPE) slap_sig_wake LDAP_P((int sig)); + +LDAP_SLAPD_F (void) slapd_set_write LDAP_P((ber_socket_t s, int wake)); +LDAP_SLAPD_F (void) slapd_clr_write LDAP_P((ber_socket_t s, int wake)); +LDAP_SLAPD_F (void) slapd_set_read LDAP_P((ber_socket_t s, int wake)); +LDAP_SLAPD_F (void) slapd_clr_read LDAP_P((ber_socket_t s, int wake)); /* * dn.c */ -char * dn_normalize( char *dn ); -char * dn_normalize_case( char *dn ); -char * dn_parent( Backend *be, char *dn ); -int dn_issuffix( char *dn, char *suffix ); -int dn_type( char *dn ); -char * dn_upcase( char *dn ); +#define dn_match(dn1, dn2) ( ber_bvcmp((dn1), (dn2)) == 0 ) + +LDAP_SLAPD_V( const struct berval ) slap_empty_bv; + +LDAP_SLAPD_F (int) dnValidate LDAP_P(( + Syntax *syntax, + struct berval *val )); + +LDAP_SLAPD_F (int) dnNormalize LDAP_P(( + Syntax *syntax, + struct berval *val, + struct berval **normalized )); + +LDAP_SLAPD_F (int) dnNormalize2 LDAP_P(( + Syntax *syntax, + struct berval *val, + struct berval *normalized )); + +LDAP_SLAPD_F (int) dnPretty LDAP_P(( + Syntax *syntax, + struct berval *val, + struct berval **pretty )); + +LDAP_SLAPD_F (int) dnPretty2 LDAP_P(( + Syntax *syntax, + struct berval *val, + struct berval *pretty )); + +LDAP_SLAPD_F (int) dnPrettyNormal LDAP_P(( + Syntax *syntax, + struct berval *val, + struct berval *pretty, + struct berval *normal )); + +LDAP_SLAPD_F (int) dnMatch LDAP_P(( + int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue )); + +LDAP_SLAPD_F (int) dnIsSuffix LDAP_P(( + const struct berval *dn, const struct berval *suffix )); + +LDAP_SLAPD_F (int) dnExtractRdn LDAP_P(( + struct berval *dn, struct berval *rdn )); + +LDAP_SLAPD_F (int) rdnValidate LDAP_P(( struct berval * rdn )); + +LDAP_SLAPD_F (int) dn_rdnlen LDAP_P(( Backend *be, struct berval *dn )); + +LDAP_SLAPD_F (void) build_new_dn LDAP_P(( + struct berval * new_dn, + struct berval * parent_dn, + struct berval * newrdn )); + +LDAP_SLAPD_F (void) dnParent LDAP_P(( struct berval *dn, struct berval *pdn )); /* * entry.c */ +LDAP_SLAPD_V (const Entry) slap_entry_root; -Entry * str2entry( char *s ); -char * entry2str( Entry *e, int *len, int printid ); -void entry_free( Entry *e ); +LDAP_SLAPD_F (int) entry_destroy LDAP_P((void)); + +LDAP_SLAPD_F (Entry *) str2entry LDAP_P(( char *s )); +LDAP_SLAPD_F (char *) entry2str LDAP_P(( Entry *e, int *len )); + +LDAP_SLAPD_F (int) entry_decode LDAP_P(( struct berval *bv, Entry **e )); +LDAP_SLAPD_F (int) entry_encode LDAP_P(( Entry *e, struct berval *bv )); + +LDAP_SLAPD_F (void) entry_free LDAP_P(( Entry *e )); +LDAP_SLAPD_F (int) entry_cmp LDAP_P(( Entry *a, Entry *b )); +LDAP_SLAPD_F (int) entry_dn_cmp LDAP_P(( Entry *a, Entry *b )); +LDAP_SLAPD_F (int) entry_id_cmp LDAP_P(( Entry *a, Entry *b )); + +/* + * extended.c + */ +typedef int (SLAP_EXTOP_MAIN_FN) LDAP_P(( + Connection *conn, Operation *op, + const char * reqoid, + struct berval * reqdata, + char ** rspoid, + struct berval ** rspdata, + LDAPControl *** rspctrls, + const char ** text, + BerVarray *refs )); + +typedef int (SLAP_EXTOP_GETOID_FN) LDAP_P(( + int index, char *oid, int blen )); + +LDAP_SLAPD_F (int) load_extop LDAP_P(( + const char *ext_oid, + SLAP_EXTOP_MAIN_FN *ext_main )); + +LDAP_SLAPD_F (int) extops_init LDAP_P(( void )); + +LDAP_SLAPD_F (int) extops_kill LDAP_P(( void )); + +LDAP_SLAPD_F (struct berval *) get_supported_extop LDAP_P((int index)); /* * filter.c */ +LDAP_SLAPD_F (int) get_filter LDAP_P(( + Connection *conn, + BerElement *ber, + Filter **filt, + const char **text )); -int get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr ); -void filter_free( Filter *f ); -void filter_print( Filter *f ); +LDAP_SLAPD_F (void) filter_free LDAP_P(( Filter *f )); +LDAP_SLAPD_F (void) filter2bv LDAP_P(( Filter *f, struct berval *bv )); /* * filterentry.c */ +LDAP_SLAPD_F (int) test_filter LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, Filter *f )); + +/* + * index.c + */ +LDAP_SLAPD_F (int) slap_str2index LDAP_P(( const char *str, slap_mask_t *idx )); + +/* + * init.c + */ +LDAP_SLAPD_F (int) slap_init LDAP_P((int mode, const char* name)); +LDAP_SLAPD_F (int) slap_startup LDAP_P(( Backend *be )); +LDAP_SLAPD_F (int) slap_shutdown LDAP_P(( Backend *be )); +LDAP_SLAPD_F (int) slap_destroy LDAP_P((void)); + +/* + * kerberos.c + */ +#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND +LDAP_SLAPD_V (char *) ldap_srvtab; +LDAP_SLAPD_V (int) krbv4_ldap_auth(); +#endif -int test_filter( Backend *be, Connection *conn, Operation *op, Entry *e, - Filter *f ); +/* + * limits.c + */ +LDAP_SLAPD_F (int) get_limits LDAP_P(( + Backend *be, struct berval *ndn, + struct slap_limits_set **limit )); +LDAP_SLAPD_F (int) parse_limits LDAP_P(( + Backend *be, const char *fname, int lineno, + int argc, char **argv )); +LDAP_SLAPD_F (int) parse_limit LDAP_P(( const char *arg, + struct slap_limits_set *limit )); /* * lock.c */ +LDAP_SLAPD_F (FILE *) lock_fopen LDAP_P(( const char *fname, + const char *type, FILE **lfp )); +LDAP_SLAPD_F (int) lock_fclose LDAP_P(( FILE *fp, FILE *lfp )); + +/* + * modify.c + */ +LDAP_SLAPD_F( int ) slap_mods_check( + Modifications *ml, + int update, + const char **text, + char *textbuf, size_t textlen ); -FILE * lock_fopen( char *fname, char *type, FILE **lfp ); -int lock_fclose( FILE *fp, FILE *lfp ); +LDAP_SLAPD_F( int ) slap_mods_opattrs( + Operation *op, + Modifications *mods, + Modifications **modlist, + const char **text, + char *textbuf, size_t textlen ); /* - * monitor.c + * mods.c */ +LDAP_SLAPD_F( int ) modify_add_values( Entry *e, + Modification *mod, + const char **text, char *textbuf, size_t textlen ); +LDAP_SLAPD_F( int ) modify_delete_values( Entry *e, + Modification *mod, + const char **text, char *textbuf, size_t textlen ); +LDAP_SLAPD_F( int ) modify_replace_values( Entry *e, + Modification *mod, + const char **text, char *textbuf, size_t textlen ); -void monitor_info( Connection *conn, Operation *op ); +LDAP_SLAPD_F( void ) slap_mod_free( Modification *mod, int freeit ); +LDAP_SLAPD_F( void ) slap_mods_free( Modifications *mods ); +LDAP_SLAPD_F( void ) slap_modlist_free( LDAPModList *ml ); + +/* + * module.c + */ +#ifdef SLAPD_MODULES + +LDAP_SLAPD_F (int) module_init LDAP_P(( void )); +LDAP_SLAPD_F (int) module_kill LDAP_P(( void )); + +LDAP_SLAPD_F (int) load_null_module( + const void *module, const char *file_name); +LDAP_SLAPD_F (int) load_extop_module( + const void *module, const char *file_name); + +LDAP_SLAPD_F (int) module_load LDAP_P(( + const char* file_name, + int argc, char *argv[] )); +LDAP_SLAPD_F (int) module_path LDAP_P(( const char* path )); + +LDAP_SLAPD_F (void) *module_resolve LDAP_P(( + const void *module, const char *name)); + +#endif /* SLAPD_MODULES */ + +/* mr.c */ +LDAP_SLAPD_F (MatchingRule *) mr_bvfind LDAP_P((struct berval *mrname)); +LDAP_SLAPD_F (MatchingRule *) mr_find LDAP_P((const char *mrname)); +LDAP_SLAPD_F (int) mr_add LDAP_P(( LDAPMatchingRule *mr, + unsigned usage, + slap_mr_convert_func *convert, + slap_mr_normalize_func *normalize, + slap_mr_match_func *match, + slap_mr_indexer_func *indexer, + slap_mr_filter_func *filter, + MatchingRule * associated, + const char **err )); +LDAP_SLAPD_F (void) mr_destroy LDAP_P(( void )); + +LDAP_SLAPD_F (int) register_matching_rule LDAP_P(( + const char * desc, + unsigned usage, + slap_mr_convert_func *convert, + slap_mr_normalize_func *normalize, + slap_mr_match_func *match, + slap_mr_indexer_func *indexer, + slap_mr_filter_func *filter, + const char *associated )); + +LDAP_SLAPD_F (int) mr_schema_info( Entry *e ); +LDAP_SLAPD_F (int) mru_schema_info( Entry *e ); + +/* + * mra.c + */ +LDAP_SLAPD_F (int) get_mra LDAP_P(( + BerElement *ber, + MatchingRuleAssertion **mra, + const char **text )); +LDAP_SLAPD_F (void) mra_free LDAP_P(( + MatchingRuleAssertion *mra, + int freeit )); + +/* oc.c */ +LDAP_SLAPD_F (int) oc_add LDAP_P(( + LDAPObjectClass *oc, + const char **err)); +LDAP_SLAPD_F (void) oc_destroy LDAP_P(( void )); + +LDAP_SLAPD_F (ObjectClass *) oc_find LDAP_P(( + const char *ocname)); +LDAP_SLAPD_F (ObjectClass *) oc_bvfind LDAP_P(( + struct berval *ocname)); +LDAP_SLAPD_F (int) is_object_subclass LDAP_P(( + ObjectClass *sup, + ObjectClass *sub )); + +LDAP_SLAPD_F (int) is_entry_objectclass LDAP_P(( + Entry *, ObjectClass *oc, int set_flags )); +#define is_entry_alias(e) \ + (((e)->e_ocflags & SLAP_OC__END) ? ((e)->e_ocflags & SLAP_OC_ALIAS) : \ + is_entry_objectclass((e), slap_schema.si_oc_alias, 1)) +#define is_entry_referral(e) \ + (((e)->e_ocflags & SLAP_OC__END) ? ((e)->e_ocflags & SLAP_OC_REFERRAL) : \ + is_entry_objectclass((e), slap_schema.si_oc_referral, 1)) +#define is_entry_subentry(e) \ + (((e)->e_ocflags & SLAP_OC__END) ? ((e)->e_ocflags & SLAP_OC_SUBENTRY) : \ + is_entry_objectclass((e), slap_schema.si_oc_subentry, 1)) +#define is_entry_collectiveAttributeSubentry(e) \ + (((e)->e_ocflags & SLAP_OC__END) ? ((e)->e_ocflags & SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY) : \ + is_entry_objectclass((e), slap_schema.si_oc_collectiveAttributeSubentry, 1)) +#define is_entry_dynamicObject(e) \ + (((e)->e_ocflags & SLAP_OC__END) ? ((e)->e_ocflags & SLAP_OC_DYNAMICOBJECT) : \ + is_entry_objectclass((e), slap_schema.si_oc_dynamicObject, 1)) + +LDAP_SLAPD_F (int) oc_schema_info( Entry *e ); + +/* + * oidm.c + */ +LDAP_SLAPD_F(char *) oidm_find(char *oid); +LDAP_SLAPD_F (void) oidm_destroy LDAP_P(( void )); +LDAP_SLAPD_F (int) parse_oidm LDAP_P(( + const char *fname, int lineno, int argc, char **argv )); /* * operation.c */ +LDAP_SLAPD_F (void) slap_op_free LDAP_P(( Operation *op )); +LDAP_SLAPD_F (Operation *) slap_op_alloc LDAP_P(( + BerElement *ber, ber_int_t msgid, + ber_tag_t tag, ber_int_t id )); -void op_free( Operation *op ); -Operation * op_add( Operation **olist, BerElement *ber, unsigned long msgid, - unsigned long tag, char *dn, int id, int connid ); -void op_delete( Operation **olist, Operation *op ); +LDAP_SLAPD_F (int) slap_op_add LDAP_P(( Operation **olist, Operation *op )); +LDAP_SLAPD_F (int) slap_op_remove LDAP_P(( Operation **olist, Operation *op )); +LDAP_SLAPD_F (Operation *) slap_op_pop LDAP_P(( Operation **olist )); + +/* + * operational.c + */ +LDAP_SLAPD_F (Attribute *) slap_operational_subschemaSubentry( void ); +LDAP_SLAPD_F (Attribute *) slap_operational_hasSubordinate( int has ); + +/* + * passwd.c + */ +LDAP_SLAPD_F (SLAP_EXTOP_MAIN_FN) passwd_extop; + +LDAP_SLAPD_F (int) slap_passwd_check( + Connection *conn, + Attribute *attr, + struct berval *cred ); + +LDAP_SLAPD_F (void) slap_passwd_generate( struct berval * ); + +LDAP_SLAPD_F (void) slap_passwd_hash( + struct berval *cred, + struct berval *hash ); + +LDAP_SLAPD_F (struct berval *) slap_passwd_return( + struct berval *cred ); + +LDAP_SLAPD_F (int) slap_passwd_parse( + struct berval *reqdata, + struct berval *id, + struct berval *oldpass, + struct berval *newpass, + const char **text ); /* * phonetic.c */ +LDAP_SLAPD_F (char *) phonetic LDAP_P(( char *s )); + +/* + * referral.c + */ +LDAP_SLAPD_F (int) validate_global_referral LDAP_P(( + const char *url )); + +LDAP_SLAPD_F (BerVarray) get_entry_referrals LDAP_P(( + Backend *be, Connection *conn, Operation *op, Entry *e )); -char * first_word( char *s ); -char * next_word( char *s ); -char * word_dup( char *w ); -char * phonetic( char *s ); +LDAP_SLAPD_F (BerVarray) referral_rewrite LDAP_P(( + BerVarray refs, + struct berval *base, + struct berval *target, + int scope )); /* * repl.c */ - -void replog( Backend *be, int optype, char *dn, void *change, int flag ); +LDAP_SLAPD_F (int) add_replica_info LDAP_P(( Backend *be, + const char *host )); +LDAP_SLAPD_F (int) add_replica_suffix LDAP_P(( Backend *be, + int nr, const char *suffix )); +LDAP_SLAPD_F (int) add_replica_attrs LDAP_P(( Backend *be, + int nr, char *attrs, int exclude )); +LDAP_SLAPD_F (void) replog LDAP_P(( Backend *be, Operation *op, + struct berval *dn, struct berval *ndn, void *change )); /* * result.c */ +LDAP_SLAPD_F (void) send_ldap_result LDAP_P(( + Connection *conn, Operation *op, + ber_int_t err, const char *matched, const char *text, + BerVarray refs, + LDAPControl **ctrls )); + +LDAP_SLAPD_F (void) send_ldap_sasl LDAP_P(( + Connection *conn, Operation *op, + ber_int_t err, const char *matched, + const char *text, + BerVarray refs, + LDAPControl **ctrls, + struct berval *cred )); + +LDAP_SLAPD_F (void) send_ldap_disconnect LDAP_P(( + Connection *conn, Operation *op, + ber_int_t err, const char *text )); + +LDAP_SLAPD_F (void) send_ldap_extended LDAP_P(( + Connection *conn, Operation *op, + ber_int_t err, const char *matched, + const char *text, BerVarray refs, + const char *rspoid, struct berval *rspdata, + LDAPControl **ctrls )); + +LDAP_SLAPD_F (void) send_ldap_partial LDAP_P(( + Connection *conn, Operation *op, + const char *rspoid, struct berval *rspdata, + LDAPControl **ctrls )); + +LDAP_SLAPD_F (void) send_search_result LDAP_P(( + Connection *conn, Operation *op, + ber_int_t err, const char *matched, const char *text, + BerVarray refs, + LDAPControl **ctrls, + int nentries )); + +LDAP_SLAPD_F (int) send_search_reference LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, BerVarray refs, + LDAPControl **ctrls, + BerVarray *v2refs )); + +LDAP_SLAPD_F (int) send_search_entry LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, AttributeName *attrs, int attrsonly, + LDAPControl **ctrls )); + +LDAP_SLAPD_F (int) str2result LDAP_P(( char *s, + int *code, char **matched, char **info )); + +/* + * root_dse.c + */ +LDAP_SLAPD_F (int) root_dse_info LDAP_P(( + Connection *conn, + Entry **e, + const char **text )); -void send_ldap_result( Connection *conn, Operation *op, int err, char *matched, - char *text ); -void send_ldap_search_result( Connection *conn, Operation *op, int err, - char *matched, char *text, int nentries ); -void close_connection( Connection *conn, int opconnid, int opid ); +LDAP_SLAPD_F (int) read_root_dse_file LDAP_P(( + const char *file)); + +/* + * sasl.c + */ +LDAP_SLAPD_F (int) slap_sasl_init(void); +LDAP_SLAPD_F (char *) slap_sasl_secprops( const char * ); +LDAP_SLAPD_F (int) slap_sasl_destroy(void); + +LDAP_SLAPD_F (int) slap_sasl_open( Connection *c ); +LDAP_SLAPD_F (char **) slap_sasl_mechs( Connection *c ); + +LDAP_SLAPD_F (int) slap_sasl_external( Connection *c, + slap_ssf_t ssf, /* relative strength of external security */ + const char *authid ); /* asserted authenication id */ + +LDAP_SLAPD_F (int) slap_sasl_reset( Connection *c ); +LDAP_SLAPD_F (int) slap_sasl_close( Connection *c ); + +LDAP_SLAPD_F (int) slap_sasl_bind LDAP_P(( + Connection *conn, Operation *op, + struct berval *dn, struct berval *ndn, + struct berval *cred, + struct berval *edn, slap_ssf_t *ssf )); + +/* + * saslauthz.c + */ +LDAP_SLAPD_F (void) slap_sasl2dn LDAP_P(( + struct berval *saslname, + struct berval *dn )); +LDAP_SLAPD_F (int) slap_sasl_authorized LDAP_P(( + struct berval *authcid, + struct berval *authzid )); +LDAP_SLAPD_F (int) slap_sasl_regexp_config LDAP_P(( + const char *match, const char *replace )); /* * schema.c */ +LDAP_SLAPD_F (int) schema_info LDAP_P(( Entry **entry, const char **text )); + +/* + * schema_check.c + */ +LDAP_SLAPD_F( int ) oc_check_allowed( + AttributeType *type, + BerVarray oclist, + ObjectClass *sc ); + +LDAP_SLAPD_F( int ) structural_class( + BerVarray ocs, + struct berval *scbv, + ObjectClass **sc, + const char **text, + char *textbuf, size_t textlen ); + +LDAP_SLAPD_F( int ) entry_schema_check( + Backend *be, Entry *e, Attribute *attrs, + const char** text, + char *textbuf, size_t textlen ); + +LDAP_SLAPD_F( int ) mods_structural_class( + Modifications *mods, + struct berval *oc, + const char** text, + char *textbuf, size_t textlen ); + +/* + * schema_init.c + */ +LDAP_SLAPD_V( int ) schema_init_done; +LDAP_SLAPD_F (int) slap_schema_init LDAP_P((void)); +LDAP_SLAPD_F (void) schema_destroy LDAP_P(( void )); -int oc_schema_check( Entry *e ); +/* + * schema_prep.c + */ +LDAP_SLAPD_V( struct slap_internal_schema ) slap_schema; +LDAP_SLAPD_F (int) slap_schema_load LDAP_P((void)); +LDAP_SLAPD_F (int) slap_schema_check LDAP_P((void)); /* * schemaparse.c */ +LDAP_SLAPD_F( int ) slap_valid_descr( const char * ); -void parse_oc( Backend *be, char *fname, int lineno, int argc, char **argv ); +LDAP_SLAPD_F (int) parse_oc_old LDAP_P(( + Backend *be, const char *fname, int lineno, int argc, char **argv )); +LDAP_SLAPD_F (int) parse_oc LDAP_P(( + const char *fname, int lineno, char *line, char **argv )); +LDAP_SLAPD_F (int) parse_at LDAP_P(( + const char *fname, int lineno, char *line, char **argv )); +LDAP_SLAPD_F (char *) scherr2str LDAP_P((int code)) LDAP_GCCATTR((const)); +LDAP_SLAPD_F (int) dscompare LDAP_P(( const char *s1, const char *s2del, + char delim )); + +/* + * starttls.c + */ +LDAP_SLAPD_F (SLAP_EXTOP_MAIN_FN) starttls_extop; /* * str2filter.c */ +LDAP_SLAPD_F (Filter *) str2filter LDAP_P(( const char *str )); + +/* + * suffixalias.c + */ +LDAP_SLAPD_F (void) suffix_alias LDAP_P(( Backend *be, struct berval *ndn )); + +/* syntax.c */ +LDAP_SLAPD_F (Syntax *) syn_find LDAP_P(( + const char *synname )); +LDAP_SLAPD_F (Syntax *) syn_find_desc LDAP_P(( + const char *syndesc, int *slen )); +#ifdef SLAPD_BINARY_CONVERSION +LDAP_SLAPD_F (int) syn_add LDAP_P(( + LDAPSyntax *syn, + unsigned flags, + slap_syntax_validate_func *validate, + slap_syntax_transform_func *normalize, + slap_syntax_transform_func *pretty, + slap_syntax_transform_func *ber2str, + slap_syntax_transform_func *str2ber, + const char **err )); +#else +LDAP_SLAPD_F (int) syn_add LDAP_P(( + LDAPSyntax *syn, + unsigned flags, + slap_syntax_validate_func *validate, + slap_syntax_transform_func *normalize, + slap_syntax_transform_func *pretty, + const char **err )); +#endif +LDAP_SLAPD_F (void) syn_destroy LDAP_P(( void )); + +LDAP_SLAPD_F (int) register_syntax LDAP_P(( + const char *desc, + unsigned flags, + slap_syntax_validate_func *validate, + slap_syntax_transform_func *normalize, + slap_syntax_transform_func *pretty )); + +LDAP_SLAPD_F (int) syn_schema_info( Entry *e ); -Filter * str2filter( char *str ); +/* + * user.c + */ +#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H) +LDAP_SLAPD_F (void) slap_init_user LDAP_P(( char *username, char *groupname )); +#endif /* * value.c */ +LDAP_SLAPD_F (int) value_validate LDAP_P(( + MatchingRule *mr, + struct berval *in, + const char ** text )); +LDAP_SLAPD_F (int) value_normalize LDAP_P(( + AttributeDescription *ad, + unsigned usage, + struct berval *in, + struct berval *out, + const char ** text )); +LDAP_SLAPD_F (int) value_validate_normalize LDAP_P(( + AttributeDescription *ad, + unsigned usage, + struct berval *in, + struct berval *out, + const char ** text )); +LDAP_SLAPD_F (int) value_match LDAP_P(( + int *match, + AttributeDescription *ad, + MatchingRule *mr, + unsigned flags, + struct berval *v1, + void *v2, + const char ** text )); +#define value_find(ad,values,value) (value_find_ex((ad),0,(values),(value))) +LDAP_SLAPD_F (int) value_find_ex LDAP_P(( + AttributeDescription *ad, + unsigned flags, + BerVarray values, + struct berval *value )); +LDAP_SLAPD_F (int) value_add LDAP_P(( + BerVarray *vals, + BerVarray addvals )); + +/* + * Other... + */ +LDAP_SLAPD_V(unsigned) num_subordinates; + +LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming; +LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming_auth; + +LDAP_SLAPD_V (slap_mask_t) global_restrictops; +LDAP_SLAPD_V (slap_mask_t) global_allows; +LDAP_SLAPD_V (slap_mask_t) global_disallows; +LDAP_SLAPD_V (slap_mask_t) global_requires; +LDAP_SLAPD_V (slap_ssf_set_t) global_ssf_set; + +LDAP_SLAPD_V (BerVarray) default_referral; +LDAP_SLAPD_V (char *) replogfile; +LDAP_SLAPD_V (const char) Versionstr[]; +LDAP_SLAPD_V (struct slap_limits_set) deflimit; + +LDAP_SLAPD_V (slap_access_t) global_default_access; +LDAP_SLAPD_V (int) global_idletimeout; +LDAP_SLAPD_V (int) global_schemacheck; +LDAP_SLAPD_V (char *) global_host; +LDAP_SLAPD_V (char *) global_realm; +LDAP_SLAPD_V (int) sasl_external_x509dn_convert; +LDAP_SLAPD_V (char *) default_passwd_hash; +LDAP_SLAPD_V (int) lber_debug; +LDAP_SLAPD_V (int) ldap_syslog; +LDAP_SLAPD_V (struct berval) default_search_base; +LDAP_SLAPD_V (struct berval) default_search_nbase; + +LDAP_SLAPD_V (int) nSaslRegexp; +LDAP_SLAPD_V (SaslRegexp_t*) SaslRegexp; + +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) num_sent_mutex; +LDAP_SLAPD_V (unsigned long) num_bytes_sent; +LDAP_SLAPD_V (unsigned long) num_pdu_sent; +LDAP_SLAPD_V (unsigned long) num_entries_sent; +LDAP_SLAPD_V (unsigned long) num_refs_sent; + +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) num_ops_mutex; +LDAP_SLAPD_V (unsigned long) num_ops_completed; +LDAP_SLAPD_V (unsigned long) num_ops_initiated; +#ifdef SLAPD_MONITOR +LDAP_SLAPD_V (unsigned long) num_ops_completed_[SLAP_OP_LAST]; +LDAP_SLAPD_V (unsigned long) num_ops_initiated_[SLAP_OP_LAST]; +#endif /* SLAPD_MONITOR */ + +LDAP_SLAPD_V (char *) slapd_pid_file; +LDAP_SLAPD_V (char *) slapd_args_file; +LDAP_SLAPD_V (time_t) starttime; + +/* use time(3) -- no mutex */ +#define slap_get_time() time( NULL ) + +LDAP_SLAPD_V (ldap_pvt_thread_pool_t) connection_pool; +LDAP_SLAPD_V (int) connection_pool_max; + +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) entry2str_mutex; +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) replog_mutex; + +#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) passwd_mutex; +#endif +LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) gmtime_mutex; + +LDAP_SLAPD_V (AccessControl *) global_acl; + +LDAP_SLAPD_V (ber_socket_t) dtblsize; + +LDAP_SLAPD_V (int) use_reverse_lookup; + +/* + * operations + */ +LDAP_SLAPD_F (int) do_abandon LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_add LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_bind LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_compare LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_delete LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_modify LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_modrdn LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_search LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_unbind LDAP_P((Connection *conn, Operation *op)); +LDAP_SLAPD_F (int) do_extended LDAP_P((Connection *conn, Operation *op)); + +LDAP_END_DECL -int value_add_fast( struct berval ***vals, struct berval **addvals, int nvals, - int naddvals, int *maxvals ); -int value_add( struct berval ***vals, struct berval **addvals ); -void value_normalize( char *s, int syntax ); -int value_cmp( struct berval *v1, struct berval *v2, int syntax, - int normalize ); -int value_ncmp( struct berval *v1, struct berval *v2, int syntax, int len, - int normalize ); -int value_find( struct berval **vals, struct berval *v, int syntax, - int normalize ); +#endif /* PROTO_SLAP_H */ -#endif /* _proto_slap */ diff --git a/servers/slapd/referral.c b/servers/slapd/referral.c new file mode 100644 index 0000000000000000000000000000000000000000..d3caa3ffd4a0c39c767160ae4fc48ea1f04d1a92 --- /dev/null +++ b/servers/slapd/referral.c @@ -0,0 +1,342 @@ +/* referral.c - muck with referrals */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include <ldap_pvt.h> + +#include "slap.h" + +/* + * This routine generates the DN appropriate to return in + * an LDAP referral. + */ +static char * referral_dn_muck( + const char * refDN, + const char * baseDN, + const char * targetDN ) +{ + int rc; + struct berval bvin; + struct berval nrefDN = { 0, NULL }; + struct berval nbaseDN = { 0, NULL }; + struct berval ntargetDN = { 0, NULL }; + + if( !baseDN ) { + /* no base, return target */ + return targetDN ? ch_strdup( targetDN ) : NULL; + } + + if( refDN ) { + bvin.bv_val = (char *)refDN; + bvin.bv_len = strlen( refDN ); + + rc = dnPretty2( NULL, &bvin, &nrefDN ); + if( rc != LDAP_SUCCESS ) { + /* Invalid refDN */ + return NULL; + } + } + + if( !targetDN ) { + /* continuation reference + * if refDN present return refDN + * else return baseDN + */ + return nrefDN.bv_len ? nrefDN.bv_val : ch_strdup( baseDN ); + } + + bvin.bv_val = (char *)targetDN; + bvin.bv_len = strlen( targetDN ); + + rc = dnPretty2( NULL, &bvin, &ntargetDN ); + if( rc != LDAP_SUCCESS ) { + /* Invalid targetDN */ + ch_free( nrefDN.bv_val ); + return NULL; + } + + if( nrefDN.bv_len ) { + bvin.bv_val = (char *)baseDN; + bvin.bv_len = strlen( baseDN ); + + rc = dnPretty2( NULL, &bvin, &nbaseDN ); + if( rc != LDAP_SUCCESS ) { + /* Invalid baseDN */ + ch_free( nrefDN.bv_val ); + ch_free( ntargetDN.bv_val ); + return NULL; + } + + if( dn_match( &nbaseDN, &nrefDN ) == 0 ) { + ch_free( nrefDN.bv_val ); + ch_free( nbaseDN.bv_val ); + return ntargetDN.bv_val; + } + + { + struct berval muck; + + if( ntargetDN.bv_len < nbaseDN.bv_len ) { + ch_free( nrefDN.bv_val ); + ch_free( nbaseDN.bv_val ); + return ntargetDN.bv_val; + } + + rc = strcasecmp( + &ntargetDN.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], + nbaseDN.bv_val ); + if( rc ) { + /* target not subordinate to base */ + ch_free( nrefDN.bv_val ); + ch_free( nbaseDN.bv_val ); + return ntargetDN.bv_val; + } + + muck.bv_len = ntargetDN.bv_len + nrefDN.bv_len - nbaseDN.bv_len; + muck.bv_val = ch_malloc( muck.bv_len + 1 ); + + strncpy( muck.bv_val, ntargetDN.bv_val, + ntargetDN.bv_len-nbaseDN.bv_len ); + strcpy( &muck.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], + nrefDN.bv_val ); + + ch_free( nrefDN.bv_val ); + ch_free( nbaseDN.bv_val ); + ch_free( ntargetDN.bv_val ); + + return muck.bv_val; + } + } + + ch_free( nrefDN.bv_val ); + return ntargetDN.bv_val; +} + + +/* validate URL for global referral use + * LDAP URLs must not have: + * DN, attrs, scope, nor filter + * Any non-LDAP URL is okay + * + * XXYYZ: should return an error string + */ +int validate_global_referral( const char *url ) +{ + int rc; + LDAPURLDesc *lurl; + + rc = ldap_url_parse_ext( url, &lurl ); + + switch( rc ) { + case LDAP_URL_SUCCESS: + break; + + case LDAP_URL_ERR_BADSCHEME: + /* not LDAP hence valid */ + return 0; + + default: + /* other error, bail */ +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: invalid URL (%s): %s (%d)\n", + url, "" /* ldap_url_error2str(rc) */, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: invalid URL (%s): %s (%d)\n", + url, "" /* ldap_url_error2str(rc) */, rc ); +#endif + return 1; + } + + rc = 0; + + if( lurl->lud_dn && *lurl->lud_dn ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains DN\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains DN\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_attrs ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): requests attributes\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): requests attributes\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains explicit scope\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains explicit scope\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_filter ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains explicit filter\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains explicit filter\n", + url, 0, 0 ); +#endif + rc = 1; + } + + ldap_free_urldesc( lurl ); + return rc; +} + +BerVarray referral_rewrite( + BerVarray in, + struct berval *base, + struct berval *target, + int scope ) +{ + int i; + BerVarray refs; + struct berval *iv, *jv; + + if( in == NULL ) return NULL; + + for( i=0; in[i].bv_val != NULL ; i++ ) { + /* just count them */ + } + + if( i < 1 ) return NULL; + + refs = ch_malloc( (i+1) * sizeof( struct berval ) ); + + for( iv=in,jv=refs; iv->bv_val != NULL ; iv++ ) { + LDAPURLDesc *url; + int rc = ldap_url_parse_ext( iv->bv_val, &url ); + + if( rc == LDAP_URL_ERR_BADSCHEME ) { + ber_dupbv( jv++, iv ); + continue; + + } else if( rc != LDAP_URL_SUCCESS ) { + continue; + } + + { + char *dn = url->lud_dn; + url->lud_dn = referral_dn_muck( + ( dn && *dn ) ? dn : NULL, + base ? base->bv_val : NULL, + target ? target->bv_val : NULL ); + + ldap_memfree( dn ); + } + + if( url->lud_scope == LDAP_SCOPE_DEFAULT ) { + url->lud_scope = scope; + } + + jv->bv_val = ldap_url_desc2str( url ); + jv->bv_len = strlen( jv->bv_val ); + + ldap_free_urldesc( url ); + jv++; + } + + if( jv == refs ) { + ch_free( refs ); + refs = NULL; + + } else { + jv->bv_val = NULL; + } + + return refs; +} + + +BerVarray get_entry_referrals( + Backend *be, + Connection *conn, + Operation *op, + Entry *e ) +{ + Attribute *attr; + BerVarray refs; + unsigned i; + struct berval *iv, *jv; + + AttributeDescription *ad_ref = slap_schema.si_ad_ref; + + attr = attr_find( e->e_attrs, ad_ref ); + + if( attr == NULL ) return NULL; + + for( i=0; attr->a_vals[i].bv_val != NULL; i++ ) { + /* count references */ + } + + if( i < 1 ) return NULL; + + refs = ch_malloc( (i + 1) * sizeof(struct berval)); + + for( iv=attr->a_vals, jv=refs; iv->bv_val != NULL; iv++ ) { + unsigned k; + ber_dupbv( jv, iv ); + + /* trim the label */ + for( k=0; k<jv->bv_len; k++ ) { + if( isspace(jv->bv_val[k]) ) { + jv->bv_val[k] = '\0'; + jv->bv_len = k; + break; + } + } + + if( jv->bv_len > 0 ) { + jv++; + } else { + free( jv->bv_val ); + } + } + + if( jv == refs ) { + free( refs ); + refs = NULL; + + } else { + jv->bv_val = NULL; + } + + /* we should check that a referral value exists... */ + return refs; +} + diff --git a/servers/slapd/repl.c b/servers/slapd/repl.c index 028b1919620527b5bbaa26a9d4188e855028c9a5..6f2b3ac262dd11923036fa8fa83aca188e0adc29 100644 --- a/servers/slapd/repl.c +++ b/servers/slapd/repl.c @@ -1,94 +1,321 @@ /* repl.c - log modifications for replication purposes */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> + +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/socket.h> + +#ifdef HAVE_SYS_FILE_H #include <sys/file.h> -#include <sys/socket.h> -#include <slap.h> +#endif + +#include "slap.h" +#include "ldif.h" + +int +add_replica_info( + Backend *be, + const char *host +) +{ + int i = 0; + + assert( be ); + assert( host ); + + if ( be->be_replica != NULL ) { + for ( ; be->be_replica[ i ] != NULL; i++ ); + } + + be->be_replica = ch_realloc( be->be_replica, + sizeof( struct slap_replica_info * )*( i + 2 ) ); + + be->be_replica[ i ] + = ch_calloc( sizeof( struct slap_replica_info ), 1 ); + be->be_replica[ i ]->ri_host = ch_strdup( host ); + be->be_replica[ i ]->ri_nsuffix = NULL; + be->be_replica[ i ]->ri_attrs = NULL; + be->be_replica[ i + 1 ] = NULL; + + return( i ); +} + +int +add_replica_suffix( + Backend *be, + int nr, + const char *suffix +) +{ + struct berval dn, *ndn = NULL; + int rc; + + dn.bv_val = (char *) suffix; + dn.bv_len = strlen( dn.bv_val ); + + rc = dnNormalize( NULL, &dn, &ndn ); + if( rc != LDAP_SUCCESS ) { + return 2; + } + + if ( select_backend( ndn, 0, 0 ) != be ) { + ber_bvfree( ndn ); + return 1; + } + + ber_bvecadd( &be->be_replica[nr]->ri_nsuffix, ndn ); + return 0; +} -extern pthread_mutex_t replog_mutex; -extern pthread_mutex_t entry2str_mutex; -extern time_t currenttime; -extern char *replogfile; +int +add_replica_attrs( + Backend *be, + int nr, + char *attrs, + int exclude +) +{ + if ( be->be_replica[nr]->ri_attrs != NULL ) { + if ( be->be_replica[nr]->ri_exclude != exclude ) { + fprintf( stderr, "attr selective replication directive '%s' conflicts with previous one (discarded)\n", attrs ); + ch_free( be->be_replica[nr]->ri_attrs ); + be->be_replica[nr]->ri_attrs = NULL; + } + } -extern FILE *lock_fopen(); -extern int lock_fclose(); -extern char *ch_malloc(); -extern char *entry2str(); + be->be_replica[nr]->ri_exclude = exclude; + be->be_replica[nr]->ri_attrs = str2anlist( be->be_replica[nr]->ri_attrs, + attrs, "," ); + return ( be->be_replica[nr]->ri_attrs == NULL ); +} + +static void +print_vals( FILE *fp, struct berval *type, struct berval *bv ); +static void +replog1( struct slap_replica_info *ri, Operation *op, void *change, FILE *fp, void *first); void replog( Backend *be, - int optype, - char *dn, - void *change, - int flag + Operation *op, + struct berval *dn, + struct berval *ndn, + void *change ) { - LDAPMod *mods; + Modifications *ml = NULL; + Attribute *a = NULL; Entry *e; - char *newrdn, *tmp; - int deleteoldrdn; FILE *fp, *lfp; - int len, i; + int i; +/* undef NO_LOG_WHEN_NO_REPLICAS */ +#ifdef NO_LOG_WHEN_NO_REPLICAS + int count = 0; +#endif + int subsets = 0; + long now = slap_get_time(); if ( be->be_replogfile == NULL && replogfile == NULL ) { return; } - pthread_mutex_lock( &replog_mutex ); + ldap_pvt_thread_mutex_lock( &replog_mutex ); if ( (fp = lock_fopen( be->be_replogfile ? be->be_replogfile : replogfile, "a", &lfp )) == NULL ) { - pthread_mutex_unlock( &replog_mutex ); + ldap_pvt_thread_mutex_unlock( &replog_mutex ); return; } - for ( i = 0; be->be_replica != NULL && be->be_replica[i] != NULL; - i++ ) { - fprintf( fp, "replica: %s\n", be->be_replica[i] ); + for ( i = 0; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) { + /* check if dn's suffix matches legal suffixes, if any */ + if ( be->be_replica[i]->ri_nsuffix != NULL ) { + int j; + + for ( j = 0; be->be_replica[i]->ri_nsuffix[j]; j++ ) { + if ( dnIsSuffix( ndn, be->be_replica[i]->ri_nsuffix[j] ) ) { + break; + } + } + + if ( !be->be_replica[i]->ri_nsuffix[j] ) { + /* do not add "replica:" line */ + continue; + } + } + /* See if we only want a subset of attributes */ + if ( be->be_replica[i]->ri_attrs != NULL && + ( op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD || op->o_tag == LDAP_REQ_EXTENDED ) ) { + if ( !subsets ) { + subsets = i + 1; + } + /* Do attribute subsets by themselves in a second pass */ + continue; + } + + fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host ); +#ifdef NO_LOG_WHEN_NO_REPLICAS + ++count; +#endif } - fprintf( fp, "time: %ld\n", currenttime ); - fprintf( fp, "dn: %s\n", dn ); - switch ( optype ) { - case LDAP_REQ_MODIFY: - fprintf( fp, "changetype: modify\n" ); - mods = change; - for ( ; mods != NULL; mods = mods->mod_next ) { - switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) { - case LDAP_MOD_ADD: - fprintf( fp, "add: %s\n", mods->mod_type ); - break; +#ifdef NO_LOG_WHEN_NO_REPLICAS + if ( count == 0 && subsets == 0 ) { + /* if no replicas matched, drop the log + * (should we log it anyway?) */ + lock_fclose( fp, lfp ); + ldap_pvt_thread_mutex_unlock( &replog_mutex ); - case LDAP_MOD_DELETE: - fprintf( fp, "delete: %s\n", mods->mod_type ); + return; + } +#endif + + fprintf( fp, "time: %ld\n", now ); + fprintf( fp, "dn: %s\n", dn->bv_val ); + + replog1( NULL, op, change, fp, NULL ); + + if ( subsets > 0 ) { + void *first; + for ( i = subsets - 1; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) { + + /* If no attrs, we already did this above */ + if ( be->be_replica[i]->ri_attrs == NULL ) { + continue; + } + + /* check if dn's suffix matches legal suffixes, if any */ + if ( be->be_replica[i]->ri_nsuffix != NULL ) { + int j; + + for ( j = 0; be->be_replica[i]->ri_nsuffix[j]; j++ ) { + if ( dnIsSuffix( ndn, be->be_replica[i]->ri_nsuffix[j] ) ) { + break; + } + } + + if ( !be->be_replica[i]->ri_nsuffix[j] ) { + /* do not add "replica:" line */ + continue; + } + } + subsets = 0; + first = NULL; + switch( op->o_tag ) { + case LDAP_REQ_EXTENDED: + /* quick hack for extended operations */ + /* assume change parameter is a Modfications* */ + /* fall thru */ + case LDAP_REQ_MODIFY: + for ( ml = change; ml != NULL; ml = ml->sml_next ) { + int is_in, exclude; + + is_in = ad_inlist( ml->sml_desc, be->be_replica[i]->ri_attrs ); + exclude = be->be_replica[i]->ri_exclude; + + /* + * there might be a more clever way to do this test, + * but this way, at least, is comprehensible :) + */ + if ( ( is_in && !exclude ) || ( !is_in && exclude ) ) { + subsets = 1; + first = ml; + break; + } + } + if ( !subsets ) { + continue; + } break; + case LDAP_REQ_ADD: + e = change; + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { + int is_in, exclude; - case LDAP_MOD_REPLACE: - fprintf( fp, "replace: %s\n", mods->mod_type ); + is_in = ad_inlist( a->a_desc, be->be_replica[i]->ri_attrs ); + exclude = be->be_replica[i]->ri_exclude; + + if ( ( is_in && !exclude ) || ( !is_in && exclude ) ) { + subsets = 1; + first = a; + break; + } + } + if ( !subsets ) { + continue; + } break; + default: + /* Other operations were logged in the first pass */ + continue; } + fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host ); + fprintf( fp, "time: %ld\n", now ); + fprintf( fp, "dn: %s\n", dn->bv_val ); + replog1( be->be_replica[i], op, change, fp, first ); + } + } - for ( i = 0; mods->mod_bvalues != NULL && - mods->mod_bvalues[i] != NULL; i++ ) { - char *buf, *bufp; + lock_fclose( fp, lfp ); + ldap_pvt_thread_mutex_unlock( &replog_mutex ); +} - len = strlen( mods->mod_type ); - len = LDIF_SIZE_NEEDED( len, - mods->mod_bvalues[i]->bv_len ) + 1; - buf = ch_malloc( len ); - bufp = buf; - put_type_and_value( &bufp, mods->mod_type, - mods->mod_bvalues[i]->bv_val, - mods->mod_bvalues[i]->bv_len ); - *bufp = '\0'; +static void +replog1( + struct slap_replica_info *ri, + Operation *op, + void *change, + FILE *fp, + void *first +) +{ + Modifications *ml; + Attribute *a; + Entry *e; + struct slap_replog_moddn *moddn; - fputs( buf, fp ); + switch ( op->o_tag ) { + case LDAP_REQ_EXTENDED: + /* quick hack for extended operations */ + /* assume change parameter is a Modfications* */ + /* fall thru */ - free( buf ); + case LDAP_REQ_MODIFY: + fprintf( fp, "changetype: modify\n" ); + ml = first ? first : change; + for ( ; ml != NULL; ml = ml->sml_next ) { + char *type; + if ( ri && ri->ri_attrs ) { + int is_in = ad_inlist( ml->sml_desc, ri->ri_attrs ); + + if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) { + continue; + } } + type = ml->sml_desc->ad_cname.bv_val; + switch ( ml->sml_op ) { + case LDAP_MOD_ADD: + fprintf( fp, "add: %s\n", type ); + break; + + case LDAP_MOD_DELETE: + fprintf( fp, "delete: %s\n", type ); + break; + + case LDAP_MOD_REPLACE: + fprintf( fp, "replace: %s\n", type ); + break; + } + if ( ml->sml_bvalues ) + print_vals( fp, &ml->sml_desc->ad_cname, ml->sml_bvalues ); fprintf( fp, "-\n" ); } break; @@ -96,15 +323,43 @@ replog( case LDAP_REQ_ADD: e = change; fprintf( fp, "changetype: add\n" ); - pthread_mutex_lock( &entry2str_mutex ); - tmp = entry2str( e, &len, 0 ); - while ( (tmp = strchr( tmp, '\n' )) != NULL ) { - tmp++; - if ( ! isspace( *tmp ) ) - break; + a = first ? first : e->e_attrs; + for ( ; a != NULL; a=a->a_next ) { + if ( ri && ri->ri_attrs ) { + int is_in = ad_inlist( a->a_desc, ri->ri_attrs ); + if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) { + continue; + } + /* If the list includes objectClass names, + * only include those classes in the + * objectClass attribute + */ + if ( a->a_desc == slap_schema.si_ad_objectClass ) { + int ocs = 0; + AttributeName *an; + struct berval vals[2]; + vals[1].bv_val = NULL; + vals[1].bv_len = 0; + for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) { + if ( an->an_oc ) { + int i; + for ( i=0; a->a_vals[i].bv_val; i++ ) { + if ( a->a_vals[i].bv_len == an->an_name.bv_len + && !strcasecmp(a->a_vals[i].bv_val, + an->an_name.bv_val ) ) { + ocs = 1; + vals[0] = an->an_name; + print_vals( fp, &a->a_desc->ad_cname, vals ); + break; + } + } + } + } + if ( ocs ) continue; + } + } + print_vals( fp, &a->a_desc->ad_cname, a->a_vals ); } - fprintf( fp, "%s", tmp ); - pthread_mutex_unlock( &entry2str_mutex ); break; case LDAP_REQ_DELETE: @@ -112,13 +367,42 @@ replog( break; case LDAP_REQ_MODRDN: - newrdn = change; + moddn = change; fprintf( fp, "changetype: modrdn\n" ); - fprintf( fp, "newrdn: %s\n", newrdn ); - fprintf( fp, "deleteoldrdn: %d\n", flag ? 1 : 0 ); + fprintf( fp, "newrdn: %s\n", moddn->newrdn->bv_val ); + fprintf( fp, "deleteoldrdn: %d\n", moddn->deloldrdn ? 1 : 0 ); + if( moddn->newsup != NULL ) { + fprintf( fp, "newsuperior: %s\n", moddn->newsup->bv_val ); + } } fprintf( fp, "\n" ); +} - lock_fclose( fp, lfp ); - pthread_mutex_unlock( &replog_mutex ); +static void +print_vals( + FILE *fp, + struct berval *type, + struct berval *bv ) +{ + ber_len_t i, len; + char *buf, *bufp; + + for ( i = 0, len = 0; bv && bv[i].bv_val; i++ ) { + if ( bv[i].bv_len > len ) + len = bv[i].bv_len; + } + + len = LDIF_SIZE_NEEDED( type->bv_len, len ) + 1; + buf = (char *) ch_malloc( len ); + + for ( ; bv && bv->bv_val; bv++ ) { + bufp = buf; + ldif_sput( &bufp, LDIF_PUT_VALUE, type->bv_val, + bv->bv_val, bv->bv_len ); + *bufp = '\0'; + + fputs( buf, fp ); + + } + free( buf ); } diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0ef82a7b3e36e03f85a4a71a91040153fe182064..8c96ff0239683f6f1b0d69de9297b65ec2e695af 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -1,50 +1,85 @@ /* result.c - routines to send ldap results, errors, and referrals */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ -#include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> -#include <signal.h> #include "portable.h" + +#include <stdio.h> + +#include <ac/socket.h> +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/time.h> +#include <ac/unistd.h> + #include "slap.h" -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; -#endif -extern int active_threads; -extern pthread_mutex_t active_threads_mutex; -extern pthread_mutex_t new_conn_mutex; -extern pthread_t listener_tid; -extern struct acl *acl_get_applicable(); -extern long num_entries_sent; -extern long num_bytes_sent; -extern pthread_mutex_t num_sent_mutex; +static char *v2ref( BerVarray ref, const char *text ) +{ + size_t len = 0, i = 0; + char *v2; + + if(ref == NULL) { + if (text) { + return ch_strdup(text); + } else { + return NULL; + } + } + + if ( text != NULL ) { + len = strlen( text ); + if (text[len-1] != '\n') { + i = 1; + } + } -void close_connection(); + v2 = ch_malloc( len+i+sizeof("Referral:") ); + if( text != NULL ) { + strcpy(v2, text); + if( i ) { + v2[len++] = '\n'; + } + } + strcpy( v2+len, "Referral:" ); + len += sizeof("Referral:"); -static void -send_ldap_result2( - Connection *conn, - Operation *op, - int err, - char *matched, - char *text, - int nentries -) + for( i=0; ref[i].bv_val != NULL; i++ ) { + v2 = ch_realloc( v2, len + ref[i].bv_len + 1 ); + v2[len-1] = '\n'; + AC_MEMCPY(&v2[len], ref[i].bv_val, ref[i].bv_len ); + len += ref[i].bv_len; + if (ref[i].bv_val[ref[i].bv_len-1] != '/') { + ++len; + } + } + + v2[len-1] = '\0'; + return v2; +} + +static ber_tag_t req2res( ber_tag_t tag ) { - BerElement *ber; - int rc, sd; - unsigned long tag, bytes; + switch( tag ) { + case LDAP_REQ_ADD: + case LDAP_REQ_BIND: + case LDAP_REQ_COMPARE: + case LDAP_REQ_EXTENDED: + case LDAP_REQ_MODIFY: + case LDAP_REQ_MODRDN: + tag++; + break; - Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", err, matched ? - matched : "", text ? text : "" ); + case LDAP_REQ_DELETE: + tag = LDAP_RES_DELETE; + break; - switch ( op->o_tag ) { - case LBER_DEFAULT: + case LDAP_REQ_ABANDON: + case LDAP_REQ_UNBIND: tag = LBER_SEQUENCE; break; @@ -52,312 +87,1051 @@ send_ldap_result2( tag = LDAP_RES_SEARCH_RESULT; break; - case LDAP_REQ_DELETE: - tag = LDAP_RES_DELETE; - break; - default: - tag = op->o_tag + 1; - break; + tag = LBER_SEQUENCE; } -#ifdef COMPAT30 - if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER )) - == NULLBER ) { -#else - if ( (ber = der_alloc()) == NULLBER ) { -#endif - Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - return; - } + return tag; +} -#ifdef CLDAP - if ( op->o_cldap ) { - rc = ber_printf( ber, "{is{t{ess}}}", op->o_msgid, "", tag, - err, matched ? matched : "", text ? text : "" ); - } else -#endif -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - rc = ber_printf( ber, "{it{{ess}}}", op->o_msgid, tag, err, - matched ? matched : "", text ? text : "" ); - } else -#endif - rc = ber_printf( ber, "{it{ess}}", op->o_msgid, tag, err, - matched ? matched : "", text ? text : "" ); +static long send_ldap_ber( + Connection *conn, + BerElement *ber ) +{ + ber_len_t bytes; - if ( rc == -1 ) { - Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - return; - } + ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes ); /* write only one pdu at a time - wait til it's our turn */ - pthread_mutex_lock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_lock( &conn->c_write_mutex ); + + /* lock the connection */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); /* write the pdu */ - bytes = ber->ber_ptr - ber->ber_buf; - pthread_mutex_lock( &new_conn_mutex ); - while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber, - 1 ) != 0 ) { - pthread_mutex_unlock( &new_conn_mutex ); + while( 1 ) { + int err; + ber_socket_t sd; + + if ( connection_state_closing( conn ) ) { + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + + return 0; + } + + if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) { + break; + } + + err = errno; + /* * we got an error. if it's ewouldblock, we need to * wait on the socket being writable. otherwise, figure * it's a hard error and return. */ - Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] - : "unknown", 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_ldap_ber: conn %d ber_flush failed err=%d (%s)\n", + conn ? conn->c_connid : 0, err, sock_errstr(err) )); +#else + Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n", + err, sock_errstr(err), 0 ); +#endif + + if ( err != EWOULDBLOCK && err != EAGAIN ) { + connection_closing( conn ); - if ( errno != EWOULDBLOCK && errno != EAGAIN ) { - close_connection( conn, op->o_connid, op->o_opid ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - pthread_mutex_unlock( &conn->c_pdumutex ); - return; + return( -1 ); } /* wait for socket to be write-ready */ - pthread_mutex_lock( &active_threads_mutex ); - active_threads--; conn->c_writewaiter = 1; - pthread_kill( listener_tid, SIGUSR1 ); - pthread_cond_wait( &conn->c_wcv, &active_threads_mutex ); - pthread_mutex_unlock( &active_threads_mutex ); + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); + slapd_set_write( sd, 1 ); - pthread_yield(); - pthread_mutex_lock( &new_conn_mutex ); + ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); + conn->c_writewaiter = 0; } - pthread_mutex_unlock( &new_conn_mutex ); - pthread_mutex_unlock( &conn->c_pdumutex ); - pthread_mutex_lock( &num_sent_mutex ); - num_bytes_sent += bytes; - pthread_mutex_unlock( &num_sent_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - Statslog( LDAP_DEBUG_STATS, - "conn=%d op=%d RESULT err=%d tag=%d nentries=%d\n", conn->c_connid, - op->o_opid, err, tag, nentries ); + return bytes; +} + +static void +send_ldap_response( + Connection *conn, + Operation *op, + ber_tag_t tag, + ber_int_t msgid, + ber_int_t err, + const char *matched, + const char *text, + BerVarray ref, + const char *resoid, + struct berval *resdata, + struct berval *sasldata, + LDAPControl **ctrls +) +{ + char berbuf[256]; + BerElement *ber = (BerElement *)berbuf; + int rc; + long bytes; + + if (op->o_callback && op->o_callback->sc_response) { + op->o_callback->sc_response( conn, op, tag, msgid, err, matched, + text, ref, resoid, resdata, sasldata, ctrls ); + return; + } + + assert( ctrls == NULL ); /* ctrls not implemented */ + + ber_init_w_nullc( ber, LBER_USE_DER ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_ldap_response: conn %d msgid=%ld tag=%ld err=%ld\n", + conn ? conn->c_connid : 0, (long)msgid, (long)tag, (long)err )); +#else + Debug( LDAP_DEBUG_TRACE, + "send_ldap_response: msgid=%ld tag=%ld err=%ld\n", + (long) msgid, (long) tag, (long) err ); +#endif + + if( ref ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "send_ldap_response: conn %d ref=\"%s\"\n", + conn ? conn->c_connid : 0, + ref[0].bv_val ? ref[0].bv_val : "NULL" )); +#else + Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n", + ref[0].bv_val ? ref[0].bv_val : "NULL", + NULL, NULL ); +#endif + + } + +#ifdef LDAP_CONNECTIONLESS + if (conn->c_is_udp) { + rc = ber_write(ber, (char *)&op->o_peeraddr, sizeof(struct sockaddr), 0); + if (rc != sizeof(struct sockaddr)) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_ldap_response: conn %d ber_write failed\n", + conn ? conn->c_connid : 0 )); +#else + Debug( LDAP_DEBUG_ANY, "ber_write failed\n", 0, 0, 0 ); +#endif + ber_free_buf( ber ); + return; + } + } + if (conn->c_is_udp && op->o_protocol == LDAP_VERSION2) { + rc = ber_printf( ber, "{is{t{ess", + msgid, "", tag, err, + matched == NULL ? "" : matched, + text == NULL ? "" : text ); + } else +#endif + { + rc = ber_printf( ber, "{it{ess", + msgid, tag, err, + matched == NULL ? "" : matched, + text == NULL ? "" : text ); + } + + if( rc != -1 ) { + if ( ref != NULL ) { + assert( err == LDAP_REFERRAL ); + rc = ber_printf( ber, "t{W}", + LDAP_TAG_REFERRAL, ref ); + } else { + assert( err != LDAP_REFERRAL ); + } + } + + if( rc != -1 && sasldata != NULL ) { + rc = ber_printf( ber, "tO", + LDAP_TAG_SASL_RES_CREDS, sasldata ); + } + + if( rc != -1 && resoid != NULL ) { + rc = ber_printf( ber, "ts", + LDAP_TAG_EXOP_RES_OID, resoid ); + } + if( rc != -1 && resdata != NULL ) { + rc = ber_printf( ber, "tO", + LDAP_TAG_EXOP_RES_VALUE, resdata ); + } + + if( rc != -1 ) { + rc = ber_printf( ber, "N}N}" ); + } +#ifdef LDAP_CONNECTIONLESS + if( conn->c_is_udp && op->o_protocol == LDAP_VERSION2 && rc != -1 ) { + rc = ber_printf( ber, "N}" ); + } +#endif + + if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_ldap_response: conn %d ber_printf failed\n", + conn ? conn->c_connid : 0 )); +#else + Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); +#endif + + ber_free_buf( ber ); + return; + } + + /* send BER */ + bytes = send_ldap_ber( conn, ber ); + ber_free_buf( ber ); + + if ( bytes < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_ldap_response: conn %d ber write failed\n", + conn ? conn->c_connid : 0 )); +#else + Debug( LDAP_DEBUG_ANY, + "send_ldap_response: ber write failed\n", + 0, 0, 0 ); +#endif + + return; + } + + ldap_pvt_thread_mutex_lock( &num_sent_mutex ); + num_bytes_sent += bytes; + num_pdu_sent++; + ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); return; } + +void +send_ldap_disconnect( + Connection *conn, + Operation *op, + ber_int_t err, + const char *text +) +{ + ber_tag_t tag; + ber_int_t msgid; + char *reqoid; + +#define LDAP_UNSOLICITED_ERROR(e) \ + ( (e) == LDAP_PROTOCOL_ERROR \ + || (e) == LDAP_STRONG_AUTH_REQUIRED \ + || (e) == LDAP_UNAVAILABLE ) + + assert( LDAP_UNSOLICITED_ERROR( err ) ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_ldap_disconnect: conn %d %d:%s\n", + conn ? conn->c_connid : 0, err, text ? text : "" )); +#else + Debug( LDAP_DEBUG_TRACE, + "send_ldap_disconnect %d:%s\n", + err, text ? text : "", NULL ); +#endif + + + if ( op->o_protocol < LDAP_VERSION3 ) { + reqoid = NULL; + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + + } else { + reqoid = LDAP_NOTICE_DISCONNECT; + tag = LDAP_RES_EXTENDED; + msgid = 0; + } + + send_ldap_response( conn, op, tag, msgid, + err, NULL, text, NULL, + reqoid, NULL, NULL, NULL ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld DISCONNECT tag=%lu err=%ld text=%s\n", + (long) op->o_connid, (long) op->o_opid, + (unsigned long) tag, (long) err, text ? text : "" ); +} + void send_ldap_result( Connection *conn, Operation *op, - int err, - char *matched, - char *text + ber_int_t err, + const char *matched, + const char *text, + BerVarray ref, + LDAPControl **ctrls ) { -#ifdef CLDAP - if ( op->o_cldap ) { - SAFEMEMCPY( (char *)conn->c_sb.sb_useaddr, &op->o_clientaddr, - sizeof( struct sockaddr )); - Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", - inet_ntoa(((struct sockaddr_in *) - conn->c_sb.sb_useaddr)->sin_addr ), - ((struct sockaddr_in *) conn->c_sb.sb_useaddr)->sin_port, - 0 ); - } -#endif - send_ldap_result2( conn, op, err, matched, text, 0 ); + ber_tag_t tag; + ber_int_t msgid; + char *tmp = NULL; + + assert( !LDAP_API_ERROR( err ) ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_ldap_result : conn %ld op=%ld p=%d\n", + (long)op->o_connid, (long)op->o_opid, op->o_protocol )); +#else + Debug( LDAP_DEBUG_TRACE, + "send_ldap_result: conn=%ld op=%ld p=%d\n", + (long) op->o_connid, (long) op->o_opid, op->o_protocol ); +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "send_ldap_result: conn=%ld err=%d matched=\"%s\" text=\"%s\"\n", + (long)op->o_connid, err, matched ? matched : "", text ? text : "" )); +#else + Debug( LDAP_DEBUG_ARGS, + "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n", + err, matched ? matched : "", text ? text : "" ); +#endif + + + if( ref ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "send_ldap_result: referral=\"%s\"\n", + ref[0].bv_val ? ref[0].bv_val : "NULL" )); +#else + Debug( LDAP_DEBUG_ARGS, + "send_ldap_result: referral=\"%s\"\n", + ref[0].bv_val ? ref[0].bv_val : "NULL", + NULL, NULL ); +#endif + } + + assert( err != LDAP_PARTIAL_RESULTS ); + + if ( err == LDAP_REFERRAL ) { + if( ref == NULL ) { + err = LDAP_NO_SUCH_OBJECT; + } else if ( op->o_protocol < LDAP_VERSION3 ) { + err = LDAP_PARTIAL_RESULTS; + } + } + + if ( op->o_protocol < LDAP_VERSION3 ) { + tmp = v2ref( ref, text ); + text = tmp; + ref = NULL; + } + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, ref, + NULL, NULL, NULL, ctrls ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n", + (long) op->o_connid, (long) op->o_opid, + (unsigned long) tag, (long) err, text ? text : "" ); + + if( tmp != NULL ) { + ch_free(tmp); + } +} + +void +send_ldap_sasl( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray ref, + LDAPControl **ctrls, + struct berval *cred +) +{ + ber_tag_t tag; + ber_int_t msgid; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_ldap_sasl: conn %d err=%ld len=%ld\n", + op->o_connid, (long)err, cred ? cred->bv_len : -1 )); +#else + Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%ld len=%ld\n", + (long) err, cred ? cred->bv_len : -1, NULL ); +#endif + + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, ref, + NULL, NULL, cred, ctrls ); } void -send_ldap_search_result( +send_ldap_extended( Connection *conn, Operation *op, - int err, - char *matched, - char *text, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + const char *rspoid, + struct berval *rspdata, + LDAPControl **ctrls +) +{ + ber_tag_t tag; + ber_int_t msgid; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_ldap_extended: conn %d err=%ld oid=%s len=%ld\n", + op->o_connid, (long)err, rspoid ? rspoid : "", + rspdata != NULL ? (long)rspdata->bv_len : (long)0 )); +#else + Debug( LDAP_DEBUG_TRACE, + "send_ldap_extended err=%ld oid=%s len=%ld\n", + (long) err, + rspoid ? rspoid : "", + rspdata != NULL ? (long) rspdata->bv_len : (long) 0 ); +#endif + + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, refs, + rspoid, rspdata, NULL, ctrls ); +} + + +void +send_search_result( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + LDAPControl **ctrls, int nentries ) { - send_ldap_result2( conn, op, err, matched, text, nentries ); + ber_tag_t tag; + ber_int_t msgid; + char *tmp = NULL; + + assert( !LDAP_API_ERROR( err ) ); + + if (op->o_callback && op->o_callback->sc_sresult) { + op->o_callback->sc_sresult(conn, op, err, matched, text, refs, + ctrls, nentries); + return; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_search_result: conn %d err=%d matched=\"%s\"\n", + op->o_connid, err, matched ? matched : "", + text ? text : "" )); +#else + Debug( LDAP_DEBUG_TRACE, + "send_search_result: err=%d matched=\"%s\" text=\"%s\"\n", + err, matched ? matched : "", text ? text : "" ); +#endif + + + assert( err != LDAP_PARTIAL_RESULTS ); + + if( op->o_protocol < LDAP_VERSION3 ) { + /* send references in search results */ + if( err == LDAP_REFERRAL ) { + err = LDAP_PARTIAL_RESULTS; + } + + tmp = v2ref( refs, text ); + text = tmp; + refs = NULL; + + } else { + /* don't send references in search results */ + assert( refs == NULL ); + refs = NULL; + + if( err == LDAP_REFERRAL ) { + err = LDAP_SUCCESS; + } + } + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, refs, + NULL, NULL, NULL, ctrls ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n", + (long) op->o_connid, (long) op->o_opid, + (unsigned long) tag, (long) err, text ? text : "" ); + + if (tmp != NULL) { + ch_free(tmp); + } } +static struct berval AllUser = { sizeof(LDAP_ALL_USER_ATTRIBUTES)-1, + LDAP_ALL_USER_ATTRIBUTES }; +static struct berval AllOper = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES)-1, + LDAP_ALL_OPERATIONAL_ATTRIBUTES }; + int send_search_entry( Backend *be, Connection *conn, Operation *op, Entry *e, - char **attrs, - int attrsonly + AttributeName *attrs, + int attrsonly, + LDAPControl **ctrls ) { - BerElement *ber; - Attribute *a; - int i, rc, bytes, sd; - struct acl *acl; + char berbuf[256]; + BerElement *ber = (BerElement *)berbuf; + Attribute *a, *aa; + int i, rc=-1, bytes; + char *edn; + int userattrs; + int opattrs; + static AccessControlState acl_state_init = ACL_STATE_INIT; + AccessControlState acl_state; - Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); + AttributeDescription *ad_entry = slap_schema.si_ad_entry; - if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn, - ACL_READ ) ) { - Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n", - 0, 0, 0 ); - return( 1 ); + if (op->o_callback && op->o_callback->sc_sendentry) { + return op->o_callback->sc_sendentry( be, conn, op, e, attrs, + attrsonly, ctrls ); } -#ifdef COMPAT30 - if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER )) - == NULLBER ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_search_entry: conn %d dn=\"%s\"%s\n", + op->o_connid, e->e_dn, + attrsonly ? " (attrsOnly)" : "" )); #else - if ( (ber = der_alloc()) == NULLBER ) { + Debug( LDAP_DEBUG_TRACE, + "=> send_search_entry: dn=\"%s\"%s\n", + e->e_dn, attrsonly ? " (attrsOnly)" : "", 0 ); #endif - Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ber_alloc" ); + + if ( ! access_allowed( be, conn, op, e, + ad_entry, NULL, ACL_READ, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_entry: conn %d access to entry (%s) not allowed\n", + op->o_connid, e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "send_search_entry: access to entry not allowed\n", + 0, 0, 0 ); +#endif + return( 1 ); } -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - rc = ber_printf( ber, "{it{{s{", op->o_msgid, - LDAP_RES_SEARCH_ENTRY, e->e_dn ); + edn = e->e_ndn; + + ber_init_w_nullc( ber, LBER_USE_DER ); + +#ifdef LDAP_CONNECTIONLESS + if (conn->c_is_udp) { + rc = ber_write(ber, (char *)&op->o_peeraddr, sizeof(struct sockaddr), 0); + if (rc != sizeof(struct sockaddr)) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + conn ? conn->c_connid : 0 )); +#else + Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); +#endif + ber_free_buf( ber ); + return; + } + } + if (conn->c_is_udp && op->o_protocol == LDAP_VERSION2) { + rc = ber_printf( ber, "{is{t{O{" /*}}}*/, + op->o_msgid, "", LDAP_RES_SEARCH_ENTRY, &e->e_name ); } else #endif - rc = ber_printf( ber, "{it{s{", op->o_msgid, - LDAP_RES_SEARCH_ENTRY, e->e_dn ); + { + rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid, + LDAP_RES_SEARCH_ENTRY, &e->e_name ); + } if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - ber_free( ber, 1 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ber_printf dn" ); - return( 1 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encoding DN error", NULL, NULL ); + goto error_return; } + /* check for special all user attributes ("*") type */ + userattrs = ( attrs == NULL ) ? 1 + : an_find( attrs, &AllUser ); + + /* check for special all operational attributes ("+") type */ + opattrs = ( attrs == NULL ) ? 0 + : an_find( attrs, &AllOper ); + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) { - continue; + AttributeDescription *desc = a->a_desc; + + if ( attrs == NULL ) { + /* all attrs request, skip operational attributes */ + if( is_at_operational( desc->ad_type ) ) { + continue; + } + + } else { + /* specific attrs requested */ + if ( is_at_operational( desc->ad_type ) ) { + if( !opattrs && !ad_inlist( desc, attrs ) ) { + continue; + } + + } else { + if (!userattrs && !ad_inlist( desc, attrs ) ) { + continue; + } + } } - acl = acl_get_applicable( be, op, e, a->a_type ); + acl_state = acl_state_init; - if ( ! acl_access_allowed( acl, be, conn, e, NULL, op, - ACL_READ ) ) { + if ( ! access_allowed( be, conn, op, e, desc, NULL, + ACL_READ, &acl_state ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, "send_search_entry: " + "conn %d access to attribute %s not allowed\n", + op->o_connid, desc->ad_cname.bv_val )); +#else + Debug( LDAP_DEBUG_ACL, "acl: " + "access to attribute %s not allowed\n", + desc->ad_cname.bv_val, 0, 0 ); +#endif continue; } - if ( ber_printf( ber, "{s[", a->a_type ) == -1 ) { + if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - ber_free( ber, 1 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - NULL, "ber_printf type" ); - return( 1 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encoding description error", NULL, NULL ); + goto error_return; } if ( ! attrsonly ) { - for ( i = 0; a->a_vals[i] != NULL; i++ ) { - if ( a->a_syntax & SYNTAX_DN && - ! acl_access_allowed( acl, be, conn, e, - a->a_vals[i], op, ACL_READ ) ) + for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { + if ( ! access_allowed( be, conn, op, e, + desc, &a->a_vals[i], ACL_READ, &acl_state ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_entry: conn %d " + "access to attribute %s, value %d not allowed\n", + op->o_connid, desc->ad_cname.bv_val, i )); +#else + Debug( LDAP_DEBUG_ACL, + "acl: access to attribute %s, value %d not allowed\n", + desc->ad_cname.bv_val, i, 0 ); +#endif + continue; } - if ( ber_printf( ber, "o", - a->a_vals[i]->bv_val, - a->a_vals[i]->bv_len ) == -1 ) - { + if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed.\n", + op->o_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - ber_free( ber, 1 ); - send_ldap_result( conn, op, - LDAP_OPERATIONS_ERROR, NULL, - "ber_printf value" ); - return( 1 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encoding values error", NULL, NULL ); + goto error_return; } } } - if ( ber_printf( ber, "]}" ) == -1 ) { + if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - ber_free( ber, 1 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - NULL, "ber_printf type end" ); - return( 1 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encode end error", NULL, NULL ); + goto error_return; } } -#ifdef COMPAT30 - if ( conn->c_version == 30 ) { - rc = ber_printf( ber, "}}}}" ); - } else + /* eventually will loop through generated operational attributes */ + /* only have subschemaSubentry implemented */ + aa = backend_operational( be, conn, op, e, attrs, opattrs ); + + for (a = aa ; a != NULL; a = a->a_next ) { + AttributeDescription *desc = a->a_desc; + + if ( attrs == NULL ) { + /* all attrs request, skip operational attributes */ + if( is_at_operational( desc->ad_type ) ) { + continue; + } + + } else { + /* specific attrs requested */ + if( is_at_operational( desc->ad_type ) ) { + if( !opattrs && !ad_inlist( desc, attrs ) ) { + continue; + } + } else { + if (!userattrs && !ad_inlist( desc, attrs ) ) + { + continue; + } + } + } + + acl_state = acl_state_init; + + if ( ! access_allowed( be, conn, op, e, desc, NULL, + ACL_READ, &acl_state ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_entry: conn %s " + "access to attribute %s not allowed\n", + op->o_connid, desc->ad_cname.bv_val )); +#else + Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n", + desc->ad_cname.bv_val, 0, 0 ); +#endif + + continue; + } + + rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname ); + if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encoding description error", NULL, NULL ); + attrs_free( aa ); + goto error_return; + } + + if ( ! attrsonly ) { + for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { + if ( ! access_allowed( be, conn, op, e, + desc, &a->a_vals[i], ACL_READ, &acl_state ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_entry: conn %d " + "access to %s, value %d not allowed\n", + op->o_connid, desc->ad_cname.bv_val, i )); +#else + Debug( LDAP_DEBUG_ACL, + "acl: access to attribute %s, value %d not allowed\n", + desc->ad_cname.bv_val, i, 0 ); +#endif + + continue; + } + + if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "ber_printf failed\n", 0, 0, 0 ); #endif - rc = ber_printf( ber, "}}}" ); + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encoding values error", NULL, NULL ); + attrs_free( aa ); + goto error_return; + } + } + } + + if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encode end error", NULL, NULL ); + attrs_free( aa ); + goto error_return; + } + } + + attrs_free( aa ); + + rc = ber_printf( ber, /*{{{*/ "}N}N}" ); + +#ifdef LDAP_CONNECTIONLESS + if (conn->c_is_udp && op->o_protocol == LDAP_VERSION2 && rc != -1) + rc = ber_printf( ber, "}" ); +#endif if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %d ber_printf failed\n", + op->o_connid )); +#else Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - ber_free( ber, 1 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ber_printf entry end" ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encode entry end error", NULL, NULL ); return( 1 ); } - /* write only one pdu at a time - wait til it's our turn */ - pthread_mutex_lock( &conn->c_pdumutex ); + bytes = send_ldap_ber( conn, ber ); + ber_free_buf( ber ); - bytes = ber->ber_ptr - ber->ber_buf; - pthread_mutex_lock( &new_conn_mutex ); - while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber, - 1 ) != 0 ) { - pthread_mutex_unlock( &new_conn_mutex ); - /* - * we got an error. if it's ewouldblock, we need to - * wait on the socket being writable. otherwise, figure - * it's a hard error and return. - */ + if ( bytes < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_ldap_response: conn %d ber write failed.\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "send_ldap_response: ber write failed\n", + 0, 0, 0 ); +#endif - Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] - : "unknown", 0 ); + return -1; + } - if ( errno != EWOULDBLOCK && errno != EAGAIN ) { - close_connection( conn, op->o_connid, op->o_opid ); + ldap_pvt_thread_mutex_lock( &num_sent_mutex ); + num_bytes_sent += bytes; + num_entries_sent++; + num_pdu_sent++; + ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); - pthread_mutex_unlock( &conn->c_pdumutex ); - return( -1 ); + Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n", + (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_search_entry: conn %d exit.\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); +#endif + + rc = 0; + +error_return:; + return( rc ); +} + +int +send_search_reference( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + BerVarray refs, + LDAPControl **ctrls, + BerVarray *v2refs +) +{ + char berbuf[256]; + BerElement *ber = (BerElement *)berbuf; + int rc; + int bytes; + + AttributeDescription *ad_ref = slap_schema.si_ad_ref; + AttributeDescription *ad_entry = slap_schema.si_ad_entry; + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_search_reference: conn %d dn=\"%s\"\n", + op->o_connid, e->e_dn )); +#else + Debug( LDAP_DEBUG_TRACE, + "=> send_search_reference: dn=\"%s\"\n", + e->e_dn, 0, 0 ); +#endif + + + if ( ! access_allowed( be, conn, op, e, + ad_entry, NULL, ACL_READ, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_reference: conn %d access to entry %s not allowed\n", + op->o_connid, e->e_dn )); +#else + Debug( LDAP_DEBUG_ACL, + "send_search_reference: access to entry not allowed\n", + 0, 0, 0 ); +#endif + + return( 1 ); + } + + if ( ! access_allowed( be, conn, op, e, + ad_ref, NULL, ACL_READ, NULL ) ) + { +#ifdef NEW_LOGGING + LDAP_LOG(( "acl", LDAP_LEVEL_INFO, + "send_search_reference: conn %d access to reference not allowed.\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ACL, + "send_search_reference: access to reference not allowed\n", + 0, 0, 0 ); +#endif + + return( 1 ); + } + + if( refs == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_reference: null ref in (%s).\n", + op->o_connid, e->e_dn )); +#else + Debug( LDAP_DEBUG_ANY, + "send_search_reference: null ref in (%s)\n", + e->e_dn, 0, 0 ); +#endif + + return( 1 ); + } + + if( op->o_protocol < LDAP_VERSION3 ) { + /* save the references for the result */ + if( refs[0].bv_val != NULL ) { + value_add( v2refs, refs ); } + return 0; + } - /* wait for socket to be write-ready */ - pthread_mutex_lock( &active_threads_mutex ); - active_threads--; - conn->c_writewaiter = 1; - pthread_kill( listener_tid, SIGUSR1 ); - pthread_cond_wait( &conn->c_wcv, &active_threads_mutex ); - pthread_mutex_unlock( &active_threads_mutex ); + ber_init_w_nullc( ber, LBER_USE_DER ); + + rc = ber_printf( ber, "{it{W}N}", op->o_msgid, + LDAP_RES_SEARCH_REFERENCE, refs ); - pthread_yield(); - pthread_mutex_lock( &new_conn_mutex ); + if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_reference: conn %d ber_printf failed.\n", + op->o_connid )); +#else + Debug( LDAP_DEBUG_ANY, + "send_search_reference: ber_printf failed\n", 0, 0, 0 ); +#endif + + ber_free_buf( ber ); + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "encode DN error", NULL, NULL ); + return -1; } - pthread_mutex_unlock( &new_conn_mutex ); - pthread_mutex_unlock( &conn->c_pdumutex ); - pthread_mutex_lock( &num_sent_mutex ); + bytes = send_ldap_ber( conn, ber ); + ber_free_buf( ber ); + + ldap_pvt_thread_mutex_lock( &num_sent_mutex ); num_bytes_sent += bytes; - num_entries_sent++; - pthread_mutex_unlock( &num_sent_mutex ); + num_refs_sent++; + num_pdu_sent++; + ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); - pthread_mutex_lock( &new_conn_mutex ); - if ( conn->c_connid == op->o_connid ) { - rc = 0; - Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n", - conn->c_connid, op->o_opid, e->e_dn, 0, 0 ); - } else { - rc = -1; - } - pthread_mutex_unlock( &new_conn_mutex ); + Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld REF dn=\"%s\"\n", + (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "send_search_reference: conn %d exit.\n", op->o_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 ); +#endif - return( rc ); + return 0; } + int str2result( char *s, @@ -374,8 +1148,14 @@ str2result( *info = NULL; if ( strncasecmp( s, "RESULT", 6 ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "str2result: (%s), expecting \"RESULT\"\n", s )); +#else Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n", s, 0, 0 ); +#endif + return( -1 ); } @@ -403,32 +1183,17 @@ str2result( *info = c; } } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "str2result: (%s) unknown.\n", s )); +#else Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n", s, 0, 0 ); +#endif + rc = -1; } } return( rc ); } - -/* - * close_connection - close a connection. takes the connection to close, - * the connid associated with the operation generating the close (so we - * don't accidentally close a connection that's not ours), and the opid - * of the operation generating the close (for logging purposes). - */ -void -close_connection( Connection *conn, int opconnid, int opid ) -{ - pthread_mutex_lock( &new_conn_mutex ); - if ( conn->c_sb.sb_sd != -1 && conn->c_connid == opconnid ) { - Statslog( LDAP_DEBUG_STATS, - "conn=%d op=%d fd=%d closed errno=%d\n", conn->c_connid, - opid, conn->c_sb.sb_sd, errno, 0 ); - close( conn->c_sb.sb_sd ); - conn->c_sb.sb_sd = -1; - conn->c_version = 0; - } - pthread_mutex_unlock( &new_conn_mutex ); -} diff --git a/servers/slapd/root_dse.c b/servers/slapd/root_dse.c new file mode 100644 index 0000000000000000000000000000000000000000..b52e3558b499e1dcf6904203d5aeaec1bcfaabce --- /dev/null +++ b/servers/slapd/root_dse.c @@ -0,0 +1,224 @@ +/* $OpenLDAP$ */ +/* root_dse.c - Provides the ROOT DSA-Specific Entry + * + * Copyright 1999-2002 The OpenLDAP Foundation. + * 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 <ac/string.h> + +#include "slap.h" +#include <ldif.h> +#include "lber_pvt.h" + +static struct berval supportedFeatures[] = { + BER_BVC("1.3.6.1.4.1.4203.1.5.1"), /* all Operational Attributes ("+") */ + BER_BVC("1.3.6.1.4.1.4203.1.5.2"), /* OCs in Attributes List */ + BER_BVC("1.3.6.1.4.1.4203.1.5.3"), /* (&) and (|) search filters */ + BER_BVC("1.3.6.1.4.1.4203.1.5.4"), /* Language Tag Options */ + BER_BVC("1.3.6.1.4.1.4203.1.5.5"), /* Language Range Options */ + {0,NULL} +}; + +static Entry *usr_attr = NULL; + +int +root_dse_info( + Connection *conn, + Entry **entry, + const char **text ) +{ + char buf[BUFSIZ]; + Entry *e; + struct berval vals[2], *bv; + int i, j; + char ** supportedSASLMechanisms; + + AttributeDescription *ad_structuralObjectClass + = slap_schema.si_ad_structuralObjectClass; + AttributeDescription *ad_objectClass + = slap_schema.si_ad_objectClass; + AttributeDescription *ad_namingContexts + = slap_schema.si_ad_namingContexts; + AttributeDescription *ad_supportedControl + = slap_schema.si_ad_supportedControl; + AttributeDescription *ad_supportedExtension + = slap_schema.si_ad_supportedExtension; + AttributeDescription *ad_supportedLDAPVersion + = slap_schema.si_ad_supportedLDAPVersion; + AttributeDescription *ad_supportedSASLMechanisms + = slap_schema.si_ad_supportedSASLMechanisms; + AttributeDescription *ad_supportedFeatures + = slap_schema.si_ad_supportedFeatures; + AttributeDescription *ad_ref + = slap_schema.si_ad_ref; + + vals[1].bv_val = NULL; + + e = (Entry *) ch_calloc( 1, sizeof(Entry) ); + + e->e_attrs = NULL; + e->e_name.bv_val = ch_strdup( LDAP_ROOT_DSE ); + e->e_name.bv_len = sizeof( LDAP_ROOT_DSE )-1; + e->e_nname.bv_val = ch_strdup( LDAP_ROOT_DSE ); + e->e_nname.bv_len = sizeof( LDAP_ROOT_DSE )-1; + + /* the DN is an empty string so no pretty/normalization is needed */ + assert( !e->e_name.bv_len ); + assert( !e->e_nname.bv_len ); + + e->e_private = NULL; + + vals[0].bv_val = "OpenLDAProotDSE"; + vals[0].bv_len = sizeof("OpenLDAProotDSE")-1; + attr_merge( e, ad_structuralObjectClass, vals ); + + vals[0].bv_val = "top"; + vals[0].bv_len = sizeof("top")-1; + attr_merge( e, ad_objectClass, vals ); + + vals[0].bv_val = "OpenLDAProotDSE"; + vals[0].bv_len = sizeof("OpenLDAProotDSE")-1; + attr_merge( e, ad_objectClass, vals ); + + for ( i = 0; i < nbackends; i++ ) { + if ( backends[i].be_flags & SLAP_BFLAG_GLUE_SUBORDINATE ) { + continue; + } + for ( j = 0; backends[i].be_suffix[j] != NULL; j++ ) { + vals[0] = *backends[i].be_suffix[j]; + attr_merge( e, ad_namingContexts, vals ); + } + } + + /* altServer unsupported */ + + /* supportedControl */ + for ( i=0; (vals[0].bv_val = get_supported_ctrl(i)) != NULL; i++ ) { + vals[0].bv_len = strlen( vals[0].bv_val ); + attr_merge( e, ad_supportedControl, vals ); + } + + /* supportedExtension */ + for ( i=0; (bv = get_supported_extop(i)) != NULL; i++ ) { + vals[0] = *bv; + attr_merge( e, ad_supportedExtension, vals ); + } + + /* supportedFeatures */ + attr_merge( e, ad_supportedFeatures, supportedFeatures ); + + /* supportedLDAPVersion */ + for ( i=LDAP_VERSION_MIN; i<=LDAP_VERSION_MAX; i++ ) { + if (!( global_allows & SLAP_ALLOW_BIND_V2 ) && + ( i < LDAP_VERSION3 ) ) + { + /* version 2 and lower are disallowed */ + continue; + } + sprintf(buf,"%d",i); + vals[0].bv_val = buf; + vals[0].bv_len = strlen( vals[0].bv_val ); + attr_merge( e, ad_supportedLDAPVersion, vals ); + } + + /* supportedSASLMechanism */ + supportedSASLMechanisms = slap_sasl_mechs( conn ); + + if( supportedSASLMechanisms != NULL ) { + for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) { + vals[0].bv_val = supportedSASLMechanisms[i]; + vals[0].bv_len = strlen( vals[0].bv_val ); + attr_merge( e, ad_supportedSASLMechanisms, vals ); + } + charray_free( supportedSASLMechanisms ); + } + + if ( default_referral != NULL ) { + attr_merge( e, ad_ref, default_referral ); + } + + if( usr_attr != NULL) { + Attribute *a; + for( a = usr_attr->e_attrs; a != NULL; a = a->a_next ) { + attr_merge( e, a->a_desc, a->a_vals ); + } + } + + *entry = e; + return LDAP_SUCCESS; +} + +/* + * Read the entries specified in fname and merge the attributes + * to the user defined rootDSE. Note thaat if we find any errors + * what so ever, we will discard the entire entries, print an + * error message and return. + */ +int read_root_dse_file( const char *fname ) +{ + FILE *fp; + int rc = 0, lineno = 0, lmax = 0; + char *buf = NULL; + + if ( (fp = fopen( fname, "r" )) == NULL ) { + Debug( LDAP_DEBUG_ANY, + "could not open rootdse attr file \"%s\" - absolute path?\n", + fname, 0, 0 ); + perror( fname ); + return EXIT_FAILURE; + } + + usr_attr = (Entry *) ch_calloc( 1, sizeof(Entry) ); + usr_attr->e_attrs = NULL; + + while( ldif_read_record( fp, &lineno, &buf, &lmax ) ) { + Entry *e = str2entry( buf ); + Attribute *a; + + if( e == NULL ) { + fprintf( stderr, "root_dse: could not parse entry (line=%d)\n", + lineno ); + entry_free( e ); + entry_free( usr_attr ); + usr_attr = NULL; + return EXIT_FAILURE; + } + + /* make sure the DN is the empty DN */ + if( e->e_nname.bv_len ) { + fprintf( stderr, + "root_dse: invalid rootDSE - dn=\"%s\" (line=%d)\n", + e->e_dn, lineno ); + entry_free( e ); + entry_free( usr_attr ); + usr_attr = NULL; + return EXIT_FAILURE; + } + + /* + * we found a valid entry, so walk thru all the attributes in the + * entry, and add each attribute type and description to the + * usr_attr entry + */ + + for(a = e->e_attrs; a != NULL; a = a->a_next) { + attr_merge( usr_attr, a->a_desc, a->a_vals ); + } + + entry_free( e ); + } + + ch_free( buf ); + + Debug(LDAP_DEBUG_CONFIG, "rootDSE file %s read.\n", fname, 0, 0); + return rc; +} diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c new file mode 100644 index 0000000000000000000000000000000000000000..4876c076f8dada7137043cdefa924744fa580e7d --- /dev/null +++ b/servers/slapd/sasl.c @@ -0,0 +1,1160 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> +#include <ac/string.h> + +#include <lber.h> +#include <ldap_log.h> + +#include "slap.h" + +#ifdef HAVE_CYRUS_SASL +#include <limits.h> + +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#else +#include <sasl.h> +#endif + +#if SASL_VERSION_MAJOR >= 2 +#include <lutil.h> +#define SASL_CONST const +#else +#define SASL_CONST +#endif + +#include <ldap_pvt.h> + +#ifdef SLAPD_SPASSWD +#include <lutil.h> +#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 + +static sasl_security_properties_t sasl_secprops; + +static int +slap_sasl_log( + void *context, + int priority, + const char *message) +{ + Connection *conn = context; + int level; + const char * label; + + if ( message == NULL ) { + return SASL_BADPARAM; + } + + switch (priority) { +#if SASL_VERSION_MAJOR >= 2 + case SASL_LOG_NONE: + level = LDAP_DEBUG_NONE; + label = "None"; + break; + case SASL_LOG_ERR: + level = LDAP_DEBUG_ANY; + label = "Error"; + break; + case SASL_LOG_FAIL: + level = LDAP_DEBUG_ANY; + label = "Failure"; + break; + case SASL_LOG_WARN: + level = LDAP_DEBUG_TRACE; + label = "Warning"; + break; + case SASL_LOG_NOTE: + level = LDAP_DEBUG_TRACE; + label = "Notice"; + break; + case SASL_LOG_DEBUG: + level = LDAP_DEBUG_TRACE; + label = "Debug"; + break; + case SASL_LOG_TRACE: + level = LDAP_DEBUG_TRACE; + label = "Trace"; + break; + case SASL_LOG_PASS: + level = LDAP_DEBUG_TRACE; + label = "Password Trace"; + break; +#else + case SASL_LOG_ERR: + level = LDAP_DEBUG_ANY; + label = "Error"; + break; + case SASL_LOG_WARNING: + level = LDAP_DEBUG_TRACE; + label = "Warning"; + break; + case SASL_LOG_INFO: + level = LDAP_DEBUG_TRACE; + label = "Info"; + break; +#endif + default: + return SASL_BADPARAM; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "SASL [conn=%ld] %s: %s\n", + conn ? conn->c_connid : -1, + label, message )); +#else + Debug( level, "SASL [conn=%ld] %s: %s\n", + conn ? conn->c_connid: -1, + label, message ); +#endif + + + return SASL_OK; +} + + +/* Take any sort of identity string and return a DN with the "dn:" prefix. The + string returned in *dn is in its own allocated memory, and must be free'd + by the calling process. + -Mark Adamson, Carnegie Mellon +*/ + +#define SET_DN 1 +#define SET_U 2 + +static struct berval ext_bv = { sizeof("EXTERNAL")-1, "EXTERNAL" }; + +int slap_sasl_getdn( Connection *conn, char *id, + char *user_realm, struct berval *dn, int flags ) +{ + char *c1; + int rc, len, is_dn = 0; + sasl_conn_t *ctx; + struct berval dn2; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_getdn: conn %d id=%s\n", + conn ? conn->c_connid : -1, + id ? (*id ? id : "<empty>") : "NULL" )); +#else + Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: id=%s\n", + id?(*id?id:"<empty>"):"NULL",0,0 ); +#endif + + dn->bv_val = NULL; + dn->bv_len = 0; + + /* Blatantly anonymous ID */ + if( id && + ( id[sizeof( "anonymous" )-1] == '\0' + || id[sizeof( "anonymous" )-1] == '@' ) && + !strncasecmp( id, "anonymous", sizeof( "anonymous" )-1) ) { + return( LDAP_SUCCESS ); + } + ctx = conn->c_sasl_context; + len = strlen( id ); + + /* An authcID needs to be converted to authzID form */ + if( flags & FLAG_GETDN_AUTHCID ) { + if( sasl_external_x509dn_convert + && conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len + && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 ) + && 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); + is_dn = SET_DN; + + } else { + /* convert to u:<username> form */ + ber_str2bv( id, len, 1, dn ); + is_dn = SET_U; + } + } + if( !is_dn ) { + if( !strncasecmp( id, "u:", sizeof("u:")-1 )) { + is_dn = SET_U; + ber_str2bv( id+2, len-2, 1, dn ); + } else if ( !strncasecmp( id, "dn:", sizeof("dn:")-1) ) { + is_dn = SET_DN; + ber_str2bv( id+3, len-3, 1, dn ); + } + } + + /* An authzID must be properly prefixed */ + if( (flags & FLAG_GETDN_AUTHZID) && !is_dn ) { + free( dn->bv_val ); + dn->bv_val = NULL; + dn->bv_len = 0; + return( LDAP_INAPPROPRIATE_AUTH ); + } + + /* Username strings */ + if( is_dn == SET_U ) { + char *p; + len = dn->bv_len + sizeof("uid=")-1 + sizeof(",cn=auth")-1; + + if( user_realm && *user_realm ) { + len += strlen( user_realm ) + sizeof(",cn=")-1; + } + + if( conn->c_sasl_bind_mech.bv_len ) { + len += conn->c_sasl_bind_mech.bv_len + sizeof(",cn=")-1; + } + + /* Build the new dn */ + c1 = dn->bv_val; + dn->bv_val = ch_malloc( len+1 ); + p = slap_strcopy( dn->bv_val, "uid=" ); + p = slap_strcopy( p, c1 ); + ch_free( c1 ); + + if( user_realm && *user_realm ) { + p = slap_strcopy( p, ",cn=" ); + p = slap_strcopy( p, user_realm ); + } + if( conn->c_sasl_bind_mech.bv_len ) { + p = slap_strcopy( p, ",cn=" ); + p = slap_strcopy( p, conn->c_sasl_bind_mech.bv_val ); + } + p = slap_strcopy( p, ",cn=auth" ); + dn->bv_len = p - dn->bv_val; + is_dn = SET_DN; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_getdn: u:id converted to %s.\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "getdn: u:id converted to %s\n", dn->bv_val,0,0 ); +#endif + } + + /* DN strings that are a cn=auth identity to run through regexp */ + if( is_dn == SET_DN && ( ( flags & FLAG_GETDN_FINAL ) == 0 ) ) + { + slap_sasl2dn( dn, &dn2 ); + if( dn2.bv_val ) { + ch_free( dn->bv_val ); + *dn = dn2; +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_getdn: dn:id converted to %s.\n", dn->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "getdn: dn:id converted to %s\n", + dn->bv_val, 0, 0 ); +#endif + } + } + + if( flags & FLAG_GETDN_FINAL ) { + /* omit "dn:" prefix */ + is_dn = 0; + } else { + rc = dnNormalize2( NULL, dn, &dn2 ); + free(dn->bv_val); + if ( rc != LDAP_SUCCESS ) { + *dn = slap_empty_bv; + return rc; + } + *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 ); +} + +#if SASL_VERSION_MAJOR >= 2 +static int +slap_sasl_checkpass( + sasl_conn_t *sconn, + void *context, + const char *username, + const char *pass, + unsigned passlen, + struct propctx *propctx) +{ + Connection *conn = (Connection *)context; + struct berval dn, cred; + int rc; + BerVarray vals, bv; + + cred.bv_val = (char *)pass; + cred.bv_len = passlen; + + /* XXX do we need to check sasldb as well? */ + + /* XXX can we do both steps at once? */ + rc = slap_sasl_getdn( conn, (char *)username, NULL, &dn, + FLAG_GETDN_AUTHCID | FLAG_GETDN_FINAL ); + if ( rc != LDAP_SUCCESS ) { + sasl_seterror( sconn, 0, ldap_err2string( rc ) ); + return SASL_NOUSER; + } + + if ( dn.bv_len == 0 ) { + sasl_seterror( sconn, 0, + "No password is associated with the Root DSE" ); + if ( dn.bv_val != NULL ) { + ch_free( dn.bv_val ); + } + return SASL_NOUSER; + } + + rc = backend_attribute( NULL, NULL, NULL, NULL, &dn, + slap_schema.si_ad_userPassword, &vals); + if ( rc != LDAP_SUCCESS ) { + ch_free( dn.bv_val ); + sasl_seterror( sconn, 0, ldap_err2string( rc ) ); + return SASL_NOVERIFY; + } + + rc = SASL_NOVERIFY; + + if ( vals != NULL ) { + for ( bv = vals; bv->bv_val != NULL; bv++ ) { + if ( !lutil_passwd( bv, &cred, NULL ) ) { + rc = SASL_OK; + break; + } + } + ber_bvarray_free( vals ); + } + + if ( rc != SASL_OK ) { + sasl_seterror( sconn, 0, + ldap_err2string( LDAP_INVALID_CREDENTIALS ) ); + } + + ch_free( dn.bv_val ); + + return rc; +} + +#if 0 /* CANON isn't for what you think it does. */ +static int +slap_sasl_canonicalize( + sasl_conn_t *sconn, + void *context, + const char *in, + unsigned inlen, + unsigned flags, + const char *user_realm, + char *out, + unsigned out_max, + unsigned *out_len) +{ + Connection *conn = (Connection *)context; + struct berval dn; + int rc; + + *out_len = 0; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_canonicalize: conn %d %s=\"%s\"\n", + conn ? conn->c_connid : -1, + (flags == SASL_CU_AUTHID) ? "authcid" : "authzid", + in ? in : "<empty>" )); +#else + Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: " + "%s=\"%s\"\n", + conn ? conn->c_connid : -1, + (flags == SASL_CU_AUTHID) ? "authcid" : "authzid", + in ? in : "<empty>" ); +#endif + + rc = slap_sasl_getdn( conn, (char *)in, (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 ) ); + return SASL_NOAUTHZ; + } + + if ( out_max < dn.bv_len ) { + return SASL_BUFOVER; + } + + AC_MEMCPY( out, dn.bv_val, dn.bv_len ); + out[dn.bv_len] = '\0'; + + *out_len = dn.bv_len; + + ch_free( dn.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_canonicalize: conn %d %s=\"%s\"\n", + conn ? conn->c_connid : -1, + (flags == SASL_CU_AUTHID) ? "authcDN" : "authzDN", + out )); +#else + Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: " + "%s=\"%s\"\n", + conn ? conn->c_connid : -1, + (flags == SASL_CU_AUTHID) ? "authcDN" : "authzDN", + out ); +#endif + + return SASL_OK; +} +#endif + +#define CANON_BUF_SIZE 256 /* from saslint.h */ + +static int +slap_sasl_authorize( + sasl_conn_t *sconn, + void *context, + char *requested_user, + unsigned rlen, + char *auth_identity, + unsigned alen, + const char *def_realm, + unsigned urlen, + struct propctx *propctx) +{ + Connection *conn = (Connection *)context; + struct berval authcDN, authzDN; + char *realm; + int rc, equal = 1; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorize: conn %d authcid=\"%s\" authzid=\"%s\"\n", + conn ? conn->c_connid : -1, auth_identity, requested_user)); +#else + Debug( LDAP_DEBUG_ARGS, "SASL Authorize [conn=%ld]: " + "authcid=\"%s\" authzid=\"%s\"\n", + conn ? conn->c_connid : -1, auth_identity, requested_user ); +#endif + + if ( requested_user ) + equal = !strcmp( auth_identity, requested_user ); + + realm = strchr( auth_identity, '@' ); + if ( realm ) + *realm++ = '\0'; + + rc = slap_sasl_getdn( conn, auth_identity, realm ? realm : (char *)def_realm, + &authcDN, FLAG_GETDN_AUTHCID ); + if ( realm ) + realm[-1] = '@'; + + if ( rc != LDAP_SUCCESS ) { + sasl_seterror( sconn, 0, ldap_err2string( rc ) ); + return SASL_NOAUTHZ; + } + + if ( equal ) { + if ( authcDN.bv_len > CANON_BUF_SIZE ) { + free( authcDN.bv_val ); + return SASL_BUFOVER; + } + AC_MEMCPY( requested_user, authcDN.bv_val, authcDN.bv_len ); + + return SASL_OK; + } + + realm = strchr( requested_user, '@' ); + if ( realm ) + *realm++ = '\0'; + + rc = slap_sasl_getdn( conn, requested_user, realm ? realm : (char *)def_realm, + &authzDN, FLAG_GETDN_AUTHZID ); + if ( realm ) + realm[-1] = '@'; + + if ( rc != LDAP_SUCCESS ) { + free( authcDN.bv_val ); + sasl_seterror( sconn, 0, ldap_err2string( rc ) ); + return SASL_NOAUTHZ; + } + + if (authzDN.bv_len > CANON_BUF_SIZE) { + free( authcDN.bv_val ); + free( authzDN.bv_val ); + return SASL_BUFOVER; + } + + rc = slap_sasl_authorized( &authcDN, &authzDN ); + free( authcDN.bv_val ); + if ( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_INFO, + "slap_sasl_authorize: conn %ld authorization disallowed (%d)\n", + (long)(conn ? conn->c_connid : -1), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " + " authorization disallowed (%d)\n", + (long) (conn ? conn->c_connid : -1), rc, 0 ); +#endif + + sasl_seterror( sconn, 0, "not authorized" ); + free( authzDN.bv_val ); + return SASL_NOAUTHZ; + } + AC_MEMCPY( requested_user, authzDN.bv_val, authzDN.bv_len ); + free( authzDN.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorize: conn %d authorization allowed\n", + (long)(conn ? conn->c_connid : -1 ) )); +#else + Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " + " authorization allowed\n", + (long) (conn ? conn->c_connid : -1), 0, 0 ); +#endif + + return SASL_OK; +} +#else +static int +slap_sasl_authorize( + void *context, + const char *authcid, + const char *authzid, + const char **user, + const char **errstr) +{ + struct berval authcDN, authzDN; + int rc; + Connection *conn = context; + char *realm; + + *user = NULL; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorize: conn %d authcid=\"%s\" authzid=\"%s\"\n", + conn ? conn->c_connid : -1, + authcid ? authcid : "<empty>", + authzid ? authzid : "<empty>" )); +#else + Debug( LDAP_DEBUG_ARGS, "SASL Authorize [conn=%ld]: " + "authcid=\"%s\" authzid=\"%s\"\n", + (long) (conn ? conn->c_connid : -1), + authcid ? authcid : "<empty>", + authzid ? authzid : "<empty>" ); +#endif + + /* Figure out how much data we have for the dn */ + rc = sasl_getprop( conn->c_sasl_context, SASL_REALM, (void **)&realm ); + if( rc != SASL_OK && rc != SASL_NOTDONE ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_authorize: getprop(REALM) failed.\n" )); +#else + Debug(LDAP_DEBUG_TRACE, + "authorize: getprop(REALM) failed!\n", 0,0,0); +#endif + *errstr = "Could not extract realm"; + return SASL_NOAUTHZ; + } + + /* 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( rc != LDAP_SUCCESS ) { + *errstr = ldap_err2string( rc ); + return SASL_NOAUTHZ; + } + if( ( authzid == NULL ) || !strcmp( authcid,authzid ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorize: conn %d Using authcDN=%s\n", + conn ? conn->c_connid : -1, authcDN.bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " + "Using authcDN=%s\n", (long) (conn ? conn->c_connid : -1), authcDN.bv_val,0 ); +#endif + + *user = authcDN.bv_val; + *errstr = NULL; + return SASL_OK; + } + rc = slap_sasl_getdn( conn, (char *)authzid, realm, &authzDN, FLAG_GETDN_AUTHZID ); + if( rc != LDAP_SUCCESS ) { + ch_free( authcDN.bv_val ); + *errstr = ldap_err2string( rc ); + return SASL_NOAUTHZ; + } + + rc = slap_sasl_authorized( &authcDN, &authzDN ); + if( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_INFO, + "slap_sasl_authorize: conn %ld authorization disallowed (%d)\n", + (long)(conn ? conn->c_connid : -1), rc )); +#else + Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " + " authorization disallowed (%d)\n", + (long) (conn ? conn->c_connid : -1), rc, 0 ); +#endif + + *errstr = "not authorized"; + ch_free( authcDN.bv_val ); + ch_free( authzDN.bv_val ); + return SASL_NOAUTHZ; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorize: conn %d authorization allowed\n", + (long)(conn ? conn->c_connid : -1 ) )); +#else + Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " + " authorization allowed\n", + (long) (conn ? conn->c_connid : -1), 0, 0 ); +#endif + + + ch_free( authcDN.bv_val ); + *user = authzDN.bv_val; + *errstr = NULL; + return SASL_OK; +} +#endif /* SASL_VERSION_MAJOR >= 2 */ + +static int +slap_sasl_err2ldap( int saslerr ) +{ + int rc; + + switch (saslerr) { + case SASL_CONTINUE: + rc = LDAP_SASL_BIND_IN_PROGRESS; + break; + case SASL_FAIL: + rc = LDAP_OTHER; + break; + case SASL_NOMEM: + rc = LDAP_OTHER; + break; + case SASL_NOMECH: + rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; + break; + case SASL_BADAUTH: + rc = LDAP_INVALID_CREDENTIALS; + break; + case SASL_NOAUTHZ: + rc = LDAP_INSUFFICIENT_ACCESS; + break; + case SASL_TOOWEAK: + case SASL_ENCRYPT: + rc = LDAP_INAPPROPRIATE_AUTH; + break; + default: + rc = LDAP_OTHER; + break; + } + + return rc; +} +#endif + + +int slap_sasl_init( void ) +{ +#ifdef HAVE_CYRUS_SASL + int rc; + static sasl_callback_t server_callbacks[] = { + { SASL_CB_LOG, &slap_sasl_log, NULL }, + { SASL_CB_LIST_END, NULL, NULL } + }; + + sasl_set_alloc( + ch_malloc, + ch_calloc, + ch_realloc, + ch_free ); + + sasl_set_mutex( + ldap_pvt_sasl_mutex_new, + ldap_pvt_sasl_mutex_lock, + ldap_pvt_sasl_mutex_unlock, + ldap_pvt_sasl_mutex_dispose ); + + /* should provide callbacks for logging */ + /* server name should be configurable */ + rc = sasl_server_init( server_callbacks, "slapd" ); + + if( rc != SASL_OK ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_INFO, + "slap_sasl_init: init failed.\n" )); +#else + Debug( LDAP_DEBUG_ANY, "sasl_server_init failed\n", + 0, 0, 0 ); +#endif + + return -1; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_INFO, + "slap_sasl_init: initialized!\n")); +#else + Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n", + 0, 0, 0 ); +#endif + + + /* default security properties */ + memset( &sasl_secprops, '\0', sizeof(sasl_secprops) ); + sasl_secprops.max_ssf = INT_MAX; + sasl_secprops.maxbufsize = 65536; + sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS; +#endif + + return 0; +} + +int slap_sasl_destroy( void ) +{ +#ifdef HAVE_CYRUS_SASL + sasl_done(); +#endif + free( global_host ); + global_host = NULL; + + return 0; +} + +int slap_sasl_open( Connection *conn ) +{ + int cb, sc = LDAP_SUCCESS; +#if SASL_VERSION_MAJOR >= 2 + char *ipremoteport = NULL, *iplocalport = NULL; +#endif + +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ctx = NULL; + sasl_callback_t *session_callbacks; + + assert( conn->c_sasl_context == NULL ); + assert( conn->c_sasl_extra == NULL ); + + conn->c_sasl_layers = 0; + + session_callbacks = +#if SASL_VERSION_MAJOR >= 2 + ch_calloc( 5, sizeof(sasl_callback_t)); +#else + ch_calloc( 3, sizeof(sasl_callback_t)); +#endif + conn->c_sasl_extra = session_callbacks; + + session_callbacks[cb=0].id = SASL_CB_LOG; + session_callbacks[cb].proc = &slap_sasl_log; + session_callbacks[cb++].context = conn; + + session_callbacks[cb].id = SASL_CB_PROXY_POLICY; + session_callbacks[cb].proc = &slap_sasl_authorize; + session_callbacks[cb++].context = conn; + +#if SASL_VERSION_MAJOR >= 2 +#if 0 /* CANON isn't for what you think it does. */ + session_callbacks[cb].id = SASL_CB_CANON_USER; + session_callbacks[cb].proc = &slap_sasl_canonicalize; + session_callbacks[cb++].context = conn; +#endif + + /* XXXX: this should be conditional */ + session_callbacks[cb].id = SASL_CB_SERVER_USERDB_CHECKPASS; + session_callbacks[cb].proc = &slap_sasl_checkpass; + session_callbacks[cb++].context = conn; +#endif + + session_callbacks[cb].id = SASL_CB_LIST_END; + session_callbacks[cb].proc = NULL; + session_callbacks[cb++].context = NULL; + + if( global_host == NULL ) { + global_host = ldap_pvt_get_fqdn( NULL ); + } + + /* create new SASL context */ +#if SASL_VERSION_MAJOR >= 2 + if ( conn->c_sock_name.bv_len != 0 && + strncmp( conn->c_sock_name.bv_val, "IP=", 3 ) == 0) { + char *p; + + iplocalport = ch_strdup( conn->c_sock_name.bv_val + 3 ); + /* Convert IPv6 addresses to address;port syntax. */ + p = strrchr( iplocalport, ' ' ); + /* Convert IPv4 addresses to address;port syntax. */ + if ( p == NULL ) p = strchr( iplocalport, ':' ); + if ( p != NULL ) { + *p = ';'; + } + } + if ( conn->c_peer_name.bv_len != 0 && + strncmp( conn->c_peer_name.bv_val, "IP=", 3 ) == 0) { + char *p; + + ipremoteport = ch_strdup( conn->c_peer_name.bv_val + 3 ); + /* Convert IPv6 addresses to address;port syntax. */ + p = strrchr( ipremoteport, ' ' ); + /* Convert IPv4 addresses to address;port syntax. */ + if ( p == NULL ) p = strchr( ipremoteport, ':' ); + if ( p != NULL ) { + *p = ';'; + } + } + sc = sasl_server_new( "ldap", global_host, global_realm, + iplocalport, ipremoteport, session_callbacks, 0, &ctx ); + if ( iplocalport != NULL ) { + ch_free( iplocalport ); + } + if ( ipremoteport != NULL ) { + ch_free( ipremoteport ); + } +#else + sc = sasl_server_new( "ldap", global_host, global_realm, + session_callbacks, SASL_SECURITY_LAYER, &ctx ); +#endif + + if( sc != SASL_OK ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_open: sasl_server_new failed: %d\n", sc )); +#else + Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n", + sc, 0, 0 ); +#endif + + return -1; + } + + conn->c_sasl_context = ctx; + + if( sc == SASL_OK ) { + sc = sasl_setprop( ctx, + SASL_SEC_PROPS, &sasl_secprops ); + + if( sc != SASL_OK ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_open: sasl_setprop failed: %d \n", sc )); +#else + Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n", + sc, 0, 0 ); +#endif + + slap_sasl_close( conn ); + return -1; + } + } + + sc = slap_sasl_err2ldap( sc ); +#endif + return sc; +} + +int slap_sasl_external( + Connection *conn, + slap_ssf_t ssf, + const char *auth_id ) +{ +#if SASL_VERSION_MAJOR >= 2 + int sc; + sasl_conn_t *ctx = conn->c_sasl_context; + + if ( ctx == NULL ) { + return LDAP_UNAVAILABLE; + } + + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf ); + + if ( sc != SASL_OK ) { + return LDAP_OTHER; + } + + sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, auth_id ); + + if ( sc != SASL_OK ) { + return LDAP_OTHER; + } + +#elif defined(HAVE_CYRUS_SASL) + int sc; + sasl_conn_t *ctx = conn->c_sasl_context; + sasl_external_properties_t extprops; + + if ( ctx == NULL ) { + return LDAP_UNAVAILABLE; + } + + memset( &extprops, '\0', sizeof(extprops) ); + extprops.ssf = ssf; + extprops.auth_id = (char *) auth_id; + + sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, + (void *) &extprops ); + + if ( sc != SASL_OK ) { + return LDAP_OTHER; + } +#endif + + return LDAP_SUCCESS; +} + +int slap_sasl_reset( Connection *conn ) +{ +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ctx = conn->c_sasl_context; + + if( ctx != NULL ) { + } +#endif + /* must return "anonymous" */ + return LDAP_SUCCESS; +} + +char ** slap_sasl_mechs( Connection *conn ) +{ + char **mechs = NULL; + +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ctx = conn->c_sasl_context; + + if( ctx != NULL ) { + int sc; + SASL_CONST char *mechstr; + + sc = sasl_listmech( ctx, + NULL, NULL, ",", NULL, + &mechstr, NULL, NULL ); + + if( sc != SASL_OK ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_mechs: sasl_listmech failed: %d\n", sc )); +#else + Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n", + sc, 0, 0 ); +#endif + + return NULL; + } + + mechs = str2charray( mechstr, "," ); + +#if SASL_VERSION_MAJOR < 2 + ch_free( mechstr ); +#endif + } +#endif + + return mechs; +} + +int slap_sasl_close( Connection *conn ) +{ +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ctx = conn->c_sasl_context; + + if( ctx != NULL ) { + sasl_dispose( &ctx ); + } + + conn->c_sasl_context = NULL; + + free( conn->c_sasl_extra ); + conn->c_sasl_extra = NULL; +#endif + + return LDAP_SUCCESS; +} + +int slap_sasl_bind( + Connection *conn, + Operation *op, + struct berval *dn, + struct berval *ndn, + struct berval *cred, + struct berval *edn, + slap_ssf_t *ssfp ) +{ + int rc = 1; + +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ctx = conn->c_sasl_context; + struct berval response; + unsigned reslen = 0; + const char *errstr = NULL; + int sc; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "sasl_bind: conn %ld dn=\"%s\" mech=%s datalen=%ld\n", + conn->c_connid, + dn->bv_len ? dn->bv_val : "", + conn->c_sasl_bind_in_progress ? "<continuing>" : conn->c_sasl_bind_mech.bv_val, + cred ? cred->bv_len : 0 )); +#else + Debug(LDAP_DEBUG_ARGS, + "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n", + dn->bv_len ? dn->bv_val : "", + conn->c_sasl_bind_in_progress ? "<continuing>":conn->c_sasl_bind_mech.bv_val, + cred ? cred->bv_len : 0 ); +#endif + + + if( ctx == NULL ) { + send_ldap_result( conn, op, LDAP_UNAVAILABLE, + NULL, "SASL unavailable on this session", NULL, NULL ); + return rc; + } + +#if SASL_VERSION_MAJOR >= 2 +#define START( ctx, mech, cred, clen, resp, rlen, err ) \ + sasl_server_start( ctx, mech, cred, clen, resp, rlen ) +#define STEP( ctx, cred, clen, resp, rlen, err ) \ + sasl_server_step( ctx, cred, clen, resp, rlen ) +#else +#define START( ctx, mech, cred, clen, resp, rlen, err ) \ + sasl_server_start( ctx, mech, cred, clen, resp, rlen, err ) +#define STEP( ctx, cred, clen, resp, rlen, err ) \ + sasl_server_step( ctx, cred, clen, resp, rlen, err ) +#endif + + if ( !conn->c_sasl_bind_in_progress ) { + sc = START( ctx, + conn->c_sasl_bind_mech.bv_val, + cred->bv_len ? cred->bv_val : "", + cred->bv_len, + (SASL_CONST char **)&response.bv_val, &reslen, &errstr ); + + } else { + sc = STEP( ctx, + cred->bv_val, cred->bv_len, + (SASL_CONST char **)&response.bv_val, &reslen, &errstr ); + } + + response.bv_len = reslen; + + if ( sc == SASL_OK ) { + char *username = NULL; + char *realm = NULL; + +#if SASL_VERSION_MAJOR >= 2 + sc = sasl_getprop( ctx, SASL_DEFUSERREALM, (const void **)&realm ); +#else + sc = sasl_getprop( ctx, SASL_REALM, (void **)&realm ); +#endif + sc = sasl_getprop( ctx, + SASL_USERNAME, (SASL_CONST void **)&username ); + + if ( sc != SASL_OK ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_bind: getprop(USERNAME) failed: %d\n", sc )); +#else + Debug(LDAP_DEBUG_TRACE, + "slap_sasl_bind: getprop(USERNAME) failed!\n", + 0, 0, 0); +#endif + + + send_ldap_result( conn, op, rc = slap_sasl_err2ldap( sc ), + 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; + + 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 SASL_VERSION_MAJOR >= 2 + errstr = sasl_errdetail( ctx ); +#endif + send_ldap_result( conn, op, rc, + NULL, errstr, NULL, NULL ); + } + } + + } else if ( sc == SASL_CONTINUE ) { + send_ldap_sasl( conn, op, rc = LDAP_SASL_BIND_IN_PROGRESS, + NULL, NULL, NULL, NULL, &response ); + + } else { +#if SASL_VERSION_MAJOR >= 2 + errstr = sasl_errdetail( ctx ); +#endif + send_ldap_result( conn, op, rc = slap_sasl_err2ldap( sc ), + NULL, errstr, NULL, NULL ); + } + +#if SASL_VERSION_MAJOR < 2 + if( response.bv_len ) { + ch_free( response.bv_val ); + } +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_bind: rc=%d\n", rc )); +#else + Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rc, 0, 0); +#endif + + +#else + send_ldap_result( conn, op, rc = LDAP_UNAVAILABLE, + NULL, "SASL not supported", NULL, NULL ); +#endif + + return rc; +} + +char* slap_sasl_secprops( const char *in ) +{ +#ifdef HAVE_CYRUS_SASL + int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops ); + + return rc == LDAP_SUCCESS ? NULL : "Invalid security properties"; +#else + return "SASL not supported"; +#endif +} diff --git a/servers/slapd/saslauthz.c b/servers/slapd/saslauthz.c new file mode 100644 index 0000000000000000000000000000000000000000..2f9ee9b74a12e514870cf7f731254c7ce675bb96 --- /dev/null +++ b/servers/slapd/saslauthz.c @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2000, Mark Adamson, Carnegie Mellon. All rights reserved. + * This software is not subject to any license of Carnegie Mellon 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. + * + * The name "Carnegie Mellon" must not be used to endorse or promote + * products derived from this software without prior written permission. + * + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> +#include <ac/string.h> + +#include "slap.h" + +#ifdef HAVE_CYRUS_SASL +#include <limits.h> + +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#else +#include <sasl.h> +#endif + +#include <ldap_pvt.h> +#endif + +/* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]] */ + +static int slap_parseURI( struct berval *uri, + struct berval *searchbase, int *scope, Filter **filter ) +{ + struct berval bv; + int rc; + LDAPURLDesc *ludp; + + assert( uri != NULL && uri->bv_val != NULL ); + searchbase->bv_val = NULL; + searchbase->bv_len = 0; + *scope = -1; + *filter = NULL; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_parseURI: parsing %s\n", uri->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 ); +#endif + + /* If it does not look like a URI, assume it is a DN */ + if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) { + bv.bv_val = uri->bv_val + sizeof("dn:")-1; + bv.bv_val += strspn( bv.bv_val, " " ); + +is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val); + rc = dnNormalize2( NULL, &bv, searchbase ); + if (rc == LDAP_SUCCESS) { + *scope = LDAP_SCOPE_BASE; + } + return( rc ); + } + + rc = ldap_url_parse( uri->bv_val, &ludp ); + if ( rc == LDAP_URL_ERR_BADSCHEME ) { + bv.bv_val = uri->bv_val; + goto is_dn; + } + + if ( rc != LDAP_URL_SUCCESS ) { + return( LDAP_PROTOCOL_ERROR ); + } + + /* could check the hostname here */ + + /* Grab the scope */ + *scope = ludp->lud_scope; + + /* Grab the filter */ + if ( ludp->lud_filter ) { + *filter = str2filter( ludp->lud_filter ); + if ( *filter == NULL ) + rc = LDAP_PROTOCOL_ERROR; + } + + /* Grab the searchbase */ + if ( rc == LDAP_URL_SUCCESS ) { + bv.bv_val = ludp->lud_dn; + bv.bv_len = strlen( bv.bv_val ); + rc = dnNormalize2( NULL, &bv, searchbase ); + } + + ldap_free_urldesc( ludp ); + + return( rc ); +} + + +int slap_sasl_regexp_config( const char *match, const char *replace ) +{ +#ifdef HAVE_CYRUS_SASL + const char *c; + int rc, n; + SaslRegexp_t *reg; + struct berval bv, nbv; + + SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp, + (nSaslRegexp + 1) * sizeof(SaslRegexp_t) ); + reg = &( SaslRegexp[nSaslRegexp] ); + ber_str2bv( match, 0, 0, &bv ); + rc = dnNormalize2( NULL, &bv, &nbv ); + if ( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_regexp_config: \"%s\" could not be normalized.\n", + match )); +#else + Debug( LDAP_DEBUG_ANY, + "SASL match pattern %s could not be normalized.\n", + match, 0, 0 ); +#endif + return( rc ); + } + reg->sr_match = nbv.bv_val; + + ber_str2bv( replace, 0, 0, &bv ); + rc = dnNormalize2( NULL, &bv, &nbv ); + if ( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_regexp_config: \"%s\" could not be normalized.\n", + replace )); +#else + Debug( LDAP_DEBUG_ANY, + "SASL replace pattern %s could not be normalized.\n", + replace, 0, 0 ); +#endif + return( rc ); + } + reg->sr_replace = nbv.bv_val; + + /* Precompile matching pattern */ + rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE ); + if ( rc ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_regexp_config: \"%s\" could not be compiled.\n", + reg->sr_match )); +#else + Debug( LDAP_DEBUG_ANY, + "SASL match pattern %s could not be compiled by regexp engine\n", + reg->sr_match, 0, 0 ); +#endif + + return( LDAP_OPERATIONS_ERROR ); + } + + /* Precompile replace pattern. Find the $<n> placeholders */ + reg->sr_offset[0] = -2; + n = 1; + for ( c = reg->sr_replace; *c; c++ ) { + if ( *c == '\\' ) { + c++; + continue; + } + if ( *c == '$' ) { + if ( n == SASLREGEX_REPLACE ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ERR, + "slap_sasl_regexp_config: \"%s\" has too many $n " + "placeholders (max %d)\n", + reg->sr_replace, SASLREGEX_REPLACE )); +#else + Debug( LDAP_DEBUG_ANY, + "SASL replace pattern %s has too many $n " + "placeholders (max %d)\n", + reg->sr_replace, SASLREGEX_REPLACE, 0 ); +#endif + + return( LDAP_OPERATIONS_ERROR ); + } + reg->sr_offset[n] = c - reg->sr_replace; + n++; + } + } + + /* Final placeholder, after the last $n */ + reg->sr_offset[n] = c - reg->sr_replace; + n++; + reg->sr_offset[n] = -1; + + nSaslRegexp++; +#endif + return( LDAP_SUCCESS ); +} + + +#ifdef HAVE_CYRUS_SASL + +/* Take the passed in SASL name and attempt to convert it into an + LDAP URI to find the matching LDAP entry, using the pattern matching + strings given in the saslregexp config file directive(s) */ +static int slap_sasl_regexp( struct berval *in, struct berval *out ) +{ + char *saslname = in->bv_val; + int i, n, len, insert; + SaslRegexp_t *reg; + + out->bv_val = NULL; + out->bv_len = 0; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_regexp: converting SASL name %s\n", saslname )); +#else + Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n", + saslname, 0, 0 ); +#endif + + if (( saslname == NULL ) || ( nSaslRegexp == 0 )) + return( 0 ); + + /* Match the normalized SASL name to the saslregexp patterns */ + for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) { + if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE, + reg->sr_strings, 0) == 0 ) + break; + } + + if( i >= nSaslRegexp ) + return( 0 ); + + /* + * The match pattern may have been of the form "a(b.*)c(d.*)e" and the + * replace pattern of the form "x$1y$2z". The returned string needs + * to replace the $1,$2 with the strings that matched (b.*) and (d.*) + */ + + + /* Get the total length of the final URI */ + + n=1; + len = 0; + while( reg->sr_offset[n] >= 0 ) { + /* Len of next section from replacement string (x,y,z above) */ + len += reg->sr_offset[n] - reg->sr_offset[n-1] - 2; + if( reg->sr_offset[n+1] < 0) + break; + + /* Len of string from saslname that matched next $i (b,d above) */ + i = reg->sr_replace[ reg->sr_offset[n] + 1 ] - '0'; + len += reg->sr_strings[i].rm_eo - reg->sr_strings[i].rm_so; + n++; + } + out->bv_val = ch_malloc( len + 1 ); + out->bv_len = len; + + /* Fill in URI with replace string, replacing $i as we go */ + n=1; + insert = 0; + while( reg->sr_offset[n] >= 0) { + /* Paste in next section from replacement string (x,y,z above) */ + len = reg->sr_offset[n] - reg->sr_offset[n-1] - 2; + strncpy( out->bv_val+insert, reg->sr_replace + reg->sr_offset[n-1] + 2, len); + insert += len; + if( reg->sr_offset[n+1] < 0) + break; + + /* Paste in string from saslname that matched next $i (b,d above) */ + i = reg->sr_replace[ reg->sr_offset[n] + 1 ] - '0'; + len = reg->sr_strings[i].rm_eo - reg->sr_strings[i].rm_so; + strncpy( out->bv_val+insert, saslname + reg->sr_strings[i].rm_so, len ); + insert += len; + + n++; + } + + out->bv_val[insert] = '\0'; +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_regexp: converted SASL name to %s\n", out->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_sasl_regexp: converted SASL name to %s\n", out->bv_val, 0, 0 ); +#endif + + return( 1 ); +} + +/* Two empty callback functions to avoid sending results */ +static void sasl_sc_r( Connection *conn, Operation *o, ber_tag_t tag, + ber_int_t msgid, ber_int_t err, const char *matched, + const char *text, BerVarray ref, const char *resoid, + struct berval *resdata, struct berval *sasldata, LDAPControl **c) +{ +} + +static void sasl_sc_s( Connection *conn, Operation *o, ber_int_t err, + const char *matched, const char *text, BerVarray refs, LDAPControl **c, + int nentries) +{ +} + +/* This callback actually does some work...*/ +static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o, + Entry *e, AttributeName *an, int ao, LDAPControl **c) +{ + struct berval *ndn = o->o_callback->sc_private; + + /* We only want to be called once */ + if (ndn->bv_val) { + free(ndn->bv_val); + ndn->bv_val = NULL; +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1, + "slap_sasl2dn: search DN returned more than 1 entry\n" )); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 ); +#endif + return -1; + } else { + ber_dupbv(ndn, &e->e_nname); + return 0; + } +} + +/* + * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH") + * return the LDAP DN to which it matches. The SASL regexp rules in the config + * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a + * search with scope=base), just return the URI (or its searchbase). Otherwise + * an internal search must be done, and if that search returns exactly one + * entry, return the DN of that one entry. + */ + +void slap_sasl2dn( struct berval *saslname, struct berval *dn ) +{ + struct berval uri = {0, NULL}; + struct berval searchbase = {0, NULL}; + int rc, scope; + Backend *be; + Filter *filter=NULL; + slap_callback cb = {sasl_sc_r, sasl_sc_s, sasl_sc_sasl2dn, NULL}; + Operation op = {0}; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl2dn: converting SASL name %s to DN.\n", saslname->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "==>slap_sasl2dn: Converting SASL name %s to a DN\n", saslname->bv_val, 0,0 ); +#endif + dn->bv_val = NULL; + dn->bv_len = 0; + cb.sc_private = dn; + + /* Convert the SASL name into an LDAP URI */ + if( !slap_sasl_regexp( saslname, &uri ) ) + goto FINISHED; + + rc = slap_parseURI( &uri, &searchbase, &scope, &filter ); + if( rc ) { + goto FINISHED; + } + + /* Massive shortcut: search scope == base */ + if( scope == LDAP_SCOPE_BASE ) { + *dn = searchbase; + searchbase.bv_len = 0; + searchbase.bv_val = NULL; + goto FINISHED; + } + + /* Must do an internal search */ + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1, + "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n", + searchbase.bv_val, scope )); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n", + searchbase.bv_val, scope, 0 ); +#endif + + be = select_backend( &searchbase, 0, 1 ); + if(( be == NULL ) || ( be->be_search == NULL)) + goto FINISHED; + suffix_alias( be, &searchbase ); + + op.o_tag = LDAP_REQ_SEARCH; + op.o_protocol = LDAP_VERSION3; + op.o_ndn = *saslname; + op.o_callback = &cb; + op.o_time = slap_get_time(); + + (*be->be_search)( be, /*conn*/NULL, &op, /*base*/NULL, &searchbase, + scope, /*deref=*/1, /*sizelimit=*/1, /*time=*/0, filter, /*fstr=*/NULL, + /*attrs=*/NULL, /*attrsonly=*/0 ); + +FINISHED: + if( searchbase.bv_len ) ch_free( searchbase.bv_val ); + if( filter ) filter_free( filter ); + if( uri.bv_val ) ch_free( uri.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl2dn: Converted SASL name to %s\n", + dn->bv_len ? dn->bv_val : "<nothing>" )); +#else + Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n", + dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 ); +#endif + + return; +} + +typedef struct smatch_info { + struct berval *dn; + int match; +} smatch_info; + +static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o, + Entry *e, AttributeName *an, int ao, LDAPControl **c) +{ + smatch_info *sm = o->o_callback->sc_private; + + if (dn_match(sm->dn, &e->e_nname)) { + sm->match = 1; + return -1; /* short-circuit the search */ + } else { + return 1; + } +} + +/* + * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base + * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise, + * the rule must be used as an internal search for entries. If that search + * returns the *assertDN entry, the match is successful. + * + * The assertDN should not have the dn: prefix + */ + +static +int slap_sasl_match( struct berval *rule, struct berval *assertDN, struct berval *authc ) +{ + struct berval searchbase = {0, NULL}; + int rc, scope; + Backend *be; + Filter *filter=NULL; + regex_t reg; + smatch_info sm; + slap_callback cb = { sasl_sc_r, sasl_sc_s, sasl_sc_smatch, NULL }; + Operation op = {0}; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 ); +#endif + + rc = slap_parseURI( rule, &searchbase, &scope, &filter ); + if( rc != LDAP_SUCCESS ) + goto CONCLUDED; + + /* Massive shortcut: search scope == base */ + if( scope == LDAP_SCOPE_BASE ) { + rc = regcomp(®, searchbase.bv_val, + REG_EXTENDED|REG_ICASE|REG_NOSUB); + if ( rc == 0 ) { + rc = regexec(®, assertDN->bv_val, 0, NULL, 0); + regfree( ® ); + } + if ( rc == 0 ) + rc = LDAP_SUCCESS; + else + rc = LDAP_INAPPROPRIATE_AUTH; + goto CONCLUDED; + } + + /* Must run an internal search. */ + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1, + "slap_sasl_match: performing internal search (base=%s, scope=%d)\n", + searchbase.bv_val, scope )); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_sasl_match: performing internal search (base=%s, scope=%d)\n", + searchbase.bv_val, scope, 0 ); +#endif + + be = select_backend( &searchbase, 0, 1 ); + if(( be == NULL ) || ( be->be_search == NULL)) { + rc = LDAP_INAPPROPRIATE_AUTH; + goto CONCLUDED; + } + suffix_alias( be, &searchbase ); + + sm.dn = assertDN; + sm.match = 0; + cb.sc_private = &sm; + + op.o_tag = LDAP_REQ_SEARCH; + op.o_protocol = LDAP_VERSION3; + op.o_ndn = *authc; + op.o_callback = &cb; + op.o_time = slap_get_time(); + + (*be->be_search)( be, /*conn=*/NULL, &op, /*base=*/NULL, &searchbase, + scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL, + /*attrs=*/NULL, /*attrsonly=*/0 ); + + if (sm.match) + rc = LDAP_SUCCESS; + else + rc = LDAP_INAPPROPRIATE_AUTH; + +CONCLUDED: + if( searchbase.bv_len ) ch_free( searchbase.bv_val ); + if( filter ) filter_free( filter ); +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_match: comparison returned %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0); +#endif + + return( rc ); +} + + +/* + * This function answers the question, "Can this ID authorize to that ID?", + * based on authorization rules. The rules are stored in the *searchDN, in the + * 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 + */ +static int +slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct berval *attr, struct berval *authc) +{ + const char *errmsg; + int i, rc; + BerVarray vals=NULL; + AttributeDescription *ad=NULL; + struct berval bv; + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_check_authz: does %s match %s rule in %s?\n", + assertDN->bv_val, attr->bv_val, searchDN->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "==>slap_sasl_check_authz: does %s match %s rule in %s?\n", + assertDN->bv_val, attr->bv_val, searchDN->bv_val); +#endif + + rc = slap_bv2ad( attr, &ad, &errmsg ); + 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 ); + 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 ); + if ( rc == LDAP_SUCCESS ) + goto COMPLETE; + } + rc = LDAP_INAPPROPRIATE_AUTH; + +COMPLETE: + if( vals ) ber_bvarray_free( vals ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_check_authz: %s check returning %s\n", attr->bv_val, rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<==slap_sasl_check_authz: %s check returning %d\n", attr->bv_val, rc, 0); +#endif + + return( rc ); +} +#endif /* HAVE_CYRUS_SASL */ + + +/* Check if a bind can SASL authorize to another identity. + Accepts authorization DN's with "dn:" prefix */ + +static struct berval sasl_authz_src = { + sizeof(SASL_AUTHZ_SOURCE_ATTR)-1, SASL_AUTHZ_SOURCE_ATTR }; + +static struct berval sasl_authz_dst = { + sizeof(SASL_AUTHZ_DEST_ATTR)-1, SASL_AUTHZ_DEST_ATTR }; + +int slap_sasl_authorized( struct berval *authcDN, struct berval *authzDN ) +{ + int rc = LDAP_INAPPROPRIATE_AUTH; + +#ifdef HAVE_CYRUS_SASL + /* User binding as anonymous */ + if ( authzDN == NULL ) { + rc = LDAP_SUCCESS; + goto DONE; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, + "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 ); +#endif + + /* If person is authorizing to self, succeed */ + if ( dn_match( authcDN, authzDN ) ) { + rc = LDAP_SUCCESS; + goto DONE; + } + + /* Check source rules */ + rc = slap_sasl_check_authz( authcDN, authzDN, &sasl_authz_src, + authcDN ); + if( rc == LDAP_SUCCESS ) { + goto DONE; + } + + /* Check destination rules */ + rc = slap_sasl_check_authz( authzDN, authcDN, &sasl_authz_dst, + authcDN ); + if( rc == LDAP_SUCCESS ) { + goto DONE; + } + + rc = LDAP_INAPPROPRIATE_AUTH; + +DONE: +#endif + +#ifdef NEW_LOGGING + LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, + "slap_sasl_authorized: return %d\n", rc )); +#else + Debug( LDAP_DEBUG_TRACE, + "<== slap_sasl_authorized: return %d\n", rc, 0, 0 ); +#endif + + return( rc ); +} diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index ba16d9b0f13540041d9b221fcc4db4888f99a794..4be9256d060c095c762d678141cba82b4c777aef 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -1,179 +1,104 @@ -/* schema.c - routines to enforce schema definitions */ +/* schema.c - routines to manage schema definitions */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -extern Attribute *attr_find(); -extern char **str2charray(); -extern void charray_merge(); +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> -extern struct objclass *global_oc; -extern int global_schemacheck; +#include "slap.h" +#include "ldap_pvt.h" -static struct objclass *oc_find(); -static int oc_check_required(); -static int oc_check_allowed(); -/* - * oc_check - check that entry e conforms to the schema required by - * its object class(es). returns 0 if so, non-zero otherwise. - */ +#if defined( SLAPD_SCHEMA_DN ) int -oc_schema_check( Entry *e ) +schema_info( Entry **entry, const char **text ) { - Attribute *a, *aoc; - struct objclass *oc; - int i; - int ret = 0; - - /* find the object class attribute - could error out here */ - if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) { - Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n", - e->e_dn, 0, 0 ); - return( 0 ); - } - - /* check that the entry has required attrs for each oc */ - for ( i = 0; aoc->a_vals[i] != NULL; i++ ) { - if ( oc_check_required( e, aoc->a_vals[i]->bv_val ) != 0 ) { - Debug( LDAP_DEBUG_ANY, - "Entry (%s), required attr (%s) missing\n", - e->e_dn, aoc->a_vals[i]->bv_val, 0 ); - ret = 1; - } - } + AttributeDescription *ad_structuralObjectClass + = slap_schema.si_ad_structuralObjectClass; + AttributeDescription *ad_objectClass + = slap_schema.si_ad_objectClass; - if ( ret != 0 ) { - return( ret ); - } + Entry *e; + struct berval vals[2]; - /* check that each attr in the entry is allowed by some oc */ - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) { - Debug( LDAP_DEBUG_ANY, - "Entry (%s), attr (%s) not allowed\n", - e->e_dn, a->a_type, 0 ); - ret = 1; - } - } + vals[1].bv_val = NULL; - return( ret ); -} + e = (Entry *) ch_calloc( 1, sizeof(Entry) ); -static int -oc_check_required( Entry *e, char *ocname ) -{ - struct objclass *oc; - int i; - Attribute *a; + e->e_attrs = NULL; + ber_str2bv( SLAPD_SCHEMA_DN, sizeof(SLAPD_SCHEMA_DN)-1, 1, &e->e_name); + (void) dnNormalize2( NULL, &e->e_name, &e->e_nname ); + e->e_private = NULL; - /* find global oc defn. it we don't know about it assume it's ok */ - if ( (oc = oc_find( ocname )) == NULL ) { - return( 0 ); - } + vals[0].bv_val = "subentry"; + vals[0].bv_len = sizeof("subentry")-1; + attr_merge( e, ad_structuralObjectClass, vals ); - /* for each required attribute */ - for ( i = 0; oc->oc_required[i] != NULL; i++ ) { - /* see if it's in the entry */ - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - if ( strcasecmp( a->a_type, oc->oc_required[i] ) - == 0 ) { - break; - } - } + vals[0].bv_val = "top"; + vals[0].bv_len = sizeof("top")-1; + attr_merge( e, ad_objectClass, vals ); - /* not there => schema violation */ - if ( a == NULL ) { - return( 1 ); - } - } + vals[0].bv_val = "subentry"; + vals[0].bv_len = sizeof("subentry")-1; + attr_merge( e, ad_objectClass, vals ); - return( 0 ); -} + vals[0].bv_val = "subschema"; + vals[0].bv_len = sizeof("subschema")-1; + attr_merge( e, ad_objectClass, vals ); -static int -oc_check_allowed( char *type, struct berval **ocl ) -{ - struct objclass *oc; - int i, j; + vals[0].bv_val = "extensibleObject"; + vals[0].bv_len = sizeof("extensibleObject")-1; + attr_merge( e, ad_objectClass, vals ); - /* always allow objectclass attribute */ - if ( strcasecmp( type, "objectclass" ) == 0 ) { - return( 0 ); - } + { + int rc; + AttributeDescription *desc = NULL; + struct berval rdn = { sizeof(SLAPD_SCHEMA_DN)-1, + SLAPD_SCHEMA_DN }; + vals[0].bv_val = strchr( rdn.bv_val, '=' ); - /* check that the type appears as req or opt in at least one oc */ - for ( i = 0; ocl[i] != NULL; i++ ) { - /* if we know about the oc */ - if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) { - /* does it require the type? */ - for ( j = 0; oc->oc_required[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_required[j], type ) - == 0 ) { - return( 0 ); - } - } - /* does it allow the type? */ - for ( j = 0; oc->oc_allowed[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_allowed[j], type ) - == 0 || strcmp( oc->oc_allowed[j], "*" ) - == 0 ) - { - return( 0 ); - } - } - /* maybe the next oc allows it */ - - /* we don't know about the oc. assume it allows it */ - } else { - return( 0 ); + if( vals[0].bv_val == NULL ) { + *text = "improperly configured subschema subentry"; + return LDAP_OTHER; } - } - /* not allowed by any oc */ - return( 1 ); -} + vals[0].bv_val++; + vals[0].bv_len = rdn.bv_len - (vals[0].bv_val - rdn.bv_val); + rdn.bv_len -= vals[0].bv_len + 1; -static struct objclass * -oc_find( char *ocname ) -{ - struct objclass *oc; + rc = slap_bv2ad( &rdn, &desc, text ); - for ( oc = global_oc; oc != NULL; oc = oc->oc_next ) { - if ( strcasecmp( oc->oc_name, ocname ) == 0 ) { - return( oc ); + if( rc != LDAP_SUCCESS ) { + entry_free( e ); + *text = "improperly configured subschema subentry"; + return LDAP_OTHER; } - } - return( NULL ); -} - -#ifdef LDAP_DEBUG - -static -oc_print( struct objclass *oc ) -{ - int i; - - printf( "objectclass %s\n", oc->oc_name ); - if ( oc->oc_required != NULL ) { - printf( "\trequires %s", oc->oc_required[0] ); - for ( i = 1; oc->oc_required[i] != NULL; i++ ) { - printf( ",%s", oc->oc_required[i] ); - } - printf( "\n" ); + attr_merge( e, desc, vals ); } - if ( oc->oc_allowed != NULL ) { - printf( "\tallows %s", oc->oc_allowed[0] ); - for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) { - printf( ",%s", oc->oc_allowed[i] ); - } - printf( "\n" ); + + if ( syn_schema_info( e ) + || mr_schema_info( e ) + || mru_schema_info( e ) + || at_schema_info( e ) + || oc_schema_info( e ) ) + { + /* Out of memory, do something about it */ + entry_free( e ); + *text = "out of memory"; + return LDAP_OTHER; } + + *entry = e; + return LDAP_SUCCESS; } - #endif diff --git a/servers/slapd/schema_check.c b/servers/slapd/schema_check.c index bedbb14d4fc842d5d7a4c1b12d7f6d00d94bab91..ec1def4308b4488ef9c224b2daf2324d157ab94f 100644 --- a/servers/slapd/schema_check.c +++ b/servers/slapd/schema_check.c @@ -165,7 +165,7 @@ entry_schema_check( if ( aoc == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "schema", LDAP_LEVEL_INFO, - "entry_schema_check: No objectClass for entry (%s).\n" + "entry_schema_check: No objectClass for entry (%s).\n", e->e_dn )); #else Debug( LDAP_DEBUG_ANY, "No objectClass for entry (%s)\n", diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index d8d82496b7e3d6651f36025ffe138842a18f1ec4..8695cd8fe63855189fc1f100c9bf0ab59143a48e 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -43,6 +43,7 @@ #define generalizedTimeMatch caseIgnoreIA5Match #define generalizedTimeOrderingMatch caseIgnoreIA5Match #define uniqueMemberMatch dnMatch +#define integerFirstComponentMatch integerMatch /* approx matching rules */ #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4" @@ -54,15 +55,15 @@ #define IA5StringApproxIndexer approxIndexer #define IA5StringApproxFilter approxFilter -/* orderring matching rules */ +/* ordering matching rules */ #define caseIgnoreOrderingMatch caseIgnoreMatch #define caseExactOrderingMatch caseExactMatch +#define integerOrderingMatch integerMatch /* unimplemented matching routines */ #define caseIgnoreListMatch NULL #define caseIgnoreListSubstringsMatch NULL #define protocolInformationMatch NULL -#define integerFirstComponentMatch NULL #ifdef SLAPD_ACI_ENABLED #define OpenLDAPaciMatch NULL @@ -82,9 +83,20 @@ #define telephoneNumberSubstringsIndexer caseIgnoreIA5SubstringsIndexer #define telephoneNumberSubstringsFilter caseIgnoreIA5SubstringsFilter -/* must match OIDs below */ -#define caseExactMatchOID "2.5.13.5" -#define caseExactSubstringsMatchOID "2.5.13.7" +static MatchingRule *caseExactMatchingRule; +static MatchingRule *caseExactSubstringsMatchingRule; +static MatchingRule *integerFirstComponentMatchingRule; + +static const struct MatchingRulePtr { + const char *oid; + MatchingRule **mr; +} mr_ptr [] = { + /* must match OIDs below */ + { "2.5.13.5", &caseExactMatchingRule }, + { "2.5.13.7", &caseExactSubstringsMatchingRule }, + { "2.5.13.29", &integerFirstComponentMatchingRule } +}; + static char *bvcasechr( struct berval *bv, int c, ber_len_t *len ) { @@ -539,6 +551,7 @@ UTF8StringNormalize( ber_mem2bv( p, val->bv_len - (p - val->bv_val), 1, normalized ); e = normalized->bv_val + val->bv_len - (p - val->bv_val); + assert( normalized->bv_len ); assert( normalized->bv_val ); p = q = normalized->bv_val; @@ -646,30 +659,6 @@ err: return NULL; } -/* Strip characters with the 8th bit set */ -static char * -strip8bitChars( - char *in ) -{ - char *p = in, *q; - - if( in == NULL ) { - return NULL; - } - while( *p ) { - if( *p & 0x80 ) { - q = p; - while( *++q & 0x80 ) { - /* empty */ - } - p = AC_MEMCPY(p, q, strlen(q) + 1); - } else { - p++; - } - } - return in; -} - #ifndef SLAPD_APPROX_OLDSINGLESTRING #if defined(SLAPD_APPROX_INITIALS) @@ -689,31 +678,27 @@ approxMatch( struct berval *value, void *assertedValue ) { - char *val, *nval, *assertv, **values, **words, *c; + struct berval *nval, *assertv; + char *val, **values, **words, *c; int i, count, len, nextchunk=0, nextavail=0; - size_t avlen; /* Yes, this is necessary */ - nval = UTF8normalize( value, LDAP_UTF8_NOCASEFOLD ); + nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX ); if( nval == NULL ) { *matchp = 1; return LDAP_SUCCESS; } - strip8bitChars( nval ); /* Yes, this is necessary */ - assertv = UTF8normalize( ((struct berval *)assertedValue), - LDAP_UTF8_NOCASEFOLD ); + assertv = UTF8bvnormalize( ((struct berval *)assertedValue), NULL, LDAP_UTF8_APPROX ); if( assertv == NULL ) { - ch_free( nval ); + ber_bvfree( nval ); *matchp = 1; return LDAP_SUCCESS; } - strip8bitChars( assertv ); - avlen = strlen( assertv ); /* Isolate how many words there are */ - for( c=nval,count=1; *c; c++ ) { + for ( c = nval->bv_val, count = 1; *c; c++ ) { c = strpbrk( c, SLAPD_APPROX_DELIMITER ); if ( c == NULL ) break; *c = '\0'; @@ -723,7 +708,7 @@ approxMatch( /* Get a phonetic copy of each word */ words = (char **)ch_malloc( count * sizeof(char *) ); values = (char **)ch_malloc( count * sizeof(char *) ); - for( c=nval,i=0; i<count; i++,c+=strlen(c)+1 ) { + for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) { words[i] = c; values[i] = phonetic(c); } @@ -731,8 +716,8 @@ approxMatch( /* Work through the asserted value's words, to see if at least some of the words are there, in the same order. */ len = 0; - while ( (size_t) nextchunk < avlen ) { - len = strcspn( assertv + nextchunk, SLAPD_APPROX_DELIMITER); + while ( (ber_len_t) nextchunk < assertv->bv_len ) { + len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER); if( len == 0 ) { nextchunk++; continue; @@ -741,7 +726,7 @@ approxMatch( else if( len == 1 ) { /* Single letter words need to at least match one word's initial */ for( i=nextavail; i<count; i++ ) - if( !strncasecmp( assertv+nextchunk, words[i], 1 )) { + if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) { nextavail=i+1; break; } @@ -749,8 +734,8 @@ approxMatch( #endif else { /* Isolate the next word in the asserted value and phonetic it */ - assertv[nextchunk+len] = '\0'; - val = phonetic( assertv + nextchunk ); + assertv->bv_val[nextchunk+len] = '\0'; + val = phonetic( assertv->bv_val + nextchunk ); /* See if this phonetic chunk is in the remaining words of *value */ for( i=nextavail; i<count; i++ ){ @@ -781,13 +766,13 @@ approxMatch( } /* Cleanup allocs */ - free( assertv ); + ber_bvfree( assertv ); for( i=0; i<count; i++ ) { ch_free( values[i] ); } ch_free( values ); ch_free( words ); - ch_free( nval ); + ber_bvfree( nval ); return LDAP_SUCCESS; } @@ -802,18 +787,19 @@ approxIndexer( BerVarray values, BerVarray *keysp ) { - char *val, *c; + char *c; int i,j, len, wordcount, keycount=0; struct berval *newkeys; BerVarray keys=NULL; for( j=0; values[j].bv_val != NULL; j++ ) { + struct berval val = { 0, NULL }; /* Yes, this is necessary */ - val = UTF8normalize( &values[j], LDAP_UTF8_NOCASEFOLD ); - strip8bitChars( val ); + UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX ); + assert( val.bv_val != NULL ); /* Isolate how many words there are. There will be a key for each */ - for( wordcount=0,c=val; *c; c++) { + for( wordcount = 0, c = val.bv_val; *c; c++) { len = strcspn(c, SLAPD_APPROX_DELIMITER); if( len >= SLAPD_APPROX_WORDLEN ) wordcount++; c+= len; @@ -829,7 +815,7 @@ approxIndexer( keys = newkeys; /* Get a phonetic copy of each word */ - for( c=val,i=0; i<wordcount; c+=len+1 ) { + for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) { len = strlen( c ); if( len < SLAPD_APPROX_WORDLEN ) continue; ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] ); @@ -837,7 +823,7 @@ approxIndexer( i++; } - free( val ); + ber_memfree( val.bv_val ); } keys[keycount].bv_val = NULL; *keysp = keys; @@ -855,23 +841,23 @@ approxFilter( void * assertValue, BerVarray *keysp ) { - char *val, *c; + char *c; int i, count, len; + struct berval *val; BerVarray keys; /* Yes, this is necessary */ - val = UTF8normalize( ((struct berval *)assertValue), - LDAP_UTF8_NOCASEFOLD ); - if( val == NULL ) { + val = UTF8bvnormalize( ((struct berval *)assertValue), NULL, LDAP_UTF8_APPROX ); + if( val == NULL || val->bv_val == NULL ) { keys = (struct berval *)ch_malloc( sizeof(struct berval) ); keys[0].bv_val = NULL; *keysp = keys; + ber_bvfree( val ); return LDAP_SUCCESS; } - strip8bitChars( val ); /* Isolate how many words there are. There will be a key for each */ - for( count=0,c=val; *c; c++) { + for( count = 0,c = val->bv_val; *c; c++) { len = strcspn(c, SLAPD_APPROX_DELIMITER); if( len >= SLAPD_APPROX_WORDLEN ) count++; c+= len; @@ -883,14 +869,14 @@ approxFilter( keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) ); /* Get a phonetic copy of each word */ - for( c=val,i=0; i<count; c+=len+1 ) { + for( c = val->bv_val, i = 0; i < count; c += len + 1 ) { len = strlen(c); if( len < SLAPD_APPROX_WORDLEN ) continue; ber_str2bv( phonetic( c ), 0, 0, &keys[i] ); i++; } - free( val ); + ber_bvfree( val ); keys[count].bv_val = NULL; *keysp = keys; @@ -1025,8 +1011,8 @@ caseExactMatch( struct berval *value, void *assertedValue ) { - *matchp = UTF8normcmp( value->bv_val, - ((struct berval *) assertedValue)->bv_val, + *matchp = UTF8bvnormcmp( value, + (struct berval *) assertedValue, LDAP_UTF8_NOCASEFOLD ); return LDAP_SUCCESS; } @@ -1048,7 +1034,7 @@ caseExactIgnoreSubstringsMatch( char *nav = NULL; unsigned casefold; - casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID ) + casefold = ( mr != caseExactSubstringsMatchingRule ) ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD; if ( UTF8bvnormalize( value, &left, casefold ) == NULL ) { @@ -1218,13 +1204,12 @@ static int caseExactIgnoreIndexer( slen = syntax->ssyn_oidlen; mlen = mr->smr_oidlen; - casefold = strcmp( mr->smr_oid, caseExactMatchOID ) + casefold = ( mr != caseExactMatchingRule ) ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD; for( i=0; values[i].bv_val != NULL; i++ ) { struct berval value; - ber_str2bv( UTF8normalize( &values[i], casefold ), 0, 0, - &value ); + UTF8bvnormalize( &values[i], &value, casefold ); HASH_Init( &HASHcontext ); if( prefix != NULL && prefix->bv_len > 0 ) { @@ -1264,19 +1249,19 @@ static int caseExactIgnoreFilter( BerVarray keys; HASH_CONTEXT HASHcontext; unsigned char HASHdigest[HASH_BYTES]; - struct berval value; + struct berval value = { 0, NULL }; struct berval digest; + digest.bv_val = HASHdigest; digest.bv_len = sizeof(HASHdigest); slen = syntax->ssyn_oidlen; mlen = mr->smr_oidlen; - casefold = strcmp( mr->smr_oid, caseExactMatchOID ) + casefold = ( mr != caseExactMatchingRule ) ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD; - ber_str2bv( UTF8normalize( ((struct berval *) assertValue), casefold ), - 0, 0, &value ); + UTF8bvnormalize( (struct berval *) assertValue, &value, casefold ); /* This usually happens if filter contains bad UTF8 */ if( value.bv_val == NULL ) { keys = ch_malloc( sizeof( struct berval ) ); @@ -1339,13 +1324,12 @@ static int caseExactIgnoreSubstringsIndexer( /* we should have at least one value at this point */ assert( i > 0 ); - casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID ) + casefold = ( mr != caseExactSubstringsMatchingRule ) ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD; nvalues = ch_malloc( sizeof( struct berval ) * (i+1) ); for( i=0; values[i].bv_val != NULL; i++ ) { - ber_str2bv( UTF8normalize( &values[i], casefold ), - 0, 0, &nvalues[i] ); + UTF8bvnormalize( &values[i], &nvalues[i], casefold ); } nvalues[i].bv_val = NULL; values = nvalues; @@ -1510,7 +1494,7 @@ static int caseExactIgnoreSubstringsFilter( struct berval *value; struct berval digest; - casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID ) + casefold = ( mr != caseExactSubstringsMatchingRule ) ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD; sa = UTF8SubstringsassertionNormalize( assertValue, casefold ); @@ -1675,12 +1659,33 @@ caseIgnoreMatch( struct berval *value, void *assertedValue ) { - *matchp = UTF8normcmp( value->bv_val, - ((struct berval *) assertedValue)->bv_val, + *matchp = UTF8bvnormcmp( value, + (struct berval *) assertedValue, LDAP_UTF8_CASEFOLD ); return LDAP_SUCCESS; } +/* Remove all spaces and '-' characters */ +static int +telephoneNumberNormalize( + Syntax *syntax, + struct berval *val, + struct berval *normalized ) +{ + char *p, *q; + + q = normalized->bv_val = ch_malloc( val->bv_len + 1 ); + + for( p = val->bv_val; *p; p++ ) + if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) + *q++ = *p; + *q = '\0'; + + normalized->bv_len = q - normalized->bv_val; + + return LDAP_SUCCESS; +} + static int oidValidate( Syntax *syntax, @@ -1730,85 +1735,47 @@ integerMatch( void *assertedValue ) { char *v, *av; - int vsign=0, avsign=0; + int vsign = 1, avsign = 1; /* default sign = '+' */ struct berval *asserted; ber_len_t vlen, avlen; + int match; - - /* Start off pessimistic */ - *matchp = 1; - - /* Skip past leading spaces/zeros, and get the sign of the *value number */ + /* Skip leading space/sign/zeroes, and get the sign of the *value number */ v = value->bv_val; vlen = value->bv_len; - while( vlen ) { - if( ASCII_SPACE(*v) || ( *v == '0' )) { - /* empty -- skip spaces */ - } - else if ( *v == '+' ) { - vsign = 1; - } - else if ( *v == '-' ) { + if( mr == integerFirstComponentMatchingRule ) { + char *tmp = memchr( v, '$', vlen ); + if( tmp ) + vlen = tmp - v; + while( vlen && ASCII_SPACE( v[vlen-1] )) + vlen--; + } + for( ; vlen && ( *v < '1' || '9' < *v ); v++, vlen-- ) /* ANSI 2.2.1 */ + if( *v == '-' ) vsign = -1; - } - else if ( ASCII_DIGIT(*v) ) { - if ( vsign == 0 ) vsign = 1; - vsign *= 2; - break; - } - v++; - vlen--; - } + if( vlen == 0 ) + vsign = 0; - /* Skip past leading spaces/zeros, and get the sign of the *assertedValue - number */ + /* Do the same with the *assertedValue number */ asserted = (struct berval *) assertedValue; av = asserted->bv_val; avlen = asserted->bv_len; - while( avlen ) { - if( ASCII_SPACE(*av) || ( *av == '0' )) { - /* empty -- skip spaces */ - } - else if ( *av == '+' ) { - avsign = 1; - } - else if ( *av == '-' ) { + for( ; avlen && ( *av < '1' || '9' < *av ); av++, avlen-- ) + if( *av == '-' ) avsign = -1; - } - else if ( ASCII_DIGIT(*av) ) { - if ( avsign == 0 ) avsign = 1; - avsign *= 2; - break; - } - av++; - avlen--; - } - - /* The two ?sign vars are now one of : - -2 negative non-zero number - -1 -0 \ - 0 0 collapse these three to 0 - +1 +0 / - +2 positive non-zero number - */ - if ( abs( vsign ) == 1 ) vsign = 0; - if ( abs( avsign ) == 1 ) avsign = 0; + if( avlen == 0 ) + avsign = 0; - if( vsign != avsign ) return LDAP_SUCCESS; - - /* Check the significant digits */ - while( vlen && avlen ) { - if( *v != *av ) break; - v++; - vlen--; - av++; - avlen--; + match = vsign - avsign; + if( match == 0 ) { + match = (vlen != avlen + ? ( vlen < avlen ? -1 : 1 ) + : memcmp( v, av, vlen )); + if( vsign < 0 ) + match = -match; } - /* If all digits compared equal, the numbers are equal */ - if(( vlen == 0 ) && ( avlen == 0 )) { - *matchp = 0; - } + *matchp = match; return LDAP_SUCCESS; } @@ -1877,11 +1844,12 @@ integerNormalize( } else { normalized->bv_len = len+negative; - normalized->bv_val = ch_malloc( normalized->bv_len ); + normalized->bv_val = ch_malloc( normalized->bv_len + 1 ); if( negative ) { normalized->bv_val[0] = '-'; } AC_MEMCPY( normalized->bv_val + negative, p, len ); + normalized->bv_val[len+negative] = '\0'; } return LDAP_SUCCESS; @@ -1898,19 +1866,45 @@ static int integerIndexer( BerVarray *keysp ) { int i; + size_t slen, mlen; BerVarray keys; - - /* we should have at least one value at this point */ - assert( values != NULL && values[0].bv_val != NULL ); + HASH_CONTEXT HASHcontext; + unsigned char HASHdigest[HASH_BYTES]; + struct berval digest; + digest.bv_val = HASHdigest; + digest.bv_len = sizeof(HASHdigest); for( i=0; values[i].bv_val != NULL; i++ ) { - /* empty -- just count them */ + /* empty - just count them */ } + /* we should have at least one value at this point */ + assert( i > 0 ); + keys = ch_malloc( sizeof( struct berval ) * (i+1) ); + slen = syntax->ssyn_oidlen; + mlen = mr->smr_oidlen; + for( i=0; values[i].bv_val != NULL; i++ ) { - integerNormalize( syntax, &values[i], &keys[i] ); + struct berval norm; + integerNormalize( syntax, &values[i], &norm ); + + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + norm.bv_val, norm.bv_len ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[i], &digest ); + ch_free( norm.bv_val ); } keys[i].bv_val = NULL; @@ -1928,13 +1922,40 @@ static int integerFilter( void * assertValue, BerVarray *keysp ) { + size_t slen, mlen; BerVarray keys; + HASH_CONTEXT HASHcontext; + unsigned char HASHdigest[HASH_BYTES]; + struct berval norm; + struct berval digest; + digest.bv_val = HASHdigest; + digest.bv_len = sizeof(HASHdigest); + + slen = syntax->ssyn_oidlen; + mlen = mr->smr_oidlen; + + integerNormalize( syntax, assertValue, &norm ); keys = ch_malloc( sizeof( struct berval ) * 2 ); - integerNormalize( syntax, assertValue, &keys[0] ); + + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + norm.bv_val, norm.bv_len ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[0], &digest ); keys[1].bv_val = NULL; - *keysp = keys; + ch_free( norm.bv_val ); + *keysp = keys; return LDAP_SUCCESS; } @@ -2799,7 +2820,7 @@ static int caseIgnoreIA5Indexer( for( i=0; values[i].bv_val != NULL; i++ ) { struct berval value; ber_dupbv( &value, &values[i] ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); HASH_Init( &HASHcontext ); if( prefix != NULL && prefix->bv_len > 0 ) { @@ -2847,7 +2868,7 @@ static int caseIgnoreIA5Filter( mlen = mr->smr_oidlen; ber_dupbv( &value, (struct berval *) assertValue ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); keys = ch_malloc( sizeof( struct berval ) * 2 ); @@ -2947,7 +2968,7 @@ static int caseIgnoreIA5SubstringsIndexer( if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue; ber_dupbv( &value, &values[i] ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); if( ( flags & SLAP_INDEX_SUBSTR_ANY ) && ( value.bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) ) @@ -3100,7 +3121,7 @@ static int caseIgnoreIA5SubstringsFilter( { pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX; ber_dupbv( &value, &sa->sa_initial ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len; @@ -3135,7 +3156,7 @@ static int caseIgnoreIA5SubstringsFilter( } ber_dupbv( &value, &sa->sa_any[i] ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); for(j=0; j <= value.bv_len - SLAP_INDEX_SUBSTR_MAXLEN; @@ -3168,7 +3189,7 @@ static int caseIgnoreIA5SubstringsFilter( { pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX; ber_dupbv( &value, &sa->sa_final ); - ldap_pvt_str2upper( value.bv_val ); + ldap_pvt_str2lower( value.bv_val ); klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len; @@ -3676,7 +3697,7 @@ certificateExactMatch( 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)); + asserted_serial->bv_val, asserted_issuer_dn->bv_val)); #else Debug( LDAP_DEBUG_ARGS, "certificateExactMatch " "%d\n\t\"%s $ %s\"\n", @@ -3959,6 +3980,7 @@ check_time_syntax (struct berval *val, return LDAP_SUCCESS; } +#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX static int utcTimeNormalize( Syntax *syntax, @@ -3984,7 +4006,9 @@ utcTimeNormalize( return LDAP_SUCCESS; } +#endif +#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX static int utcTimeValidate( Syntax *syntax, @@ -3994,6 +4018,7 @@ utcTimeValidate( return check_time_syntax(in, 1, parts); } +#endif static int generalizedTimeValidate( @@ -4181,7 +4206,7 @@ static struct syntax_defs_rec { {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )", 0, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )", - 0, printablesStringValidate, IA5StringNormalize, NULL}, + 0, printablesStringValidate, telephoneNumberNormalize, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")", SLAP_SYNTAX_BLOB, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )", @@ -4233,13 +4258,15 @@ static struct syntax_defs_rec { X_BINARY X_NOT_H_R ")", SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )", - 0, printableStringValidate, IA5StringNormalize, NULL}, + 0, printableStringValidate, telephoneNumberNormalize, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )", 0, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )", 0, printablesStringValidate, IA5StringNormalize, NULL}, +#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )", 0, utcTimeValidate, utcTimeNormalize, NULL}, +#endif {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )", 0, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )", @@ -4291,7 +4318,6 @@ static struct syntax_defs_rec { * Other matching rules in X.520 that we do not use (yet): * * 2.5.13.9 numericStringOrderingMatch - * 2.5.13.15 integerOrderingMatch * 2.5.13.18 octetStringOrderingMatch * 2.5.13.19 octetStringSubstringsMatch * 2.5.13.25 uTCTimeMatch @@ -4453,6 +4479,13 @@ static struct mrule_defs_rec { integerMatch, integerIndexer, integerFilter, NULL}, + {"( 2.5.13.15 NAME 'integerOrderingMatch' " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", + SLAP_MR_ORDERING, + NULL, NULL, + integerOrderingMatch, NULL, NULL, + NULL}, + {"( 2.5.13.16 NAME 'bitStringMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, @@ -4667,6 +4700,9 @@ slap_schema_init( void ) } } + for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ ) + *mr_ptr[i].mr = mr_find( mr_ptr[i].oid ); + res = slap_schema_load(); schema_init_done = 1; return res; @@ -4675,9 +4711,12 @@ slap_schema_init( void ) void schema_destroy( void ) { + int i; oidm_destroy(); oc_destroy(); at_destroy(); + for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ ) + *mr_ptr[i].mr = NULL; mr_destroy(); syn_destroy(); } diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 78293d9a8fadebb8b5108d8eef51267bdb98c1be..33d11278f740de9c98281c9ee5f3616bf37ec450 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -230,7 +230,7 @@ static struct slap_schema_ad_map { "DESC 'X.500(93): structural object class of entry' " "EQUALITY objectIdentifierMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " - "NO-USER-MODIFICATION SINGLE-VALUE USAGE directoryOperation )", + "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", NULL, 0, structuralObjectClassMatch, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_structuralObjectClass) }, { "createTimestamp", "( 2.5.18.1 NAME 'createTimestamp' " @@ -273,8 +273,8 @@ static struct slap_schema_ad_map { { "subschemaSubentry", "( 2.5.18.10 NAME 'subschemaSubentry' " "DESC 'RFC2252: name of controlling subschema entry' " "EQUALITY distinguishedNameMatch " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION " - "SINGLE-VALUE USAGE directoryOperation )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE " + "NO-USER-MODIFICATION USAGE directoryOperation )", NULL, 0, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_subschemaSubentry) }, @@ -292,8 +292,8 @@ static struct slap_schema_ad_map { offsetof(struct slap_internal_schema, si_ad_namingContexts) }, { "supportedControl", "( 1.3.6.1.4.1.1466.101.120.13 " "NAME 'supportedControl' " - "DESC 'RFC2252: supported controls' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )", + "DESC 'RFC2252: supported controls' " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )", rootDseAttribute, 0, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_supportedControl) }, { "supportedExtension", "( 1.3.6.1.4.1.1466.101.120.7 " @@ -531,6 +531,8 @@ static struct slap_schema_syn_map { char *sssm_name; size_t sssm_offset; } syn_map[] = { + { "1.3.6.1.4.1.1466.115.121.1.40", + offsetof(struct slap_internal_schema, si_syn_octetString) }, { "1.3.6.1.4.1.1466.115.121.1.12", offsetof(struct slap_internal_schema, si_syn_distinguishedName) }, { "1.3.6.1.4.1.1466.115.121.1.27", @@ -542,8 +544,42 @@ int slap_schema_load( void ) { int i; + + for( i=0; syn_map[i].sssm_name; i++ ) { + Syntax ** synp = (Syntax **) + &(((char *) &slap_schema)[syn_map[i].sssm_offset]); + + assert( *synp == NULL ); + + *synp = syn_find( syn_map[i].sssm_name ); + + if( *synp == NULL ) { + fprintf( stderr, "slap_schema_check: " + "No syntax \"%s\" defined in schema\n", + syn_map[i].sssm_name ); + return LDAP_INVALID_SYNTAX; + } + } + + for( i=0; mr_map[i].ssmm_name; i++ ) { + MatchingRule ** mrp = (MatchingRule **) + &(((char *) &slap_schema)[mr_map[i].ssmm_offset]); + + assert( *mrp == NULL ); + + *mrp = mr_find( mr_map[i].ssmm_name ); + + if( *mrp == NULL ) { + fprintf( stderr, "slap_schema_check: " + "No matching rule \"%s\" defined in schema\n", + mr_map[i].ssmm_name ); + return LDAP_INAPPROPRIATE_MATCHING; + } + } + for( i=0; ad_map[i].ssam_name; i++ ) { - if( ad_map[i].ssam_defn != NULL ) { + assert( ad_map[i].ssam_defn != NULL ); + { LDAPAttributeType *at; int code; const char *err; @@ -573,10 +609,40 @@ slap_schema_load( void ) } ldap_memfree( at ); } + { + int rc; + const char *text; + + AttributeDescription ** adp = (AttributeDescription **) + &(((char *) &slap_schema)[ad_map[i].ssam_offset]); + + assert( *adp == NULL ); + + rc = slap_str2ad( ad_map[i].ssam_name, adp, &text ); + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "slap_schema_check: " + "No attribute \"%s\" defined in schema\n", + ad_map[i].ssam_name ); + return rc; + } + + if( ad_map[i].ssam_check ) { + /* install check routine */ + (*adp)->ad_type->sat_check = ad_map[i].ssam_check; + } + /* install flags */ + (*adp)->ad_type->sat_flags |= ad_map[i].ssam_flags; + + if( ad_map[i].ssam_match ) { + /* install custom matching routine */ + (*adp)->ad_type->sat_equality->smr_match = ad_map[i].ssam_match; + } + } } for( i=0; oc_map[i].ssom_name; i++ ) { - if( oc_map[i].ssom_defn != NULL ) { + assert( oc_map[i].ssom_defn != NULL ); + { LDAPObjectClass *oc; int code; const char *err; @@ -607,110 +673,41 @@ slap_schema_load( void ) ldap_memfree(oc); } + { + ObjectClass ** ocp = (ObjectClass **) + &(((char *) &slap_schema)[oc_map[i].ssom_offset]); + + assert( *ocp == NULL ); + + *ocp = oc_find( oc_map[i].ssom_name ); + if( *ocp == NULL ) { + fprintf( stderr, "slap_schema_check: " + "No objectClass \"%s\" defined in schema\n", + oc_map[i].ssom_name ); + return LDAP_OBJECT_CLASS_VIOLATION; + } + + if( oc_map[i].ssom_check ) { + /* install check routine */ + (*ocp)->soc_check = oc_map[i].ssom_check; + } + /* install flags */ + (*ocp)->soc_flags |= oc_map[i].ssom_flags; + } } + slap_at_undefined.sat_syntax = slap_schema.si_syn_distinguishedName; + slap_schema.si_at_undefined = &slap_at_undefined; + return LDAP_SUCCESS; } int slap_schema_check( void ) { - int i; /* we should only be called once after schema_init() was called */ assert( schema_init_done == 1 ); - for( i=0; syn_map[i].sssm_name; i++ ) { - Syntax ** synp = (Syntax **) - &(((char *) &slap_schema)[syn_map[i].sssm_offset]); - - assert( *synp == NULL ); - - *synp = syn_find( syn_map[i].sssm_name ); - - if( *synp == NULL ) { - fprintf( stderr, "slap_schema_check: " - "No syntax \"%s\" defined in schema\n", - syn_map[i].sssm_name ); - return LDAP_INVALID_SYNTAX; - } - } - - for( i=0; mr_map[i].ssmm_name; i++ ) { - MatchingRule ** mrp = (MatchingRule **) - &(((char *) &slap_schema)[mr_map[i].ssmm_offset]); - - assert( *mrp == NULL ); - - *mrp = mr_find( mr_map[i].ssmm_name ); - - if( *mrp == NULL ) { - fprintf( stderr, "slap_schema_check: " - "No matching rule \"%s\" defined in schema\n", - mr_map[i].ssmm_name ); - return LDAP_INAPPROPRIATE_MATCHING; - } - } - - slap_at_undefined.sat_syntax = syn_find( SLAPD_OCTETSTRING_SYNTAX ); - if( slap_at_undefined.sat_syntax == NULL ) { - fprintf( stderr, "slap_schema_check: " - "No octetString syntax \"" SLAPD_OCTETSTRING_SYNTAX "\"\n" ); - return LDAP_INVALID_SYNTAX; - } - slap_schema.si_at_undefined = &slap_at_undefined; - - for( i=0; ad_map[i].ssam_name; i++ ) { - int rc; - const char *text; - - AttributeDescription ** adp = (AttributeDescription **) - &(((char *) &slap_schema)[ad_map[i].ssam_offset]); - - assert( *adp == NULL ); - - rc = slap_str2ad( ad_map[i].ssam_name, adp, &text ); - if( rc != LDAP_SUCCESS ) { - fprintf( stderr, "slap_schema_check: " - "No attribute \"%s\" defined in schema\n", - ad_map[i].ssam_name ); - return rc; - } - - if( ad_map[i].ssam_check ) { - /* install check routine */ - (*adp)->ad_type->sat_check = ad_map[i].ssam_check; - } - /* install flags */ - (*adp)->ad_type->sat_flags |= ad_map[i].ssam_flags; - - if( ad_map[i].ssam_match ) { - /* install custom matching routine */ - (*adp)->ad_type->sat_equality->smr_match = ad_map[i].ssam_match; - } - } - - for( i=0; oc_map[i].ssom_name; i++ ) { - ObjectClass ** ocp = (ObjectClass **) - &(((char *) &slap_schema)[oc_map[i].ssom_offset]); - - assert( *ocp == NULL ); - - *ocp = oc_find( oc_map[i].ssom_name ); - if( *ocp == NULL ) { - fprintf( stderr, "slap_schema_check: " - "No objectClass \"%s\" defined in schema\n", - oc_map[i].ssom_name ); - return LDAP_OBJECT_CLASS_VIOLATION; - } - - if( oc_map[i].ssom_check ) { - /* install check routine */ - (*ocp)->soc_check = oc_map[i].ssom_check; - } - /* install flags */ - (*ocp)->soc_flags |= oc_map[i].ssom_flags; - } - ++schema_init_done; return LDAP_SUCCESS; } diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c index 180ed71d005caeca8636e3c0336294756ef91b43..171bd3473edf39ea434574af4be6cb4838efb645 100644 --- a/servers/slapd/schemaparse.c +++ b/servers/slapd/schemaparse.c @@ -1,79 +1,219 @@ /* schemaparse.c - routines to parse config file objectclass definitions */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> + #include "slap.h" +#include "ldap_schema.h" + +int global_schemacheck = 1; /* schemacheck ON is default */ + +static void oc_usage(void); +static void at_usage(void); + +static char *const err2text[SLAP_SCHERR_LAST+1] = { + "Success", + "Out of memory", + "ObjectClass not found", + "ObjectClass inappropriate SUPerior", + "AttributeType not found", + "AttributeType inappropriate USAGE", + "Duplicate objectClass", + "Duplicate attributeType", + "Duplicate ldapSyntax", + "Duplicate matchingRule", + "OID or name required", + "SYNTAX or SUPerior required", + "MatchingRule not found", + "Syntax not found", + "Syntax required", + "Qualifier not supported", + "Invalid NAME", + "OID could not be expanded" +}; -extern char **str2charray(); -extern void charray_merge(); +char * +scherr2str(int code) +{ + if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { + return "Unknown error"; + } else { + return err2text[code]; + } +} -struct objclass *global_oc; -int global_schemacheck; +/* check schema descr validity */ +int slap_valid_descr( const char *descr ) +{ + int i=0; -static void oc_usage(); + if( !DESC_LEADCHAR( descr[i] ) ) { + return 0; + } -void + while( descr[++i] ) { + if( !DESC_CHAR( descr[i] ) ) { + return 0; + } + } + + return 1; +} + + +/* OID Macros */ + +/* String compare with delimiter check. Return 0 if not + * matched, otherwise return length matched. + */ +int +dscompare(const char *s1, const char *s2, char delim) +{ + const char *orig = s1; + while (*s1++ == *s2++) + if (!s1[-1]) break; + --s1; + --s2; + if (!*s1 && (!*s2 || *s2 == delim)) + return s1 - orig; + return 0; +} + + +int parse_oc( - Backend *be, - char *fname, + const char *fname, int lineno, - int argc, + char *line, char **argv ) { - int i; - char last; - struct objclass *oc; - struct objclass **ocp; - - oc = (struct objclass *) ch_calloc( 1, sizeof(struct objclass) ); - oc->oc_name = strdup( argv[1] ); - for ( i = 2; i < argc; i++ ) { - /* required attributes */ - if ( strcasecmp( argv[i], "requires" ) == 0 ) { - do { - i++; - if ( i < argc ) { - last = argv[i][strlen( argv[i] ) - 1]; - charray_merge( &oc->oc_required, - str2charray( argv[i], "," ) ); - } - } while ( i < argc && last == ',' ); - - /* optional attributes */ - } else if ( strcasecmp( argv[i], "allows" ) == 0 ) { - do { - i++; - if ( i < argc ) { - last = argv[i][strlen( argv[i] ) - 1]; - charray_merge( &oc->oc_allowed, - str2charray( argv[i], "," ) ); - } - } while ( i < argc && last == ',' ); - - } else { - fprintf( stderr, - "%s: line %d: expecting \"requires\" or \"allows\" got \"%s\"\n", - fname, lineno, argv[i] ); - oc_usage(); - } + LDAPObjectClass *oc; + int code; + const char *err; + + oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); + if ( !oc ) { + fprintf( stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err ); + oc_usage(); + return 1; + } + + if ( oc->oc_oid == NULL ) { + fprintf( stderr, + "%s: line %d: objectclass has no OID\n", + fname, lineno ); + oc_usage(); + return 1; } - ocp = &global_oc; - while ( *ocp != NULL ) { - ocp = &(*ocp)->oc_next; + code = oc_add(oc,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, scherr2str(code), err); + return 1; } - *ocp = oc; + + ldap_memfree(oc); + return 0; } static void -oc_usage() +oc_usage( void ) { - fprintf( stderr, "<oc clause> ::= objectclass <ocname>\n" ); - fprintf( stderr, " [ requires <attrlist> ]\n" ); - fprintf( stderr, " [ allows <attrlist> ]\n" ); - exit( 1 ); + fprintf( stderr, + "ObjectClassDescription = \"(\" whsp\n" + " numericoid whsp ; ObjectClass identifier\n" + " [ \"NAME\" qdescrs ]\n" + " [ \"DESC\" qdstring ]\n" + " [ \"OBSOLETE\" whsp ]\n" + " [ \"SUP\" oids ] ; Superior ObjectClasses\n" + " [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n" + " ; default structural\n" + " [ \"MUST\" oids ] ; AttributeTypes\n" + " [ \"MAY\" oids ] ; AttributeTypes\n" + " whsp \")\"\n" ); } + +static void +at_usage( void ) +{ + fprintf( stderr, + "AttributeTypeDescription = \"(\" whsp\n" + " numericoid whsp ; AttributeType identifier\n" + " [ \"NAME\" qdescrs ] ; name used in AttributeType\n" + " [ \"DESC\" qdstring ] ; description\n" + " [ \"OBSOLETE\" whsp ]\n" + " [ \"SUP\" woid ] ; derived from this other\n" + " ; AttributeType\n" + " [ \"EQUALITY\" woid ] ; Matching Rule name\n" + " [ \"ORDERING\" woid ] ; Matching Rule name\n" + " [ \"SUBSTR\" woid ] ; Matching Rule name\n" + " [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n" + " [ \"SINGLE-VALUE\" whsp ] ; default multi-valued\n" + " [ \"COLLECTIVE\" whsp ] ; default not collective\n" + " [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n" + " [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n" + " ; userApplications\n" + " ; directoryOperation\n" + " ; distributedOperation\n" + " ; dSAOperation\n" + " whsp \")\"\n"); +} + +int +parse_at( + const char *fname, + int lineno, + char *line, + char **argv +) +{ + LDAPAttributeType *at; + int code; + const char *err; + + at = ldap_str2attributetype( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); + if ( !at ) { + fprintf( stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err ); + at_usage(); + return 1; + } + + if ( at->at_oid == NULL ) { + fprintf( stderr, + "%s: line %d: attributeType has no OID\n", + fname, lineno ); + at_usage(); + return 1; + } + + /* operational attributes should be defined internally */ + if ( at->at_usage ) { + fprintf( stderr, "%s: line %d: attribute type \"%s\" is operational\n", + fname, lineno, at->at_oid ); + return 1; + } + + code = at_add(at,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, scherr2str(code), err); + return 1; + } + ldap_memfree(at); + return 0; +} diff --git a/servers/slapd/search.c b/servers/slapd/search.c index fc96d2fd021727bd9f14c04445f3ace096defa32..c4db3e52e664bb210845a9949a740ca3bc33b156 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -1,4 +1,9 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * @@ -10,32 +15,41 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "ldap_pvt.h" #include "slap.h" -#include "ldapconfig.h" - -extern int get_filter(); -extern Backend *select_backend(); - -extern char *default_referral; - -void -do_search( conn, op ) - Connection *conn; /* where to send results */ - Operation *op; /* info about the op to which we're responding */ -{ - int i, err; - int scope, deref, attrsonly; - int sizelimit, timelimit; - char *base, *fstr; - Filter *filter; - char **attrs; + +int +do_search( + Connection *conn, /* where to send results */ + Operation *op /* info about the op to which we're responding */ +) { + ber_int_t scope, deref, attrsonly; + ber_int_t sizelimit, timelimit; + struct berval base = { 0, NULL }; + struct berval pbase = { 0, NULL }; + struct berval nbase = { 0, NULL }; + struct berval fstr = { 0, NULL }; + Filter *filter = NULL; + AttributeName *an = NULL; + ber_len_t siz, off, i; Backend *be; + int rc; + const char *text; + int manageDSAit; +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_search: conn %d\n", conn->c_connid )); +#else Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 ); +#endif /* * Parse the search request. It looks like this: @@ -62,118 +76,263 @@ do_search( conn, op ) */ /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */ - if ( ber_scanf( op->o_ber, "{aiiiib", &base, &scope, &deref, &sizelimit, - &timelimit, &attrsonly ) == LBER_ERROR ) { - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" ); - return; + if ( ber_scanf( op->o_ber, "{miiiib" /*}*/, + &base, &scope, &deref, &sizelimit, + &timelimit, &attrsonly ) == LBER_ERROR ) + { + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding error" ); + rc = SLAPD_DISCONNECT; + goto return_results; + } + + switch( scope ) { + case LDAP_SCOPE_BASE: + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: + break; + default: + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "invalid scope", NULL, NULL ); + goto return_results; } - if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL - && scope != LDAP_SCOPE_SUBTREE ) { - free( base ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, - "Unknown search scope" ); - return; + + switch( deref ) { + case LDAP_DEREF_NEVER: + case LDAP_DEREF_FINDING: + case LDAP_DEREF_SEARCHING: + case LDAP_DEREF_ALWAYS: + break; + default: + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "invalid deref", NULL, NULL ); + goto return_results; } - (void) dn_normalize( base ); - Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", base, scope, deref ); - Debug( LDAP_DEBUG_ARGS, " %d %d %d\n", sizelimit, timelimit, - attrsonly); + rc = dnPrettyNormal( NULL, &base, &pbase, &nbase ); + if( rc != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_search: conn %d invalid dn (%s)\n", + conn->c_connid, base.bv_val )); +#else + Debug( LDAP_DEBUG_ANY, + "do_search: invalid dn (%s)\n", base.bv_val, 0, 0 ); +#endif + send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL, + "invalid DN", NULL, NULL ); + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_search \"%s\" %d %d %d %d %d\n", base.bv_val, scope, + deref, sizelimit, timelimit, attrsonly )); +#else + Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", + base.bv_val, scope, deref ); + Debug( LDAP_DEBUG_ARGS, " %d %d %d\n", + sizelimit, timelimit, attrsonly); +#endif /* filter - returns a "normalized" version */ - filter = NULL; - fstr = NULL; - if ( (err = get_filter( conn, op->o_ber, &filter, &fstr )) != 0 ) { - if ( fstr != NULL ) { - free( fstr ); + rc = get_filter( conn, op->o_ber, &filter, &text ); + if( rc != LDAP_SUCCESS ) { + if( rc == SLAPD_DISCONNECT ) { + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, text ); + } else { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); } - free( base ); - send_ldap_result( conn, op, err, NULL, "Bad search filter" ); - return; + goto return_results; + + } else { + filter2bv( filter, &fstr ); } - Debug( LDAP_DEBUG_ARGS, " filter: %s\n", fstr, 0, 0 ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_search: conn %d filter: %s\n", conn->c_connid, + fstr.bv_len ? fstr.bv_val : "empty" )); +#else + Debug( LDAP_DEBUG_ARGS, " filter: %s\n", + fstr.bv_len ? fstr.bv_val : "empty", 0, 0 ); +#endif /* attributes */ - attrs = NULL; - if ( ber_scanf( op->o_ber, "{v}}", &attrs ) == LBER_ERROR ) { - free( base ); - free( fstr ); - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" ); - return; + siz = sizeof(AttributeName); + off = 0; + if ( ber_scanf( op->o_ber, "{M}}", &an, &siz, off ) == LBER_ERROR ) { + send_ldap_disconnect( conn, op, + LDAP_PROTOCOL_ERROR, "decoding attrs error" ); + rc = SLAPD_DISCONNECT; + goto return_results; + } + for ( i=0; i<siz; i++ ) { + an[i].an_desc = NULL; + an[i].an_oc = NULL; + slap_bv2ad(&an[i].an_name, &an[i].an_desc, &text); + } + + if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "do_search: conn %d get_ctrls failed (%d)\n", + conn->c_connid, rc )); +#else + Debug( LDAP_DEBUG_ANY, "do_search: get_ctrls failed\n", 0, 0, 0 ); +#endif + + goto return_results; } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_search: conn %d attrs:", conn->c_connid )); +#else Debug( LDAP_DEBUG_ARGS, " attrs:", 0, 0, 0 ); - if ( attrs != NULL ) { - for ( i = 0; attrs[i] != NULL; i++ ) { - attr_normalize( attrs[i] ); - Debug( LDAP_DEBUG_ARGS, " %s", attrs[i], 0, 0 ); +#endif + + if ( siz != 0 ) { + for ( i = 0; i<siz; i++ ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, + "do_search: %s", an[i].an_name.bv_val )); +#else + Debug( LDAP_DEBUG_ARGS, " %s", an[i].an_name.bv_val, 0, 0 ); +#endif } } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, "\n" )); +#else Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 ); +#endif Statslog( LDAP_DEBUG_STATS, - "conn=%d op=%d SRCH base=\"%s\" scope=%d filter=\"%s\"\n", - conn->c_connid, op->o_opid, base, scope, fstr ); + "conn=%lu op=%lu SRCH base=\"%s\" scope=%d filter=\"%s\"\n", + op->o_connid, op->o_opid, pbase.bv_val, scope, fstr.bv_val ); + + manageDSAit = get_manageDSAit( op ); -#if defined( SLAPD_MONITOR_DN ) || defined( SLAPD_CONFIG_DN ) || defined( SLAPD_SCHEMA_DN ) if ( scope == LDAP_SCOPE_BASE ) { -#if defined( SLAPD_MONITOR_DN ) - if ( strcasecmp( base, SLAPD_MONITOR_DN ) == 0 ) { - free( base ); - free( fstr ); - monitor_info( conn, op ); - return; - } + Entry *entry = NULL; + + if ( nbase.bv_len == 0 ) { +#ifdef LDAP_CONNECTIONLESS + /* Ignore LDAPv2 CLDAP Root DSE queries */ + if (op->o_protocol==LDAP_VERSION2 && conn->c_is_udp) { + goto return_results; + } #endif -#if defined( SLAPD_CONFIG_DN ) - if ( strcasecmp( base, SLAPD_CONFIG_DN ) == 0 ) { - free( base ); - free( fstr ); - config_info( conn, op ); - return; + /* check restrictions */ + rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto return_results; + } + + rc = root_dse_info( conn, &entry, &text ); } -#endif + #if defined( SLAPD_SCHEMA_DN ) - if ( strcasecmp( base, SLAPD_SCHEMA_DN ) == 0 ) { - free( base ); - free( fstr ); - schema_info( conn, op ); - return; + else if ( strcasecmp( nbase.bv_val, SLAPD_SCHEMA_DN ) == 0 ) { + /* check restrictions */ + rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto return_results; + } + + rc = schema_info( &entry, &text ); } #endif + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto return_results; + + } else if ( entry != NULL ) { + rc = test_filter( NULL, conn, op, + entry, filter ); + + if( rc == LDAP_COMPARE_TRUE ) { + send_search_entry( NULL, conn, op, + entry, an, attrsonly, NULL ); + } + entry_free( entry ); + + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); + + goto return_results; + } + } + + if( !nbase.bv_len && default_search_nbase.bv_len ) { + ch_free( pbase.bv_val ); + ch_free( nbase.bv_val ); + + ber_dupbv( &pbase, &default_search_base ); + ber_dupbv( &nbase, &default_search_nbase ); } -#endif /* monitor or config or schema dn */ /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - if ( (be = select_backend( base )) == NULL ) { - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); - - free( base ); - free( fstr ); - filter_free( filter ); - if ( attrs != NULL ) { - charray_free( attrs ); - } - return; + if ( (be = select_backend( &nbase, manageDSAit, 1 )) == NULL ) { + BerVarray ref = referral_rewrite( default_referral, + NULL, &pbase, scope ); + + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvarray_free( ref ); + goto return_results; + } + + /* check restrictions */ + rc = backend_check_restrictions( be, conn, op, NULL, &text ) ; + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, text, NULL, NULL ); + goto return_results; } + /* check for referrals */ + rc = backend_check_referrals( be, conn, op, &pbase, &nbase ); + if ( rc != LDAP_SUCCESS ) { + goto return_results; + } + + /* deref the base if needed */ + suffix_alias( be, &nbase ); + /* actually do the search and send the result(s) */ - if ( be->be_search != NULL ) { - (*be->be_search)( be, conn, op, base, scope, deref, sizelimit, - timelimit, filter, fstr, attrs, attrsonly ); + if ( be->be_search ) { + (*be->be_search)( be, conn, op, &pbase, &nbase, + scope, deref, sizelimit, + timelimit, filter, &fstr, an, attrsonly ); } else { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "operation not supported within namingContext", + NULL, NULL ); } - free( base ); - free( fstr ); - filter_free( filter ); - if ( attrs != NULL ) { - charray_free( attrs ); - } +return_results:; + if( pbase.bv_val != NULL) free( pbase.bv_val ); + if( nbase.bv_val != NULL) free( nbase.bv_val ); + + if( fstr.bv_val != NULL) free( fstr.bv_val ); + if( filter != NULL) filter_free( filter ); + if( an != NULL ) free( an ); + + return rc; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 6ce21c742698a5bd0a8b207a24596f754d1a9f6a..123b7b06bddf0d6f35ae527bfb3e944978270dda 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -16,6 +16,7 @@ #include <sys/types.h> #include <ac/syslog.h> #include <ac/regex.h> +#include <ac/signal.h> #include <ac/socket.h> #include <ac/time.h> #include <ac/param.h> @@ -69,7 +70,7 @@ LDAP_BEGIN_DECL */ #define SLAP_MOD_SOFTADD 0x1000 -#define MAXREMATCHES (10) +#define MAXREMATCHES (100) #define SLAP_MAX_WORKER_THREADS (32) @@ -626,6 +627,7 @@ struct slap_internal_schema { MatchingRule *si_mr_integerMatch; /* Syntaxes */ + Syntax *si_syn_octetString; Syntax *si_syn_distinguishedName; Syntax *si_syn_integer; }; @@ -900,6 +902,7 @@ typedef struct slap_access { slap_style_t a_dn_style; AttributeDescription *a_dn_at; int a_dn_self; + int a_dn_expand; slap_style_t a_peername_style; struct berval a_peername_pat; @@ -908,6 +911,8 @@ typedef struct slap_access { slap_style_t a_domain_style; struct berval a_domain_pat; + int a_domain_expand; + slap_style_t a_sockurl_style; struct berval a_sockurl_pat; slap_style_t a_set_style; @@ -959,7 +964,7 @@ typedef struct slap_acl_state { int as_result; } AccessControlState; -#define ACL_STATE_INIT { ACL_STATE_NOT_RECORDED, NULL, 0UL, { 0 }, 0, NULL, 0 } +#define ACL_STATE_INIT { ACL_STATE_NOT_RECORDED, NULL, 0UL, { { 0, 0 } }, 0, NULL, 0, 0 } /* * replog moddn param structure @@ -995,6 +1000,7 @@ struct slap_replica_info { char *ri_host; /* supersedes be_replica */ struct berval **ri_nsuffix; /* array of suffixes this replica accepts */ AttributeName *ri_attrs; /* attrs to replicate, NULL=all */ + int ri_exclude; /* 1 => exclude ri_attrs */ }; struct slap_limits_set { @@ -1403,28 +1409,43 @@ typedef struct slap_callback { void *sc_private; } slap_callback; +/* + * Paged Results state + */ +typedef unsigned long PagedResultsCookie; +typedef struct slap_paged_state { + Backend *ps_be; + PagedResultsCookie ps_cookie; + ID ps_id; +} PagedResultsState; + /* * represents an operation pending from an ldap client */ typedef struct slap_op { - ber_int_t o_opid; /* id of this operation */ - ber_int_t o_msgid; /* msgid of the request */ + unsigned long o_opid; /* id of this operation */ + unsigned long o_connid; /* id of conn initiating this op */ + + ber_int_t o_msgid; /* msgid of the request */ ber_int_t o_protocol; /* version of the LDAP protocol used by client */ - ber_tag_t o_tag; /* tag of the request */ - time_t o_time; /* time op was initiated */ - unsigned long o_connid; /* id of conn initiating this op */ - ldap_pvt_thread_t o_tid; /* thread handling this op */ + ber_tag_t o_tag; /* tag of the request */ + time_t o_time; /* time op was initiated */ + + ldap_pvt_thread_t o_tid; /* thread handling this op */ + + volatile sig_atomic_t o_abandon; /* abandon flag */ #define SLAP_NO_CONTROL 0 #define SLAP_NONCRITICAL_CONTROL 1 #define SLAP_CRITICAL_CONTROL 2 char o_managedsait; + char o_noop; char o_subentries; char o_subentries_visibility; - char o_noop; - char o_abandon; /* abandon flag */ - ldap_pvt_thread_mutex_t o_abandonmutex; /* protects o_abandon */ + char o_pagedresults; + ber_int_t o_pagedresults_size; + PagedResultsState o_pagedresults_state; #ifdef LDAP_CONNECTIONLESS Sockaddr o_peeraddr; /* UDP peer address */ @@ -1482,10 +1503,7 @@ typedef struct slap_conn { struct berval c_sasl_bind_mech; /* mech in progress */ struct berval c_cdn; - /* authentication backend */ - Backend *c_authc_backend; - - /* authorization backend - normally same as c_authc_backend */ + /* authorization backend */ Backend *c_authz_backend; AuthorizationInformation c_authz; @@ -1513,6 +1531,8 @@ typedef struct slap_conn { void *c_sasl_context; /* SASL session context */ void *c_sasl_extra; /* SASL session extra stuff */ + PagedResultsState c_pagedresults_state; /* paged result state */ + long c_n_ops_received; /* num of ops received (next op_id) */ long c_n_ops_executing; /* num of ops currently executing */ long c_n_ops_pending; /* num of ops pending execution */ @@ -1566,6 +1586,25 @@ typedef struct slap_listener { #define sl_addr sl_sa.sa_in_addr } Listener; +#ifdef SLAPD_MONITOR +/* + * Operation indices + */ +enum { + SLAP_OP_BIND = 0, + SLAP_OP_UNBIND, + SLAP_OP_ADD, + SLAP_OP_DELETE, + SLAP_OP_MODRDN, + SLAP_OP_MODIFY, + SLAP_OP_COMPARE, + SLAP_OP_SEARCH, + SLAP_OP_ABANDON, + SLAP_OP_EXTENDED, + SLAP_OP_LAST +}; +#endif /* SLAPD_MONITOR */ + LDAP_END_DECL #include "proto-slap.h" diff --git a/servers/slapd/slapd.dsp b/servers/slapd/slapd.dsp new file mode 100644 index 0000000000000000000000000000000000000000..dbc66e070bf8a1779dc9dd20b073d66fc15e4de0 --- /dev/null +++ b/servers/slapd/slapd.dsp @@ -0,0 +1,165 @@ +# Microsoft Developer Studio Project File - Name="slapd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=slapd - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "slapd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "slapd.mak" CFG="slapd - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "slapd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "slapd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "slapd - Win32 Single Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "slapd - Win32 Single Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "slapd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\Release" +# PROP Intermediate_Dir "..\..\Release\slapd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 advapi32.lib rpcrt4.lib sasl.lib libdb40.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\Release" + +!ELSEIF "$(CFG)" == "slapd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\Debug" +# PROP Intermediate_Dir "..\..\Debug\slapd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 advapi32.lib rpcrt4.lib libdb40d.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\Debug" + +!ELSEIF "$(CFG)" == "slapd - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "slapd___" +# PROP BASE Intermediate_Dir "slapd___" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\SDebug" +# PROP Intermediate_Dir "..\..\SDebug\slapd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 hs_regexd.lib libdbs.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 rpcrt4.lib libdb32.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\SDebug" + +!ELSEIF "$(CFG)" == "slapd - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "slapd__0" +# PROP BASE Intermediate_Dir "slapd__0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\SRelease" +# PROP Intermediate_Dir "..\..\SRelease\slapd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 hs_regex.lib libdb.lib wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libdb.lib libdb32.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\SRelease" + +!ENDIF + +# Begin Target + +# Name "slapd - Win32 Release" +# Name "slapd - Win32 Debug" +# Name "slapd - Win32 Single Debug" +# Name "slapd - Win32 Single Release" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\nt_svc.c +# End Source File +# Begin Source File + +SOURCE=.\operational.c +# End Source File +# Begin Source File + +SOURCE=".\proto-slap.h" +# End Source File +# Begin Source File + +SOURCE=.\result.c +# End Source File +# Begin Source File + +SOURCE=.\slap.h +# End Source File +# End Target +# End Project diff --git a/servers/slapd/str2filter.c b/servers/slapd/str2filter.c index aca9674fd846519207cd3e26d05a867f00419c45..45a42ad60034e5c883520f39f5a859ed9bc6d6bb 100644 --- a/servers/slapd/str2filter.c +++ b/servers/slapd/str2filter.c @@ -1,250 +1,77 @@ /* str2filter.c - parse an rfc 1588 string filter */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/socket.h> + #include "slap.h" +#include <ldap_pvt.h> -static char *find_matching_paren(); -static Filter *str2list(); -static Filter *str2simple(); -static int str2subvals(); +static char *find_matching_paren( const char *s ); +static Filter *str2list( const char *str, long unsigned int ftype); +static Filter *str2simple( const char *str); +static int str2subvals( const char *val, Filter *f); Filter * -str2filter( char *str ) +str2filter( const char *str ) { - Filter *f; - char *end; - + int rc; + Filter *f = NULL; + BerElement *ber; + char berbuf[256]; + struct berval *bv = NULL; + Connection conn; + const char *text = NULL; + +#ifdef NEW_LOGGING + LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, + "str2filter: \"%s\"\n", str )); +#else Debug( LDAP_DEBUG_FILTER, "str2filter \"%s\"\n", str, 0, 0 ); +#endif if ( str == NULL || *str == '\0' ) { - return( NULL ); + return NULL; } - switch ( *str ) { - case '(': - if ( (end = find_matching_paren( str )) == NULL ) { - filter_free( f ); - return( NULL ); - } - *end = '\0'; - - str++; - switch ( *str ) { - case '&': - Debug( LDAP_DEBUG_FILTER, "str2filter: AND\n", - 0, 0, 0 ); - - str++; - f = str2list( str, LDAP_FILTER_AND ); - break; - - case '|': - Debug( LDAP_DEBUG_FILTER, "put_filter: OR\n", - 0, 0, 0 ); - - str++; - f = str2list( str, LDAP_FILTER_OR ); - break; - - case '!': - Debug( LDAP_DEBUG_FILTER, "put_filter: NOT\n", - 0, 0, 0 ); - - str++; - f = str2list( str, LDAP_FILTER_NOT ); - break; - - default: - Debug( LDAP_DEBUG_FILTER, "str2filter: simple\n", - 0, 0, 0 ); - - f = str2simple( str ); - break; - } - *end = ')'; - break; - - default: /* assume it's a simple type=value filter */ - Debug( LDAP_DEBUG_FILTER, "str2filter: default\n", 0, 0, - 0 ); - - f = str2simple( str ); - break; + ber = ber_alloc_t( LBER_USE_DER ); + if( ber == NULL ) { + return NULL; } - return( f ); -} - -/* - * Put a list of filters like this "(filter1)(filter2)..." - */ - -static Filter * -str2list( char *str, unsigned long ftype ) -{ - Filter *f; - Filter **fp; - char *next; - char save; - - Debug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 ); - - f = (Filter *) ch_calloc( 1, sizeof(Filter) ); - f->f_choice = ftype; - fp = &f->f_list; - - while ( *str ) { - while ( *str && isspace( *str ) ) - str++; - if ( *str == '\0' ) - break; - - if ( (next = find_matching_paren( str )) == NULL ) { - filter_free( f ); - return( NULL ); - } - save = *++next; - *next = '\0'; - - /* now we have "(filter)" with str pointing to it */ - if ( (*fp = str2filter( str )) == NULL ) { - filter_free( f ); - *next = save; - return( NULL ); - } - *next = save; - - str = next; - fp = &(*fp)->f_next; + rc = ldap_pvt_put_filter( ber, str ); + if( rc < 0 ) { + goto done; } - *fp = NULL; - return( f ); -} - -static Filter * -str2simple( char *str ) -{ - Filter *f; - char *s; - char *value, savechar; - - Debug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 ); - - if ( (s = strchr( str, '=' )) == NULL ) { - return( NULL ); + rc = ber_flatten( ber, &bv ); + if( rc < 0 ) { + goto done; } - value = s + 1; - *s-- = '\0'; - savechar = *s; - - f = (Filter *) ch_calloc( 1, sizeof(Filter) ); - - switch ( *s ) { - case '<': - f->f_choice = LDAP_FILTER_LE; - *s = '\0'; - break; - case '>': - f->f_choice = LDAP_FILTER_GE; - *s = '\0'; - break; - case '~': - f->f_choice = LDAP_FILTER_APPROX; - *s = '\0'; - break; - default: - if ( strchr( value, '*' ) == NULL ) { - f->f_choice = LDAP_FILTER_EQUALITY; - } else if ( strcmp( value, "*" ) == 0 ) { - f->f_choice = LDAP_FILTER_PRESENT; - } else { - f->f_choice = LDAP_FILTER_SUBSTRINGS; - f->f_sub_type = strdup( str ); - if ( str2subvals( value, f ) != 0 ) { - filter_free( f ); - *(value-1) = '='; - return( NULL ); - } - *(value-1) = '='; - return( f ); - } - break; - } - - if ( f->f_choice == LDAP_FILTER_PRESENT ) { - f->f_type = strdup( str ); - } else { - f->f_avtype = strdup( str ); - f->f_avvalue.bv_val = strdup( value ); - f->f_avvalue.bv_len = strlen( value ); - } - - *s = savechar; - *(value-1) = '='; - return( f ); -} -static int -str2subvals( char *val, Filter *f ) -{ - char *nextstar; - int gotstar; - - Debug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 ); - - gotstar = 0; - while ( val != NULL && *val ) { - if ( (nextstar = strchr( val, '*' )) != NULL ) - *nextstar++ = '\0'; - - if ( gotstar == 0 ) { - f->f_sub_initial = strdup( val ); - } else if ( nextstar == NULL ) { - f->f_sub_final = strdup( val ); - } else { - charray_add( &f->f_sub_any, strdup( val ) ); - } - - gotstar = 1; - if ( nextstar != NULL ) - *(nextstar-1) = '*'; - val = nextstar; - } + ber_free( ber, 0 ); - return( 0 ); -} + ber = (BerElement *)berbuf; + ber_init2( ber, bv, 0 ); -/* - * find_matching_paren - return a pointer to the right paren in s matching - * the left paren to which *s currently points - */ + conn.c_connid = 0; -static char * -find_matching_paren( char *s ) -{ - int balance, escape; - - balance = 0; - escape = 0; - for ( ; *s; s++ ) { - if ( escape == 0 ) { - if ( *s == '(' ) - balance++; - else if ( *s == ')' ) - balance--; - } - if ( balance == 0 ) { - return( s ); - } - if ( *s == '\\' && ! escape ) - escape = 1; - else - escape = 0; + rc = get_filter( &conn, ber, &f, &text ); + if( rc ) { + goto done; } - return( NULL ); +done: + ber_bvfree( bv ); + + return f; } diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..6310473b83c2d436e28b0d388e262423d64ff7eb --- /dev/null +++ b/servers/slapd/tools/Makefile.in @@ -0,0 +1,81 @@ +# $OpenLDAP$ +## Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. +## COPYING RESTRICTIONS APPLY, see COPYRIGHT file +#----------------------------------------------------------------------------- +# Portions Copyright (c) 1995 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. +# +# Stand alone LDAP server tools makefile +# +#----------------------------------------------------------------------------- + +LDAP_INCDIR= ../../../include +LDAP_LIBDIR= ../../../libraries + +SLAP_DIR=../ +SLAPD_MODULES = @SLAPD_MODULES_LIST@ +XDEFS = $(MODULES_CPPFLAGS) +XLDFLAGS = $(MODULES_LDFLAGS) $(SLAPD_MODULES) + +XLIBS = $(SLAPD_L) $(LDBM_LIBS) +XXLIBS = $(SLAPD_LIBS) \ + $(LDBM_LIBS) $(SECURITY_LIBS) \ + $(LDIF_LIBS) $(LUTIL_LIBS) +XXXLIBS = $(MODULES_LIBS) $(LTHREAD_LIBS) + +PROGRAMS=slapadd slapcat slapindex slappasswd + +SRCS = mimic.c slapcommon.c \ + slapadd.c slapcat.c slapindex.c slappasswd.c + +SLAPD_OBJS = ../config.o ../ch_malloc.o ../backend.o ../charray.o \ + ../module.o ../aclparse.o ../filterentry.o ../schema.o \ + ../schema_check.o ../schema_init.o ../schema_prep.o \ + ../schemaparse.o ../ad.o ../at.o ../mr.o ../oc.o \ + ../syntax.o ../acl.o ../phonetic.o ../attr.o ../value.o \ + ../entry.o ../dn.o ../filter.o ../str2filter.o ../ava.o \ + ../init.o ../controls.o ../kerberos.o ../passwd.o \ + ../index.o ../extended.o ../starttls.o ../sets.o ../mra.o \ + ../referral.o ../backglue.o ../oidm.o ../mods.o + +SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o + +all-local: build-progs + +build-progs: $(PROGRAMS) + +# +# SLAP Tools +# +slapadd: slapadd.o ../libbackends.a $(SLAPOBJS) $(SLAPD_L) + $(LTLINK) -o $@ slapadd.o $(SLAPOBJS) ../libbackends.a $(LIBS) + +slapcat: slapcat.o ../libbackends.a $(SLAPOBJS) $(SLAPD_L) + $(LTLINK) -o $@ slapcat.o $(SLAPOBJS) ../libbackends.a $(LIBS) + +slapindex: slapindex.o ../libbackends.a $(SLAPOBJS) $(SLAPD_L) + $(LTLINK) -o $@ slapindex.o $(SLAPOBJS) ../libbackends.a $(LIBS) + +slappasswd: slappasswd.o $(SLAPD_L) + $(LTLINK) -o $@ slappasswd.o $(LIBS) + +clean-local: FORCE + $(RM) $(PROGRAMS) $(XPROGRAMS) $(XSRCS) *.o core .libs/* *.exe + +depend-local: FORCE + $(MKDEP) $(DEFS) $(DEFINES) $(SRCS) + +install-local: FORCE + -$(MKDIR) $(DESTDIR)$(sbindir) + @for bin in $(PROGRAMS); do \ + $(LTINSTALL) $(INSTALLFLAGS) -s -m 755 \ + $$bin$(EXEEXT) $(DESTDIR)$(sbindir); \ + done + diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c new file mode 100644 index 0000000000000000000000000000000000000000..3db426bac42a2c9763730db289879a6632b521b6 --- /dev/null +++ b/servers/slapd/tools/mimic.c @@ -0,0 +1,246 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Mimic unused interfaces of slapd... + * needed for linking. + */ +#include "portable.h" + +#include <stdio.h> + +#include "../slap.h" + +/* needed by WIN32 and back-monitor */ +time_t starttime; + +/* because Versionstr is used in back-monitor */ +const char Versionstr[] = ""; + +/* bogus ../results.c */ +int str2result( + char* s, + int *code, + char **matched, + char **info ) +{ + assert(0); + return 0; +} + +void +send_ldap_disconnect( + Connection *conn, + Operation *op, + ber_int_t err, + const char *text +) +{ + assert(0); +} + +void +send_ldap_extended( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + const char *rspoid, + struct berval *rspdata, + LDAPControl **ctrls +) +{ + assert(0); +} + +void +send_ldap_sasl( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + LDAPControl **ctrls, + struct berval *cred +) +{ + assert(0); +} + +void +send_ldap_result( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + LDAPControl **ctrls +) +{ + assert(0); +} + +void +send_search_result( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + LDAPControl **ctrls, + int nentries +) +{ + assert(0); +} + +int +send_search_entry( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + AttributeName *attrs, + int attrsonly, + LDAPControl **ctrls +) +{ + assert(0); + return -1; +} + +int send_search_reference( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + BerVarray refs, + LDAPControl **ctrls, + BerVarray *v2refs +) +{ + assert(0); + return -1; +} + +int slap_sasl_init(void) +{ + return LDAP_SUCCESS; +} + +int slap_sasl_destroy(void) +{ + return LDAP_SUCCESS; +} + +char * slap_sasl_secprops( const char *in ) +{ + return NULL; +} + + +int slap_sasl_regexp_config( const char *match, const char *replace ) +{ + return(0); +} + + +void connection2anonymous( Connection *c ) +{ + assert(0); +} + +Connection * connection_first( ber_socket_t *b ) +{ + assert(0); + return NULL; +} + +Connection * connection_next( Connection *c, ber_socket_t *b ) +{ + assert(0); + return NULL; +} + +unsigned long connections_nextid(void) +{ + return 0; +} + +void connection_done( Connection *c ) +{ + assert(0); +} + +const char * connection_state2str( int state ) +{ + assert(0); + return NULL; +} + +void replog( Backend *be, Operation *op, + struct berval *dn, struct berval *ndn, void *change) +{ + assert(0); +} + +int add_replica_info( Backend *be, const char *host ) +{ + return 0; +} + +int add_replica_suffix( Backend *be, int nr, const char *suffix ) +{ + return 0; +} + +int add_replica_attrs( Backend *be, int nr, char *attrs, int exclude ) +{ + return 0; +} + +int parse_limits( Backend *be, const char *fname, int lineno, int argc, char **argv ) +{ + return 0; +} + +int parse_limit( const char *arg, struct slap_limits_set *limit ) +{ + return 0; +} + +int get_limits( Backend *be, struct berval *ndn, struct slap_limits_set **limit ) +{ + return 0; +} + +int read_root_dse_file ( const char *file ) +{ + return 0; +} + +Attribute * +slap_operational_subschemaSubentry( void ) +{ + return NULL; +} + +Attribute * +slap_operational_hasSubordinate( int hs ) +{ + return NULL; +} + +Listener ** +slapd_get_listeners(void) +{ + return NULL; +} + diff --git a/servers/slapd/tools/slapadd.c b/servers/slapd/tools/slapadd.c index d3ce99b9d2e6dd27a1890f4e2019cddc643fe9fc..ad18fe9c6b18e658d02cc6997e9c3f4c685d190d 100644 --- a/servers/slapd/tools/slapadd.c +++ b/servers/slapd/tools/slapadd.c @@ -115,7 +115,8 @@ main( int argc, char **argv ) if( sc == NULL ) { struct berval vals[2]; - int ret = structural_class( oc->a_vals, vals, + /* int ret = */ + structural_class( oc->a_vals, vals, NULL, &text, textbuf, textlen ); if( vals[0].bv_len == 0 ) { diff --git a/servers/slapd/tools/slapadd.dsp b/servers/slapd/tools/slapadd.dsp new file mode 100644 index 0000000000000000000000000000000000000000..88e6c5da442dcbbe4a11f43e41760a24d7646299 --- /dev/null +++ b/servers/slapd/tools/slapadd.dsp @@ -0,0 +1,157 @@ +# Microsoft Developer Studio Project File - Name="slapadd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=slapadd - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "slapadd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "slapadd.mak" CFG="slapadd - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "slapadd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "slapadd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "slapadd - Win32 Single Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "slapadd - Win32 Single Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "slapadd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\Release" +# PROP Intermediate_Dir "..\..\..\Release\slapadd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 sasl.lib libdb40.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\Release" + +!ELSEIF "$(CFG)" == "slapadd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ldif2" +# PROP BASE Intermediate_Dir "ldif2" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\Debug" +# PROP Intermediate_Dir "..\..\..\Debug\slapadd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb40d.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\Debug" + +!ELSEIF "$(CFG)" == "slapadd - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ldif2" +# PROP BASE Intermediate_Dir "ldif2" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\SDebug" +# PROP Intermediate_Dir "..\..\..\SDebug\slapadd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib hs_regexd.lib libdbs.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb32.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\SDebug" + +!ELSEIF "$(CFG)" == "slapadd - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ldif2id0" +# PROP BASE Intermediate_Dir "ldif2id0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\SRelease" +# PROP Intermediate_Dir "..\..\..\SRelease\slapadd" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 hs_regex.lib libdb.lib ws2_32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libdbs.lib libdb32.lib hs_regex.lib libsasl.lib ws2_32.lib rpcrt4.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\SRelease" + +!ENDIF + +# Begin Target + +# Name "slapadd - Win32 Release" +# Name "slapadd - Win32 Debug" +# Name "slapadd - Win32 Single Debug" +# Name "slapadd - Win32 Single Release" +# Begin Source File + +SOURCE=.\mimic.c +# End Source File +# Begin Source File + +SOURCE=.\slapadd.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.h +# End Source File +# End Target +# End Project diff --git a/servers/slapd/tools/slapcat.dsp b/servers/slapd/tools/slapcat.dsp new file mode 100644 index 0000000000000000000000000000000000000000..8aa4dc912a16ece2bb0ad5e1ae2c4e501c8a4a36 --- /dev/null +++ b/servers/slapd/tools/slapcat.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="slapcat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=slapcat - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "slapcat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "slapcat.mak" CFG="slapcat - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "slapcat - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "slapcat - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "slapcat - Win32 Single Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "slapcat - Win32 Single Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "slapcat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\Release" +# PROP Intermediate_Dir "..\..\..\Release\slapcat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 sasl.lib libdb40.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\Release" + +!ELSEIF "$(CFG)" == "slapcat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "slapcat" +# PROP BASE Intermediate_Dir "slapcat" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\Debug" +# PROP Intermediate_Dir "..\..\..\Debug\slapcat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb40d.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\Debug" + +!ELSEIF "$(CFG)" == "slapcat - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "slapcat" +# PROP BASE Intermediate_Dir "slapcat" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\Sdebug" +# PROP Intermediate_Dir "..\..\..\SDebug\slapcat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 oldbm32.lib libdb.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\libraries\Debug" +# ADD LINK32 libdb32.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\SDebug" + +!ELSEIF "$(CFG)" == "slapcat - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "slapcat" +# PROP BASE Intermediate_Dir "slapcat" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\SRelease" +# PROP Intermediate_Dir "..\..\..\SRelease\slapcat" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libdb.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\libraries\Release" +# ADD LINK32 libdbs.lib libdb32.lib hs_regex.lib libsasl.lib ws2_32.lib rpcrt4.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\SRelease" + +!ENDIF + +# Begin Target + +# Name "slapcat - Win32 Release" +# Name "slapcat - Win32 Debug" +# Name "slapcat - Win32 Single Debug" +# Name "slapcat - Win32 Single Release" +# Begin Source File + +SOURCE=.\mimic.c +# End Source File +# Begin Source File + +SOURCE=.\slapcat.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.h +# End Source File +# End Target +# End Project diff --git a/servers/slapd/tools/slapcommon.c b/servers/slapd/tools/slapcommon.c new file mode 100644 index 0000000000000000000000000000000000000000..abe5b7abeb754ee50f234627758e243640aa7887 --- /dev/null +++ b/servers/slapd/tools/slapcommon.c @@ -0,0 +1,285 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* slapcommon.c - common routine for the slap tools */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> +#include <ac/unistd.h> + +#include "slapcommon.h" +#include "lutil.h" + + +char *progname = NULL; +char *conffile = SLAPD_DEFAULT_CONFIGFILE; +int truncatemode = 0; +int verbose = 0; +int continuemode = 0; +int nosubordinates = 0; +int dryrun = 0; + +char *ldiffile = NULL; +FILE *ldiffp = NULL; + +#ifdef CSRIMALLOC + char *leakfilename; + FILE *leakfile; +#endif + +Backend *be = NULL; + +static void +usage( int tool ) +{ + char *options = NULL; + fprintf( stderr, + "usage: %s [-v] [-c] [-d debuglevel] [-f configfile]\n" + "\t[-n databasenumber | -b suffix]", progname ); + + switch( tool ) { + case SLAPADD: + options = "\t[-l ldiffile]\n"; + break; + + case SLAPCAT: + options = "\t[-l ldiffile]\n"; + break; + + case SLAPINDEX: + options = "\n"; + break; + } + + if( options != NULL ) { + fputs( options, stderr ); + } + exit( EXIT_FAILURE ); +} + + +/* + * slap_tool_init - initialize slap utility, handle program options. + * arguments: + * name program name + * tool tool code + * argc, argv command line arguments + */ + +void +slap_tool_init( + const char* name, + int tool, + int argc, char **argv ) +{ + char *options; + struct berval base = { 0, NULL }; + int rc, i, dbnum; + int mode = SLAP_TOOL_MODE; + + progname = lutil_progname( name, argc, argv ); + +#ifdef CSRIMALLOC + leakfilename = malloc( strlen( progname ) + sizeof(".leak") ); + sprintf( leakfilename, "%s.leak", progname ); + if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) { + leakfile = stderr; + } + free( leakfilename ); +#endif + + switch( tool ) { + case SLAPADD: + options = "b:cd:f:l:n:tuv"; + break; + + case SLAPINDEX: + options = "b:cd:f:n:v"; + break; + + case SLAPCAT: + options = "b:cd:f:l:n:v"; + break; + + default: + fprintf( stderr, "%s: unknown tool mode (%d)\n", + progname, tool ); + exit( EXIT_FAILURE ); + } + + ldiffile = NULL; + conffile = SLAPD_DEFAULT_CONFIGFILE; + dbnum = -1; + while ( (i = getopt( argc, argv, options )) != EOF ) { + switch ( i ) { + case 'b': + base.bv_val = strdup( optarg ); + base.bv_len = strlen( base.bv_val ); + + case 'c': /* enable continue mode */ + continuemode++; + break; + + case 'd': /* turn on debugging */ + ldap_debug += atoi( optarg ); + break; + + case 'f': /* specify a conf file */ + conffile = strdup( optarg ); + break; + + case 'l': /* LDIF file */ + ldiffile = strdup( optarg ); + break; + + case 'n': /* which config file db to index */ + dbnum = atoi( optarg ) - 1; + break; + + case 't': /* turn on truncate */ + truncatemode++; + mode |= SLAP_TRUNCATE_MODE; + break; + + case 'u': /* dry run */ + dryrun++; + break; + + case 'v': /* turn on verbose */ + verbose++; + break; + + default: + usage( tool ); + break; + } + } + + if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) { + usage( tool ); + } + + if ( ldiffile == NULL ) { + ldiffp = tool == SLAPCAT ? stdout : stdin; + + } else if( (ldiffp = fopen( ldiffile, tool == SLAPCAT ? "w" : "r" )) + == NULL ) + { + perror( ldiffile ); + exit( EXIT_FAILURE ); + } + + /* + * initialize stuff and figure out which backend we're dealing with + */ + + rc = slap_init( mode, progname ); + + if (rc != 0 ) { + fprintf( stderr, "%s: slap_init failed!\n", progname ); + exit( EXIT_FAILURE ); + } + + rc = slap_schema_init(); + + if (rc != 0 ) { + fprintf( stderr, "%s: slap_schema_init failed!\n", progname ); + exit( EXIT_FAILURE ); + } + + rc = read_config( conffile ); + + if ( rc != 0 ) { + fprintf( stderr, "%s: bad configuration file!\n", progname ); + exit( EXIT_FAILURE ); + } + + if ( !nbackends ) { + fprintf( stderr, "No databases found in config file\n" ); + exit( EXIT_FAILURE ); + } + + rc = glue_sub_init(); + + if (rc != 0 ) { + fprintf( stderr, "Subordinate configuration error\n" ); + exit( EXIT_FAILURE ); + } + + rc = slap_schema_check(); + + if (rc != 0 ) { + fprintf( stderr, "%s: slap_schema_prep failed!\n", progname ); + exit( EXIT_FAILURE ); + } + + if( base.bv_val != NULL ) { + struct berval *nbase = NULL; + + rc = dnNormalize( NULL, &base, &nbase ); + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n", + progname, base.bv_val ); + exit( EXIT_FAILURE ); + } + + be = select_backend( nbase, 0, 0 ); + ber_bvfree( nbase ); + + if( be == NULL ) { + fprintf( stderr, "%s: slap_init no backend for \"%s\"\n", + progname, base.bv_val ); + exit( EXIT_FAILURE ); + } + /* If the named base is a glue master, operate on the + * entire context + */ + if (be->be_flags & SLAP_BFLAG_GLUE_INSTANCE) + nosubordinates = 1; + + } else if ( dbnum == -1 ) { + be = &backends[dbnum=0]; + /* If just doing the first by default and it is a + * glue subordinate, find the master. + */ + while (be->be_flags & SLAP_BFLAG_GLUE_SUBORDINATE) { + nosubordinates = 1; + be++; + } + + } else if ( dbnum < 0 || dbnum > (nbackends-1) ) { + fprintf( stderr, + "Database number selected via -n is out of range\n" + "Must be in the range 1 to %d" + " (number of databases in the config file)\n", + nbackends ); + exit( EXIT_FAILURE ); + + } else { + be = &backends[dbnum]; + } + +#ifdef CSRIMALLOC + mal_leaktrace(1); +#endif + + slap_startup( be ); +} + +void slap_tool_destroy( void ) +{ + slap_shutdown( be ); + slap_destroy(); + +#ifdef CSRIMALLOC + mal_dumpleaktrace( leakfile ); +#endif +} diff --git a/servers/slapd/tools/slapindex.dsp b/servers/slapd/tools/slapindex.dsp new file mode 100644 index 0000000000000000000000000000000000000000..1a836ace52262ebbf287a9776feacf5edd3b370e --- /dev/null +++ b/servers/slapd/tools/slapindex.dsp @@ -0,0 +1,158 @@ +# Microsoft Developer Studio Project File - Name="slapindex" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=slapindex - Win32 Single Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "slapindex.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "slapindex.mak" CFG="slapindex - Win32 Single Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "slapindex - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "slapindex - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "slapindex - Win32 Single Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "slapindex - Win32 Single Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "slapindex - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\Release" +# PROP Intermediate_Dir "..\..\..\Release\slapindex" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 sasl.lib libdb40.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\Release" + +!ELSEIF "$(CFG)" == "slapindex - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ldif2ind" +# PROP BASE Intermediate_Dir "ldif2ind" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\Debug" +# PROP Intermediate_Dir "..\..\..\Debug\slapindex" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb40d.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\Debug" + +!ELSEIF "$(CFG)" == "slapindex - Win32 Single Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ldif2ind" +# PROP BASE Intermediate_Dir "ldif2ind" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\SDebug" +# PROP Intermediate_Dir "..\..\..\SDebug\slapindex" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib shell32.lib hs_regexd.lib libdbs.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb32.lib rpcrt4.lib hs_regex.lib libsasl.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\SDebug" + +!ELSEIF "$(CFG)" == "slapindex - Win32 Single Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ldif2in0" +# PROP BASE Intermediate_Dir "ldif2in0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\SRelease" +# PROP Intermediate_Dir "..\..\..\SRelease\slapindex" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 hs_regex.lib libdb.lib ws2_32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libdbs.lib libdb32.lib hs_regex.lib libsasl.lib ws2_32.lib rpcrt4.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\SRelease" + +!ENDIF + +# Begin Target + +# Name "slapindex - Win32 Release" +# Name "slapindex - Win32 Debug" +# Name "slapindex - Win32 Single Debug" +# Name "slapindex - Win32 Single Release" +# Begin Source File + +SOURCE=.\mimic.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.c +# End Source File +# Begin Source File + +SOURCE=.\slapcommon.h +# End Source File +# Begin Source File + +SOURCE=.\slapindex.c +# End Source File +# End Target +# End Project diff --git a/servers/slapd/unbind.c b/servers/slapd/unbind.c index 500006c34f0a76218346a570a99fb6d992198863..40457cfe9ace176af24e749075d2b23bba5f3eb4 100644 --- a/servers/slapd/unbind.c +++ b/servers/slapd/unbind.c @@ -1,4 +1,9 @@ /* unbind.c - decode an ldap unbind operation and pass it to a backend db */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ /* * Copyright (c) 1995 Regents of the University of Michigan. @@ -13,24 +18,28 @@ * */ +#include "portable.h" + #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include "slap.h" -extern Backend *select_backend(); -extern void be_unbind(); +#include <ac/socket.h> + +#include "slap.h" -extern char *default_referral; -extern pthread_mutex_t new_conn_mutex; -void +int do_unbind( Connection *conn, Operation *op ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "do_unbind: conn %d\n", conn ? conn->c_connid : -1 )); +#else Debug( LDAP_DEBUG_TRACE, "do_unbind\n", 0, 0, 0 ); +#endif + /* * Parse the unbind request. It looks like this: @@ -38,12 +47,11 @@ do_unbind( * UnBindRequest ::= NULL */ - Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d UNBIND\n", conn->c_connid, + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu UNBIND\n", op->o_connid, op->o_opid, 0, 0, 0 ); /* pass the unbind to all backends */ - be_unbind( conn, op ); - - /* close the connection to the client */ - close_connection( conn, op->o_connid, op->o_opid ); + backend_unbind( conn, op ); + + return 0; } diff --git a/servers/slapd/value.c b/servers/slapd/value.c index c9e6fbb5774a1560f88990c63cab8a1e528fed5b..002a105ab36aad5cd4c7ede354cecb4992ec15e8 100644 --- a/servers/slapd/value.c +++ b/servers/slapd/value.c @@ -1,212 +1,350 @@ /* value.c - routines for dealing with values */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> + +#include <ac/ctype.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + #include <sys/stat.h> -#include "portable.h" + #include "slap.h" int -value_add_fast( - struct berval ***vals, - struct berval **addvals, - int nvals, - int naddvals, - int *maxvals +value_add( + BerVarray *vals, + BerVarray addvals ) { - int need, i, j; + int n, nn; + BerVarray v2; - if ( *maxvals == 0 ) { - *maxvals = 1; - } - need = nvals + naddvals + 1; - while ( *maxvals < need ) { - *maxvals *= 2; - *vals = (struct berval **) ch_realloc( (char *) *vals, - *maxvals * sizeof(struct berval *) ); - } + for ( nn = 0; addvals != NULL && addvals[nn].bv_val != NULL; nn++ ) + ; /* NULL */ - for ( i = 0, j = 0; i < naddvals; i++, j++ ) { - if ( addvals[i]->bv_len > 0 ) { - (*vals)[nvals + j] = ber_bvdup( addvals[i] ); + if ( *vals == NULL ) { + *vals = (BerVarray) ch_malloc( (nn + 1) + * sizeof(struct berval) ); + n = 0; + } else { + for ( n = 0; (*vals)[n].bv_val != NULL; n++ ) { + ; /* Empty */ } + *vals = (BerVarray) ch_realloc( (char *) *vals, + (n + nn + 1) * sizeof(struct berval) ); + } + + v2 = *vals + n; + for ( ; addvals->bv_val; v2++, addvals++ ) { + ber_dupbv(v2, addvals); + if (v2->bv_val == NULL) break; } - (*vals)[nvals + j] = NULL; + v2->bv_val = NULL; + v2->bv_len = 0; - return( 0 ); + return LDAP_SUCCESS; } int -value_add( - struct berval ***vals, - struct berval **addvals -) +value_validate( + MatchingRule *mr, + struct berval *in, + const char **text ) { - int n, nn, i, j; + int rc; - for ( nn = 0; addvals != NULL && addvals[nn] != NULL; nn++ ) - ; /* NULL */ + if( mr == NULL ) { + *text = "inappropriate matching request"; + return LDAP_INAPPROPRIATE_MATCHING; + } - if ( *vals == NULL ) { - *vals = (struct berval **) ch_malloc( (nn + 1) - * sizeof(struct berval *) ); - n = 0; - } else { - for ( n = 0; (*vals)[n] != NULL; n++ ) - ; /* NULL */ - *vals = (struct berval **) ch_realloc( (char *) *vals, - (n + nn + 1) * sizeof(struct berval *) ); + if( mr->smr_syntax == NULL ) { + *text = "no assertion syntax"; + return LDAP_INVALID_SYNTAX; } - for ( i = 0, j = 0; i < nn; i++ ) { - if ( addvals[i]->bv_len > 0 ) { - (*vals)[n + j++] = ber_bvdup( addvals[i] ); - } + if( ! mr->smr_syntax->ssyn_validate ) { + *text = "no syntax validator"; + return LDAP_INVALID_SYNTAX; + } + + rc = (mr->smr_syntax->ssyn_validate)( mr->smr_syntax, in ); + + if( rc != LDAP_SUCCESS ) { + *text = "value is invalid"; + return LDAP_INVALID_SYNTAX; } - (*vals)[n + j] = NULL; - return( 0 ); + return LDAP_SUCCESS; } -void +int value_normalize( - char *s, - int syntax -) + AttributeDescription *ad, + unsigned usage, + struct berval *in, + struct berval *out, + const char **text ) { - char *d, *save; + int rc; + MatchingRule *mr; + + switch( usage & SLAP_MR_TYPE_MASK ) { + case SLAP_MR_NONE: + case SLAP_MR_EQUALITY: + mr = ad->ad_type->sat_equality; + break; + case SLAP_MR_ORDERING: + mr = ad->ad_type->sat_ordering; + break; + case SLAP_MR_SUBSTR: + mr = ad->ad_type->sat_substr; + break; + case SLAP_MR_EXT: + default: + assert( 0 ); + *text = "internal error"; + return LDAP_OTHER; + } - if ( ! (syntax & SYNTAX_CIS) ) { - return; + if( mr == NULL ) { + *text = "inappropriate matching request"; + return LDAP_INAPPROPRIATE_MATCHING; } - if ( syntax & SYNTAX_DN ) { - (void) dn_normalize_case( s ); - return; + /* we only support equality matching of binary attributes */ + /* This is suspect, flexible certificate matching will hit this */ + if( slap_ad_is_binary( ad ) && usage != SLAP_MR_EQUALITY ) { + *text = "inappropriate binary matching"; + return LDAP_INAPPROPRIATE_MATCHING; } - save = s; - for ( d = s; *s; s++ ) { - if ( (syntax & SYNTAX_TEL) && (*s == ' ' || *s == '-') ) { - continue; + if( mr->smr_normalize ) { + rc = (mr->smr_normalize)( usage, + ad->ad_type->sat_syntax, + mr, in, out ); + + if( rc != LDAP_SUCCESS ) { + *text = "unable to normalize value"; + return LDAP_INVALID_SYNTAX; } - *d++ = TOUPPER( *s ); + + } else if ( mr->smr_syntax->ssyn_normalize ) { + rc = (mr->smr_syntax->ssyn_normalize)( + ad->ad_type->sat_syntax, + in, out ); + + if( rc != LDAP_SUCCESS ) { + *text = "unable to normalize value"; + return LDAP_INVALID_SYNTAX; + } + + } else { + ber_dupbv( out, in ); } - *d = '\0'; -} -#define MIN( a, b ) (a < b ? a : b ) + return LDAP_SUCCESS; +} int -value_cmp( - struct berval *v1, - struct berval *v2, - int syntax, - int normalize /* 1 => arg 1; 2 => arg 2; 3 => both */ -) +value_validate_normalize( + AttributeDescription *ad, + unsigned usage, + struct berval *in, + struct berval *out, + const char **text ) { - int rc; - struct stat st1, st2; + int rc; + MatchingRule *mr; - if ( normalize & 1 ) { - v1 = ber_bvdup( v1 ); - value_normalize( v1->bv_val, syntax ); + switch( usage & SLAP_MR_TYPE_MASK ) { + case SLAP_MR_NONE: + case SLAP_MR_EQUALITY: + mr = ad->ad_type->sat_equality; + break; + case SLAP_MR_ORDERING: + mr = ad->ad_type->sat_ordering; + break; + case SLAP_MR_SUBSTR: + mr = ad->ad_type->sat_substr; + break; + case SLAP_MR_EXT: + default: + assert( 0 ); + *text = "internal error"; + return LDAP_OTHER; } - if ( normalize & 2 ) { - v2 = ber_bvdup( v2 ); - value_normalize( v2->bv_val, syntax ); + + if( mr == NULL ) { + *text = "inappropriate matching request"; + return LDAP_INAPPROPRIATE_MATCHING; } - switch ( syntax ) { - case SYNTAX_CIS: - case (SYNTAX_CIS | SYNTAX_TEL): - case (SYNTAX_CIS | SYNTAX_DN): - rc = strcasecmp( v1->bv_val, v2->bv_val ); - break; + if( mr->smr_syntax == NULL ) { + *text = "no assertion syntax"; + return LDAP_INVALID_SYNTAX; + } - case SYNTAX_CES: - rc = strcmp( v1->bv_val, v2->bv_val ); - break; + if( ! mr->smr_syntax->ssyn_validate ) { + *text = "no syntax validator"; + return LDAP_INVALID_SYNTAX; + } - case SYNTAX_BIN: - rc = memcmp( v1->bv_val, v2->bv_val, MIN( v1->bv_len, - v2->bv_len ) ); - break; + rc = (mr->smr_syntax->ssyn_validate)( mr->smr_syntax, in ); + + if( rc != LDAP_SUCCESS ) { + *text = "value is invalid"; + return LDAP_INVALID_SYNTAX; } - if ( normalize & 1 ) { - ber_bvfree( v1 ); + /* we only support equality matching of binary attributes */ + /* This is suspect, flexible certificate matching will hit this */ + if( slap_ad_is_binary( ad ) && usage != SLAP_MR_EQUALITY ) { + *text = "inappropriate binary matching"; + return LDAP_INAPPROPRIATE_MATCHING; } - if ( normalize & 2 ) { - ber_bvfree( v2 ); + + if( mr->smr_normalize ) { + rc = (mr->smr_normalize)( usage, + ad->ad_type->sat_syntax, + mr, in, out ); + + if( rc != LDAP_SUCCESS ) { + *text = "unable to normalize value"; + return LDAP_INVALID_SYNTAX; + } + + } else if ( mr->smr_syntax->ssyn_normalize ) { + rc = (mr->smr_syntax->ssyn_normalize)( + ad->ad_type->sat_syntax, + in, out ); + + if( rc != LDAP_SUCCESS ) { + *text = "unable to normalize value"; + return LDAP_INVALID_SYNTAX; + } + + } else { + ber_dupbv( out, in ); } - return( rc ); + return LDAP_SUCCESS; } + int -value_ncmp( - struct berval *v1, - struct berval *v2, - int syntax, - int len, - int normalize -) +value_match( + int *match, + AttributeDescription *ad, + MatchingRule *mr, + unsigned flags, + struct berval *v1, /* stored value */ + void *v2, /* assertion */ + const char ** text ) { - int rc; + int rc; + struct berval nv1 = { 0, NULL }; + struct berval nv2 = { 0, NULL }; - if ( normalize & 1 ) { - v1 = ber_bvdup( v1 ); - value_normalize( v1->bv_val, syntax ); + if( !mr->smr_match ) { + return LDAP_INAPPROPRIATE_MATCHING; } - if ( normalize & 2 ) { - v2 = ber_bvdup( v2 ); - value_normalize( v2->bv_val, syntax ); - } - - switch ( syntax ) { - case SYNTAX_CIS: - case (SYNTAX_CIS | SYNTAX_TEL): - rc = strncasecmp( v1->bv_val, v2->bv_val, len ); - break; - case SYNTAX_CES: - rc = strncmp( v1->bv_val, v2->bv_val, len ); - break; + if( ad->ad_type->sat_syntax->ssyn_normalize ) { + rc = ad->ad_type->sat_syntax->ssyn_normalize( + ad->ad_type->sat_syntax, v1, &nv1 ); - case SYNTAX_BIN: - rc = memcmp( v1->bv_val, v2->bv_val, len ); + if( rc != LDAP_SUCCESS ) { + return LDAP_INAPPROPRIATE_MATCHING; + } } - if ( normalize & 1 ) { - ber_bvfree( v1 ); - } - if ( normalize & 2 ) { - ber_bvfree( v2 ); + if ( SLAP_IS_MR_VALUE_SYNTAX_NONCONVERTED_MATCH( flags ) && + mr->smr_convert ) + { + rc = (mr->smr_convert)( v2, &nv2 ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + /* let smr_match know we've converted the value */ + flags |= SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH; } - return( rc ); + rc = (mr->smr_match)( match, flags, + ad->ad_type->sat_syntax, + mr, + nv1.bv_val != NULL ? &nv1 : v1, + nv2.bv_val != NULL ? &nv2 : v2 ); + + if (nv1.bv_val ) free( nv1.bv_val ); + if (nv2.bv_val ) free( nv2.bv_val ); + return rc; } -int -value_find( - struct berval **vals, - struct berval *v, - int syntax, - int normalize -) + +int value_find_ex( + AttributeDescription *ad, + unsigned flags, + BerVarray vals, + struct berval *val ) { int i; + int rc; + struct berval nval = { 0, NULL }; + struct berval nval_tmp; + MatchingRule *mr = ad->ad_type->sat_equality; + + if( mr == NULL || !mr->smr_match ) { + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* Take care of this here or ssyn_normalize later will hurt */ + if ( SLAP_IS_MR_VALUE_SYNTAX_NONCONVERTED_MATCH( flags ) + && mr->smr_convert ) + { + rc = (mr->smr_convert)( val, &nval ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + + /* let value_match know we've done the version */ + flags |= SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH; + } + + if( mr->smr_syntax->ssyn_normalize ) { + rc = mr->smr_syntax->ssyn_normalize( + mr->smr_syntax, nval.bv_val == NULL ? val : &nval, &nval_tmp ); + + free(nval.bv_val); + nval = nval_tmp; + if( rc != LDAP_SUCCESS ) { + free(nval.bv_val); + return LDAP_INAPPROPRIATE_MATCHING; + } + } + + for ( i = 0; vals[i].bv_val != NULL; i++ ) { + int match; + const char *text; + + rc = value_match( &match, ad, mr, flags, + &vals[i], nval.bv_val == NULL ? val : &nval, &text ); - for ( i = 0; vals[i] != NULL; i++ ) { - if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) { - return( 0 ); + if( rc == LDAP_SUCCESS && match == 0 ) { + free( nval.bv_val ); + return LDAP_SUCCESS; } } - return( 1 ); + free( nval.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; } diff --git a/servers/slurpd/ldap_op.c b/servers/slurpd/ldap_op.c index 08253921cd891a768349e7c94b8242acc29f85bf..4d676fe4523cacbdba673d9998b28a5eb780f328 100644 --- a/servers/slurpd/ldap_op.c +++ b/servers/slurpd/ldap_op.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,55 +19,41 @@ * ldap_op.c - routines to perform LDAP operations */ +#include "portable.h" + #include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/time.h> -#ifdef KERBEROS -#include <krb.h> -#endif /* KERBEROS */ +#include <ac/stdlib.h> -#include <lber.h> -#include <ldap.h> +#include <ac/errno.h> +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/time.h> +#include <ac/unistd.h> -#include "portable.h" +#include <ldap.h> +#include "lutil_ldap.h" #include "slurp.h" /* Forward references */ -static int get_changetype( char * ); -static struct berval **make_singlevalued_berval( char *, int ); -static int op_ldap_add( Ri *, Re *, char ** ); -static int op_ldap_modify( Ri *, Re *, char ** ); -static int op_ldap_delete( Ri *, Re *, char ** ); -static int op_ldap_modrdn( Ri *, Re *, char ** ); -static LDAPMod *alloc_ldapmod(); -static void free_ldapmod( LDAPMod * ); -static void free_ldmarr( LDAPMod ** ); -static int getmodtype( char * ); -static void dump_ldm_array( LDAPMod ** ); -static char **read_krbnames( Ri * ); -static void upcase( char * ); -static int do_bind( Ri *, int * ); -static int do_unbind( Ri * ); - - -/* External references */ -#ifndef SYSERRLIST_IN_STDIO -extern char *sys_errlist[]; -#endif /* SYSERRLIST_IN_STDIO */ - -extern char *ch_malloc( unsigned long ); - -static char *kattrs[] = {"kerberosName", NULL }; -static struct timeval kst = {30L, 0L}; - +static struct berval **make_singlevalued_berval LDAP_P(( char *, int )); +static int op_ldap_add LDAP_P(( Ri *, Re *, char ** )); +static int op_ldap_modify LDAP_P(( Ri *, Re *, char ** )); +static int op_ldap_delete LDAP_P(( Ri *, Re *, char ** )); +static int op_ldap_modrdn LDAP_P(( Ri *, Re *, char ** )); +static LDAPMod *alloc_ldapmod LDAP_P(( void )); +static void free_ldapmod LDAP_P(( LDAPMod * )); +static void free_ldmarr LDAP_P(( LDAPMod ** )); +static int getmodtype LDAP_P(( char * )); +static void dump_ldm_array LDAP_P(( LDAPMod ** )); +static int do_bind LDAP_P(( Ri *, int * )); +static int do_unbind LDAP_P(( Ri * )); /* * Determine the type of ldap operation being performed and call the * appropriate routine. - * - If successful, returns ERR_DO_LDAP_OK + * - If successful, returns DO_LDAP_OK * - If a retryable error occurs, ERR_DO_LDAP_RETRYABLE is returned. * The caller should wait a while and retry the operation. * - If a fatal error occurs, ERR_DO_LDAP_FATAL is returned. The caller @@ -71,91 +62,95 @@ static struct timeval kst = {30L, 0L}; */ int do_ldap( - Ri *ri, - Re *re, - char **errmsg + Ri *ri, + Re *re, + char **errmsg ) { - int rc = 0; - int lderr = LDAP_SUCCESS; - int retry = 2; - char *msg; - - *errmsg = NULL; - - while ( retry > 0 ) { - if ( ri->ri_ldp == NULL ) { - rc = do_bind( ri, &lderr ); - if ( rc != BIND_OK ) { - return DO_LDAP_ERR_RETRYABLE; - } - } - - switch ( re->re_changetype ) { - case T_ADDCT: - lderr = op_ldap_add( ri, re, errmsg ); - if ( lderr != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: ldap_add_s failed adding \"%s\": %s\n", - *errmsg ? *errmsg : ldap_err2string( lderr ), - re->re_dn, 0 ); - } - break; - case T_MODIFYCT: - lderr = op_ldap_modify( ri, re, errmsg ); - if ( lderr != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: ldap_modify_s failed modifying \"%s\": %s\n", - *errmsg ? *errmsg : ldap_err2string( lderr ), - re->re_dn, 0 ); - } - break; - case T_DELETECT: - lderr = op_ldap_delete( ri, re, errmsg ); - if ( lderr != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: ldap_delete_s failed deleting \"%s\": %s\n", - *errmsg ? *errmsg : ldap_err2string( lderr ), - re->re_dn, 0 ); - } - break; - case T_MODRDNCT: - lderr = op_ldap_modrdn( ri, re, errmsg ); - if ( lderr != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: ldap_modrdn_s failed modifying %s: %s\n", - *errmsg ? *errmsg : ldap_err2string( lderr ), - re->re_dn, 0 ); - } - break; - default: - Debug( LDAP_DEBUG_ANY, - "Error: do_ldap: bad op \"%d\", dn = \"%s\"\n", - re->re_changetype, re->re_dn, 0 ); - return DO_LDAP_ERR_FATAL; - } - - /* - * Analyze return code. If ok, just return. If LDAP_SERVER_DOWN, - * we may have been idle long enough that the remote slapd timed - * us out. Rebind and try again. - */ - if ( lderr == LDAP_SUCCESS ) { - return DO_LDAP_OK; - } else if ( lderr == LDAP_SERVER_DOWN ) { - /* The LDAP server may have timed us out - rebind and try again */ - (void) do_unbind( ri ); - retry--; - } else { - return DO_LDAP_ERR_FATAL; - } - } - return DO_LDAP_ERR_FATAL; + int retry = 2; + *errmsg = NULL; + + do { + int lderr; + if ( ri->ri_ldp == NULL ) { + lderr = do_bind( ri, &lderr ); + + if ( lderr != BIND_OK ) { + return DO_LDAP_ERR_RETRYABLE; + } + } + + switch ( re->re_changetype ) { + case T_ADDCT: + lderr = op_ldap_add( ri, re, errmsg ); + if ( lderr != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_add_s failed adding \"%s\": %s\n", + *errmsg ? *errmsg : ldap_err2string( lderr ), + re->re_dn, 0 ); + } + break; + + case T_MODIFYCT: + lderr = op_ldap_modify( ri, re, errmsg ); + if ( lderr != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_modify_s failed modifying \"%s\": %s\n", + *errmsg ? *errmsg : ldap_err2string( lderr ), + re->re_dn, 0 ); + } + break; + + case T_DELETECT: + lderr = op_ldap_delete( ri, re, errmsg ); + if ( lderr != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_delete_s failed deleting \"%s\": %s\n", + *errmsg ? *errmsg : ldap_err2string( lderr ), + re->re_dn, 0 ); + } + break; + + case T_MODRDNCT: + lderr = op_ldap_modrdn( ri, re, errmsg ); + if ( lderr != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_modrdn_s failed modifying %s: %s\n", + *errmsg ? *errmsg : ldap_err2string( lderr ), + re->re_dn, 0 ); + } + break; + + default: + Debug( LDAP_DEBUG_ANY, + "Error: do_ldap: bad op \"%d\", dn = \"%s\"\n", + re->re_changetype, re->re_dn, 0 ); + return DO_LDAP_ERR_FATAL; + } + + /* + * Analyze return code. If ok, just return. If LDAP_SERVER_DOWN, + * we may have been idle long enough that the remote slapd timed + * us out. Rebind and try again. + */ + switch( lderr ) { + case LDAP_SUCCESS: + return DO_LDAP_OK; + + default: + return DO_LDAP_ERR_FATAL; + + case LDAP_SERVER_DOWN: /* server went down */ + (void) do_unbind( ri ); + retry--; + } + } while ( retry > 0 ); + + return DO_LDAP_ERR_RETRYABLE; } - /* * Perform an ldap add operation. */ @@ -198,11 +193,13 @@ op_ldap_add( Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n", ri->ri_hostname, ri->ri_port, re->re_dn ); rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr ); - lderr = ri->ri_ldp->ld_errno; + + ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr); + } else { *errmsg = "No modifications to do"; Debug( LDAP_DEBUG_ANY, - "Error: op_ldap_add: no mods to do (%s)!", re->re_dn, 0, 0 ); + "Error: op_ldap_add: no mods to do (%s)!\n", re->re_dn, 0, 0 ); } free_ldmarr( ldmarr ); return( lderr ); @@ -226,7 +223,7 @@ op_ldap_modify( int state; /* This code is a simple-minded state machine */ int nvals; /* Number of values we're modifying */ int nops; /* Number of LDAPMod structs in ldmarr */ - LDAPMod *ldm, *nldm, **ldmarr; + LDAPMod *ldm = NULL, **ldmarr; int i, len; char *type, *value; int rc = 0; @@ -292,6 +289,8 @@ op_ldap_modify( continue; } + assert( ldm ); + /* * We should have an attribute: value pair here. * Construct the mod_bvalues part of the ldapmod struct. @@ -353,9 +352,12 @@ op_ldap_delete( /* * Perform an ldap modrdn operation. */ -#define GOT_NEWRDN 1 -#define GOT_DRDNFLAGSTR 2 -#define GOT_ALLNEWRDNFLAGS ( GOT_NEWRDN | GOT_DRDNFLAGSTR ) +#define GOT_NEWRDN 0x1 +#define GOT_DELOLDRDN 0x2 +#define GOT_NEWSUP 0x4 + +#define GOT_MODDN_REQ (GOT_NEWRDN|GOT_DELOLDRDN) +#define GOT_ALL_MODDN(f) (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ) static int op_ldap_modrdn( Ri *ri, @@ -366,9 +368,11 @@ op_ldap_modrdn( int rc = 0; Mi *mi; int i; + int lderr = 0; int state = 0; int drdnflag = -1; - char *newrdn; + char *newrdn = NULL; + char *newsup = NULL; if ( re->re_mods == NULL ) { *errmsg = "No arguments given"; @@ -382,10 +386,27 @@ 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 ) { + Debug( LDAP_DEBUG_ANY, + "Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n", + mi[ i ].mi_val, 0, 0 ); + *errmsg = "Multiple newrdn argument"; + return -1; + } + newrdn = mi[ i ].mi_val; state |= GOT_NEWRDN; - } else if ( !strcmp( mi[ i ].mi_type, T_DRDNFLAGSTR )) { - state |= GOT_DRDNFLAGSTR; + + } else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) { + if( state & GOT_DELOLDRDN ) { + Debug( LDAP_DEBUG_ANY, + "Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n", + mi[ i ].mi_val, 0, 0 ); + *errmsg = "Multiple newrdn argument"; + return -1; + } + + state |= GOT_DELOLDRDN; if ( !strcmp( mi[ i ].mi_val, "0" )) { drdnflag = 0; } else if ( !strcmp( mi[ i ].mi_val, "1" )) { @@ -397,6 +418,19 @@ op_ldap_modrdn( *errmsg = "Incorrect argument to deleteoldrdn"; return -1; } + + } else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) { + if( state & GOT_NEWSUP ) { + Debug( LDAP_DEBUG_ANY, + "Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n", + mi[ i ].mi_val, 0, 0 ); + *errmsg = "Multiple newsuperior argument"; + return -1; + } + + newsup = mi[ i ].mi_val; + state |= GOT_NEWSUP; + } else { Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n", mi[ i ].mi_type, 0, 0 ); @@ -408,7 +442,7 @@ op_ldap_modrdn( /* * Punt if we don't have all the args. */ - if ( state != GOT_ALLNEWRDNFLAGS ) { + if ( !GOT_ALL_MODDN(state) ) { Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n", 0, 0, 0 ); *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\""; @@ -430,10 +464,13 @@ op_ldap_modrdn( } #endif /* LDAP_DEBUG */ + assert( newrdn ); + /* Do the modrdn */ - rc = ldap_modrdn2_s( ri->ri_ldp, re->re_dn, mi->mi_val, drdnflag ); + rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag ); - return( ri->ri_ldp->ld_errno ); + ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr); + return( lderr ); } @@ -442,7 +479,7 @@ op_ldap_modrdn( * Allocate and initialize an ldapmod struct. */ static LDAPMod * -alloc_ldapmod() +alloc_ldapmod( void ) { LDAPMod *ldm; @@ -557,7 +594,7 @@ do_unbind( if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n", - ldap_err2string( rc ), ri->ri_hostname, ri->ri_port ); + ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) ); } ri->ri_ldp = NULL; } @@ -583,18 +620,7 @@ do_bind( int *lderr ) { - int rc; int ldrc; - char msgbuf[ 1024]; -#ifdef KERBEROS - int retval = 0; - int kni, got_tgt; - char **krbnames; - char *skrbnames[ 2 ]; - char realm[ REALM_SZ ]; - char name[ ANAME_SZ ]; - char instance[ INST_SZ ]; -#endif /* KERBEROS */ *lderr = 0; @@ -613,108 +639,70 @@ do_bind( ri->ri_ldp = NULL; } - Debug( LDAP_DEBUG_ARGS, "Open connection to %s:%d\n", + Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n", ri->ri_hostname, ri->ri_port, 0 ); - ri->ri_ldp = ldap_open( ri->ri_hostname, ri->ri_port ); + + ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port ); if ( ri->ri_ldp == NULL ) { - Debug( LDAP_DEBUG_ANY, "Error: ldap_open(%s, %d) failed: %s\n", - ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] ); - return( BIND_ERR_OPEN ); + Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n", + ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] ); + return( BIND_ERR_OPEN ); } + { /* set version 3 */ + int err, version = 3; + err = ldap_set_option(ri->ri_ldp, + LDAP_OPT_PROTOCOL_VERSION, &version); + + if( err != LDAP_OPT_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n", + ri->ri_hostname, NULL, NULL ); + + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return BIND_ERR_VERSION; + } + } + /* * Set ldap library options to (1) not follow referrals, and * (2) restart the select() system call. */ -#ifdef LDAP_REFERRALS - ri->ri_ldp->ld_options &= ~LDAP_OPT_REFERRALS; -#endif /* LDAP_REFERRALS */ - ri->ri_ldp->ld_options |= LDAP_OPT_RESTART; - - switch ( ri->ri_bind_method ) { - case AUTH_KERBEROS: -#ifndef KERBEROS - Debug( LDAP_DEBUG_ANY, - "Error: Kerberos bind for %s:%d, but not compiled w/kerberos\n", - ri->ri_hostname, ri->ri_port, 0 ); - return( BIND_ERR_KERBEROS_FAILED ); -#else /* KERBEROS */ - /* - * Bind using kerberos. - * If "bindprincipal" was given in the config file, then attempt - * to get a TGT for that principal (via the srvtab file). If only - * a binddn was given, then we need to read that entry to get - * the kerberosName attributes, and try to get a TGT for one - * of them. All are tried. The first one which succeeds is - * returned. XXX It might be a good idea to just require a - * bindprincipal. Reading the entry every time might be a significant - * amount of overhead, if the connection is closed between most - * updates. - */ - - if ( ri->ri_principal != NULL ) { - skrbnames[ 0 ] = ri->ri_principal; - skrbnames[ 1 ] = NULL; - krbnames = skrbnames; - } else { - krbnames = read_krbnames( ri ); - } - - if (( krbnames == NULL ) || ( krbnames[ 0 ] == NULL )) { - Debug( LDAP_DEBUG_ANY, - "Error: Can't find krbname for binddn \"%s\"\n", - ri->ri_bind_dn, 0, 0 ); - retval = BIND_ERR_KERBEROS_FAILED; - goto kexit; - } - /* - * Now we've got one or more kerberos principals. See if any - * of them are in the srvtab file. - */ - got_tgt = 0; - for ( kni = 0; krbnames[ kni ] != NULL; kni++ ) { - rc = kname_parse( name, instance, realm, krbnames[ kni ]); - if ( rc != KSUCCESS ) { - continue; - } - upcase( realm ); - rc = krb_get_svc_in_tkt( name, instance, realm, "krbtgt", realm, - 1, ri->ri_srvtab ); - if ( rc != KSUCCESS) { - Debug( LDAP_DEBUG_ANY, "Error: Can't get TGT for %s: %s\n", - krbnames[ kni ], krb_err_txt[ rc ], 0 ); - } else { - got_tgt = 1; - break; - } + { + int err; + err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); + + if( err != LDAP_OPT_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n", + ri->ri_hostname, NULL, NULL ); + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return BIND_ERR_REFERRALS; + } } - if (!got_tgt) { - Debug( LDAP_DEBUG_ANY, - "Error: Could not obtain TGT for DN \"%s\"\n", - ri->ri_bind_dn, 0, 0 ); - retval = BIND_ERR_KERBEROS_FAILED; - goto kexit; + ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON); + + if( ri->ri_tls ) { + int err; + err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL); + + if( err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "%s: ldap_start_tls failed: %s (%d)\n", + ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning", + ldap_err2string( err ), err ); + + if( ri->ri_tls == TLS_CRITICAL ) { + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return BIND_ERR_TLS_FAILED; + } + } } - /* - * We've got a TGT. Do a kerberos bind. - */ - Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (kerberos)\n", - ri->ri_hostname, ri->ri_port, ri->ri_bind_dn ); - ldrc = ldap_kerberos_bind_s( ri->ri_ldp, ri->ri_bind_dn ); - ri->ri_principal = strdup( krbnames[ kni ] ); - if ( ldrc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "Error: kerberos bind for %s:%dfailed: %s\n", - ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc )); - *lderr = ldrc; - retval = BIND_ERR_KERBEROS_FAILED; - goto kexit; - } -kexit: if ( krbnames != NULL ) { - ldap_value_free( krbnames ); - } - return( retval); - break; -#endif /* KERBEROS */ + + switch ( ri->ri_bind_method ) { case AUTH_SIMPLE: /* * Bind with a plaintext password. @@ -728,17 +716,96 @@ kexit: if ( krbnames != NULL ) { "Error: ldap_simple_bind_s for %s:%d failed: %s\n", ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc )); *lderr = ldrc; + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; return( BIND_ERR_SIMPLE_FAILED ); - } else { - return( BIND_OK ); } break; + + case AUTH_SASL: + Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n", + ri->ri_hostname, ri->ri_authcId, ri->ri_saslmech ); + +#ifdef HAVE_CYRUS_SASL + if( ri->ri_secprops != NULL ) { + int err; + err = ldap_set_option(ri->ri_ldp, LDAP_OPT_X_SASL_SECPROPS, + ri->ri_secprops); + + if( err != LDAP_OPT_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n", + ri->ri_hostname, ri->ri_secprops, NULL ); + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return BIND_ERR_SASL_FAILED; + } + } + + { + char *passwd = ri->ri_password ? ber_strdup( ri->ri_password ) : NULL; + void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech, + ri->ri_realm, ri->ri_authcId, passwd, ri->ri_authzId ); + + ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn, + ri->ri_saslmech, NULL, NULL, + LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); + if ( ldrc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n", + ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc )); + *lderr = ldrc; + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return( BIND_ERR_SASL_FAILED ); + } + + ber_memfree( passwd ); + ber_memfree( defaults ); + } + break; +#else + Debug( LDAP_DEBUG_ANY, + "Error: do_bind: SASL not supported %s:%d\n", + ri->ri_hostname, ri->ri_port, NULL ); + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return( BIND_ERR_BAD_ATYPE ); +#endif + default: Debug( LDAP_DEBUG_ANY, "Error: do_bind: unknown auth type \"%d\" for %s:%d\n", ri->ri_bind_method, ri->ri_hostname, ri->ri_port ); + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; return( BIND_ERR_BAD_ATYPE ); } + + { + int err; + LDAPControl c; + LDAPControl *ctrls[2]; + ctrls[0] = &c; + ctrls[1] = NULL; + + c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; + c.ldctl_value.bv_val = NULL; + c.ldctl_value.bv_len = 0; + c.ldctl_iscritical = 0; + + err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls); + + if( err != LDAP_OPT_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "Error: " + "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n", + ri->ri_hostname, NULL, NULL ); + ldap_unbind( ri->ri_ldp ); + ri->ri_ldp = NULL; + return BIND_ERR_MANAGEDSAIT; + } + } + + return( BIND_OK ); } @@ -750,7 +817,8 @@ kexit: if ( krbnames != NULL ) { */ static void dump_ldm_array( -LDAPMod **ldmarr ) + LDAPMod **ldmarr +) { int i, j; LDAPMod *ldm; @@ -760,99 +828,23 @@ LDAPMod **ldmarr ) for ( i = 0; ldmarr[ i ] != NULL; i++ ) { ldm = ldmarr[ i ]; Debug( LDAP_DEBUG_TRACE, - "Trace (%d): *** ldmarr[ %d ] contents:\n", - getpid(), i, 0 ); + "Trace (%ld): *** ldmarr[ %d ] contents:\n", + (long) getpid(), i, 0 ); Debug( LDAP_DEBUG_TRACE, - "Trace (%d): *** ldm->mod_op: %d\n", - getpid(), ldm->mod_op, 0 ); + "Trace (%ld): *** ldm->mod_op: %d\n", + (long) getpid(), ldm->mod_op, 0 ); Debug( LDAP_DEBUG_TRACE, - "Trace (%d): *** ldm->mod_type: %s\n", - getpid(), ldm->mod_type, 0 ); + "Trace (%ld): *** ldm->mod_type: %s\n", + (long) getpid(), ldm->mod_type, 0 ); if ( ldm->mod_bvalues != NULL ) { for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) { msgbuf = ch_malloc( b->bv_len + 512 ); - sprintf( msgbuf, "***** bv[ %d ] len = %d, val = <%s>", + sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>", j, b->bv_len, b->bv_val ); Debug( LDAP_DEBUG_TRACE, - "Trace (%d):%s\n", getpid(), msgbuf, 0 ); + "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 ); free( msgbuf ); } } } } - - -/* - * Get the kerberos names from the binddn for "replica" via an ldap search. - * Returns a null-terminated array of char *, or NULL if the entry could - * not be found or there were no kerberosName attributes. The caller is - * responsible for freeing the returned array and strings it points to. - */ -static char ** -read_krbnames( - Ri *ri -) -{ - int rc; - char **krbnames; - int ne; - LDAPMessage *result, *entry; - - /* First need to bind as NULL */ - rc = ldap_simple_bind_s( ri->ri_ldp, NULL, NULL ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: null bind failed getting krbnames for %s:%d: %s\n", - ri->ri_hostname, ri->ri_port, ldap_err2string( rc )); - return( NULL ); - } - rc = ldap_search_st( ri->ri_ldp, ri->ri_bind_dn, LDAP_SCOPE_BASE, - "objectclass=*", kattrs, 0, &kst, &result ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "Error: search failed getting krbnames for %s:%d: %s\n", - ri->ri_hostname, ri->ri_port, ldap_err2string( rc )); - return( NULL ); - } - ne = ldap_count_entries( ri->ri_ldp, result ); - if ( ne == 0 ) { - Debug( LDAP_DEBUG_ANY, - "Error: Can't find entry \"%s\" for %s:%d kerberos bind\n", - ri->ri_bind_dn, ri->ri_hostname, ri->ri_port ); - return( NULL ); - } - if ( ne > 1 ) { - Debug( LDAP_DEBUG_ANY, - "Error: Kerberos binddn \"%s\" for %s:%dis ambiguous\n", - ri->ri_bind_dn, ri->ri_hostname, ri->ri_port ); - return( NULL ); - } - entry = ldap_first_entry( ri->ri_ldp, result ); - if ( entry == NULL ) { - Debug( LDAP_DEBUG_ANY, - "Error: Can't find \"%s\" for kerberos binddn for %s:%d\n", - ri->ri_bind_dn, ri->ri_hostname, ri->ri_port ); - return( NULL ); - } - krbnames = ldap_get_values( ri->ri_ldp, entry, "kerberosName" ); - ldap_msgfree( result ); - return( krbnames ); -} - - - -/* - * upcase a string - */ -static void -upcase( -char *s ) -{ - char *p; - - for ( p = s; ( p != NULL ) && ( *p != '\0' ); p++ ) { - if ( islower( *p )) { - *p = toupper( *p ); - } - } -} diff --git a/servers/slurpd/main.c b/servers/slurpd/main.c index a3b935faa578f384b348171f9122abe6aa06c260..19949128d31d294996029b9619ad24eadaa91e8a 100644 --- a/servers/slurpd/main.c +++ b/servers/slurpd/main.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,35 +20,34 @@ * main.c - main routine for slurpd. */ +#include "portable.h" + +#include <ac/stdlib.h> + #include <stdio.h> #include "slurp.h" #include "globals.h" +#include "lutil.h" +#include <ldap_pvt.h> -extern int doargs( int, char **, Globals * ); -extern void fm(); -extern int start_replica_thread( Ri * ); -extern Globals *init_globals(); -extern int sanity(); -#if defined( THREAD_SUNOS4_LWP ) -extern void start_lwp_scheduler(); -#endif /* THREAD_SUNOS4_LWP */ - +int main( int argc, char **argv ) { - pthread_attr_t attr; - int status; +#ifdef NO_THREADS + /* Haven't yet written the non-threaded version */ + fputs( "slurpd currently requires threads support\n", stderr ); + return( 1 ); +#else + int i; -#ifndef _THREAD - /* Haven't yet written the non-threaded version */ - fprintf( stderr, "slurpd currently requires threads support\n" ); - exit( 1 ); -#endif /* !_THREAD */ + /* initialize thread package */ + ldap_pvt_thread_initialize(); /* * Create and initialize globals. init_globals() also initializes @@ -51,14 +55,14 @@ main( */ if (( sglob = init_globals()) == NULL ) { fprintf( stderr, "Out of memory initializing globals\n" ); - exit( 1 ); + exit( EXIT_FAILURE ); } /* * Process command-line args and fill in globals. */ if ( doargs( argc, argv, sglob ) < 0 ) { - exit( 1 ); + exit( EXIT_FAILURE ); } /* @@ -68,6 +72,21 @@ main( fprintf( stderr, "Errors encountered while processing config file \"%s\"\n", sglob->slapd_configfile ); + exit( EXIT_FAILURE ); + } + +#ifdef HAVE_TLS + if( ldap_pvt_tls_init() || ldap_pvt_tls_init_def_ctx() ) { + fprintf( stderr, "TLS Initialization failed.\n" ); + exit( EXIT_FAILURE); + } +#endif + + /* + * Make sure our directory exists + */ + if ( mkdir(sglob->slurpd_rdir, 0755) == -1 && errno != EEXIST) { + perror(sglob->slurpd_rdir); exit( 1 ); } @@ -77,7 +96,7 @@ main( if ( sglob->st->st_read( sglob->st )) { fprintf( stderr, "Malformed slurpd status file \"%s\"\n", sglob->slurpd_status_file, 0, 0 ); - exit( 1 ); + exit( EXIT_FAILURE ); } /* @@ -85,71 +104,60 @@ main( * Check for any fatal error conditions before we get started */ if ( sanity() < 0 ) { - exit( 1 ); + exit( EXIT_FAILURE ); } /* - * Detach from the controlling terminal, if debug level = 0, - * and if not in one-shot mode. + * Detach from the controlling terminal + * unless the -d flag is given or in one-shot mode. */ -#ifdef LDAP_DEBUG - if (( ldap_debug == 0 ) && !sglob->one_shot_mode ) { -#else /* LDAP_DEBUG */ - if ( !sglob->one_shot_mode ) { -#endif /* LDAP_DEBUG */ - detach(); - } + if ( ! (sglob->no_detach || sglob->one_shot_mode) ) + lutil_detach( 0, 0 ); -#ifdef _THREAD - -#if defined( THREAD_SUNOS4_LWP ) /* - * Need to start a scheduler thread under SunOS 4 + * Start the main file manager thread (in fm.c). */ - start_lwp_scheduler(); -#endif /* THREAD_SUNOS4_LWP */ + if ( ldap_pvt_thread_create( &(sglob->fm_tid), + 0, fm, (void *) NULL ) != 0 ) + { + Debug( LDAP_DEBUG_ANY, "file manager ldap_pvt_thread_create failed\n", + 0, 0, 0 ); + exit( EXIT_FAILURE ); + } /* - * Start threads - one thread for each replica + * wait for fm to finish if in oneshot mode */ - for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) { - start_replica_thread( sglob->replicas[ i ]); + if ( sglob->one_shot_mode ) { + ldap_pvt_thread_join( sglob->fm_tid, (void *) NULL ); } /* - * Start the main file manager thread (in fm.c). + * Start threads - one thread for each replica */ - pthread_attr_init( &attr ); - if ( pthread_create( &(sglob->fm_tid), attr, (void *) fm, (void *) NULL ) - != 0 ) { - Debug( LDAP_DEBUG_ANY, "file manager pthread_create failed\n", - 0, 0, 0 ); - exit( 1 ); - + for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) { + start_replica_thread( sglob->replicas[ i ]); } - pthread_attr_destroy( &attr ); /* * Wait for the fm thread to finish. */ - pthread_join( sglob->fm_tid, (void *) &status ); + if ( !sglob->one_shot_mode ) { + ldap_pvt_thread_join( sglob->fm_tid, (void *) NULL ); + } + /* * Wait for the replica threads to finish. */ for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) { - pthread_join( sglob->replicas[ i ]->ri_tid, (void *) &status ); + ldap_pvt_thread_join( sglob->replicas[ i ]->ri_tid, (void *) NULL ); } - Debug( LDAP_DEBUG_ANY, "slurpd: terminating normally\n", 0, 0, 0 ); - sglob->slurpd_shutdown = 1; - pthread_exit( 0 ); -#else /* !_THREAD */ - /* - * Non-threaded case. - */ - exit( 0 ); + /* destroy the thread package */ + ldap_pvt_thread_destroy(); -#endif /* !_THREAD */ - + Debug( LDAP_DEBUG_ANY, "slurpd: terminated.\n", 0, 0, 0 ); + return 0; +#endif /* !NO_THREADS */ } diff --git a/servers/slurpd/ri.c b/servers/slurpd/ri.c index cc478d1e6a77386007feb94078d5b432e56bfd87..a805060a98f0672683e25c0127854154cd7d09a5 100644 --- a/servers/slurpd/ri.c +++ b/servers/slurpd/ri.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,33 +22,21 @@ */ +#include "portable.h" #include <stdio.h> -#include <signal.h> + +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/signal.h> #include "slurp.h" #include "globals.h" -/* External references */ -#ifdef NEEDPROTOS -extern void write_reject( Ri *, Re *, int, char * ); -extern void do_nothing(); -#else /* NEEDPROTOS */ -extern void write_reject(); -extern void do_nothing(); -#endif /* NEEDPROTOS */ - /* Forward references */ -#ifdef NEEDPROTOS -static int ismine( Ri *, Re * ); -static int isnew( Ri *, Re * ); -void tsleep( time_t ); -#else /* NEEDPROTOS */ -static int ismine(); -static int isnew(); -void tsleep(); -#endif /* NEEDPROTOS */ +static int ismine LDAP_P(( Ri *, Re * )); +static int isnew LDAP_P(( Ri *, Re * )); /* @@ -55,12 +48,11 @@ Ri_process( ) { Rq *rq = sglob->rq; - Re *re, *new_re; - int i; + Re *re = NULL, *new_re = NULL; int rc ; char *errmsg; - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); + (void) SIGNAL( LDAP_SIGUSR1, do_nothing ); (void) SIGNAL( SIGPIPE, SIG_IGN ); if ( ri == NULL ) { Debug( LDAP_DEBUG_ANY, "Error: Ri_process: ri == NULL!\n", 0, 0, 0 ); @@ -74,8 +66,14 @@ Ri_process( rq->rq_lock( rq ); while ( !sglob->slurpd_shutdown && (( re = rq->rq_gethead( rq )) == NULL )) { - /* No work - wait on condition variable */ - pthread_cond_wait( &rq->rq_more, &rq->rq_mutex ); + /* No work */ + if ( sglob->one_shot_mode ) { + /* give up if in one shot mode */ + rq->rq_unlock( rq ); + return 0; + } + /* wait on condition variable */ + ldap_pvt_thread_cond_wait( &rq->rq_more, &rq->rq_mutex ); } /* @@ -99,20 +97,22 @@ Ri_process( rc = do_ldap( ri, re, &errmsg ); switch ( rc ) { case DO_LDAP_ERR_RETRYABLE: - tsleep( RETRY_SLEEP_TIME ); + ldap_pvt_thread_sleep( RETRY_SLEEP_TIME ); Debug( LDAP_DEBUG_ANY, "Retrying operation for DN %s on replica %s:%d\n", re->re_dn, ri->ri_hostname, ri->ri_port ); continue; break; - case DO_LDAP_ERR_FATAL: + case DO_LDAP_ERR_FATAL: { /* Non-retryable error. Write rejection log. */ - write_reject( ri, re, ri->ri_ldp->ld_errno, errmsg ); + int ld_errno = 0; + ldap_get_option(ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno); + write_reject( ri, re, ld_errno, errmsg ); /* Update status ... */ (void) sglob->st->st_update( sglob->st, ri->ri_stel, re ); /* ... and write to disk */ (void) sglob->st->st_write( sglob->st ); - break; + } break; default: /* LDAP op completed ok - update status... */ (void) sglob->st->st_update( sglob->st, ri->ri_stel, re ); @@ -129,10 +129,11 @@ Ri_process( while ( !sglob->slurpd_shutdown && ((new_re = re->re_getnext( re )) == NULL )) { if ( sglob->one_shot_mode ) { + rq->rq_unlock( rq ); return 0; } /* No work - wait on condition variable */ - pthread_cond_wait( &rq->rq_more, &rq->rq_mutex ); + ldap_pvt_thread_cond_wait( &rq->rq_more, &rq->rq_mutex ); } re->re_decrefcnt( re ); re = new_re; @@ -146,7 +147,8 @@ Ri_process( /* - * Wake a replication thread which may be sleeping. Send it a SIGUSR1. + * Wake a replication thread which may be sleeping. + * Send it a LDAP_SIGUSR1. */ static void Ri_wake( @@ -156,8 +158,7 @@ Ri_wake( if ( ri == NULL ) { return; } - pthread_kill( ri->ri_tid, SIGUSR1 ); - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); + ldap_pvt_thread_kill( ri->ri_tid, LDAP_SIGUSR1 ); } @@ -170,7 +171,7 @@ Ri_init( Ri **ri ) { - (*ri) = ( Ri * ) malloc( sizeof( Ri )); + (*ri) = ( Ri * ) calloc( 1, sizeof( Ri )); if ( *ri == NULL ) { return -1; } @@ -181,12 +182,10 @@ Ri_init( /* Initialize private data */ (*ri)->ri_hostname = NULL; - (*ri)->ri_port = 0; (*ri)->ri_ldp = NULL; - (*ri)->ri_bind_method = 0; (*ri)->ri_bind_dn = NULL; (*ri)->ri_password = NULL; - (*ri)->ri_principal = NULL; + (*ri)->ri_authcId = NULL; (*ri)->ri_srvtab = NULL; (*ri)->ri_curr = NULL; @@ -239,12 +238,12 @@ isnew( Re *re ) { - int x; + long x; int ret; /* Lock the St struct to avoid a race */ sglob->st->st_lock( sglob->st ); - x = strcmp( re->re_timestamp, ri->ri_stel->last ); + x = re->re_timestamp - ri->ri_stel->last; if ( x > 0 ) { /* re timestamp is newer */ ret = 1; @@ -262,5 +261,3 @@ isnew( sglob->st->st_unlock( sglob->st ); return ret; } - - diff --git a/tests/data/passwd.ldif b/tests/data/passwd.ldif new file mode 100644 index 0000000000000000000000000000000000000000..221af87ea226c85f33c89e1a69114bd37f9fd184 --- /dev/null +++ b/tests/data/passwd.ldif @@ -0,0 +1,32 @@ +dn: o=University of Michigan,c=US +objectclass: top +objectclass: organization +o: University of Michigan + +dn: cn=md5,o=University of Michigan,c=US +objectclass: top +objectclass: person +cn: md5 +sn: md5 +userpassword:: e01ENX1YcjRpbE96UTRQQ09xM2FRMHFidWFRPT0= + +dn: cn=smd5,o=University of Michigan,c=US +objectclass: top +objectclass: person +cn: smd5 +sn: smd5 +userpassword: secret + +dn: cn=sha,o=University of Michigan,c=US +objectclass: top +objectclass: person +cn: sha +sn: sha +userpassword:: e1NIQX01ZW42RzZNZXpScm9UM1hLcWtkUE9tWS9CZlE9 + +dn: cn=ssha,o=University of Michigan,c=US +objectclass: top +objectclass: person +cn: ssha +sn: ssha +userpassword: secret diff --git a/tests/data/slapd-acl.conf b/tests/data/slapd-acl.conf index 5e56dea19c4f65759ed6425af7d0d5b2bed06481..d04ae6b4d2b64f9ba4e71ad3421a2f0d2f5b4a2a 100644 --- a/tests/data/slapd-acl.conf +++ b/tests/data/slapd-acl.conf @@ -1,36 +1,64 @@ +# $OpenLDAP$ # # master slapd config -- for testing # -include ./data/slapd.at.conf -include ./data/slapd.oc.conf -schemacheck off +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +# global ACLs +access to dn.base="" attr=objectClass by users read +access to * by * read ####################################################################### # ldbm database definitions ####################################################################### -database ldbm -suffix "o=University of Michigan, c=US" +database @BACKEND@ +#ldbm#cachesize 0 +suffix "o=University of Michigan,c=US" directory ./test-db -rootdn "cn=Manager, o=University of Michigan, c=US" +rootdn "cn=Manager,o=University of Michigan,c=US" rootpw secret -index cn,sn,uid pres,eq,approx -index default none -lastmod on -defaultaccess none +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub + +# +# normal installations should protect root dse, +# cn=monitor, cn=schema, and cn=config +# + access to attr=objectclass - by * read -access to attr=userpassword + by * =rsc stop + +access to filter="(objectclass=person)" attr=userpassword + by anonymous auth by self write - by * compare -access to dn=".*,ou=Alumni Association,ou=People,o=University of Michigan,c=US" - by dn=".*,o=University of Michigan,c=US" - read - by * none + +access to dn.children="ou=Alumni Association,ou=People,o=University of Michigan,c=US" + by dn.regex=".+,o=University of Michigan,c=US" +c continue + by dn.subtree="o=University of Michigan,c=US" +rs continue + by * stop + access to attr=member by dnattr=member selfwrite by * read -access to filter="objectclass=rfc822mailgroup" - by dn="Bjorn Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US" write + +access to attr=member filter=(mail=*edu) by * read -access to * by * read + +access to filter="(objectclass=groupofnames)" + by dn.base="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US" =sc continue + by dn="^cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US$" +rw stop + by * break + +access to filter="(name=X*Y*Z)" + by * continue + +# fall into global ACLs diff --git a/tests/data/slapd-dnssrv.conf b/tests/data/slapd-dnssrv.conf new file mode 100644 index 0000000000000000000000000000000000000000..60fef032510c153e57b173f517f540e8c12265f6 --- /dev/null +++ b/tests/data/slapd-dnssrv.conf @@ -0,0 +1,18 @@ +# $OpenLDAP$ +# +# DNS SRV slapd config -- for testing +# +ucdata-path ./ucdata +include ./schema/core.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +sasl-secprops noanonymous +#sasl-secprops none + +####################################################################### +# ldbm database definitions +####################################################################### + +database dnssrv +suffix "" diff --git a/tests/data/slapd-glue.conf b/tests/data/slapd-glue.conf new file mode 100644 index 0000000000000000000000000000000000000000..5bf85b1a8e9c27f8b071c40836a6d5cca19c5506 --- /dev/null +++ b/tests/data/slapd-glue.conf @@ -0,0 +1,60 @@ +# $OpenLDAP$ +# +# stand-alone slapd config -- for backglue testing +# with indexing +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +database @BACKEND@ +suffix "ou=Information Technology Division,ou=People,o=University of Michigan, c=US" +subordinate +directory ./test-db/C_db1 +rootdn "cn=Manager, o=University of Michigan, c=US" +rootpw secret +#ldbm#index objectclass eq +#ldbm#index uid pres,eq,sub +#ldbm#index cn,sn pres,eq,sub,subany +#ldbm#dbnosync +#ldbm#dbnolocking +#bdb#index objectclass eq +#bdb#index uid pres,eq,sub +#bdb#index cn,sn pres,eq,sub,subany + +database @BACKEND@ +suffix "ou=Groups,o=University of Michigan, c=US" +subordinate +directory ./test-db/C_db2 +rootdn "cn=Manager, o=University of Michigan, c=US" +rootpw secret +#ldbm#index objectclass eq +#ldbm#index uid pres,eq,sub +#ldbm#index cn,sn pres,eq,sub,subany +#ldbm#dbnosync +#ldbm#dbnolocking +#bdb#index objectclass eq +#bdb#index uid pres,eq,sub +#bdb#index cn,sn pres,eq,sub,subany + +database @BACKEND@ +suffix "o=University of Michigan, c=US" +directory ./test-db/C_db3 +rootdn "cn=Manager, o=University of Michigan, c=US" +rootpw secret +#ldbm#index objectclass eq +#ldbm#index uid pres,eq,sub +#ldbm#index cn,sn pres,eq,sub,subany +#ldbm#dbnosync +#ldbm#dbnolocking +#bdb#index objectclass eq +#bdb#index uid pres,eq,sub +#bdb#index cn,sn pres,eq,sub,subany diff --git a/tests/data/slapd-master.conf b/tests/data/slapd-master.conf index 2b936ab605f9f3fb83ae7dac84c95e2b39051551..2d4e879bd41640b000ee6baf8cb5b4db38ba20bd 100644 --- a/tests/data/slapd-master.conf +++ b/tests/data/slapd-master.conf @@ -1,19 +1,23 @@ +# $OpenLDAP$ # # master slapd config -- for testing # -include ./data/slapd.at.conf -include ./data/slapd.oc.conf -schemacheck off +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args ####################################################################### # ldbm database definitions ####################################################################### -database ldbm -suffix "o=University of Michigan, c=US" +database @BACKEND@ +suffix "o=University of Michigan,c=US" directory ./test-db -rootdn "cn=Manager, o=University of Michigan, c=US" +rootdn "cn=Manager,o=University of Michigan,c=US" rootpw secret -index cn,sn,uid pres,eq,approx -index default none -lastmod on +#ldbm#index objectClass eq +#bdb#index objectClass eq diff --git a/tests/data/slapd-nis-master.conf b/tests/data/slapd-nis-master.conf new file mode 100644 index 0000000000000000000000000000000000000000..dc56ac87e187cf44cb742b596e11b13590fec932 --- /dev/null +++ b/tests/data/slapd-nis-master.conf @@ -0,0 +1,39 @@ +# $OpenLDAP$ +# +# master slapd config -- for testing +# needs updating +# +ucdata-path ./ucdata +include ./schema/others_nis.at.conf +include ./schema/others_nis.oc.conf +include ./schema/nis.at.conf +include ./schema/nis.oc.conf +include ./schema/internet_mail.at.conf +include ./schema/internet_mail.oc.conf +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +database ldbm +cachesize 4 +suffix "o=SGI, c=US" +directory ./test-db +rootdn "cn=Manager, o=SGI, c=US" +rootpw secret +index objectClass eq +index uid pres,eq,approx +index gidNumber pres,eq,approx +index uidNumber pres,eq,approx +index cn pres,eq,approx +index memberUid pres,eq,approx +index macAddress pres,eq,approx +index ipServiceProtocol pres,eq,approx +index ipServicePort pres,eq,approx +index oncRpcNumber pres,eq,approx +index ipHostNumber pres,eq,approx +index ipNetworkNumber pres,eq,approx +index ipProtocolNumber pres,eq,approx +index default none diff --git a/tests/data/slapd-passwd.conf b/tests/data/slapd-passwd.conf new file mode 100644 index 0000000000000000000000000000000000000000..1238d24649f04a5c3a62a0499bdd3a91f5a9cfb1 --- /dev/null +++ b/tests/data/slapd-passwd.conf @@ -0,0 +1,21 @@ +# $OpenLDAP$ +# +# master slapd config -- for testing +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +database passwd +suffix "o=University of Michigan,c=US" +rootdn "cn=Manager,o=University of Michigan,c=US" +rootpw secret +#file ./data/passwd diff --git a/tests/data/slapd-pw.conf b/tests/data/slapd-pw.conf new file mode 100644 index 0000000000000000000000000000000000000000..a40542e220c35e68798d56c29677c34876cbe321 --- /dev/null +++ b/tests/data/slapd-pw.conf @@ -0,0 +1,39 @@ +# $OpenLDAP$ +# +# master slapd config -- for testing +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +# password-hash {md5} + +####################################################################### +# ldbm database definitions +####################################################################### + +database @BACKEND@ +#ldbm#cachesize 0 +suffix "o=University of Michigan,c=US" +directory ./test-db +rootdn "cn=Manager,o=University of Michigan,c=US" +rootpw secret +index objectClass eq +index cn,sn,uid pres,eq,sub + +# +# normal installations should protect root dse, +# cn=monitor, cn=schema, and cn=config +# + +access to attr=userpassword + by anonymous auth + by self write + +access to * + by self write + by * read diff --git a/tests/data/slapd-ref-slave.conf b/tests/data/slapd-ref-slave.conf new file mode 100644 index 0000000000000000000000000000000000000000..f9335b767bcdd5ebed8e14d53c319874f8eeb70b --- /dev/null +++ b/tests/data/slapd-ref-slave.conf @@ -0,0 +1,29 @@ +# $OpenLDAP$ +# +# slave slapd config -- for default referral testing +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +# +pidfile ./test-repl/slapd.pid +argsfile ./test-repl/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +referral "ldap://localhost:9009/" + +database @BACKEND@ +cachesize 0 +suffix "o=University of Mich,c=US" +directory ./test-repl +rootdn "cn=Manager,o=University of Mich,c=US" +rootpw secret +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub diff --git a/tests/data/slapd-repl-master.conf b/tests/data/slapd-repl-master.conf index bce1d6821cd41854f1c05dc8f748bc6fb218e202..48c1c1b9b30486c4bd428186112af76e828e65f1 100644 --- a/tests/data/slapd-repl-master.conf +++ b/tests/data/slapd-repl-master.conf @@ -1,26 +1,34 @@ +# $OpenLDAP$ # # master slapd config -- for testing of replication # -include ./data/slapd.at.conf -include ./data/slapd.oc.conf -schemacheck off +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +# +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args ####################################################################### # ldbm database definitions ####################################################################### -database ldbm -suffix "o=University of Michigan, c=US" +database @BACKEND@ +#ldbm#cachesize 0 +suffix "o=University of Michigan,c=US" directory ./test-db -rootdn "cn=Manager, o=University of Michigan, c=US" +rootdn "cn=Manager,o=University of Michigan,c=US" rootpw secret -index cn,sn,uid pres,eq,approx -index default none -lastmod on +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub replogfile ./test-db/slapd.replog replica host=localhost:9010 - binddn="cn=Manager, o=University of Michigan, c=US" + binddn="cn=Replica,o=University of Michigan,c=US" bindmethod=simple credentials=secret diff --git a/tests/data/slapd-repl-slave.conf b/tests/data/slapd-repl-slave.conf index ca81b76529d5c2443970cebe24581ea05b68bc90..28ab1289712d2e0270026fd6ebfbea780a293780 100644 --- a/tests/data/slapd-repl-slave.conf +++ b/tests/data/slapd-repl-slave.conf @@ -1,20 +1,31 @@ +# $OpenLDAP$ # -# master slapd config -- for testing of replication +# slave slapd config -- for testing of replication # -include ./data/slapd.at.conf -include ./data/slapd.oc.conf -schemacheck off +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +# +pidfile ./test-repl/slapd.pid +argsfile ./test-repl/slapd.args + +#referral "ldap://localhost:9009/" ####################################################################### # ldbm database definitions ####################################################################### -database ldbm -suffix "o=University of Michigan, c=US" +database @BACKEND@ +#ldbm#cachesize 0 +suffix "o=University of Michigan,c=US" directory ./test-repl -rootdn "cn=Manager, o=University of Michigan, c=US" +rootdn "cn=Replica,o=University of Michigan,c=US" rootpw secret -updatedn "cn=Manager, o=University of Michigan, c=US" -index cn,sn,uid pres,eq,approx -index default none -lastmod on +updatedn "cn=Replica,o=University of Michigan,c=US" +updateref "ldap://localhost:9009" +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub diff --git a/tests/data/slapd-repl-submaster.conf b/tests/data/slapd-repl-submaster.conf new file mode 100644 index 0000000000000000000000000000000000000000..699dedbcc9a0ca4003aa1088660eea9d6a153312 --- /dev/null +++ b/tests/data/slapd-repl-submaster.conf @@ -0,0 +1,35 @@ +# $OpenLDAP$ +# +# master slapd config -- for testing of replication +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +# +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +database @BACKEND@ +#ldbm#cachesize 0 +suffix "o=University of Michigan,c=US" +directory ./test-db +rootdn "cn=Manager,o=University of Michigan,c=US" +rootpw secret +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub + +replogfile ./test-db/slapd.replog + +replica host=localhost:9010 + suffix="ou=Groups,o=University of Michigan,c=US" + binddn="cn=Replica,ou=Groups,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret diff --git a/tests/data/slapd-repl-subslave.conf b/tests/data/slapd-repl-subslave.conf new file mode 100644 index 0000000000000000000000000000000000000000..79b2f80dbab105562cdc1b3b149102da36ee0cb4 --- /dev/null +++ b/tests/data/slapd-repl-subslave.conf @@ -0,0 +1,31 @@ +# $OpenLDAP$ +# +# slave slapd config -- for testing of replication +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +# +pidfile ./test-repl/slapd.pid +argsfile ./test-repl/slapd.args + +#referral "ldap://localhost:9009/" + +####################################################################### +# ldbm database definitions +####################################################################### + +database @BACKEND@ +#ldbm#cachesize 0 +suffix "ou=Groups, o=University of Michigan, c=US" +directory ./test-repl +rootdn "cn=Replica,ou=Groups,o=University of Michigan,c=US" +rootpw secret +updatedn "cn=Replica,ou=Groups,o=University of Michigan,c=US" +updateref "ldap://localhost:9009" +#ldbm#index objectClass eq +#ldbm#index cn,sn,uid pres,eq,sub +#bdb#index objectClass eq +#bdb#index cn,sn,uid pres,eq,sub diff --git a/tests/data/slapd-schema.conf b/tests/data/slapd-schema.conf index fe93d3706663e827abc503458849c822e5aa36a5..fa715ef1c76688d9839f7414cdcab82b68d8f3fb 100644 --- a/tests/data/slapd-schema.conf +++ b/tests/data/slapd-schema.conf @@ -15,7 +15,6 @@ include ./schema/misc.schema include ./schema/nis.schema include ./schema/openldap.schema # -schemacheck on pidfile ./test-db/slapd.pid argsfile ./test-db/slapd.args diff --git a/tests/data/slapd.conf b/tests/data/slapd.conf new file mode 100644 index 0000000000000000000000000000000000000000..ce2f117d57854dbd2318e6309265b7c43b1cc994 --- /dev/null +++ b/tests/data/slapd.conf @@ -0,0 +1,31 @@ +# $OpenLDAP$ +# +# stand-alone slapd config -- for testing +# with indexing +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +pidfile ./test-db/slapd.pid +argsfile ./test-db/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +database @BACKEND@ +suffix "o=University of Michigan, c=US" +directory ./test-db +rootdn "cn=Manager, o=University of Michigan, c=US" +rootpw secret +#ldbm#index objectclass eq +#ldbm#index uid pres,eq,sub +#ldbm#index name pres,eq,sub,subany +#ldbm#dbnosync +#ldbm#dbnolocking +#bdb#index objectclass eq +#bdb#index uid pres,eq,sub +#bdb#index name pres,eq,sub,subany +#bdb#lockdetect default 5 diff --git a/tests/scripts/conf.sh b/tests/scripts/conf.sh new file mode 100755 index 0000000000000000000000000000000000000000..afdaa5c693cfc76ce70f285d2f7840f22d4f829c --- /dev/null +++ b/tests/scripts/conf.sh @@ -0,0 +1,3 @@ +#! /bin/sh +# $OpenLDAP$ +sed -e "s/@BACKEND@/$BACKEND/" -e "s/^#$BACKEND#//" diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 6d8bf2f3914ee96be39d585f33f1b456c70307f4..3c1eeba5303208556c739328f21ea56a4ce1fd80 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -1,33 +1,101 @@ -LDIF2LDBM=../servers/slapd/tools/ldif2ldbm -SLAPD=../servers/slapd/slapd +#! /bin/sh +# $OpenLDAP$ + +DATADIR=$SRCDIR/data +PROGDIR=./progs +DBDIR=./test-db +REPLDIR=./test-repl + +CONF=$DATADIR/slapd.conf +MCONF=$DATADIR/slapd-master.conf +PWCONF=$DATADIR/slapd-pw.conf +ACLCONF=$DATADIR/slapd-acl.conf +MASTERCONF=$DATADIR/slapd-repl-master.conf +SLAVECONF=$DATADIR/slapd-repl-slave.conf +REFSLAVECONF=$DATADIR/slapd-ref-slave.conf +SUBMASTERCONF=$DATADIR/slapd-repl-submaster.conf +SUBSLAVECONF=$DATADIR/slapd-repl-subslave.conf +SCHEMACONF=$DATADIR/slapd-schema.conf +GLUECONF=$DATADIR/slapd-glue.conf + +DBCONF=$DBDIR/slapd.conf +ADDCONF=$DBDIR/slapadd.conf +REPLCONF=$REPLDIR/slapd.conf + +TOOLARGS="-x $LDAP_TOOLARGS" +TOOLPROTO="-P 3" + +PASSWDCONF=$DATADIR/slapd-passwd.conf + +CLIENTDIR=../clients/tools +#CLIENTDIR=/usr/local/bin + +LDIFFILTER=$SRCDIR/scripts/acfilter.sh +SUBFILTER=$SRCDIR/scripts/subfilter.sh +UNDIFFFILTER=$SRCDIR/scripts/undiff.sh +CONFFILTER=$SRCDIR/scripts/conf.sh + +SLAPADD="../servers/slapd/tools/slapadd $LDAP_VERBOSE" +SLAPCAT="../servers/slapd/tools/slapcat $LDAP_VERBOSE" +SLAPINDEX="../servers/slapd/tools/slapindex $LDAP_VERBOSE" + +unset DIFF_OPTIONS +DIFF="diff -iu" +CMP="diff -i" +CMPOUT=/dev/null +SLAPD="../servers/slapd/slapd -s0" SLURPD=../servers/slurpd/slurpd -LDAPSEARCH=../clients/tools/ldapsearch -LDAPMODIFY=../clients/tools/ldapmodify -LDAPADD=../clients/tools/ldapadd +LDAPPASSWD="$CLIENTDIR/ldappasswd $TOOLARGS" +LDAPSEARCH="$CLIENTDIR/ldapsearch $TOOLPROTO $TOOLARGS -LLL" +LDAPMODIFY="$CLIENTDIR/ldapmodify $TOOLPROTO $TOOLARGS" +LDAPADD="$CLIENTDIR/ldapadd $TOOLPROTO $TOOLARGS" +LDAPMODRDN="$CLIENTDIR/ldapmodrdn $TOOLPROTO $TOOLARGS" +LDAPWHOAMI="$CLIENTDIR/ldapwhoami $TOOLARGS" +SLAPDTESTER=$PROGDIR/slapd-tester +LVL=${SLAPD_DEBUG-5} +LOCALHOST=localhost PORT=9009 SLAVEPORT=9010 -DBDIR=./test-db -REPLDIR=./test-repl -CONF=./data/slapd-master.conf -ACLCONF=./data/slapd-acl.conf -MASTERCONF=./data/slapd-repl-master.conf -SLAVECONF=./data/slapd-repl-slave.conf -LDIF=./data/test.ldif -LDIFORDERED=./data/test-ordered.ldif -BASEDN="o=University of Michigan, c=US" -MANAGERDN="cn=Manager, o=University of Michigan, c=US" +MASTERURI="ldap://${LOCALHOST}:$PORT/" +SLAVEURI="ldap://${LOCALHOST}:$SLAVEPORT/" +LDIF=$DATADIR/test.ldif +LDIFGLUED=$DATADIR/test-glued.ldif +LDIFORDERED=$DATADIR/test-ordered.ldif +LDIFBASE=$DATADIR/test-base.ldif +LDIFPASSWD=$DATADIR/passwd.ldif +LDIFPASSWDOUT=$DATADIR/passwd-out.ldif +LDIFLANG=$DATADIR/test-lang.ldif +LDIFLANGOUT=$DATADIR/lang-out.ldif +MONITOR="" +BASEDN="o=University of Michigan,c=US" +MANAGERDN="cn=Manager,o=University of Michigan,c=US" +UPDATEDN="cn=Replica,o=University of Michigan,c=US" PASSWD=secret -BABSDN="cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US" -BJORNSDN="cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US" -JAJDN="cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US" +BABSDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US" +BJORNSDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US" +JAJDN="cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Michigan,c=US" +MASTERLOG=$DBDIR/master.log +SLAVELOG=$DBDIR/slave.log +SLURPLOG=$DBDIR/slurp.log SEARCHOUT=$DBDIR/ldapsearch.out +SEARCHFLT=$DBDIR/ldapsearch.flt +LDIFFLT=$DBDIR/ldif.flt +SUBFLT=$DBDIR/sub.flt +SUBFLT2=$DBDIR/sub2.flt MASTEROUT=$DBDIR/master.out SLAVEOUT=$DBDIR/slave.out -TESTOUT=$DBDIR/ldapsearch.out -SEARCHOUTMASTER=./data/search.out.master -MODIFYOUTMASTER=./data/modify.out.master -ADDDELOUTMASTER=./data/adddel.out.master -MODRDNOUTMASTER=./data/modrdn.out.master -ACLOUTMASTER=./data/acl.out.master -REPLOUTMASTER=./data/repl.out.master -MODSRCHFILTERS=./data/modify.search.filters +SUBMASTEROUT=$DBDIR/submaster.out +TESTOUT=$DBDIR/test.out +INITOUT=$DBDIR/init.out +SEARCHOUTMASTER=$DATADIR/search.out.master +MODIFYOUTMASTER=$DATADIR/modify.out.master +ADDDELOUTMASTER=$DATADIR/adddel.out.master +MODRDNOUTMASTER0=$DATADIR/modrdn.out.master.0 +MODRDNOUTMASTER1=$DATADIR/modrdn.out.master.1 +MODRDNOUTMASTER2=$DATADIR/modrdn.out.master.2 +MODRDNOUTMASTER3=$DATADIR/modrdn.out.master.3 +ACLOUTMASTER=$DATADIR/acl.out.master +REPLOUTMASTER=$DATADIR/repl.out.master +MODSRCHFILTERS=$DATADIR/modify.search.filters +# Just in case we linked the binaries dynamically +LD_LIBRARY_PATH=`pwd`/../libraries:${LD_LIBRARY_PATH} export LD_LIBRARY_PATH diff --git a/tests/scripts/test003-search b/tests/scripts/test003-search index 0912550608cd2c813a09508ce523c102c4c2bfb0..d0173fbac2b50bfad713b6dc8fca6a306fbae510 100755 --- a/tests/scripts/test003-search +++ b/tests/scripts/test003-search @@ -1,84 +1,119 @@ -#!/bin/sh +#! /bin/sh +# $OpenLDAP$ -. scripts/defines.sh +SRCDIR="." +if test $# -ge 1 ; then + SRCDIR=$1; shift +fi +BACKEND=bdb +if test $# -ge 1 ; then + BACKEND=$1; shift +fi +WAIT=0 +if test $# -ge 1 ; then + WAIT=1; shift +fi + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh echo "Cleaning up in $DBDIR..." -rm -f $DBDIR/* +rm -f $DBDIR/[!C]* -echo "Running ldif2ldbm to build slapd database..." -$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools +echo "Running slapadd to build slapd database..." +. $CONFFILTER $BACKEND < $MCONF > $ADDCONF +$SLAPADD -f $ADDCONF -l $LDIFORDERED RC=$? -if [ $RC != 0 ]; then - echo "ldif2ldbm failed!" +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" exit $RC fi +echo "Running slapindex to index slapd database..." +. $CONFFILTER $BACKEND < $CONF > $DBCONF +$SLAPINDEX -f $DBCONF +RC=$? +if test $RC != 0 ; then + echo "warning: slapindex failed ($RC)" + echo " assuming no indexing support" +fi + echo "Starting slapd on TCP/IP port $PORT..." -$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 & +$SLAPD -f $DBCONF -h $MASTERURI -d $LVL $TIMING > $MASTERLOG 2>&1 & PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi echo "Testing slapd searching..." for i in 0 1 2 3 4 5; do - $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - 'cn=Manager' > /dev/null 2>&1 + $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT \ + 'objectclass=*' > /dev/null 2>&1 RC=$? - if [ $RC = 1 ]; then + if test $RC = 1 ; then echo "Waiting 5 seconds for slapd to start..." sleep 5 fi done -if [ $RC != 0 ]; then - echo "ldapsearch failed!" +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" kill -HUP $PID exit $RC fi -cat /dev/null > $TESTOUT +cat /dev/null > $SEARCHOUT echo "Testing exact searching..." -$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - 'sn=jensen' >> $TESTOUT 2>&1 -if [ $RC != 0 ]; then - echo "ldapsearch failed!" +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + 'sn=jensen' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" kill -HUP $PID exit $RC fi echo "Testing OR searching..." -$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - '(|(objectclass=rfc822mailgroup)(sn=jones))' >> $TESTOUT 2>&1 -if [ $RC != 0 ]; then - echo "ldapsearch failed!" +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(|(givenName=XX*YY*Z)(cn=)(undef=*)(objectclass=groupofnames)(sn=jones))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" kill -HUP $PID exit $RC fi echo "Testing AND matching and ends-with searching..." -$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - '(&(objectclass=rfc822mailgroup)(cn=A*))' >> $TESTOUT 2>&1 -if [ $RC != 0 ]; then - echo "ldapsearch failed!" +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(&(objectclass=groupofnames)(cn=A*))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" kill -HUP $PID exit $RC fi echo "Testing NOT searching..." -$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - '(!(objectclass=person))' | grep -v "^modifytimestamp:" \ - >> $TESTOUT 2>&1 -if [ $RC != 0 ]; then - echo "ldapsearch failed!" +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" kill -HUP $PID exit $RC fi kill -HUP $PID -echo "Comparing results" -cmp $TESTOUT $SEARCHOUTMASTER -if [ $? != 0 ]; then +LDIF=$SEARCHOUTMASTER + +echo "Filtering ldapsearch results..." +. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering original ldif used to create database..." +. $LDIFFILTER < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then echo "Comparison failed" exit 1 fi diff --git a/tests/scripts/test014-whoami b/tests/scripts/test014-whoami new file mode 100755 index 0000000000000000000000000000000000000000..705600981b605f01f054de0cbe3952f16e04fcba --- /dev/null +++ b/tests/scripts/test014-whoami @@ -0,0 +1,59 @@ +#! /bin/sh +# $OpenLDAP$ + +SRCDIR="." +if test $# -ge 1 ; then + SRCDIR=$1; shift +fi +BACKEND=bdb +if test $# -ge 1 ; then + BACKEND=$1; shift +fi +WAIT=0 +if test $# -ge 1 ; then + WAIT=1; shift +fi + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +echo "Cleaning up in $DBDIR..." + +rm -f $DBDIR/[!C]* + +echo "Starting slapd on TCP/IP port $PORT..." +. $CONFFILTER $BACKEND < $PWCONF > $DBCONF +$SLAPD -f $DBCONF -h $MASTERURI -d $LVL $TIMING > $MASTERLOG 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi + +echo "Using ldapsearch to check that slapd is running..." +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 1 ; then + echo "Waiting 5 seconds for slapd to start..." + sleep 5 + fi +done + +echo "Testing ldapwhoami ..." +$LDAPWHOAMI -h $LOCALHOST -p $PORT \ + -D "$MANAGERDN" -w $PASSWD + +RC=$? +if test $RC != 0 ; then + echo "ldapwhoami failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +kill -HUP $PID + +echo ">>>>> Test succeeded" + +exit 0 diff --git a/tests/scripts/test015-xsearch b/tests/scripts/test015-xsearch new file mode 100755 index 0000000000000000000000000000000000000000..c5c60b2e6adbaeab5a8d620f6030783f79ff272f --- /dev/null +++ b/tests/scripts/test015-xsearch @@ -0,0 +1,124 @@ +#! /bin/sh +# $OpenLDAP$ + +SRCDIR="." +if test $# -ge 1 ; then + SRCDIR=$1; shift +fi +BACKEND=bdb +if test $# -ge 1 ; then + BACKEND=$1; shift +fi +WAIT=0 +if test $# -ge 1 ; then + WAIT=1; shift +fi + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +echo "Cleaning up in $DBDIR..." + +rm -f $DBDIR/[!C]* + +echo "Running slapadd to build slapd database..." +. $CONFFILTER $BACKEND < $MCONF > $ADDCONF +$SLAPADD -f $ADDCONF -l $LDIFORDERED +RC=$? +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" + exit $RC +fi + +echo "Running slapindex to index slapd database..." +. $CONFFILTER $BACKEND < $CONF > $DBCONF +$SLAPINDEX -f $DBCONF +RC=$? +if test $RC != 0 ; then + echo "warning: slapindex failed ($RC)" + echo " assuming no indexing support" +fi + +echo "Starting slapd on TCP/IP port $PORT..." +$SLAPD -f $DBCONF -h $MASTERURI -d $LVL $TIMING > $MASTERLOG 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi + +echo "Testing slapd searching..." +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 1 ; then + echo "Waiting 5 seconds for slapd to start..." + sleep 5 + fi +done + +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +cat /dev/null > $SEARCHOUT + +echo "Testing exact searching..." +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(sn:=jensen)' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +echo "Testing OR searching..." +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(|(givenName=XX*YY*Z)(cn=)(undef=*)(objectclass=groupofnames)(sn:caseExactMatch:=Jones))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +echo "Testing AND matching and ends-with searching..." +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(&(objectclass=groupofnames)(cn=A*))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +echo "Testing NOT searching..." +$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT \ + '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + kill -HUP $PID + exit $RC +fi + +kill -HUP $PID + +LDIF=$SEARCHOUTMASTER + +echo "Filtering ldapsearch results..." +. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering original ldif used to create database..." +. $LDIFFILTER < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + + +exit 0