From ac9395d83669deb68c67a1ebbd361157067ad628 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga <kurt@openldap.org> Date: Wed, 5 Jun 2002 22:07:20 +0000 Subject: [PATCH] updates from HEAD --- clients/tools/ldapsearch.c | 106 +++++- doc/devel/args | 62 ++++ doc/man/man1/ldapdelete.1 | 192 ++++++++--- doc/man/man3/ldap_error.3 | 3 +- doc/man/man5/slapd-shell.5 | 37 +-- doc/man/man5/slapd.conf.5 | 16 + libraries/libldap/controls.c | 5 +- libraries/libldap/dnssrv.c | 304 +++++++++++++++++ libraries/libldap/error.c | 9 - libraries/libldap/extended.c | 10 - libraries/libldap/getdn.c | 9 +- libraries/libldap/getentry.c | 134 ++++++-- libraries/libldap/references.c | 146 ++++++++ libraries/libldap/result.c | 9 - libraries/libldap/sasl.c | 9 - libraries/libldap/sort.c | 84 ++--- libraries/libldap/sortctrl.c | 466 ++++++++++++++++++++++++++ libraries/libldap/url.c | 12 +- libraries/libldap/vlvctrl.c | 277 ++++++++++++++++ libraries/libldap_r/tpool.c | 4 + libraries/liblutil/entropy.c | 18 +- servers/slapd/at.c | 12 +- servers/slapd/back-ldbm/modify.c | 1 - servers/slapd/back-shell/abandon.c | 22 +- servers/slapd/back-shell/add.c | 1 - servers/slapd/back-shell/bind.c | 1 - servers/slapd/back-shell/compare.c | 1 - servers/slapd/back-shell/delete.c | 1 - servers/slapd/back-shell/modify.c | 1 - servers/slapd/back-shell/modrdn.c | 1 - servers/slapd/back-shell/search.c | 1 - servers/slapd/back-shell/unbind.c | 1 - servers/slapd/config.c | 19 +- servers/slapd/daemon.c | 80 ++++- servers/slapd/matchedValues.c | 92 ++---- servers/slapd/mr.c | 4 +- servers/slapd/oc.c | 512 +++++++++++++++++++++++++++++ servers/slapd/passwd.c | 8 +- servers/slapd/proto-slap.h | 4 +- servers/slapd/result.c | 78 ++++- servers/slapd/schema_prep.c | 66 ++-- servers/slapd/schemaparse.c | 19 +- servers/slapd/slap.h | 59 ++-- servers/slapd/syntax.c | 240 ++++++++++++++ 44 files changed, 2746 insertions(+), 390 deletions(-) create mode 100644 doc/devel/args create mode 100644 libraries/libldap/dnssrv.c create mode 100644 libraries/libldap/references.c create mode 100644 libraries/libldap/sortctrl.c create mode 100644 libraries/libldap/vlvctrl.c create mode 100644 servers/slapd/oc.c create mode 100644 servers/slapd/syntax.c diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index bf76dbdfdd..868ac0697f 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -186,9 +186,14 @@ main( int argc, char **argv ) int referrals, timelimit, sizelimit, debug; int authmethod, version, want_bindpw; LDAP *ld = NULL; + int valuesReturnFilter; + BerElement *ber; + struct berval *bvalp; + char *vrFilter = NULL, *control = NULL, *s; + infile = NULL; - debug = verbose = not = vals2tmp = referrals = + debug = verbose = not = vals2tmp = referrals = valuesReturnFilter = attrsonly = manageDSAit = ldif = want_bindpw = 0; lutil_log_initialize(argc, argv); @@ -222,7 +227,7 @@ main( int argc, char **argv ) prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1; - while (( i = getopt( argc, argv, "Aa:b:F:f:Ll:S:s:T:tuz:" + while (( i = getopt( argc, argv, "Aa:b:E:F:f:Ll:S:s:T:tuz:" "Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z")) != EOF ) { switch( i ) { @@ -254,6 +259,47 @@ main( int argc, char **argv ) } infile = strdup( optarg ); break; + case 'E': /* controls */ + if( version == LDAP_VERSION2 ) { + fprintf( stderr, "%s: -C incompatible with LDAPv%d\n", + prog, version ); + return EXIT_FAILURE; + } + + /* should be extended to support comma separated list of + * key/value pairs: -E foo=123,bar=567 + */ + + control = strdup( optarg ); + if ( (s = strchr( control, '=' )) == NULL ) { + return EXIT_FAILURE; + } + + *s++ = '\0'; + if ( strcasecmp( control, "mv" ) == 0 ) { + /* ValuesReturnFilter control */ + if (valuesReturnFilter!=0) { + fprintf( stderr, "ValuesReturnFilter previously specified"); + return EXIT_FAILURE; + } + + if ( *s == '!' ){ + s++; + valuesReturnFilter=2; + } else { + valuesReturnFilter=1; + } + + vrFilter = s; + version = LDAP_VERSION3; + break; + + } else { + fprintf( stderr, "Invalid control name: %s\n", control ); + usage(prog); + return EXIT_FAILURE; + } + case 'F': /* uri prefix */ if( urlpre ) free( urlpre ); urlpre = strdup( optarg ); @@ -829,24 +875,56 @@ main( int argc, char **argv ) } } - if ( manageDSAit ) { + if ( manageDSAit || valuesReturnFilter ) { int err; - LDAPControl c; - LDAPControl *ctrls[2]; - ctrls[0] = &c; - ctrls[1] = NULL; + int i=0; + LDAPControl c1,c2; + LDAPControl *ctrls[3]; + + if ( manageDSAit ) { + ctrls[i++]=&c1; + ctrls[i] = NULL; + + c1.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; + c1.ldctl_value.bv_val = NULL; + c1.ldctl_value.bv_len = 0; + c1.ldctl_iscritical = manageDSAit > 1; + } - c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; - c.ldctl_value.bv_val = NULL; - c.ldctl_value.bv_len = 0; - c.ldctl_iscritical = manageDSAit > 1; + if ( valuesReturnFilter ) { + struct berval *bvalp; + ctrls[i++]=&c2; + ctrls[i] = NULL; + c2.ldctl_oid = LDAP_CONTROL_VALUESRETURNFILTER; + c2.ldctl_iscritical = valuesReturnFilter > 1; + + if (( ber = ber_alloc_t(LBER_USE_DER)) == NULL ) + exit( EXIT_FAILURE ); + + if ( err = put_vrFilter(ber, vrFilter)==-1 ) { + ber_free( ber, 1 ); + fprintf( stderr, "Bad ValuesReturnFilter: %s\n", vrFilter ); + exit( EXIT_FAILURE ); + } + + if ( ber_flatten( ber, &bvalp ) == LBER_ERROR ) + return LDAP_NO_MEMORY; + + c2.ldctl_value=(*bvalp); + + } + err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls ); + ber_bvfree(bvalp); + ber_free( ber, 1 ); + if( err != LDAP_OPT_SUCCESS ) { - fprintf( stderr, "Could not set ManageDSAit %scontrol\n", - c.ldctl_iscritical ? "critical " : "" ); - if( c.ldctl_iscritical ) { + fprintf( stderr, "Could not set %scontrols\n", + (c1.ldctl_iscritical || c2.ldctl_iscritical) + ? "critical " : "" ); + if( c1.ldctl_iscritical && c2.ldctl_iscritical ) { exit( EXIT_FAILURE ); } } diff --git a/doc/devel/args b/doc/devel/args new file mode 100644 index 0000000000..ea02cfa4f4 --- /dev/null +++ b/doc/devel/args @@ -0,0 +1,62 @@ +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* +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 + +Other Clients ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +fax500 * f h m +finger * c f i l p t x +go500 I * bcd f l p t x +go500gw I P * a cd f h l p t x +mail500 C * d f h lm v +rcpt500 U* abc f h l p st z +rp500 * ab d f x z +ud D * cd f l p s uv + + +* reserved + GJNgijmoqy + +* General flags: + -C Chase Referrals + -D Bind DN + -E CommandSpecific Extensions (e.g., -E <[!]oid[=options]>*) + -e General Extensions (e.g., -e <[!]oid[=options]>*) + -H URI + -P protocol version + -V version information + -W prompt for bind password + -d debug + -h host + -n no-op + -p port + -v verbose + -w Bind password + + +* LDAPv3 Only + -x simple bind (not recommended excepting for + anonymous access, w/ -ZZ, or with ldaps://. + + -M ManageDSAIT + -Z StartTLS + + -Y SASL Mechanism (defaults to "best") + -R SASL Realm (defaults to empty) + -O SASL Security Options (defaults to "noanonymous,noplain") + -U SASL Authentication Identity (defaults to USER) + -X SASL Authorization Identity (defaults to empty) + + -I SASL interactive mode (default: automatic) + -Q SASL quiet mode (default: automatic) + + +* LDAPv2+ Only (DEPRECATED) + -K LDAPv2 Kerberos Bind (Step 1 only) + -k LDAPv2 Kerberos Bind + + +--- +$OpenLDAP$ diff --git a/doc/man/man1/ldapdelete.1 b/doc/man/man1/ldapdelete.1 index ea2f4726c2..1969b20cc3 100644 --- a/doc/man/man1/ldapdelete.1 +++ b/doc/man/man1/ldapdelete.1 @@ -1,20 +1,61 @@ -.TH LDAPDELETE 1 "13 November 1995" "U-M LDAP LDVERSION" +.TH LDAPDELETE 1 "20 August 2001" "OpenLDAP LDVERSION" +.\" $OpenLDAP$ +.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldapdelete \- ldap delete entry tool +ldapdelete \- LDAP delete entry tool .SH SYNOPSIS .B ldapdelete -.B [\-n] -.B [\-v] -.B [\-k] -.B [\-K] -.B [\-c] -.B [\-d debuglevel] -.B [\-f file] -.B [\-D binddn] -.B [\-w passwd] -.B [\-h ldaphost] -.B [\-p ldapport] -.B [dn]... +[\c +.BR \-n ] +[\c +.BR \-v ] +[\c +.BR \-k ] +[\c +.BR \-K ] +[\c +.BR \-c ] +[\c +.BR \-C ] +[\c +.BR \-M[M] ] +[\c +.BI \-d \ debuglevel\fR] +[\c +.BI \-f \ file\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 \ 2\fR\||\|\fI3\fR] +[\c +.BI \-p \ ldapport\fR] +[\c +.BR \-O \ security-properties ] +[\c +.BI \-U \ authcid\fR] +[\c +.BR \-x ] +[\c +.BR \-I ] +[\c +.BR \-Q ] +[\c +.BI \-X \ authzid\fR] +[\c +.BI \-Y \ mech\fR] +[\c +.BR \-Z[Z] ] +[\c +.IR dn ]... .SH DESCRIPTION .I ldapdelete is a shell-accessible interface to the @@ -23,9 +64,10 @@ library call. .LP .B ldapdelete opens a connection to an LDAP server, binds, and deletes one or more -entries. If one or more \fIdn\fP arguments are provided, entries with -those Distinguished Names are deleted. Each \fIdn\fP should be a -string-represented DN as defined in RFC 1779. If no \fIdn\fP arguments +entries. If one or more \fIDN\fP arguments are provided, entries with +those Distinguished Names are deleted. Each \fIDN\fP should be provided +using the LDAPv3 string representation as defined in RFC 2253. +If no \fIdn\fP arguments are provided, a list of DNs is read from standard input (or from \fIfile\fP if the -f flag is used). .SH OPTIONS @@ -38,16 +80,19 @@ 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. This option only has effect if . B ldapdelete -is compiled with KERBEROS defined. +is compiled with Kerberos support. .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 \-C +Automatically chase referrals. .TP .B \-c Continuous operation mode. Errors are reported, but @@ -55,55 +100,110 @@ Continuous operation mode. Errors are reported, but will continue with deletions. The default is to exit after reporting an error. .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 ldapdelete must be compiled with LDAP_DEBUG defined for this option to have any effect. .TP -.B \-f file -Read a series of lines from \fIfile\fP, performing one LDAP search for -each line. In this case, the \fIfilter\fP given on the command line -is treated as a pattern where the first occurrence of \fB%s\fP is -replaced with a line from \fIfile\fP. +.BI \-f \ file +Read a series of DNs from \fIfile\fP, one per line, performing an +LDAP delete for each. +.TP +.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 \-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 \-W +Prompt for simple authentication. +This is used instead of specifying the password on the command line. .TP -.B \-w passwd +.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 +.B \-r +Do a recursive delete. If the DN specified isn't a leaf, its +children, and all their children are deleted down the tree. No +verification is done, so if you add this switch, ldapdelete will +happily delete large portions of your tree. Use with care. +.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 identity 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 EXAMPLE The following command: .LP .nf - ldapdelete "cn=Delete Me, o=University of Michigan, c=US" + ldapdelete "cn=Delete Me,dc=example,dc=com" .fi .LP -will attempt to delete the entry named with commonName "Delete Me" -directly below the University of Michigan organizational entry. Of -course it would probably be necessary to supply a \fIbinddn\fP and -\fIpasswd\fP for deletion to be allowed (see the -D and -w options). +will attempt to delete the entry named "cn=Delete Me,dc=example,dc=com". +Of course it would probably be necessary to supply authentication +credentials. .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. .SH "SEE ALSO" +.BR ldap.conf (5), .BR ldapadd (1), .BR ldapmodify (1), .BR ldapmodrdn (1), .BR ldapsearch (1), .BR ldap (3), .BR ldap_delete (3) -.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/doc/man/man3/ldap_error.3 b/doc/man/man3/ldap_error.3 index da99aa6231..f19e7ff6e3 100644 --- a/doc/man/man3/ldap_error.3 +++ b/doc/man/man3/ldap_error.3 @@ -193,8 +193,7 @@ An invalid filter was supplied to ldap_search() (e.g., unbalanced parentheses). .TP .SM LDAP_PARAM_ERROR -An ldap routine was called with a bad parameter (e.g., a NULL ld -pointer, etc.). +An ldap routine was called with a bad parameter. .TP .SM LDAP_NO_MEMORY An memory allocation (e.g., malloc(3) or other dynamic memory diff --git a/doc/man/man5/slapd-shell.5 b/doc/man/man5/slapd-shell.5 index 0beee6d657..a880f68c6a 100644 --- a/doc/man/man5/slapd-shell.5 +++ b/doc/man/man5/slapd-shell.5 @@ -15,10 +15,8 @@ make it easy to tie an existing database to the front-end. .SH WARNING .B "This backend's calling conventions have changed since OpenLDAP 2.0." -The operations receive a new "opid:" (operation ID) line, to be used -instead of "msgid:". -The "msgid:" line will be removed in a future version. -Also, abandon now gets a new "abandonid:" line. +The abandon operation now gets a new "pid:" line. +The "msgid:" lines will be removed in a future version. .SH CONFIGURATION These .B slapd.conf @@ -36,17 +34,15 @@ Each option is followed by the input lines that the program receives: .B abandon <pathname> <argument>... .nf ABANDON -opid: <operation ID> msgid: <message ID of operation to abandon> <repeat { "suffix:" <database suffix DN> }> -abandonid: <operation ID of operation to abandon> +pid: <process ID of operation to abandon> .fi .TP .B add <pathname> <argument>... .nf ADD -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> <entry in LDIF format> .fi @@ -54,8 +50,7 @@ msgid: <message ID> .B bind <pathname> <argument>... .nf BIND -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <DN> method: <method number> @@ -66,8 +61,7 @@ cred: <credentials> .B compare <pathname> <argument>... .nf COMPARE -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <DN> <attribute>: <value> @@ -76,8 +70,7 @@ dn: <DN> .B delete <pathname> <argument>... .nf DELETE -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <DN> .fi @@ -85,8 +78,7 @@ dn: <DN> .B modify <pathname> <argument>... .nf MODIFY -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <DN> <repeat { @@ -99,8 +91,7 @@ dn: <DN> .B modrdn <pathname> <argument>... .nf MODRDN -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <DN> newrdn: <new RDN> @@ -111,8 +102,7 @@ deleteoldrdn: <0 or 1> .B search <pathname> <argument>... .nf SEARCH -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> base: <base DN> scope: <0-2, see ldap.h> @@ -127,16 +117,11 @@ attrs: <"all" or space-separated attribute list> .B unbind <pathname> <argument>... .nf UNBIND -opid: <operation ID> -msgid: <message ID> +msgid: <message id> <repeat { "suffix:" <database suffix DN> }> dn: <bound DN> .fi .LP -An -.I operation ID -is a "connection ID/message ID" string identifying an operation. -.LP Note that you need only supply configuration lines for those commands you want the backend to handle. Operations for which a command is not supplied will be refused with an diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index 3c9ed2bc52..9a22026da7 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -204,6 +204,22 @@ disables Start TLS from forcing session to anonymous status (see also disables StartTLS if authenticated (see also .BR tls_2_anon ). .TP +.B gentlehup { on | off } +A SIGHUP signal will only cause a 'gentle' shutdown-attempt: +.B Slapd +will stop listening for new connections, but will not close the +connections to the current clients. It terminates when all clients +have closed their connections (if they ever do), or \- as before \- +if it receives a SIGTERM signal. This can be useful if you wish to +terminate the server and start a new +.B slapd +server +.B with another database, +without disrupting the currently active clients. +The default is off. You may wish to use +.B idletimeout +along with this option. +.TP .B idletimeout <integer> Specify the number of seconds to wait before forcibly closing an idle client connection. A idletimeout of 0 disables this diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c index 9925357b0c..76c2799236 100644 --- a/libraries/libldap/controls.c +++ b/libraries/libldap/controls.c @@ -413,9 +413,8 @@ ldap_create_control( LDAPControl *ctrl; struct berval *bvalp; - if ( requestOID == NULL || ctrlp == NULL ) { - return LDAP_PARAM_ERROR; - } + assert( requestOID != NULL ); + assert( ctrlp != NULL ); ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); if ( ctrl == NULL ) { diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c new file mode 100644 index 0000000000..1a763c9b6e --- /dev/null +++ b/libraries/libldap/dnssrv.c @@ -0,0 +1,304 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * locate LDAP servers using DNS SRV records. + * Location code based on MIT Kerberos KDC location code. + */ +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/param.h> +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +#ifdef HAVE_ARPA_NAMESER_H +#include <arpa/nameser.h> +#endif +#ifdef HAVE_RESOLV_H +#include <resolv.h> +#endif + +/* Sometimes this is not defined. */ +#ifndef T_SRV +#define T_SRV 33 +#endif /* T_SRV */ + +int ldap_dn2domain( + LDAP_CONST char *dn_in, + char **domainp) +{ + int i; + char *domain = NULL; + char **dn; + + if( dn_in == NULL || domainp == NULL ) { + return -1; + } + + dn = ldap_explode_dn( dn_in, 0 ); + + if( dn == NULL ) { + return -2; + } + + for( i=0; dn[i] != NULL; i++ ) { + char ** rdn = ldap_explode_rdn( dn[i], 0 ); + + if( rdn == NULL || *rdn == NULL ) { + LDAP_FREE( rdn ); + LDAP_FREE( domain ); + LDAP_VFREE( dn ); + return -3; + } + + + if( rdn[1] == NULL ) { + /* + * single-valued RDN + */ + char *dc; + +#define LDAP_DC "dc=" +#define LDAP_DCOID "0.9.2342.19200300.100.1.25=" + + if( strncasecmp( rdn[0], + LDAP_DC, sizeof(LDAP_DC)-1 ) == 0 ) + { + dc = &rdn[0][sizeof(LDAP_DC)-1]; + + } else if( strncmp( rdn[0], + LDAP_DCOID, sizeof(LDAP_DCOID)-1 ) == 0 ) + { + dc = &rdn[0][sizeof(LDAP_DCOID)-1]; + + } else { + dc = NULL; + } + + if( dc != NULL ) { + char *ndomain; + + if( *dc == '\0' ) { + /* dc value is empty! */ + LDAP_FREE( rdn ); + LDAP_FREE( domain ); + LDAP_VFREE( dn ); + LDAP_VFREE( rdn ); + return -4; + } + + ndomain = LDAP_REALLOC( domain, + ( domain == NULL ? 0 : strlen(domain) ) + + strlen(dc) + sizeof(".") ); + + if( ndomain == NULL ) { + LDAP_FREE( rdn ); + LDAP_FREE( domain ); + LDAP_VFREE( dn ); + LDAP_VFREE( rdn ); + return -5; + } + + if( domain == NULL ) { + ndomain[0] = '\0'; + } else { + strcat( ndomain, "." ); + } + + strcat( ndomain, dc ); + + domain = ndomain; + continue; + } + } + + /* + * multi-valued RDN or fall thru + */ + + LDAP_VFREE( rdn ); + LDAP_FREE( domain ); + domain = NULL; + } + + if( domain != NULL && *domain == '\0' ) { + LDAP_FREE( domain ); + domain = NULL; + } + + *domainp = domain; + return 0; +} + +int ldap_domain2dn( + LDAP_CONST char *domain_in, + char **dnp) +{ + char *domain, *s, *tok_r, *dn; + size_t loc; + + if (domain_in == NULL || dnp == NULL) { + return LDAP_NO_MEMORY; + } + domain = LDAP_STRDUP(domain_in); + if (domain == NULL) { + return LDAP_NO_MEMORY; + } + dn = NULL; + loc = 0; + + for (s = ldap_pvt_strtok(domain, ".", &tok_r); + s != NULL; + s = ldap_pvt_strtok(NULL, ".", &tok_r)) { + size_t len = strlen(s); + + dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len ); + if (dn == NULL) { + LDAP_FREE(domain); + return LDAP_NO_MEMORY; + } + if (loc > 0) { + /* not first time. */ + strcpy(dn + loc, ","); + loc++; + } + strcpy(dn + loc, "dc="); + loc += sizeof("dc=")-1; + + strcpy(dn + loc, s); + loc += len; + } + + LDAP_FREE(domain); + + *dnp = dn; + + return LDAP_SUCCESS; +} + +/* + * Lookup and return LDAP servers for domain (using the DNS + * SRV record _ldap._tcp.domain). + */ +int ldap_domain2hostlist( + LDAP_CONST char *domain, + char **list ) +{ +#ifdef HAVE_RES_QUERY + char *request; + char *hostlist = NULL; + int rc, len, cur = 0; + unsigned char reply[1024]; + + assert( domain != NULL ); + assert( list != NULL ); + + if( *domain == '\0' ) { + return LDAP_PARAM_ERROR; + } + + request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp.")); + if (request == NULL) { + return LDAP_NO_MEMORY; + } + sprintf(request, "_ldap._tcp.%s", domain); + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex); +#endif + + rc = LDAP_UNAVAILABLE; + len = res_query(request, C_IN, T_SRV, reply, sizeof(reply)); + if (len >= 0) { + unsigned char *p; + char host[1024]; + int status; + u_short port; + /* int priority, weight; */ + + /* Parse out query */ + p = reply; + p += sizeof(HEADER); + status = dn_expand(reply, reply + len, p, host, sizeof(host)); + if (status < 0) { + goto out; + } + p += status; + p += 4; + + while (p < reply + len) { + int type, class, ttl, size; + status = dn_expand(reply, reply + len, p, host, sizeof(host)); + if (status < 0) { + goto out; + } + p += status; + type = (p[0] << 8) | p[1]; + p += 2; + class = (p[0] << 8) | p[1]; + p += 2; + ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + size = (p[0] << 8) | p[1]; + p += 2; + if (type == T_SRV) { + int buflen; + status = dn_expand(reply, reply + len, p + 6, host, sizeof(host)); + if (status < 0) { + goto out; + } + /* ignore priority and weight for now */ + /* priority = (p[0] << 8) | p[1]; */ + /* weight = (p[2] << 8) | p[3]; */ + port = (p[4] << 8) | p[5]; + + buflen = strlen(host) + sizeof(":65355"); + hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen); + if (hostlist == NULL) { + rc = LDAP_NO_MEMORY; + goto out; + } + if (cur > 0) { + /* not first time around */ + hostlist[cur++] = ' '; + } + cur += sprintf(&hostlist[cur], "%s:%hd", host, port); + } + p += size; + } + } + if (hostlist == NULL) { + /* No LDAP servers found in DNS. */ + rc = LDAP_UNAVAILABLE; + goto out; + } + + rc = LDAP_SUCCESS; + *list = hostlist; + + out: +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex); +#endif + + if (request != NULL) { + LDAP_FREE(request); + } + if (rc != LDAP_SUCCESS && hostlist != NULL) { + LDAP_FREE(hostlist); + } + return rc; +#else + return LDAP_NOT_SUPPORTED; +#endif /* HAVE_RES_QUERY */ +} diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c index 8fc685b25f..3569887747 100644 --- a/libraries/libldap/error.c +++ b/libraries/libldap/error.c @@ -172,11 +172,6 @@ ldap_perror( LDAP *ld, LDAP_CONST char *str ) assert( LDAP_VALID( ld ) ); assert( str ); - if ( ld == NULL ) { - fprintf( stderr, "ldap_perror: invalid session handle\n" ); - return; - } - e = ldap_int_error( ld->ld_errno ); fprintf( stderr, "%s: %s (%d)\n", @@ -257,10 +252,6 @@ ldap_parse_result( assert( LDAP_VALID( ld ) ); assert( r != NULL ); - if ( ld == NULL || r == NULL ) { - return LDAP_PARAM_ERROR; - } - if(errcodep != NULL) *errcodep = LDAP_SUCCESS; if(matcheddnp != NULL) *matcheddnp = NULL; if(errmsgp != NULL) *errmsgp = NULL; diff --git a/libraries/libldap/extended.c b/libraries/libldap/extended.c index 58bffe8620..74e31281ca 100644 --- a/libraries/libldap/extended.c +++ b/libraries/libldap/extended.c @@ -60,11 +60,6 @@ ldap_extended_operation( return( ld->ld_errno ); } - if( reqoid == NULL || *reqoid == '\0' || msgidp == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return( ld->ld_errno ); - } - /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; @@ -132,11 +127,6 @@ ldap_extended_operation_s( assert( reqoid != NULL || *reqoid == '\0' ); assert( retoidp != NULL || retdatap != NULL ); - if( retoidp == NULL || retdatap == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return( ld->ld_errno ); - } - rc = ldap_extended_operation( ld, reqoid, reqdata, sctrls, cctrls, &msgid ); diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index bec27bc7da..4dd2279ee5 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -90,10 +90,9 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry ) Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); #endif - if ( entry == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return( NULL ); - } + assert( ld != NULL ); + assert( LDAP_VALID(ld) ); + assert( entry != NULL ); tmp = *entry->lm_ber; /* struct copy */ if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) { @@ -2878,7 +2877,7 @@ ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags ) break; default: - return( LDAP_PARAM_ERROR ); + return LDAP_PARAM_ERROR; } bv->bv_val = LDAP_MALLOC( l + 1 ); diff --git a/libraries/libldap/getentry.c b/libraries/libldap/getentry.c index f3f896e7b8..b75a4403f4 100644 --- a/libraries/libldap/getentry.c +++ b/libraries/libldap/getentry.c @@ -1,60 +1,130 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * getentry.c */ -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif +#include "portable.h" #include <stdio.h> -#include <ctype.h> -#include <string.h> -#ifdef MACOS -#include <stdlib.h> -#include "macos.h" -#else /* MACOS */ -#if defined( DOS ) || defined( _WIN32 ) -#include <malloc.h> -#include "msdos.h" -#else /* DOS */ -#include <sys/types.h> -#include <sys/socket.h> -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" +#include <ac/stdlib.h> + +#include <ac/socket.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" /* ARGSUSED */ LDAPMessage * ldap_first_entry( LDAP *ld, LDAPMessage *chain ) { - return( chain == NULLMSG || chain->lm_msgtype == LDAP_RES_SEARCH_RESULT - ? NULLMSG : chain ); + assert( ld != NULL ); + 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 ); } -/* ARGSUSED */ -LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry ) +LDAPMessage * +ldap_next_entry( LDAP *ld, LDAPMessage *entry ) { - if ( entry == NULLMSG || entry->lm_chain == NULLMSG - || entry->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) - return( NULLMSG ); + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); - return( entry->lm_chain ); + if ( ld == NULL || entry == NULL ) { + return NULL; + } + + for ( + entry = entry->lm_chain; + entry != NULL; + entry = entry->lm_chain ) + { + if( entry->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { + return( entry ); + } + } + + return( NULL ); } -/* ARGSUSED */ int ldap_count_entries( LDAP *ld, LDAPMessage *chain ) { int i; - for ( i = 0; chain != NULL && chain->lm_msgtype - != LDAP_RES_SEARCH_RESULT; chain = chain->lm_chain ) - i++; + 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++; + } + } return( i ); } + +int +ldap_get_entry_controls( + LDAP *ld, + LDAPMessage *entry, + LDAPControl ***sctrls ) +{ + int rc; + BerElement be; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( entry != NULL ); + assert( sctrls != NULL ); + + if ( entry->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) { + return LDAP_PARAM_ERROR; + } + + /* make a local copy of the BerElement */ + AC_MEMCPY(&be, entry->lm_ber, sizeof(be)); + + if ( ber_scanf( &be, "{xx" /*}*/ ) == LBER_ERROR ) { + rc = LDAP_DECODING_ERROR; + goto cleanup_and_return; + } + + rc = ldap_int_get_controls( &be, sctrls ); + +cleanup_and_return: + if( rc != LDAP_SUCCESS ) { + ld->ld_errno = rc; + + if( ld->ld_matched != NULL ) { + LDAP_FREE( ld->ld_matched ); + ld->ld_matched = NULL; + } + + if( ld->ld_error != NULL ) { + LDAP_FREE( ld->ld_error ); + ld->ld_error = NULL; + } + } + + return rc; +} diff --git a/libraries/libldap/references.c b/libraries/libldap/references.c new file mode 100644 index 0000000000..2aae3f469c --- /dev/null +++ b/libraries/libldap/references.c @@ -0,0 +1,146 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * references.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_reference( LDAP *ld, LDAPMessage *chain ) +{ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( chain != NULL ); + + return chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE + ? chain + : ldap_next_reference( ld, chain ); +} + +LDAPMessage * +ldap_next_reference( LDAP *ld, LDAPMessage *ref ) +{ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( ref != NULL ); + + for ( + ref = ref->lm_chain; + ref != NULL; + ref = ref->lm_chain ) + { + if( ref->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) { + return( ref ); + } + } + + return( NULL ); +} + +int +ldap_count_references( LDAP *ld, LDAPMessage *chain ) +{ + int i; + + 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++; + } + } + + return( i ); +} + +int +ldap_parse_reference( + LDAP *ld, + LDAPMessage *ref, + char ***referralsp, + LDAPControl ***serverctrls, + int freeit) +{ + BerElement be; + char **refs = NULL; + int rc; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( ref != NULL ); + + if( ref->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) { + return LDAP_PARAM_ERROR; + } + + /* make a private copy of BerElement */ + AC_MEMCPY(&be, ref->lm_ber, sizeof(be)); + + if ( ber_scanf( &be, "{v" /*}*/, &refs ) == LBER_ERROR ) { + rc = LDAP_DECODING_ERROR; + goto free_and_return; + } + + if ( serverctrls == NULL ) { + rc = LDAP_SUCCESS; + goto free_and_return; + } + + if ( ber_scanf( &be, /*{*/ "}" ) == LBER_ERROR ) { + rc = LDAP_DECODING_ERROR; + goto free_and_return; + } + + rc = ldap_int_get_controls( &be, serverctrls ); + +free_and_return: + + if( referralsp != NULL ) { + /* provide references regradless of return code */ + *referralsp = refs; + + } else { + LDAP_VFREE( refs ); + } + + if( freeit ) { + ldap_msgfree( ref ); + } + + if( rc != LDAP_SUCCESS ) { + ld->ld_errno = rc; + + if( ld->ld_matched != NULL ) { + LDAP_FREE( ld->ld_matched ); + ld->ld_matched = NULL; + } + + if( ld->ld_error != NULL ) { + LDAP_FREE( ld->ld_error ); + ld->ld_error = NULL; + } + } + + return rc; +} diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index f409afcc9e..a1ee317cf6 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -103,15 +103,6 @@ ldap_result( Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 ); #endif - if( ld == NULL ) { - return -1; - } - - if( result == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return -1; - } - lm = chkResponseList(ld, msgid, all); if ( lm == NULL ) { diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c index 93a52472f8..0164bc962f 100644 --- a/libraries/libldap/sasl.c +++ b/libraries/libldap/sasl.c @@ -75,11 +75,6 @@ ldap_sasl_bind( rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; - if( msgidp == NULL ) { - ld->ld_errno = LDAP_PARAM_ERROR; - return ld->ld_errno; - } - if( mechanism == LDAP_SASL_SIMPLE ) { if( dn == NULL && cred != NULL ) { /* use default binddn */ @@ -269,10 +264,6 @@ ldap_parse_sasl_bind_result( assert( LDAP_VALID( ld ) ); assert( res != NULL ); - if ( ld == NULL || res == NULL ) { - return LDAP_PARAM_ERROR; - } - if( servercredp != NULL ) { if( ld->ld_version < LDAP_VERSION2 ) { return LDAP_NOT_SUPPORTED; diff --git a/libraries/libldap/sort.c b/libraries/libldap/sort.c index ee5d549c89..84557eb33a 100644 --- a/libraries/libldap/sort.c +++ b/libraries/libldap/sort.c @@ -1,4 +1,9 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1994 Regents of the University of Michigan. * All rights reserved. * @@ -12,53 +17,45 @@ * sort.c: LDAP library entry and value sort routines */ +#include "portable.h" + #include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <stdlib.h> -#ifdef MACOS -#include "macos.h" -#else /* MACOS */ -#ifdef DOS -#include <malloc.h> -#include "msdos.h" -#endif /* DOS */ -#endif /* MACOS */ - -#include "lber.h" -#include "ldap.h" +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/time.h> + + +#include "ldap-int.h" struct entrything { char **et_vals; LDAPMessage *et_msg; + int (*et_cmp_fn) LDAP_P((const char *a, const char *b)); }; -#ifndef NEEDPROTOS -static int (*et_cmp_fn)(); -static int et_cmp(); -#else /* !NEEDPROTOS */ -static int (*et_cmp_fn)( char *a, char *b ); -static int et_cmp( void *aa, void *bb); -#endif /* !NEEDPROTOS */ +static int et_cmp LDAP_P(( const void *aa, const void *bb)); + int ldap_sort_strcasecmp( - char **a, - char **b + LDAP_CONST void *a, + LDAP_CONST void *b ) { - return( strcasecmp( *a, *b ) ); + return( strcasecmp( *(char *const *)a, *(char *const *)b ) ); } static int et_cmp( - void *aa, - void *bb + const void *aa, + const void *bb ) { int i, rc; - struct entrything *a = (struct entrything *)aa; - struct entrything *b = (struct entrything *)bb; + const struct entrything *a = (const struct entrything *)aa; + const struct entrything *b = (const struct entrything *)bb; if ( a->et_vals == NULL && b->et_vals == NULL ) return( 0 ); @@ -68,8 +65,7 @@ et_cmp( return( 1 ); for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) { - if ( (rc = (*et_cmp_fn)( a->et_vals[i], b->et_vals[i] )) - != 0 ) { + if ( (rc = a->et_cmp_fn( a->et_vals[i], b->et_vals[i] )) != 0 ) { return( rc ); } } @@ -85,8 +81,8 @@ int ldap_sort_entries( LDAP *ld, LDAPMessage **chain, - char *attr, /* NULL => sort by DN */ - int (*cmp)() + LDAP_CONST char *attr, /* NULL => sort by DN */ + int (*cmp) (LDAP_CONST char *, LDAP_CONST char *) ) { int i, count; @@ -94,9 +90,19 @@ ldap_sort_entries( LDAPMessage *e, *last; LDAPMessage **ep; + assert( ld != NULL ); + count = ldap_count_entries( ld, *chain ); - if ( (et = (struct entrything *) malloc( count * + if ( count < 0 ) { + return -1; + + } else if ( count < 2 ) { + /* zero or one entries -- already sorted! */ + return 0; + } + + if ( (et = (struct entrything *) LDAP_MALLOC( count * sizeof(struct entrything) )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); @@ -104,13 +110,14 @@ ldap_sort_entries( e = *chain; for ( i = 0; i < count; i++ ) { + et[i].et_cmp_fn = cmp; et[i].et_msg = e; if ( attr == NULL ) { char *dn; dn = ldap_get_dn( ld, e ); et[i].et_vals = ldap_explode_dn( dn, 1 ); - free( dn ); + LDAP_FREE( dn ); } else { et[i].et_vals = ldap_get_values( ld, e, attr ); } @@ -119,18 +126,17 @@ ldap_sort_entries( } last = e; - et_cmp_fn = cmp; - qsort( et, count, sizeof(struct entrything), (void *) et_cmp ); + qsort( et, count, sizeof(struct entrything), et_cmp ); ep = chain; for ( i = 0; i < count; i++ ) { *ep = et[i].et_msg; ep = &(*ep)->lm_chain; - ldap_value_free( et[i].et_vals ); + LDAP_VFREE( et[i].et_vals ); } *ep = last; - free( (char *) et ); + LDAP_FREE( (char *) et ); return( 0 ); } @@ -139,7 +145,7 @@ int ldap_sort_values( LDAP *ld, char **vals, - int (*cmp)() + int (*cmp) (LDAP_CONST void *, LDAP_CONST void *) ) { int nel; diff --git a/libraries/libldap/sortctrl.c b/libraries/libldap/sortctrl.c new file mode 100644 index 0000000000..f215a839d2 --- /dev/null +++ b/libraries/libldap/sortctrl.c @@ -0,0 +1,466 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */ +/*--- + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + * + *---*/ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +#define LDAP_MATCHRULE_IDENTIFIER 0x80L +#define LDAP_REVERSEORDER_IDENTIFIER 0x81L +#define LDAP_ATTRTYPES_IDENTIFIER 0x80L + + + +/* --------------------------------------------------------------------------- + countKeys + + Internal function to determine the number of keys in the string. + + keyString (IN) String of items separated by whitespace. + ---------------------------------------------------------------------------*/ + +static int countKeys(char *keyString) +{ + char *p = keyString; + int count = 0; + + for (;;) + { + while (LDAP_SPACE(*p)) /* Skip leading whitespace */ + p++; + + if (*p == '\0') /* End of string? */ + return count; + + count++; /* Found start of a key */ + + while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */ + if (*p++ == '\0') + return count; + } +} + + +/* --------------------------------------------------------------------------- + readNextKey + + Internal function to parse the next sort key in the string. + Allocate an LDAPSortKey structure and initialize it with + attribute name, reverse flag, and matching rule OID. + + Each sort key in the string has the format: + [whitespace][-]attribute[:[OID]] + + pNextKey (IN/OUT) Points to the next key in the sortkey string to parse. + The pointer is updated to point to the next character + after the sortkey being parsed. + + key (OUT) Points to the address of an LDAPSortKey stucture + which has been allocated by this routine and + initialized with information from the next sortkey. + ---------------------------------------------------------------------------*/ + +static int readNextKey( char **pNextKey, LDAPSortKey **key) +{ + char *p = *pNextKey; + int rev = 0; + char *attrStart; + int attrLen; + char *oidStart = NULL; + int oidLen = 0; + + /* Skip leading white space. */ + while (LDAP_SPACE(*p)) + p++; + + if (*p == '-') /* Check if the reverse flag is present. */ + { + rev=1; + p++; + } + + /* We're now positioned at the start of the attribute. */ + attrStart = p; + + /* Get the length of the attribute until the next whitespace or ":". */ + attrLen = strcspn(p, " \t:"); + p += attrLen; + + if (attrLen == 0) /* If no attribute name was present, quit. */ + return LDAP_PARAM_ERROR; + + if (*p == ':') + { + oidStart = ++p; /* Start of the OID, after the colon */ + oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */ + p += oidLen; + } + + *pNextKey = p; /* Update argument to point to next key */ + + /* Allocate an LDAPSortKey structure */ + *key = LDAP_MALLOC(sizeof(LDAPSortKey)); + if (*key == NULL) return LDAP_NO_MEMORY; + + /* Allocate memory for the attribute and copy to it. */ + (*key)->attributeType = LDAP_MALLOC(attrLen+1); + if ((*key)->attributeType == NULL) { + LDAP_FREE(*key); + return LDAP_NO_MEMORY; + } + + strncpy((*key)->attributeType, attrStart, attrLen); + (*key)->attributeType[attrLen] = 0; + + /* If present, allocate memory for the OID and copy to it. */ + if (oidLen) { + (*key)->orderingRule = LDAP_MALLOC(oidLen+1); + if ((*key)->orderingRule == NULL) { + LDAP_FREE((*key)->attributeType); + LDAP_FREE(*key); + return LDAP_NO_MEMORY; + } + strncpy((*key)->orderingRule, oidStart, oidLen); + (*key)->orderingRule[oidLen] = 0; + + } else { + (*key)->orderingRule = NULL; + } + + (*key)->reverseOrder = rev; + + return LDAP_SUCCESS; +} + + +/* --------------------------------------------------------------------------- + ldap_create_sort_keylist + + Create an array of pointers to LDAPSortKey structures, containing the + information specified by the string representation of one or more + sort keys. + + sortKeyList (OUT) Points to a null-terminated array of pointers to + LDAPSortKey structures allocated by this routine. + This memory SHOULD be freed by the calling program + using ldap_free_sort_keylist(). + + keyString (IN) Points to a string of one or more sort keys. + + ---------------------------------------------------------------------------*/ + +int +ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString ) +{ + int numKeys, rc, i; + char *nextKey; + LDAPSortKey **keyList = NULL; + + assert( sortKeyList != NULL ); + assert( keyString != NULL ); + + *sortKeyList = NULL; + + /* Determine the number of sort keys so we can allocate memory. */ + if (( numKeys = countKeys(keyString)) == 0) { + return LDAP_PARAM_ERROR; + } + + /* Allocate the array of pointers. Initialize to NULL. */ + keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*)); + if ( keyList == NULL) return LDAP_NO_MEMORY; + + /* For each sort key in the string, create an LDAPSortKey structure + and add it to the list. + */ + nextKey = keyString; /* Points to the next key in the string */ + for (i=0; i < numKeys; i++) { + rc = readNextKey(&nextKey, &keyList[i]); + + if (rc != LDAP_SUCCESS) { + ldap_free_sort_keylist(keyList); + return rc; + } + } + + *sortKeyList = keyList; + return LDAP_SUCCESS; +} + + +/* --------------------------------------------------------------------------- + ldap_free_sort_keylist + + Frees the sort key structures created by ldap_create_sort_keylist(). + Frees the memory referenced by the LDAPSortKey structures, + the LDAPSortKey structures themselves, and the array of pointers + to the structures. + + keyList (IN) Points to an array of pointers to LDAPSortKey structures. + ---------------------------------------------------------------------------*/ + +void +ldap_free_sort_keylist ( LDAPSortKey **keyList ) +{ + int i; + LDAPSortKey *nextKeyp; + + if (keyList == NULL) return; + + i=0; + while ( 0 != (nextKeyp = keyList[i++]) ) { + if (nextKeyp->attributeType) { + LBER_FREE(nextKeyp->attributeType); + } + + if (nextKeyp->orderingRule != NULL) { + LBER_FREE(nextKeyp->orderingRule); + } + + LBER_FREE(nextKeyp); + } + + LBER_FREE(keyList); +} + + +/* --------------------------------------------------------------------------- + ldap_create_sort_control + + Create and encode the server-side sort control. + + ld (IN) An LDAP session handle, as obtained from a call to + ldap_init(). + + keyList (IN) Points to a null-terminated array of pointers to + LDAPSortKey structures, containing a description of + each of the sort keys to be used. The description + consists of an attribute name, ascending/descending flag, + and an optional matching rule (OID) to use. + + isCritical (IN) 0 - Indicates the control is not critical to the operation. + non-zero - The control is critical to the operation. + + ctrlp (OUT) Returns a pointer to the LDAPControl created. This control + SHOULD be freed by calling ldap_control_free() when done. + + + Ber encoding + + SortKeyList ::= SEQUENCE OF SEQUENCE { + attributeType AttributeDescription, + orderingRule [0] MatchingRuleId OPTIONAL, + reverseOrder [1] BOOLEAN DEFAULT FALSE } + + ---------------------------------------------------------------------------*/ + +int +ldap_create_sort_control ( + LDAP *ld, + LDAPSortKey **keyList, + int isCritical, + LDAPControl **ctrlp ) +{ + int i; + BerElement *ber; + ber_tag_t tag; + + + if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return(ld->ld_errno); + } + + if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + return( ld->ld_errno ); + } + + tag = ber_printf(ber, "{" /*}*/); + if (tag == LBER_ERROR) goto exit; + + for (i = 0; keyList[i] != NULL; i++) { + tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType); + if (tag == LBER_ERROR) goto exit; + + if ((keyList[i])->orderingRule != NULL) { + tag = ber_printf( ber, "ts", + LDAP_MATCHRULE_IDENTIFIER, + (keyList[i])->orderingRule ); + + if( tag == LBER_ERROR ) goto exit; + } + + if ((keyList[i])->reverseOrder) { + tag = ber_printf(ber, "tb", + LDAP_REVERSEORDER_IDENTIFIER, + (keyList[i])->reverseOrder ); + + if( tag == LBER_ERROR ) goto exit; + } + + tag = ber_printf(ber, /*{*/ "N}"); + if( tag == LBER_ERROR ) goto exit; + } + + tag = ber_printf(ber, /*{*/ "N}"); + if( tag == LBER_ERROR ) goto exit; + + ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST, + ber, isCritical, ctrlp); + + ber_free(ber, 1); + + return(ld->ld_errno); + +exit: + ber_free(ber, 1); + ld->ld_errno = LDAP_ENCODING_ERROR; + return(ld->ld_errno); +} + + +/* --------------------------------------------------------------------------- + ldap_parse_sort_control + + Decode the server-side sort control return information. + + ld (IN) An LDAP session handle, as obtained from a call to + ldap_init(). + + ctrls (IN) The address of a NULL-terminated array of LDAPControl + structures, typically obtained by a call to + ldap_parse_result(). + + returnCode (OUT) This result parameter is filled in with the sort control + result code. This parameter MUST not be NULL. + + attribute (OUT) If an error occured the server may return a string + indicating the first attribute in the sortkey list + that was in error. If a string is returned, the memory + should be freed with ldap_memfree. If this parameter is + NULL, no string is returned. + + + Ber encoding for sort control + + SortResult ::= SEQUENCE { + sortResult ENUMERATED { + success (0), -- results are sorted + operationsError (1), -- server internal failure + timeLimitExceeded (3), -- timelimit reached before + -- sorting was completed + strongAuthRequired (8), -- refused to return sorted + -- results via insecure + -- protocol + adminLimitExceeded (11), -- too many matching entries + -- for the server to sort + noSuchAttribute (16), -- unrecognized attribute + -- type in sort key + inappropriateMatching (18), -- unrecognized or inappro- + -- priate matching rule in + -- sort key + insufficientAccessRights (50), -- refused to return sorted + -- results to this client + busy (51), -- too busy to process + unwillingToPerform (53), -- unable to sort + other (80) + }, + attributeType [0] AttributeDescription OPTIONAL } + ---------------------------------------------------------------------------*/ + +int +ldap_parse_sort_control( + LDAP *ld, + LDAPControl **ctrls, + unsigned long *returnCode, + char **attribute ) +{ + BerElement *ber; + LDAPControl *pControl; + int i; + ber_tag_t tag, berTag; + ber_len_t berLen; + + if (ld == NULL) { + ld->ld_errno = LDAP_PARAM_ERROR; + return(ld->ld_errno); + } + + if (ctrls == NULL) { + ld->ld_errno = LDAP_CONTROL_NOT_FOUND; + return(ld->ld_errno); + } + + if (attribute) { + *attribute = NULL; + } + + /* Search the list of control responses for a sort control. */ + for (i=0; ctrls[i]; i++) { + pControl = ctrls[i]; + if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid)) + goto foundSortControl; + } + + /* No sort control was found. */ + ld->ld_errno = LDAP_CONTROL_NOT_FOUND; + return(ld->ld_errno); + +foundSortControl: + /* Create a BerElement from the berval returned in the control. */ + ber = ber_init(&pControl->ldctl_value); + + if (ber == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + return(ld->ld_errno); + } + + /* Extract the result code from the control. */ + tag = ber_scanf(ber, "{e" /*}*/, returnCode); + + if( tag == LBER_ERROR ) { + ber_free(ber, 1); + ld->ld_errno = LDAP_DECODING_ERROR; + return(ld->ld_errno); + } + + /* If caller wants the attribute name, and if it's present in the control, + extract the attribute name which caused the error. */ + if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen))) + { + tag = ber_scanf(ber, "ta", &berTag, attribute); + + if (tag == LBER_ERROR ) { + ber_free(ber, 1); + ld->ld_errno = LDAP_DECODING_ERROR; + return(ld->ld_errno); + } + } + + ber_free(ber,1); + + ld->ld_errno = LDAP_SUCCESS; + return(ld->ld_errno); +} diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 97059170b7..e7985dae6b 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -886,10 +886,10 @@ ldap_url_parselist (LDAPURLDesc **ludlist, const char *url ) LDAPURLDesc *ludp; char **urls; - *ludlist = NULL; + assert( ludlist != NULL ); + assert( url != NULL ); - if (url == NULL) - return LDAP_PARAM_ERROR; + *ludlist = NULL; urls = ldap_str2charray(url, ", "); if (urls == NULL) @@ -923,10 +923,10 @@ ldap_url_parsehosts( LDAPURLDesc *ludp; char **specs, *p; - *ludlist = NULL; + assert( ludlist != NULL ); + assert( hosts != NULL ); - if (hosts == NULL) - return LDAP_PARAM_ERROR; + *ludlist = NULL; specs = ldap_str2charray(hosts, ", "); if (specs == NULL) diff --git a/libraries/libldap/vlvctrl.c b/libraries/libldap/vlvctrl.c new file mode 100644 index 0000000000..0ee5ed2ab4 --- /dev/null +++ b/libraries/libldap/vlvctrl.c @@ -0,0 +1,277 @@ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */ +/*--- + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + *---*/ + +#include "portable.h" + +#include <stdio.h> +#include <ac/stdlib.h> +#include <ac/string.h> +#include <ac/time.h> + +#include "ldap-int.h" + +#define LDAP_VLVBYINDEX_IDENTIFIER 0xa0L +#define LDAP_VLVBYVALUE_IDENTIFIER 0x81L +#define LDAP_VLVCONTEXT_IDENTIFIER 0x04L + + +/*--- + ldap_create_vlv_control + + Create and encode the Virtual List View control. + + ld (IN) An LDAP session handle, as obtained from a call to + ldap_init(). + + vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents + are used to construct the value of the control + that is created. + + ctrlp (OUT) A result parameter that will be assigned the address + of an LDAPControl structure that contains the + VirtualListViewRequest control created by this function. + The memory occupied by the LDAPControl structure + SHOULD be freed when it is no longer in use by + calling ldap_control_free(). + + + Ber encoding + + VirtualListViewRequest ::= SEQUENCE { + beforeCount INTEGER (0 .. maxInt), + afterCount INTEGER (0 .. maxInt), + CHOICE { + byoffset [0] SEQUENCE, { + offset INTEGER (0 .. maxInt), + contentCount INTEGER (0 .. maxInt) } + [1] greaterThanOrEqual assertionValue } + contextID OCTET STRING OPTIONAL } + + + Note: The first time the VLV control is created, the ldvlv_context + field of the LDAPVLVInfo structure should be set to NULL. + The context obtained from calling ldap_parse_vlv_control() + should be used as the context in the next ldap_create_vlv_control + call. + + ---*/ + +int +ldap_create_vlv_control( LDAP *ld, + LDAPVLVInfo *vlvinfop, + LDAPControl **ctrlp ) +{ + ber_tag_t tag; + BerElement *ber; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( vlvinfop != NULL ); + assert( ctrlp != NULL ); + + if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + return(LDAP_NO_MEMORY); + } + + tag = ber_printf(ber, "{ii" /*}*/, + vlvinfop->ldvlv_before_count, + vlvinfop->ldvlv_after_count); + if( tag == LBER_ERROR ) goto exit; + + if (vlvinfop->ldvlv_attrvalue == NULL) { + tag = ber_printf(ber, "t{iiN}", + LDAP_VLVBYINDEX_IDENTIFIER, + vlvinfop->ldvlv_offset, + vlvinfop->ldvlv_count); + if( tag == LBER_ERROR ) goto exit; + + } else { + tag = ber_printf(ber, "tO", + LDAP_VLVBYVALUE_IDENTIFIER, + vlvinfop->ldvlv_attrvalue); + if( tag == LBER_ERROR ) goto exit; + } + + if (vlvinfop->ldvlv_context) { + tag = ber_printf(ber, "tO", + LDAP_VLVCONTEXT_IDENTIFIER, + vlvinfop->ldvlv_context); + if( tag == LBER_ERROR ) goto exit; + } + + tag = ber_printf(ber, /*{*/ "N}"); + if( tag == LBER_ERROR ) goto exit; + + ld->ld_errno = ldap_create_control( LDAP_CONTROL_VLVREQUEST, + ber, 1, ctrlp); + + ber_free(ber, 1); + return(ld->ld_errno); + +exit: + ber_free(ber, 1); + ld->ld_errno = LDAP_ENCODING_ERROR; + return(ld->ld_errno); +} + + +/*--- + ldap_parse_vlv_control + + Decode the Virtual List View control return information. + + ld (IN) An LDAP session handle. + + ctrls (IN) The address of a NULL-terminated array of + LDAPControl structures, typically obtained + by a call to ldap_parse_result(). + + target_posp (OUT) This result parameter is filled in with the list + index of the target entry. If this parameter is + NULL, the target position is not returned. + + list_countp (OUT) This result parameter is filled in with the server's + estimate of the size of the list. If this parameter + is NULL, the size is not returned. + + contextp (OUT) This result parameter is filled in with the address + of a struct berval that contains the server- + generated context identifier if one was returned by + the server. If the server did not return a context + identifier, this parameter will be set to NULL, even + if an error occured. + The returned context SHOULD be used in the next call + to create a VLV sort control. The struct berval + returned SHOULD be disposed of by calling ber_bvfree() + when it is no longer needed. If NULL is passed for + contextp, the context identifier is not returned. + + errcodep (OUT) This result parameter is filled in with the VLV + result code. If this parameter is NULL, the result + code is not returned. + + + Ber encoding + + VirtualListViewResponse ::= SEQUENCE { + targetPosition INTEGER (0 .. maxInt), + contentCount INTEGER (0 .. maxInt), + virtualListViewResult ENUMERATED { + success (0), + operatonsError (1), + unwillingToPerform (53), + insufficientAccessRights (50), + busy (51), + timeLimitExceeded (3), + adminLimitExceeded (11), + sortControlMissing (60), + offsetRangeError (61), + other (80) }, + contextID OCTET STRING OPTIONAL } + +---*/ + +int +ldap_parse_vlv_control( + LDAP *ld, + LDAPControl **ctrls, + unsigned long *target_posp, + unsigned long *list_countp, + struct berval **contextp, + int *errcodep ) +{ + BerElement *ber; + LDAPControl *pControl; + int i; + unsigned long pos, count, err; + ber_tag_t tag, berTag; + ber_len_t berLen; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + if (contextp) { + *contextp = NULL; /* Make sure we return a NULL if error occurs. */ + } + + if (ctrls == NULL) { + ld->ld_errno = LDAP_CONTROL_NOT_FOUND; + return(ld->ld_errno); + } + + /* Search the list of control responses for a VLV control. */ + for (i=0; ctrls[i]; i++) { + pControl = ctrls[i]; + if (!strcmp(LDAP_CONTROL_VLVRESPONSE, pControl->ldctl_oid)) + goto foundVLVControl; + } + + /* No sort control was found. */ + ld->ld_errno = LDAP_CONTROL_NOT_FOUND; + return(ld->ld_errno); + +foundVLVControl: + /* Create a BerElement from the berval returned in the control. */ + ber = ber_init(&pControl->ldctl_value); + + if (ber == NULL) { + ld->ld_errno = LDAP_NO_MEMORY; + return(ld->ld_errno); + } + + /* Extract the data returned in the control. */ + tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err); + + if( tag == LBER_ERROR) { + ber_free(ber, 1); + ld->ld_errno = LDAP_DECODING_ERROR; + return(ld->ld_errno); + } + + + /* Since the context is the last item encoded, if caller doesn't want + it returned, don't decode it. */ + if (contextp) { + if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) { + tag = ber_scanf(ber, "tO", &berTag, contextp); + + if( tag == LBER_ERROR) { + ber_free(ber, 1); + ld->ld_errno = LDAP_DECODING_ERROR; + return(ld->ld_errno); + } + } + } + + ber_free(ber, 1); + + /* Return data to the caller for items that were requested. */ + if (target_posp) { + *target_posp = pos; + } + if (list_countp) { + *list_countp = count; + } + if (errcodep) { + *errcodep = err; + } + + ld->ld_errno = LDAP_SUCCESS; + return(ld->ld_errno); +} diff --git a/libraries/libldap_r/tpool.c b/libraries/libldap_r/tpool.c index 923a1b9ce4..d48a8e9370 100644 --- a/libraries/libldap_r/tpool.c +++ b/libraries/libldap_r/tpool.c @@ -399,7 +399,11 @@ ldap_int_thread_pool_wrapper ( ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); (ctx->ltc_start_routine)(ctx->ltc_arg); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); LDAP_SLIST_INSERT_HEAD(&pool->ltp_free_list, ctx, ltc_next.l); + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + ldap_pvt_thread_yield(); /* if we use an idle timer, here's diff --git a/libraries/liblutil/entropy.c b/libraries/liblutil/entropy.c index cd379c6724..74d3f3210a 100644 --- a/libraries/liblutil/entropy.c +++ b/libraries/liblutil/entropy.c @@ -36,21 +36,27 @@ int lutil_entropy( unsigned char *buf, ber_len_t nbytes ) if( nbytes == 0 ) return 0; #ifdef URANDOM_DEVICE +#define URANDOM_NREADS 4 /* Linux and *BSD offer a urandom device */ { - int rc, fd; + int rc, fd, n=0; fd = open( URANDOM_DEVICE, O_RDONLY ); if( fd < 0 ) return -1; - rc = read( fd, buf, nbytes ); - close(fd); + do { + rc = read( fd, buf, nbytes ); + if( rc <= 0 ) break; - /* should return nbytes */ - if( rc != nbytes ) return -1; + buf+=rc; + nbytes-=rc; - return 0; + if( ++n >= URANDOM_NREADS ) break; + } while( nbytes > 0 ); + + close(fd); + return nbytes > 0 ? -1 : 0; } #elif PROV_RSA_FULL { diff --git a/servers/slapd/at.c b/servers/slapd/at.c index 91015007b9..ef73fe7b45 100644 --- a/servers/slapd/at.c +++ b/servers/slapd/at.c @@ -235,7 +235,7 @@ at_insert( (AVL_DUP) avl_dup_error ) ) { *err = sat->sat_oid; ldap_memfree(air); - return SLAP_SCHERR_DUP_ATTR; + return SLAP_SCHERR_ATTR_DUP; } /* FIX: temporal consistency check */ at_bvfind(&air->air_name); @@ -253,7 +253,7 @@ at_insert( (AVL_DUP) avl_dup_error ) ) { *err = *names; ldap_memfree(air); - return SLAP_SCHERR_DUP_ATTR; + return SLAP_SCHERR_ATTR_DUP; } /* FIX: temporal consistency check */ at_bvfind(&air->air_name); @@ -371,6 +371,11 @@ at_add( /* subtypes must have same usage as their SUP */ return SLAP_SCHERR_ATTR_BAD_USAGE; } + + if ( sat->sat_flags & SLAP_AT_FINAL ) { + /* cannot subtype a "final" attribute type */ + return SLAP_SCHERR_ATTR_BAD_SUP; + } } /* @@ -467,6 +472,9 @@ at_schema_info( Entry *e ) if ( ldap_attributetype2bv( &at->sat_atype, vals ) == NULL ) { return -1; } + + if( at->sat_flags & SLAP_AT_HIDE ) continue; + #if 0 Debug( LDAP_DEBUG_TRACE, "Merging at [%ld] %s\n", (long) vals[0].bv_len, vals[0].bv_val, 0 ); diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 2dfb9be680..03f81b1687 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -110,7 +110,6 @@ int ldbm_modify_internal( #endif rc = modify_replace_values( e, mod, text, textbuf, textlen ); - assert( rc != LDAP_TYPE_OR_VALUE_EXISTS ); if( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, diff --git a/servers/slapd/back-shell/abandon.c b/servers/slapd/back-shell/abandon.c index cae990af5b..3f0f6ed28d 100644 --- a/servers/slapd/back-shell/abandon.c +++ b/servers/slapd/back-shell/abandon.c @@ -38,24 +38,11 @@ shell_back_abandon( break; } } - if( pid == -1 ) { - LDAP_STAILQ_FOREACH( o, &conn->c_pending_ops, o_next ) { - if ( o->o_msgid == msgid ) { - pid = (pid_t) o->o_private; - break; - } - } - } ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + } - if ( pid != -1 ) { - Debug( LDAP_DEBUG_ARGS, "shell killing pid %d\n", - (int) pid, 0, 0 ); - kill( pid, SIGTERM ); - } else { - Debug( LDAP_DEBUG_ARGS, "shell could not find op %d\n", - msgid, 0, 0 ); - } + if ( pid == -1 ) { + Debug( LDAP_DEBUG_ARGS, "shell could not find op %d\n", msgid, 0, 0 ); return 0; } @@ -65,10 +52,9 @@ shell_back_abandon( /* write out the request to the abandon process */ fprintf( wfp, "ABANDON\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %d\n", msgid ); print_suffixes( wfp, be ); - fprintf( wfp, "abandonid: %ld/%d\n", op->o_connid, msgid ); + fprintf( wfp, "pid: %ld\n", (long) pid ); fclose( wfp ); /* no result from abandon */ diff --git a/servers/slapd/back-shell/add.c b/servers/slapd/back-shell/add.c index 134416866b..1d08c0c088 100644 --- a/servers/slapd/back-shell/add.c +++ b/servers/slapd/back-shell/add.c @@ -41,7 +41,6 @@ shell_back_add( /* write out the request to the add process */ fprintf( wfp, "ADD\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); ldap_pvt_thread_mutex_lock( &entry2str_mutex ); diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c index fe36059215..e41c06c1f2 100644 --- a/servers/slapd/back-shell/bind.c +++ b/servers/slapd/back-shell/bind.c @@ -46,7 +46,6 @@ shell_back_bind( /* write out the request to the bind process */ fprintf( wfp, "BIND\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn->bv_val ); diff --git a/servers/slapd/back-shell/compare.c b/servers/slapd/back-shell/compare.c index b5ef2d24eb..4b19e8f374 100644 --- a/servers/slapd/back-shell/compare.c +++ b/servers/slapd/back-shell/compare.c @@ -48,7 +48,6 @@ shell_back_compare( /* write out the request to the compare process */ fprintf( wfp, "COMPARE\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn->bv_val ); diff --git a/servers/slapd/back-shell/delete.c b/servers/slapd/back-shell/delete.c index e675f8062e..6d3b27908d 100644 --- a/servers/slapd/back-shell/delete.c +++ b/servers/slapd/back-shell/delete.c @@ -42,7 +42,6 @@ shell_back_delete( /* write out the request to the delete process */ fprintf( wfp, "DELETE\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn->bv_val ); diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c index 5acddbe994..0b1719eddd 100644 --- a/servers/slapd/back-shell/modify.c +++ b/servers/slapd/back-shell/modify.c @@ -45,7 +45,6 @@ shell_back_modify( /* write out the request to the modify process */ fprintf( wfp, "MODIFY\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn->bv_val ); diff --git a/servers/slapd/back-shell/modrdn.c b/servers/slapd/back-shell/modrdn.c index e2c7d64d5f..68bfed9795 100644 --- a/servers/slapd/back-shell/modrdn.c +++ b/servers/slapd/back-shell/modrdn.c @@ -60,7 +60,6 @@ shell_back_modrdn( /* write out the request to the modrdn process */ fprintf( wfp, "MODRDN\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn->bv_val ); diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c index a1579e20e2..c8c1118172 100644 --- a/servers/slapd/back-shell/search.c +++ b/servers/slapd/back-shell/search.c @@ -51,7 +51,6 @@ shell_back_search( /* write out the request to the search process */ fprintf( wfp, "SEARCH\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "base: %s\n", base->bv_val ); diff --git a/servers/slapd/back-shell/unbind.c b/servers/slapd/back-shell/unbind.c index a4327f99e2..e54173d7ba 100644 --- a/servers/slapd/back-shell/unbind.c +++ b/servers/slapd/back-shell/unbind.c @@ -36,7 +36,6 @@ shell_back_unbind( /* write out the request to the unbind process */ fprintf( wfp, "UNBIND\n" ); - fprintf( wfp, "opid: %ld/%ld\n", op->o_connid, (long) op->o_msgid ); fprintf( wfp, "msgid: %ld\n", (long) op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", (conn->c_dn.bv_len ? conn->c_dn.bv_val : "") ); diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 23a4599f06..d89f9cb21b 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -11,6 +11,7 @@ #include <ac/string.h> #include <ac/ctype.h> +#include <ac/signal.h> #include <ac/socket.h> #include <ac/errno.h> @@ -40,6 +41,7 @@ slap_mask_t global_disallows = 0; slap_mask_t global_requires = 0; slap_ssf_set_t global_ssf_set; char *replogfile; +int global_gentlehup = 0; int global_idletimeout = 0; char *global_host = NULL; char *global_realm = NULL; @@ -1651,7 +1653,6 @@ read_config( const char *fname ) "%s: line %d: old objectclass format not supported.\n", fname, lineno, 0 ); #endif - } /* specify an attribute type */ @@ -2039,6 +2040,22 @@ read_config( const char *fname ) } } +#ifdef SIGHUP + /* turn on/off gentle SIGHUP handling */ + } else if ( strcasecmp( cargv[0], "gentlehup" ) == 0 ) { + if ( cargc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing on|off in \"gentlehup <on|off>\" line\n", + fname, lineno, 0 ); + return( 1 ); + } + if ( strcasecmp( cargv[1], "off" ) == 0 ) { + global_gentlehup = 0; + } else { + global_gentlehup = 1; + } +#endif + /* set idle timeout value */ } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) { int i; diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 2ab0fa769f..3dc4cdbcf1 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -55,12 +55,12 @@ do { if (w) tcp_write( wake_sds[1], "0", 1 ); } while(0) #ifndef HAVE_WINSOCK static #endif -volatile sig_atomic_t slapd_shutdown = 0; +volatile sig_atomic_t slapd_shutdown = 0, slapd_gentle_shutdown = 0; static struct slap_daemon { ldap_pvt_thread_mutex_t sd_mutex; - int sd_nactives; + ber_socket_t sd_nactives; #ifndef HAVE_WINSOCK /* In winsock, accept() returns values higher than dtblsize @@ -192,6 +192,8 @@ static void slapd_add(ber_socket_t s) { } #endif + slap_daemon.sd_nactives++; + FD_SET( s, &slap_daemon.sd_actives ); FD_SET( s, &slap_daemon.sd_readers ); @@ -216,6 +218,8 @@ static void slapd_add(ber_socket_t s) { void slapd_remove(ber_socket_t s, int wake) { ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + slap_daemon.sd_nactives--; + #ifdef NEW_LOGGING LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1, "slapd_remove: removing %ld%s%s\n", @@ -233,7 +237,7 @@ void slapd_remove(ber_socket_t s, int wake) { FD_CLR( s, &slap_daemon.sd_writers ); ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); - WAKE_LISTENER(wake); + WAKE_LISTENER(wake || slapd_gentle_shutdown < 0); } void slapd_clr_write(ber_socket_t s, int wake) { @@ -980,6 +984,34 @@ slapd_daemon_destroy(void) } +static void +close_listeners( + int remove +) +{ + int l; + + for ( l = 0; slap_listeners[l] != NULL; l++ ) { + if ( remove ) + slapd_remove( slap_listeners[l]->sl_sd, 0 ); + if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) { +#ifdef LDAP_PF_LOCAL + if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_LOCAL ) { + unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path ); + } +#endif /* LDAP_PF_LOCAL */ + slapd_close( slap_listeners[l]->sl_sd ); + } + if ( slap_listeners[l]->sl_url ) + free ( slap_listeners[l]->sl_url ); + if ( slap_listeners[l]->sl_name ) + free ( slap_listeners[l]->sl_name ); + free ( slap_listeners[l] ); + slap_listeners[l] = NULL; + } +} + + static void * slapd_daemon_task( void *ptr @@ -1066,6 +1098,26 @@ slapd_daemon_task( } } +#ifdef SIGHUP + if( slapd_gentle_shutdown ) { + ber_socket_t active; + + if( slapd_gentle_shutdown > 0 ) { + Debug( LDAP_DEBUG_ANY, "slapd gentle shutdown\n", 0, 0, 0 ); + close_listeners( 1 ); + slapd_gentle_shutdown = -1; + } + + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + active = slap_daemon.sd_nactives; + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + if( active == 0 ) { + slapd_shutdown = -1; + break; + } + } +#endif + FD_ZERO( &writefds ); FD_ZERO( &readfds ); @@ -1716,21 +1768,8 @@ slapd_daemon_task( #endif } - for ( l = 0; slap_listeners[l] != NULL; l++ ) { - if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) { -#ifdef LDAP_PF_LOCAL - if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_LOCAL ) { - unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path ); - } -#endif /* LDAP_PF_LOCAL */ - slapd_close( slap_listeners[l]->sl_sd ); - } - if ( slap_listeners[l]->sl_url ) - free ( slap_listeners[l]->sl_url ); - if ( slap_listeners[l]->sl_name ) - free ( slap_listeners[l]->sl_name ); - free ( slap_listeners[l] ); - } + if( slapd_gentle_shutdown >= 0 ) + close_listeners ( 0 ); free ( slap_listeners ); slap_listeners = NULL; @@ -1862,6 +1901,11 @@ slap_sig_shutdown( int sig ) 0, 0, 0); #endif else +#endif +#ifdef SIGHUP + if (sig == SIGHUP && global_gentlehup && slapd_gentle_shutdown == 0) + slapd_gentle_shutdown = 1; + else #endif slapd_shutdown = 1; diff --git a/servers/slapd/matchedValues.c b/servers/slapd/matchedValues.c index ac953f111e..56bd29667b 100644 --- a/servers/slapd/matchedValues.c +++ b/servers/slapd/matchedValues.c @@ -23,7 +23,7 @@ static int test_mra_vrFilter( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, MatchingRuleAssertion *mra, char ***e_flags ); @@ -33,7 +33,7 @@ test_substrings_vrFilter( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, ValuesReturnFilter *f, char ***e_flags ); @@ -43,7 +43,7 @@ test_presence_vrFilter( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, AttributeDescription *desc, char ***e_flags ); @@ -53,7 +53,7 @@ test_ava_vrFilter( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, AttributeAssertion *ava, int type, char ***e_flags @@ -65,7 +65,7 @@ filter_matched_values( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, char ***e_flags ) { @@ -108,7 +108,7 @@ filter_matched_values( #else Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 ); #endif - rc = test_ava_vrFilter( be, conn, op, e, f->f_ava, + rc = test_ava_vrFilter( be, conn, op, a, f->f_ava, LDAP_FILTER_EQUALITY, e_flags ); if( rc == -1 ) { return rc; @@ -123,7 +123,7 @@ filter_matched_values( Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 ); #endif - rc = test_substrings_vrFilter( be, conn, op, e, + rc = test_substrings_vrFilter( be, conn, op, a, f, e_flags ); if( rc == -1 ) { return rc; @@ -137,7 +137,7 @@ filter_matched_values( #else Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 ); #endif - rc = test_presence_vrFilter( be, conn, op, e, + rc = test_presence_vrFilter( be, conn, op, a, f->f_desc, e_flags ); if( rc == -1 ) { return rc; @@ -145,7 +145,7 @@ filter_matched_values( break; case LDAP_FILTER_GE: - rc = test_ava_vrFilter( be, conn, op, e, f->f_ava, + rc = test_ava_vrFilter( be, conn, op, a, f->f_ava, LDAP_FILTER_GE, e_flags ); if( rc == -1 ) { return rc; @@ -153,7 +153,7 @@ filter_matched_values( break; case LDAP_FILTER_LE: - rc = test_ava_vrFilter( be, conn, op, e, f->f_ava, + rc = test_ava_vrFilter( be, conn, op, a, f->f_ava, LDAP_FILTER_LE, e_flags ); if( rc == -1 ) { return rc; @@ -167,7 +167,7 @@ filter_matched_values( #else Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 ); #endif - rc = test_mra_vrFilter( be, conn, op, e, + rc = test_mra_vrFilter( be, conn, op, a, f->f_mra, e_flags ); if( rc == -1 ) { return rc; @@ -198,25 +198,18 @@ filter_matched_values( static int test_ava_vrFilter( - Backend *be, + Backend *be, Connection *conn, - Operation *op, - Entry *e, + Operation *op, + Attribute *a, AttributeAssertion *ava, - int type, - char ***e_flags + int type, + char ***e_flags ) { int i, j; - Attribute *a; - - if ( !access_allowed( be, conn, op, e, - ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) ) - { - return LDAP_INSUFFICIENT_ACCESS; - } - for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) { + for ( i=0; a != NULL; a = a->a_next, i++ ) { MatchingRule *mr; struct berval *bv; @@ -287,22 +280,17 @@ test_ava_vrFilter( static int test_presence_vrFilter( - Backend *be, - Connection *conn, - Operation *op, - Entry *e, - AttributeDescription *desc, - char ***e_flags + Backend *be, + Connection *conn, + Operation *op, + Attribute *a, + AttributeDescription *desc, + char ***e_flags ) { int i, j; - Attribute *a; - if ( !access_allowed( be, conn, op, e, desc, NULL, ACL_SEARCH, NULL ) ) { - return LDAP_INSUFFICIENT_ACCESS; - } - - for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) { + for ( i=0; a != NULL; a = a->a_next, i++ ) { struct berval *bv; if ( !is_ad_subtype( a->a_desc, desc ) ) { @@ -318,24 +306,17 @@ test_presence_vrFilter( static int test_substrings_vrFilter( - Backend *be, - Connection *conn, - Operation *op, - Entry *e, - ValuesReturnFilter *f, - char ***e_flags + Backend *be, + Connection *conn, + Operation *op, + Attribute *a, + ValuesReturnFilter *f, + char ***e_flags ) { int i, j; - Attribute *a; - - if ( !access_allowed( be, conn, op, e, - f->f_sub_desc, NULL, ACL_SEARCH, NULL ) ) - { - return LDAP_INSUFFICIENT_ACCESS; - } - for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) { + for ( i=0; a != NULL; a = a->a_next, i++ ) { MatchingRule *mr = a->a_desc->ad_type->sat_substr; struct berval *bv; @@ -373,21 +354,14 @@ static int test_mra_vrFilter( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, MatchingRuleAssertion *mra, char ***e_flags ) { int i, j; - Attribute *a; - - if( !access_allowed( be, conn, op, e, - mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) ) - { - return LDAP_INSUFFICIENT_ACCESS; - } - for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) { + for ( i=0; a != NULL; a = a->a_next, i++ ) { struct berval *bv; if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) { diff --git a/servers/slapd/mr.c b/servers/slapd/mr.c index e1af29d0c8..f8e788b6e0 100644 --- a/servers/slapd/mr.c +++ b/servers/slapd/mr.c @@ -108,7 +108,7 @@ mr_insert( (AVL_DUP) avl_dup_error ) ) { *err = smr->smr_oid; ldap_memfree(mir); - return SLAP_SCHERR_DUP_RULE; + return SLAP_SCHERR_MR_DUP; } /* FIX: temporal consistency check */ mr_bvfind(&mir->mir_name); @@ -125,7 +125,7 @@ mr_insert( (AVL_DUP) avl_dup_error ) ) { *err = *names; ldap_memfree(mir); - return SLAP_SCHERR_DUP_RULE; + return SLAP_SCHERR_MR_DUP; } /* FIX: temporal consistency check */ mr_bvfind(&mir->mir_name); diff --git a/servers/slapd/oc.c b/servers/slapd/oc.c new file mode 100644 index 0000000000..02f6ea4022 --- /dev/null +++ b/servers/slapd/oc.c @@ -0,0 +1,512 @@ +/* oc.c - object class routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "ldap_pvt.h" + +int is_object_subclass( + ObjectClass *sup, + ObjectClass *sub ) +{ + int i; + + if( sub == NULL || sup == NULL ) return 0; + +#if 1 + Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n", + sup->soc_oid, sub->soc_oid, sup == sub ); +#endif + + if( sup == sub ) { + return 1; + } + + if( sub->soc_sups == NULL ) { + return 0; + } + + for( i=0; sub->soc_sups[i] != NULL; i++ ) { + if( is_object_subclass( sup, sub->soc_sups[i] ) ) { + return 1; + } + } + + return 0; +} + +int is_entry_objectclass( + Entry* e, + ObjectClass *oc, + int set_flags ) +{ + Attribute *attr; + struct berval *bv; + AttributeDescription *objectClass = slap_schema.si_ad_objectClass; + assert(!( e == NULL || oc == NULL )); + + if( e == NULL || oc == NULL ) { + return 0; + } + + if( set_flags && ( e->e_ocflags & SLAP_OC__END )) { + return (e->e_ocflags & oc->soc_flags) ? 1 : 0; + } + + /* + * find objectClass attribute + */ + attr = attr_find(e->e_attrs, objectClass); + + if( attr == NULL ) { + /* no objectClass attribute */ +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, "is_entry_objectclass: " + "dn(%s), oid (%s), no objectClass attribute.\n", + e->e_dn == NULL ? "" : e->e_dn, + oc->soc_oclass.oc_oid )); +#else + Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") " + "no objectClass attribute\n", + e->e_dn == NULL ? "" : e->e_dn, + oc->soc_oclass.oc_oid, 0 ); +#endif + + return 0; + } + + for( bv=attr->a_vals; bv->bv_val; bv++ ) { + ObjectClass *objectClass = oc_bvfind( bv ); + + if ( objectClass == oc && !set_flags ) { + return 1; + } + + if ( objectClass != NULL ) { + e->e_ocflags |= objectClass->soc_flags; + } + } + e->e_ocflags |= SLAP_OC__END; /* We've finished this */ + + return (e->e_ocflags & oc->soc_flags); +} + + +struct oindexrec { + struct berval oir_name; + ObjectClass *oir_oc; +}; + +static Avlnode *oc_index = NULL; +static ObjectClass *oc_list = NULL; + +static int +oc_index_cmp( + struct oindexrec *oir1, + struct oindexrec *oir2 ) +{ + int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len; + if (i) + return i; + return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val ); +} + +static int +oc_index_name_cmp( + struct berval *name, + struct oindexrec *oir ) +{ + int i = name->bv_len - oir->oir_name.bv_len; + if (i) + return i; + return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len ); +} + +ObjectClass * +oc_find( const char *ocname ) +{ + struct berval bv; + + bv.bv_val = (char *)ocname; + bv.bv_len = strlen( ocname ); + + return( oc_bvfind( &bv ) ); +} + +ObjectClass * +oc_bvfind( struct berval *ocname ) +{ + struct oindexrec *oir; + + oir = (struct oindexrec *) avl_find( oc_index, ocname, + (AVL_CMP) oc_index_name_cmp ); + + if ( oir != NULL ) { + return( oir->oir_oc ); + } + + return( NULL ); +} + +static int +oc_create_required( + ObjectClass *soc, + char **attrs, + int *op, + const char **err ) +{ + char **attrs1; + AttributeType *sat; + AttributeType **satp; + int i; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + + if( is_at_operational( sat )) (*op)++; + + if ( at_find_in_list(sat, soc->soc_required) < 0) { + if ( at_append_to_list(sat, &soc->soc_required) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } + attrs1++; + } + /* Now delete duplicates from the allowed list */ + for ( satp = soc->soc_required; *satp; satp++ ) { + i = at_find_in_list(*satp,soc->soc_allowed); + if ( i >= 0 ) { + at_delete_from_list(i, &soc->soc_allowed); + } + } + } + return 0; +} + +static int +oc_create_allowed( + ObjectClass *soc, + char **attrs, + int *op, + const char **err ) +{ + char **attrs1; + AttributeType *sat; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + + if( is_at_operational( sat )) (*op)++; + + if ( at_find_in_list(sat, soc->soc_required) < 0 && + at_find_in_list(sat, soc->soc_allowed) < 0 ) { + if ( at_append_to_list(sat, &soc->soc_allowed) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } + attrs1++; + } + } + return 0; +} + +static int +oc_add_sups( + ObjectClass *soc, + char **sups, + int *op, + const char **err ) +{ + int code; + ObjectClass *soc1; + int nsups; + char **sups1; + int add_sups = 0; + + if ( sups ) { + if ( !soc->soc_sups ) { + /* We are at the first recursive level */ + add_sups = 1; + nsups = 1; + sups1 = sups; + while ( *sups1 ) { + nsups++; + sups1++; + } + soc->soc_sups = (ObjectClass **)ch_calloc(nsups, + sizeof(ObjectClass *)); + } + + nsups = 0; + sups1 = sups; + while ( *sups1 ) { + soc1 = oc_find(*sups1); + if ( !soc1 ) { + *err = *sups1; + return SLAP_SCHERR_CLASS_NOT_FOUND; + } + + /* check object class usage + * abstract classes can only sup abstract classes + * structural classes can not sup auxiliary classes + * auxiliary classes can not sup structural classes + */ + if( soc->soc_kind != soc1->soc_kind + && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT ) + { + *err = *sups1; + return SLAP_SCHERR_CLASS_BAD_USAGE; + } + + if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++; + + if ( add_sups ) { + soc->soc_sups[nsups] = soc1; + } + + code = oc_add_sups( soc, soc1->soc_sup_oids, op, err ); + if ( code ) return code; + + code = oc_create_required( soc, soc1->soc_at_oids_must, op, err ); + if ( code ) return code; + + code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err ); + if ( code ) return code; + + nsups++; + sups1++; + } + } + + return 0; +} + +void +oc_destroy( void ) +{ + ObjectClass *o, *n; + + avl_free(oc_index, ldap_memfree); + for (o=oc_list; o; o=n) + { + n = o->soc_next; + if (o->soc_sups) ldap_memfree(o->soc_sups); + if (o->soc_required) ldap_memfree(o->soc_required); + if (o->soc_allowed) ldap_memfree(o->soc_allowed); + ldap_objectclass_free((LDAPObjectClass *)o); + } +} + +static int +oc_insert( + ObjectClass *soc, + const char **err +) +{ + ObjectClass **ocp; + struct oindexrec *oir; + char **names; + + ocp = &oc_list; + while ( *ocp != NULL ) { + ocp = &(*ocp)->soc_next; + } + *ocp = soc; + + if ( soc->soc_oid ) { + oir = (struct oindexrec *) + ch_calloc( 1, sizeof(struct oindexrec) ); + oir->oir_name.bv_val = soc->soc_oid; + oir->oir_name.bv_len = strlen( soc->soc_oid ); + oir->oir_oc = soc; + + assert( oir->oir_name.bv_val ); + assert( oir->oir_oc ); + + if ( avl_insert( &oc_index, (caddr_t) oir, + (AVL_CMP) oc_index_cmp, + (AVL_DUP) avl_dup_error ) ) + { + *err = soc->soc_oid; + ldap_memfree(oir); + return SLAP_SCHERR_CLASS_DUP; + } + + /* FIX: temporal consistency check */ + assert( oc_bvfind(&oir->oir_name) != NULL ); + } + + if ( (names = soc->soc_names) ) { + while ( *names ) { + oir = (struct oindexrec *) + ch_calloc( 1, sizeof(struct oindexrec) ); + oir->oir_name.bv_val = *names; + oir->oir_name.bv_len = strlen( *names ); + oir->oir_oc = soc; + + assert( oir->oir_name.bv_val ); + assert( oir->oir_oc ); + + if ( avl_insert( &oc_index, (caddr_t) oir, + (AVL_CMP) oc_index_cmp, + (AVL_DUP) avl_dup_error ) ) + { + *err = *names; + ldap_memfree(oir); + return SLAP_SCHERR_CLASS_DUP; + } + + /* FIX: temporal consistency check */ + assert( oc_bvfind(&oir->oir_name) != NULL ); + + names++; + } + } + + return 0; +} + +int +oc_add( + LDAPObjectClass *oc, + int user, + const char **err +) +{ + ObjectClass *soc; + int code; + int op = 0; + + if ( oc->oc_names != NULL ) { + int i; + + for( i=0; oc->oc_names[i]; i++ ) { + if( !slap_valid_descr( oc->oc_names[i] ) ) { + return SLAP_SCHERR_BAD_DESCR; + } + } + } + + if ( !OID_LEADCHAR( oc->oc_oid[0] )) { + /* Expand OID macros */ + char *oid = oidm_find( oc->oc_oid ); + if ( !oid ) { + *err = oc->oc_oid; + return SLAP_SCHERR_OIDM; + } + if ( oid != oc->oc_oid ) { + ldap_memfree( oc->oc_oid ); + oc->oc_oid = oid; + } + } + + soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) ); + AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) ); + + if( soc->soc_sup_oids == NULL && + soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) + { + /* structural object classes implicitly inherit from 'top' */ + static char *top_oids[] = { SLAPD_TOP_OID, NULL }; + code = oc_add_sups( soc, top_oids, &op, err ); + } else { + code = oc_add_sups( soc, soc->soc_sup_oids, &op, err ); + } + + if ( code != 0 ) return code; + + code = oc_create_required( soc, soc->soc_at_oids_must, &op, err ); + if ( code != 0 ) return code; + + code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err ); + if ( code != 0 ) return code; + + if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP; + + code = oc_insert(soc,err); + return code; +} + +#ifdef LDAP_DEBUG + +static void +oc_print( ObjectClass *oc ) +{ + int i; + const char *mid; + + printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) ); + if ( oc->soc_required != NULL ) { + mid = "\trequires "; + for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," ) + printf( "%s%s", mid, + ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) ); + printf( "\n" ); + } + if ( oc->soc_allowed != NULL ) { + mid = "\tallows "; + for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," ) + printf( "%s%s", mid, + ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) ); + printf( "\n" ); + } +} + +#endif + + +#if defined( SLAPD_SCHEMA_DN ) + +int +oc_schema_info( Entry *e ) +{ + struct berval vals[2]; + ObjectClass *oc; + + AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses; + + vals[1].bv_val = NULL; + + for ( oc = oc_list; oc; oc = oc->soc_next ) { + if ( ldap_objectclass2bv( &oc->soc_oclass, vals ) == NULL ) { + return -1; + } + + if( oc->soc_flags & SLAP_OC_HIDE ) continue; + +#if 0 + Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n", + (long) vals[0].bv_len, vals[0].bv_val, 0 ); +#endif + attr_merge( e, ad_objectClasses, vals ); + ldap_memfree( vals[0].bv_val ); + } + return 0; +} + +#endif diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c index 3a8ddd9c1d..94cbeac0cf 100644 --- a/servers/slapd/passwd.c +++ b/servers/slapd/passwd.c @@ -321,13 +321,17 @@ slap_passwd_hash( #endif tmp = lutil_passwd_hash( cred , hash ); - assert( tmp != NULL ); #if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) ldap_pvt_thread_mutex_unlock( &passwd_mutex ); #endif + + if( tmp == NULL ) { + new->bv_len = 0; + new->bv_val = NULL; + } + *new = *tmp; free( tmp ); - return; } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 7b2a65a980..f80e53969a 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -526,7 +526,7 @@ LDAP_SLAPD_F (int) filter_matched_values( Backend *be, Connection *conn, Operation *op, - Entry *e, + Attribute *a, char ***e_flags ); /* @@ -626,6 +626,7 @@ LDAP_SLAPD_F (void) mra_free LDAP_P(( /* oc.c */ LDAP_SLAPD_F (int) oc_add LDAP_P(( LDAPObjectClass *oc, + int user, const char **err)); LDAP_SLAPD_F (void) oc_destroy LDAP_P(( void )); @@ -1016,6 +1017,7 @@ LDAP_SLAPD_V (const char) Versionstr[]; LDAP_SLAPD_V (struct slap_limits_set) deflimit; LDAP_SLAPD_V (slap_access_t) global_default_access; +LDAP_SLAPD_V (int) global_gentlehup; LDAP_SLAPD_V (int) global_idletimeout; LDAP_SLAPD_V (int) global_schemacheck; LDAP_SLAPD_V (char *) global_host; diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 83906f6418..140e4a6d6c 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -744,9 +744,9 @@ send_search_entry( e_flags[i] = a_flags; } - if ( op->vrFilter != NULL ){ + if ( op->vrFilter != NULL ){ - rc = filter_matched_values(be, conn, op, e, &e_flags) ; + rc = filter_matched_values(be, conn, op, e->e_attrs, &e_flags) ; if ( rc == -1 ) { #ifdef NEW_LOGGING @@ -917,8 +917,51 @@ send_search_entry( /* eventually will loop through generated operational attributes */ /* only have subschemaSubentry implemented */ aa = backend_operational( be, conn, op, e, attrs, opattrs ); + + for ( a = aa, i=0; a != NULL; a = a->a_next ) i++; + e_flags = ch_malloc ( i * sizeof(a_flags) ); - for (a = aa ; a != NULL; a = a->a_next ) { + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ); + + a_flags = ch_calloc ( j, sizeof(char) ); + /* If no ValuesReturnFilter control return everything */ + if ( op->vrFilter == NULL ){ + memset(a_flags, 1, j); + } + e_flags[i] = a_flags; + } + + if ( op->vrFilter != NULL ){ + + rc = filter_matched_values(be, conn, op, aa, &e_flags) ; + + if ( rc == -1 ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ERR, + "send_search_entry: conn %lu " + "matched values filtering failed\n", + conn ? conn->c_connid : 0 )); +#else + Debug( LDAP_DEBUG_ANY, + "matched values filtering failed\n", 0, 0, 0 ); +#endif + ber_free( ber, 1 ); + + /* free e_flags */ + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + free( e_flags[i] ); + } + free( e_flags ); + + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "matched values filtering error", + NULL, NULL ); + goto error_return; + } + } + + for (a = aa, j=0; a != NULL; a = a->a_next, j++ ) { AttributeDescription *desc = a->a_desc; if ( attrs == NULL ) { @@ -974,6 +1017,12 @@ send_search_entry( ber_free_buf( ber ); send_ldap_result( conn, op, LDAP_OTHER, NULL, "encoding description error", NULL, NULL ); + /* free e_flags */ + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + free( e_flags[i] ); + } + free( e_flags ); + attrs_free( aa ); goto error_return; } @@ -1000,6 +1049,10 @@ send_search_entry( continue; } + if ( e_flags[j][i] == 0 ){ + continue; + } + if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ERR, @@ -1016,6 +1069,12 @@ send_search_entry( send_ldap_result( conn, op, LDAP_OTHER, NULL, "encoding values error", NULL, NULL ); + /* free e_flags */ + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + free( e_flags[i] ); + } + free( e_flags ); + attrs_free( aa ); goto error_return; } @@ -1035,13 +1094,24 @@ send_search_entry( ber_free_buf( ber ); send_ldap_result( conn, op, LDAP_OTHER, NULL, "encode end error", NULL, NULL ); + /* free e_flags */ + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + free( e_flags[i] ); + } + free( e_flags ); + attrs_free( aa ); goto error_return; } } - attrs_free( aa ); + /* free e_flags */ + for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) { + free( e_flags[i] ); + } + free( e_flags ); + attrs_free( aa ); rc = ber_printf( ber, /*{{{*/ "}N}N}" ); #ifdef LDAP_CONNECTIONLESS diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 33d11278f7..184aad8d15 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -162,28 +162,29 @@ static struct slap_schema_oc_map { "NAME 'extensibleObject' " "DESC 'RFC2252: extensible object' " "SUP top AUXILIARY )", - 0, 0, offsetof(struct slap_internal_schema, si_oc_extensibleObject) }, + 0, SLAP_OC_OPERATIONAL, + offsetof(struct slap_internal_schema, si_oc_extensibleObject) }, { "alias", "( 2.5.6.1 NAME 'alias' " "DESC 'RFC2256: an alias' " "SUP top STRUCTURAL " "MUST aliasedObjectName )", - aliasObjectClass, SLAP_OC_ALIAS, + aliasObjectClass, SLAP_OC_ALIAS|SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_alias) }, { "referral", "( 2.16.840.1.113730.3.2.6 NAME 'referral' " "DESC 'namedref: named subordinate referral' " "SUP top STRUCTURAL MUST ref )", - referralObjectClass, SLAP_OC_REFERRAL, + referralObjectClass, SLAP_OC_REFERRAL|SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_referral) }, { "LDAProotDSE", "( 1.3.6.1.4.1.4203.1.4.1 " "NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' ) " "DESC 'OpenLDAP Root DSE object' " "SUP top STRUCTURAL MAY cn )", - rootDseObjectClass, 0, + rootDseObjectClass, SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_rootdse) }, { "subentry", "( 2.5.20.0 NAME 'subentry' " "SUP top STRUCTURAL " "MUST ( cn $ subtreeSpecification ) )", - subentryObjectClass, SLAP_OC_SUBENTRY, + subentryObjectClass, SLAP_OC_SUBENTRY|SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_subentry) }, { "subschema", "( 2.5.20.1 NAME 'subschema' " "DESC 'RFC2252: controlling subschema (sub)entry' " @@ -191,13 +192,14 @@ static struct slap_schema_oc_map { "MAY ( dITStructureRules $ nameForms $ ditContentRules $ " "objectClasses $ attributeTypes $ matchingRules $ " "matchingRuleUse ) )", - subentryObjectClass, 0, + subentryObjectClass, SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_subschema) }, { "monitor", "( 1.3.6.1.4.1.4203.666.3.2 NAME 'monitor' " "DESC 'OpenLDAP system monitoring' " "STRUCTURAL " "MUST cn )", - 0, 0, offsetof(struct slap_internal_schema, si_oc_monitor) }, + 0, SLAP_OC_OPERATIONAL, + offsetof(struct slap_internal_schema, si_oc_monitor) }, { NULL, NULL, NULL, 0, 0 } }; @@ -222,7 +224,7 @@ static struct slap_schema_ad_map { "DESC 'RFC2256: object classes of the entity' " "EQUALITY objectIdentifierMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", - NULL, 0, objectClassMatch, NULL, NULL, + NULL, SLAP_AT_FINAL, objectClassMatch, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_objectClass) }, /* user entry operational attributes */ @@ -278,6 +280,21 @@ static struct slap_schema_ad_map { NULL, 0, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_subschemaSubentry) }, + { "entryUUID", "( 1.3.6.1.4.1.4203.666.1.6 NAME 'entryUUID' " + "DESC 'LCUP/LDUP: universally unique identifier' " + "EQUALITY octetStringMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} " + "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", + NULL, SLAP_AT_HIDE, NULL, NULL, NULL, + offsetof(struct slap_internal_schema, si_ad_entryUUID) }, + { "entryCSN", "( 1.3.6.1.4.1.4203.666.1.7 NAME 'entryCSN' " + "DESC 'LCUP/LDUP: change sequence number' " + "EQUALITY octetStringMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} " + "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", + NULL, SLAP_AT_HIDE, NULL, NULL, NULL, + offsetof(struct slap_internal_schema, si_ad_entryCSN) }, + /* root DSE attributes */ { "altServer", "( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' " "DESC 'RFC2252: alternative servers' " @@ -344,13 +361,13 @@ static struct slap_schema_ad_map { "EQUALITY objectIdentifierMatch " "USAGE directoryOperation " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", - administrativeRoleAttribute, 0, NULL, NULL, NULL, + administrativeRoleAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_administrativeRole) }, { "subtreeSpecification", "( 2.5.18.6 NAME 'subtreeSpecification' " "SINGLE-VALUE " "USAGE directoryOperation " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 )", - subentryAttribute, 0, NULL, NULL, NULL, + subentryAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_subtreeSpecification) }, /* subschema subentry attributes */ @@ -359,13 +376,13 @@ static struct slap_schema_ad_map { "EQUALITY integerFirstComponentMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 " "USAGE directoryOperation ) ", - subentryAttribute, 0, NULL, NULL, NULL, + subentryAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_ditStructureRules) }, { "ditContentRules", "( 2.5.21.2 NAME 'dITContentRules' " "DESC 'RFC2252: DIT content rules' " "EQUALITY objectIdentifierFirstComponentMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )", - subentryAttribute, 0, NULL, NULL, NULL, + subentryAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_ditContentRules) }, { "matchingRules", "( 2.5.21.4 NAME 'matchingRules' " "DESC 'RFC2252: matching rules' " @@ -389,13 +406,13 @@ static struct slap_schema_ad_map { "DESC 'RFC2252: name forms ' " "EQUALITY objectIdentifierFirstComponentMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )", - subentryAttribute, 0, NULL, NULL, NULL, + subentryAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_nameForms) }, { "matchingRuleUse", "( 2.5.21.8 NAME 'matchingRuleUse' " "DESC 'RFC2252: matching rule uses' " "EQUALITY objectIdentifierFirstComponentMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )", - subentryAttribute, 0, NULL, NULL, NULL, + subentryAttribute, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_matchingRuleUse) }, { "ldapSyntaxes", "( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' " @@ -411,7 +428,7 @@ static struct slap_schema_ad_map { "DESC 'RFC2256: name of aliased object' " "EQUALITY distinguishedNameMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )", - aliasAttribute, 0, NULL, NULL, NULL, + aliasAttribute, SLAP_AT_FINAL, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_aliasedObjectName) }, { "ref", "( 2.16.840.1.113730.3.1.34 NAME 'ref' " "DESC 'namedref: subordinate referral URL' " @@ -427,14 +444,14 @@ static struct slap_schema_ad_map { "DESC 'OpenLDAP ACL entry pseudo-attribute' " "SYNTAX 1.3.6.1.4.1.4203.1.1.1 " "SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_entry) }, { "children", "( 1.3.6.1.4.1.4203.1.3.2 " "NAME 'children' " "DESC 'OpenLDAP ACL children pseudo-attribute' " "SYNTAX 1.3.6.1.4.1.4203.1.1.1 " "SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_HIDE, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_children) }, #ifdef SLAPD_ACI_ENABLED @@ -453,14 +470,14 @@ static struct slap_schema_ad_map { "DESC 'RFC2256: common supertype of DN attributes' " "EQUALITY distinguishedNameMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_ABSTRACT, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_distinguishedName) }, { "name", "( 2.5.4.41 NAME 'name' " "DESC 'RFC2256: common supertype of name attributes' " "EQUALITY caseIgnoreMatch " "SUBSTR caseIgnoreSubstringsMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )", - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_ABSTRACT, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_name) }, { "cn", "( 2.5.4.3 NAME ( 'cn' 'commonName' ) " "DESC 'RFC2256: common name(s) for which the entity is known by' " @@ -471,7 +488,7 @@ static struct slap_schema_ad_map { "DESC 'RFC2256/2307: password of user' " "EQUALITY octetStringMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )", - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_FINAL, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_userPassword) }, #ifdef SLAPD_AUTHPASSWD @@ -480,7 +497,7 @@ static struct slap_schema_ad_map { "DESC 'RFC3112: authentication password attribute' " "EQUALITY 1.3.6.1.4.1.4203.1.2.2 " "SYNTAX 1.3.6.1.4.1.4203.1.1.2 )", - NULL, 0, + NULL, SLAP_AT_FINAL, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_authPassword) }, { "supportedAuthPasswordSchemes", "( 1.3.6.1.4.1.4203.1.3.3 " @@ -494,7 +511,7 @@ static struct slap_schema_ad_map { #endif #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND { "krbName", NULL, - NULL, 0, NULL, NULL, NULL, + NULL, SLAP_AT_FINAL, NULL, NULL, NULL, offsetof(struct slap_internal_schema, si_ad_krbName) }, #endif @@ -510,7 +527,8 @@ static AttributeType slap_at_undefined = { NULL, /* subtypes */ NULL, NULL, NULL, NULL, /* matching rules */ NULL, /* syntax (this may need to be defined) */ - (AttributeTypeSchemaCheckFN *) 0, 0, /* schema check function/mask */ + (AttributeTypeSchemaCheckFN *) 0, /* schema check function */ + SLAP_AT_ABSTRACT|SLAP_AT_FINAL, /* mask */ NULL, /* next */ NULL /* attribute description */ /* mutex (don't know how to initialize it :) */ @@ -663,7 +681,7 @@ slap_schema_load( void ) return LDAP_OTHER; } - code = oc_add(oc,&err); + code = oc_add(oc,0,&err); if ( code ) { fprintf( stderr, "slap_schema_load: " "%s: %s: \"%s\"\n", diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c index 171bd3473e..10e92f827c 100644 --- a/servers/slapd/schemaparse.c +++ b/servers/slapd/schemaparse.c @@ -21,22 +21,23 @@ int global_schemacheck = 1; /* schemacheck ON is default */ static void oc_usage(void); static void at_usage(void); -static char *const err2text[SLAP_SCHERR_LAST+1] = { - "Success", +static char *const err2text[] = { "Out of memory", "ObjectClass not found", "ObjectClass inappropriate SUPerior", + "ObjectClass operational", + "Duplicate objectClass", "AttributeType not found", "AttributeType inappropriate USAGE", - "Duplicate objectClass", + "AttributeType inappropriate SUPerior", + "AttributeType SYNTAX or SUPerior required", "Duplicate attributeType", - "Duplicate ldapSyntax", - "Duplicate matchingRule", - "OID or name required", - "SYNTAX or SUPerior required", "MatchingRule not found", + "Duplicate matchingRule", "Syntax not found", "Syntax required", + "Duplicate ldapSyntax", + "OID or name required", "Qualifier not supported", "Invalid NAME", "OID could not be expanded" @@ -45,7 +46,7 @@ static char *const err2text[SLAP_SCHERR_LAST+1] = { char * scherr2str(int code) { - if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { + if ( code < 0 || SLAP_SCHERR_LAST < code ) { return "Unknown error"; } else { return err2text[code]; @@ -118,7 +119,7 @@ parse_oc( return 1; } - code = oc_add(oc,&err); + code = oc_add(oc,1,&err); if ( code ) { fprintf( stderr, "%s: line %d: %s: \"%s\"\n", fname, lineno, scherr2str(code), err); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 62ddc37bcc..1437f35cc4 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -218,24 +218,26 @@ typedef struct slap_ssf_set { /* * represents schema information for a database */ -#define SLAP_SCHERR_OUTOFMEM 1 -#define SLAP_SCHERR_CLASS_NOT_FOUND 2 -#define SLAP_SCHERR_CLASS_BAD_USAGE 3 -#define SLAP_SCHERR_ATTR_NOT_FOUND 4 -#define SLAP_SCHERR_ATTR_BAD_USAGE 5 -#define SLAP_SCHERR_DUP_CLASS 6 -#define SLAP_SCHERR_DUP_ATTR 7 -#define SLAP_SCHERR_DUP_SYNTAX 8 -#define SLAP_SCHERR_DUP_RULE 9 -#define SLAP_SCHERR_NO_NAME 10 -#define SLAP_SCHERR_ATTR_INCOMPLETE 11 -#define SLAP_SCHERR_MR_NOT_FOUND 12 -#define SLAP_SCHERR_SYN_NOT_FOUND 13 -#define SLAP_SCHERR_MR_INCOMPLETE 14 -#define SLAP_SCHERR_NOT_SUPPORTED 15 -#define SLAP_SCHERR_BAD_DESCR 16 -#define SLAP_SCHERR_OIDM 17 -#define SLAP_SCHERR_LAST SLAP_SCHERR_OIDM +#define SLAP_SCHERR_OUTOFMEM 1 +#define SLAP_SCHERR_CLASS_NOT_FOUND 2 +#define SLAP_SCHERR_CLASS_BAD_USAGE 3 +#define SLAP_SCHERR_CLASS_BAD_SUP 4 +#define SLAP_SCHERR_CLASS_DUP 5 +#define SLAP_SCHERR_ATTR_NOT_FOUND 6 +#define SLAP_SCHERR_ATTR_BAD_USAGE 7 +#define SLAP_SCHERR_ATTR_BAD_SUP 8 +#define SLAP_SCHERR_ATTR_INCOMPLETE 9 +#define SLAP_SCHERR_ATTR_DUP 10 +#define SLAP_SCHERR_MR_NOT_FOUND 11 +#define SLAP_SCHERR_MR_INCOMPLETE 12 +#define SLAP_SCHERR_MR_DUP 13 +#define SLAP_SCHERR_SYN_NOT_FOUND 14 +#define SLAP_SCHERR_SYN_DUP 15 +#define SLAP_SCHERR_NO_NAME 16 +#define SLAP_SCHERR_NOT_SUPPORTED 17 +#define SLAP_SCHERR_BAD_DESCR 18 +#define SLAP_SCHERR_OIDM 19 +#define SLAP_SCHERR_LAST SLAP_SCHERR_OIDM typedef union slap_sockaddr { struct sockaddr sa_addr; @@ -431,6 +433,11 @@ typedef struct slap_attribute_type { Syntax *sat_syntax; AttributeTypeSchemaCheckFN *sat_check; + +#define SLAP_AT_NONE 0x0000U +#define SLAP_AT_ABSTRACT 0x0100U /* cannot be instantiated */ +#define SLAP_AT_FINAL 0x0200U /* cannot be subtyped */ +#define SLAP_AT_HIDE 0x8000U /* hide attribute */ slap_mask_t sat_flags; struct slap_attribute_type *sat_next; @@ -489,13 +496,15 @@ typedef struct slap_object_class { struct slap_object_class *soc_next; } ObjectClass; -#define SLAP_OC_ALIAS 0x01 -#define SLAP_OC_REFERRAL 0x02 -#define SLAP_OC_SUBENTRY 0x04 -#define SLAP_OC_DYNAMICOBJECT 0x08 -#define SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY 0x10 -#define SLAP_OC__MASK 0x1F -#define SLAP_OC__END 0x20 +#define SLAP_OC_ALIAS 0x0001 +#define SLAP_OC_REFERRAL 0x0002 +#define SLAP_OC_SUBENTRY 0x0004 +#define SLAP_OC_DYNAMICOBJECT 0x0008 +#define SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY 0x0010 +#define SLAP_OC__MASK 0x001F +#define SLAP_OC__END 0x0020 +#define SLAP_OC_OPERATIONAL 0x4000 +#define SLAP_OC_HIDE 0x8000 #ifdef LDAP_EXTENDED_SCHEMA /* diff --git a/servers/slapd/syntax.c b/servers/slapd/syntax.c new file mode 100644 index 0000000000..eea2e1b110 --- /dev/null +++ b/servers/slapd/syntax.c @@ -0,0 +1,240 @@ +/* syntax.c - routines to manage syntax definitions */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "ldap_pvt.h" + + +struct sindexrec { + char *sir_name; + Syntax *sir_syn; +}; + +static Avlnode *syn_index = NULL; +static Syntax *syn_list = NULL; + +static int +syn_index_cmp( + struct sindexrec *sir1, + struct sindexrec *sir2 +) +{ + return (strcmp( sir1->sir_name, sir2->sir_name )); +} + +static int +syn_index_name_cmp( + const char *name, + struct sindexrec *sir +) +{ + return (strcmp( name, sir->sir_name )); +} + +Syntax * +syn_find( const char *synname ) +{ + struct sindexrec *sir = NULL; + + if ( (sir = (struct sindexrec *) avl_find( syn_index, synname, + (AVL_CMP) syn_index_name_cmp )) != NULL ) { + return( sir->sir_syn ); + } + return( NULL ); +} + +Syntax * +syn_find_desc( const char *syndesc, int *len ) +{ + Syntax *synp; + + for (synp = syn_list; synp; synp = synp->ssyn_next) + if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{'))) + return synp; + return( NULL ); +} + +void +syn_destroy( void ) +{ + Syntax *s, *n; + + avl_free(syn_index, ldap_memfree); + for (s=syn_list; s; s=n) { + n = s->ssyn_next; + ldap_syntax_free((LDAPSyntax *)s); + } +} + +static int +syn_insert( + Syntax *ssyn, + const char **err +) +{ + Syntax **synp; + struct sindexrec *sir; + + synp = &syn_list; + while ( *synp != NULL ) { + synp = &(*synp)->ssyn_next; + } + *synp = ssyn; + + if ( ssyn->ssyn_oid ) { + sir = (struct sindexrec *) + ch_calloc( 1, sizeof(struct sindexrec) ); + sir->sir_name = ssyn->ssyn_oid; + sir->sir_syn = ssyn; + if ( avl_insert( &syn_index, (caddr_t) sir, + (AVL_CMP) syn_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = ssyn->ssyn_oid; + ldap_memfree(sir); + return SLAP_SCHERR_SYN_DUP; + } + /* FIX: temporal consistency check */ + syn_find(sir->sir_name); + } + return 0; +} + +int +syn_add( + LDAPSyntax *syn, + unsigned flags, + slap_syntax_validate_func *validate, + slap_syntax_transform_func *normalize, + slap_syntax_transform_func *pretty, +#ifdef SLAPD_BINARY_CONVERSION + slap_syntax_transform_func *ber2str, + slap_syntax_transform_func *str2ber, +#endif + const char **err +) +{ + Syntax *ssyn; + int code; + + ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) ); + + AC_MEMCPY( &ssyn->ssyn_syn, syn, sizeof(LDAPSyntax) ); + + ssyn->ssyn_next = NULL; + + ssyn->ssyn_oidlen = strlen(syn->syn_oid); + ssyn->ssyn_flags = flags; + ssyn->ssyn_validate = validate; + ssyn->ssyn_normalize = normalize; + ssyn->ssyn_pretty = pretty; + +#ifdef SLAPD_BINARY_CONVERSION + ssyn->ssyn_ber2str = ber2str; + ssyn->ssyn_str2ber = str2ber; +#endif + + code = syn_insert(ssyn, err); + return code; +} + +int +register_syntax( + const char * desc, + unsigned flags, + slap_syntax_validate_func *validate, + slap_syntax_transform_func *normalize, + slap_syntax_transform_func *pretty ) +{ + LDAPSyntax *syn; + int code; + const char *err; + + syn = ldap_str2syntax( desc, &code, &err, LDAP_SCHEMA_ALLOW_ALL); + if ( !syn ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "schema", LDAP_LEVEL_ERR, + "register_syntax: Error - %s before %s in %s.\n", + ldap_scherr2str(code), err, desc )); +#else + Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n", + ldap_scherr2str(code), err, desc ); +#endif + + return( -1 ); + } + + code = syn_add( syn, flags, validate, normalize, pretty, &err ); + + ldap_memfree( syn ); + + if ( code ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "schema", LDAP_LEVEL_ERR, + "register_syntax: Error - %s %s in %s\n", + scherr2str(code), err, desc )); +#else + Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n", + scherr2str(code), err, desc ); +#endif + + return( -1 ); + } + + return( 0 ); +} + +#if defined( SLAPD_SCHEMA_DN ) + +int +syn_schema_info( Entry *e ) +{ + struct berval vals[2]; + Syntax *syn; + + AttributeDescription *ad_ldapSyntaxes = slap_schema.si_ad_ldapSyntaxes; + + vals[1].bv_val = NULL; + + for ( syn = syn_list; syn; syn = syn->ssyn_next ) { + if ( ! syn->ssyn_validate ) { + /* skip syntaxes without validators */ + continue; + } + if ( syn->ssyn_flags & SLAP_SYNTAX_HIDE ) { + /* hide syntaxes */ + continue; + } + + if ( ldap_syntax2bv( &syn->ssyn_syn, vals ) == NULL ) { + return -1; + } +#if 0 +#ifdef NEW_LOGGING + LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY, + "syn_schema_info: Merging syn [%ld] %s\n", + (long)vals[0].bv_len, vals[0].bv_val )); +#else + Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n", + (long) vals[0].bv_len, vals[0].bv_val, 0 ); +#endif + +#endif + attr_merge( e, ad_ldapSyntaxes, vals ); + ldap_memfree( vals[0].bv_val ); + } + return 0; +} + +#endif -- GitLab