diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c index f55cb80aa15d2bc2bf83bfc057d768979e58e4b8..427952c5fa027e43b57a931f692257a0a923287f 100644 --- a/clients/tools/ldapmodify.c +++ b/clients/tools/ldapmodify.c @@ -103,12 +103,14 @@ usage( const char *prog ) " specified by \"-f file\".\n" "Add or modify options:\n" " -a add values (default%s)\n" +" -c continuous operation mode (do not stop on errors)\n" +" -f file read operations from `file'\n" " -F force all changes records to be used\n" +" -S file write skipped modifications to `file'\n" "Common options:\n" " -d level set LDAP debugging level to `level'\n" " -D binddn bind DN\n" -" -f file read operations from `file'\n" " -h host LDAP server\n" " -H URI LDAP Uniform Resource Indentifier(s)\n" " -I use SASL Interactive mode\n" @@ -138,10 +140,11 @@ usage( const char *prog ) int main( int argc, char **argv ) { - char *infile, *rbuf, *start; - FILE *fp; + char *infile, *rejfile, *rbuf, *start, *rejbuf; + FILE *fp, *rejfp; + char *matched_msg = NULL, *error_msg = NULL; int rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals; - int count; + int count, len; if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) { prog = argv[ 0 ]; @@ -156,12 +159,13 @@ main( int argc, char **argv ) ldapadd = ( strncmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 ); infile = NULL; + rejfile = NULL; not = verbose = want_bindpw = debug = manageDSAit = referrals = 0; authmethod = -1; version = -1; while (( i = getopt( argc, argv, "acrf:F" - "Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF ) + "Cd:D:h:H:IkKMnO:p:P:QR:S:U:vw:WxX:Y:Z" )) != EOF ) { switch( i ) { /* Modify Options */ @@ -403,6 +407,13 @@ main( int argc, char **argv ) return( EXIT_FAILURE ); #endif break; + case 'S': /* skipped modifications to file */ + if( rejfile != NULL ) { + fprintf( stderr, "%s: -S previously specified\n", prog ); + return EXIT_FAILURE; + } + rejfile = strdup( optarg ); + break; case 'U': #ifdef HAVE_CYRUS_SASL if( sasl_authc_id != NULL ) { @@ -539,6 +550,15 @@ main( int argc, char **argv ) if ( argc != optind ) usage( prog ); + if ( rejfile != NULL ) { + if (( rejfp = fopen( rejfile, "w" )) == NULL ) { + perror( rejfile ); + return( EXIT_FAILURE ); + } + } else { + rejfp = NULL; + } + if ( infile != NULL ) { if (( fp = fopen( infile, "r" )) == NULL ) { perror( infile ); @@ -671,6 +691,7 @@ main( int argc, char **argv ) ldap_perror( ld, "ldap_bind" ); return( EXIT_FAILURE ); } + } } @@ -707,10 +728,33 @@ main( int argc, char **argv ) start = rbuf; + if ( rejfp ) { + len = strlen( rbuf ); + if (( rejbuf = (char *)malloc( len+1 )) == NULL ) { + perror( "realloc" ); + exit( EXIT_FAILURE ); + } + memcpy( rejbuf, rbuf, len+1 ); + } + rc = process_ldif_rec( start, count ); - if( rc ) - fprintf( stderr, "ldif_record() = %d\n", rc ); + if ( rc && rejfp ) { + fprintf(rejfp, "# Error: %s (%d)", ldap_err2string(rc), rc); + + ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg); + if ( matched_msg != NULL && *matched_msg != '\0' ) { + fprintf( rejfp, ", matched DN: %s", matched_msg ); + } + + ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &error_msg); + if ( error_msg != NULL && *error_msg != '\0' ) { + fprintf( rejfp, ", additional info: %s", error_msg ); + } + fprintf( rejfp, "\n%s\n", rejbuf ); + } + if (rejfp) + free( rejbuf ); free( rbuf ); } @@ -718,6 +762,10 @@ main( int argc, char **argv ) ldap_unbind( ld ); } + if ( rejfp != NULL ) { + fclose( rejfp ); + } + return( rc ); } diff --git a/doc/devel/args b/doc/devel/args index ea02cfa4f42b29bc149ef7cb40d1ddf91ba19b60..e000234440bafbba36332d93f384a1ed179576e1 100644 --- a/doc/devel/args +++ b/doc/devel/args @@ -1,6 +1,6 @@ Tools ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ldapdelete *CDE *HI*K M*OPQR U*WXYZ cdef*h**k *n*p* vwx* -ldapmodify *CDEF*HI*K M*OPQR U*WXYZabcdef*h**k *n*p*r t vwx* +ldapmodify *CDEF*HI*K M*OPQRS U*WXYZabcdef*h**k *n*p*r t vwx* ldapmodrdn *CDE *HI*K M*OPQR U*WXYZ cdef*h**k *n*p*rs vwx* ldappasswd A*CDE *HI* *O QRS U*WXYZa de *h** * * * s vwx* ldapsearch A*CDE *HI*KLM*OPQRSTU*WXYZab*def*h**kl*n*p* stuvwx*z diff --git a/doc/man/man1/ldapmodify.1 b/doc/man/man1/ldapmodify.1 index 3ffbe59a92f63c27156d2ad78e69edb06a2bb692..139753363277a7a1d0f0658884a00e6c5d5e949c 100644 --- a/doc/man/man1/ldapmodify.1 +++ b/doc/man/man1/ldapmodify.1 @@ -1,36 +1,113 @@ -.TH LDAPMODIFY 1 "13 November 1995" "U-M LDAP LDVERSION" +.TH LDAPMODIFY 1 "20 August 2001" "OpenLDAP LDVERSION" +.\" $OpenLDAP$ +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldapmodify, ldapadd \- ldap modify entry and ldap add entry tools +ldapmodify, ldapadd \- LDAP modify entry and LDAP add entry tools .SH SYNOPSIS .B ldapmodify -.B [\-a] -.B [\-b] -.B [\-c] -.B [\-r] -.B [\-n] -.B [\-v] -.B [\-k] -.B [\-d debuglevel] -.B [\-D binddn] -.B [\-w passwd] -.B [\-h ldaphost] -.B [\-p ldapport] -.B [\-f file] +[\c +.BR \-a ] +[\c +.BR \-c ] +[\c +.BI \-S \ file\fR] +.[\c +.BR \-C ] +[\c +.BR \-n ] +[\c +.BR \-v ] +[\c +.BR \-k ] +[\c +.BR \-K ] +[\c +.BR \-M[M] ] +[\c +.BI \-d \ debuglevel\fR] +[\c +.BI \-D \ binddn\fR] +[\c +.BR \-W ] +[\c +.BI \-w \ passwd\fR] +[\c +.BI \-H \ ldapuri\fR] +[\c +.BI \-h \ ldaphost\fR] +[\c +.BI \-p \ ldapport\fR] +[\c +.BI \-P \ 2\fR\||\|\fI3\fR] +[\c +.BR \-O \ security-properties ] +[\c +.BR \-I ] +[\c +.BR \-Q ] +[\c +.BI \-U \ authcid\fR] +[\c +.BR \-x ] +[\c +.BI \-X \ authzid\fR] +[\c +.BI \-Y \ mech\fR] +[\c +.BR \-Z[Z] ] +[\c +.BI \-f \ file\fR] .LP .B ldapadd -.B [\-b] -.B [\-c] -.B [\-r] -.B [\-n] -.B [\-v] -.B [\-k] -.B [\-K] -.B [\-d debuglevel] -.B [\-D binddn] -.B [\-w passwd] -.B [\-h ldaphost] -.B [\-p ldapport] -.B [\-f file] +[\c +.BR \-c ] +[\c +.BI \-S \ file\fR] +[\c +.BR \-C ] +[\c +.BR \-n ] +[\c +.BR \-v ] +[\c +.BR \-k ] +[\c +.BR \-K ] +[\c +.BR \-M[M] ] +[\c +.BI \-d \ debuglevel\fR] +[\c +.BI \-D \ binddn\fR] +[\c +.BR \-W ] +[\c +.BI \-w \ passwd\fR] +[\c +.BI \-h \ ldaphost\fR] +[\c +.BI \-p \ ldapport\fR] +[\c +.BI \-P \ 2\fR\||\|\fI3\fR] +[\c +.BR \-O \ security-properties ] +[\c +.BR \-I ] +[\c +.BR \-Q ] +[\c +.BI \-U \ authcid\fR] +[\c +.BR \-x ] +[\c +.BI \-X \ authzid\fR] +[\c +.BI \-Y \ mech\fR] +[\c +.BR \-Z[Z] ] +[\c +.BI \-f \ file\fR] .SH DESCRIPTION .B ldapmodify is a shell-accessible interface to the @@ -56,10 +133,8 @@ is to modify existing entries. If invoked as .BR ldapadd , this flag is always set. .TP -.B \-b -Assume that any values that start with a `/' are binary values and that -the actual value is in a file whose path is specified in the place where -values normally appear. +.B \-C +Automatically chase referrals. .TP .B \-c Continuous operation mode. Errors are reported, but @@ -67,8 +142,10 @@ Continuous operation mode. Errors are reported, but will continue with modifications. The default is to exit after reporting an error. .TP -.B \-r -Replace existing values by default. +.BI \-S \ file +Add or change records which where skipped due to an error are written to \fIfile\fP +and the error message returned by the server is added as a comment. Most useful in +conjunction with -c. .TP .B \-n Show what would be done, but don't actually modify entries. Useful for @@ -78,14 +155,14 @@ debugging in conjunction with -v. Use verbose mode, with many diagnostics written to standard output. .TP .B \-k -Use Kerberos authentication instead of simple authentication. It is +Use Kerberos IV authentication instead of simple authentication. It is assumed that you already have a valid ticket granting ticket. You must -compile with KERBEROS defined for this option to have any effect. +compile with Kerberos support for this option to have any effect. .TP .B \-K -Same as \-k, but only does step 1 of the kerberos bind. This is useful +Same as \-k, but only does step 1 of the Kerberos IV bind. This is useful when connecting to a slapd and there is no x500dsa.hostname principal -registered with your kerberos servers. +registered with your Kerberos Domain Controller(s). .TP .B \-F Force application of all changes regardless of the contents of input @@ -94,36 +171,85 @@ 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 \-d debuglevel +.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 must be compiled with LDAP_DEBUG defined for this option to have any effect. .TP -.B \-f file +.BI \-f \ file Read the entry modification information from \fIfile\fP instead of from standard input. .TP -.B \-D binddn -Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be -a string-represented DN as defined in RFC 1779. +.B \-x +Use simple authentication instead of SASL. +.TP +.BI \-D \ binddn +Use the Distinguished Name \fIbinddn\fP to bind to the LDAP directory. .TP -.B \-w passwd +.B \-W +Prompt for simple authentication. +This is used instead of specifying the password on the command line. +.TP +.BI \-w \ passwd Use \fIpasswd\fP as the password for simple authentication. .TP -.B \-h ldaphost +.BI \-H \ ldapuri +Specify URI(s) referring to the ldap server(s). +.TP +.BI \-h \ ldaphost Specify an alternate host on which the ldap server is running. +Deprecated in favor of -H. .TP -.B \-p ldapport +.BI \-p \ ldapport Specify an alternate TCP port where the ldap server is listening. +Deprecated in favor of -H. +.TP +.BI \-P \ 2\fR\||\|\fI3 +Specify the LDAP protocol version to use. +.TP +.BI \-O \ security-properties +Specify SASL security properties. +.TP +.B \-I +Enable SASL Interactive mode. Always prompt. Default is to prompt +only as needed. +.TP +.B \-Q +Enable SASL Quiet mode. Never prompt. +.TP +.BI \-U \ authcid +Specify the authentication ID for SASL bind. The form of the ID +depends on the actual SASL mechanism used. +.TP +.BI \-X \ authzid +Specify the requested authorization ID for SASL bind. +.I authzid +must be one of the following formats: +.B dn:\c +.I <distinguished name> +or +.B u:\c +.I <username> +.TP +.BI \-Y \ mech +Specify the SASL mechanism to be used for authentication. If it's not +specified, the program will choose the best mechanism the server knows. +.TP +.B \-Z[Z] +Issue StartTLS (Transport Layer Security) extended operation. If you use +.B \-ZZ\c +, the command will require the operation to be successful. .SH INPUT FORMAT The contents of \fIfile\fP (or standard input if no \-f flag is given on the command line) should conform to the format defined in .BR slapd.replog (5), with the exceptions noted below. .LP -If the first line of a record consists of a decimal number (entry id), -it is ignored. -.LP Lines that begin with "replica:" are matched against the LDAP server host and port in use to decide if a particular replog record should be applied. Any other lines that precede the "dn:" line are ignored. @@ -138,8 +264,10 @@ flag is set (or if the program was invoked as and "modify" otherwise. .LP If changetype is "modify" and no "add:", "replace:", or "delete:" lines -appear, the default is "replace" if the -r flag is set and "add" -otherwise. +appear, the default is "replace" for and "add" +.BR ldapmodify (1) +for +.BR ldapadd (1). .LP Note that the above exceptions to the .BR slapd.replog (5) @@ -149,56 +277,22 @@ entries to be used as input to .I ldapmodify or .I ldapadd. -.SH ALTERNATIVE INPUT FORMAT -An alternative input format is supported for compatibility with older -versions of -.I ldapmodify. -This format consists of one or more entries separated by blank lines, -where each entry looks like: -.LP -.nf - Distinguished Name (DN) - attr=value - [attr=value ...] -.fi -.LP -where \fIattr\fP is the name of the attribute and \fIvalue\fP is the -value. -.LP -By default, values are added. If the -.RI \- r -command line flag is -given, the default is to replace existing values with the new one. -Note that it is permissible for a given attribute to appear more than -once (for example, to add more than one value for an attribute). Also -note that you can use a trailing `\\' to continue values across lines and -preserve newlines in the value itself (this is useful for modifying -QUIPU iattr attributes among others). -.LP -.I attr -should be preceded by a \fB-\fP to remove a value. The `=' and -value should be omitted to remove an entire attribute. -.LP -.I attr -should be preceded by a \fB+\fP to add a value in the presence of the -\-r flag. -.LP .SH EXAMPLES Assuming that the file .B /tmp/entrymods exists and has the contents: .LP .nf - dn: cn=Modify Me, o=University of Michigan, c=US + dn: cn=Modify Me,dc=example,dc=com changetype: modify replace: mail - mail: modme@terminator.rs.itd.umich.edu + mail: modme@OpenLDAP.org - add: title title: Grand Poobah - add: jpegPhoto - jpegPhoto: /tmp/modme.jpeg + jpegPhoto:< file://tmp/modme.jpeg - delete: description - @@ -207,12 +301,12 @@ exists and has the contents: the command: .LP .nf - ldapmodify -b -r -f /tmp/entrymods + ldapmodify -f /tmp/entrymods .fi .LP will replace the contents of the "Modify Me" entry's .I mail -attribute with the value "modme@terminator.rs.itd.umich.edu", add a +attribute with the value "modme@example.com", add a .I title of "Grand Poobah", and the contents of the file "/tmp/modme.jpeg" as a @@ -220,36 +314,19 @@ as a and completely remove the .I description attribute. -The same modifications as above can be performed using the older -.I ldapmodify -inout format: -.LP -.nf - cn=Modify Me, o=University of Michigan, c=US - mail=modme@terminator.rs.itd.umich.edu - +title=Grand Poobah - +jpegPhoto=/tmp/modme.jpeg - -description -.fi -.LP -and the command: -.LP -.nf - ldapmodify -b -r -f /tmp/entrymods -.fi .LP Assuming that the file .B /tmp/newentry exists and has the contents: .LP .nf - dn: cn=Barbara Jensen, o=University of Michigan, c=US + dn: cn=Barbara Jensen,dc=example,dc=com objectClass: person cn: Barbara Jensen cn: Babs Jensen sn: Jensen title: the world's most famous mythical manager - mail: bjensen@terminator.rs.itd.umich.edu + mail: bjensen@example.com uid: bjensen .LP the command: @@ -267,7 +344,7 @@ Assuming that the file exists and has the contents: .LP .nf - dn: cn=Barbara Jensen, o=University of Michigan, c=US + dn: cn=Barbara Jensen,dc=example,dc=com changetype: delete .LP the command: @@ -278,24 +355,24 @@ the command: .LP will remove Babs Jensen's entry. .SH DIAGNOSTICS -Exit status is 0 if no errors occur. Errors result in a non-zero exit -status and a diagnostic message being written to standard error. +Exit status is zero if no errors occur. Errors result in a non-zero +exit status and a diagnostic message being written to standard error. .SH "SEE ALSO" .BR ldapadd (1), .BR ldapdelete (1), .BR ldapmodrdn (1), .BR ldapsearch (1), +.BR ldap.conf (5), .BR ldap (3), .BR ldap_add (3), .BR ldap_delete (3), .BR ldap_modify (3), .BR ldap_modrdn (3), .BR slapd.replog (5) -.LP -Kille, S., -.IR "A String Representation of Distinguished Names", -.SM RFC -1779, -ISODE Consortium, March 1995. -.SH BUGS -There is no interactive mode, but there probably should be. +.SH AUTHOR +The OpenLDAP Project <http://www.openldap.org/> +.SH ACKNOWLEDGEMENTS +.B OpenLDAP +is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). +.B OpenLDAP +is derived from University of Michigan LDAP 3.3 Release. diff --git a/libraries/libldap/cache.c b/libraries/libldap/cache.c index ccfc763092d3973aac0e8100edb35cceeb2ccba9..83e6e7953cbe9b0ff8da07f23f52149eb1999bf9 100644 --- a/libraries/libldap/cache.c +++ b/libraries/libldap/cache.c @@ -37,6 +37,9 @@ static void uncache_entry_or_req LDAP_P(( LDAP *ld, LDAP_CONST char *dn, ber_in int ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifndef LDAP_NOCACHE if ( ld->ld_cache == NULL ) { if (( ld->ld_cache = (LDAPCache *)LDAP_MALLOC( sizeof( LDAPCache ))) @@ -62,6 +65,9 @@ ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem ) void ldap_disable_cache( LDAP *ld ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { ld->ld_cache->lc_enabled = 0; @@ -74,6 +80,9 @@ ldap_disable_cache( LDAP *ld ) void ldap_set_cache_options( LDAP *ld, unsigned long opts ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { ld->ld_cache->lc_options = opts; @@ -85,6 +94,9 @@ ldap_set_cache_options( LDAP *ld, unsigned long opts ) void ldap_destroy_cache( LDAP *ld ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifndef LDAP_NOCACHE if ( ld->ld_cache != NULL ) { ldap_flush_cache( ld ); @@ -102,6 +114,9 @@ ldap_flush_cache( LDAP *ld ) int i; LDAPMessage *m, *next; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_flush_cache\n" )); #else @@ -134,6 +149,9 @@ ldap_flush_cache( LDAP *ld ) void ldap_uncache_request( LDAP *ld, int msgid ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifndef LDAP_NOCACHE #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, @@ -152,6 +170,10 @@ ldap_uncache_request( LDAP *ld, int msgid ) void ldap_uncache_entry( LDAP *ld, LDAP_CONST char *dn ) { + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( dn != NULL ); + #ifndef LDAP_NOCACHE #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, @@ -240,6 +262,9 @@ ldap_add_request_to_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request ) LDAPMessage *new; ber_len_t len; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_add_request_to_cache\n" )); #else @@ -288,6 +313,10 @@ ldap_add_result_to_cache( LDAP *ld, LDAPMessage *result ) LDAPMessage *m, **mp, *req, *new, *prev; int err, keep; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( result != NULL ); + #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, "ldap_add_result_to_cache: id %ld, type %ld\n", @@ -447,6 +476,10 @@ ldap_check_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request ) int first, hash; time_t c_time; + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( request != NULL ); + #ifdef NEW_LOGGING LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_check_cache\n" )); #else diff --git a/libraries/libldap/compare.c b/libraries/libldap/compare.c index 83d7ec125e934325daa614f8e27b0f6f3b25576c..4af59d01b8d15842a6a5f44db0244028d1a04c66 100644 --- a/libraries/libldap/compare.c +++ b/libraries/libldap/compare.c @@ -131,6 +131,8 @@ ldap_compare( int msgid; struct berval bvalue; + assert( value != NULL ); + bvalue.bv_val = (char *) value; bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); @@ -171,6 +173,8 @@ ldap_compare_s( { struct berval bvalue; + assert( value != NULL ); + bvalue.bv_val = (char *) value; bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c index 76c2799236133b46dc3e2dcc760936d29b8e37cf..12f455be9863cc1e9fc97ef205d6a2b14abc3bd5 100644 --- a/libraries/libldap/controls.c +++ b/libraries/libldap/controls.c @@ -38,6 +38,7 @@ ldap_int_put_controls( LDAPControl *const *c; assert( ld != NULL ); + assert( LDAP_VALID(ld) ); assert( ber != NULL ); if( ctrls == NULL ) { @@ -414,6 +415,7 @@ ldap_create_control( struct berval *bvalp; assert( requestOID != NULL ); + assert( ber != NULL ); assert( ctrlp != NULL ); ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); @@ -452,6 +454,7 @@ int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls ) LDAPControl *const *c; assert( ld != NULL ); + assert( LDAP_VALID(ld) ); if( ctrls == NULL ) { /* use default server controls */ diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c index c35eb0d5a996c2a90d84c205bc67f2973f1dc02b..b2707577dfa0e6c6f7dccd4c462a9e5de2cef1d4 100644 --- a/libraries/libldap/cyrus.c +++ b/libraries/libldap/cyrus.c @@ -434,19 +434,6 @@ ldap_int_sasl_open( int rc; sasl_conn_t *ctx; - sasl_callback_t *session_callbacks = - LDAP_CALLOC( 2, sizeof( sasl_callback_t ) ); - - if( session_callbacks == NULL ) return LDAP_NO_MEMORY; - - session_callbacks[0].id = SASL_CB_USER; - session_callbacks[0].proc = NULL; - session_callbacks[0].context = ld; - - session_callbacks[1].id = SASL_CB_LIST_END; - session_callbacks[1].proc = NULL; - session_callbacks[1].context = NULL; - assert( lc->lconn_sasl_ctx == NULL ); if ( host == NULL ) { @@ -456,14 +443,13 @@ ldap_int_sasl_open( #if SASL_VERSION_MAJOR >= 2 rc = sasl_client_new( "ldap", host, NULL, NULL, - session_callbacks, 0, &ctx ); + NULL, 0, &ctx ); #else - rc = sasl_client_new( "ldap", host, session_callbacks, + rc = sasl_client_new( "ldap", host, NULL, SASL_SECURITY_LAYER, &ctx ); #endif if ( rc != SASL_OK ) { - LDAP_FREE( session_callbacks ); ld->ld_errno = sasl_err2ldap( rc ); return ld->ld_errno; } @@ -477,7 +463,6 @@ ldap_int_sasl_open( #endif lc->lconn_sasl_ctx = ctx; - lc->lconn_sasl_cbs = session_callbacks; if( ssf ) { #if SASL_VERSION_MAJOR >= 2 @@ -510,8 +495,6 @@ int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) if( ctx != NULL ) { sasl_dispose( &ctx ); lc->lconn_sasl_ctx = NULL; - LDAP_FREE( lc->lconn_sasl_cbs ); - lc->lconn_sasl_cbs = NULL; } return LDAP_SUCCESS; diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c index 1a763c9b6efc3b419206f83e464d11cab6988cb7..cc193e93582bef587dcfb15c511b60feaf00d18d 100644 --- a/libraries/libldap/dnssrv.c +++ b/libraries/libldap/dnssrv.c @@ -41,9 +41,8 @@ int ldap_dn2domain( char *domain = NULL; char **dn; - if( dn_in == NULL || domainp == NULL ) { - return -1; - } + assert( dn_in != NULL ); + assert( domainp != NULL ); dn = ldap_explode_dn( dn_in, 0 ); @@ -147,12 +146,12 @@ int ldap_domain2dn( char *domain, *s, *tok_r, *dn; size_t loc; - if (domain_in == NULL || dnp == NULL) { - return LDAP_NO_MEMORY; - } + assert( domain_in != NULL ); + assert( dnp != NULL ); + domain = LDAP_STRDUP(domain_in); if (domain == NULL) { - return LDAP_NO_MEMORY; + return LDAP_NO_MEMORY; } dn = NULL; loc = 0; diff --git a/libraries/libldap/getentry.c b/libraries/libldap/getentry.c index b75a4403f4e787efcffc57c15f2665bcaca5dd88..4fb23eff6cb69bc0993f0daec9c65963daf39231 100644 --- a/libraries/libldap/getentry.c +++ b/libraries/libldap/getentry.c @@ -29,10 +29,6 @@ ldap_first_entry( LDAP *ld, LDAPMessage *chain ) assert( LDAP_VALID( ld ) ); assert( chain != NULL ); - if( ld == NULL || chain == NULL ) { - return NULL; - } - return chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ? chain : ldap_next_entry( ld, chain ); @@ -45,11 +41,7 @@ ldap_next_entry( LDAP *ld, LDAPMessage *entry ) assert( LDAP_VALID( ld ) ); assert( entry != NULL ); - if ( ld == NULL || entry == NULL ) { - return NULL; - } - - for ( + for( entry = entry->lm_chain; entry != NULL; entry = entry->lm_chain ) @@ -70,10 +62,6 @@ ldap_count_entries( LDAP *ld, LDAPMessage *chain ) assert( ld != NULL ); assert( LDAP_VALID( ld ) ); - if ( ld == NULL ) { - return -1; - } - for ( i = 0; chain != NULL; chain = chain->lm_chain ) { if( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { i++; diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index cd10cde790ab87aaf485cf9b3ddcde46f3469ca7..4ad20dd9f4c813a6172fbc9e940e42b441803d9d 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -189,7 +189,6 @@ typedef struct ldap_conn { #endif #ifdef HAVE_CYRUS_SASL void *lconn_sasl_ctx; - void *lconn_sasl_cbs; #endif int lconn_refcnt; time_t lconn_lastused; /* time */ diff --git a/libraries/libldap/messages.c b/libraries/libldap/messages.c new file mode 100644 index 0000000000000000000000000000000000000000..bcb13a7f1461d4697705cdfe67387a07c183eec0 --- /dev/null +++ b/libraries/libldap/messages.c @@ -0,0 +1,55 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * messages.c + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +LDAPMessage * +ldap_first_message( LDAP *ld, LDAPMessage *chain ) +{ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( chain != NULL ); + + return chain; +} + +LDAPMessage * +ldap_next_message( LDAP *ld, LDAPMessage *msg ) +{ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( msg != NULL ); + + return msg->lm_chain; +} + +int +ldap_count_messages( LDAP *ld, LDAPMessage *chain ) +{ + int i; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + for ( i = 0; chain != NULL; chain = chain->lm_chain ) { + i++; + } + + return( i ); +} diff --git a/libraries/libldap/references.c b/libraries/libldap/references.c index 2aae3f469c5a0bcce38000b0685e601c19cb4a6f..ff9b63fc0c7902403a6716bee1cf279004311cd6 100644 --- a/libraries/libldap/references.c +++ b/libraries/libldap/references.c @@ -24,7 +24,7 @@ ldap_first_reference( LDAP *ld, LDAPMessage *chain ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); - assert( chain != NULL ); + assert( chain != NULL ); return chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ? chain @@ -36,7 +36,7 @@ ldap_next_reference( LDAP *ld, LDAPMessage *ref ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); - assert( ref != NULL ); + assert( ref != NULL ); for ( ref = ref->lm_chain; @@ -58,13 +58,7 @@ ldap_count_references( LDAP *ld, LDAPMessage *chain ) assert( ld != NULL ); assert( LDAP_VALID( ld ) ); - assert( chain != NULL ); - - if ( ld == NULL ) { - return -1; - } - for ( i = 0; chain != NULL; chain = chain->lm_chain ) { if( chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) { i++; diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index b7cc3e70ef661f6a08cb1c6d0550da567177b2fc..98fa9b85665a0c0e60fbc89325a5879ce13856ac 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -23,7 +23,7 @@ bdb_add( struct bdb_info *bdb = (struct bdb_info *) be->be_private; struct berval pdn; Entry *p = NULL; - int rc; + int rc, ret; const char *text; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; @@ -33,6 +33,8 @@ bdb_add( #ifdef BDB_SUBENTRIES int subentry; #endif + u_int32_t locker; + DB_LOCK lock; #if 0 u_int32_t lockid; DB_LOCK lock; @@ -108,6 +110,8 @@ retry: /* transaction retry */ text = "internal error"; goto return_results; } + + locker = TXN_ID ( ltid ); #if 0 lockid = TXN_ID( ltid ); #endif @@ -142,7 +146,7 @@ retry: /* transaction retry */ #endif /* get parent */ - rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 ); + rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0, locker, &lock ); switch( rc ) { case 0: @@ -169,7 +173,7 @@ retry: /* transaction retry */ refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r(&bdb->bi_cache, matched); + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched ); matched = NULL; } else { @@ -200,7 +204,7 @@ retry: /* transaction retry */ case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: /* free parent and reader lock */ - bdb_cache_return_entry_r( &bdb->bi_cache, p ); + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p ); p = NULL; goto retry; } @@ -262,7 +266,7 @@ retry: /* transaction retry */ matched_dn, NULL, refs, NULL ); ber_bvarray_free( refs ); - bdb_cache_return_entry_r( &bdb->bi_cache, p ); + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p ); p = NULL; goto done; } @@ -275,7 +279,7 @@ retry: /* transaction retry */ #endif /* free parent and reader lock */ - bdb_cache_return_entry_r( &bdb->bi_cache, p ); + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p ); p = NULL; } else { @@ -430,9 +434,22 @@ retry: /* transaction retry */ text = "txn_prepare failed"; } else { + ret = bdb_cache_add_entry_rw(bdb->bi_dbenv, &bdb->bi_cache, e, CACHE_WRITE_LOCK, locker, &lock); +#if 0 if ( bdb_cache_add_entry_rw(&bdb->bi_cache, e, CACHE_WRITE_LOCK) != 0 ) - { +#endif + switch ( ret ) { + case 0: + break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + default: + ret = LDAP_OTHER; + } + + if ( ret ) { if(( rc=TXN_ABORT( ltid )) != 0 ) { text = "cache add & txn_abort failed"; } else { diff --git a/servers/slapd/back-bdb/attribute.c b/servers/slapd/back-bdb/attribute.c index 38203b994d3e245290427b0d29eb1e30a4962c8e..1277f0256104f9addae957f37ed24829b19ed65a 100644 --- a/servers/slapd/back-bdb/attribute.c +++ b/servers/slapd/back-bdb/attribute.c @@ -39,6 +39,9 @@ bdb_attribute( const char *entry_at_name = entry_at->ad_cname.bv_val; AccessControlState acl_state = ACL_STATE_INIT; + u_int32_t locker; + DB_LOCK lock; + #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ARGS, "bdb_attribute: gr dn: \"%s\"\n", entry_ndn->bv_val )); @@ -65,6 +68,11 @@ bdb_attribute( txn = boi->boi_txn; } + if ( txn != NULL ) + locker = TXN_ID ( txn ); + else + LOCK_ID ( bdb->bi_dbenv, &locker ); + if (target != NULL && dn_match(&target->e_nname, entry_ndn)) { /* we already have a LOCKED copy of the entry */ e = target; @@ -80,16 +88,23 @@ bdb_attribute( } else { +dn2entry_retry: /* can we find entry */ - rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0 ); + rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0, locker, &lock ); switch( rc ) { case DB_NOTFOUND: case 0: break; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto dn2entry_retry; default: if( txn != NULL ) { boi->boi_err = rc; } + else { + LOCK_ID_FREE( bdb->bi_dbenv, locker ); + } return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY; } if (e == NULL) { @@ -102,6 +117,9 @@ bdb_attribute( "=> bdb_attribute: cannot find entry: \"%s\"\n", entry_ndn->bv_val, 0, 0 ); #endif + if ( txn == NULL ) { + LOCK_ID_FREE( bdb->bi_dbenv, locker ); + } return LDAP_NO_SUCH_OBJECT; } @@ -205,7 +223,11 @@ bdb_attribute( return_results: if( target != e ) { /* free entry */ - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); + } + + if ( txn == NULL ) { + LOCK_ID_FREE( bdb->bi_dbenv, locker ); } #ifdef NEW_LOGGING diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index be89b98bf30361f5165387cc92175719c878f71b..784bbc89aaa40eeffa247c368991d747d9db1dc7 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -146,21 +146,27 @@ struct bdb_op_info { #if DB_VERSION_MAJOR < 4 #define LOCK_DETECT(env,f,t,a) lock_detect(env, f, t, a) #define LOCK_GET(env,i,f,o,m,l) lock_get(env, i, f, o, m, l) +#define LOCK_PUT(env,l) lock_put(env, l) #define TXN_CHECKPOINT(env,k,m,f) txn_checkpoint(env, k, m, f) #define TXN_BEGIN(env,p,t,f) txn_begin((env), p, t, f) #define TXN_PREPARE(txn,gid) txn_prepare((txn), (gid)) #define TXN_COMMIT(txn,f) txn_commit((txn), (f)) #define TXN_ABORT(txn) txn_abort((txn)) #define TXN_ID(txn) txn_id(txn) +#define LOCK_ID(env, locker) lock_id(env, locker) +#define LOCK_ID_FREE(env, locker) lock_id_free(env, locker) #else #define LOCK_DETECT(env,f,t,a) (env)->lock_detect(env, f, t, a) #define LOCK_GET(env,i,f,o,m,l) (env)->lock_get(env, i, f, o, m, l) +#define LOCK_PUT(env,l) (env)->lock_put(env, l) #define TXN_CHECKPOINT(env,k,m,f) (env)->txn_checkpoint(env, k, m, f) #define TXN_BEGIN(env,p,t,f) (env)->txn_begin((env), p, t, f) #define TXN_PREPARE(txn,g) (txn)->prepare((txn), (g)) #define TXN_COMMIT(txn,f) (txn)->commit((txn), (f)) #define TXN_ABORT(txn) (txn)->abort((txn)) #define TXN_ID(txn) (txn)->id(txn) +#define LOCK_ID(env, locker) (env)->lock_id(env, locker) +#define LOCK_ID_FREE(env, locker) (env)->lock_id_free(env, locker) #endif LDAP_END_DECL diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c index ad1bcfe3bb8315648d2da15b9a6ec51412cce818..be64c5b6a8c90ca587a63b51cbf81943868bf619 100644 --- a/servers/slapd/back-bdb/bind.c +++ b/servers/slapd/back-bdb/bind.c @@ -40,14 +40,20 @@ bdb_bind( AttributeDescription *password = slap_schema.si_ad_userPassword; + u_int32_t locker; + DB_LOCK lock; + #ifdef NEW_LOGGING LDAP_LOG (( "bind", LDAP_LEVEL_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val )); #else Debug( LDAP_DEBUG_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val, 0, 0); #endif + LOCK_ID(bdb->bi_dbenv, &locker); + +dn2entry_retry: /* get entry */ - rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock ); switch(rc) { case DB_NOTFOUND: @@ -56,10 +62,15 @@ bdb_bind( case LDAP_BUSY: send_ldap_result( conn, op, LDAP_BUSY, NULL, "ldap server busy", NULL, NULL ); + LOCK_ID_FREE(bdb->bi_dbenv, locker); return LDAP_BUSY; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto dn2entry_retry; default: send_ldap_result( conn, op, rc=LDAP_OTHER, NULL, "internal error", NULL, NULL ); + LOCK_ID_FREE(bdb->bi_dbenv, locker); return rc; } @@ -75,7 +86,7 @@ bdb_bind( ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock ); matched = NULL; } else { @@ -108,6 +119,8 @@ bdb_bind( NULL, NULL, NULL, NULL ); } + LOCK_ID_FREE(bdb->bi_dbenv, locker); + ber_bvarray_free( refs ); free( matched_dn ); @@ -274,9 +287,11 @@ bdb_bind( done: /* free entry and reader lock */ if( e != NULL ) { - bdb_cache_return_entry_r( &bdb->bi_cache, e ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); } + LOCK_ID_FREE(bdb->bi_dbenv, locker); + /* front end with send result on success (rc==0) */ return rc; } diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index 5038db4bc799bacf7dbe6f7982e621f379a1a0db..18854548fed61a6764105066e3f1d7348f53a697 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -132,6 +132,36 @@ bdb_cache_entry_private_init( Entry *e ) return 0; } +int +bdb_cache_entry_db_lock +( DB_ENV *env, u_int32_t locker, Entry *e, int rw, u_int32_t flags, DB_LOCK *lock ) +{ + int rc; + DBT lockobj; + int db_rw; + + if (rw) + db_rw = DB_LOCK_WRITE; + else + db_rw = DB_LOCK_READ; + + lockobj.data = e->e_nname.bv_val; + lockobj.size = e->e_nname.bv_len; + rc = LOCK_GET(env, locker, flags | DB_LOCK_NOWAIT, + &lockobj, db_rw, lock); + return rc; +} + +int +bdb_cache_entry_db_unlock +( DB_ENV *env, DB_LOCK *lock ) +{ + int rc; + + rc = LOCK_PUT ( env, lock ); + return rc; +} + /* * marks an entry in CREATING state as committed, so it is really returned * to the cache. Otherwise an entry in CREATING state is removed. @@ -162,8 +192,9 @@ bdb_cache_entry_private_destroy( Entry *e ) } void -bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ) +bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw ) { + ID id; int refcnt, freeit = 1; @@ -172,7 +203,112 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ) assert( e->e_private ); +#if 0 bdb_cache_entry_rdwr_unlock(e, rw); +#endif + + id = e->e_id; + refcnt = --BEI(e)->bei_refcnt; + + /* + * if the entry is returned when in CREATING state, it is deleted + * but not freed because it may belong to someone else (do_add, + * for instance) + */ + if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) { + /* set lru mutex */ + ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); + bdb_cache_delete_entry_internal( cache, e ); + /* free lru mutex */ + ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); + freeit = 0; + /* now the entry is in DELETED state */ + } + + if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) { + BEI(e)->bei_state = CACHE_ENTRY_READY; + + /* free cache write lock */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_unlocked_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n", + id, rw ? "w" : "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_unlocked_cache_return_entry_%s( %ld ): created (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + + } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) { + if( refcnt > 0 ) { + /* free cache write lock */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_unlocked_cache_return_entry_rw: %ld, delete pending (%d).\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_unlocked_cache_return_entry_%s( %ld ): delete pending (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + + } else { + bdb_cache_entry_private_destroy( e ); + if ( freeit ) { + bdb_entry_return( e ); + } + + /* free cache write lock */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_unlocked_cache_return_entry_rw: (%ld): deleted (%d)\n", + id, refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_unlocked_cache_return_entry_%s( %ld ): deleted (%d)\n", + rw ? "w" : "r", id, refcnt ); +#endif + } + + } else { + /* free cache write lock */ + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1, + "bdb_unlocked_cache_return_entry_rw: ID %ld:%s returned (%d)\n", + id, rw ? "w": "r", refcnt )); +#else + Debug( LDAP_DEBUG_TRACE, + "====> bdb_unlocked_cache_return_entry_%s( %ld ): returned (%d)\n", + rw ? "w" : "r", id, refcnt); +#endif + } +} + +void +bdb_cache_return_entry_rw +( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock ) +{ + ID id; + int refcnt, freeit = 1; + + /* set cache write lock */ + ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); + + assert( e->e_private ); + + bdb_cache_entry_db_unlock( env, lock ); +#if 0 + bdb_cache_entry_rdwr_unlock(e, rw); +#endif id = e->e_id; refcnt = --BEI(e)->bei_refcnt; @@ -290,12 +426,16 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ) * returns: 0 entry has been created and locked * 1 entry already existed * -1 something bad happened + * other Berkeley DB locking error code */ int bdb_cache_add_entry_rw( + DB_ENV *env, Cache *cache, Entry *e, - int rw + int rw, + u_int32_t locker, + DB_LOCK *lock ) { int i, rc; @@ -385,7 +525,37 @@ bdb_cache_add_entry_rw( return( -1 ); } - bdb_cache_entry_rdwr_lock( e, rw ); + rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock ); + switch ( rc ) { + case 0 : + break; + case DB_LOCK_DEADLOCK : + case DB_LOCK_NOTGRANTED : + /* undo avl changes immediately */ + if ( avl_delete( &cache->c_idtree, (caddr_t) e, + (AVL_CMP) entry_id_cmp ) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 ); +#endif + } + if ( avl_delete( &cache->c_dntree, (caddr_t) e, + (AVL_CMP) entry_dn_cmp ) == NULL ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "cache", LDAP_LEVEL_INFO, + "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn )); +#else + Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 ); +#endif + } + /* fall through */ + default : + bdb_cache_entry_private_destroy(e); + ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); + return rc; + } /* put the entry into 'CREATING' state */ /* will be marked after when entry is returned */ @@ -661,14 +831,18 @@ try_again: Entry * bdb_cache_find_entry_id( + DB_ENV *env, Cache *cache, ID id, - int rw + int rw, + u_int32_t locker, + DB_LOCK *lock ) { Entry e; Entry *ep; int count = 0; + int rc; e.e_id = id; @@ -715,7 +889,13 @@ try_again: } /* acquire reader lock */ + rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock ); + +#if 0 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) { +#endif + + if ( rc ) { /* will be changed to retry beyond threshold */ /* could not acquire entry lock... * owner cannot free as we have the cache locked. * so, unlock the cache, yield, and try again. @@ -732,6 +912,9 @@ try_again: Debug(LDAP_DEBUG_TRACE, "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n", id, ep_id, state); + Debug(LDAP_DEBUG_TRACE, + "locker = %d\n", + locker, 0, 0); #endif ldap_pvt_thread_yield(); diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c index e9c40dcbbc4bb5b721b096f200b0a188869b359c..ac799bb62777791701da86b2cd90c090a076f781 100644 --- a/servers/slapd/back-bdb/compare.c +++ b/servers/slapd/back-bdb/compare.c @@ -31,8 +31,14 @@ bdb_compare( const char *text = NULL; int manageDSAit = get_manageDSAit( op ); + u_int32_t locker; + DB_LOCK lock; + + LOCK_ID ( bdb->bi_dbenv, &locker ); + +dn2entry_retry: /* get entry */ - rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock ); switch( rc ) { case DB_NOTFOUND: @@ -41,6 +47,9 @@ bdb_compare( case LDAP_BUSY: text = "ldap server busy"; goto return_results; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto dn2entry_retry; default: rc = LDAP_OTHER; text = "internal error"; @@ -56,7 +65,7 @@ bdb_compare( refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock ); matched = NULL; } else { @@ -125,8 +134,10 @@ return_results: done: /* free entry */ if( e != NULL ) { - bdb_cache_return_entry_r( &bdb->bi_cache, e ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); } + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); + return rc; } diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index dcaf399fafd07c9abb777f2abc130bf84a00a992..a348631cc73205f4f1564e750ddaf69f75e85d53 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -33,6 +33,9 @@ bdb_delete( AttributeDescription *children = slap_schema.si_ad_children; DB_TXN *ltid = NULL; struct bdb_op_info opinfo; + + u_int32_t locker; + DB_LOCK lock; #if 0 u_int32_t lockid; DB_LOCK lock; @@ -49,7 +52,7 @@ bdb_delete( if( 0 ) { retry: /* transaction retry */ if( e != NULL ) { - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); } #ifdef NEW_LOGGING LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, @@ -87,6 +90,8 @@ retry: /* transaction retry */ text = "internal error"; goto return_results; } + + locker = TXN_ID ( ltid ); #if 0 lockid = TXN_ID( ltid ); #endif @@ -111,7 +116,7 @@ retry: /* transaction retry */ } #endif /* get parent */ - rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0 ); + rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0, locker, &lock ); switch( rc ) { case 0: @@ -147,7 +152,7 @@ retry: /* transaction retry */ rc = access_allowed( be, conn, op, p, children, NULL, ACL_WRITE, NULL ); - bdb_cache_return_entry_r(&bdb->bi_cache, p); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); p = NULL; switch( opinfo.boi_err ) { @@ -226,7 +231,7 @@ retry: /* transaction retry */ } /* get entry for read/modify/write */ - rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW ); + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW, locker, &lock ); switch( rc ) { case 0: @@ -263,7 +268,7 @@ retry: /* transaction retry */ refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r(&bdb->bi_cache, matched ); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched); matched = NULL; } else { @@ -465,7 +470,7 @@ return_results: done: /* free entry */ if( e != NULL ) { - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); } if( ltid != NULL ) { diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c index 00cd9efed7cea38446f909fe4af43ce29d6312a1..a6440536f7ebb662761bab2260d71ab522273371 100644 --- a/servers/slapd/back-bdb/dn2entry.c +++ b/servers/slapd/back-bdb/dn2entry.c @@ -25,7 +25,9 @@ bdb_dn2entry_rw( Entry **e, Entry **matched, int flags, - int rw ) + int rw, + u_int32_t locker, + DB_LOCK *lock ) { int rc; ID id, id2 = 0; @@ -52,9 +54,9 @@ bdb_dn2entry_rw( } if( id2 == 0 ) { - rc = bdb_id2entry_rw( be, tid, id, e, rw ); + rc = bdb_id2entry_rw( be, tid, id, e, rw, locker, lock ); } else { - rc = bdb_id2entry_r( be, tid, id2, matched); + rc = bdb_id2entry_r( be, tid, id2, matched, locker, lock ); } return rc; diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c index bd8adc0bdc8c2deb688b4adf0a0c59f0ee3757c5..a09bc1e3f4b578dcec590e8befcd484512c263a7 100644 --- a/servers/slapd/back-bdb/filterindex.c +++ b/servers/slapd/back-bdb/filterindex.c @@ -65,6 +65,10 @@ bdb_filter_candidates( Debug( LDAP_DEBUG_FILTER, "\tDN ONE\n", 0, 0, 0 ); #endif rc = bdb_dn2idl( be, f->f_dn, DN_ONE_PREFIX, ids ); + if( rc == DB_NOTFOUND ) { + BDB_IDL_ZERO( ids ); + rc = 0; + } break; case SLAPD_FILTER_DN_SUBTREE: diff --git a/servers/slapd/back-bdb/group.c b/servers/slapd/back-bdb/group.c index 2000de520996c7f849c70efc136ce9ac9bd2c2b1..6c2cdf11330a3c7f9035248c16555a65ffa41101 100644 --- a/servers/slapd/back-bdb/group.c +++ b/servers/slapd/back-bdb/group.c @@ -44,6 +44,9 @@ bdb_group( const char *group_oc_name = NULL; const char *group_at_name = group_at->ad_cname.bv_val; + u_int32_t locker; + DB_LOCK lock; + if( group_oc->soc_names && group_oc->soc_names[0] ) { group_oc_name = group_oc->soc_names[0]; } else { @@ -76,6 +79,11 @@ bdb_group( txn = boi->boi_txn; } + if ( txn ) + locker = TXN_ID( txn ); + else + LOCK_ID ( bdb->bi_dbenv, &locker ); + if (dn_match(&target->e_name, gr_ndn)) { /* we already have a LOCKED copy of the entry */ e = target; @@ -88,12 +96,18 @@ bdb_group( gr_ndn->bv_val, 0, 0 ); #endif } else { +dn2entry_retry: /* can we find group entry */ - rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0 ); + rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0, locker, &lock ); if( rc ) { + if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) + goto dn2entry_retry; if( txn ) { boi->boi_err = rc; } + else { + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); + } return( 1 ); } if (e == NULL) { @@ -106,6 +120,9 @@ bdb_group( "=> bdb_group: cannot find group: \"%s\"\n", gr_ndn->bv_val, 0, 0 ); #endif + if ( txn == NULL ) { + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); + } return( 1 ); } #ifdef NEW_LOGGING @@ -211,7 +228,11 @@ bdb_group( return_results: if( target != e ) { /* free entry */ - bdb_cache_return_entry_r( &bdb->bi_cache, e ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); + } + + if ( txn == NULL ) { + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); } #ifdef NEW_LOGGING diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index 10ec1637a58aacd6baff8e40cd27354fbedacbc0..0a841cab21e1c7099e740d2ef8e7886d067e8133 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -80,13 +80,15 @@ int bdb_id2entry_rw( DB_TXN *tid, ID id, Entry **e, - int rw ) + int rw, + u_int32_t locker, + DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; DB *db = bdb->bi_id2entry->bdi_db; DBT key, data; struct berval bv; - int rc = 0; + int rc = 0, ret = 0; *e = NULL; @@ -97,7 +99,7 @@ int bdb_id2entry_rw( DBTzero( &data ); data.flags = DB_DBT_MALLOC; - if ((*e = bdb_cache_find_entry_id(&bdb->bi_cache, id, rw)) != NULL) { + if ((*e = bdb_cache_find_entry_id(bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock)) != NULL) { return 0; } @@ -121,24 +123,36 @@ int bdb_id2entry_rw( ch_free( data.data ); } - while (rc == 0 && bdb_cache_add_entry_rw(&bdb->bi_cache, *e, rw) != 0) { - Entry *ee; - int add_loop_cnt = 0; - if ( (*e)->e_private != NULL ) { - free ((*e)->e_private); - } - (*e)->e_private = NULL; - if ( (ee = bdb_cache_find_entry_id - (&bdb->bi_cache, id, rw) ) != NULL) { - bdb_entry_return ( *e ); - *e = ee; - return 0; + if ( rc == 0 ) { + ret = bdb_cache_add_entry_rw( bdb->bi_dbenv, + &bdb->bi_cache, *e, rw, locker, lock); + while ( ret == 1 || ret == -1 ) { + Entry *ee; + int add_loop_cnt = 0; + if ( (*e)->e_private != NULL ) { + free ((*e)->e_private); + } + (*e)->e_private = NULL; + if ( (ee = bdb_cache_find_entry_id + (bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock) ) != NULL) { + bdb_entry_return ( *e ); + *e = ee; + return 0; + } + if ( ++add_loop_cnt == BDB_MAX_ADD_LOOP ) { + bdb_entry_return ( *e ); + *e = NULL; + return LDAP_BUSY; + } } - if ( ++add_loop_cnt == BDB_MAX_ADD_LOOP ) { - bdb_entry_return ( *e ); + if ( ret != 0 ) { + if ( (*e)->e_private != NULL ) + free ( (*e)->e_private ); + bdb_entry_return( *e ); *e = NULL; - return LDAP_BUSY; + ch_free( data.data ); } + rc = ret; } #ifdef BDB_HIER @@ -232,7 +246,7 @@ int bdb_entry_release( if ( slapMode == SLAP_SERVER_MODE ) { /* free entry and reader or writer lock */ - bdb_cache_return_entry_rw( &bdb->bi_cache, e, rw ); + bdb_unlocked_cache_return_entry_rw( &bdb->bi_cache, e, rw ); } else { if (e->e_private != NULL) free (e->e_private); diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index 9fece09c88f86b7b916666f4f517ae71bebcb31e..d205b60060b3b925e34da6ed69b678309afb62be 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -91,7 +91,6 @@ int bdb_modify_internal( Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0); #endif err = modify_replace_values( e, mod, text, textbuf, textlen ); - assert( err != LDAP_TYPE_OR_VALUE_EXISTS ); if( err != LDAP_SUCCESS ) { #ifdef NEW_LOGGING LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text )); @@ -250,6 +249,9 @@ bdb_modify( DB_TXN *ltid = NULL; struct bdb_op_info opinfo; + u_int32_t locker; + DB_LOCK lock; + #ifdef NEW_LOGGING LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY, "bdb_modify: %s\n", dn->bv_val )); #else @@ -260,7 +262,7 @@ bdb_modify( retry: /* transaction retry */ if( e != NULL ) { bdb_cache_delete_entry(&bdb->bi_cache, e); - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); } #ifdef NEW_LOGGING LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: retrying...\n" )); @@ -296,13 +298,15 @@ retry: /* transaction retry */ goto return_results; } + locker = TXN_ID ( ltid ); + opinfo.boi_bdb = be; opinfo.boi_txn = ltid; opinfo.boi_err = 0; op->o_private = &opinfo; /* get entry */ - rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 ); + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0, locker, &lock ); if ( rc != 0 ) { #ifdef NEW_LOGGING @@ -338,7 +342,7 @@ retry: /* transaction retry */ refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r (&bdb->bi_cache, matched); + bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, matched); matched = NULL; } else { @@ -464,7 +468,7 @@ done: } if( e != NULL ) { - bdb_cache_return_entry_w (&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e); } return rc; } diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index cb1e1517ebb81f3f5bc9377d26152d5af4a8dd69..30f345c7f072ed1193e2aaef51b0eb7c6f647a2c 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -56,6 +56,9 @@ bdb_modrdn( int manageDSAit = get_manageDSAit( op ); + u_int32_t locker; + DB_LOCK lock; + #ifdef NEW_LOGGING LDAP_LOG (( "modrdn", LDAP_LEVEL_ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", dn->bv_val,newrdn->bv_val, @@ -78,13 +81,13 @@ bdb_modrdn( retry: /* transaction retry */ if (e != NULL) { bdb_cache_delete_entry(&bdb->bi_cache, e); - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); } if (p != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, p); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); } if (np != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, np); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np); } #ifdef NEW_LOGGING LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: retrying...\n")); @@ -119,13 +122,15 @@ retry: /* transaction retry */ goto return_results; } + locker = TXN_ID ( ltid ); + opinfo.boi_bdb = be; opinfo.boi_txn = ltid; opinfo.boi_err = 0; op->o_private = &opinfo; /* get entry */ - rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 ); + rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0, locker, &lock ); switch( rc ) { case 0: @@ -152,7 +157,7 @@ retry: /* transaction retry */ refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r( &bdb->bi_cache, matched ); + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched); matched = NULL; } else { @@ -199,7 +204,7 @@ retry: /* transaction retry */ /* Make sure parent entry exist and we can write its * children. */ - rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0 ); + rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0, locker, &lock ); switch( rc ) { case 0: @@ -348,7 +353,7 @@ retry: /* transaction retry */ /* newSuperior == entry being moved?, if so ==> ERROR */ /* Get Entry with dn=newSuperior. Does newSuperior exist? */ - rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0 ); + rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0, locker, &lock ); switch( rc ) { case 0: @@ -855,17 +860,17 @@ done: /* LDAP v3 Support */ if( np != NULL ) { /* free new parent and reader lock */ - bdb_cache_return_entry_r(&bdb->bi_cache, np); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np); } if( p != NULL ) { /* free parent and reader lock */ - bdb_cache_return_entry_r(&bdb->bi_cache, p); + bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); } /* free entry */ if( e != NULL ) { - bdb_cache_return_entry_w( &bdb->bi_cache, e ); + bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e); } if( ltid != NULL ) { diff --git a/servers/slapd/back-bdb/operational.c b/servers/slapd/back-bdb/operational.c index 08172b8c2d173278de42aa9669ca1114285caf58..5278c23ba3baa83ca6ed59a29f9a81223b903eab 100644 --- a/servers/slapd/back-bdb/operational.c +++ b/servers/slapd/back-bdb/operational.c @@ -44,9 +44,11 @@ bdb_operational( if( 0 ) { retry: /* transaction retry */ +#if 0 if( e != NULL ) { - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); } +#endif #ifdef NEW_LOGGING LDAP_LOG (( "operational", LDAP_LEVEL_DETAIL1, "=> bdb_operational: retrying...\n" )); diff --git a/servers/slapd/back-bdb/passwd.c b/servers/slapd/back-bdb/passwd.c index 0e05443926b91970ecebf9e9b951c6c76ed4cb32..25f0c654ed7513a2184c6684b29b49dc0af7abc9 100644 --- a/servers/slapd/back-bdb/passwd.c +++ b/servers/slapd/back-bdb/passwd.c @@ -41,6 +41,9 @@ bdb_exop_passwd( struct berval dn; struct berval ndn; + u_int32_t locker; + DB_LOCK lock; + assert( reqoid != NULL ); assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 ); @@ -109,7 +112,7 @@ bdb_exop_passwd( retry: /* transaction retry */ if ( e != NULL ) { bdb_cache_delete_entry(&bdb->bi_cache, e); - bdb_cache_return_entry_w(&bdb->bi_cache, e); + bdb_cache_return_entry_w(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } #ifdef NEW_LOGGING LDAP_LOG (( "passwd", LDAP_LEVEL_DETAIL1, "bdb_exop_passwd: retrying...\n" )); @@ -144,13 +147,15 @@ retry: /* transaction retry */ goto done; } + locker = TXN_ID ( ltid ); + opinfo.boi_bdb = be; opinfo.boi_txn = ltid; opinfo.boi_err = 0; op->o_private = &opinfo; /* get entry */ - rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 ); + rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 , locker, &lock); switch(rc) { case DB_LOCK_DEADLOCK: @@ -256,7 +261,7 @@ retry: /* transaction retry */ done: if( e != NULL ) { - bdb_cache_return_entry_w( &bdb->bi_cache, e ); + bdb_cache_return_entry_w( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); } if( hash.bv_val != NULL ) { diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index cdea9803e190411fc29f2d066bf0051eca884bc4..f5c7af92fd366317f5c380ea9e4a9ece9c14d031 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -58,9 +58,9 @@ bdb_db_cache( * dn2entry.c */ int bdb_dn2entry_rw LDAP_P(( BackendDB *be, DB_TXN *tid, - struct berval *dn, Entry **e, Entry **matched, int flags, int rw )); -#define bdb_dn2entry_r(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0) -#define bdb_dn2entry_w(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1) + struct berval *dn, Entry **e, Entry **matched, int flags, int rw , u_int32_t locker, DB_LOCK *lock)); +#define bdb_dn2entry_r(be, tid, dn, e, m, f, locker, lock) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0, locker, lock) +#define bdb_dn2entry_w(be, tid, dn, e, m, f, locker, lock) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1, locker, lock) /* * dn2id.c @@ -152,9 +152,11 @@ int bdb_id2entry_rw( DB_TXN *tid, ID id, Entry **e, - int rw ); -#define bdb_id2entry_r(be, tid, id, e) bdb_id2entry_rw((be), (tid), (id), (e), 0) -#define bdb_id2entry_w(be, tid, id, e) bdb_id2entry_rw((be), (tid), (id), (e), 1) + int rw, + u_int32_t locker, + DB_LOCK *lock ); +#define bdb_id2entry_r(be, tid, id, e, locker, lock) bdb_id2entry_rw((be), (tid), (id), (e), 0, locker, lock) +#define bdb_id2entry_w(be, tid, id, e, locker, lock) bdb_id2entry_rw((be), (tid), (id), (e), 1, locker, lock) void bdb_entry_free ( Entry *e ); @@ -301,13 +303,19 @@ BI_op_extended bdb_exop_passwd; */ void bdb_cache_entry_commit( Entry *e ); -void bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw ); -#define bdb_cache_return_entry_r(c, e) bdb_cache_return_entry_rw((c), (e), 0) -#define bdb_cache_return_entry_w(c, e) bdb_cache_return_entry_rw((c), (e), 1) +void bdb_cache_return_entry_rw( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock ); +#define bdb_cache_return_entry_r(env, c, e, l) bdb_cache_return_entry_rw((env), (c), (e), 0, (l)) +#define bdb_cache_return_entry_w(env, c, e, l) bdb_cache_return_entry_rw((env), (c), (e), 1, (l)) +void bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw ); +#define bdb_unlocked_cache_return_entry_r( c, e ) bdb_unlocked_cache_return_entry_rw((c), (e), 0) +#define bdb_unlocked_cache_return_entry_w( c, e ) bdb_unlocked_cache_return_entry_rw((c), (e), 1) int bdb_cache_add_entry_rw( - Cache *cache, - Entry *e, - int rw + DB_ENV *env, + Cache *cache, + Entry *e, + int rw, + u_int32_t locker, + DB_LOCK *lock ); int bdb_cache_update_entry( Cache *cache, @@ -319,9 +327,12 @@ ID bdb_cache_find_entry_ndn2id( struct berval *ndn ); Entry* bdb_cache_find_entry_id( - Cache *cache, - ID id, - int rw + DB_ENV *env, + Cache *cache, + ID id, + int rw, + u_int32_t locker, + DB_LOCK *lock ); int bdb_cache_delete_entry( Cache *cache, diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c index 3517492c7945b8c24374ec5a254258689bab207d..4d60f68d0e83030029b78329c7c41b3424ea4b3f 100644 --- a/servers/slapd/back-bdb/referral.c +++ b/servers/slapd/back-bdb/referral.c @@ -26,6 +26,9 @@ bdb_referrals( Entry *e = NULL; Entry *matched = NULL; + u_int32_t locker; + DB_LOCK lock; + if( op->o_tag == LDAP_REQ_SEARCH ) { /* let search take care of itself */ return rc; @@ -36,8 +39,11 @@ bdb_referrals( return rc; } + LOCK_ID ( bdb->bi_dbenv, &locker ); + +dn2entry_retry: /* get entry */ - rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 ); + rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock ); switch(rc) { case DB_NOTFOUND: @@ -46,14 +52,18 @@ bdb_referrals( break; case LDAP_BUSY: if (e != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } if (matched != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, matched); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); } send_ldap_result( conn, op, LDAP_BUSY, NULL, "ldap server busy", NULL, NULL ); + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); return LDAP_BUSY; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto dn2entry_retry; default: #ifdef NEW_LOGGING LDAP_LOG (( "referral", LDAP_LEVEL_ERR, @@ -65,13 +75,14 @@ bdb_referrals( db_strerror(rc), rc, 0 ); #endif if (e != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } if (matched != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, matched); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); } send_ldap_result( conn, op, rc=LDAP_OTHER, NULL, "internal error", NULL, NULL ); + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); return rc; } @@ -97,7 +108,7 @@ bdb_referrals( refs = get_entry_referrals( be, conn, op, matched ); } - bdb_cache_return_entry_r (&bdb->bi_cache, matched); + bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); matched = NULL; } else if ( default_referral != NULL ) { rc = LDAP_OTHER; @@ -116,6 +127,7 @@ bdb_referrals( NULL, NULL ); } + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); free( matched_dn ); return rc; } @@ -148,6 +160,7 @@ bdb_referrals( ber_bvarray_free( refs ); } - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); + LOCK_ID_FREE ( bdb->bi_dbenv, locker ); return rc; } diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 9887feb342c6515c777c11af87c1e1cb0a8d31c0..a68e17fb646e90400b4058bb1f660c30aea5f04b 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -59,6 +59,9 @@ bdb_search( struct slap_limits_set *limit = NULL; int isroot = 0; + u_int32_t locker; + DB_LOCK lock; + #ifdef NEW_LOGGING LDAP_LOG (( "search", LDAP_LEVEL_ENTRY,"bdb_back_search\n")); #else @@ -68,6 +71,8 @@ bdb_search( manageDSAit = get_manageDSAit( op ); + LOCK_ID (bdb->bi_dbenv, &locker ); + if ( nbase->bv_len == 0 ) { /* DIT root special case */ e = (Entry *) &slap_entry_root; @@ -81,7 +86,8 @@ bdb_search( } else #endif { - rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0 ); +dn2entry_retry: + rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0, locker, &lock ); } switch(rc) { @@ -90,23 +96,28 @@ bdb_search( break; case LDAP_BUSY: if (e != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } if (matched != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, matched); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); } send_ldap_result( conn, op, LDAP_BUSY, NULL, "ldap server busy", NULL, NULL ); + LOCK_ID_FREE (bdb->bi_dbenv, locker ); return LDAP_BUSY; + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto dn2entry_retry; default: if (e != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } if (matched != NULL) { - bdb_cache_return_entry_r(&bdb->bi_cache, matched); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); } send_ldap_result( conn, op, rc=LDAP_OTHER, NULL, "internal error", NULL, NULL ); + LOCK_ID_FREE (bdb->bi_dbenv, locker ); return rc; } @@ -116,14 +127,13 @@ bdb_search( if ( matched != NULL ) { BerVarray erefs; - ber_dupbv( &matched_dn, &matched->e_name ); erefs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; - bdb_cache_return_entry_r (&bdb->bi_cache, matched); + bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); matched = NULL; if( erefs ) { @@ -140,6 +150,7 @@ bdb_search( send_ldap_result( conn, op, rc=LDAP_REFERRAL , matched_dn.bv_val, text, refs, NULL ); + LOCK_ID_FREE (bdb->bi_dbenv, locker ); if ( refs ) ber_bvarray_free( refs ); if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val ); return rc; @@ -154,7 +165,7 @@ bdb_search( erefs = get_entry_referrals( be, conn, op, e ); refs = NULL; - bdb_cache_return_entry_r( &bdb->bi_cache, e ); + bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); e = NULL; if( erefs ) { @@ -175,6 +186,7 @@ bdb_search( refs ? NULL : "bad referral object", refs, NULL ); + LOCK_ID_FREE (bdb->bi_dbenv, locker ); ber_bvarray_free( refs ); ber_memfree( matched_dn.bv_val ); return 1; @@ -270,7 +282,7 @@ bdb_search( cursor = e->e_id == NOID ? 1 : e->e_id; if ( e != &slap_entry_root ) { - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } e = NULL; @@ -320,13 +332,17 @@ bdb_search( goto done; } +id2entry_retry: /* get the entry with reader lock */ - rc = bdb_id2entry_r( be, NULL, id, &e ); + rc = bdb_id2entry_r( be, NULL, id, &e, locker, &lock ); if (rc == LDAP_BUSY) { send_ldap_result( conn, op, rc=LDAP_BUSY, NULL, "ldap server busy", NULL, NULL ); goto done; + + } else if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) { + goto id2entry_retry; } if ( e == NULL ) { @@ -416,18 +432,49 @@ bdb_search( if ( !manageDSAit && scope != LDAP_SCOPE_BASE && is_entry_referral( e ) ) { - BerVarray erefs = get_entry_referrals( - be, conn, op, e ); - BerVarray refs = referral_rewrite( erefs, - &e->e_name, NULL, - scope == LDAP_SCOPE_SUBTREE - ? LDAP_SCOPE_SUBTREE - : LDAP_SCOPE_BASE ); + struct berval dn; - send_search_reference( be, conn, op, - e, refs, NULL, &v2refs ); + /* check scope */ + if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) { + if ( !be_issuffix( be, &e->e_nname ) ) { + dnParent( &e->e_nname, &dn ); + scopeok = dn_match( &dn, &realbase ); + } else { + scopeok = (realbase.bv_len == 0); + } - ber_bvarray_free( refs ); + } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) { + scopeok = dnIsSuffix( &e->e_nname, &realbase ); + + } else { + scopeok = 1; + } + + if( scopeok ) { + BerVarray erefs = get_entry_referrals( + be, conn, op, e ); + BerVarray refs = referral_rewrite( erefs, + &e->e_name, NULL, + scope == LDAP_SCOPE_SUBTREE + ? LDAP_SCOPE_SUBTREE + : LDAP_SCOPE_BASE ); + + send_search_reference( be, conn, op, + e, refs, NULL, &v2refs ); + + ber_bvarray_free( refs ); + + } else { +#ifdef NEW_LOGGING + LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, + "bdb_search: candidate referral %ld scope not okay\n", + id )); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: candidate referral %ld scope not okay\n", + id, 0, 0 ); +#endif + } goto loop_continue; } @@ -456,7 +503,7 @@ bdb_search( if ( scopeok ) { /* check size limit */ if ( --slimit == -1 ) { - bdb_cache_return_entry_r (&bdb->bi_cache, e); + bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &lock); e = NULL; send_search_result( conn, op, rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, @@ -481,7 +528,7 @@ bdb_search( case 1: /* entry not sent */ break; case -1: /* connection closed */ - bdb_cache_return_entry_r(&bdb->bi_cache, e); + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); e = NULL; rc = LDAP_OTHER; goto done; @@ -509,7 +556,7 @@ bdb_search( loop_continue: if( e != NULL ) { /* free reader lock */ - bdb_cache_return_entry_r ( &bdb->bi_cache, e ); + bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e , &lock); e = NULL; } @@ -524,9 +571,11 @@ loop_continue: done: if( e != NULL ) { /* free reader lock */ - bdb_cache_return_entry_r ( &bdb->bi_cache, e ); + bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); } + LOCK_ID_FREE (bdb->bi_dbenv, locker ); + if( v2refs ) ber_bvarray_free( v2refs ); if( realbase.bv_val ) ch_free( realbase.bv_val ); diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 3dc4cdbcf1baff1e096801430229fbf0868d2233..137734c104b8d3a3d2fb8557cd4d137c911d21e1 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -490,13 +490,15 @@ static int slap_get_listener_addresses( freeaddrinfo(res); #else + int i, n = 1; struct in_addr in; + struct hostent *he = NULL; if ( host == NULL ) { in.s_addr = htonl(INADDR_ANY); } else if ( !inet_aton( host, &in ) ) { - struct hostent *he = gethostbyname( host ); + he = gethostbyname( host ); if( he == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "connection", LDAP_LEVEL_INFO, @@ -508,25 +510,30 @@ static int slap_get_listener_addresses( #endif return -1; } - AC_MEMCPY( &in, he->h_addr, sizeof( in ) ); + for (n = 0; he->h_addr_list[n]; n++) ; } - *sal = ch_malloc(2 * sizeof(void *)); + *sal = ch_malloc((n+1) * sizeof(void *)); if (*sal == NULL) { return -1; } sap = *sal; - *sap = ch_malloc(sizeof(struct sockaddr_in)); - if (*sap == NULL) { - goto errexit; + for ( i = 0; i<n; i++ ) { + sap[i] = ch_malloc(sizeof(struct sockaddr_in)); + if (*sap == NULL) { + goto errexit; + } + (void)memset( (void *)sap[i], '\0', sizeof(struct sockaddr_in) ); + sap[i]->sa_family = AF_INET; + ((struct sockaddr_in *)sap[i])->sin_port = htons(port); + if (he) { + AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, he->h_addr_list[i], sizeof(struct in_addr) ); + } else { + AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, &in, sizeof(struct in_addr) ); + } } - sap[1] = NULL; - - (void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_in) ); - (*sap)->sa_family = AF_INET; - ((struct sockaddr_in *)*sap)->sin_port = htons(port); - ((struct sockaddr_in *)*sap)->sin_addr = in; + sap[i] = NULL; #endif } @@ -537,10 +544,13 @@ errexit: return -1; } -static Listener * slap_open_listener( - const char* url ) +static int slap_open_listener( + const char* url, + int *listeners, + int *cur + ) { - int tmp, rc; + int num, tmp, rc; Listener l; Listener *li; LDAPURLDesc *lud; @@ -565,7 +575,7 @@ static Listener * slap_open_listener( "daemon: listen URL \"%s\" parse error=%d\n", url, rc, 0 ); #endif - return NULL; + return rc; } #ifndef HAVE_TLS @@ -580,7 +590,7 @@ static Listener * slap_open_listener( url, 0, 0 ); #endif ldap_free_urldesc( lud ); - return NULL; + return -1; } if(! lud->lud_port ) { @@ -620,7 +630,7 @@ static Listener * slap_open_listener( url, 0, 0); #endif ldap_free_urldesc( lud ); - return NULL; + return -1; #endif } else { #ifdef LDAP_CONNECTIONLESS @@ -637,7 +647,16 @@ static Listener * slap_open_listener( ldap_free_urldesc( lud ); if ( err ) { - return NULL; + return -1; + } + + /* If we got more than one address returned, we need to make space + * for it in the slap_listeners array. + */ + for ( num=0; sal[num]; num++ ); + if ( num > 1 ) { + *listeners += num-1; + slap_listeners = ch_realloc( slap_listeners, (*listeners + 1) * sizeof(Listener *) ); } psal = sal; @@ -732,9 +751,8 @@ static Listener * slap_open_listener( #endif } - if (!bind(l.sl_sd, *sal, addrlen)) - break; - err = sock_errno(); + if (bind(l.sl_sd, *sal, addrlen)) { + err = sock_errno(); #ifdef NEW_LOGGING LDAP_LOG(( "connection", LDAP_LEVEL_INFO, "slap_open_listener: bind(%ld) failed errno=%d (%s)\n", @@ -743,21 +761,10 @@ static Listener * slap_open_listener( Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n", (long) l.sl_sd, err, sock_errstr(err) ); #endif - tcp_close( l.sl_sd ); - sal++; - } /* while ( *sal != NULL ) */ - - if ( *sal == NULL ) { -#ifdef NEW_LOGGING - LDAP_LOG(( "connection", LDAP_LEVEL_INFO, - "slap_open_listener: bind(%ld) failed.\n", (long)l.sl_sd )); -#else - Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed\n", - (long) l.sl_sd, 0, 0 ); -#endif - slap_free_listener_addresses(psal); - return NULL; - } + tcp_close( l.sl_sd ); + sal++; + continue; + } switch ( (*sal)->sa_family ) { #ifdef LDAP_PF_LOCAL @@ -775,7 +782,7 @@ static Listener * slap_open_listener( #endif tcp_close( l.sl_sd ); slap_free_listener_addresses(psal); - return NULL; + return -1; } l.sl_name = ch_malloc( strlen(addr) + sizeof("PATH=") ); sprintf( l.sl_name, "PATH=%s", addr ); @@ -821,20 +828,27 @@ static Listener * slap_open_listener( break; } - slap_free_listener_addresses(psal); - + AC_MEMCPY(&l.sl_sa, *sal, addrlen); l.sl_url = ch_strdup( url ); li = ch_malloc( sizeof( Listener ) ); *li = l; + slap_listeners[*cur] = li; + (*cur)++; + sal++; + + } /* while ( *sal != NULL ) */ + + slap_free_listener_addresses(psal); + #ifdef NEW_LOGGING LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS, - "slap_open_listener: daemon initialzed %s\n", l.sl_url )); + "slap_open_listener: daemon initialized %s\n", l.sl_url )); #else Debug( LDAP_DEBUG_TRACE, "daemon: initialized %s\n", l.sl_url, 0, 0 ); #endif - return li; + return 0; } static int sockinit(void); @@ -842,7 +856,7 @@ static int sockdestroy(void); int slapd_daemon_init( const char *urls ) { - int i, rc; + int i, j, n, rc; char **u; #ifdef NEW_LOGGING @@ -938,15 +952,13 @@ int slapd_daemon_init( const char *urls ) #endif slap_listeners = ch_malloc( (i+1)*sizeof(Listener *) ); - for(i = 0; u[i] != NULL; i++ ) { - slap_listeners[i] = slap_open_listener( u[i] ); - - if( slap_listeners[i] == NULL ) { + for(n = 0, j = 0; u[n]; n++ ) { + if ( slap_open_listener( u[n], &i, &j ) ) { charray_free( u ); return -1; } } - slap_listeners[i] = NULL; + slap_listeners[j] = NULL; #ifdef NEW_LOGGING LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 1437f35cc4279e7dcde36f81f143bb0a8752305b..a4b02c75bd730eb2011c75cc7dca46db56a35fdf 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -579,6 +579,8 @@ struct slap_internal_schema { AttributeDescription *si_ad_modifyTimestamp; AttributeDescription *si_ad_hasSubordinates; AttributeDescription *si_ad_subschemaSubentry; + AttributeDescription *si_ad_entryUUID; + AttributeDescription *si_ad_entryCSN; /* root DSE attribute descriptions */ AttributeDescription *si_ad_altServer;