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; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + char **dnlist; - if (!e) return NULL; /* be sure we have a starting entry */ + assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) ); - Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 ); + *matched = NULL; + *err = LDAP_SUCCESS; + *text = NULL; - /* - * 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) - { + if( alias == NULL ) { + dn = ch_strdup( dn ); + entry = bdb2i_dn2entry_r( be, dn, &sup ); - /* - * 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; -} - -/* - * 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 */ - } - 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); - } - /* 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 ); + dn = ch_strdup( alias->e_ndn ); + entry = alias; + sup = 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 ); + dnlist = NULL; + charray_add( &dnlist, dn ); - return newDN; + 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; } + + +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; +} + +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; +} + +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; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + int rc = 1; + Attribute *attr; + struct berval bv; - Debug( LDAP_DEBUG_TRACE, + 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 ); - } + } - - /* check for deleted */ - - /* 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 * - */ + /* 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; + rc = 1; - Debug( LDAP_DEBUG_ARGS, "<= bdb2i_back_group: found objectClass and %s\n", groupattrName, 0, 0 ); + 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; + } - bvObjectClass.bv_val = objectclassValue; - bvObjectClass.bv_len = strlen( bvObjectClass.bv_val ); + bv.bv_val = "ALIAS"; + bv.bv_len = sizeof("ALIAS")-1; - bvMembers.bv_val = op_ndn; - bvMembers.bv_len = strlen( op_ndn ); + 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; + } - 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 = "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; - - } else { - ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e ); + goto done; } + 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); +static ID_BLOCK *base_candidate( + Backend *be, Entry *e ); -#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 *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_ARGS, "=> bdb2i_back_search\n", 0, 0, 0); + 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 ); + + 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 - */ + if ( scope == LDAP_SCOPE_BASE) { + candidates = base_candidate( be, e ); - switch ( deref ) { - case LDAP_DEREF_FINDING: - case LDAP_DEREF_ALWAYS: - realBase = bdb2i_derefDN ( be, conn, op, base ); - break; - default: - realBase = ch_strdup(base); + } else { + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); } - (void) dn_normalize_case( realBase ); + /* need normalized dn below */ + realbase = ch_strdup( e->e_ndn ); + bdb2i_cache_return_entry_r( &li->li_cache, e ); - 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 ); - } - - /* null candidates means we could not find the base object */ 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 ); + + rc = 1; + goto done; } - if ( matched != NULL ) { - free( matched ); - } - - 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 ); - free( dn ); - } - - 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 ); - } - - /* - * 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; - } - - 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 ); - } - } - } - } + 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'); + } + + } 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 ) { + 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, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e = NULL; - Filter *f; - char buf[20]; - ID_BLOCK *candidates; - - Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0); - - *err = LDAP_SUCCESS; - - /* 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 ); - } - - /* - * 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 ); - } - return( candidates ); -} - -static ID_BLOCK * -subtree_candidates( - BackendDB *be, - Connection *conn, - Operation *op, - char *base, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, +search_candidates( + Backend *be, Entry *e, - int *err, - int lookupbase + Filter *filter, + int scope, + int deref, + int manageDSAit ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Filter *f, **filterarg_ptr; ID_BLOCK *candidates; + Filter *f, *rf, *af, *lf; - Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n", - base ? base : "NULL", lookupbase ? "lookupbase" : "", 0); + Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" s=%d d=%d\n", + e->e_ndn, scope, deref ); - /* - * 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; - if ( base != NULL && *base != '\0' && - (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } - - if (e) { - bdb2i_cache_return_entry_r( &li->li_cache, e ); - } - - 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; - } + 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; } - candidates = bdb2i_filter_candidates( be, filter ); + 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; + } - /* free up just the parts we allocated above */ - if ( f != NULL ) { - *filterarg_ptr = NULL; - filter_free( f ); + 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) ); + + 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 ); + + lf->f_and->f_next = f; + f = lf; + + } else if ( scope == LDAP_SCOPE_ONELEVEL ) { + char buf[16]; + + 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, 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 ); + } + + 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,21 +103,55 @@ ldbm_back_add( free(pdn); - if ( matched != NULL ) { - free( matched ); - } - if ( ! access_allowed( be, conn, op, p, "children", NULL, ACL_WRITE ) ) { - Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, - 0, 0 ); - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - "", "" ); - /* 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 ); + + 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; } @@ -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; /* to free cache entries */ - Attribute *a; - int depth; - char *matched; - Entry *origDN = e; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + char **dnlist; - if (!e) return NULL; /* be sure we have a starting entry */ + assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) ); - Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 ); + *matched = NULL; + *err = LDAP_SUCCESS; + *text = NULL; - /* - * 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) - { + if( alias == NULL ) { + dn = ch_strdup( dn ); + entry = dn2entry_r( be, dn, &sup ); - /* - * 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; + } else { + dn = ch_strdup( alias->e_ndn ); + entry = alias; + sup = NULL; + } - 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); + dnlist = NULL; + charray_add( &dnlist, dn ); - /* - * release past lock if not original - */ - if ( (depth > 0) && e ) { - cache_return_entry_r(&li->li_cache, e); - } + for( depth=0 ; ; depth++ ) { + if( entry != NULL ) { + Entry *newe; + char *aliasDN; - /* 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; - } + /* have entry, may be an alias */ - /* 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; - } + if( !is_entry_alias( entry ) ) { + /* entry is not an alias */ + 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 ) { + /* 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; + } - /* 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" ); + /* deref entry */ + aliasDN = get_alias_dn( entry, err, text ); - if (matched != NULL) free(matched); - free (newDN); - free (oldDN); - break; - } + if( aliasDN == NULL ) { + *matched = entry; + entry = NULL; + 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; - } - } + /* 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; + } - /* - * 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" ); - } + /* attempt to dereference alias */ - return e; + 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; } -/* - * 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 -) -{ - 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 ); +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ) +{ + Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" ); - /* 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 */ + 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 */ - 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); + /* + * 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 */ - 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( a->a_vals[1] != NULL ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias has multivalued aliasedObjectName"; + return NULL; + } - if (newDN == NULL) { - newDN = ch_strdup ( dn ); - } - - Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); - - return newDN; + return a->a_vals[0]->bv_val; } + +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; +} + +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-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,35 +20,44 @@ 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; } + + 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 ( 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; - } - #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL if ( ! access_allowed( be, conn, op, e, "entry", NULL, ACL_WRITE ) ) @@ -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; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + int rc = 1; - Debug( LDAP_DEBUG_TRACE, + 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 ); - } + } - - /* check for deleted */ - - /* 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 * - */ + /* 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; + 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; - Debug( LDAP_DEBUG_ARGS, "<= ldbm_back_group: found objectClass and %s\n", groupattrName, 0, 0 ); + 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; + } - bvObjectClass.bv_val = objectclassValue; - bvObjectClass.bv_len = strlen( bvObjectClass.bv_val ); + bv.bv_val = "REFERRAL"; + bv.bv_len = sizeof("REFERRAL")-1; - bvMembers.bv_val = op_ndn; - bvMembers.bv_len = strlen( op_ndn ); + 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; + } - 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; - } - } + 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 ); } - /* Modify the entry */ - if ( ldbm_modify_internal( be, conn, op, dn, modlist, e ) != 0 ) { + 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, "" ); - if ( matched != NULL ) { - free( 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 ) { + 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); +static ID_BLOCK *base_candidate( + Backend *be, Entry *e ); -#define GRABSIZE BUFSIZ +static ID_BLOCK *search_candidates( + Backend *be, Entry *e, Filter *filter, + int scope, int deref, int manageDSAit ); -#define MAKE_SPACE( n ) { \ - if ( rcur + (n) > rbuf + rmaxsize ) { \ - int offset = rcur - rbuf; \ - rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \ - rmaxsize += GRABSIZE; \ - rcur = rbuf + offset; \ - } \ -} int ldbm_back_search( @@ -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_ARGS, "=> ldbm_back_search\n", 0, 0, 0); + 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 ); + + } 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 - */ + if ( scope == LDAP_SCOPE_BASE) { + candidates = base_candidate( be, e ); - switch ( deref ) { - case LDAP_DEREF_FINDING: - case LDAP_DEREF_ALWAYS: - realBase = derefDN ( be, conn, op, base ); - break; - default: - realBase = ch_strdup(base); + } else { + candidates = search_candidates( be, e, filter, + scope, deref, manageDSAit ); } - (void) dn_normalize_case( realBase ); + /* need normalized dn below */ + realbase = ch_strdup( e->e_ndn ); + cache_return_entry_r( &li->li_cache, e ); - 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 ); - } - - /* null candidates means we could not find the base object */ 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 ); + + rc = 1; + goto done; } - if ( matched != NULL ) { - free( matched ); - } - - 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 ); - free( dn ); - } - - 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 ); - } - - /* - * 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; - } - } - 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 ); - } - } - } - } + 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'); + } + + } 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; + } + + 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 */ + 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, - Filter *filter, - char **attrs, - int attrsonly, - char **matched, - int *err -) -{ - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Entry *e = NULL; - Filter *f; - char buf[20]; - ID_BLOCK *candidates; - - Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0); - - *err = LDAP_SUCCESS; - - /* 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 ); - } - - /* - * 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 ); - } - 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 + Filter *filter, + int scope, + int deref, + int manageDSAit ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - Filter *f, **filterarg_ptr; ID_BLOCK *candidates; + Filter *f, *rf, *af, *lf; - Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n", - base ? base : "NULL", lookupbase ? "lookupbase" : "", 0); + Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" s=%d d=%d\n", + e->e_ndn, scope, deref ); - /* - * 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; - if ( base != NULL && *base != '\0' && - (e = dn2entry_r( be, base, matched )) == NULL ) - { - *err = LDAP_NO_SUCH_OBJECT; - return( NULL ); - } - - if (e) { - cache_return_entry_r( &li->li_cache, e ); - } - - 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; - } + 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; } - candidates = filter_candidates( be, filter ); + 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; + } - /* free up just the parts we allocated above */ - if ( f != NULL ) { - *filterarg_ptr = NULL; - filter_free( f ); + 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) ); + + 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 ); + + lf->f_and->f_next = f; + f = lf; + + } else if ( scope == LDAP_SCOPE_ONELEVEL ) { + char buf[16]; + + 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, 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 ); + } + + 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); + matched = ch_strdup( base ); - /* Use the first attribute of the DN - * as an attribute within the entry itself. - */ - rdn = dn_rdn(NULL, base); + 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 ); - if( rdn == NULL || (s = strchr(rdn, '=')) == NULL ) { - err = LDAP_INVALID_DN_SYNTAX; - goto done; - } + /* Use the first attribute of the DN + * as an attribute within the entry itself. + */ + rdn = dn_rdn(NULL, base); - val.bv_val = rdn_attr_value(rdn); - val.bv_len = strlen( val.bv_val ); - attr_merge( e, rdn_attr_type(rdn), vals ); + if( rdn == NULL || (s = strchr(rdn, '=')) == NULL ) { + err = LDAP_INVALID_DN_SYNTAX; + goto done; + } - free(rdn); - rdn = NULL; + val.bv_val = rdn_attr_value(rdn); + val.bv_len = strlen( val.bv_val ); + attr_merge( e, rdn_attr_type(rdn), vals ); - /* 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 ); + 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,376 +9,150 @@ #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 ) - - assert( LDAP_UNSOLICITED_ERROR( err ) ); - - } 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; - - case LDAP_REQ_SEARCH: - tag = LDAP_RES_SEARCH_RESULT; - break; - - case LDAP_REQ_DELETE: - tag = LDAP_RES_DELETE; - break; - - default: - tag = op->o_tag + 1; - break; - } + 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; } - - ber = ber_alloc_t( LBER_USE_DER ); - - 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 - if( tag == LDAP_RES_EXTENDED ) { - rc = ber_printf( ber, "{it{esss}}", - msgid, tag, err, - "", text ? text : "", - LDAP_NOTICE_DISCONNECT ); - - } else { - rc = ber_printf( ber, "{it{ess}}", - msgid, tag, err, - matched ? matched : "", text ? text : "" ); - } - - if ( rc == -1 ) { - Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); - return; - } - - /* 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 */ - ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - - /* write the pdu */ - bytes = ber_pvt_ber_bytes( ber ); - - 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; - } - - if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) { - break; - } - - err = errno; - - /* - * we got an error. if it's ewouldblock, we need to - * wait on the socket being writable. otherwise, figure - * it's a hard error and return. - */ - - Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n", - err, err > -1 && err < sys_nerr ? sys_errlist[err] - : "unknown", 0 ); - - if ( err != EWOULDBLOCK && err != EAGAIN ) { - connection_closing( conn ); - - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - return; - } - - /* wait for socket to be write-ready */ - conn->c_writewaiter = 1; - slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 ); - - ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); - conn->c_writewaiter = 0; - } - - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); - - ldap_pvt_thread_mutex_lock( &num_sent_mutex ); - num_bytes_sent += bytes; - 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; + v2[len-1] = '\0'; + return v2; } -void -send_ldap_result( - Connection *conn, - Operation *op, - ber_int_t err, - char *matched, - char *text -) +static ber_tag_t req2res( ber_tag_t tag ) { - assert( !LDAP_API_ERROR( err ) ); + switch( tag ) { + case LDAP_REQ_ADD: + case LDAP_REQ_BIND: + case LDAP_REQ_COMPARE: + case LDAP_REQ_EXTENDED: + case LDAP_REQ_MODIFY: + case LDAP_REQ_MODRDN: + tag++; + break; - Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", - err, matched ? matched : "", text ? text : "" ); + case LDAP_REQ_DELETE: + tag = LDAP_RES_DELETE; + break; -#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 ); + 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; } -#endif - send_ldap_result2( conn, op, 0, err, matched, text, 0 ); + return tag; } -void -send_ldap_disconnect( - Connection *conn, - Operation *op, - ber_int_t err, - char *text -) +static void trim_refs_urls( + struct berval **refs ) { - assert( !LDAP_API_ERROR( err ) ); + unsigned i; - Debug( LDAP_DEBUG_TRACE, - "send_ldap_disconnect %d:%s\n", - err, text ? text : "", NULL ); + if( refs == NULL ) return; -#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_result2( conn, op, 0, err, NULL, text, 0 ); -} - -void -send_ldap_search_result( - Connection *conn, - Operation *op, - ber_int_t err, - char *matched, - char *text, - int nentries -) -{ - 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 ); -} - -int -send_search_entry( - Backend *be, - Connection *conn, - Operation *op, - Entry *e, - char **attrs, - int attrsonly, - int opattrs -) -{ - BerElement *ber; - Attribute *a; - int i, rc=-1, bytes; - struct acl *acl; - char *edn; - - Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); - -#if defined( SLAPD_SCHEMA_DN ) - { - /* this could be backend specific */ - struct berval val; - val.bv_val = SLAPD_SCHEMA_DN; - val.bv_len = strlen( val.bv_val ); - attr_merge( e, "subschemaSubentry", vals ); - ldap_memfree( val.bv_val ); - } -#endif - - if ( ! access_allowed( be, conn, op, e, - "entry", NULL, ACL_READ ) ) - { - Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n", - 0, 0, 0 ); - return( 1 ); - } - - edn = e->e_ndn; - - ber = ber_alloc_t( LBER_USE_DER ); - - 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" ); - goto error_return; - } - - rc = ber_printf( ber, "{it{s{", op->o_msgid, - LDAP_RES_SEARCH_ENTRY, e->e_dn ); - - 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" ); - goto error_return; - } - - 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 )) { - continue; + 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; + + attr = attr_find( e->e_attrs, "ref" ); + + if( attr == NULL ) return NULL; + + for( i=0; attr->a_vals[i] != NULL; i++ ) { + /* count references */ + } + + if( i < 1 ) return NULL; + + 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 { - /* specific addrs requested */ - if ( !charray_inlist( attrs, a->a_type ) - && !charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ) ) - { - continue; - } - } - - acl = acl_get_applicable( be, op, e, a->a_type, - MAXREMATCHES, matches ); - - if ( ! acl_access_allowed( acl, be, conn, e, - NULL, op, ACL_READ, edn, matches ) ) - { - continue; - } - - if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -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 type" ); - goto error_return; - } - - if ( ! attrsonly ) { - for ( i = 0; a->a_vals[i] != NULL; i++ ) { - if ( a->a_syntax & SYNTAX_DN && - ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op, - ACL_READ, edn, matches) ) - { - continue; - } - - if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -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 value" ); - goto error_return; - } - } - } - - if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -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 type end" ); - goto error_return; + ber_bvfree( ref ); } } - rc = ber_printf( ber, /*{{{*/ "}}}" ); + refs[j] = NULL; - 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" ); - return( 1 ); + if( j == 0 ) { + ber_bvecfree( refs ); + refs = NULL; } - bytes = ber_pvt_ber_bytes( ber ); + /* 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 ); @@ -431,9 +205,430 @@ send_search_entry( 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 ); + return; +} + + +void +send_ldap_disconnect( + Connection *conn, + Operation *op, + ber_int_t err, + char *text +) +{ + ber_tag_t tag; + ber_int_t msgid; + char *reqoid; + +#define LDAP_UNSOLICITED_ERROR(e) \ + ( (e) == LDAP_PROTOCOL_ERROR \ + || (e) == LDAP_STRONG_AUTH_REQUIRED \ + || (e) == LDAP_UNAVAILABLE ) + + assert( LDAP_UNSOLICITED_ERROR( err ) ); + + 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 ) { + 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, 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_result( + Connection *conn, + Operation *op, + ber_int_t err, + 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_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 ) { + 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, 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_search_result( + Connection *conn, + Operation *op, + ber_int_t err, + char *matched, + 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 : "" ); + + 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, + Connection *conn, + Operation *op, + Entry *e, + char **attrs, + int attrsonly, + int opattrs, + LDAPControl **ctrls +) +{ + BerElement *ber; + Attribute *a; + 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 ); + +#if defined( SLAPD_SCHEMA_DN ) + { + /* this could be backend specific */ + struct berval val; + val.bv_val = SLAPD_SCHEMA_DN; + val.bv_len = strlen( val.bv_val ); + attr_merge( e, "subschemaSubentry", vals ); + ldap_memfree( val.bv_val ); + } +#endif + + if ( ! access_allowed( be, conn, op, e, + "entry", NULL, ACL_READ ) ) + { + Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n", + 0, 0, 0 ); + return( 1 ); + } + + edn = e->e_ndn; + + ber = ber_alloc_t( LBER_USE_DER ); + + if ( ber == NULL ) { + Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "allocating BER error", NULL, NULL ); + goto error_return; + } + + rc = ber_printf( ber, "{it{s{", op->o_msgid, + LDAP_RES_SEARCH_ENTRY, e->e_dn ); + + 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, "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 ) ) { + continue; + } + + } else { + /* specific addrs requested */ + if ( !allattrs && !charray_inlist( attrs, a->a_type ) ) { + continue; + } + } + + acl = acl_get_applicable( be, op, e, a->a_type, + MAXREMATCHES, matches ); + + if ( ! acl_access_allowed( acl, be, conn, e, + NULL, op, ACL_READ, edn, matches ) ) + { + continue; + } + + if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -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, "encoding type error", NULL, NULL ); + goto error_return; + } + + if ( ! attrsonly ) { + for ( i = 0; a->a_vals[i] != NULL; i++ ) { + if ( a->a_syntax & SYNTAX_DN && + ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op, + ACL_READ, edn, matches) ) + { + continue; + } + + if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -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, "encoding value error", NULL, NULL ); + goto error_return; + } + } + } + + if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -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, "encode end error", NULL, NULL ); + goto error_return; + } + } + + rc = ber_printf( ber, /*{{{*/ "}}}" ); + + 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, "encode entry end error", NULL, NULL ); + return( 1 ); + } + + bytes = send_ldap_ber( conn, ber ); + + if ( bytes < 0 ) { + Debug( LDAP_DEBUG_ANY, + "send_ldap_response: ber write failed\n", + 0, 0, 0 ); + return -1; + } + 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 ); Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n", @@ -447,6 +642,96 @@ error_return:; return( rc ); } +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_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); + + 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 ); + } + + 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; + } + + ber = ber_alloc_t( LBER_USE_DER ); + + 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; + } + + 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_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", + (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 ); + + Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); + + 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