From 73276e84ae32e9e148197971d1d6729739980353 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Fri, 16 Jul 1999 02:45:46 +0000 Subject: [PATCH] Import experimental referral implementation from OPENLDAP_DEVEL_REFERRALS. Includes support for update referral for each replicated backend. Reworked replication test to use update referral. Includes major rewrite of response encoding codes (result.c). Includes reworked alias support and eliminates old suffix alias codes (can be emulated using named alias). Includes (untested) support for the Manage DSA IT control. Works in LDAPv2 world. Still testing in LDAPv3 world. Added default referral (test009) test. --- build/main.dsw | 39 ++ clients/tools/ldapdelete.c | 34 +- clients/tools/ldapmodify.c | 35 +- clients/tools/ldapmodrdn.c | 34 +- clients/tools/ldapsearch.c | 39 +- doc/man/man1/ldapdelete.1 | 7 + doc/man/man1/ldapmodify.1 | 7 + doc/man/man1/ldapmodrdn.1 | 7 + doc/man/man1/ldapsearch.1 | 7 + doc/man/man5/slapd.conf.5 | 7 + include/ldap.h | 2 + libraries/libldbm/libldbm.dsp | 4 +- servers/slapd/Makefile.in | 4 +- servers/slapd/abandon.c | 26 +- servers/slapd/aclparse.c | 1 + servers/slapd/add.c | 18 +- servers/slapd/back-bdb2/add.c | 108 +++- servers/slapd/back-bdb2/alias.c | 563 +++++++++--------- servers/slapd/back-bdb2/bind.c | 101 +++- servers/slapd/back-bdb2/compare.c | 58 +- servers/slapd/back-bdb2/delete.c | 72 ++- servers/slapd/back-bdb2/dn2id.c | 24 +- servers/slapd/back-bdb2/group.c | 147 +++-- servers/slapd/back-bdb2/modify.c | 74 ++- servers/slapd/back-bdb2/modrdn.c | 94 ++- servers/slapd/back-bdb2/proto-back-bdb2.h | 31 +- servers/slapd/back-bdb2/search.c | 674 ++++++++++------------ servers/slapd/back-ldap/bind.c | 6 +- servers/slapd/back-ldap/search.c | 5 +- servers/slapd/back-ldbm/add.c | 108 +++- servers/slapd/back-ldbm/alias.c | 570 +++++++++--------- servers/slapd/back-ldbm/bind.c | 98 +++- servers/slapd/back-ldbm/compare.c | 55 +- servers/slapd/back-ldbm/delete.c | 81 ++- servers/slapd/back-ldbm/dn2id.c | 26 +- servers/slapd/back-ldbm/group.c | 152 +++-- servers/slapd/back-ldbm/modify.c | 65 ++- servers/slapd/back-ldbm/modrdn.c | 124 ++-- servers/slapd/back-ldbm/proto-back-ldbm.h | 24 +- servers/slapd/back-ldbm/search.c | 665 ++++++++++----------- servers/slapd/back-passwd/search.c | 109 ++-- servers/slapd/back-perl/add.c | 6 +- servers/slapd/back-perl/compare.c | 6 +- servers/slapd/back-perl/delete.c | 6 +- servers/slapd/back-perl/modify.c | 6 +- servers/slapd/back-perl/modrdn.c | 6 +- servers/slapd/back-perl/search.c | 15 +- servers/slapd/back-perl/unbind.c | 2 - servers/slapd/back-shell/add.c | 4 +- servers/slapd/back-shell/bind.c | 4 +- servers/slapd/back-shell/compare.c | 4 +- servers/slapd/back-shell/delete.c | 4 +- servers/slapd/back-shell/modify.c | 4 +- servers/slapd/back-shell/modrdn.c | 4 +- servers/slapd/back-shell/result.c | 4 +- servers/slapd/back-shell/search.c | 4 +- servers/slapd/back-shell/unbind.c | 4 +- servers/slapd/back-tcl/tcl_add.c | 6 +- servers/slapd/back-tcl/tcl_bind.c | 6 +- servers/slapd/back-tcl/tcl_compare.c | 6 +- servers/slapd/back-tcl/tcl_delete.c | 6 +- servers/slapd/back-tcl/tcl_modify.c | 6 +- servers/slapd/back-tcl/tcl_modrdn.c | 6 +- servers/slapd/back-tcl/tcl_search.c | 6 +- servers/slapd/back-tcl/tcl_unbind.c | 4 +- servers/slapd/back-tcl/tcl_util.c | 8 +- servers/slapd/backend.c | 20 - servers/slapd/bind.c | 30 +- servers/slapd/charray.c | 29 + servers/slapd/compare.c | 15 +- servers/slapd/config.c | 93 ++- servers/slapd/configinfo.c | 13 +- servers/slapd/controls.c | 23 +- servers/slapd/delete.c | 19 +- servers/slapd/extended.c | 6 +- servers/slapd/init.c | 4 +- servers/slapd/libslapd.dsp | 4 - servers/slapd/modify.c | 23 +- servers/slapd/modrdn.c | 26 +- servers/slapd/monitor.c | 38 +- servers/slapd/proto-slap.h | 58 +- servers/slapd/result.c | 599 ++++++++++++++----- servers/slapd/root_dse.c | 9 +- servers/slapd/schema.c | 38 +- servers/slapd/schema/core.schema | 11 + servers/slapd/search.c | 55 +- servers/slapd/slap.h | 14 +- servers/slapd/slapd.at.conf | 1 + servers/slapd/slapd.dsp | 8 +- servers/slapd/slapd.dsw | 15 + servers/slapd/slapd.oc.conf | 5 + servers/slapd/suffixalias.c | 67 --- servers/slapd/tools/Makefile.in | 2 +- servers/slapd/tools/ldbmcat.dsp | 6 +- servers/slapd/tools/ldbmtest.c | 4 + servers/slapd/tools/ldbmtest.dsp | 14 +- servers/slapd/tools/mimic.c | 44 +- tests/data/referrals.ldif | 50 ++ tests/data/slapd-acl.conf | 5 + tests/data/slapd-bdb2-ref-slave.conf | 28 + tests/data/slapd-bdb2-repl-master.conf | 2 +- tests/data/slapd-bdb2-repl-slave.conf | 7 +- tests/data/slapd-ref-slave.conf | 25 + tests/data/slapd-repl-master.conf | 2 +- tests/data/slapd-repl-slave.conf | 7 +- tests/data/slapd.at.conf | 1 + tests/data/slapd.oc.conf | 5 + tests/scripts/defines.sh | 4 + tests/scripts/test002-populate | 4 +- tests/scripts/test003-search | 4 +- tests/scripts/test004-modify | 4 +- tests/scripts/test005-modrdn | 4 +- tests/scripts/test006-acls | 4 +- tests/scripts/test007-replication | 18 +- tests/scripts/test008-concurrency | 12 +- tests/scripts/test009-referral | 126 ++++ 116 files changed, 3663 insertions(+), 2384 deletions(-) delete mode 100644 servers/slapd/suffixalias.c create mode 100644 tests/data/referrals.ldif create mode 100644 tests/data/slapd-bdb2-ref-slave.conf create mode 100644 tests/data/slapd-ref-slave.conf create mode 100755 tests/scripts/test009-referral diff --git a/build/main.dsw b/build/main.dsw index 7ba7d7be6b..e728552c96 100644 --- a/build/main.dsw +++ b/build/main.dsw @@ -272,6 +272,21 @@ Package=<4> Begin Project Dependency Project_Dep_Name libldbm End Project Dependency + Begin Project Dependency + Project_Dep_Name backldbm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + 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 liblutil + End Project Dependency }}} ############################################################################### @@ -284,6 +299,30 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name backldbm + 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 liblutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libslapd + End Project Dependency + Begin Project Dependency + Project_Dep_Name libavl + End Project Dependency + Begin Project Dependency + Project_Dep_Name libldif + End Project Dependency }}} ############################################################################### diff --git a/clients/tools/ldapdelete.c b/clients/tools/ldapdelete.c index 72d550df2f..ddd80e399b 100644 --- a/clients/tools/ldapdelete.c +++ b/clients/tools/ldapdelete.c @@ -29,17 +29,17 @@ static int dodelete LDAP_P(( int main( int argc, char **argv ) { - char *usage = "usage: %s [-n] [-v] [-k] [-W] [-d debug-level] [-f file] [-h ldaphost] [-P version] [-p ldapport] [-D binddn] [-w passwd] [dn]...\n"; + char *usage = "usage: %s [-n] [-v] [-k] [-W] [-M[M]] [-d debug-level] [-f file] [-h ldaphost] [-P version] [-p ldapport] [-D binddn] [-w passwd] [dn]...\n"; char buf[ 4096 ]; FILE *fp; - int i, rc, authmethod, want_bindpw, version, debug; + int i, rc, authmethod, want_bindpw, version, debug, manageDSAit; - not = verbose = contoper = want_bindpw = debug = 0; + not = verbose = contoper = want_bindpw = debug = manageDSAit = 0; fp = NULL; authmethod = LDAP_AUTH_SIMPLE; version = -1; - while (( i = getopt( argc, argv, "WnvkKch:P:p:D:w:d:f:" )) != EOF ) { + while (( i = getopt( argc, argv, "WMnvkKch:P:p:D:w:d:f:" )) != EOF ) { switch( i ) { case 'k': /* kerberos bind */ #ifdef HAVE_KERBEROS @@ -96,6 +96,10 @@ main( int argc, char **argv ) case 'v': /* verbose mode */ verbose++; break; + case 'M': + /* enable Manage DSA IT */ + manageDSAit++; + break; case 'W': want_bindpw++; break; @@ -164,6 +168,28 @@ main( int argc, char **argv ) return( EXIT_FAILURE ); } + 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 Manage DSA IT Control\n" ); + if( c.ldctl_iscritical ) { + exit( EXIT_FAILURE ); + } + } + } + if ( fp == NULL ) { for ( ; optind < argc; ++optind ) { rc = dodelete( ld, argv[ optind ] ); diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c index dc150e31f0..36edc0d29f 100644 --- a/clients/tools/ldapmodify.c +++ b/clients/tools/ldapmodify.c @@ -72,12 +72,13 @@ usage( const char *prog ) { fprintf( stderr, "Add or modify entries from an LDAP server\n\n" - "usage: %s [-abcknrvF] [-d debug-level] [-P version] [-h ldaphost]\n" + "usage: %s [-abcknrvF] [-M[M]] [-d debug-level] [-P version] [-h ldaphost]\n" " [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile ]\n" " a - add values (default%s)\n" " b - read values from files (for binary attributes)\n" " c - continuous operation\n" " D - bind DN\n" + " M - enable Manage DSA IT control (-MM for critical)\n" " d - debug level\n" " f - read from file\n" " F - force all changes records to be used\n" @@ -97,7 +98,7 @@ main( int argc, char **argv ) { char *infile, *rbuf, *start, *p, *q; FILE *fp; - int rc, i, use_ldif, authmethod, version, want_bindpw, debug; + int rc, i, use_ldif, authmethod, version, want_bindpw, debug, manageDSAit; if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) { prog = argv[ 0 ]; @@ -112,11 +113,11 @@ main( int argc, char **argv ) new = ( strcmp( prog, "ldapadd" ) == 0 ); infile = NULL; - not = verbose = valsfromfiles = want_bindpw = debug = 0; + not = verbose = valsfromfiles = want_bindpw = debug = manageDSAit = 0; authmethod = LDAP_AUTH_SIMPLE; version = -1; - while (( i = getopt( argc, argv, "WFabckKnrtvh:p:D:w:d:f:P:" )) != EOF ) { + while (( i = getopt( argc, argv, "WFMabckKnrtvh:p:D:w:d:f:P:" )) != EOF ) { switch( i ) { case 'a': /* add */ new = 1; @@ -182,6 +183,10 @@ main( int argc, char **argv ) case 'v': /* verbose mode */ verbose++; break; + case 'M': + /* enable Manage DSA IT */ + manageDSAit++; + break; case 'W': want_bindpw++; break; @@ -259,6 +264,28 @@ main( int argc, char **argv ) rc = 0; + if ( manageDSAit ) { + int err; + LDAPControl c; + LDAPControl *ctrls[2]; + ctrls[0] = &c; + ctrls[1] = NULL; + + c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; + c.ldctl_value.bv_val = NULL; + c.ldctl_value.bv_len = 0; + c.ldctl_iscritical = manageDSAit > 1; + + err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &ctrls ); + + if( err != LDAP_OPT_SUCCESS ) { + fprintf( stderr, "Could not set Manage DSA IT Control\n" ); + if( c.ldctl_iscritical ) { + exit( EXIT_FAILURE ); + } + } + } + while (( rc == 0 || contoper ) && ( rbuf = read_one_record( fp )) != NULL ) { /* diff --git a/clients/tools/ldapmodrdn.c b/clients/tools/ldapmodrdn.c index a3571863ad..d7c98d3854 100644 --- a/clients/tools/ldapmodrdn.c +++ b/clients/tools/ldapmodrdn.c @@ -44,20 +44,20 @@ static int domodrdn LDAP_P(( int main(int argc, char **argv) { - char *usage = "usage: %s [-nvkWc] [-d debug-level] [-h ldaphost] [-P version] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile | dn newrdn ] [-s newSuperior]\n"; + char *usage = "usage: %s [-nvkWc] [-M[M]] [-d debug-level] [-h ldaphost] [-P version] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile | dn newrdn ] [-s newSuperior]\n"; char *myname,*infile, *entrydn, *rdn, buf[ 4096 ]; FILE *fp; - int rc, i, remove, havedn, authmethod, version, want_bindpw, debug; + int rc, i, remove, havedn, authmethod, version, want_bindpw, debug, manageDSAit; char *newSuperior=NULL; infile = NULL; - not = contoper = verbose = remove = want_bindpw = debug = 0; + not = contoper = verbose = remove = want_bindpw = debug = manageDSAit = 0; authmethod = LDAP_AUTH_SIMPLE; version = -1; myname = (myname = strrchr(argv[0], '/')) == NULL ? argv[0] : ++myname; - while (( i = getopt( argc, argv, "WkKcnvrh:P:p:D:w:d:f:s:" )) != EOF ) { + while (( i = getopt( argc, argv, "WkKMcnvrh:P:p:D:w:d:f:s:" )) != EOF ) { switch( i ) { case 'k': /* kerberos bind */ #ifdef HAVE_KERBEROS @@ -116,6 +116,10 @@ main(int argc, char **argv) case 'r': /* remove old RDN */ remove++; break; + case 'M': + /* enable Manage DSA IT */ + manageDSAit++; + break; case 'W': want_bindpw++; break; @@ -217,6 +221,28 @@ main(int argc, char **argv) return( EXIT_FAILURE ); } + 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 Manage DSA IT Control\n" ); + if( c.ldctl_iscritical ) { + exit( EXIT_FAILURE ); + } + } + } + rc = 0; if (havedn) rc = domodrdn(ld, entrydn, rdn, remove, newSuperior); diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index 54e4b24429..be840ee596 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -22,7 +22,9 @@ usage( 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, "\t\t* -- all user attributes\n" ); + fprintf( stderr, "\t\tempty list -- all non-operational attributes\n" ); + fprintf( stderr, "\t\t1.1 -- no attributes\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" ); @@ -31,9 +33,8 @@ usage( char *s ) 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_API_FEATURE_X_OPENLDAP_V2_REFERRALS + fprintf( stderr, " -M\t\tenable Manage DSA IT control (-MM implies critical)\n" ); fprintf( stderr, " -R\t\tdo not automatically follow referrals\n" ); -#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_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" ); @@ -89,21 +90,21 @@ main( int argc, char **argv ) { char *infile, *filtpattern, **attrs, line[ BUFSIZ ]; FILE *fp; - int rc, i, first, scope, deref, attrsonly; + int rc, i, first, scope, deref, attrsonly, manageDSAit; int referrals, timelimit, sizelimit, debug; int authmethod, version, want_bindpw; LDAP *ld; infile = NULL; debug = verbose = allow_binary = not = vals2tmp = - attrsonly = ldif = want_bindpw = 0; + attrsonly = manageDSAit = ldif = want_bindpw = 0; deref = referrals = sizelimit = timelimit = version = -1; scope = LDAP_SCOPE_SUBTREE; authmethod = LDAP_AUTH_SIMPLE; - while (( i = getopt( argc, argv, "WKknuvtRABLD:s:f:h:b:d:P:p:F:a:w:l:z:S:")) != EOF ) { + while (( i = getopt( argc, argv, "WKknuvtMRABLD:s:f:h:b:d:P:p:F:a:w:l:z:S:")) != EOF ) { switch( i ) { case 'n': /* do Not do any searches */ ++not; @@ -134,6 +135,10 @@ main( int argc, char **argv ) case 't': /* write attribute values to /tmp files */ ++vals2tmp; break; + case 'M': + /* enable Manage DSA IT */ + manageDSAit++; + break; case 'R': /* don't automatically chase referrals */ referrals = (int) LDAP_OPT_OFF; break; @@ -339,6 +344,28 @@ main( int argc, char **argv ) fprintf( stderr, "\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 Manage DSA IT Control\n" ); + if( c.ldctl_iscritical ) { + exit( EXIT_FAILURE ); + } + } + } + if ( infile == NULL ) { rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern, "" ); } else { diff --git a/doc/man/man1/ldapdelete.1 b/doc/man/man1/ldapdelete.1 index 859623b1d8..492de10202 100644 --- a/doc/man/man1/ldapdelete.1 +++ b/doc/man/man1/ldapdelete.1 @@ -14,6 +14,8 @@ ldapdelete \- ldap delete entry tool [\c .BR \-c ] [\c +.BR \-M[M] ] +[\c .BI \-d \ debuglevel\fR] [\c .BI \-f \ file\fR] @@ -71,6 +73,11 @@ Continuous operation mode. Errors are reported, but will continue with deletions. The default is to exit after reporting an error. .TP +.B \-M[M] +Enable manage DSA IT control. +.B \-MM +makes control critical. +.TP .BI \-d \ debuglevel Set the LDAP debugging level to \fIdebuglevel\fP. .B ldapdelete diff --git a/doc/man/man1/ldapmodify.1 b/doc/man/man1/ldapmodify.1 index 2b7e4b84b3..8da1462d44 100644 --- a/doc/man/man1/ldapmodify.1 +++ b/doc/man/man1/ldapmodify.1 @@ -18,6 +18,8 @@ ldapmodify, ldapadd \- ldap modify entry and ldap add entry tools [\c .BR \-k ] [\c +.BR \-M[M] ] +[\c .BI \-d \ debuglevel\fR] [\c .BI \-D \ binddn\fR] @@ -124,6 +126,11 @@ lines that begin with (by default, replica: lines are compared against the LDAP server host and port in use to decide if a replog record should actually be applied). .TP +.B \-M[M] +Enable manage DSA IT control. +.B \-MM +makes control critical. +.TP .BI \-d \ debuglevel Set the LDAP debugging level to \fIdebuglevel\fP. .B ldapmodify diff --git a/doc/man/man1/ldapmodrdn.1 b/doc/man/man1/ldapmodrdn.1 index 43caf29114..1d9dd12e21 100644 --- a/doc/man/man1/ldapmodrdn.1 +++ b/doc/man/man1/ldapmodrdn.1 @@ -16,6 +16,8 @@ ldapmodrdn \- ldap modify entry RDN tool [\c .BR \-c ] [\c +.BR \-M[M] ] +[\c .BI \-d \ debuglevel\fR] [\c .BI \-D \ binddn\fR] @@ -74,6 +76,11 @@ Continuous operation mode. Errors are reported, but ldapmodify will continue with modifications. The default is to exit after reporting an error. .TP +.B \-M[M] +Enable manage DSA IT control. +.B \-MM +makes control critical. +.TP .B \-d debuglevel Set the LDAP debugging level to \fIdebuglevel\fP. .B ldapmodrdn diff --git a/doc/man/man1/ldapsearch.1 b/doc/man/man1/ldapsearch.1 index 38e4db98e2..96b38ea6f9 100644 --- a/doc/man/man1/ldapsearch.1 +++ b/doc/man/man1/ldapsearch.1 @@ -22,6 +22,8 @@ ldapsearch \- ldap search tool [\c .BR \-L ] [\c +.BR \-M[M] ] +[\c .BR \-R ] [\c .BI \-d \ debuglevel\fR] @@ -114,6 +116,11 @@ Display search results in format. This option also turns on the -B option, and causes the -F option to be ignored. .TP +.B \-M[M] +Enable manage DSA IT control. +.B \-MM +makes control critical. +.TP .B \-R Do not automatically follow referrals returned while searching. .B ldapsearch diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index 7bca55ba17..a075970637 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -198,6 +198,7 @@ used in conjunction with the schemacheck option. 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 schemacheck { on | off } Turn schema checking on or off. The default is on. @@ -284,6 +285,12 @@ 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). +.TP +.B updateref +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 database. That is, they must follow a "database ldbm" line and come before any subsequent diff --git a/include/ldap.h b/include/ldap.h index 1cadf3ba38..397e63db5d 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -167,6 +167,8 @@ typedef struct ldapcontrol { #define LDAP_CHASE_SUBORDINATE_REFERRALS 0x0020 #define LDAP_CHASE_EXTERNAL_REFERRALS 0x0040 +#define LDAP_CONTROL_MANAGEDSAIT "2.16.16.840.1.113730.3.4.2" + /* LDAP Unsolicited Notifications */ #define LDAP_NOTICE_DISCONNECT "1.3.6.1.4.1.1466.20036" diff --git a/libraries/libldbm/libldbm.dsp b/libraries/libldbm/libldbm.dsp index ec1fd56843..60e8320349 100644 --- a/libraries/libldbm/libldbm.dsp +++ b/libraries/libldbm/libldbm.dsp @@ -90,7 +90,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo /out:"..\Debug\oldbm32.lib" -# ADD LIB32 /nologo /out:"..\Debug\oldbm32.lib" +# ADD LIB32 /nologo /out:"..\SDebug\oldbm32.lib" !ELSEIF "$(CFG)" == "libldbm - Win32 Single Release" @@ -111,7 +111,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo /out:"..\Release\oldbm32.lib" -# ADD LIB32 /nologo /out:"..\Release\oldbm32.lib" +# ADD LIB32 /nologo /out:"..\SRelease\oldbm32.lib" !ENDIF diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index c3bd8a51c0..2e0aa85782 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -10,7 +10,7 @@ SRCS = main.c daemon.c connection.c search.c filter.c add.c charray.c \ value.c ava.c bind.c unbind.c abandon.c filterentry.c \ phonetic.c acl.c str2filter.c aclparse.c init.c user.c \ repl.c lock.c controls.c extended.c \ - suffixalias.c schema.c schemaparse.c monitor.c configinfo.c \ + schema.c schemaparse.c monitor.c configinfo.c \ root_dse.c module.c OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \ attr.o entry.o config.o backend.o result.o operation.o \ @@ -18,7 +18,7 @@ OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \ value.o ava.o bind.o unbind.o abandon.o filterentry.o \ phonetic.o acl.o str2filter.o aclparse.o init.o user.o \ repl.o lock.o controls.o extended.o \ - suffixalias.o schema.o schemaparse.o monitor.o configinfo.o \ + schema.o schemaparse.o monitor.o configinfo.o \ root_dse.o module.o LDAP_INCDIR= ../../include diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index bac282e2b3..3069ed7452 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -28,7 +28,7 @@ do_abandon( ber_int_t id; Operation *o; Operation **oo; - int rc; + int rc, notfound; Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 ); @@ -52,21 +52,28 @@ do_abandon( Debug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 ); + if( id <= 0 ) { + Debug( LDAP_DEBUG_ANY, + "do_abandon: bad msgid %ld\n", (long) id, 0, 0 ); + return LDAP_SUCCESS; + } + + notfound = 1; /* not found */ + 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. */ - ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - for ( o = conn->c_ops; o != NULL; o = o->o_next ) { if ( o->o_msgid == id ) { ldap_pvt_thread_mutex_lock( &o->o_abandonmutex ); o->o_abandon = 1; ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex ); - goto found_it; + notfound = 0; + goto done; } } @@ -81,13 +88,14 @@ do_abandon( o = *oo; *oo = (*oo)->o_next; slap_op_free( o ); - - goto found_it; + notfound = 0; } - Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0, 0 ); - -found_it: +done: ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + + Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n", + id, notfound ? "not " : "", 0 ); + return LDAP_SUCCESS; } diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index e32e5ee675..3c69482fce 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -330,6 +330,7 @@ access2str( int access ) strcat( buf, "read" ); } else if ( ACL_IS_WRITE(access) ) { strcat( buf, "write" ); + } else { strcat( buf, "unknown" ); } diff --git a/servers/slapd/add.c b/servers/slapd/add.c index e2438a5d3b..cfff625602 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -38,7 +38,7 @@ do_add( Connection *conn, Operation *op ) if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_add: SASL bind in progress.\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -89,8 +89,8 @@ do_add( Connection *conn, Operation *op ) 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, "no values for type" ); + send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, + NULL, "no values for type", NULL, NULL ); free( type ); entry_free( e ); return LDAP_PROTOCOL_ERROR; @@ -127,8 +127,8 @@ do_add( Connection *conn, Operation *op ) be = select_backend( e->e_ndn ); if ( be == NULL ) { entry_free( e ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, LDAP_REFERRAL, NULL, + NULL, default_referral, NULL ); return rc; } @@ -155,14 +155,14 @@ do_add( Connection *conn, Operation *op ) } else { entry_free( e ); - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + be->be_update_refs ? be->be_update_refs : default_referral, NULL ); } } else { Debug( LDAP_DEBUG_ARGS, " do_add: HHH\n", 0, 0, 0 ); entry_free( e ); - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } return rc; diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c index 1f51d43d52..5c72225f76 100644 --- a/servers/slapd/back-bdb2/add.c +++ b/servers/slapd/back-bdb2/add.c @@ -32,7 +32,8 @@ bdb2i_back_add_internal( if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) { entry_free( e ); - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" ); + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -41,8 +42,8 @@ bdb2i_back_add_internal( 0, 0, 0 ); entry_free( e ); - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "", - "" ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -55,19 +56,37 @@ bdb2i_back_add_internal( pdn = dn_parent( be, e->e_ndn ); if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) { - char *matched = NULL; + Entry *matched = NULL; assert( *pdn != '\0' ); /* get parent with writer lock */ if ( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) { - Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, - 0, 0 ); + char *matched_dn; + struct berval **refs; + + if( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + + bdb2i_cache_return_entry_w( &li->li_cache, matched ); + + } else { + matched_dn = NULL; + refs = default_referral; + } + + Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, - matched, "" ); + matched_dn, NULL, NULL, NULL ); if ( matched != NULL ) { - free( matched ); + ber_bvecfree( refs ); + free( matched_dn ); } entry_free( e ); @@ -77,21 +96,54 @@ bdb2i_back_add_internal( free(pdn); - if ( matched != NULL ) { - free( matched ); - } - if ( ! access_allowed( be, conn, op, p, "children", NULL, ACL_WRITE ) ) { + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); + + entry_free( e ); + return -1; + } + + + if ( is_entry_alias( p ) ) { + /* parent is an alias, don't allow add */ + + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + + Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, NULL, NULL, NULL ); + + entry_free( e ); + return -1; + } + + if ( is_entry_referral( p ) ) { + /* parent is an referral, don't allow add */ + char *matched_dn = ch_strdup( matched->e_dn ); + struct berval **refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; /* free parent and writer lock */ bdb2i_cache_return_entry_w( &li->li_cache, p ); + Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + free( matched_dn ); entry_free( e ); return -1; } @@ -109,7 +161,7 @@ bdb2i_back_add_internal( 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); entry_free( e ); return -1; @@ -142,11 +194,9 @@ bdb2i_back_add_internal( /* free the entry */ entry_free( e ); - if(rc > 0) { - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" ); - } else { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); - } + send_ldap_result( conn, op, + rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -162,7 +212,8 @@ bdb2i_back_add_internal( if ( bdb2i_id2children_add( be, p, e ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op ); @@ -182,7 +233,8 @@ bdb2i_back_add_internal( if ( bdb2i_index_add_entry( be, e ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op ); @@ -197,7 +249,8 @@ bdb2i_back_add_internal( if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op ); @@ -213,7 +266,8 @@ bdb2i_back_add_internal( Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0, 0, 0 ); (void) bdb2i_dn2id_delete( be, e->e_ndn ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op ); @@ -222,7 +276,8 @@ bdb2i_back_add_internal( bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op ); - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; return_results:; @@ -255,10 +310,9 @@ bdb2_back_add( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_w( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); - } /* check, if a new default attribute index will be created, diff --git a/servers/slapd/back-bdb2/alias.c b/servers/slapd/back-bdb2/alias.c index beb1fb9dc6..89834748fd 100644 --- a/servers/slapd/back-bdb2/alias.c +++ b/servers/slapd/back-bdb2/alias.c @@ -1,13 +1,6 @@ /* - * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC - * 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 ITSD, Government of BC. The name of ITSD - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ #include "portable.h" @@ -19,303 +12,273 @@ #include "back-bdb2.h" #include "proto-back-bdb2.h" -/* - * given an alias object, dereference it to its end point. - * Entry returned has reader lock or is NULL. Starting entry is not released. - */ -Entry *bdb2i_derefAlias_r ( BackendDB *be, - Connection *conn, - Operation *op, - Entry *e) +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ); + +static char* new_superior( + char *dn, + char *oldSup, + char *newSup ); + +static int dnlist_subordinate( + char** dnlist, + char *dn ); + +Entry *bdb2i_deref_r( + Backend* be, + Entry* alias, + char* dn, + int* err, + Entry** matched, + char** text ) { - /* to free cache entries */ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Attribute *a; - int depth; - char *matched; - Entry *origDN = e; - - if (!e) return NULL; /* be sure we have a starting entry */ - - Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 ); - - /* - * try to deref fully, up to a maximum depth. If the max depth exceeded - * then send an error - */ - for ( depth = 0; - ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) && - ( depth < be->be_maxDerefDepth ); - ++depth) - { - - /* - * make sure there is a defined aliasedobjectname. - * can only have one value so just use first value (0) in the attr list. - */ - if (a->a_vals[0] && a->a_vals[0]->bv_val) { - char *newDN, *oldDN; - - Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", - e->e_dn, a->a_vals[0]->bv_val, 0 ); - newDN = ch_strdup (a->a_vals[0]->bv_val); - oldDN = ch_strdup (e->e_ndn); - - /* - * release past lock if not original - */ - if ( (depth > 0) && e ) { - bdb2i_cache_return_entry_r(&li->li_cache, e); - } - - /* make sure new and old DN are not same to avoid loops */ - dn_normalize_case (newDN); - if ( strcmp (newDN, oldDN) == 0 ) { - - Debug( LDAP_DEBUG_TRACE, - "<= %s alias is same as current %s\n", - oldDN, newDN, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Circular alias" ); - free (newDN); - free (oldDN); - break; - } - - /* make sure new and original are not same to avoid deadlocks */ - if ( strcmp (newDN, origDN->e_ndn) == 0 ) { - Debug( LDAP_DEBUG_TRACE, - "<= %s alias is same as original %s\n", - oldDN, origDN->e_ndn, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Circular alias" ); - free (newDN); - free (oldDN); - break; - } - - /* - * ok, so what happens if there is an alias in the DN of a dereferenced - * alias object? - */ - if ( (e = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL ) { - - /* could not deref return error */ - Debug( LDAP_DEBUG_TRACE, - "<= %s is a dangling alias to %s\n", - oldDN, newDN, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Dangling Alias" ); - - if(matched != NULL) free(matched); - free (newDN); - free (oldDN); - break; - } - - free (newDN); - free (oldDN); - } - else { - /* - * there was an aliasedobjectname defined but no data. - * this can't happen, right? - */ - Debug( LDAP_DEBUG_TRACE, - "<= %s has no data in aliasedobjectname attribute\n", - (e && e->e_dn) ? e->e_dn : "(null)", 0, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "", - "Alias missing aliasedobjectname" ); - break; - } - } - - /* - * warn if we pulled out due to exceeding the maximum deref depth - */ - if ( depth >= be->be_maxDerefDepth ) { - Debug( LDAP_DEBUG_TRACE, - "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n", - origDN->e_dn ? origDN->e_dn : "(null)", - be->be_maxDerefDepth, - (e && e->e_ndn) ? e->e_ndn : "(null)"); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Maximum alias dereference depth exceeded" ); - } - - return e; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + char **dnlist; + + assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) ); + + *matched = NULL; + *err = LDAP_SUCCESS; + *text = NULL; + + if( alias == NULL ) { + dn = ch_strdup( dn ); + entry = bdb2i_dn2entry_r( be, dn, &sup ); + + } else { + dn = ch_strdup( alias->e_ndn ); + entry = alias; + sup = NULL; + } + + dnlist = NULL; + charray_add( &dnlist, dn ); + + for( depth=0 ; ; depth++ ) { + if( entry != NULL ) { + Entry *newe; + char *aliasDN; + + /* have entry, may be an alias */ + + if( !is_entry_alias( entry ) ) { + /* entry is not an alias */ + break; + } + + /* entry is alias */ + if( depth > be->be_max_deref_depth ) { + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_DEREF_PROBLEM; + *text = "maximum deref depth exceeded"; + break; + } + + /* deref entry */ + aliasDN = get_alias_dn( entry, err, text ); + + if( aliasDN == NULL ) { + *matched = entry; + entry = NULL; + break; + } + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, aliasDN ) ) { + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_PROBLEM; + *text = "circular alias"; + break; + } + + /* attempt to dereference alias */ + + newe = bdb2i_dn2entry_r( be, aliasDN, &sup ); + + if( newe != NULL ) { + free( dn ); + bdb2i_cache_return_entry_r(&li->li_cache, entry ); + entry = newe; + dn = ch_strdup( entry->e_ndn ); + charray_add( &dnlist, dn ); + continue; + + } + + if ( sup != NULL ) { + bdb2i_cache_return_entry_r(&li->li_cache, entry ); + entry = NULL; + continue; + } + + /* no newe and no superior, we're done */ + break; + + } else if( sup != NULL ) { + /* have superior, may be an alias */ + Entry *newe; + Entry *newSup; + char *supDN; + char *aliasDN; + + if( !is_entry_alias( sup ) ) { + /* entry is not an alias */ + *matched = sup; + sup = NULL; + break; + } + + /* entry is alias */ + if( depth > be->be_max_deref_depth ) { + *matched = sup; + entry = NULL; + *err = LDAP_ALIAS_DEREF_PROBLEM; + *text = "maximum deref depth exceeded"; + break; + } + + /* deref entry */ + supDN = get_alias_dn( sup, err, text ); + + if( supDN == NULL ) { + *matched = sup; + break; + } + + aliasDN = new_superior( dn, sup->e_ndn, supDN ); + + if( aliasDN == NULL ) { + free(aliasDN); + *matched = sup; + *err = LDAP_ALIAS_PROBLEM; + *text = "superior alias problem"; + break; + } + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, aliasDN ) ) { + free(aliasDN); + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_PROBLEM; + *text = "subordinate circular alias"; + break; + } + + /* attempt to dereference alias */ + newe = bdb2i_dn2entry_r( be, aliasDN, &newSup ); + + if( newe != NULL ) { + free(aliasDN); + free( dn ); + bdb2i_cache_return_entry_r(&li->li_cache, sup ); + entry = newe; + dn = ch_strdup( entry->e_ndn ); + charray_add( &dnlist, dn ); + continue; + + } + + if ( newSup != NULL ) { + free( dn ); + bdb2i_cache_return_entry_r(&li->li_cache, sup ); + sup = newSup; + dn = aliasDN; + continue; + } + + break; + + } else { + /* no newe and no superior, we're done */ + break; + } + } + + free( dn ); + return entry; } -/* - * given a DN fully deref it and return the real DN or original DN if it fails - * This involves finding the last matched part then reconstructing forward - * e.g. - * ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg - * loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry - * dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched - * dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry - * remainder is ou=MyOU - * dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry - * release lock on o=MyAliasedOrg,c=MyCountry entry - * reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry - * release lock on o=MyOrg,c=MyCountry entry - */ -char *bdb2i_derefDN ( BackendDB *be, - Connection *conn, - Operation *op, - char *dn -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = 0; - char *newDN = NULL; - int depth, i; - Entry *eMatched; - Entry *eDeref; - Entry *eNew; - - if (!dn) return NULL; - - Debug( LDAP_DEBUG_TRACE, - "<= dereferencing dn: \"%s\"\n", - dn, 0, 0 ); - - newDN = ch_strdup ( dn ); - - /* while we don't have a matched dn, deref the DN */ - for ( depth = 0; - ( (eMatched = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL) && - (depth < be->be_maxDerefDepth); - ++depth ) { - - if ((matched != NULL) && *matched) { - char *submatch; - - /* - * make sure there actually is an entry for the matched part - */ - if ( (eMatched = bdb2i_dn2entry_r( be, matched, &submatch )) != NULL) { - char *remainder; /* part before the aliased part */ - int rlen = strlen(newDN) - strlen(matched); - - Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 ); - - remainder = ch_malloc (rlen + 1); - strncpy ( remainder, newDN, rlen ); - remainder[rlen] = '\0'; - - Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 ); - - if ((eNew = bdb2i_derefAlias_r( be, conn, op, eMatched )) == NULL) { - free (matched); - matched = NULL; - free (newDN); - newDN = NULL; - free (remainder); - remainder = NULL; - - bdb2i_cache_return_entry_r(&li->li_cache, eMatched); - eMatched = NULL; - break; /* no associated entry, dont deref */ + +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ) +{ + Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" ); + + if( a == NULL ) { + /* + * there was an aliasedobjectname defined but no data. + */ + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName attribute"; + return NULL; } - else { - - Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 ); - - i = strcasecmp (matched, eNew->e_dn); - /* free reader lock */ - bdb2i_cache_return_entry_r(&li->li_cache, eNew); - - free (matched); - matched = NULL; - - if (! i) { - /* newDN same as old so not an alias, no need to go further */ - free (newDN); - newDN = NULL; - free (remainder); - - bdb2i_cache_return_entry_r(&li->li_cache, eMatched); - eMatched = NULL; - break; - } - - /* - * we have dereferenced the aliased part so put - * the new dn together - */ - free (newDN); - newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1); - strcpy (newDN, remainder); - strcat (newDN, eMatched->e_dn); - Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 ); - - free (remainder); + + /* + * aliasedObjectName should be SINGLE-VALUED with a single value. + */ + if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val != NULL ) { + /* + * there was an aliasedobjectname defined but no data. + */ + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName value"; + return NULL; } - /* free reader lock */ - bdb2i_cache_return_entry_r(&li->li_cache, eMatched); - } - else { - if(submatch != NULL) free(submatch); - break; /* there was no entry for the matched part */ - } - } - else { - break; /* there was no matched part */ - } - } - - /* release lock if a match terminated the loop, there should be no - * outstanding locks at this point - */ - if(eMatched != NULL) { - /* free reader lock */ - bdb2i_cache_return_entry_r(&li->li_cache, eMatched); - } - - /* - * the final part of the DN might be an alias so try to dereference it. - * e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match - * and the above loop complete but we would still be left with an aliased DN. - */ - if (newDN != NULL) { - if ( (eNew = bdb2i_dn2entry_r( be, newDN, &matched )) != NULL) { - if ((eDeref = bdb2i_derefAlias_r( be, conn, op, eNew )) != NULL) { - free (newDN); - newDN = ch_strdup (eDeref->e_dn); - /* free reader lock */ - bdb2i_cache_return_entry_r(&li->li_cache, eDeref); - } - /* free reader lock */ - bdb2i_cache_return_entry_r(&li->li_cache, eNew); - } - } - if (matched != NULL) free(matched); - - /* - * warn if we exceeded the max depth as the resulting DN may not be dereferenced - */ - if (depth >= be->be_maxDerefDepth) { - if (newDN) { - Debug( LDAP_DEBUG_TRACE, - "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n", - dn, newDN, 0 ); - free (newDN); - newDN = NULL; - } else { - Debug( LDAP_DEBUG_TRACE, - "<= max deref depth exceeded in derefDN for \"%s\", result NULL\n", - dn, 0, 0 ); + + if( a->a_vals[1] != NULL ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias has multivalued aliasedObjectName"; + return NULL; } - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Maximum alias dereference depth exceeded for base" ); - } - if (newDN == NULL) { - newDN = ch_strdup ( dn ); - } - - Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); + return a->a_vals[0]->bv_val; +} + +static char* new_superior( + char *dn, + char *oldSup, + char *newSup ) +{ + char *newDN; + size_t dnlen, olen, nlen; + assert( dn && oldSup && newSup ); + + dnlen = strlen( dn ); + olen = strlen( oldSup ); + nlen = strlen( newSup ); + + newDN = ch_malloc( dnlen - olen + nlen + 1 ); + + memcpy( newDN, dn, dnlen - olen ); + memcpy( &newDN[dnlen - olen], newSup, nlen ); + newDN[dnlen - olen + nlen] = '\0'; - return newDN; + return newDN; } + +static int dnlist_subordinate( + char** dnlist, + char *dn ) +{ + int i; + assert( dnlist ); + + for( i = 0; dnlist[i] != NULL; i++ ) { + if( dn_issuffix( dnlist[i], dn ) ) { + return 1; + } + } + + return 0; +} + diff --git a/servers/slapd/back-bdb2/bind.c b/servers/slapd/back-bdb2/bind.c index db0cf7bf62..5f2ae0d9a2 100644 --- a/servers/slapd/back-bdb2/bind.c +++ b/servers/slapd/back-bdb2/bind.c @@ -74,7 +74,7 @@ bdb2i_back_bind_internal( Entry *e; Attribute *a; int rc; - char *matched; + Entry *matched; #ifdef HAVE_KERBEROS char krbname[MAX_K_NAME_SZ + 1]; AUTH_DAT ad; @@ -86,12 +86,26 @@ bdb2i_back_bind_internal( /* get entry with reader lock */ if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; + } + /* allow noauth binds */ rc = 1; if ( method == LDAP_AUTH_SIMPLE ) { if( cred->bv_len == 0 ) { /* SUCCESS */ - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } else if ( be_isroot_pw( be, dn, cred ) ) { /* front end will send result */ @@ -99,27 +113,30 @@ bdb2i_back_bind_internal( rc = 0; } else { - send_ldap_result( conn, op, - LDAP_NO_SUCH_OBJECT, matched, NULL ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); } } else if ( method == LDAP_AUTH_SASL ) { if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) { /* insert DIGEST calls here */ - send_ldap_result( conn, op, - LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL ); + send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, - LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL ); + send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, NULL, NULL, NULL ); } } else { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, NULL ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); rc = 1; } + if ( matched != NULL ) { - free( matched ); + ber_bvecfree( refs ); + free( matched_dn ); } return( rc ); } @@ -131,7 +148,38 @@ bdb2i_back_bind_internal( if ( ! access_allowed( be, conn, op, e, "entry", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + rc = 1; + goto return_results; + } + + if ( is_entry_alias( e ) ) { + /* entry is a alias, don't allow bind */ + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, NULL, NULL, NULL ); + + rc = 1; + goto return_results; + } + + + if ( is_entry_referral( e ) ) { + /* entry is a referral, don't allow bind */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + rc = 1; goto return_results; } @@ -139,7 +187,8 @@ bdb2i_back_bind_internal( switch ( method ) { case LDAP_AUTH_SIMPLE: if ( cred->bv_len == 0 ) { - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; @@ -158,14 +207,15 @@ bdb2i_back_bind_internal( if ( ! access_allowed( be, conn, op, e, "userpassword", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL); rc = 1; goto return_results; } if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) { send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, - NULL, NULL ); + NULL, NULL, NULL, NULL); /* stop front end from sending result */ rc = 1; @@ -175,7 +225,7 @@ bdb2i_back_bind_internal( if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 ) { send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, - NULL, NULL ); + NULL, NULL, NULL, NULL); /* stop front end from sending result */ rc = 1; goto return_results; @@ -187,7 +237,7 @@ bdb2i_back_bind_internal( case LDAP_AUTH_KRBV41: if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) { send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, - NULL, NULL ); + NULL, NULL, NULL, NULL); rc = 1; goto return_results; } @@ -195,7 +245,8 @@ bdb2i_back_bind_internal( if ( ! access_allowed( be, conn, op, e, "krbname", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL); rc = 1; goto return_results; } @@ -212,7 +263,7 @@ bdb2i_back_bind_internal( break; } send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, - NULL, NULL ); + NULL, NULL, NULL, NULL); rc = 1; goto return_results; } else { /* look for krbName match */ @@ -222,8 +273,8 @@ bdb2i_back_bind_internal( krbval.bv_len = strlen( krbname ); if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) { - send_ldap_result( conn, op, - LDAP_INVALID_CREDENTIALS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL); rc = 1; goto return_results; } @@ -232,7 +283,8 @@ bdb2i_back_bind_internal( break; case LDAP_AUTH_KRBV42: - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; goto return_results; @@ -243,7 +295,7 @@ bdb2i_back_bind_internal( default: send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED, - NULL, "auth method not supported" ); + NULL, "auth method not supported", NULL, NULL ); rc = 1; goto return_results; } @@ -277,10 +329,9 @@ bdb2_back_bind( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_r( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( 1 ); - } ret = bdb2i_back_bind_internal( be, conn, op, dn, method, mech, cred, edn ); diff --git a/servers/slapd/back-bdb2/compare.c b/servers/slapd/back-bdb2/compare.c index 2c07093416..f2fa1dd164 100644 --- a/servers/slapd/back-bdb2/compare.c +++ b/servers/slapd/back-bdb2/compare.c @@ -21,38 +21,77 @@ bdb2i_back_compare_internal( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; + Entry *matched; Entry *e; Attribute *a; int rc; + int manageDSAit = get_manageDSAit( op ); /* get entry with reader lock */ if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + char *matched_dn = NULL; + struct berval **refs = NULL; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } - if(matched == NULL) free(matched); return( 1 ); } - /* check for deleted */ + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + rc = 1; + goto return_results; + } + if ( ! access_allowed( be, conn, op, e, ava->ava_type, &ava->ava_value, ACL_COMPARE ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" ); + send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) - send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_TRUE, + NULL, NULL, NULL, NULL ); else - send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, + NULL, NULL, NULL, NULL ); rc = 0; @@ -80,7 +119,8 @@ bdb2_back_compare( if ( bdb2i_enter_backend_r( &lock ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( 1 ); } diff --git a/servers/slapd/back-bdb2/delete.c b/servers/slapd/back-bdb2/delete.c index b00c155ec3..ca36c2bacf 100644 --- a/servers/slapd/back-bdb2/delete.c +++ b/servers/slapd/back-bdb2/delete.c @@ -20,31 +20,63 @@ bdb2i_back_delete_internal( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = NULL; + Entry *matched = NULL; char *pdn = NULL; Entry *e, *p = NULL; - int rc = -1; + int rc = -1, manageDSAit; Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_delete: %s\n", dn, 0, 0); /* get entry with writer lock */ if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: no such object %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + if ( matched != NULL ) { - free( matched ); + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + return( -1 ); } - /* check for deleted */ + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + goto return_results; + } + if ( bdb2i_has_children( be, e ) ) { Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: non leaf %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "", - "" ); + send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -55,7 +87,8 @@ bdb2i_back_delete_internal( Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: insufficient access %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); goto return_results; } #endif @@ -66,7 +99,7 @@ bdb2i_back_delete_internal( Debug( LDAP_DEBUG_TRACE, "<=- bdb2i_back_delete: parent does not exist\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -77,7 +110,7 @@ bdb2i_back_delete_internal( Debug( LDAP_DEBUG_TRACE, "<=- bdb2i_back_delete: no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -87,7 +120,7 @@ bdb2i_back_delete_internal( Debug( LDAP_DEBUG_TRACE, "<=- bdb2i_back_delete: no parent & not root\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } } @@ -96,7 +129,8 @@ bdb2i_back_delete_internal( Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "","" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -105,7 +139,8 @@ bdb2i_back_delete_internal( Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -114,11 +149,13 @@ bdb2i_back_delete_internal( Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; return_results:; @@ -155,10 +192,9 @@ bdb2_back_delete( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_w( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); - } ret = bdb2i_back_delete_internal( be, conn, op, dn ); diff --git a/servers/slapd/back-bdb2/dn2id.c b/servers/slapd/back-bdb2/dn2id.c index 470eb6a142..e77cabfa20 100644 --- a/servers/slapd/back-bdb2/dn2id.c +++ b/servers/slapd/back-bdb2/dn2id.c @@ -156,7 +156,7 @@ Entry * bdb2i_dn2entry_rw( BackendDB *be, char *dn, - char **matched, + Entry **matched, int rw ) { @@ -168,7 +168,10 @@ bdb2i_dn2entry_rw( Debug(LDAP_DEBUG_TRACE, "dn2entry_%s: dn: \"%s\"\n", rw ? "w" : "r", dn, 0); - *matched = NULL; + if( matched != NULL ) { + /* caller cares about match */ + *matched = NULL; + } if ( (id = bdb2i_dn2id( be, dn )) != NOID && (e = bdb2i_id2entry_rw( be, id, rw )) != NULL ) @@ -184,24 +187,17 @@ bdb2i_dn2entry_rw( /* treat as if NOID was found */ } - /* stop when we get to the suffix */ - if ( be_issuffix( be, dn ) ) { - return( NULL ); - } + /* caller doesn't care about match */ + if( matched == NULL ) return NULL; /* entry does not exist - see how much of the dn does exist */ + /* dn_parent checks returns NULL if dn is suffix */ if ( (pdn = dn_parent( be, dn )) != NULL ) { /* get entry with reader lock */ if ( (e = bdb2i_dn2entry_r( be, pdn, matched )) != NULL ) { - if(*matched != NULL) { - free(*matched); - } - *matched = pdn; - /* free entry with reader lock */ - bdb2i_cache_return_entry_r( &li->li_cache, e ); - } else { - free( pdn ); + *matched = e; } + free( pdn ); } return( NULL ); diff --git a/servers/slapd/back-bdb2/group.c b/servers/slapd/back-bdb2/group.c index fc3377cc35..6e393757e3 100644 --- a/servers/slapd/back-bdb2/group.c +++ b/servers/slapd/back-bdb2/group.c @@ -26,93 +26,116 @@ bdb2i_back_group_internal( char *groupattrName ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e; - char *matched; - Attribute *objectClass; - Attribute *member; - int rc; - - Debug( LDAP_DEBUG_TRACE, + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + int rc = 1; + Attribute *attr; + struct berval bv; + + Debug( LDAP_DEBUG_ARGS, "=> bdb2i_back_group: gr dn: \"%s\"\n", gr_ndn, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> bdb2i_back_group: op dn: \"%s\"\n", op_ndn, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> bdb2i_back_group: objectClass: \"%s\" attrName: \"%s\"\n", objectclassValue, groupattrName, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> bdb2i_back_group: tr dn: \"%s\"\n", target->e_ndn, 0, 0 ); if (strcmp(target->e_ndn, gr_ndn) == 0) { /* we already have a LOCKED copy of the entry */ e = target; - Debug( LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "=> bdb2i_back_group: target is group: \"%s\"\n", gr_ndn, 0, 0 ); + } else { /* can we find group entry with reader lock */ - if ((e = bdb2i_dn2entry_r(be, gr_ndn, &matched )) == NULL) { - Debug( LDAP_DEBUG_TRACE, - "=> bdb2i_back_group: cannot find group: \"%s\" matched: \"%s\"\n", - gr_ndn, (matched ? matched : ""), 0 ); - if (matched != NULL) - free(matched); + if ((e = bdb2i_dn2entry_r(be, gr_ndn, NULL )) == NULL) { + Debug( LDAP_DEBUG_ACL, + "=> bdb2i_back_group: cannot find group: \"%s\"\n", + gr_ndn, 0, 0 ); return( 1 ); } - Debug( LDAP_DEBUG_ARGS, + + Debug( LDAP_DEBUG_ACL, "=> bdb2i_back_group: found group: \"%s\"\n", gr_ndn, 0, 0 ); - } + } + /* 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; - /* check for deleted */ + if ((attr = attr_find(e->e_attrs, "objectclass")) == NULL) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: failed to find objectClass\n", 0, 0, 0 ); + goto return_results; + } - /* 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; - if ((objectClass = attr_find(e->e_attrs, "objectclass")) == NULL) { - Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find objectClass\n", 0, 0, 0 ); - } - else if ((member = attr_find(e->e_attrs, groupattrName)) == NULL) { - Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find %s\n", groupattrName, 0, 0 ); - } - else { - struct berval bvObjectClass; - struct berval bvMembers; - - Debug( LDAP_DEBUG_ARGS, "<= bdb2i_back_group: found objectClass and %s\n", groupattrName, 0, 0 ); - - bvObjectClass.bv_val = objectclassValue; - bvObjectClass.bv_len = strlen( bvObjectClass.bv_val ); - - bvMembers.bv_val = op_ndn; - bvMembers.bv_len = strlen( op_ndn ); - - if (value_find(objectClass->a_vals, &bvObjectClass, SYNTAX_CIS, 1) != 0) { - Debug( LDAP_DEBUG_TRACE, - "<= bdb2i_back_group: failed to find %s in objectClass\n", - objectclassValue, 0, 0 ); - } - else if (value_find(member->a_vals, &bvMembers, SYNTAX_CIS, 1) != 0) { - Debug( LDAP_DEBUG_ACL, - "<= bdb2i_back_group: \"%s\" not in \"%s\": %s\n", - op_ndn, gr_ndn, groupattrName ); - } - else { - Debug( LDAP_DEBUG_ACL, - "<= bdb2i_back_group: \"%s\" is in \"%s\": %s\n", - op_ndn, gr_ndn, groupattrName ); - rc = 0; - } - } + bv.bv_val = "ALIAS"; + bv.bv_len = sizeof("ALIAS")-1; + + if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: group is an alias\n", 0, 0, 0 ); + goto return_results; + } + + bv.bv_val = "REFERRAL"; + bv.bv_len = sizeof("REFERRAL")-1; + + if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: group is a referral\n", 0, 0, 0 ); + goto return_results; + } + + bv.bv_val = objectclassValue; + bv.bv_len = strlen( bv.bv_val ); + + if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: failed to find %s in objectClass\n", + objectclassValue, 0, 0 ); + goto return_results; + } + + if ((attr = attr_find(e->e_attrs, groupattrName)) == NULL) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: failed to find %s\n", + groupattrName, 0, 0 ); + goto return_results; + } + + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: found objectClass %s and %s\n", + objectclassValue, groupattrName, 0 ); + + + bv.bv_val = op_ndn; + bv.bv_len = strlen( op_ndn ); + + if (value_find( attr->a_vals, &bv, attr->a_syntax, 1) != 0 ) { + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: \"%s\" not in \"%s\": %s\n", + op_ndn, gr_ndn, groupattrName ); + goto return_results; + } + + Debug( LDAP_DEBUG_ACL, + "<= bdb2i_back_group: \"%s\" is in \"%s\": %s\n", + op_ndn, gr_ndn, groupattrName ); + rc = 0; +return_results: if( target != e ) { /* free entry and reader lock */ bdb2i_cache_return_entry_r( &li->li_cache, e ); diff --git a/servers/slapd/back-bdb2/modify.c b/servers/slapd/back-bdb2/modify.c index e158f6cdef..6dee5eeace 100644 --- a/servers/slapd/back-bdb2/modify.c +++ b/servers/slapd/back-bdb2/modify.c @@ -104,7 +104,8 @@ bdb2i_back_modify_internal( Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0); if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) { - send_ldap_result( conn, op, err, NULL, NULL ); + send_ldap_result( conn, op, err, + NULL, NULL, NULL, NULL ); goto error_return; } @@ -141,7 +142,8 @@ bdb2i_back_modify_internal( if ( err != LDAP_SUCCESS ) { /* unlock entry, delete from cache */ - send_ldap_result( conn, op, err, NULL, NULL ); + send_ldap_result( conn, op, err, + NULL, NULL, NULL, NULL ); goto error_return; } } @@ -149,7 +151,8 @@ bdb2i_back_modify_internal( /* check that the entry still obeys the schema */ if ( global_schemacheck && oc_schema_check( e ) != 0 ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL, NULL ); goto error_return; } @@ -163,7 +166,8 @@ bdb2i_back_modify_internal( /* modify indexes */ if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto error_return; } @@ -177,16 +181,16 @@ bdb2i_back_modify_internal( /* change the entry itself */ if ( bdb2i_id2entry_add( be, e ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto error_return; } - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); - bdb2i_cache_return_entry_w( &li->li_cache, e ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); return( 0 ); error_return:; - bdb2i_cache_return_entry_w( &li->li_cache, e ); return( -1 ); } @@ -203,17 +207,16 @@ bdb2_back_modify( DB_LOCK lock; struct ldbminfo *li = (struct ldbminfo *) be->be_private; struct timeval time1; - int ret; - char *matched; + int ret, manageDSAit; + Entry *matched; Entry *e; bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_w( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); - } /* check, if a new default attribute index will be created, @@ -228,19 +231,54 @@ bdb2_back_modify( } if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, - NULL ); + char *matched_dn = NULL; + struct berval **refs = NULL; if ( matched != NULL ) { - free( matched ); + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); } ret = -1; + goto done; + } - } else { - ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e ); + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + bdb2i_cache_return_entry_w( &li->li_cache, e ); + + ber_bvecfree( refs ); + + ret = -1; + goto done; } + ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e ); + bdb2i_cache_return_entry_w( &li->li_cache, e ); + +done: (void) bdb2i_leave_backend_w( lock ); bdb2i_stop_timing( be->bd_info, time1, "MOD", conn, op ); diff --git a/servers/slapd/back-bdb2/modrdn.c b/servers/slapd/back-bdb2/modrdn.c index d2965a28c4..8054eed2c1 100644 --- a/servers/slapd/back-bdb2/modrdn.c +++ b/servers/slapd/back-bdb2/modrdn.c @@ -36,12 +36,12 @@ bdb2i_back_modrdn_internal( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = NULL; + Entry *matched = NULL; char *p_dn = NULL, *p_ndn = NULL; char *new_dn = NULL, *new_ndn = NULL; char sep[2]; Entry *e, *p = NULL; - int rc = -1; + int rc = -1, manageDSAit; /* Added to support LDAP v2 correctly (deleteoldrdn thing) */ char *new_rdn_val = NULL; /* Val of new rdn */ char *new_rdn_type = NULL; /* Type of new rdn */ @@ -65,13 +65,46 @@ bdb2i_back_modrdn_internal( /* get entry with writer lock */ if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + char *matched_dn = NULL; + struct berval **refs = NULL; + if ( matched != NULL ) { - free( matched ); + matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + return( -1 ); } + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + goto return_results; + } + #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL /* check parent for "children" acl */ if ( ! access_allowed( be, conn, op, e, @@ -80,7 +113,7 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } #endif @@ -91,7 +124,7 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -102,7 +135,7 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -118,7 +151,7 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -150,8 +183,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: newSup(ndn=%s) not here!\n", np_ndn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", - ""); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -167,7 +200,7 @@ bdb2i_back_modrdn_internal( "ldbm_back_modrdn: no wr to newSup children\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -191,7 +224,8 @@ bdb2i_back_modrdn_internal( new_ndn, 0, 0 ); if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) { - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -205,7 +239,8 @@ bdb2i_back_modrdn_internal( /* delete old one */ if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -218,7 +253,8 @@ bdb2i_back_modrdn_internal( /* add new one */ if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -231,7 +267,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out type of newrdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -241,7 +278,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out val of newrdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -257,7 +295,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out old_rdn from dn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -267,7 +306,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out the old_rdn type\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -318,9 +358,8 @@ bdb2i_back_modrdn_internal( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, - LDAP_OPERATIONS_ERROR, - "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; @@ -373,17 +412,20 @@ bdb2i_back_modrdn_internal( /* id2entry index */ if ( bdb2i_id2entry_add( be, e ) != 0 ) { entry_free( e ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results_after; } - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; goto return_results_after; return_results: if( new_dn != NULL ) free( new_dn ); if( new_ndn != NULL ) free( new_ndn ); + return_results_after: /* NOTE: * new_dn and new_ndn are not deallocated because they are used by @@ -392,8 +434,6 @@ return_results_after: if( p_dn != NULL ) free( p_dn ); if( p_ndn != NULL ) free( p_ndn ); - if( matched != NULL ) free( matched ); - /* LDAP v2 supporting correct attribute handling. */ if( new_rdn_type != NULL ) free(new_rdn_type); if( new_rdn_val != NULL ) free(new_rdn_val); @@ -436,8 +476,8 @@ bdb2_back_modrdn( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_w( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-bdb2/proto-back-bdb2.h b/servers/slapd/back-bdb2/proto-back-bdb2.h index c3135c68b9..e6ac08c6e6 100644 --- a/servers/slapd/back-bdb2/proto-back-bdb2.h +++ b/servers/slapd/back-bdb2/proto-back-bdb2.h @@ -17,16 +17,19 @@ int bdb2i_release_add_lock LDAP_P(()); /* * alias.c */ -Entry *bdb2i_derefAlias_r LDAP_P(( - BackendDB *be, - Connection *conn, - Operation *op, - Entry *e )); -char *bdb2i_derefDN LDAP_P(( - BackendDB *be, - Connection *conn, - Operation *op, - char *dn )); + +Entry * bdb2i_deref_r LDAP_P(( + Backend *be, + Entry *e, + char *dn, + int *err, + Entry **matched, + char **text )); + +#define deref_entry_r( be, e, err, matched, text ) \ + bdb2i_deref_r( be, e, NULL, err, matched, text ) +#define deref_dn_r( be, dn, err, matched, text ) \ + bdb2i_deref_r( be, NULL, dn, err, matched, text ) /* * attr.c @@ -74,8 +77,12 @@ int bdb2i_dn2id_add LDAP_P(( BackendDB *be, char *dn, ID id )); ID bdb2i_dn2id LDAP_P(( BackendDB *be, char *dn )); int bdb2i_dn2id_delete LDAP_P(( BackendDB *be, char *dn )); -Entry * bdb2i_dn2entry_rw LDAP_P(( BackendDB *be, char *dn, char **matched, - int rw )); +Entry * bdb2i_dn2entry_rw LDAP_P(( + BackendDB *be, + char *dn, + Entry **matched, + int rw )); + #define bdb2i_dn2entry_r(be, dn, m) bdb2i_dn2entry_rw((be), (dn), (m), 0) #define bdb2i_dn2entry_w(be, dn, m) bdb2i_dn2entry_rw((be), (dn), (m), 1) diff --git a/servers/slapd/back-bdb2/search.c b/servers/slapd/back-bdb2/search.c index 28fed4863a..63d709475c 100644 --- a/servers/slapd/back-bdb2/search.c +++ b/servers/slapd/back-bdb2/search.c @@ -12,20 +12,12 @@ #include "back-bdb2.h" #include "proto-back-bdb2.h" -static ID_BLOCK *base_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err); -static ID_BLOCK *onelevel_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err); -static ID_BLOCK *subtree_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase); - -#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; \ - } \ -} +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 ); static int bdb2i_back_search_internal( @@ -44,19 +36,76 @@ bdb2i_back_search_internal( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int err; + int rc, err; + char *text; time_t stoptime; ID_BLOCK *candidates; ID id; Entry *e; - Attribute *ref; - char *matched = NULL; - int rmaxsize, nrefs; - char *rbuf, *rcur; + struct berval **v2refs = NULL; + Entry *matched = NULL; + char *realbase = NULL; int nentries = 0; - char *realBase; + int manageDSAit = get_manageDSAit( op ); + + Debug(LDAP_DEBUG_TRACE, "=> bdb2_back_search\n", 0, 0, 0); + + /* get entry with reader lock */ + if ( deref & LDAP_DEREF_FINDING ) { + e = deref_dn_r( be, base, &err, &matched, &text ); + + } else { + e = bdb2i_dn2entry_r( be, base, &matched ); + err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL; + text = NULL; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + + if ( matched != NULL ) { + matched_dn = ch_strdup( matched->e_dn ); + + refs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched ) + : NULL; + + bdb2i_cache_return_entry_r( &li->li_cache, matched ); + } else { + refs = default_referral; + } + + send_ldap_result( conn, op, err, + matched_dn, text, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + return 1; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + char *matched_dn = ch_strdup( e->e_dn ); + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + bdb2i_cache_return_entry_r( &li->li_cache, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); - Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + free( matched_dn ); + + return 1; + } if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) { tlimit = -1; /* allow root to set no limit */ @@ -65,6 +114,7 @@ bdb2i_back_search_internal( 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 { @@ -72,220 +122,183 @@ bdb2i_back_search_internal( be->be_sizelimit : slimit; } - /* - * check and apply aliasing where the dereferencing applies to - * the subordinates of the base - */ - - switch ( deref ) { - case LDAP_DEREF_FINDING: - case LDAP_DEREF_ALWAYS: - realBase = bdb2i_derefDN ( be, conn, op, base ); - break; - default: - realBase = ch_strdup(base); - } + if ( scope == LDAP_SCOPE_BASE) { + candidates = base_candidate( be, e ); - (void) dn_normalize_case( realBase ); - - Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n", - realBase, 0, 0 ); - - switch ( scope ) { - case LDAP_SCOPE_BASE: - candidates = base_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, &err ); - break; - - case LDAP_SCOPE_ONELEVEL: - candidates = onelevel_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, &err ); - break; - - case LDAP_SCOPE_SUBTREE: - candidates = subtree_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, NULL, &err, 1 ); - break; - - default: - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "", - "Bad scope" ); - if( realBase != NULL) { - free( realBase ); - } - return( -1 ); + } else { + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); } - /* null candidates means we could not find the base object */ + /* need normalized dn below */ + realbase = ch_strdup( e->e_ndn ); + bdb2i_cache_return_entry_r( &li->li_cache, e ); + if ( candidates == NULL ) { - send_ldap_result( conn, op, err, matched, "" ); - if ( matched != NULL ) { - free( matched ); - } - if( realBase != NULL) { - free( realBase ); - } - return( -1 ); - } + /* no candidates */ + Debug( LDAP_DEBUG_TRACE, "no candidates\n", 0, + 0, 0 ); + + send_search_result( conn, op, + LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 0 ); - if ( matched != NULL ) { - free( matched ); + rc = 1; + goto done; } - rmaxsize = 0; - nrefs = 0; - rbuf = rcur = NULL; - MAKE_SPACE( sizeof("Referral:") + 1 ); - strcpy( rbuf, "Referral:" ); - rcur = strchr( rbuf, '\0' ); for ( id = bdb2i_idl_firstid( candidates ); id != NOID; - id = bdb2i_idl_nextid( candidates, id ) ) { + id = bdb2i_idl_nextid( candidates, id ) ) + { + int scopeok = 0; + /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - bdb2i_idl_free( candidates ); - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); + rc = 0; + goto done; } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); /* check time limit */ if ( tlimit != -1 && slap_get_time() > stoptime ) { - send_ldap_search_result( conn, op, - LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf : - NULL, nentries ); - bdb2i_idl_free( candidates ); - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); + send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, v2refs, NULL, nentries ); + rc = 0; + goto done; } /* get the entry with reader lock */ - if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) { - Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n", - id, 0, 0 ); - continue; + e = bdb2i_id2entry_r( be, id ); + + if ( e == NULL ) { + Debug( LDAP_DEBUG_ARGS, "search: candidate %ld not found\n", + id, 0, 0 ); + + goto loop_continue; + } + + if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) { + Entry *matched; + int err; + 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 ) { + char *pdn = dn_parent( NULL, e->e_ndn ); + if ( pdn != NULL ) { + if( strcmp( pdn, realbase ) ) { + free( pdn ); + goto loop_continue; + } + free(pdn); + } + + } else if ( dn_issuffix( e->e_ndn, realbase ) ) { + /* alias is within scope */ + Debug( LDAP_DEBUG_ARGS, "search: \"%s\" in subtree\n", + e->e_dn, 0, 0 ); + 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 ( scope == LDAP_SCOPE_SUBTREE && - e->e_ndn != NULL && - strncmp( e->e_ndn, "REF=", 4 ) == 0 && - (ref = attr_find( e->e_attrs, "ref" )) != NULL ) + if ( !manageDSAit && scope != LDAP_SCOPE_BASE && + is_entry_referral( e ) ) { - int i; + struct berval **refs = get_entry_referrals( + be, conn, op, e ); - if ( ref->a_vals == NULL ) { - Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", - e->e_dn, 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++; - } - } + send_search_reference( be, conn, op, + e, refs, scope, NULL, &v2refs ); - /* 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; + ber_bvecfree( refs ); - /* check scope */ - scopeok = 1; - if ( scope == LDAP_SCOPE_ONELEVEL ) { - if ( (dn = dn_parent( be, e->e_dn )) != NULL ) { - (void) dn_normalize_case( dn ); - scopeok = (dn == realBase) - ? 1 - : (strcmp( dn, realBase ) ? 0 : 1 ); - free( dn ); - } else { - scopeok = (realBase == NULL || *realBase == '\0'); - } - } else if ( scope == LDAP_SCOPE_SUBTREE ) { - dn = ch_strdup( e->e_ndn ); - scopeok = dn_issuffix( dn, realBase ); + goto loop_continue; + } + + /* if it matches the filter and scope, send it */ + if ( test_filter( be, conn, op, e, filter ) == 0 ) { + char *dn; + + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( (dn = dn_parent( be, e->e_ndn )) != NULL ) { + (void) dn_normalize_case( dn ); + scopeok = (dn == realbase) + ? 1 + : (strcmp( dn, realbase ) ? 0 : 1 ); free( dn ); + + } else { + scopeok = (realbase == NULL || *realbase == '\0'); } - if ( scopeok ) { - /* check size limit */ - if ( --slimit == -1 ) { - bdb2i_cache_return_entry_r( &li->li_cache, e ); - send_ldap_search_result( conn, op, - LDAP_SIZELIMIT_EXCEEDED, NULL, - nrefs > 0 ? rbuf : NULL, nentries ); - bdb2i_idl_free( candidates ); - free( rbuf ); - - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); - } + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + dn = ch_strdup( e->e_ndn ); + scopeok = dn_issuffix( dn, realbase ); + free( dn ); - /* - * check and apply aliasing where the dereferencing applies to - * the subordinates of the base - */ - switch ( deref ) { - case LDAP_DEREF_SEARCHING: - case LDAP_DEREF_ALWAYS: - { - Entry *newe = bdb2i_derefAlias_r( be, conn, op, e ); - if ( newe == NULL ) { /* problem with the alias */ - bdb2i_cache_return_entry_r( &li->li_cache, e ); - e = NULL; - } - else if ( newe != e ) { /* reassign e */ - bdb2i_cache_return_entry_r( &li->li_cache, e ); - e = newe; - } - } - break; - } + } else { + scopeok = 1; + } - if (e) { - switch ( send_search_entry( be, conn, op, e, - attrs, attrsonly, 0 ) ) { - case 0: /* entry sent ok */ - nentries++; - break; - case 1: /* entry not sent */ - break; - case -1: /* connection closed */ - bdb2i_cache_return_entry_r( &li->li_cache, e ); - bdb2i_idl_free( candidates ); - free( rbuf ); - - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); - } + if ( scopeok ) { + /* check size limit */ + if ( --slimit == -1 ) { + bdb2i_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 (e) { + switch ( send_search_entry( be, conn, op, e, + attrs, attrsonly, 0, NULL ) ) { + case 0: /* entry sent ok */ + nentries++; + break; + case 1: /* entry not sent */ + break; + case -1: /* connection closed */ + bdb2i_cache_return_entry_r( &li->li_cache, e ); + rc = 0; + goto done; } } + } else { + Debug( LDAP_DEBUG_TRACE, "candidate %ld scope not okay\n", + id, 0, 0 ); } + } else { + Debug( LDAP_DEBUG_TRACE, "candidate %ld does match filter\n", + id, 0, 0 ); } +loop_continue: if( e != NULL ) { /* free reader lock */ bdb2i_cache_return_entry_r( &li->li_cache, e ); @@ -293,21 +306,19 @@ bdb2i_back_search_internal( ldap_pvt_thread_yield(); } + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, NULL, nentries ); + + rc = 0; + +done: bdb2i_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 ); - } - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } + ber_bvecfree( v2refs ); + if( realbase ) free( realbase ); - return( 0 ); + return rc; } @@ -335,8 +346,8 @@ bdb2_back_search( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_r( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -352,191 +363,126 @@ bdb2_back_search( static ID_BLOCK * -base_candidates( - BackendDB *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err +base_candidate( + Backend *be, + Entry *e ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; ID_BLOCK *idl; - Entry *e; - - Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0); - *err = LDAP_SUCCESS; - - /* get entry with reader lock */ - if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } - - /* check for deleted */ + Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", + e->e_dn, 0, 0); idl = bdb2i_idl_alloc( 1 ); bdb2i_idl_insert( &idl, e->e_id, 1 ); - - /* free reader lock */ - bdb2i_cache_return_entry_r( &li->li_cache, e ); - return( idl ); } static ID_BLOCK * -onelevel_candidates( - BackendDB *be, - Connection *conn, - Operation *op, - char *base, +search_candidates( + Backend *be, + Entry *e, Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err + int scope, + int deref, + int manageDSAit ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e = NULL; - Filter *f; - char buf[20]; ID_BLOCK *candidates; + Filter *f, *rf, *af, *lf; - Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0); + Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" s=%d d=%d\n", + e->e_ndn, scope, deref ); - *err = LDAP_SUCCESS; + f = NULL; - /* get the base object with reader lock */ - if ( base != NULL && *base != '\0' && - (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); + if( !manageDSAit ) { + /* match referrals */ + rf = (Filter *) ch_malloc( sizeof(Filter) ); + rf->f_next = NULL; + rf->f_choice = LDAP_FILTER_OR; + rf->f_or = (Filter *) ch_malloc( sizeof(Filter) ); + rf->f_or->f_choice = LDAP_FILTER_EQUALITY; + rf->f_or->f_avtype = ch_strdup( "objectclass" ); + rf->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" ); + rf->f_or->f_avvalue.bv_len = sizeof("REFERRAL")-1; + rf->f_or->f_next = filter; + f = rf; + } else { + rf = NULL; + f = filter; } - /* - * 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 = ch_strdup( "id2children" ); - sprintf( buf, "%ld", e != NULL ? e->e_id : 0 ); - f->f_and->f_ava.ava_value.bv_val = ch_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 ); - - /* free entry and reader lock */ - if( e != NULL ) { - bdb2i_cache_return_entry_r( &li->li_cache, e ); + if( deref & LDAP_DEREF_SEARCHING ) { + /* match aliases */ + af = (Filter *) ch_malloc( sizeof(Filter) ); + af->f_next = NULL; + af->f_choice = LDAP_FILTER_OR; + af->f_or = (Filter *) ch_malloc( sizeof(Filter) ); + af->f_or->f_choice = LDAP_FILTER_EQUALITY; + af->f_or->f_avtype = ch_strdup( "objectclass" ); + af->f_or->f_avvalue.bv_val = ch_strdup( "ALIAS" ); + af->f_or->f_avvalue.bv_len = sizeof("ALIAS")-1; + af->f_or->f_next = f; + f = af; + } else { + af = NULL; } - return( candidates ); -} -static ID_BLOCK * -subtree_candidates( - BackendDB *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - Entry *e, - int *err, - int lookupbase -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Filter *f, **filterarg_ptr; - ID_BLOCK *candidates; + if ( scope == LDAP_SCOPE_SUBTREE ) { + lf = (Filter *) ch_malloc( sizeof(Filter) ); + lf->f_next = NULL; + lf->f_choice = LDAP_FILTER_AND; + lf->f_and = (Filter *) ch_malloc( sizeof(Filter) ); - Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n", - base ? base : "NULL", lookupbase ? "lookupbase" : "", 0); - - /* - * 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 ) { - e = NULL; + lf->f_and->f_choice = LDAP_FILTER_SUBSTRINGS; + lf->f_and->f_sub_type = ch_strdup( "dn" ); + lf->f_and->f_sub_initial = NULL; + lf->f_and->f_sub_any = NULL; + lf->f_and->f_sub_final = ch_strdup( e->e_ndn ); - if ( base != NULL && *base != '\0' && - (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } + lf->f_and->f_next = f; + f = lf; - if (e) { - bdb2i_cache_return_entry_r( &li->li_cache, e ); - } + } else if ( scope == LDAP_SCOPE_ONELEVEL ) { + char buf[16]; - 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 = ch_strdup( "objectclass" ); - /* Patch to use normalized uppercase */ - f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" ); - f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" ); - filterarg_ptr = &f->f_or->f_next; - *filterarg_ptr = 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 = ch_strdup( "dn" ); - f->f_and->f_sub_initial = NULL; - f->f_and->f_sub_any = NULL; - f->f_and->f_sub_final = ch_strdup( base ); - value_normalize( f->f_and->f_sub_final, SYNTAX_CIS ); - f->f_and->f_next = filter; - filter = f; - } + lf = (Filter *) ch_malloc( sizeof(Filter) ); + lf->f_next = NULL; + lf->f_choice = LDAP_FILTER_AND; + lf->f_and = (Filter *) ch_malloc( sizeof(Filter) ); + + lf->f_and->f_choice = LDAP_FILTER_EQUALITY; + lf->f_and->f_ava.ava_type = ch_strdup( "id2children" ); + sprintf( buf, "%ld", e != NULL ? e->e_id : 0 ); + lf->f_and->f_ava.ava_value.bv_val = ch_strdup( buf ); + lf->f_and->f_ava.ava_value.bv_len = strlen( buf ); + + lf->f_and->f_next = f; + f = lf; + + } else { + lf = NULL; } - candidates = bdb2i_filter_candidates( be, filter ); + candidates = bdb2i_filter_candidates( be, f ); + + /* free up filter additions we allocated above */ + if( lf != NULL ) { + lf->f_and->f_next = NULL; + filter_free( lf ); + } + + if( af != NULL ) { + af->f_or->f_next = NULL; + filter_free( af ); + } - /* free up just the parts we allocated above */ - if ( f != NULL ) { - *filterarg_ptr = NULL; - filter_free( f ); + if( rf != NULL ) { + rf->f_or->f_next = NULL; + filter_free( rf ); } return( candidates ); diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 26632c8246..d57364a637 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -75,8 +75,8 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op) if (!lc) { ld = ldap_init(li->host, li->port); if (!ld) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ldap_init failed" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "ldap_init failed", NULL, NULL ); return( NULL ); } lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn)); @@ -112,7 +112,7 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op) 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); - send_ldap_result( lc->conn, op, err, match, msg); + send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL ); free(match); free(msg); return( (err==LDAP_SUCCESS) ? 0 : -1 ); diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 6145a0704d..c742248c5e 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -116,7 +116,8 @@ fail: return( ldap_back_op_result(lc, op) ); if (rc == -1) goto fail; - send_ldap_search_result( conn, op, sres, match, err, i ); + send_search_result( conn, op, sres, + match, err, NULL, NULL, i ); if (match) free(match); if (err) @@ -158,7 +159,7 @@ ldap_send_entry( if (!attr->a_vals) attr->a_vals = &dummy; } - send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, 0 ); + send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, 0, NULL ); for (;ent.e_attrs;) { attr=ent.e_attrs; ent.e_attrs = attr->a_next; diff --git a/servers/slapd/back-ldbm/add.c b/servers/slapd/back-ldbm/add.c index 6173a78c92..c6f85169c6 100644 --- a/servers/slapd/back-ldbm/add.c +++ b/servers/slapd/back-ldbm/add.c @@ -33,7 +33,8 @@ ldbm_back_add( if ( ( dn2id( be, e->e_ndn ) ) != NOID ) { ldap_pvt_thread_mutex_unlock(&li->li_add_mutex); entry_free( e ); - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" ); + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -44,8 +45,8 @@ ldbm_back_add( 0, 0, 0 ); entry_free( e ); - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "", - "" ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -58,20 +59,38 @@ ldbm_back_add( pdn = dn_parent( be, e->e_ndn ); if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) { - char *matched = NULL; + Entry *matched = NULL; assert( *pdn != '\0' ); /* get parent with writer lock */ if ( (p = dn2entry_w( be, pdn, &matched )) == NULL ) { + char *matched_dn; + struct berval **refs; + ldap_pvt_thread_mutex_unlock(&li->li_add_mutex); - Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, - 0, 0 ); - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, - matched, "" ); if ( matched != NULL ) { - free( matched ); + 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 { + matched_dn = NULL; + refs = default_referral; + } + + Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", + 0, 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); } entry_free( e ); @@ -84,25 +103,59 @@ ldbm_back_add( free(pdn); - if ( matched != NULL ) { - free( matched ); - } - if ( ! access_allowed( be, conn, op, p, "children", NULL, ACL_WRITE ) ) { + /* free parent and writer lock */ + cache_return_entry_w( &li->li_cache, p ); + Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); + + + entry_free( e ); + return -1; + } + + if ( is_entry_alias( p ) ) { + /* parent is an alias, don't allow add */ /* free parent and writer lock */ - cache_return_entry_w( &li->li_cache, p ); + cache_return_entry_w( &li->li_cache, p ); + + Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, NULL, NULL, NULL ); entry_free( e ); return -1; } + if ( is_entry_referral( p ) ) { + /* parent is a referral, don't allow add */ + char *matched_dn = ch_strdup( p->e_dn ); + struct berval **refs = is_entry_referral( p ) + ? get_entry_referrals( be, conn, op, p ) + : NULL; + + /* free parent and writer lock */ + cache_return_entry_w( &li->li_cache, p ); + + Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + free( matched_dn ); + entry_free( e ); + return -1; + } + } else { if(pdn != NULL) { assert( *pdn == '\0' ); @@ -118,7 +171,7 @@ ldbm_back_add( 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); entry_free( e ); return -1; @@ -160,11 +213,9 @@ ldbm_back_add( /* free the entry */ entry_free( e ); - if(rc > 0) { - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" ); - } else { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); - } + send_ldap_result( conn, op, + rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return( -1 ); } @@ -178,7 +229,8 @@ ldbm_back_add( if ( id2children_add( be, p, e ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "id2children_add failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -192,7 +244,8 @@ ldbm_back_add( if ( index_add_entry( be, e ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "index_add_entry failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -201,7 +254,8 @@ ldbm_back_add( if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) { Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -211,12 +265,14 @@ ldbm_back_add( Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0, 0, 0 ); (void) dn2id_delete( be, e->e_ndn ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; return_results:; diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c index 93efcf6ca4..470ba0a7e1 100644 --- a/servers/slapd/back-ldbm/alias.c +++ b/servers/slapd/back-ldbm/alias.c @@ -1,13 +1,6 @@ /* - * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC - * 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 ITSD, Government of BC. The name of ITSD - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. This software - * is provided ``as is'' without express or implied warranty. + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ #include "portable.h" @@ -19,303 +12,274 @@ #include "back-ldbm.h" #include "proto-back-ldbm.h" -/* - * given an alias object, dereference it to its end point. - * Entry returned has reader lock or is NULL. Starting entry is not released. - */ -Entry *derefAlias_r ( Backend *be, - Connection *conn, - Operation *op, - Entry *e) + +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ); + +static char* new_superior( + char *dn, + char *oldSup, + char *newSup ); + +static int dnlist_subordinate( + char** dnlist, + char *dn ); + +Entry *deref_internal_r( + Backend* be, + Entry* alias, + char* dn, + int* err, + Entry** matched, + char** text ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + char **dnlist; + + assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) ); + + *matched = NULL; + *err = LDAP_SUCCESS; + *text = NULL; + + if( alias == NULL ) { + dn = ch_strdup( dn ); + entry = dn2entry_r( be, dn, &sup ); + + } else { + dn = ch_strdup( alias->e_ndn ); + entry = alias; + sup = NULL; + } + + dnlist = NULL; + charray_add( &dnlist, dn ); + + for( depth=0 ; ; depth++ ) { + if( entry != NULL ) { + Entry *newe; + char *aliasDN; + + /* have entry, may be an alias */ + + if( !is_entry_alias( entry ) ) { + /* entry is not an alias */ + break; + } + + /* entry is alias */ + if( depth > be->be_max_deref_depth ) { + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_DEREF_PROBLEM; + *text = "maximum deref depth exceeded"; + break; + } + + /* deref entry */ + aliasDN = get_alias_dn( entry, err, text ); + + if( aliasDN == NULL ) { + *matched = entry; + entry = NULL; + break; + } + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, aliasDN ) ) { + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_PROBLEM; + *text = "circular alias"; + break; + } + + /* attempt to dereference alias */ + + newe = dn2entry_r( be, aliasDN, &sup ); + + if( newe != NULL ) { + free( dn ); + cache_return_entry_r(&li->li_cache, entry ); + entry = newe; + dn = ch_strdup( entry->e_ndn ); + charray_add( &dnlist, dn ); + continue; + + } + + if ( sup != NULL ) { + cache_return_entry_r(&li->li_cache, entry ); + entry = NULL; + continue; + } + + /* no newe and no superior, we're done */ + break; + + } else if( sup != NULL ) { + /* have superior, may be an alias */ + Entry *newe; + Entry *newSup; + char *supDN; + char *aliasDN; + + if( !is_entry_alias( sup ) ) { + /* entry is not an alias */ + *matched = sup; + sup = NULL; + break; + } + + /* entry is alias */ + if( depth > be->be_max_deref_depth ) { + *matched = sup; + entry = NULL; + *err = LDAP_ALIAS_DEREF_PROBLEM; + *text = "maximum deref depth exceeded"; + break; + } + + /* deref entry */ + supDN = get_alias_dn( sup, err, text ); + + if( supDN == NULL ) { + *matched = sup; + break; + } + + aliasDN = new_superior( dn, sup->e_ndn, supDN ); + + if( aliasDN == NULL ) { + free(aliasDN); + *matched = sup; + *err = LDAP_ALIAS_PROBLEM; + *text = "superior alias problem"; + break; + } + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, aliasDN ) ) { + free(aliasDN); + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_PROBLEM; + *text = "subordinate circular alias"; + break; + } + + /* attempt to dereference alias */ + newe = dn2entry_r( be, aliasDN, &newSup ); + + if( newe != NULL ) { + free(aliasDN); + free( dn ); + cache_return_entry_r(&li->li_cache, sup ); + entry = newe; + dn = ch_strdup( entry->e_ndn ); + charray_add( &dnlist, dn ); + continue; + + } + + if ( newSup != NULL ) { + free( dn ); + cache_return_entry_r(&li->li_cache, sup ); + sup = newSup; + dn = aliasDN; + continue; + } + + break; + + } else { + /* no newe and no superior, we're done */ + break; + } + } + + free( dn ); + return entry; +} + + +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ) +{ + Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" ); + + if( a == NULL ) { + /* + * there was an aliasedobjectname defined but no data. + */ + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName attribute"; + return NULL; + } + + /* + * aliasedObjectName should be SINGLE-VALUED with a single value. + */ + if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val != NULL ) { + /* + * there was an aliasedobjectname defined but no data. + */ + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName value"; + return NULL; + } + + if( a->a_vals[1] != NULL ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias has multivalued aliasedObjectName"; + return NULL; + } + + return a->a_vals[0]->bv_val; +} + +char* new_superior( + char *dn, + char *oldSup, + char *newSup ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; /* to free cache entries */ - Attribute *a; - int depth; - char *matched; - Entry *origDN = e; - - if (!e) return NULL; /* be sure we have a starting entry */ - - Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 ); - - /* - * try to deref fully, up to a maximum depth. If the max depth exceeded - * then send an error - */ - for ( depth = 0; - ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) && - ( depth < be->be_maxDerefDepth ); - ++depth) - { - - /* - * make sure there is a defined aliasedobjectname. - * can only have one value so just use first value (0) in the attr list. - */ - if (a->a_vals[0] && a->a_vals[0]->bv_val) { - char *newDN, *oldDN; - - Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", - e->e_dn, a->a_vals[0]->bv_val, 0 ); - newDN = ch_strdup (a->a_vals[0]->bv_val); - oldDN = ch_strdup (e->e_ndn); - - /* - * release past lock if not original - */ - if ( (depth > 0) && e ) { - cache_return_entry_r(&li->li_cache, e); - } - - /* make sure new and old DN are not same to avoid loops */ - dn_normalize_case (newDN); - if ( strcmp (newDN, oldDN) == 0 ) { - - Debug( LDAP_DEBUG_TRACE, - "<= %s alias is same as current %s\n", - oldDN, newDN, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Circular alias" ); - free (newDN); - free (oldDN); - break; - } - - /* make sure new and original are not same to avoid deadlocks */ - if ( strcmp (newDN, origDN->e_ndn) == 0 ) { - Debug( LDAP_DEBUG_TRACE, - "<= %s alias is same as original %s\n", - oldDN, origDN->e_ndn, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Circular alias" ); - free (newDN); - free (oldDN); - break; - } - - /* - * ok, so what happens if there is an alias in the DN of a dereferenced - * alias object? - */ - if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) { - - /* could not deref return error */ - Debug( LDAP_DEBUG_TRACE, - "<= %s is a dangling alias to %s\n", - oldDN, newDN, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Dangling Alias" ); - - if (matched != NULL) free(matched); - free (newDN); - free (oldDN); - break; - } - - free (newDN); - free (oldDN); - } - else { - /* - * there was an aliasedobjectname defined but no data. - * this can't happen, right? - */ - Debug( LDAP_DEBUG_TRACE, - "<= %s has no data in aliasedobjectname attribute\n", - (e && e->e_dn) ? e->e_dn : "(null)", 0, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "", - "Alias missing aliasedobjectname" ); - break; - } - } - - /* - * warn if we pulled out due to exceeding the maximum deref depth - */ - if ( depth >= be->be_maxDerefDepth ) { - Debug( LDAP_DEBUG_TRACE, - "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n", - origDN->e_dn ? origDN->e_dn : "(null)", - be->be_maxDerefDepth, - (e && e->e_ndn) ? e->e_ndn : "(null)"); - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Maximum alias dereference depth exceeded" ); - } - - return e; + char *newDN; + size_t dnlen, olen, nlen; + assert( dn && oldSup && newSup ); + + dnlen = strlen( dn ); + olen = strlen( oldSup ); + nlen = strlen( newSup ); + + newDN = ch_malloc( dnlen - olen + nlen + 1 ); + + memcpy( newDN, dn, dnlen - olen ); + memcpy( &newDN[dnlen - olen], newSup, nlen ); + newDN[dnlen - olen + nlen] = '\0'; + + return newDN; } -/* - * given a DN fully deref it and return the real DN or original DN if it fails - * This involves finding the last matched part then reconstructing forward - * e.g. - * ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg - * loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry - * dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched - * dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry - * remainder is ou=MyOU - * dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry - * release lock on o=MyAliasedOrg,c=MyCountry entry - * reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry - * release lock on o=MyOrg,c=MyCountry entry - */ -char *derefDN ( Backend *be, - Connection *conn, - Operation *op, - char *dn -) +static int dnlist_subordinate( + char** dnlist, + char *dn ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = 0; - char *newDN = NULL; - int depth, i; - Entry *eMatched; - Entry *eDeref; - Entry *eNew; - - if (!dn) return NULL; - - Debug( LDAP_DEBUG_TRACE, - "<= dereferencing dn: \"%s\"\n", - dn, 0, 0 ); - - newDN = ch_strdup ( dn ); - - /* while we don't have a matched dn, deref the DN */ - for ( depth = 0; - ( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) && - (depth < be->be_maxDerefDepth); - ++depth ) { - - if ((matched != NULL) && *matched) { - char *submatch; - - /* - * make sure there actually is an entry for the matched part - */ - if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) { - char *remainder; /* part before the aliased part */ - int rlen = strlen(newDN) - strlen(matched); - - Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 ); - - remainder = ch_malloc (rlen + 1); - strncpy ( remainder, newDN, rlen ); - remainder[rlen] = '\0'; - - Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 ); - - if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) { - free (matched); - matched = NULL; - free (newDN); - newDN = NULL; - free (remainder); - remainder = NULL; - - cache_return_entry_r(&li->li_cache, eMatched); - eMatched = NULL; - break; /* no associated entry, dont deref */ - } - else { - - Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 ); - - i = strcasecmp (matched, eNew->e_dn); - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eNew); - - free (matched); - matched = NULL; - - if (! i) { - /* newDN same as old so not an alias, no need to go further */ - free (newDN); - newDN = NULL; - free (remainder); - - cache_return_entry_r(&li->li_cache, eMatched); - eMatched = NULL; - break; - } - - /* - * we have dereferenced the aliased part so put - * the new dn together - */ - free (newDN); - newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1); - strcpy (newDN, remainder); - strcat (newDN, eMatched->e_dn); - Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 ); - - free (remainder); + int i; + assert( dnlist ); + + for( i = 0; dnlist[i] != NULL; i++ ) { + if( dn_issuffix( dnlist[i], dn ) ) { + return 1; + } } - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eMatched); - } - else { - if(submatch != NULL) free(submatch); - break; /* there was no entry for the matched part */ - } - } - else { - break; /* there was no matched part */ - } - } - - /* release lock if a match terminated the loop, there should be no - * outstanding locks at this point - */ - if(eMatched != NULL) { - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eMatched); - } - - /* - * the final part of the DN might be an alias so try to dereference it. - * e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match - * and the above loop complete but we would still be left with an aliased DN. - */ - if (newDN != NULL) { - if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) { - if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) { - free (newDN); - newDN = ch_strdup (eDeref->e_dn); - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eDeref); - } - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eNew); - } - } - if (matched != NULL) free(matched); - - /* - * warn if we exceeded the max depth as the resulting DN may not be dereferenced - */ - if (depth >= be->be_maxDerefDepth) { - if (newDN) { - Debug( LDAP_DEBUG_TRACE, - "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n", - dn, newDN, 0 ); - free (newDN); - newDN = NULL; - } - else { - Debug( LDAP_DEBUG_TRACE, - "<= max deref depth exceeded in derefDN for \"%s\", result NULL\n", - dn, 0, 0 ); - } - send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "", - "Maximum alias dereference depth exceeded for base" ); - } - - if (newDN == NULL) { - newDN = ch_strdup ( dn ); - } - - Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); - - return newDN; + + return 0; } + diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c index 1821c9b4cc..dad6b9e2ac 100644 --- a/servers/slapd/back-ldbm/bind.c +++ b/servers/slapd/back-ldbm/bind.c @@ -74,7 +74,7 @@ ldbm_back_bind( Entry *e; Attribute *a; int rc; - char *matched; + Entry *matched; #ifdef HAVE_KERBEROS char krbname[MAX_K_NAME_SZ + 1]; AUTH_DAT ad; @@ -86,39 +86,57 @@ ldbm_back_bind( /* get entry with reader lock */ if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + + 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 = default_referral; + } + /* allow noauth binds */ rc = 1; if ( method == LDAP_AUTH_SIMPLE ) { if( cred->bv_len == 0 ) { /* SUCCESS */ - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } else if ( be_isroot_pw( be, dn, cred ) ) { *edn = ch_strdup( be_root_dn( be ) ); rc = 0; /* front end will send result */ } else { - send_ldap_result( conn, op, - LDAP_NO_SUCH_OBJECT, matched, NULL ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); } } else if ( method == LDAP_AUTH_SASL ) { if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) { /* insert DIGEST calls here */ - send_ldap_result( conn, op, - LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL ); + send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, - LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL ); + send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, NULL, NULL, NULL ); } } else { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, NULL ); + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); } if ( matched != NULL ) { - free( matched ); + ber_bvecfree( refs ); + free( matched_dn ); } return( rc ); } @@ -130,7 +148,37 @@ ldbm_back_bind( if ( ! access_allowed( be, conn, op, e, "entry", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); + rc = 1; + goto return_results; + } + + if ( is_entry_alias( e ) ) { + /* entry is an alias, don't allow bind */ + Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, NULL, NULL, NULL ); + + rc = 1; + goto return_results; + } + + if ( is_entry_referral( e ) ) { + /* entry is a referral, don't allow bind */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + rc = 1; goto return_results; } @@ -138,7 +186,8 @@ ldbm_back_bind( switch ( method ) { case LDAP_AUTH_SIMPLE: if ( cred->bv_len == 0 ) { - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; @@ -157,14 +206,15 @@ ldbm_back_bind( if ( ! access_allowed( be, conn, op, e, "userpassword", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) { send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, - NULL, NULL ); + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; @@ -174,7 +224,7 @@ ldbm_back_bind( if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 ) { send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, - NULL, NULL ); + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; goto return_results; @@ -188,14 +238,15 @@ ldbm_back_bind( if ( ! access_allowed( be, conn, op, e, "krbname", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) { send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, - NULL, NULL ); + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } @@ -203,7 +254,8 @@ ldbm_back_bind( if ( ! access_allowed( be, conn, op, e, "krbname", NULL, ACL_AUTH ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } @@ -221,7 +273,7 @@ ldbm_back_bind( break; } send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, - NULL, NULL ); + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; @@ -233,7 +285,8 @@ ldbm_back_bind( if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) { send_ldap_result( conn, op, - LDAP_INVALID_CREDENTIALS, NULL, NULL ); + LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } @@ -242,7 +295,8 @@ ldbm_back_bind( break; case LDAP_AUTH_KRBV42: - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); /* stop front end from sending result */ rc = 1; goto return_results; @@ -253,7 +307,7 @@ ldbm_back_bind( default: send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED, - NULL, "auth method not supported" ); + NULL, "auth method not supported", NULL, NULL ); rc = 1; goto return_results; } diff --git a/servers/slapd/back-ldbm/compare.c b/servers/slapd/back-ldbm/compare.c index fc6e171444..acc5571e5a 100644 --- a/servers/slapd/back-ldbm/compare.c +++ b/servers/slapd/back-ldbm/compare.c @@ -21,38 +21,77 @@ ldbm_back_compare( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; + Entry *matched; Entry *e; Attribute *a; int rc; + int manageDSAit = get_manageDSAit( op ); /* get entry with reader lock */ if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + char *matched_dn = NULL; + struct berval **refs = NULL; + + 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 = default_referral; + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } - if(matched == NULL) free(matched); return( 1 ); } - /* check for deleted */ + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + rc = 1; + goto return_results; + } + if ( ! access_allowed( be, conn, op, e, ava->ava_type, &ava->ava_value, ACL_COMPARE ) ) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" ); + send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, + NULL, NULL, NULL, NULL ); rc = 1; goto return_results; } if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) - send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_TRUE, + NULL, NULL, NULL, NULL ); else - send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, + NULL, NULL, NULL, NULL ); rc = 0; diff --git a/servers/slapd/back-ldbm/delete.c b/servers/slapd/back-ldbm/delete.c index d0be72d6c6..53bdd22f7c 100644 --- a/servers/slapd/back-ldbm/delete.c +++ b/servers/slapd/back-ldbm/delete.c @@ -20,33 +20,42 @@ ldbm_back_delete( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = NULL; + Entry *matched = NULL; char *pdn = NULL; Entry *e, *p = NULL; int rootlock = 0; int rc = -1; + int manageDSAit = get_manageDSAit( op ); Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn, 0, 0); /* get entry with writer lock */ if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: no such object %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + if ( matched != NULL ) { - free( matched ); + 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 = default_referral; } - return( -1 ); - } - /* check for deleted */ + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); - if ( has_children( be, e ) ) { - Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n", - dn, 0, 0); - send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "", - "" ); - goto return_results; + if ( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + return( -1 ); } #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL @@ -56,11 +65,39 @@ ldbm_back_delete( Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: insufficient access %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" ); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL, NULL ); goto return_results; } #endif + if ( !manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + rc = 1; + goto return_results; + } + + + if ( has_children( be, e ) ) { + Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n", + dn, 0, 0); + send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, + NULL, NULL, NULL, NULL ); + goto return_results; + } + /* delete from parent's id2children entry */ if( (pdn = dn_parent( be, e->e_ndn )) != NULL ) { if( (p = dn2entry_w( be, pdn, &matched )) == NULL) { @@ -68,7 +105,7 @@ ldbm_back_delete( "<=- ldbm_back_delete: parent does not exist\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -80,7 +117,7 @@ ldbm_back_delete( "<=- ldbm_back_delete: no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -91,7 +128,7 @@ ldbm_back_delete( "<=- ldbm_back_delete: no parent & not root\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -103,7 +140,8 @@ ldbm_back_delete( Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "","" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -112,7 +150,8 @@ ldbm_back_delete( Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -121,11 +160,13 @@ ldbm_back_delete( Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: operations error %s\n", dn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; return_results:; diff --git a/servers/slapd/back-ldbm/dn2id.c b/servers/slapd/back-ldbm/dn2id.c index a29557e11d..c361418e3c 100644 --- a/servers/slapd/back-ldbm/dn2id.c +++ b/servers/slapd/back-ldbm/dn2id.c @@ -156,7 +156,7 @@ Entry * dn2entry_rw( Backend *be, char *dn, - char **matched, + Entry **matched, int rw ) { @@ -168,7 +168,10 @@ dn2entry_rw( Debug(LDAP_DEBUG_TRACE, "dn2entry_%s: dn: \"%s\"\n", rw ? "w" : "r", dn, 0); - *matched = NULL; + if( matched != NULL ) { + /* caller cares about match */ + *matched = NULL; + } if ( (id = dn2id( be, dn )) != NOID && (e = id2entry_rw( be, id, rw )) != NULL ) @@ -184,26 +187,19 @@ dn2entry_rw( /* treat as if NOID was found */ } - /* stop when we get to the suffix */ - if ( be_issuffix( be, dn ) ) { - return( NULL ); - } + /* caller doesn't care about match */ + if( matched == NULL ) return NULL; /* entry does not exist - see how much of the dn does exist */ + /* dn_parent checks returns NULL if dn is suffix */ if ( (pdn = dn_parent( be, dn )) != NULL ) { /* get entry with reader lock */ if ( (e = dn2entry_r( be, pdn, matched )) != NULL ) { - if(*matched != NULL) { - free(*matched); - } - *matched = pdn; - /* free entry with reader lock */ - cache_return_entry_r( &li->li_cache, e ); - } else { - free( pdn ); + *matched = e; } + free( pdn ); } - return( NULL ); + return NULL; } diff --git a/servers/slapd/back-ldbm/group.c b/servers/slapd/back-ldbm/group.c index 652892c828..c890cc49e1 100644 --- a/servers/slapd/back-ldbm/group.c +++ b/servers/slapd/back-ldbm/group.c @@ -26,24 +26,24 @@ ldbm_back_group( char *groupattrName ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e; - char *matched; - Attribute *objectClass; - Attribute *member; - int rc; - - Debug( LDAP_DEBUG_TRACE, + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + int rc = 1; + + Attribute *attr; + struct berval bv; + + Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: gr dn: \"%s\"\n", gr_ndn, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: op dn: \"%s\"\n", op_ndn, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: objectClass: \"%s\" attrName: \"%s\"\n", objectclassValue, groupattrName, 0 ); - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: tr dn: \"%s\"\n", target->e_ndn, 0, 0 ); @@ -52,73 +52,99 @@ ldbm_back_group( e = target; Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: target is group: \"%s\"\n", - gr_ndn, 0, 0 ); + gr_ndn, 0, 0 ); + } else { /* can we find group entry with reader lock */ - if ((e = dn2entry_r(be, gr_ndn, &matched )) == NULL) { - Debug( LDAP_DEBUG_TRACE, - "=> ldbm_back_group: cannot find group: \"%s\" matched: \"%s\"\n", - gr_ndn, (matched ? matched : ""), 0 ); - if (matched != NULL) - free(matched); + if ((e = dn2entry_r(be, gr_ndn, NULL )) == NULL) { + Debug( LDAP_DEBUG_ACL, + "=> ldbm_back_group: cannot find group: \"%s\"\n", + gr_ndn, 0, 0 ); return( 1 ); } - Debug( LDAP_DEBUG_ARGS, + + Debug( LDAP_DEBUG_ACL, "=> ldbm_back_group: found group: \"%s\"\n", gr_ndn, 0, 0 ); - } + } + /* 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; + + if ((attr = attr_find(e->e_attrs, "objectclass")) == NULL) { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: failed to find objectClass\n", 0, 0, 0 ); + goto return_results; + } + + bv.bv_val = "ALIAS"; + bv.bv_len = sizeof("ALIAS")-1; + + if ( value_find(attr->a_vals, &bv, attr->a_syntax, 1) == 0) { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: group is an alias\n", 0, 0, 0 ); + goto return_results; + } - /* check for deleted */ + bv.bv_val = "REFERRAL"; + bv.bv_len = sizeof("REFERRAL")-1; - /* 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; - if ((objectClass = attr_find(e->e_attrs, "objectclass")) == NULL) { - Debug( LDAP_DEBUG_TRACE, "<= ldbm_back_group: failed to find objectClass\n", 0, 0, 0 ); - } - else if ((member = attr_find(e->e_attrs, groupattrName)) == NULL) { - Debug( LDAP_DEBUG_TRACE, "<= ldbm_back_group: failed to find %s\n", groupattrName, 0, 0 ); - } - else { - struct berval bvObjectClass; - struct berval bvMembers; - - Debug( LDAP_DEBUG_ARGS, "<= ldbm_back_group: found objectClass and %s\n", groupattrName, 0, 0 ); - - bvObjectClass.bv_val = objectclassValue; - bvObjectClass.bv_len = strlen( bvObjectClass.bv_val ); - - bvMembers.bv_val = op_ndn; - bvMembers.bv_len = strlen( op_ndn ); - - if (value_find(objectClass->a_vals, &bvObjectClass, SYNTAX_CIS, 1) != 0) { - Debug( LDAP_DEBUG_TRACE, - "<= ldbm_back_group: failed to find %s in objectClass\n", - objectclassValue, 0, 0 ); - } - else if (value_find(member->a_vals, &bvMembers, SYNTAX_CIS, 1) != 0) { - Debug( LDAP_DEBUG_ACL, - "<= ldbm_back_group: \"%s\" not in \"%s\": %s\n", - op_ndn, gr_ndn, groupattrName ); - } - else { - Debug( LDAP_DEBUG_ACL, - "<= ldbm_back_group: \"%s\" is in \"%s\": %s\n", - op_ndn, gr_ndn, groupattrName ); - rc = 0; - } - } + if ( value_find(attr->a_vals, &bv, attr->a_syntax, 1) == 0) { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: group is a referral\n", + 0, 0, 0 ); + goto return_results; + } + + bv.bv_val = objectclassValue; + bv.bv_len = strlen( bv.bv_val ); + + if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: failed to find %s in objectClass\n", + objectclassValue, 0, 0 ); + goto return_results; + } + + if ((attr = attr_find(e->e_attrs, groupattrName)) == NULL) { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: failed to find %s\n", + groupattrName, 0, 0 ); + goto return_results; + } + + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: found objectClass %s and %s\n", + objectclassValue, groupattrName, 0 ); + + bv.bv_val = op_ndn; + bv.bv_len = strlen( op_ndn ); + + if( value_find( attr->a_vals, &bv, attr->a_syntax, 1) != 0 ) + { + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: \"%s\" not in \"%s\": %s\n", + op_ndn, gr_ndn, groupattrName ); + goto return_results; + } + + Debug( LDAP_DEBUG_ACL, + "<= ldbm_back_group: \"%s\" is in \"%s\": %s\n", + op_ndn, gr_ndn, groupattrName ); + + rc = 0; +return_results: if( target != e ) { /* free entry and reader lock */ cache_return_entry_r( &li->li_cache, e ); } - Debug( LDAP_DEBUG_ARGS, "ldbm_back_group: rc: %d\n", rc, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "ldbm_back_group: rc=%d\n", rc, 0, 0 ); return(rc); } diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 9ae8220543..d9e9b8ed4c 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -120,8 +120,10 @@ int ldbm_modify_internal( if ( (err = acl_check_modlist( be, conn, op, e, modlist )) - != LDAP_SUCCESS ) { - send_ldap_result( conn, op, err, NULL, NULL ); + != LDAP_SUCCESS ) + { + send_ldap_result( conn, op, err, + NULL, NULL, NULL, NULL ); return -1; } @@ -173,7 +175,8 @@ int ldbm_modify_internal( if ( err != LDAP_SUCCESS ) { /* unlock entry, delete from cache */ - send_ldap_result( conn, op, err, NULL, NULL ); + send_ldap_result( conn, op, err, + NULL, NULL, NULL, NULL ); return -1; } } @@ -181,7 +184,8 @@ int ldbm_modify_internal( /* check that the entry still obeys the schema */ if ( global_schemacheck && oc_schema_check( e ) != 0 ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL, NULL ); return -1; } @@ -195,7 +199,8 @@ int ldbm_modify_internal( /* modify indexes */ if ( index_add_mods( be, modlist, e->e_id ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); return -1; } @@ -222,35 +227,69 @@ ldbm_back_modify( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; + Entry *matched; Entry *e; + int manageDSAit = get_manageDSAit( op ); Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0); /* acquire and lock entry */ if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, - NULL ); + char* matched_dn = NULL; + struct berval **refs = NULL; + if ( matched != NULL ) { - free( matched ); + 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 = default_referral; } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + if ( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + return( -1 ); } + if ( !manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + goto error_return; + } + /* Modify the entry */ if ( ldbm_modify_internal( be, conn, op, dn, modlist, e ) != 0 ) { - goto error_return; - } /* change the entry itself */ if ( id2entry_add( be, e ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto error_return; } - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); cache_return_entry_w( &li->li_cache, e ); return( 0 ); diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index 5a606acb9b..4f743c473c 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -39,10 +39,10 @@ ldbm_back_modrdn( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched = NULL; char *p_dn = NULL, *p_ndn = NULL; char *new_dn = NULL, *new_ndn = NULL; Entry *e, *p = NULL; + Entry *matched = NULL; int rootlock = 0; int rc = -1; /* Added to support LDAP v2 correctly (deleteoldrdn thing) */ @@ -62,7 +62,7 @@ ldbm_back_modrdn( struct berval del_bv; /* Stores old rdn att */ struct berval *del_bvals[2]; /* Stores old rdn att */ LDAPModList mod[2]; /* Used to delete old rdn */ - + int manageDSAit = get_manageDSAit( op ); Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n", (newSuperior ? newSuperior : "NULL"), @@ -70,29 +70,62 @@ ldbm_back_modrdn( /* get entry with writer lock */ if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" ); + char* matched_dn = NULL; + struct berval** refs = NULL; + + 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 = default_referral; + } + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + if ( matched != NULL ) { - free( matched ); + ber_bvecfree( refs ); + free( matched_dn ); } + return( -1 ); } #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL - /* check parent for "children" acl */ if ( ! access_allowed( be, conn, op, e, "entry", NULL, ACL_WRITE ) ) { Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } #endif + if (!manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + e->e_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + + goto return_results; + } + if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) { - /* Make sure parent entry exist and we can write its + /* Make sure parent entry exist and we can write its * children. */ @@ -100,7 +133,7 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -111,7 +144,7 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -131,7 +164,7 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0, 0, 0); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", ""); + NULL, NULL, NULL, NULL ); goto return_results; } @@ -162,12 +195,11 @@ ldbm_back_modrdn( /* Get Entry with dn=newSuperior. Does newSuperior exist? */ if( (np = dn2entry_w( be, np_ndn, &matched )) == NULL) { - Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: newSup(ndn=%s) not here!\n", np_ndn, 0, 0); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", - ""); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -183,7 +215,30 @@ ldbm_back_modrdn( "ldbm_back_modrdn: no wr to newSup children\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); + NULL, NULL, NULL, NULL ); + goto return_results; + } + + if ( is_entry_alias( np ) ) { + /* entry is an alias, don't allow bind */ + Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, + NULL, NULL, NULL, NULL ); + + goto return_results; + } + + if ( is_entry_referral( np ) ) { + /* parent is a referral, don't allow add */ + /* parent is an alias, don't allow add */ + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); + goto return_results; } @@ -191,9 +246,7 @@ ldbm_back_modrdn( "ldbm_back_modrdn: wr to new parent's children OK\n", 0, 0 , 0 ); - new_parent_dn = np_dn; - } /* Build target dn and make sure target entry doesn't exist already. */ @@ -207,7 +260,8 @@ ldbm_back_modrdn( new_ndn, 0, 0 ); if (dn2id ( be, new_ndn ) != NOID) { - send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -225,7 +279,8 @@ ldbm_back_modrdn( /* delete old one */ if ( dn2id_delete( be, e->e_ndn ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -237,7 +292,8 @@ ldbm_back_modrdn( /* add new one */ if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -251,7 +307,8 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out type of newrdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -261,7 +318,8 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out val of newrdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -277,7 +335,8 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out old_rdn from dn\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -287,7 +346,8 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out the old_rdn type\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -323,7 +383,6 @@ ldbm_back_modrdn( /* Remove old rdn value if required */ if (deleteoldrdn) { - /* Get value of old rdn */ if ((old_rdn_val = rdn_attr_value( old_rdn )) @@ -332,12 +391,9 @@ ldbm_back_modrdn( Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n", 0, 0, 0 ); - send_ldap_result( conn, op, - LDAP_OPERATIONS_ERROR, - "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; - - } del_bvals[0] = &del_bv; /* Array of bervals */ @@ -374,8 +430,8 @@ ldbm_back_modrdn( "ldbm_back_modrdn: not fully implemented...\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - NULL ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results; } @@ -397,11 +453,13 @@ ldbm_back_modrdn( /* id2entry index */ if ( id2entry_add( be, e ) != 0 ) { entry_free( e ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); goto return_results_after; } - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); rc = 0; goto return_results_after; diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h index a5066eff8b..6c2f90da0a 100644 --- a/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -10,16 +10,18 @@ LDAP_BEGIN_DECL /* * alias.c */ -Entry *derefAlias_r LDAP_P(( - Backend *be, - Connection *conn, - Operation *op, - Entry *e )); -char *derefDN LDAP_P(( - Backend *be, - Connection *conn, - Operation *op, - char *dn )); +Entry *deref_internal_r LDAP_P(( + Backend *be, + Entry *e, + char *dn, + int *err, + Entry **matched, + char **text )); + +#define deref_entry_r( be, e, err, matched, text ) \ + deref_internal_r( be, e, NULL, err, matched, text ) +#define deref_dn_r( be, dn, err, matched, text ) \ + deref_internal_r( be, NULL, dn, err, matched, text) /* * attr.c @@ -71,7 +73,7 @@ int dn2id_add LDAP_P(( Backend *be, char *dn, ID id )); ID dn2id LDAP_P(( Backend *be, char *dn )); int dn2id_delete LDAP_P(( Backend *be, char *dn )); -Entry * dn2entry_rw LDAP_P(( Backend *be, char *dn, char **matched, int rw )); +Entry * dn2entry_rw LDAP_P(( Backend *be, char *dn, Entry **matched, int rw )); #define dn2entry_r(be, dn, m) dn2entry_rw((be), (dn), (m), 0) #define dn2entry_w(be, dn, m) dn2entry_rw((be), (dn), (m), 1) diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 7ab4f5f761..dbbf761487 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -11,20 +11,13 @@ #include "back-ldbm.h" #include "proto-back-ldbm.h" -static ID_BLOCK *base_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err); -static ID_BLOCK *onelevel_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err); -static ID_BLOCK *subtree_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase); - -#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; \ - } \ -} +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 ); + int ldbm_back_search( @@ -43,19 +36,76 @@ ldbm_back_search( ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int err; + int rc, err; + char *text; time_t stoptime; ID_BLOCK *candidates; ID id; Entry *e; - Attribute *ref; - char *matched = NULL; - int rmaxsize, nrefs; - char *rbuf, *rcur; + struct berval **v2refs = NULL; + Entry *matched = NULL; + char *realbase = NULL; int nentries = 0; - char *realBase; + int manageDSAit = get_manageDSAit( op ); + + Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0); + + /* get entry with reader lock */ + if ( deref & LDAP_DEREF_FINDING ) { + e = deref_dn_r( be, base, &err, &matched, &text ); - Debug(LDAP_DEBUG_ARGS, "=> ldbm_back_search\n", 0, 0, 0); + } else { + e = dn2entry_r( be, base, &matched ); + err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL; + text = NULL; + } + + if ( e == NULL ) { + char *matched_dn = NULL; + struct berval **refs = NULL; + + 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 = default_referral; + } + + send_ldap_result( conn, op, err, + matched_dn, text, refs, NULL ); + + if( matched != NULL ) { + ber_bvecfree( refs ); + free( matched_dn ); + } + + return 1; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* entry is a referral, don't allow add */ + char *matched_dn = ch_strdup( e->e_dn ); + struct berval **refs = get_entry_referrals( be, + conn, op, e ); + + cache_return_entry_r( &li->li_cache, e ); + + Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + 0, 0 ); + + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + + ber_bvecfree( refs ); + free( matched_dn ); + + return 1; + } if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) { tlimit = -1; /* allow root to set no limit */ @@ -64,6 +114,7 @@ ldbm_back_search( 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 { @@ -71,220 +122,183 @@ ldbm_back_search( be->be_sizelimit : slimit; } - /* - * check and apply aliasing where the dereferencing applies to - * the subordinates of the base - */ - - switch ( deref ) { - case LDAP_DEREF_FINDING: - case LDAP_DEREF_ALWAYS: - realBase = derefDN ( be, conn, op, base ); - break; - default: - realBase = ch_strdup(base); - } - - (void) dn_normalize_case( realBase ); - - Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n", - realBase, 0, 0 ); - - switch ( scope ) { - case LDAP_SCOPE_BASE: - candidates = base_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, &err ); - break; + if ( scope == LDAP_SCOPE_BASE) { + candidates = base_candidate( be, e ); - case LDAP_SCOPE_ONELEVEL: - candidates = onelevel_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, &err ); - break; - - case LDAP_SCOPE_SUBTREE: - candidates = subtree_candidates( be, conn, op, realBase, filter, - attrs, attrsonly, &matched, NULL, &err, 1 ); - break; - - default: - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "", - "Bad scope" ); - if( realBase != NULL) { - free( realBase ); - } - return( -1 ); + } else { + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); } - /* null candidates means we could not find the base object */ + /* need normalized dn below */ + realbase = ch_strdup( e->e_ndn ); + cache_return_entry_r( &li->li_cache, e ); + if ( candidates == NULL ) { - send_ldap_result( conn, op, err, matched, "" ); - if ( matched != NULL ) { - free( matched ); - } - if( realBase != NULL) { - free( realBase ); - } - return( -1 ); - } + /* no candidates */ + Debug( LDAP_DEBUG_TRACE, "no candidates\n", 0, + 0, 0 ); + + send_search_result( conn, op, + LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 0 ); - if ( matched != NULL ) { - free( matched ); + rc = 1; + goto done; } - 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 ) ) { + id = idl_nextid( candidates, id ) ) + { + int scopeok = 0; /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - idl_free( candidates ); - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); + rc = 0; + goto done; } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); /* check time limit */ if ( tlimit != -1 && slap_get_time() > stoptime ) { - send_ldap_search_result( conn, op, - LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf : - NULL, nentries ); - idl_free( candidates ); - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); + send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, v2refs, NULL, nentries ); + rc = 0; + goto done; } /* get the entry with reader lock */ - if ( (e = id2entry_r( be, id )) == NULL ) { - Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n", - id, 0, 0 ); - continue; + e = id2entry_r( be, id ); + + if ( e == NULL ) { + Debug( LDAP_DEBUG_ARGS, "search: candidate %ld not found\n", + id, 0, 0 ); + + goto loop_continue; + } + + if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) { + Entry *matched; + int err; + 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 ) { + char *pdn = dn_parent( NULL, e->e_ndn ); + if ( pdn != NULL ) { + if( strcmp( pdn, realbase ) ) { + free( pdn ); + goto loop_continue; + } + free(pdn); + } + + } else if ( dn_issuffix( e->e_ndn, realbase ) ) { + /* alias is within scope */ + Debug( LDAP_DEBUG_ARGS, "search: \"%s\" in subtree\n", + e->e_dn, 0, 0 ); + 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 ( scope == LDAP_SCOPE_SUBTREE && - e->e_ndn != NULL && - strncmp( e->e_ndn, "REF=", 4 ) == 0 && - (ref = attr_find( e->e_attrs, "ref" )) != NULL ) + if ( !manageDSAit && scope != LDAP_SCOPE_BASE && + is_entry_referral( e ) ) { - int i; + struct berval **refs = get_entry_referrals( + be, conn, op, e ); - if ( ref->a_vals == NULL ) { - Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", - e->e_dn, 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++; - } - } + send_search_reference( be, conn, op, + e, refs, scope, NULL, &v2refs ); - /* 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; + ber_bvecfree( refs ); - /* check scope */ - scopeok = 1; - if ( scope == LDAP_SCOPE_ONELEVEL ) { - if ( (dn = dn_parent( be, e->e_dn )) != NULL ) { - (void) dn_normalize_case( dn ); - scopeok = (dn == realBase) - ? 1 - : (strcmp( dn, realBase ) ? 0 : 1 ); - free( dn ); - } else { - scopeok = (realBase == NULL || *realBase == '\0'); - } - } else if ( scope == LDAP_SCOPE_SUBTREE ) { - dn = ch_strdup( e->e_ndn ); - scopeok = dn_issuffix( dn, realBase ); + goto loop_continue; + } + + /* if it matches the filter and scope, send it */ + if ( test_filter( be, conn, op, e, filter ) == 0 ) { + char *dn; + + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( (dn = dn_parent( be, e->e_ndn )) != NULL ) { + (void) dn_normalize_case( dn ); + scopeok = (dn == realbase) + ? 1 + : (strcmp( dn, realbase ) ? 0 : 1 ); free( dn ); + + } else { + scopeok = (realbase == NULL || *realbase == '\0'); } - if ( scopeok ) { - /* check size limit */ - if ( --slimit == -1 ) { - cache_return_entry_r( &li->li_cache, e ); - send_ldap_search_result( conn, op, - LDAP_SIZELIMIT_EXCEEDED, NULL, - nrefs > 0 ? rbuf : NULL, nentries ); - idl_free( candidates ); - free( rbuf ); - - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); - } + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + dn = ch_strdup( e->e_ndn ); + scopeok = dn_issuffix( dn, realbase ); + free( dn ); + + } else { + scopeok = 1; + } + + 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; + } - /* - * check and apply aliasing where the dereferencing applies to - * the subordinates of the base - */ - switch ( deref ) { - case LDAP_DEREF_SEARCHING: - case LDAP_DEREF_ALWAYS: - { - Entry *newe = derefAlias_r( be, conn, op, e ); - if ( newe == NULL ) { /* problem with the alias */ - cache_return_entry_r( &li->li_cache, e ); - e = NULL; - } - else if ( newe != e ) { /* reassign e */ - cache_return_entry_r( &li->li_cache, e ); - e = newe; - } - } + if (e) { + switch ( send_search_entry( be, conn, op, e, + attrs, attrsonly, 0, NULL ) ) { + case 0: /* entry sent ok */ + nentries++; break; - } - if (e) { - switch ( send_search_entry( be, conn, op, e, - attrs, attrsonly, 0 ) ) { - case 0: /* entry sent ok */ - nentries++; - break; - case 1: /* entry not sent */ - break; - case -1: /* connection closed */ - cache_return_entry_r( &li->li_cache, e ); - idl_free( candidates ); - free( rbuf ); - - if( realBase != NULL) { - free( realBase ); - } - return( 0 ); - } + case 1: /* entry not sent */ + break; + case -1: /* connection closed */ + cache_return_entry_r( &li->li_cache, e ); + rc = 0; + goto done; } } + } else { + Debug( LDAP_DEBUG_TRACE, "candidate %ld scope not okay\n", + id, 0, 0 ); } + } else { + Debug( LDAP_DEBUG_TRACE, "candidate %ld does match filter\n", + id, 0, 0 ); } +loop_continue: if( e != NULL ) { /* free reader lock */ cache_return_entry_r( &li->li_cache, e ); @@ -292,209 +306,142 @@ ldbm_back_search( ldap_pvt_thread_yield(); } + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, NULL, nentries ); + + rc = 0; + +done: 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 ); - } - free( rbuf ); - if( realBase != NULL) { - free( realBase ); - } + ber_bvecfree( v2refs ); + if( realbase ) free( realbase ); - return( 0 ); + return rc; } static ID_BLOCK * -base_candidates( +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; ID_BLOCK *idl; - Entry *e; - - Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0); - *err = LDAP_SUCCESS; - - /* get entry with reader lock */ - if ( (e = dn2entry_r( be, base, matched )) == NULL ) { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } - - /* check for deleted */ + Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", + e->e_dn, 0, 0); idl = idl_alloc( 1 ); idl_insert( &idl, e->e_id, 1 ); - - /* free reader lock */ - cache_return_entry_r( &li->li_cache, e ); - return( idl ); } static ID_BLOCK * -onelevel_candidates( +search_candidates( Backend *be, - Connection *conn, - Operation *op, - char *base, + Entry *e, Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err + int scope, + int deref, + int manageDSAit ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e = NULL; - Filter *f; - char buf[20]; ID_BLOCK *candidates; + Filter *f, *rf, *af, *lf; - Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0); + Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" s=%d d=%d\n", + e->e_ndn, scope, deref ); - *err = LDAP_SUCCESS; + f = NULL; - /* get the base object with reader lock */ - if ( base != NULL && *base != '\0' && - (e = dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); + if( !manageDSAit ) { + /* match referrals */ + rf = (Filter *) ch_malloc( sizeof(Filter) ); + rf->f_next = NULL; + rf->f_choice = LDAP_FILTER_OR; + rf->f_or = (Filter *) ch_malloc( sizeof(Filter) ); + rf->f_or->f_choice = LDAP_FILTER_EQUALITY; + rf->f_or->f_avtype = ch_strdup( "objectclass" ); + rf->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" ); + rf->f_or->f_avvalue.bv_len = sizeof("REFERRAL")-1; + rf->f_or->f_next = filter; + f = rf; + } else { + rf = NULL; + f = filter; } - /* - * 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 = ch_strdup( "id2children" ); - sprintf( buf, "%ld", e != NULL ? e->e_id : 0 ); - f->f_and->f_ava.ava_value.bv_val = ch_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 ); - - /* free entry and reader lock */ - if( e != NULL ) { - cache_return_entry_r( &li->li_cache, e ); + if( deref & LDAP_DEREF_SEARCHING ) { + /* match aliases */ + af = (Filter *) ch_malloc( sizeof(Filter) ); + af->f_next = NULL; + af->f_choice = LDAP_FILTER_OR; + af->f_or = (Filter *) ch_malloc( sizeof(Filter) ); + af->f_or->f_choice = LDAP_FILTER_EQUALITY; + af->f_or->f_avtype = ch_strdup( "objectclass" ); + af->f_or->f_avvalue.bv_val = ch_strdup( "ALIAS" ); + af->f_or->f_avvalue.bv_len = sizeof("ALIAS")-1; + af->f_or->f_next = f; + f = af; + } else { + af = NULL; } - return( candidates ); -} -static ID_BLOCK * -subtree_candidates( - Backend *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - Entry *e, - int *err, - int lookupbase -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Filter *f, **filterarg_ptr; - ID_BLOCK *candidates; + if ( scope == LDAP_SCOPE_SUBTREE ) { + lf = (Filter *) ch_malloc( sizeof(Filter) ); + lf->f_next = NULL; + lf->f_choice = LDAP_FILTER_AND; + lf->f_and = (Filter *) ch_malloc( sizeof(Filter) ); - Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n", - base ? base : "NULL", lookupbase ? "lookupbase" : "", 0); - - /* - * 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 ) { - e = NULL; + lf->f_and->f_choice = LDAP_FILTER_SUBSTRINGS; + lf->f_and->f_sub_type = ch_strdup( "dn" ); + lf->f_and->f_sub_initial = NULL; + lf->f_and->f_sub_any = NULL; + lf->f_and->f_sub_final = ch_strdup( e->e_ndn ); - if ( base != NULL && *base != '\0' && - (e = dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } + lf->f_and->f_next = f; + f = lf; - if (e) { - cache_return_entry_r( &li->li_cache, e ); - } + } else if ( scope == LDAP_SCOPE_ONELEVEL ) { + char buf[16]; - 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 = ch_strdup( "objectclass" ); - /* Patch to use normalized uppercase */ - f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" ); - f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" ); - filterarg_ptr = &f->f_or->f_next; - *filterarg_ptr = 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 = ch_strdup( "dn" ); - f->f_and->f_sub_initial = NULL; - f->f_and->f_sub_any = NULL; - f->f_and->f_sub_final = ch_strdup( base ); - value_normalize( f->f_and->f_sub_final, SYNTAX_CIS ); - f->f_and->f_next = filter; - filter = f; - } + lf = (Filter *) ch_malloc( sizeof(Filter) ); + lf->f_next = NULL; + lf->f_choice = LDAP_FILTER_AND; + lf->f_and = (Filter *) ch_malloc( sizeof(Filter) ); + + lf->f_and->f_choice = LDAP_FILTER_EQUALITY; + lf->f_and->f_ava.ava_type = ch_strdup( "id2children" ); + sprintf( buf, "%ld", e != NULL ? e->e_id : 0 ); + lf->f_and->f_ava.ava_value.bv_val = ch_strdup( buf ); + lf->f_and->f_ava.ava_value.bv_len = strlen( buf ); + + lf->f_and->f_next = f; + f = lf; + + } else { + lf = NULL; } - candidates = filter_candidates( be, filter ); + candidates = filter_candidates( be, f ); + + /* free up filter additions we allocated above */ + if( lf != NULL ) { + lf->f_and->f_next = NULL; + filter_free( lf ); + } + + if( af != NULL ) { + af->f_or->f_next = NULL; + filter_free( af ); + } - /* free up just the parts we allocated above */ - if ( f != NULL ) { - *filterarg_ptr = NULL; - filter_free( f ); + if( rf != NULL ) { + rf->f_or->f_next = NULL; + filter_free( rf ); } return( candidates ); diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c index 0eea43fe99..231d664869 100644 --- a/servers/slapd/back-passwd/search.c +++ b/servers/slapd/back-passwd/search.c @@ -35,12 +35,13 @@ passwd_back_search( int attrsonly ) { - int sent = 0; struct passwd *pw; Entry *e; char *s; time_t stoptime; - int err = LDAP_NO_SUCH_OBJECT; + + int sent = 0; + int err = LDAP_SUCCESS; char *rdn = NULL; char *parent = NULL; @@ -68,43 +69,47 @@ passwd_back_search( vals[0] = &val; vals[1] = NULL; - /* Create an entry corresponding to the base DN */ - e = (Entry *) ch_calloc(1, sizeof(Entry)); - e->e_attrs = NULL; - e->e_dn = strdup(base); - - /* Use the first attribute of the DN - * as an attribute within the entry itself. - */ - rdn = dn_rdn(NULL, base); + matched = ch_strdup( base ); - if( rdn == NULL || (s = strchr(rdn, '=')) == NULL ) { - err = LDAP_INVALID_DN_SYNTAX; - goto done; - } + if( scope != LDAP_SCOPE_ONELEVEL ) { + /* Create an entry corresponding to the base DN */ + e = (Entry *) ch_calloc(1, sizeof(Entry)); + e->e_attrs = NULL; + e->e_dn = ch_strdup( base ); - val.bv_val = rdn_attr_value(rdn); - val.bv_len = strlen( val.bv_val ); - attr_merge( e, rdn_attr_type(rdn), vals ); + /* Use the first attribute of the DN + * as an attribute within the entry itself. + */ + rdn = dn_rdn(NULL, base); - free(rdn); - rdn = NULL; + if( rdn == NULL || (s = strchr(rdn, '=')) == NULL ) { + err = LDAP_INVALID_DN_SYNTAX; + goto done; + } - /* 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 - */ - val.bv_val = "organizationalUnit"; - val.bv_len = strlen( val.bv_val ); - attr_merge( e, "objectClass", vals ); + val.bv_val = rdn_attr_value(rdn); + val.bv_len = strlen( val.bv_val ); + attr_merge( e, rdn_attr_type(rdn), vals ); + + free(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 + */ + val.bv_val = "organizationalUnit"; + val.bv_len = strlen( val.bv_val ); + attr_merge( e, "objectClass", vals ); - if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); - matched = strdup( be->be_suffix[0] ); - sent++; + if ( test_filter( be, conn, op, e, filter ) == 0 ) { + send_search_entry( be, conn, op, + e, attrs, attrsonly, 0, NULL ); + sent++; + } } if ( scope != LDAP_SCOPE_BASE ) { @@ -123,7 +128,7 @@ passwd_back_search( /* check time limit */ if ( slap_get_time() > stoptime ) { send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, - NULL, NULL ); + NULL, NULL, NULL, NULL ); endpwent(); return( 0 ); } @@ -134,12 +139,13 @@ passwd_back_search( /* check size limit */ if ( --slimit == -1 ) { send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, - NULL, NULL ); + NULL, NULL, NULL, NULL ); endpwent(); return( 0 ); } - send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); + send_search_entry( be, conn, op, + e, attrs, attrsonly, 0, NULL ); sent++; } @@ -155,13 +161,25 @@ passwd_back_search( * anything deeper than that. */ if( !be_issuffix( be, parent ) ) { + int i; + for( i=0; be->be_suffix[i] != NULL; i++ ) { + if( dn_issuffix( base, be->be_suffix[i] ) ) { + matched = ch_strdup( be->be_suffix[i] ); + break; + } + } + err = LDAP_NO_SUCH_OBJECT; + goto done; + } + + if( scope == LDAP_SCOPE_ONELEVEL ) { goto done; } rdn = dn_rdn( NULL, base ); if ( (user = rdn_attr_value(rdn)) == NULL) { - err = LDAP_INVALID_DN_SYNTAX; + err = LDAP_OPERATIONS_ERROR; goto done; } @@ -170,13 +188,17 @@ passwd_back_search( } if ( (pw = getpwnam( user )) == NULL ) { + matched = parent; + parent = NULL; + err = LDAP_NO_SUCH_OBJECT; goto done; } e = pw2entry( be, pw, rdn ); if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); + send_search_entry( be, conn, op, + e, attrs, attrsonly, 0, NULL ); sent++; } @@ -184,12 +206,9 @@ passwd_back_search( } done: - if( sent ) { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); - - } else { - send_ldap_result( conn, op, err, matched, NULL ); - } + send_ldap_result( conn, op, + err, err == LDAP_NO_SUCH_OBJECT ? matched : NULL, NULL, + NULL, NULL ); if( matched != NULL ) free( matched ); if( parent != NULL ) free( parent ); diff --git a/servers/slapd/back-perl/add.c b/servers/slapd/back-perl/add.c index 9b4e09f7df..89193b499a 100644 --- a/servers/slapd/back-perl/add.c +++ b/servers/slapd/back-perl/add.c @@ -61,10 +61,12 @@ perl_back_add( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } Debug( LDAP_DEBUG_ANY, "Here ADD\n", 0, 0, 0 ); diff --git a/servers/slapd/back-perl/compare.c b/servers/slapd/back-perl/compare.c index 17429d10bc..482cdd06d5 100644 --- a/servers/slapd/back-perl/compare.c +++ b/servers/slapd/back-perl/compare.c @@ -40,7 +40,7 @@ perl_back_compare( PerlBackend *perl_back = (PerlBackend *)be->be_private; send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - "", "not yet implemented" ); + NULL, "not yet implemented", NULL, NULL ); #ifdef notdef ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); @@ -70,10 +70,10 @@ perl_back_compare( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_TRUE, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" ); + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, NULL, NULL ); } #endif diff --git a/servers/slapd/back-perl/delete.c b/servers/slapd/back-perl/delete.c index 956cc594c7..53acb19945 100644 --- a/servers/slapd/back-perl/delete.c +++ b/servers/slapd/back-perl/delete.c @@ -60,10 +60,12 @@ perl_back_delete( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } Debug( LDAP_DEBUG_ANY, "Here DELETE\n", 0, 0, 0 ); diff --git a/servers/slapd/back-perl/modify.c b/servers/slapd/back-perl/modify.c index 8ee8b82573..025823e081 100644 --- a/servers/slapd/back-perl/modify.c +++ b/servers/slapd/back-perl/modify.c @@ -93,10 +93,12 @@ perl_back_modify( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } Debug( LDAP_DEBUG_ANY, "Perl MODIFY\n", 0, 0, 0 ); diff --git a/servers/slapd/back-perl/modrdn.c b/servers/slapd/back-perl/modrdn.c index 1118829099..5fa8bca123 100644 --- a/servers/slapd/back-perl/modrdn.c +++ b/servers/slapd/back-perl/modrdn.c @@ -81,10 +81,12 @@ perl_back_modrdn( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } Debug( LDAP_DEBUG_ANY, "Perl MODRDN\n", 0, 0, 0 ); diff --git a/servers/slapd/back-perl/search.c b/servers/slapd/back-perl/search.c index 7117f4b985..16648d658c 100644 --- a/servers/slapd/back-perl/search.c +++ b/servers/slapd/back-perl/search.c @@ -86,13 +86,8 @@ perl_back_search( Debug( LDAP_DEBUG_ANY, "str2entry(%s) failed\n", buf, 0, 0 ); } else { - send_search_entry( be, - conn, - op, - e, - attrs, - attrsonly, - 0 ); + send_search_entry( be, conn, op, + e, attrs, attrsonly, 0, NULL ); entry_free( e ); } @@ -118,10 +113,12 @@ perl_back_search( ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); if( return_code != 0 ) { - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL, NULL ); } else { - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); } } diff --git a/servers/slapd/back-perl/unbind.c b/servers/slapd/back-perl/unbind.c index dad9499230..9d972195c6 100644 --- a/servers/slapd/back-perl/unbind.c +++ b/servers/slapd/back-perl/unbind.c @@ -34,8 +34,6 @@ perl_back_unbind( Operation *op ) { - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - "", "not yet implemented" ); Debug( LDAP_DEBUG_TRACE, "Perl UNBIND\n", 0, 0, 0 ); return 0; } diff --git a/servers/slapd/back-shell/add.c b/servers/slapd/back-shell/add.c index 61752d3278..9c033e7be8 100644 --- a/servers/slapd/back-shell/add.c +++ b/servers/slapd/back-shell/add.c @@ -24,13 +24,13 @@ shell_back_add( if ( si->si_add == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "add not implemented" ); + "add not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_add, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c index 5e2e195ef5..1b61eeb778 100644 --- a/servers/slapd/back-shell/bind.c +++ b/servers/slapd/back-shell/bind.c @@ -30,14 +30,14 @@ shell_back_bind( if ( si->si_bind == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "bind not implemented" ); + "bind not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_bind, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/compare.c b/servers/slapd/back-shell/compare.c index 1b724055f5..c59ac34289 100644 --- a/servers/slapd/back-shell/compare.c +++ b/servers/slapd/back-shell/compare.c @@ -24,14 +24,14 @@ shell_back_compare( if ( si->si_compare == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "compare not implemented" ); + "compare not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_compare, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/delete.c b/servers/slapd/back-shell/delete.c index be989ec9c5..1956969fbe 100644 --- a/servers/slapd/back-shell/delete.c +++ b/servers/slapd/back-shell/delete.c @@ -23,14 +23,14 @@ shell_back_delete( if ( si->si_delete == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "delete not implemented" ); + "delete not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_delete, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c index 178b1eb031..ebaa3f10e9 100644 --- a/servers/slapd/back-shell/modify.c +++ b/servers/slapd/back-shell/modify.c @@ -25,14 +25,14 @@ shell_back_modify( if ( si->si_modify == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modify not implemented" ); + "modify not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_modify, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/modrdn.c b/servers/slapd/back-shell/modrdn.c index d42742ca4c..c04e83a375 100644 --- a/servers/slapd/back-shell/modrdn.c +++ b/servers/slapd/back-shell/modrdn.c @@ -39,14 +39,14 @@ shell_back_modrdn( if ( si->si_modrdn == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modrdn not implemented" ); + "modrdn not implemented", NULL, NULL ); return( -1 ); } if ( (op->o_private = (void *) forkandexec( si->si_modrdn, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/result.c b/servers/slapd/back-shell/result.c index dfb479e36c..7e895001ac 100644 --- a/servers/slapd/back-shell/result.c +++ b/servers/slapd/back-shell/result.c @@ -59,7 +59,7 @@ read_and_send_results( buf, 0, 0 ); } else { send_search_entry( be, conn, op, e, attrs, - attrsonly, 0 ); + attrsonly, 0, NULL ); entry_free( e ); } @@ -70,7 +70,7 @@ read_and_send_results( /* otherwise, front end will send this result */ if ( err != 0 || op->o_tag != LDAP_REQ_BIND ) { - send_ldap_result( conn, op, err, matched, info ); + send_ldap_result( conn, op, err, matched, info, NULL, NULL ); } free( buf ); diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c index dc26be2d08..6f2bbb8d74 100644 --- a/servers/slapd/back-shell/search.c +++ b/servers/slapd/back-shell/search.c @@ -34,14 +34,14 @@ shell_back_search( if ( si->si_search == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "search not implemented" ); + "search not implemented", NULL, NULL ); return( -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" ); + "could not fork/exec", NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-shell/unbind.c b/servers/slapd/back-shell/unbind.c index 6e8d1009c1..f90792d876 100644 --- a/servers/slapd/back-shell/unbind.c +++ b/servers/slapd/back-shell/unbind.c @@ -22,14 +22,14 @@ shell_back_unbind( if ( si->si_unbind == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "unbind not implemented" ); + "unbind not implemented", NULL, NULL ); return 0; } if ( (op->o_private = (void *) forkandexec( si->si_unbind, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); + "could not fork/exec", NULL, NULL ); return 0; } diff --git a/servers/slapd/back-tcl/tcl_add.c b/servers/slapd/back-tcl/tcl_add.c index d964dc8060..d341c22317 100644 --- a/servers/slapd/back-tcl/tcl_add.c +++ b/servers/slapd/back-tcl/tcl_add.c @@ -1,6 +1,6 @@ /* add.c - tcl add routine * - * $Id: tcl_add.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_add.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -31,7 +31,7 @@ tcl_back_add ( if (ti->ti_add == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "add not implemented"); + "add not implemented", NULL ); return (-1); } @@ -63,7 +63,7 @@ tcl_back_add ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_bind.c b/servers/slapd/back-tcl/tcl_bind.c index 31abd6d1da..7326d129a1 100644 --- a/servers/slapd/back-tcl/tcl_bind.c +++ b/servers/slapd/back-tcl/tcl_bind.c @@ -1,6 +1,6 @@ /* bind.c - tcl bind routines * - * $Id: tcl_bind.c,v 1.5 1999/02/28 04:55:48 bcollins Exp $ + * $Id: tcl_bind.c,v 1.6.2.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -37,7 +37,7 @@ tcl_back_bind ( if (ti->ti_bind == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "bind not implemented"); + "bind not implemented", NULL ); return (-1); } @@ -67,7 +67,7 @@ tcl_back_bind ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_compare.c b/servers/slapd/back-tcl/tcl_compare.c index 7cd87affda..2982abe69d 100644 --- a/servers/slapd/back-tcl/tcl_compare.c +++ b/servers/slapd/back-tcl/tcl_compare.c @@ -1,6 +1,6 @@ /* compare.c - tcl compare routines * - * $Id: tcl_compare.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_compare.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -32,7 +32,7 @@ tcl_back_compare ( if (ti->ti_compare == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "compare not implemented"); + "compare not implemented", NULL ); return (-1); } @@ -63,7 +63,7 @@ tcl_back_compare ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_delete.c b/servers/slapd/back-tcl/tcl_delete.c index 8052978332..464292c720 100644 --- a/servers/slapd/back-tcl/tcl_delete.c +++ b/servers/slapd/back-tcl/tcl_delete.c @@ -1,6 +1,6 @@ /* delete.c - tcl delete routines * - * $Id: tcl_delete.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_delete.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -30,7 +30,7 @@ tcl_back_delete ( if (ti->ti_delete == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "delete not implemented"); + "delete not implemented", NULL ); return (-1); } @@ -59,7 +59,7 @@ tcl_back_delete ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_modify.c b/servers/slapd/back-tcl/tcl_modify.c index 047a7fbd41..ac9a130c50 100644 --- a/servers/slapd/back-tcl/tcl_modify.c +++ b/servers/slapd/back-tcl/tcl_modify.c @@ -1,6 +1,6 @@ /* modify.c - tcl modify routines * - * $Id: tcl_modify.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_modify.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -32,7 +32,7 @@ tcl_back_modify ( if (ti->ti_modify == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modify not implemented"); + "modify not implemented", NULL ); return (-1); } @@ -110,7 +110,7 @@ tcl_back_modify ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_modrdn.c b/servers/slapd/back-tcl/tcl_modrdn.c index e6af8b2b03..ffe18f9bc4 100644 --- a/servers/slapd/back-tcl/tcl_modrdn.c +++ b/servers/slapd/back-tcl/tcl_modrdn.c @@ -1,6 +1,6 @@ /* modrdn.c - tcl modify rdn routines * - * $Id: tcl_modrdn.c,v 1.6 1999/03/05 02:42:46 gomez Exp $ + * $Id: tcl_modrdn.c,v 1.7.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -47,7 +47,7 @@ tcl_back_modrdn ( if (ti->ti_modrdn == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modrdn not implemented"); + "modrdn not implemented", NULL ); return (-1); } @@ -84,7 +84,7 @@ tcl_back_modrdn ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_search.c b/servers/slapd/back-tcl/tcl_search.c index bbf95dad3c..5058bdbc9a 100644 --- a/servers/slapd/back-tcl/tcl_search.c +++ b/servers/slapd/back-tcl/tcl_search.c @@ -1,6 +1,6 @@ /* search.c - tcl search routines * - * $Id: tcl_search.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_search.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -40,7 +40,7 @@ tcl_back_search ( if (ti->ti_search == NULL) { send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "search not implemented"); + "search not implemented", NULL ); return (-1); } @@ -80,7 +80,7 @@ tcl_back_search ( if (err != LDAP_SUCCESS) send_ldap_result (conn, op, err, NULL, - "internal backend error"); + "internal backend error", NULL ); free (results); return (err); diff --git a/servers/slapd/back-tcl/tcl_unbind.c b/servers/slapd/back-tcl/tcl_unbind.c index d30aea3f1b..b75969cf75 100644 --- a/servers/slapd/back-tcl/tcl_unbind.c +++ b/servers/slapd/back-tcl/tcl_unbind.c @@ -1,6 +1,6 @@ /* unbind.c - tcl unbind routines * - * $Id: tcl_unbind.c,v 1.4 1999/02/19 06:55:20 bcollins Exp $ + * $Id: tcl_unbind.c,v 1.5.6.1 1999/07/09 18:02:59 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -29,8 +29,6 @@ tcl_back_unbind ( struct tclinfo *ti = (struct tclinfo *) be->be_private; if (ti->ti_unbind == NULL) { - send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "unbind not implemented"); return (-1); } diff --git a/servers/slapd/back-tcl/tcl_util.c b/servers/slapd/back-tcl/tcl_util.c index cdff332fc3..634009aa4b 100644 --- a/servers/slapd/back-tcl/tcl_util.c +++ b/servers/slapd/back-tcl/tcl_util.c @@ -1,6 +1,6 @@ /* result.c - tcl backend utility functions * - * $Id: tcl_util.c,v 1.5 1999/02/28 04:55:49 bcollins Exp $ + * $Id: tcl_util.c,v 1.6.2.2 1999/07/14 00:54:37 kdz Exp $ * * Copyright 1999, Ben Collins , All rights reserved. * @@ -47,7 +47,7 @@ interp_send_results ( if (code != TCL_OK) { argcPtr = 0; send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "internal backend error"); + "internal backend error", NULL ); return -1; } for (i = 0; i < argcPtr; i++) { @@ -80,7 +80,7 @@ interp_send_results ( buf, 0, 0); } else { send_search_entry (be, conn, op, e, attrs, - attrsonly, 0 ); + attrsonly, 0, NULL ); entry_free (e); } @@ -94,7 +94,7 @@ interp_send_results ( * otherwise, front end will send this result */ if (err != 0 || op->o_tag != LDAP_REQ_BIND) { - send_ldap_result (conn, op, err, matched, info); + send_ldap_result (conn, op, err, matched, info, NULL ); } free (buf); diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 7b143a08e0..3b5b51fe77 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -437,26 +437,6 @@ select_backend( char * dn ) } } - /* if no proper suffix could be found then check for aliases */ - for ( i = 0; i < nbackends; i++ ) { - for ( j = 0; - backends[i].be_suffixAlias != NULL && - backends[i].be_suffixAlias[j] != NULL; - j += 2 ) - { - len = strlen( backends[i].be_suffixAlias[j] ); - - if ( len > dnlen ) { - continue; - } - - if ( strcmp( backends[i].be_suffixAlias[j], - dn + (dnlen - len) ) == 0 ) { - return( &backends[i] ); - } - } - } - #ifdef LDAP_ALLOW_NULL_SEARCH_BASE /* Add greg@greg.rim.or.jp * It's quick hack for cheap client diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 4ab5de594a..c8daed7bfe 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -158,8 +158,8 @@ do_bind( if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) { Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 ); - send_ldap_result( conn, op, - rc = LDAP_PROTOCOL_ERROR, NULL, "version not supported" ); + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "version not supported", NULL, NULL ); goto cleanup; } @@ -178,7 +178,7 @@ do_bind( "do_bind: no sasl mechanism provided\n", version, 0, 0 ); send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED, - NULL, "no sasl mechanism provided" ); + NULL, "no sasl mechanism provided", NULL, NULL ); goto cleanup; } @@ -187,7 +187,7 @@ do_bind( "do_bind: sasl mechanism \"%s\" not supported.\n", mech, 0, 0 ); send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED, - NULL, "sasl mechanism not supported" ); + NULL, "sasl mechanism not supported", NULL, NULL ); goto cleanup; } @@ -242,7 +242,8 @@ do_bind( * we already forced connection to "anonymous", we just * need to send success */ - send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); + send_ldap_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL ); goto cleanup; } @@ -255,15 +256,15 @@ do_bind( if ( (be = select_backend( ndn )) == NULL ) { if ( cred.bv_len == 0 ) { send_ldap_result( conn, op, LDAP_SUCCESS, - NULL, NULL ); + NULL, NULL, NULL, NULL ); - } else if ( default_referral && *default_referral ) { - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, - NULL, default_referral ); + } else if ( default_referral ) { + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); } else { send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS, - NULL, default_referral ); + NULL, NULL, NULL, NULL ); } goto cleanup; @@ -273,8 +274,6 @@ do_bind( /* alias suffix */ char *edn; - ndn = suffixAlias( ndn, op, be ); - if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) { ldap_pvt_thread_mutex_lock( &conn->c_mutex ); @@ -294,15 +293,16 @@ do_bind( 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 != NULL) { free( edn ); } } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } cleanup: diff --git a/servers/slapd/charray.c b/servers/slapd/charray.c index 6ce0999294..e972d22ec4 100644 --- a/servers/slapd/charray.c +++ b/servers/slapd/charray.c @@ -109,6 +109,35 @@ charray_dup( char **a ) return( new ); } + +char * +charray2str( char **a ) +{ + char *s; + int i; + size_t cur, len = 0; + + if( a == NULL ) return NULL; + + for( i=0 ; a[i] != NULL ; i++ ) { + len += strlen( a[i] ); + } + + if( len == 0 ) return NULL; + + s = ch_malloc( len + 1 ); + + cur = 0; + for( i=0 ; a[i] != NULL ; i++ ) { + len = strlen( a[i] ); + strncpy( &s[cur], a[i], len ); + cur += len; + } + s[len] = '\0'; + return s; +} + + char ** str2charray( char *str, char *brkstr ) { diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 028a4f44d0..29a7c80962 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -34,8 +34,8 @@ do_compare( if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_compare: SASL bind in progress.\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + NULL, "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -85,19 +85,16 @@ do_compare( free( ndn ); ava_free( &ava, 0 ); - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); return 1; } - /* alias suffix if approp */ - ndn = suffixAlias( ndn, op, be ); - if ( be->be_compare ) { (*be->be_compare)( be, conn, op, ndn, &ava ); } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } free( ndn ); diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 2b9a05f920..ce402b1c8c 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -47,9 +47,15 @@ read_config( char *fname ) char *cargv[MAXARGS]; int lineno, i, rc; + struct berval *vals[2]; + struct berval val; + static BackendInfo *bi = NULL; static BackendDB *be = NULL; + vals[0] = &val; + vals[1] = NULL; + if ( (fp = fopen( fname, "r" )) == NULL ) { ldap_syslog = 1; Debug( LDAP_DEBUG_ANY, @@ -121,7 +127,7 @@ read_config( char *fname ) be = backend_db_init( cargv[1] ); /* assign a default depth limit for alias deref */ - be->be_maxDerefDepth = SLAPD_DEFAULT_MAXDEREFDEPTH; + be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; /* get pid file name */ } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) { @@ -219,54 +225,9 @@ read_config( char *fname ) free( dn ); } - /* set database suffixAlias */ - } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) { - if ( cargc < 2 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing alias and aliased_dn in \"suffixAlias \" line\n", - fname, lineno, 0 ); - return( 1 ); - } else if ( cargc < 3 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing aliased_dn in \"suffixAlias \" line\n", - fname, lineno, 0 ); - return( 1 ); - } else if ( cargc > 3 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: extra cruft in suffixAlias line (ignored)\n", - fname, lineno, 0 ); - } - if ( be == NULL ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: suffixAlias line must appear inside a database definition (ignored)\n", - fname, lineno, 0 ); - } else { - char *alias, *aliased_dn; - - alias = ch_strdup( cargv[1] ); - (void) dn_normalize( alias ); - - aliased_dn = ch_strdup( cargv[2] ); - (void) dn_normalize( aliased_dn ); - - - if ( strcasecmp( alias, aliased_dn) == 0 ) { - Debug( LDAP_DEBUG_ANY, -"%s: line %d: suffixAlias %s is not different from aliased dn (ignored)\n", - fname, lineno, alias ); - } else { - (void) dn_normalize_case( alias ); - (void) dn_normalize_case( aliased_dn ); - charray_add( &be->be_suffixAlias, alias ); - charray_add( &be->be_suffixAlias, aliased_dn ); - } - - free(alias); - free(aliased_dn); - } - /* set max deref depth */ } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) { + int i; if ( cargc < 2 ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: missing depth in \"maxDerefDepth \" line\n", @@ -277,9 +238,14 @@ read_config( char *fname ) Debug( LDAP_DEBUG_ANY, "%s: line %d: depth line must appear inside a database definition (ignored)\n", fname, lineno, 0 ); + } else if ((i = atoi(cargv[i])) < 0) { + Debug( LDAP_DEBUG_ANY, +"%s: line %d: depth must be positive (ignored)\n", + fname, lineno, 0 ); + } else { - be->be_maxDerefDepth = atoi (cargv[1]); - } + be->be_max_deref_depth = i; + } /* set magic "root" dn for this database */ @@ -343,10 +309,10 @@ read_config( char *fname ) fname, lineno, 0 ); return( 1 ); } - default_referral = (char *) ch_malloc( strlen( cargv[1] ) - + sizeof("Referral:\n") + 1 ); - strcpy( default_referral, "Referral:\n" ); - strcat( default_referral, cargv[1] ); + + vals[0]->bv_val = cargv[1]; + vals[0]->bv_len = strlen( vals[0]->bv_val ); + value_add( &default_referral, vals ); /* specify locale */ } else if ( strcasecmp( cargv[0], "locale" ) == 0 ) { @@ -500,6 +466,27 @@ read_config( char *fname ) (void) dn_normalize_case( be->be_update_ndn ); } + } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) { + if ( cargc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing dn in \"updateref \" line\n", + fname, lineno, 0 ); + return( 1 ); + } + if ( be == NULL ) { + Debug( LDAP_DEBUG_ANY, +"%s: line %d: updateref line must appear inside a database definition (ignored)\n", + fname, lineno, 0 ); + } else if ( be->be_update_ndn == NULL ) { + Debug( LDAP_DEBUG_ANY, +"%s: line %d: updateref line must after updatedn (ignored)\n", + fname, lineno, 0 ); + } else { + 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 ) { diff --git a/servers/slapd/configinfo.c b/servers/slapd/configinfo.c index ee6d63fd50..4d85b2b627 100644 --- a/servers/slapd/configinfo.c +++ b/servers/slapd/configinfo.c @@ -56,15 +56,10 @@ config_info( Connection *conn, Operation *op ) attr_merge( e, "database", vals ); } - if ( default_referral != NULL ) { - strcpy( buf, default_referral ); - val.bv_val = buf; - val.bv_len = strlen( buf ); - attr_merge( e, "database", vals ); - } - - send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 ); - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 ); + send_search_entry( &backends[0], conn, op, e, + NULL, 0, 1, NULL ); + send_search_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 1 ); entry_free( e ); } diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 1afb52038a..37361cb47c 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -17,6 +17,7 @@ #include "../../libraries/liblber/lber-int.h" char *supportedControls[] = { + LDAP_CONTROL_MANAGEDSAIT, NULL }; @@ -154,9 +155,29 @@ return_results: if( rc == -1 ) { send_ldap_disconnect( conn, op, rc, errmsg ); } else { - send_ldap_result( conn, op, rc, NULL, errmsg ); + send_ldap_result( conn, op, rc, + NULL, errmsg, NULL, NULL ); } } return rc; } + + +int get_manageDSAit( Operation *op ) +{ + int i; + if( op == NULL || op->o_ctrls == NULL ) { + return 0; + } + + for( i=0; op->o_ctrls[i] != NULL; i++ ) { + if( strcmp( LDAP_CONTROL_MANAGEDSAIT, op->o_ctrls[i]->ldctl_oid ) + == 0 ) + { + return 1; + } + } + + return 0; +} \ No newline at end of file diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index 4d0d7fb076..2b2d41cfaa 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -34,8 +34,8 @@ do_delete( if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_delete: SASL bind in progress.\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + NULL, "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -71,14 +71,11 @@ do_delete( */ if ( (be = select_backend( ndn )) == NULL ) { free( ndn ); - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); return rc; } - /* alias suffix if approp */ - ndn = suffixAlias( ndn, op, be ); - /* * do the delete if 1 && (2 || 3) * 1) there is a delete function implemented in this backend; @@ -94,12 +91,12 @@ do_delete( replog( be, LDAP_REQ_DELETE, ndn, NULL, 0 ); } } else { - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + be->be_update_refs ? be->be_update_refs : default_referral, NULL ); } } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } free( ndn ); diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c index d813cf2501..a9143e4ed8 100644 --- a/servers/slapd/extended.c +++ b/servers/slapd/extended.c @@ -73,8 +73,8 @@ do_extended( if( !charray_inlist( supportedExtensions, reqoid ) ) { Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n", reqoid, 0 ,0 ); - send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, NULL, - "unsuppored operation" ); + send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, + NULL, "unsuppored extended operation", NULL, NULL ); goto done; } @@ -98,7 +98,7 @@ do_extended( Debug( LDAP_DEBUG_ARGS, "do_extended: oid \"%s\"\n", reqoid, 0 ,0 ); send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, - NULL, "unsupported extended operation" ); + NULL, "unsupported extended operation", NULL, NULL ); done: if ( reqoid != NULL ) { diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 0990d4b533..dc50910663 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -23,7 +23,7 @@ int ldap_syslog; #endif int ldap_syslog_level = LOG_DEBUG; -char *default_referral; +struct berval **default_referral = NULL; int g_argc; char **g_argv; @@ -45,7 +45,9 @@ long num_ops_completed; ldap_pvt_thread_mutex_t num_ops_mutex; long num_entries_sent; +long num_refs_sent; long num_bytes_sent; +long num_pdu_sent; ldap_pvt_thread_mutex_t num_sent_mutex; /* * these mutexes must be used when calling the entry2str() diff --git a/servers/slapd/libslapd.dsp b/servers/slapd/libslapd.dsp index 898d368c6a..9c6ddefdd6 100644 --- a/servers/slapd/libslapd.dsp +++ b/servers/slapd/libslapd.dsp @@ -272,10 +272,6 @@ SOURCE=.\str2filter.c # End Source File # Begin Source File -SOURCE=.\suffixalias.c -# End Source File -# Begin Source File - SOURCE=.\unbind.c # End Source File # Begin Source File diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index ccae24d41f..340263037e 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -45,8 +45,8 @@ do_modify( if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_modify: SASL bind in progress.\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + NULL, "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -112,7 +112,7 @@ do_modify( (*modtail)->ml_op != LDAP_MOD_REPLACE ) { send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, - NULL, "unrecognized modify operation" ); + NULL, "unrecognized modify operation", NULL, NULL ); free( ndn ); modlist_free( modlist ); return LDAP_PROTOCOL_ERROR; @@ -122,7 +122,7 @@ do_modify( && (*modtail)->ml_op != LDAP_MOD_DELETE ) { send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, - NULL, "unrecognized modify operation" ); + NULL, "unrecognized modify operation", NULL, NULL ); free( ndn ); modlist_free( modlist ); return LDAP_PROTOCOL_ERROR; @@ -161,14 +161,11 @@ do_modify( if ( (be = select_backend( ndn )) == NULL ) { free( ndn ); modlist_free( modlist ); - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); return rc; } - /* alias suffix if approp */ - ndn = suffixAlias ( ndn, op, be ); - /* * do the modify if 1 && (2 || 3) * 1) there is a modify function implemented in this backend; @@ -186,12 +183,12 @@ do_modify( /* send a referral */ } else { - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + be->be_update_refs ? be->be_update_refs : default_referral, NULL ); } } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } free( ndn ); diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index c80a605fbd..482a9bdd74 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -53,8 +53,8 @@ do_modrdn( if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_modrdn: SASL bind in progress.\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + NULL, "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -161,8 +161,8 @@ do_modrdn( free( newrdn ); free( newSuperior ); free( nnewSuperior ); - send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); return 0; } } @@ -183,8 +183,8 @@ do_modrdn( free( newrdn ); free( newSuperior ); free( nnewSuperior ); - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); return rc; } @@ -203,16 +203,12 @@ do_modrdn( free( nnewSuperior ); send_ldap_result( conn, op, rc = LDAP_AFFECTS_MULTIPLE_DSAS, - NULL, "" ); + NULL, NULL, NULL, NULL ); return rc; } - - /* alias suffix if approp */ - ndn = suffixAlias( ndn, op, be ); - /* * do the add if 1 && (2 || 3) * 1) there is an add function implemented in this backend; @@ -231,12 +227,12 @@ do_modrdn( deloldrdn ); } } else { - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, + be->be_update_refs ? be->be_update_refs : default_referral, NULL ); } } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } free( ndn ); diff --git a/servers/slapd/monitor.c b/servers/slapd/monitor.c index a5a5274f12..855a2e8dc0 100644 --- a/servers/slapd/monitor.c +++ b/servers/slapd/monitor.c @@ -139,55 +139,69 @@ monitor_info( Connection *conn, Operation *op ) sprintf( buf, "%d", nconns ); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "currentconnections", vals ); + attr_merge( e, "currentConnections", vals ); sprintf( buf, "%ld", connections_nextid() ); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "totalconnections", vals ); + attr_merge( e, "totalConnections", vals ); sprintf( buf, "%ld", (long) dtblsize ); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "dtablesize", vals ); + attr_merge( e, "dTableSize", vals ); sprintf( buf, "%d", nwritewaiters ); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "writewaiters", vals ); + attr_merge( e, "writeWaiters", vals ); sprintf( buf, "%d", nreadwaiters ); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "readwaiters", vals ); + attr_merge( e, "readWaiters", vals ); ldap_pvt_thread_mutex_lock(&num_ops_mutex); sprintf( buf, "%ld", num_ops_initiated ); ldap_pvt_thread_mutex_unlock(&num_ops_mutex); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "opsinitiated", vals ); + attr_merge( e, "opsInitiated", vals ); ldap_pvt_thread_mutex_lock(&num_ops_mutex); sprintf( buf, "%ld", num_ops_completed ); ldap_pvt_thread_mutex_unlock(&num_ops_mutex); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "opscompleted", vals ); + attr_merge( e, "opsCompleted", vals ); ldap_pvt_thread_mutex_lock(&num_sent_mutex); sprintf( buf, "%ld", num_entries_sent ); ldap_pvt_thread_mutex_unlock(&num_sent_mutex); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "entriessent", vals ); + attr_merge( e, "entriesSent", vals ); + + ldap_pvt_thread_mutex_lock(&num_sent_mutex); + sprintf( buf, "%ld", num_refs_sent ); + ldap_pvt_thread_mutex_unlock(&num_sent_mutex); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attr_merge( e, "referencesSent", vals ); + + ldap_pvt_thread_mutex_lock(&num_sent_mutex); + sprintf( buf, "%ld", num_pdu_sent ); + ldap_pvt_thread_mutex_unlock(&num_sent_mutex); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attr_merge( e, "pduSent", vals ); ldap_pvt_thread_mutex_lock(&num_sent_mutex); sprintf( buf, "%ld", num_bytes_sent ); ldap_pvt_thread_mutex_unlock(&num_sent_mutex); val.bv_val = buf; val.bv_len = strlen( buf ); - attr_merge( e, "bytessent", vals ); + attr_merge( e, "bytesSent", vals ); currenttime = slap_get_time(); @@ -228,8 +242,10 @@ monitor_info( Connection *conn, Operation *op ) attr_merge( e, "concurrency", vals ); #endif - send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 ); - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 ); + send_search_entry( &backends[0], conn, op, e, + NULL, 0, 1, NULL ); + send_search_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 1 ); entry_free( e ); } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 442f2f450a..4931978ea5 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -119,6 +119,7 @@ void charray_free LDAP_P(( char **array )); int charray_inlist LDAP_P(( char **a, char *s )); char ** charray_dup LDAP_P(( char **a )); char ** str2charray LDAP_P(( char *str, char *brkstr )); +char * charray2str LDAP_P(( char **a )); /* * controls.c @@ -128,6 +129,8 @@ int get_ctrls LDAP_P(( Operation *op, int senderrors )); +int get_manageDSAit LDAP_P(( Operation *op )); + /* * config.c */ @@ -257,17 +260,40 @@ void replog LDAP_P(( Backend *be, int optype, char *dn, void *change, int flag ) * result.c */ +struct berval **get_entry_referrals LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e )); + void send_ldap_result LDAP_P(( Connection *conn, Operation *op, - int err, char *matched, char *text )); + int err, char *matched, char *text, + struct berval **refs, + LDAPControl **ctrls )); void send_ldap_disconnect LDAP_P(( Connection *conn, Operation *op, int err, char *text )); -void send_ldap_search_result LDAP_P(( +void send_search_result LDAP_P(( Connection *conn, Operation *op, - int err, char *matched, char *text, int nentries )); + int err, char *matched, char *text, + struct berval **refs, + LDAPControl **ctrls, + int nentries )); + +int send_search_reference LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, struct berval **refs, int scope, + LDAPControl **ctrls, + struct berval ***v2refs )); + +int send_search_entry LDAP_P(( + Backend *be, Connection *conn, Operation *op, + Entry *e, char **attrs, int attrsonly, int opattrs, + LDAPControl **ctrls )); + +int str2result LDAP_P(( char *s, + int *code, char **matched, char **info )); /* * schema.c @@ -286,6 +312,10 @@ int mr_add LDAP_P((LDAP_MATCHING_RULE *mr, slap_mr_normalize_func *normalize, sl void schema_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly)); int schema_init LDAP_P((void)); +int is_entry_objectclass LDAP_P(( Entry *, char* objectclass )); +#define is_entry_alias(e) is_entry_objectclass((e), "ALIAS") +#define is_entry_referral(e) is_entry_objectclass((e), "REFERRAL") + /* * schemaparse.c @@ -314,11 +344,6 @@ int value_cmp LDAP_P(( struct berval *v1, struct berval *v2, int syntax, int value_find LDAP_P(( struct berval **vals, struct berval *v, int syntax, int normalize )); -/* - * suffixAlias.c - */ -char *suffixAlias LDAP_P(( char *dn, Operation *op, Backend *be )); - /* * user.c */ @@ -330,7 +355,7 @@ void slap_init_user LDAP_P(( char *username, char *groupname )); * Other... */ -extern char *default_referral; +extern struct berval **default_referral; extern char *replogfile; extern const char Versionstr[]; extern int active_threads; @@ -347,7 +372,9 @@ extern int ldap_syslog; extern ldap_pvt_thread_mutex_t num_sent_mutex; extern long num_bytes_sent; +extern long num_pdu_sent; extern long num_entries_sent; +extern long num_refs_sent; extern ldap_pvt_thread_mutex_t num_ops_mutex; extern long num_ops_completed; @@ -373,10 +400,10 @@ extern ldap_pvt_thread_mutex_t gmtime_mutex; extern struct acl *global_acl; -extern int slap_init LDAP_P((int mode, char* name)); -extern int slap_startup LDAP_P((int dbnum)); -extern int slap_shutdown LDAP_P((int dbnum)); -extern int slap_destroy LDAP_P((void)); +int slap_init LDAP_P((int mode, char* name)); +int slap_startup LDAP_P((int dbnum)); +int slap_shutdown LDAP_P((int dbnum)); +int slap_destroy LDAP_P((void)); struct sockaddr_in; @@ -416,11 +443,6 @@ extern int do_search LDAP_P((Connection *conn, Operation *op)); extern int do_unbind LDAP_P((Connection *conn, Operation *op)); extern int do_extended LDAP_P((Connection *conn, Operation *op)); -extern int send_search_entry LDAP_P(( - Backend *be, Connection *conn, Operation *op, - Entry *e, char **attrs, int attrsonly, int opattrs )); - -extern int str2result LDAP_P(( char *s, int *code, char **matched, char **info )); extern ber_socket_t dtblsize; diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 764bc2e6d7..246a007764 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -9,121 +9,165 @@ #include #include #include -#include /* get close() */ +#include #include "slap.h" /* we need LBER internals */ #include "../../libraries/liblber/lber-int.h" -static void -send_ldap_result2( - Connection *conn, - Operation *op, - int disconnect, - ber_int_t err, - char *matched, - char *text, - int nentries -) +static char *v2ref( struct berval **ref ) { - BerElement *ber; - int rc; - ber_tag_t tag; - ber_len_t bytes; - int msgid; + size_t len, i; + char *v2; - assert( !LDAP_API_ERROR( err ) ); + if(ref == NULL) return NULL; - if ( err == LDAP_PARTIAL_RESULTS && (text == NULL || *text == '\0') ) - err = LDAP_NO_SUCH_OBJECT; + len = sizeof("Referral:"); + v2 = ch_strdup("Referral:"); - if( disconnect ) { - msgid = 0; /* unsolicited */ - if ( op->o_protocol > LDAP_VERSION3 ) { - tag = LDAP_RES_EXTENDED; - } - -#define LDAP_UNSOLICITED_ERROR(e) \ - ( (e) == LDAP_PROTOCOL_ERROR \ - || (e) == LDAP_STRONG_AUTH_REQUIRED \ - || (e) == LDAP_UNAVAILABLE ) + for( i=0; ref[i] != NULL; i++ ) { + v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 ); + v2[len-1] = '\n'; + memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len ); + len += ref[i]->bv_len; + } - assert( LDAP_UNSOLICITED_ERROR( err ) ); + v2[len-1] = '\0'; + return v2; +} - } else { - msgid = op->o_msgid; - - switch ( op->o_tag ) { - case LDAP_REQ_ABANDON: - case LDAP_REQ_UNBIND: - case LBER_ERROR: - tag = LBER_SEQUENCE; - msgid = 0; - assert( LDAP_UNSOLICITED_ERROR( err ) ); - break; +static ber_tag_t req2res( ber_tag_t tag ) +{ + 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; + + case LDAP_REQ_DELETE: + tag = LDAP_RES_DELETE; + break; + + case LDAP_REQ_ABANDON: + case LDAP_REQ_UNBIND: + tag = LBER_SEQUENCE; + break; + + case LDAP_REQ_SEARCH: + tag = LDAP_RES_SEARCH_RESULT; + break; + + default: + assert( 0 ); + tag = LBER_ERROR; + } + return tag; +} - case LDAP_REQ_SEARCH: - tag = LDAP_RES_SEARCH_RESULT; - break; +static void trim_refs_urls( + struct berval **refs ) +{ + unsigned i; - case LDAP_REQ_DELETE: - tag = LDAP_RES_DELETE; - break; + if( refs == NULL ) return; - default: - tag = op->o_tag + 1; - break; + for( i=0; refs[i] != NULL; i++ ) { + if( refs[i]->bv_len > sizeof("ldap://") && + strncasecmp( refs[i]->bv_val, "ldap://", + sizeof("ldap://")-1 ) == 0 ) + { + unsigned j; + for( j=sizeof("ldap://"); jbv_len ; j++ ) { + if( refs[i]->bv_val[j] = '/' ) { + refs[i]->bv_val[j] = '\0'; + refs[i]->bv_len = j; + break; + } + } } } +} +struct berval **get_entry_referrals( + Backend *be, + Connection *conn, + Operation *op, + Entry *e ) +{ + Attribute *attr; + struct berval **refs; + unsigned i, j; - ber = ber_alloc_t( LBER_USE_DER ); + attr = attr_find( e->e_attrs, "ref" ); - if ( ber == NULL ) { - Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - return; + if( attr == NULL ) return NULL; + + for( i=0; attr->a_vals[i] != NULL; i++ ) { + /* count references */ } -#ifdef LDAP_CONNECTIONLESS - if ( op->o_cldap ) { - rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag, - err, matched ? matched : "", text ? text : "" ); - } else -#endif - if( tag == LDAP_RES_EXTENDED ) { - rc = ber_printf( ber, "{it{esss}}", - msgid, tag, err, - "", text ? text : "", - LDAP_NOTICE_DISCONNECT ); + if( i < 1 ) return NULL; - } else { - rc = ber_printf( ber, "{it{ess}}", - msgid, tag, err, - matched ? matched : "", text ? text : "" ); + refs = ch_malloc( i + 1 ); + + for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) { + unsigned k; + struct berval *ref = ber_bvdup( attr->a_vals[i] ); + + /* trim the label */ + for( k=0; kbv_len; k++ ) { + if( isspace(ref->bv_val[k]) ) { + ref->bv_val[k] = '\0'; + ref->bv_len = k; + break; + } + } + + if( ref->bv_len > 0 ) { + refs[j++] = ref; + + } else { + ber_bvfree( ref ); + } } - if ( rc == -1 ) { - Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - return; + refs[j] = NULL; + + if( j == 0 ) { + ber_bvecfree( refs ); + refs = NULL; } + /* we should check that a referral value exists... */ + + return refs; +} + +static long send_ldap_ber( + Connection *conn, + BerElement *ber ) +{ + ber_len_t bytes = ber_pvt_ber_bytes( ber ); + /* write only one pdu at a time - wait til it's our turn */ ldap_pvt_thread_mutex_lock( &conn->c_write_mutex ); - /* lock the connection */ + /* lock the connection */ ldap_pvt_thread_mutex_lock( &conn->c_mutex ); /* write the pdu */ - bytes = ber_pvt_ber_bytes( ber ); - - while ( 1 ) { + while( 1 ) { int err; if ( connection_state_closing( conn ) ) { ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - return; + return 0; } if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) { @@ -147,7 +191,7 @@ send_ldap_result2( ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - return; + return( -1 ); } /* wait for socket to be write-ready */ @@ -161,31 +205,126 @@ send_ldap_result2( ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + return bytes; +} + +static void +send_ldap_response( + Connection *conn, + Operation *op, + ber_tag_t tag, + ber_int_t msgid, + ber_int_t err, + char *matched, + char *text, + struct berval **ref, + char *resoid, + struct berval *resdata, + LDAPControl **ctrls +) +{ + BerElement *ber; + int rc; + long bytes; + + assert( ctrls == NULL ); /* ctrls not implemented */ + + ber = ber_alloc_t( LBER_USE_DER ); + + Debug( LDAP_DEBUG_TRACE, "send_ldap_response: tag=%ld msgid=%ld err=%ld\n", + (long) tag, (long) msgid, (long) err ); + + if ( ber == NULL ) { + Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); + return; + } + +#ifdef LDAP_CONNECTIONLESS + if ( op->o_cldap ) { + rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag, + err, matched ? matched : "", text ? text : "" ); + } else +#endif + { + rc = ber_printf( ber, "{it{ess", + msgid, tag, err, + matched == NULL ? "" : matched, + text == NULL ? "" : text ); + + if( rc != -1 && ref != NULL ) { + rc = ber_printf( ber, "{V}", ref ); + } + + if( rc != -1 && resoid != NULL ) { + rc = ber_printf( ber, "s", resoid ); + } + + if( rc != -1 && resdata != NULL ) { + rc = ber_printf( ber, "O", resdata ); + + } + + if( rc != -1 ) { + rc = ber_printf( ber, "}}" ); + } + } + + if ( rc == -1 ) { + Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); + return; + } + + /* send BER */ + bytes = send_ldap_ber( conn, ber ); + + if ( bytes < 0 ) { + Debug( LDAP_DEBUG_ANY, + "send_ldap_response: ber write failed\n", + 0, 0, 0 ); + return; + } + ldap_pvt_thread_mutex_lock( &num_sent_mutex ); num_bytes_sent += bytes; + num_pdu_sent++; ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); - - Statslog( LDAP_DEBUG_STATS, - "conn=%ld op=%ld RESULT err=%ld tag=%lu nentries=%d\n", - (long) conn->c_connid, (long) op->o_opid, - (long) err, (long) tag, nentries ); - return; } + void -send_ldap_result( +send_ldap_disconnect( Connection *conn, Operation *op, ber_int_t err, - char *matched, char *text ) { - assert( !LDAP_API_ERROR( err ) ); + ber_tag_t tag; + ber_int_t msgid; + char *reqoid; - Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", - err, matched ? matched : "", text ? text : "" ); +#define LDAP_UNSOLICITED_ERROR(e) \ + ( (e) == LDAP_PROTOCOL_ERROR \ + || (e) == LDAP_STRONG_AUTH_REQUIRED \ + || (e) == LDAP_UNAVAILABLE ) + + assert( LDAP_UNSOLICITED_ERROR( err ) ); + + Debug( LDAP_DEBUG_TRACE, + "send_ldap_disconnect %d:%s\n", + err, text ? text : "", NULL ); + + 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; + } #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { @@ -197,22 +336,54 @@ send_ldap_result( 0 ); } #endif - send_ldap_result2( conn, op, 0, err, matched, text, 0 ); + send_ldap_response( conn, op, tag, msgid, + err, NULL, text, NULL, + reqoid, NULL, NULL ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n", + (long) conn->c_connid, (long) op->o_opid, + (long) tag, (long) err, text ); } void -send_ldap_disconnect( +send_ldap_result( Connection *conn, Operation *op, ber_int_t err, - char *text + char *matched, + char *text, + struct berval **ref, + LDAPControl **ctrls ) { + ber_tag_t tag; + ber_int_t msgid; + char *tmp = NULL; + assert( !LDAP_API_ERROR( err ) ); - Debug( LDAP_DEBUG_TRACE, - "send_ldap_disconnect %d:%s\n", - err, text ? text : "", NULL ); + Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", + err, matched ? matched : "", text ? text : "" ); + + assert( err != LDAP_PARTIAL_RESULTS ); + + if( op->o_tag != LDAP_REQ_SEARCH ) { + trim_refs_urls( ref ); + } + + if ( err == LDAP_REFERRAL ) { + if( ref == NULL ) { + err = LDAP_NO_SUCH_OBJECT; + } else if ( op->o_protocol < LDAP_VERSION3 ) { + err = LDAP_PARTIAL_RESULTS; + tmp = text = v2ref( ref ); + ref = NULL; + } + } + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; #ifdef LDAP_CONNECTIONLESS if ( op->o_cldap ) { @@ -224,25 +395,88 @@ send_ldap_disconnect( 0 ); } #endif - send_ldap_result2( conn, op, 0, err, NULL, text, 0 ); + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, ref, + NULL, NULL, ctrls ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld RESULT err=%ld tag=%lu text=%s\n", + (long) conn->c_connid, (long) op->o_opid, + (long) err, (long) tag, text ); + + if( tmp != NULL ) { + free(tmp); + } } + void -send_ldap_search_result( +send_search_result( Connection *conn, Operation *op, ber_int_t err, char *matched, - char *text, + char *text, + struct berval **refs, + LDAPControl **ctrls, int nentries ) { + ber_tag_t tag; + ber_int_t msgid; + char *tmp = NULL; + assert( !LDAP_API_ERROR( err ) ); + Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n", err, matched ? matched : "", text ? text : "" ); - send_ldap_result2( conn, op, 0, err, matched, text, nentries ); + assert( err != LDAP_PARTIAL_RESULTS ); + + trim_refs_urls( refs ); + + if( op->o_protocol < LDAP_VERSION3 ) { + /* send references in search results */ + if( err == LDAP_REFERRAL ) { + err = LDAP_PARTIAL_RESULTS; + tmp = text = v2ref( refs ); + refs = NULL; + } + + } else { + /* don't send references in search results */ + if( err == LDAP_REFERRAL ) { + err = LDAP_SUCCESS; + refs = NULL; + } + } + + tag = req2res( op->o_tag ); + msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0; + +#ifdef LDAP_CONNECTIONLESS + if ( op->o_cldap ) { + ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr ); + Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", + inet_ntoa(((struct sockaddr_in *) + &op->o_clientaddr)->sin_addr ), + ((struct sockaddr_in *) &op->o_clientaddr)->sin_port, + 0 ); + } +#endif + + send_ldap_response( conn, op, tag, msgid, + err, matched, text, refs, + NULL, NULL, ctrls ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%ld op=%ld SEARCH RESULT err=%ld tag=%lu text=%s\n", + (long) conn->c_connid, (long) op->o_opid, + (long) err, (long) tag, text ); + } + int send_search_entry( Backend *be, @@ -251,7 +485,8 @@ send_search_entry( Entry *e, char **attrs, int attrsonly, - int opattrs + int opattrs, + LDAPControl **ctrls ) { BerElement *ber; @@ -259,6 +494,7 @@ send_search_entry( int i, rc=-1, bytes; struct acl *acl; char *edn; + int allattrs; Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); @@ -287,8 +523,8 @@ send_search_entry( if ( ber == NULL ) { Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ber_alloc" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "allocating BER error", NULL, NULL ); goto error_return; } @@ -298,25 +534,28 @@ send_search_entry( if ( rc == -1 ) { 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" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "encoding dn error", NULL, NULL ); goto error_return; } + /* check for special all user attributes ("*") attribute */ + allattrs = attrs == NULL + ? 1 + : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ); + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { regmatch_t matches[MAXREMATCHES]; if ( attrs == NULL ) { /* all addrs request, skip operational attributes */ - if( !opattrs && oc_check_operational_attr( a->a_type )) { + if( !opattrs && oc_check_operational_attr( a->a_type ) ) { continue; } } else { /* specific addrs requested */ - if ( !charray_inlist( attrs, a->a_type ) - && !charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ) ) - { + if ( !allattrs && !charray_inlist( attrs, a->a_type ) ) { continue; } } @@ -334,7 +573,7 @@ send_search_entry( 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" ); + NULL, "encoding type error", NULL, NULL ); goto error_return; } @@ -351,9 +590,8 @@ send_search_entry( 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" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "encoding value error", NULL, NULL ); goto error_return; } } @@ -363,7 +601,7 @@ send_search_entry( 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" ); + NULL, "encode end error", NULL, NULL ); goto error_return; } } @@ -373,67 +611,116 @@ send_search_entry( if ( rc == -1 ) { 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" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "encode entry end error", NULL, NULL ); return( 1 ); } - bytes = ber_pvt_ber_bytes( ber ); + bytes = send_ldap_ber( conn, ber ); - /* write only one pdu at a time - wait til it's our turn */ - ldap_pvt_thread_mutex_lock( &conn->c_write_mutex ); + if ( bytes < 0 ) { + Debug( LDAP_DEBUG_ANY, + "send_ldap_response: ber write failed\n", + 0, 0, 0 ); + return -1; + } - /* lock the connection */ - ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + 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 ); - /* write the pdu */ - while( 1 ) { - int err; + 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 ); - if ( connection_state_closing( conn ) ) { - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - return 0; - } + Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); - if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) { - break; - } + rc = 0; - err = errno; +error_return:; + return( rc ); +} - /* - * 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. - */ +int +send_search_reference( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + struct berval **refs, + int scope, + LDAPControl **ctrls, + struct berval ***v2refs +) +{ + BerElement *ber; + int rc; + int bytes; - Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n", - err, err > -1 && err < sys_nerr ? sys_errlist[err] - : "unknown", 0 ); + Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); - if ( err != EWOULDBLOCK && err != EAGAIN ) { - connection_closing( conn ); + if ( ! access_allowed( be, conn, op, e, + "entry", NULL, ACL_READ ) ) + { + Debug( LDAP_DEBUG_ACL, + "send_search_reference: access to entry not allowed\n", + 0, 0, 0 ); + return( 1 ); + } - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - return( -1 ); + if ( ! access_allowed( be, conn, op, e, + "ref", NULL, ACL_READ ) ) + { + Debug( LDAP_DEBUG_ACL, + "send_search_reference: access to reference not allowed\n", + 0, 0, 0 ); + return( 1 ); + } + + if( refs == NULL ) { + Debug( LDAP_DEBUG_ANY, + "send_search_reference: null ref in (%s)\n", + e->e_dn, 0, 0 ); + return( 1 ); + } + + if( op->o_protocol < LDAP_VERSION3 ) { + /* save the references for the result */ + if( *refs == NULL ) { + value_add( v2refs, refs ); } + return 0; + } - /* wait for socket to be write-ready */ - conn->c_writewaiter = 1; - slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 ); + ber = ber_alloc_t( LBER_USE_DER ); - ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); - conn->c_writewaiter = 0; + if ( ber == NULL ) { + Debug( LDAP_DEBUG_ANY, + "send_search_reference: ber_alloc failed\n", 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "alloc BER error", NULL, NULL ); + return -1; } - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + rc = ber_printf( ber, "{it{V}}", op->o_msgid, + LDAP_RES_SEARCH_REFERENCE, refs ); + + if ( rc == -1 ) { + Debug( LDAP_DEBUG_ANY, + "send_search_reference: ber_printf failed\n", 0, 0, 0 ); + ber_free( ber, 1 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "encode dn error", NULL, NULL ); + return -1; + } + + bytes = send_ldap_ber( conn, ber ); ldap_pvt_thread_mutex_lock( &num_sent_mutex ); num_bytes_sent += bytes; - num_entries_sent++; + num_refs_sent++; + num_pdu_sent++; ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n", @@ -441,12 +728,10 @@ send_search_entry( Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); - rc = 0; - -error_return:; - return( rc ); + return 0; } + int str2result( char *s, diff --git a/servers/slapd/root_dse.c b/servers/slapd/root_dse.c index 540d218d13..25d5f7ddbf 100644 --- a/servers/slapd/root_dse.c +++ b/servers/slapd/root_dse.c @@ -93,9 +93,14 @@ root_dse_info( Connection *conn, Operation *op, char **attrs, int attrsonly ) attr_merge( e, "supportedSASLMechanism", vals ); } + if ( default_referral != NULL ) { + attr_merge( e, "ref", default_referral ); + } - send_search_entry( &backends[0], conn, op, e, attrs, attrsonly, 1 ); - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 ); + send_search_entry( &backends[0], conn, op, + e, attrs, attrsonly, 1, NULL ); + send_search_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 1 ); entry_free( e ); } diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index e71913e0e6..e2e2294d56 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -1143,8 +1143,10 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly ) return; } - send_search_entry( &backends[0], conn, op, e, attrs, attrsonly, 0 ); - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 ); + send_search_entry( &backends[0], conn, op, + e, attrs, attrsonly, 0, NULL ); + send_search_result( conn, op, LDAP_SUCCESS, + NULL, NULL, NULL, NULL, 1 ); entry_free( e ); } @@ -1179,3 +1181,35 @@ oc_print( ObjectClass *oc ) } #endif + + +int is_entry_objectclass( + Entry* e, + char* oc) +{ + Attribute *attr; + struct berval bv; + + if( e == NULL || oc == NULL || *oc == '\0' ) + return 0; + + /* + * find objectClass attribute + */ + attr = attr_find(e->e_attrs, "objectclass"); + + if( attr == NULL ) { + /* no objectClass attribute */ + return 0; + } + + bv.bv_val = oc; + bv.bv_len = strlen( bv.bv_val ); + + if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) { + /* entry is not of this objectclass */ + return 0; + } + + return 1; +} \ No newline at end of file diff --git a/servers/slapd/schema/core.schema b/servers/slapd/schema/core.schema index fa5c8900a6..18d5430be4 100644 --- a/servers/slapd/schema/core.schema +++ b/servers/slapd/schema/core.schema @@ -432,3 +432,14 @@ objectclass ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdName ) objectclass ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' SUP top AUXILIARY ) + +# +# From draft-ietf-ldapext-nameref-00.txt +# used to represent referrals in the directory +# +attribute ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'URL Reference' + EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.1466.115.121.1.26 + USAGE distributedOperation ) + +objectclass ( 2.16.840.1.113730.3.2.6 NAME 'referral' + SUP top STRUCTURAL MAY ( ref ) ) diff --git a/servers/slapd/search.c b/servers/slapd/search.c index 38f44be01c..b9906a12c9 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -41,8 +41,8 @@ do_search( if( op->o_bind_in_progress ) { Debug( LDAP_DEBUG_ANY, "do_search: SASL bind in progress.\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL, - "SASL bind in progress" ); + send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + NULL, "SASL bind in progress", NULL, NULL ); return LDAP_SASL_BIND_IN_PROGRESS; } @@ -80,10 +80,27 @@ do_search( goto return_results; } - if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL - && scope != LDAP_SCOPE_SUBTREE ) { - send_ldap_disconnect( conn, op, - LDAP_PROTOCOL_ERROR, "decoding error" ); + switch( scope ) { + case LDAP_SCOPE_BASE: + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: + break; + default: + send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, + NULL, "invalid scope", NULL, NULL ); + rc = -1; + goto return_results; + } + + 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, LDAP_PROTOCOL_ERROR, + NULL, "invalid deref", NULL, NULL ); rc = -1; goto return_results; } @@ -100,7 +117,8 @@ do_search( send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, "decode error" ); } else { - send_ldap_result( conn, op, err, NULL, "Bad search filter" ); + send_ldap_result( conn, op, err, + NULL, "Bad search filter", NULL, NULL ); } goto return_results; } @@ -137,7 +155,6 @@ do_search( "conn=%d op=%d SRCH base=\"%s\" scope=%d filter=\"%s\"\n", conn->c_connid, op->o_opid, base, scope, fstr ); -#if defined( SLAPD_MONITOR_DN ) || defined( SLAPD_CONFIG_DN ) || defined( SLAPD_SCHEMA_DN ) if ( scope == LDAP_SCOPE_BASE ) { #if defined( SLAPD_MONITOR_DN ) if ( strcmp( base, SLAPD_MONITOR_DN ) == 0 ) { @@ -145,24 +162,25 @@ do_search( goto return_results; } #endif + #if defined( SLAPD_CONFIG_DN ) if ( strcmp( base, SLAPD_CONFIG_DN ) == 0 ) { config_info( conn, op ); goto return_results; } #endif + #if defined( SLAPD_SCHEMA_DN ) if ( strcmp( base, SLAPD_SCHEMA_DN ) == 0 ) { schema_info( conn, op, attrs, attrsonly ); goto return_results; } #endif - } -#endif /* monitor or config or schema dn */ - if ( strcmp( base, LDAP_ROOT_DSE ) == 0 && scope == LDAP_SCOPE_BASE ) { - root_dse_info( conn, op, attrs, attrsonly ); - goto return_results; + if ( strcmp( base, LDAP_ROOT_DSE ) == 0 ) { + root_dse_info( conn, op, attrs, attrsonly ); + goto return_results; + } } /* @@ -171,22 +189,19 @@ do_search( * if we don't hold it. */ if ( (be = select_backend( base )) == NULL ) { - send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS, NULL, - default_referral ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, default_referral, NULL ); goto return_results; } - /* translate the base if it matches an aliased base part */ - base = suffixAlias ( base, op, be ); - /* actually do the search and send the result(s) */ if ( be->be_search ) { (*be->be_search)( be, conn, op, base, scope, deref, sizelimit, timelimit, filter, fstr, attrs, attrsonly ); } else { - send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, NULL, - "Function not implemented" ); + send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM, + NULL, "Function not implemented", NULL, NULL ); } return_results:; diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 41438d271d..d7fd7eb4c4 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -193,11 +193,11 @@ typedef struct entry { struct access { #define ACL_NONE 0x0001 -#define ACL_AUTH 0x0002 -#define ACL_COMPARE 0x0004 -#define ACL_SEARCH 0x0008 -#define ACL_READ 0x0010 -#define ACL_WRITE 0x0020 +#define ACL_AUTH 0x0004 +#define ACL_COMPARE 0x0008 +#define ACL_SEARCH 0x0010 +#define ACL_READ 0x0020 +#define ACL_WRITE 0x0040 #define ACL_PRIV_MASK 0x00ff #define ACL_SELF 0x4000 @@ -394,12 +394,11 @@ struct backend_db { /* these should be renamed from be_ to bd_ */ char **be_suffix; /* the DN suffixes of data in this backend */ char **be_nsuffix; /* the normalized DN suffixes in this backend */ - char **be_suffixAlias; /* the DN suffix aliases of data in this backend */ char *be_root_dn; /* the magic "root" dn for this db */ char *be_root_ndn; /* the magic "root" normalized dn for this db */ char *be_root_pw; /* the magic "root" password for this db */ int be_readonly; /* 1 => db is in "read only" mode */ - int be_maxDerefDepth; /* limit for depth of an alias deref */ + unsigned int be_max_deref_depth; /* limit for depth of an alias deref */ int be_sizelimit; /* size limit for this backend */ int be_timelimit; /* time limit for this backend */ struct acl *be_acl; /* access control list for this backend */ @@ -407,6 +406,7 @@ struct backend_db { char **be_replica; /* replicas of this backend (in master) */ char *be_replogfile; /* replication log file (in master) */ char *be_update_ndn; /* allowed to make changes (in replicas) */ + struct berval **be_update_refs; /* where to refer modifying clients to */ int be_lastmod; /* keep track of lastmodified{by,time} */ char *be_realm; diff --git a/servers/slapd/slapd.at.conf b/servers/slapd/slapd.at.conf index c3c8b136b0..01451706ff 100644 --- a/servers/slapd/slapd.at.conf +++ b/servers/slapd/slapd.at.conf @@ -3,6 +3,7 @@ attribute personalsignature bin attribute jpegphoto bin attribute audio bin attribute labeledurl ces +attribute ref ces attribute userpassword ces attribute telephonenumber tel attribute facsimiletelephonenumber fax tel diff --git a/servers/slapd/slapd.dsp b/servers/slapd/slapd.dsp index a8c39ef68b..ebe7203c0f 100644 --- a/servers/slapd/slapd.dsp +++ b/servers/slapd/slapd.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # 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 hs_regex.lib libdb.lib wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 hs_regex.lib libdb.lib ws2_32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "slapd - Win32 Debug" @@ -77,7 +77,7 @@ BSC32=bscmake.exe # 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 hs_regex.lib libdb.lib wsock32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 hs_regex.lib libdb.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ELSEIF "$(CFG)" == "slapd - Win32 Single Debug" @@ -102,7 +102,7 @@ BSC32=bscmake.exe # 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 hs_regex.lib libdb.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 hs_regex.lib libdb.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ELSEIF "$(CFG)" == "slapd - Win32 Single Release" @@ -127,7 +127,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 hs_regex.lib libdb.lib wsock32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 hs_regex.lib libdb.lib wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 hs_regex.lib libdb.lib ws2_32.lib /nologo /subsystem:console /machine:I386 !ENDIF diff --git a/servers/slapd/slapd.dsw b/servers/slapd/slapd.dsw index e9c636c214..b3c3ca4ded 100644 --- a/servers/slapd/slapd.dsw +++ b/servers/slapd/slapd.dsw @@ -102,6 +102,18 @@ Package=<4> ############################################################################### +Project: "setup"=..\..\include\setup.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "slapd"=.\slapd.dsp - Package Owner=<4> Package=<5> @@ -134,6 +146,9 @@ Package=<4> Begin Project Dependency Project_Dep_Name libslapd End Project Dependency + Begin Project Dependency + Project_Dep_Name setup + End Project Dependency }}} ############################################################################### diff --git a/servers/slapd/slapd.oc.conf b/servers/slapd/slapd.oc.conf index 5759eb6da1..56d90c531d 100644 --- a/servers/slapd/slapd.oc.conf +++ b/servers/slapd/slapd.oc.conf @@ -7,6 +7,11 @@ objectclass alias aliasedObjectName, objectClass +objectclass referral + requires + ref, + objectClass + objectclass dcobject requires objectClass, diff --git a/servers/slapd/suffixalias.c b/servers/slapd/suffixalias.c deleted file mode 100644 index 8751d83773..0000000000 --- a/servers/slapd/suffixalias.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved. - * - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file in the top level - * directory of this package. - */ -/* Portions - * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC - * 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 ITSD, Government of BC. The name of ITSD - * 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 -#include -#include -#include "slap.h" - -/* - * given a normalized uppercased dn (or root part), return an aliased dn if any of the - * alias suffixes match - */ -char *suffixAlias (char *dn, Operation *op, Backend *be) -{ - int i, dnLength; - - if(dn == NULL) return NULL; - - dnLength = strlen ( dn ); - for ( i = 0; - be->be_suffixAlias != NULL && be->be_suffixAlias[i] != NULL; - i += 2) { - int aliasLength = strlen (be->be_suffixAlias[i]); - int diff = dnLength - aliasLength; - - if ( diff < 0 ) { - /* alias is longer than dn */ - continue; - } else if ( diff > 0 ) { - if ( ! DNSEPARATOR(dn[diff-1]) ) { - /* boundary is not at a DN separator */ - continue; - } - /* At a DN Separator */ - /* XXX or an escaped separator... oh well */ - } - - if (!strcmp(be->be_suffixAlias[i], &dn[diff])) { - char *oldDN = dn; - dn = ch_malloc( diff + strlen(be->be_suffixAlias[i+1]) + 1 ); - strncpy( dn, oldDN, diff ); - strcpy( &dn[diff], be->be_suffixAlias[i+1] ); - Debug( LDAP_DEBUG_ARGS, "SuffixAlias: converted \"%s\" to \"%s\"\n", - oldDN, dn, 0); - free (oldDN); - break; - } - } - return dn; -} diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 917a1e0c36..70ffa26384 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -50,7 +50,7 @@ OBJS2 = mimic.o \ ../module.o ../aclparse.o ../schema.o ../filterentry.o \ ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \ ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \ - ../schemaparse.o + ../controls.o ../schemaparse.o all-local: build-ldbm build-bdb2 build-edb2ldif build-chlog2replog diff --git a/servers/slapd/tools/ldbmcat.dsp b/servers/slapd/tools/ldbmcat.dsp index ab55b065f8..e74b773e51 100644 --- a/servers/slapd/tools/ldbmcat.dsp +++ b/servers/slapd/tools/ldbmcat.dsp @@ -126,7 +126,7 @@ BSC32=bscmake.exe # 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 libdb.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\libraries\Release" +# ADD LINK32 libdbs.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\libraries\Release" !ENDIF @@ -140,5 +140,9 @@ LINK32=link.exe SOURCE=.\ldbmcat.c # End Source File +# Begin Source File + +SOURCE=.\mimic.c +# End Source File # End Target # End Project diff --git a/servers/slapd/tools/ldbmtest.c b/servers/slapd/tools/ldbmtest.c index dcf169f5a4..afe0588fca 100644 --- a/servers/slapd/tools/ldbmtest.c +++ b/servers/slapd/tools/ldbmtest.c @@ -205,6 +205,7 @@ main( int argc, char **argv ) free_and_close( dbc, key, data ); break; +#ifndef HAVE_WINSOCK case 'e': /* edit an entry */ if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL )) == NULL ) { @@ -243,6 +244,7 @@ main( int argc, char **argv ) free_and_close( dbc, key, data ); break; +#endif case 'a': /* add an entry */ if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL )) @@ -499,6 +501,7 @@ get_entry( FILE *fp, Datum *data ) data->dsize = psize + 1; } +#ifndef HAVE_WINSOCK static void edit_entry( char c, Datum *data ) { @@ -565,6 +568,7 @@ edit_entry( char c, Datum *data ) fclose( fp ); unlink( tmpname ); } +#endif static struct dbcache * openfile( char *name, int namesiz, int mode, int verbose, char c ) diff --git a/servers/slapd/tools/ldbmtest.dsp b/servers/slapd/tools/ldbmtest.dsp index 3f193c4415..6bd91f19b9 100644 --- a/servers/slapd/tools/ldbmtest.dsp +++ b/servers/slapd/tools/ldbmtest.dsp @@ -54,7 +54,7 @@ BSC32=bscmake.exe # 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 libdb.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libdb.lib hs_regex.lib ws2_32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "ldbmtest - Win32 Debug" @@ -70,7 +70,7 @@ LINK32=link.exe # 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 /MD /W3 /Gm /GX /Zi /Od /I "..\..\..\include" /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" /YX /FD /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -78,7 +78,7 @@ BSC32=bscmake.exe # 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 libdb.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdb.lib hs_regex.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ELSEIF "$(CFG)" == "ldbmtest - Win32 Single Debug" @@ -102,7 +102,7 @@ BSC32=bscmake.exe # 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 libdb.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libdbs.lib hs_regex.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ELSEIF "$(CFG)" == "ldbmtest - Win32 Single Release" @@ -126,7 +126,7 @@ BSC32=bscmake.exe # 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 libdb.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libdbs.lib hs_regex.lib ws2_32.lib /nologo /subsystem:console /machine:I386 !ENDIF @@ -140,5 +140,9 @@ LINK32=link.exe SOURCE=.\ldbmtest.c # End Source File +# Begin Source File + +SOURCE=.\mimic.c +# End Source File # End Target # End Project diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c index be5a177ab7..ea598b18c6 100644 --- a/servers/slapd/tools/mimic.c +++ b/servers/slapd/tools/mimic.c @@ -23,25 +23,40 @@ int str2result( return 0; } +void +send_ldap_disconnect( + Connection *conn, + Operation *op, + ber_int_t err, + char *text +) +{ + assert(0); +} + void send_ldap_result( Connection *conn, Operation *op, int err, char *matched, - char *text + char *text, + struct berval **refs, + LDAPControl **ctrls ) { assert(0); } void -send_ldap_search_result( +send_search_result( Connection *conn, Operation *op, int err, char *matched, char *text, + struct berval **refs, + LDAPControl **ctrls, int nentries ) { @@ -56,9 +71,32 @@ send_search_entry( Entry *e, char **attrs, int attrsonly, - int opattrs + int opattrs, + LDAPControl **ctrls ) { assert(0); return -1; } + +int send_search_reference( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + struct berval **refs, + int scope, + LDAPControl **ctrls, + struct berval ***v2refs +) +{ + assert(0); + return -1; +} + +struct berval **get_entry_referrals( + Backend *be, Connection *conn, Operation *op, Entry *e ) +{ + assert(0); + return NULL; +} diff --git a/tests/data/referrals.ldif b/tests/data/referrals.ldif new file mode 100644 index 0000000000..9e605ac244 --- /dev/null +++ b/tests/data/referrals.ldif @@ -0,0 +1,50 @@ +dn: c=US +c: US +objectclass: country + +dn: o=ABC, c=US +o: ABC +ref: ldap//hostA/o=abc,c=us HostA +ref: ldap//hostB/o=abc,c=us HostB +objectclass: referral +objectclass: extensibleObject + +dn: o=XYZ, c=US +o: XYZ +ref: ldap//hostC/o=xyz,c=us HostC +objectclass: referral +objectclass: extensibleObject + +dn: o=Alias, c=US +o: Alias +aliasedObjectName: o=University of Michigan, c=US +objectclass: alias +objectclass: extensibleObject + +dn: o=University of Michigan, c=US +o: University of Michigan +objectclass: organization + +dn: cn=Manager, o=University of Michigan, c=US +cn: Manager +cn: Directory Manager +cn: Dir Man +sn: Manager +description: Manager of the directory +userpassword: secret +objectclass: person + +dn: cn=Alias, o=University of Michigan, c=US +cn: Alias +aliasedobjectname: cn=Manager, o=University of Michigan, c=US +objectclass: extensibleObject + +dn: cn=Circular, o=University of Michigan, c=US +cn: Circular +aliasedobjectname: cn=Circular, o=University of Michigan, c=US +objectclass: extensibleObject + +dn: cn=Subordinate, o=University of Michigan, c=US +cn: Subordinate +aliasedobjectname: cn=Subordinate, cn=Alias, o=University of Michigan, c=US +objectclass: extensibleObject diff --git a/tests/data/slapd-acl.conf b/tests/data/slapd-acl.conf index 69fb8b2601..8e0e328b9d 100644 --- a/tests/data/slapd-acl.conf +++ b/tests/data/slapd-acl.conf @@ -22,6 +22,11 @@ index default none lastmod on defaultaccess none +# +# normal installations should protect root dse, +# cn=monitor, cn=schema, and cn=config +# + access to attr=objectclass by * read diff --git a/tests/data/slapd-bdb2-ref-slave.conf b/tests/data/slapd-bdb2-ref-slave.conf new file mode 100644 index 0000000000..1495bfd337 --- /dev/null +++ b/tests/data/slapd-bdb2-ref-slave.conf @@ -0,0 +1,28 @@ +# +# slave slapd config -- for default referral testing +# +include ./data/slapd.at.conf +include ./data/slapd.oc.conf +schemacheck off +pidfile ./test-repl/slapd.pid +argsfile ./test-repl/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +referral "ldap://localhost:9009/" + +backend bdb2 +home ./test-db + +database bdb2 +cachesize 0 +suffix "o=University of Mich, c=US" +directory ./test-repl +rootdn "cn=Manager, o=University of Mich, c=US" +rootpw secret +index cn,sn,uid pres,eq,approx +index default none +# index default pres,eq,approx +lastmod on diff --git a/tests/data/slapd-bdb2-repl-master.conf b/tests/data/slapd-bdb2-repl-master.conf index 3fca276902..5491bcd7b9 100644 --- a/tests/data/slapd-bdb2-repl-master.conf +++ b/tests/data/slapd-bdb2-repl-master.conf @@ -28,6 +28,6 @@ lastmod on 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-bdb2-repl-slave.conf b/tests/data/slapd-bdb2-repl-slave.conf index 3782b628af..7051425d15 100644 --- a/tests/data/slapd-bdb2-repl-slave.conf +++ b/tests/data/slapd-bdb2-repl-slave.conf @@ -7,6 +7,8 @@ schemacheck off pidfile ./test-repl/slapd.pid argsfile ./test-repl/slapd.args +referral "ldap://localhost:9009/" + ####################################################################### # ldbm database definitions ####################################################################### @@ -18,9 +20,10 @@ database bdb2 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" +updatedn "cn=Replica, o=University of Michigan, c=US" +updateref "ldap://localhost:9009/o=University%20of%20Michigan,c=US" index cn,sn,uid pres,eq,approx index default none # index default pres,eq,approx diff --git a/tests/data/slapd-ref-slave.conf b/tests/data/slapd-ref-slave.conf new file mode 100644 index 0000000000..9fa77fb978 --- /dev/null +++ b/tests/data/slapd-ref-slave.conf @@ -0,0 +1,25 @@ +# +# slave slapd config -- for default referral testing +# +include ./data/slapd.at.conf +include ./data/slapd.oc.conf +schemacheck off +pidfile ./test-repl/slapd.pid +argsfile ./test-repl/slapd.args + +####################################################################### +# ldbm database definitions +####################################################################### + +referral "ldap://localhost:9009/" + +database ldbm +cachesize 0 +suffix "o=University of Mich, c=US" +directory ./test-repl +rootdn "cn=Manager, o=University of Mich, c=US" +rootpw secret +index cn,sn,uid pres,eq,approx +index default none +# index default pres,eq,approx +lastmod on diff --git a/tests/data/slapd-repl-master.conf b/tests/data/slapd-repl-master.conf index c3e1657285..d0220ddd08 100644 --- a/tests/data/slapd-repl-master.conf +++ b/tests/data/slapd-repl-master.conf @@ -25,6 +25,6 @@ lastmod on 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 886a987edb..02fc97d6f8 100644 --- a/tests/data/slapd-repl-slave.conf +++ b/tests/data/slapd-repl-slave.conf @@ -7,6 +7,8 @@ schemacheck off pidfile ./test-repl/slapd.pid argsfile ./test-repl/slapd.args +referral "ldap://localhost:9009/" + ####################################################################### # ldbm database definitions ####################################################################### @@ -15,9 +17,10 @@ database 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" +updatedn "cn=Replica, o=University of Michigan, c=US" +updateref "ldap://localhost:9009/o=University%20of%20Michigan,c=US" index cn,sn,uid pres,eq,approx index default none # index default pres,eq,approx diff --git a/tests/data/slapd.at.conf b/tests/data/slapd.at.conf index c3c8b136b0..01451706ff 100644 --- a/tests/data/slapd.at.conf +++ b/tests/data/slapd.at.conf @@ -3,6 +3,7 @@ attribute personalsignature bin attribute jpegphoto bin attribute audio bin attribute labeledurl ces +attribute ref ces attribute userpassword ces attribute telephonenumber tel attribute facsimiletelephonenumber fax tel diff --git a/tests/data/slapd.oc.conf b/tests/data/slapd.oc.conf index 02e3b2bdb1..fe077cdfa3 100644 --- a/tests/data/slapd.oc.conf +++ b/tests/data/slapd.oc.conf @@ -7,6 +7,11 @@ objectclass alias aliasedObjectName, objectClass +objectclass referral + requires + ref, + objectClass + objectclass country requires objectClass, diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 736d3ad75d..4f5256e0d2 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -8,6 +8,7 @@ if test "$BACKEND" = "bdb2" ; then ACLCONF=$DATADIR/slapd-bdb2-acl.conf MASTERCONF=$DATADIR/slapd-bdb2-repl-master.conf SLAVECONF=$DATADIR/slapd-bdb2-repl-slave.conf + REFSLAVECONF=$DATADIR/slapd-bdb2-ref-slave.conf TIMING="-t" else LDIF2LDBM=../servers/slapd/tools/ldif2ldbm @@ -15,6 +16,7 @@ else ACLCONF=$DATADIR/slapd-acl.conf MASTERCONF=$DATADIR/slapd-repl-master.conf SLAVECONF=$DATADIR/slapd-repl-slave.conf + REFSLAVECONF=$DATADIR/slapd-ref-slave.conf fi if test "$LDAP_PROTO" ; then @@ -41,8 +43,10 @@ DBDIR=./test-db REPLDIR=./test-repl LDIF=$DATADIR/test.ldif LDIFORDERED=$DATADIR/test-ordered.ldif +MONITOR="cn=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" diff --git a/tests/scripts/test002-populate b/tests/scripts/test002-populate index 80a0479a6f..d12e14accf 100755 --- a/tests/scripts/test002-populate +++ b/tests/scripts/test002-populate @@ -22,8 +22,8 @@ PID=$! echo "Using ldapsearch to check that slapd is running..." for i in 0 1 2 3 4 5; do - $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $PORT \ - 'cn=Monitor' > /dev/null 2>&1 + $LDAPSEARCH -L -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..." diff --git a/tests/scripts/test003-search b/tests/scripts/test003-search index 03179910f6..7c1942879d 100755 --- a/tests/scripts/test003-search +++ b/tests/scripts/test003-search @@ -30,8 +30,8 @@ PID=$! 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 -L -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..." diff --git a/tests/scripts/test004-modify b/tests/scripts/test004-modify index fa3bc01985..b21483a3fe 100755 --- a/tests/scripts/test004-modify +++ b/tests/scripts/test004-modify @@ -30,8 +30,8 @@ PID=$! echo "Testing slapd modify operations..." 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 -L -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..." diff --git a/tests/scripts/test005-modrdn b/tests/scripts/test005-modrdn index a6115be9f2..5dc9f3cdfe 100755 --- a/tests/scripts/test005-modrdn +++ b/tests/scripts/test005-modrdn @@ -31,8 +31,8 @@ echo "Testing slapd modrdn operations..." # Make sure we can search the database 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 -L -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..." diff --git a/tests/scripts/test006-acls b/tests/scripts/test006-acls index 58d1215407..05323fc619 100755 --- a/tests/scripts/test006-acls +++ b/tests/scripts/test006-acls @@ -30,8 +30,8 @@ PID=$! echo "Testing slapd access control..." for i in 0 1 2 3 4 5; do - $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ - 'cn=Monitor' > /dev/null 2>&1 + $LDAPSEARCH -L -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..." diff --git a/tests/scripts/test007-replication b/tests/scripts/test007-replication index 8a79f7d3e0..9e400f8f93 100755 --- a/tests/scripts/test007-replication +++ b/tests/scripts/test007-replication @@ -43,8 +43,8 @@ SLAVEPID=$! echo "Using ldapsearch to check that master slapd is running..." for i in 0 1 2 3 4 5; do - $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $PORT \ - 'cn=Monitor' > /dev/null 2>&1 + $LDAPSEARCH -L -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..." @@ -54,8 +54,8 @@ done echo "Using ldapsearch to check that slave slapd is running..." for i in 0 1 2 3 4 5; do - $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $SLAVEPORT \ - 'cn=Monitor' > /dev/null 2>&1 + $LDAPSEARCH -L -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..." @@ -67,7 +67,7 @@ echo "Starting slurpd..." $SLURPD -f $MASTERCONF -d 4 -t $REPLDIR > $SLURPLOG 2>&1 & SLURPPID=$! -echo "Using ldapadd to populate the database..." +echo "Using ldapadd to populate the master directory..." $LDAPADD -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD < \ $LDIFORDERED > /dev/null 2>&1 RC=$? @@ -77,12 +77,16 @@ if test $RC != 0 ; then exit $RC fi -echo "Using ldapmodify to modify the database..." +echo "Waiting 15 seconds for slurpd to send changes..." +sleep 15 + +echo "Using ldapmodify to modify slave directory..." + # # Do some modifications # -$LDAPMODIFY -v -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD > \ +$LDAPMODIFY -v -D "$MANAGERDN" -h localhost -p $SLAVEPORT -w $PASSWD > \ /dev/null 2>&1 << EOMODS dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US changetype: modify diff --git a/tests/scripts/test008-concurrency b/tests/scripts/test008-concurrency index 6ac569b08f..5b8958fc82 100755 --- a/tests/scripts/test008-concurrency +++ b/tests/scripts/test008-concurrency @@ -34,8 +34,16 @@ echo "Starting slapd on TCP/IP port $PORT..." $SLAPD -f $CONF -p $PORT -d $LVL $TIMING > $MASTERLOG 2>&1 & PID=$! -echo "Waiting 5 seconds for slapd to start..." -sleep 5 +echo "Using ldapsearch to check that slapd is running..." +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -L -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 "Using tester for concurrent server access..." $SLAPDTESTER -b "$BASEDN" -P "$PROGDIR" -d "$DATADIR" -h localhost -p $PORT -D "$MANAGERDN" -w $PASSWD -l 50 diff --git a/tests/scripts/test009-referral b/tests/scripts/test009-referral new file mode 100755 index 0000000000..05bdd222d6 --- /dev/null +++ b/tests/scripts/test009-referral @@ -0,0 +1,126 @@ +#! /bin/sh + +# +# Test default referral +# + +if test $# -eq 0 ; then + SRCDIR="." +else + SRCDIR=$1; shift +fi +if test $# -eq 1 ; then + BACKEND=$1; shift +fi + +echo "running defines.sh $SRCDIR $BACKEND" +. $SRCDIR/scripts/defines.sh + +echo "Cleaning up in $DBDIR and $REPLDIR ..." + +rm -f $DBDIR/[!C]* +rm -f $REPLDIR/[!C]* + +echo "Running ldif2ldbm to build slapd database..." +$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools +RC=$? +if test $RC != 0 ; then + echo "ldif2ldbm failed!" + exit $RC +fi + +echo "Starting master slapd on TCP/IP port $PORT..." +$SLAPD -f $CONF -p $PORT -d $LVL $TIMING > $MASTERLOG 2>&1 & +PID=$! + +echo "Starting slave slapd on TCP/IP port $SLAVEPORT..." +$SLAPD -f $REFSLAVECONF -p $SLAVEPORT -d $LVL $TIMING > $SLAVELOG 2>&1 & +SLAVEPID=$! + +echo "Testing for master slapd..." +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -L -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!" + kill -HUP $PID + exit $RC +fi + +echo "Testing for slave slapd..." +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -L -s base -b "$MONITOR" -h localhost -p $SLAVEPORT \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 1 ; then + echo "Waiting 5 seconds for slapd to start..." + sleep 5 + fi +done + +cat /dev/null > $SEARCHOUT + +echo "Testing exact searching..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $SLAVEPORT \ + 'sn=jensen' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed!" + kill -HUP $PID $SLAVEPID + exit $RC +fi + +echo "Testing OR searching..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $SLAVEPORT \ + '(|(objectclass=rfc822mailgroup)(sn=jones))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed!" + kill -HUP $PID $SLAVEPID + exit $RC +fi + +echo "Testing AND matching and ends-with searching..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $SLAVEPORT \ + '(&(objectclass=rfc822mailgroup)(cn=A*))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed!" + kill -HUP $PID $SLAVEPID + exit $RC +fi + +echo "Testing NOT searching..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $SLAVEPORT \ + '(!(objectclass=person))' >> $SEARCHOUT 2>&1 +if test $RC != 0 ; then + echo "ldapsearch failed!" + kill -HUP $PID $SLAVEPID + exit $RC +fi + +kill -HUP $PID $SLAVEPID + +TESTOUT=$SEARCHOUT +LDIF=$SEARCHOUTMASTER + +echo "Filtering ldapsearch results..." +. $SRCDIR/scripts/acfilter.sh < $SEARCHOUT > $SEARCHFLT +echo "Filtering original ldif used to create database..." +. $SRCDIR/scripts/acfilter.sh < $LDIF > $LDIFFLT +echo "Comparing filter output..." +cmp $SEARCHFLT $LDIFFLT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + + +exit 0 -- 2.39.5