From: Kurt Zeilenga Date: Wed, 8 Dec 1999 04:37:59 +0000 (+0000) Subject: Reengineered ldappasswd(1). Uses extended operation to set X-Git-Tag: UCDATA_2_4~130 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=d5edb4bff62150cf35e8b9c59798017ff58febc0;p=openldap Reengineered ldappasswd(1). Uses extended operation to set user password. Likely to be modified to use bind control instead. Use of modify deprecated in favor mechanisms that support passwords stored externally to the directory (such as in a SASL service). Modified slapd extended operation infrastructure to support backend provided extended operations. --- diff --git a/clients/tools/ldappasswd.c b/clients/tools/ldappasswd.c index c6cc0bce18..c8337121ba 100644 --- a/clients/tools/ldappasswd.c +++ b/clients/tools/ldappasswd.c @@ -3,20 +3,6 @@ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ -/* - * Copyright 1998, David E. Storey, All rights reserved. - * This software is not subject to any license of The Murphy Group, Inc. - * or George Mason University. - * - * Redistribution and use in source and binary forms are permitted only - * as authorized by the OpenLDAP Public License. A copy of this - * license is available at http://www.OpenLDAP.org/license.html or - * in file LICENSE in the top-level directory of the distribution. - * - * ldappasswd.c - program to modify passwords in an LDAP tree - * - * Author: David E. Storey - */ #include "portable.h" @@ -30,383 +16,61 @@ #include #include #include -#include -#include #include -#include -#include -#include #include "ldap_defaults.h" -/* local macros */ -#define LDAP_PASSWD_ATTRIB "userPassword" -#define LDAP_PASSWD_CONF LDAP_SYSCONFDIR LDAP_DIRSEP "passwd.conf" - -#define HS_NONE 0 -#define HS_PLAIN 1 -#define HS_CONV 2 - -typedef enum -{ - HASHTYPE_NONE, - HASHTYPE_CRYPT, - HASHTYPE_MD5, - HASHTYPE_SMD5, - HASHTYPE_SHA1, - HASHTYPE_SSHA1 -} -HashTypes; - -typedef struct salt_t -{ - unsigned char *salt; - unsigned int len; -} -Salt; - -typedef struct hash_t -{ - const char *name; - unsigned int namesz; - char *(*func) (const char *, Salt *); - unsigned char takes_salt; - HashTypes type; - HashTypes type_salted; - unsigned int default_salt_len; -} -Hash; - -static int noupdates = 0; static int verbose = 0; -static int want_entryhash = 0; -static int auto_gen_pw = 0; - -/*** functions ***/ - -/* - * pw_encode() essentially base64 encodes a password and its salt - */ - -static char * -pw_encode (unsigned char *passwd, Salt * salt, unsigned int len) -{ - int salted = salt && salt->salt && salt->len; - int b64_len = 0; - char *base64digest = NULL; - unsigned char *npasswd = passwd; - - if (salted) - { - npasswd = (unsigned char *)malloc (len + salt->len); - memcpy (npasswd, passwd, len); - memcpy (&npasswd[len], salt->salt, salt->len); - len += salt->len; - } - - b64_len = LUTIL_BASE64_ENCODE_LEN(len) + 1; - - base64digest = (char *)malloc (b64_len); - - if (lutil_b64_ntop (npasswd, len, base64digest, b64_len) < 0) - { - free (base64digest); - base64digest = NULL; - } - - if (salted) - free (npasswd); - - return (base64digest); -} - -/* - * if you'd like to write a better salt generator, please, be my guest. - */ - -static void -make_salt (Salt * salt, unsigned int len) -{ - - if (!salt) - return; - - salt->len = len; - salt->salt = (unsigned char *)malloc (len); - - for (len = 0; len < salt->len; len++) - salt->salt[len] = rand () & 0xff; -} - -/* - * password generator - */ - -static char * -gen_pass (unsigned int len) -{ - static const unsigned char autogen[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.,"; - unsigned int i; - Salt salt; - - salt.salt = NULL; - salt.len = 0; - - make_salt (&salt, len); - for (i = 0; i < len; i++) - salt.salt[i] = autogen[salt.salt[i] % (sizeof (autogen) - 1)]; - - return ((char *)salt.salt); -} - -#ifdef SLAPD_CLEARTEXT -static char * -hash_none (const char *pw_in, Salt * salt) -{ - return (strdup (pw_in)); -} -#endif - -#ifdef SLAPD_CRYPT -static char * -hash_crypt (const char *pw_in, Salt * salt) -{ - static const unsigned char crypt64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./"; - char *crypted_pw = NULL; - Salt lsalt; - - if (salt && salt->salt && strlen ((char *)salt->salt) >= 2) - { - /* sanity check */ - if (!(isalnum(salt->salt[0]) || salt->salt[0] == '.' || salt->salt[0] == '/')) - salt->salt[0] = crypt64[salt->salt[0] % (sizeof (crypt64) - 1)]; - if (!(isalnum(salt->salt[1]) || salt->salt[1] == '.' || salt->salt[1] == '/')) - salt->salt[1] = crypt64[salt->salt[1] % (sizeof (crypt64) - 1)]; - - crypted_pw = crypt (pw_in, (char *)salt->salt); - } - else - { - make_salt (&lsalt, 2); - lsalt.salt[0] = crypt64[lsalt.salt[0] % (sizeof (crypt64) - 1)]; - lsalt.salt[1] = crypt64[lsalt.salt[1] % (sizeof (crypt64) - 1)]; - crypted_pw = crypt (pw_in, (char *)lsalt.salt); - free (lsalt.salt); - } - return (strdup (crypted_pw)); -} -#endif - -static char * -hash_md5 (const char *pw_in, Salt * salt) -{ - lutil_MD5_CTX MD5context; - unsigned char MD5digest[16]; - - lutil_MD5Init (&MD5context); - lutil_MD5Update (&MD5context, - (const unsigned char *)pw_in, strlen(pw_in)); - if (salt && salt->salt && salt->len) - lutil_MD5Update (&MD5context, salt->salt, salt->len); - lutil_MD5Final (MD5digest, &MD5context); - - return (pw_encode (MD5digest, salt, sizeof (MD5digest))); -} - -static char * -hash_sha1 (const char *pw_in, Salt * salt) -{ - lutil_SHA1_CTX SHA1context; - unsigned char SHA1digest[20]; - - lutil_SHA1Init (&SHA1context); - lutil_SHA1Update (&SHA1context, - (const unsigned char *)pw_in, strlen(pw_in)); - if (salt && salt->salt && salt->len) - lutil_SHA1Update (&SHA1context, salt->salt, salt->len); - lutil_SHA1Final (SHA1digest, &SHA1context); - - return (pw_encode (SHA1digest, salt, sizeof (SHA1digest))); -} - -static const Hash hashes[] = -{ -#ifdef SLAPD_CLEARTEXT - {"none", 4, hash_none, 0, HASHTYPE_NONE, HASHTYPE_NONE, 0}, -#endif -#ifdef SLAPD_CRYPT - {"crypt", 5, hash_crypt, 1, HASHTYPE_CRYPT, HASHTYPE_CRYPT, 2}, -#endif - {"md5", 3, hash_md5, 0, HASHTYPE_MD5, HASHTYPE_SMD5, 0}, - {"smd5", 4, hash_md5, 1, HASHTYPE_SMD5, HASHTYPE_SMD5, 4}, - {"sha", 3, hash_sha1, 0, HASHTYPE_SHA1, HASHTYPE_SSHA1, 0}, - {"ssha", 4, hash_sha1, 1, HASHTYPE_SSHA1, HASHTYPE_SSHA1, 4}, - {NULL, 0, NULL, 0, HASHTYPE_NONE, HASHTYPE_NONE, 0} -}; - -static int -modify_dn (LDAP * ld, char *targetdn, char *pwattr, char *oldpw, - char *newpw, HashTypes htype, Salt * salt) -{ - int ret = 0; - int salted = salt->salt ? 1 : 0; - int want_salt = salt->len && !salted; - char *buf = NULL; - char *hashed_pw = NULL; - char *strvals[2]; - LDAPMod mod, *mods[2]; - - if (!ld || !targetdn || !newpw) - return (1); - - /* auto-generate password */ - if (auto_gen_pw) - newpw = gen_pass (auto_gen_pw); - - /* handle salt */ - if (want_salt) - { - make_salt (salt, salt->len); - htype = hashes[htype].type_salted; - } - else if (hashes[htype].default_salt_len) - { - /* user chose a salted hash and needs a salt */ - if (!salted) - { - want_salt++; - salt->len = hashes[htype].default_salt_len; - make_salt (salt, salt->len); - } - } - - /* hash password */ - hashed_pw = hashes[htype].func (newpw, salt->len ? salt : NULL); - - /* return salt back to its original state */ - if (want_salt) - { - free (salt->salt); - salt->salt = NULL; - } - - buf = (char *)malloc (hashes[htype].namesz + 3 + strlen (hashed_pw)); - if (htype) - sprintf (buf, "{%s}%s", hashes[htype].name, hashed_pw); - else - sprintf (buf, "%s", hashed_pw); - - if (verbose > 0) - { - printf ("%s", targetdn); - if (verbose > 1) - { - printf (":%s", buf); - if (verbose > 2) - printf (":%s", newpw); - } - printf ("\n"); - } - - strvals[0] = buf; - strvals[1] = NULL; - mod.mod_values = strvals; - mod.mod_type = pwattr; - mod.mod_op = LDAP_MOD_REPLACE; - mods[0] = &mod; - mods[1] =NULL; - - if (!noupdates && (ret = ldap_modify_s (ld, targetdn, mods)) != LDAP_SUCCESS) - ldap_perror (ld, "ldap_modify"); - - free (hashed_pw); - free (buf); - return (ret); -} static void usage(const char *s) { - fprintf (stderr, "Usage: %s [options] [filter]\n", s); - fprintf (stderr, " -a attrib\tpassword attribute (default: " LDAP_PASSWD_ATTRIB ")\n"); - fprintf (stderr, " -b basedn\tbasedn to perform searches\n"); -/* fprintf (stderr, " -C\t\tuse entry's current hash mechanism\n"); */ - fprintf (stderr, " -D binddn\tbind dn\n"); - fprintf (stderr, " -d level\tdebugging level\n"); - fprintf (stderr, " -E\t\tprompt for new password\n"); - fprintf (stderr, " -e passwd\tnew password\n"); - fprintf (stderr, " -g passlen\tauto-generate passwords with length pwlen\n"); - fprintf (stderr, " -H hash\thash type (default: crypt)\n"); - fprintf (stderr, " -h host\tldap server (default: localhost)\n"); -#ifdef HAVE_KERBEROS - fprintf (stderr, " -K\t\tuse Kerberos step 1\n"); - fprintf (stderr, " -k\t\tuse Kerberos\n"); -#endif - fprintf (stderr, " -l time\ttime limit\n"); - fprintf (stderr, " -n\t\tmake no modifications\n"); - fprintf (stderr, " -P version\tprotocol version (2 or 3)\n"); - fprintf (stderr, " -p port\tldap port\n"); - fprintf (stderr, " -s scope\tsearch scope: base, one, sub (default: sub)\n"); - fprintf (stderr, " -t targetdn\tdn to change password\n"); - fprintf (stderr, " -v\t\tverbose (more v's, more verbose)\n"); - fprintf (stderr, " -W\t\tprompt for bind password\n"); - fprintf (stderr, " -w passwd\tbind password (for simple authentication)\n"); - fprintf (stderr, " -Y saltlen\tsalt length to use\n"); -/* fprintf (stderr, " -y salt\tsalt to use\n"); */ - fprintf (stderr, " -z size\tsize limit\n"); + fprintf(stderr, + "Usage: %s [options]\n" + " -D binddn\tbind dn\tREQUIRED\n" + " -d level\tdebugging level\n" + " -h host\tldap server (default: localhost)\n" + " -n\t\tmake no modifications\n" + " -p port\tldap port\n" + " -s secret\tnew password\n" + " -v\t\tincrease verbosity\n" + " -W\t\tprompt for bind password\n" + " -w passwd\tbind password (for simple authentication)\n" + , s ); + exit( EXIT_FAILURE ); } int -main (int argc, char *argv[]) +main( int argc, char *argv[] ) { - char *base = NULL; - char *binddn = NULL; - char *bindpw = NULL; - char *filtpattern = NULL; - char *ldaphost = NULL; - char *targetdn = NULL; - char *pwattr = LDAP_PASSWD_ATTRIB; - char *newpw = NULL; - int authmethod = LDAP_AUTH_SIMPLE; - int hashtype = HASHTYPE_CRYPT; + int rc; + char *binddn = NULL; + char *bindpw = NULL; + char *ldaphost = NULL; + char *newpw = NULL; + int noupdates = 0; int i, j; int ldapport = 0; int debug = 0; - int scope = LDAP_SCOPE_SUBTREE; - int sizelimit = -1; - int timelimit = -1; int version = -1; int want_bindpw = 0; - int want_newpw = 0; LDAP *ld; - Salt salt; + struct berval cred; + struct berval *bv = NULL; + BerElement *ber; - salt.salt = NULL; - salt.len = 0; + char *retoid; + struct berval *retdata; if (argc == 1) usage (argv[0]); - while ((i = getopt (argc, argv, "a:b:C:D:d:Ee:g:H:h:Kkl:nP:p:s:t:vWw:Y:y:z:")) != EOF) + while( (i = getopt( argc, argv, + "D:d:h:np:s:vWw:" )) != EOF ) { - switch (i) - { - case 'a': /* password attribute */ - pwattr = strdup (optarg); - break; - - case 'b': /* base search dn */ - base = strdup (optarg); - break; - - case 'C': - want_entryhash++; - break; - + switch (i) { case 'D': /* bind distinguished name */ binddn = strdup (optarg); break; @@ -415,106 +79,27 @@ main (int argc, char *argv[]) debug |= atoi (optarg); break; - case 'E': /* prompt for new password */ - want_newpw++; - break; - - case 'e': /* new password */ - newpw = strdup (optarg); - break; - - case 'g': - auto_gen_pw = strtol (optarg, NULL, 10); - break; - - case 'H': /* hashes */ - for (j = 0; hashes[j].name; j++) - { - if (!strncasecmp (optarg, hashes[j].name, hashes[j].namesz)) - { - hashtype = hashes[j].type; - break; - } - } - - if (!hashes[j].name) - { - fprintf (stderr, "hash type: %s is unknown\n", optarg); - usage (argv[0]); - } - break; - case 'h': /* ldap host */ ldaphost = strdup (optarg); break; - case 'K': /* use kerberos bind, 1st part only */ -#ifdef HAVE_KERBEROS - authmethod = LDAP_AUTH_KRBV41; -#else - fprintf (stderr, "%s was not compiled with Kerberos support\n", argv[0]); - usage (argv[0]); -#endif - break; - - case 'k': /* use kerberos bind */ -#ifdef HAVE_KERBEROS - authmethod = LDAP_AUTH_KRBV4; -#else - fprintf (stderr, "%s was not compiled with Kerberos support\n", argv[0]); - usage (argv[0]); -#endif - break; - - case 'l': /* time limit */ - timelimit = strtol (optarg, NULL, 10); - break; - case 'n': /* don't update entry(s) */ noupdates++; break; - case 'P': - switch( atoi( optarg ) ) { - case 2: - version = LDAP_VERSION2; - break; - case 3: - version = LDAP_VERSION3; - break; - default: - fprintf( stderr, "protocol version should be 2 or 3\n" ); - usage( argv[0] ); - } - break; - case 'p': /* ldap port */ - ldapport = strtol (optarg, NULL, 10); + ldapport = strtol( optarg, NULL, 10 ); break; - case 's': /* scope */ - if (strcasecmp (optarg, "base") == 0) - scope = LDAP_SCOPE_BASE; - else if (strcasecmp (optarg, "one") == 0) - scope = LDAP_SCOPE_ONELEVEL; - else if (strcasecmp (optarg, "sub") == 0) - scope = LDAP_SCOPE_SUBTREE; - else - { - fprintf (stderr, "scope should be base, one, or sub\n"); - usage (argv[0]); - } - break; - - case 't': /* target dn */ - targetdn = strdup (optarg); + case 's': /* new password (secret) */ + newpw = strdup (optarg); break; case 'v': /* verbose */ verbose++; break; - case 'W': /* promt for bind password */ + case 'W': /* prompt for bind password */ want_bindpw++; break; @@ -529,50 +114,35 @@ main (int argc, char *argv[]) } break; - case 'Y': /* salt length */ - salt.len = strtol (optarg, NULL, 10); - break; - - case 'y': /* user specified salt */ - salt.len = strlen (optarg); - salt.salt = (unsigned char *)strdup (optarg); - break; - - case 'z': /* time limit */ - sizelimit = strtol (optarg, NULL, 10); - break; default: usage (argv[0]); } } - /* grab filter */ - if (!(argc - optind < 1)) - filtpattern = strdup (argv[optind]); - - /* check for target(s) */ - if (!filtpattern && !targetdn) - targetdn = binddn; - - /* handle bind password */ - if (want_bindpw) - bindpw = strdup (getpass ("Enter LDAP password: ")); - - /* handle new password */ - if (!newpw) - { + if( newpw == NULL ) { + /* prompt for new password */ char *cknewpw; - newpw = strdup (getpass ("New password: ")); - cknewpw = getpass ("Re-enter new password: "); + newpw = strdup(getpass("New password: ")); + cknewpw = getpass("Re-enter new password: "); - if (strncmp (newpw, cknewpw, strlen (newpw))) - { - fprintf (stderr, "passwords do not match\n"); - return ( EXIT_FAILURE ); + if( strncmp( newpw, cknewpw, strlen(newpw) )) { + fprintf( stderr, "passwords do not match\n" ); + return EXIT_FAILURE; } } + if( binddn == NULL ) { + fprintf( stderr, "no bind DN specified\n" ); + return EXIT_FAILURE; + } + + /* handle bind password */ + if (want_bindpw) { + fprintf( stderr, "Bind DN: %s\n", binddn ); + bindpw = strdup( getpass("Enter bind password: ")); + } + if ( debug ) { if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) { fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug ); @@ -585,105 +155,70 @@ main (int argc, char *argv[]) #ifdef SIGPIPE (void) SIGNAL( SIGPIPE, SIG_IGN ); #endif - /* seed random number generator */ - -#ifdef HAVE_GETTIMEOFDAY - /* this is of questionable value - * gettimeofday may not provide much usec - */ - { - struct timeval tv; - gettimeofday (&tv, NULL); - srand(tv.tv_sec * (tv.tv_usec + 1)); - } -#else - /* The traditional seed */ - srand((unsigned)time( NULL )); -#endif /* connect to server */ - if ((ld = ldap_init (ldaphost, ldapport)) == NULL) - { - perror ("ldap_init"); - return ( EXIT_FAILURE ); + if ((ld = ldap_init( ldaphost, ldapport )) == NULL) { + perror("ldap_init"); + return EXIT_FAILURE; } - /* set options */ - if (timelimit != -1 && - ldap_set_option( ld, LDAP_OPT_TIMELIMIT, (void *) &timelimit ) != LDAP_OPT_SUCCESS ) - { - fprintf( stderr, "Could not set LDAP_OPT_TIMELIMIT %d\n", timelimit ); - } - if (sizelimit != -1 && - ldap_set_option( ld, LDAP_OPT_SIZELIMIT, (void *) &sizelimit ) != LDAP_OPT_SUCCESS ) - { - fprintf( stderr, "Could not set LDAP_OPT_SIZELIMIT %d\n", sizelimit ); - } - - /* this seems prudent */ - { - int deref = LDAP_DEREF_NEVER; - ldap_set_option( ld, LDAP_OPT_DEREF, &deref); - } /* don't chase referrals */ ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ); - if (version != -1 && - ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ) != LDAP_OPT_SUCCESS ) - { + version = 3; + rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + + if(rc != LDAP_OPT_SUCCESS ) { fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version ); } - /* authenticate to server */ - if (ldap_bind_s (ld, binddn, bindpw, authmethod) != LDAP_SUCCESS) - { - ldap_perror (ld, "ldap_bind"); - return ( EXIT_FAILURE ); + rc = ldap_bind_s( ld, binddn, bindpw, LDAP_AUTH_SIMPLE ); + + if ( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_bind" ); + ldap_unbind( ld ); + return EXIT_FAILURE; } - if (targetdn) - { - if (want_entryhash) - { - /* insert code here =) */ - } - else - modify_dn (ld, targetdn, pwattr, NULL, newpw, hashtype, &salt); + /* build change password control */ + ber = ber_alloc_t( LBER_USE_DER ); + + if( ber == NULL ) { + perror( "ber_alloc_t" ); + ldap_unbind( ld ); + return EXIT_FAILURE; } - if (filtpattern) - { - char filter[BUFSIZ]; - LDAPMessage *result = NULL, *e; - char *attrs[2]; - attrs[0] = pwattr; - attrs[1] = NULL; - - /* search */ - sprintf (filter, "%s", filtpattern); - i = ldap_search_s (ld, base, scope, filter, attrs, 0, &result); - if (i != LDAP_SUCCESS && - i != LDAP_TIMELIMIT_EXCEEDED && - i != LDAP_SIZELIMIT_EXCEEDED) - { - ldap_perror (ld, "ldap_search"); - return ( EXIT_FAILURE ); - } + ber_printf( ber, "{es}", + (ber_int_t) 0, + newpw ); - for (e = ldap_first_entry (ld, result); e; e = ldap_next_entry (ld, e)) - { - char *dn = ldap_get_dn (ld, e); - if (dn) - { - struct berval **pw_vals = ldap_get_values_len (ld, e, pwattr); - modify_dn (ld, dn, pwattr, pw_vals ? pw_vals[0]->bv_val : NULL, newpw, hashtype, &salt); - if (pw_vals) - ldap_value_free_len (pw_vals); - free (dn); - } - } + rc = ber_flatten( ber, &bv ); + + if( rc < 0 ) { + perror( "ber_flatten" ); + ldap_unbind( ld ); + return EXIT_FAILURE; } + ber_free( ber, 1 ); + + rc = ldap_extended_operation_s( ld, + LDAP_EXOP_X_MODIFY_PASSWD, bv, + NULL, NULL, + &retoid, &retdata ); + + ber_bvfree( bv ); + + if ( rc != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_extended_operation" ); + ldap_unbind( ld ); + return EXIT_FAILURE; + } + + ldap_memfree( retoid ); + ber_bvfree( retdata ); + /* disconnect from server */ ldap_unbind (ld); diff --git a/doc/man/man1/ldappasswd.1 b/doc/man/man1/ldappasswd.1 index 24d5ca240d..6772123db9 100644 --- a/doc/man/man1/ldappasswd.1 +++ b/doc/man/man1/ldappasswd.1 @@ -6,150 +6,76 @@ ldappasswd \- change the password of an LDAP entry .SH SYNOPSIS .B ldappasswd -[\c -.BI \-a \ passwdattribute\fR] -[\c -.BI \-b \ searchbase\fR] -[\c -.BI \-D \ binddn\fR] +.BI \-D \ binddn\fR [\c .BI \-d \ debuglevel\fR] [\c -.BR \-E ] -[\c -.BI \-e \ passwd\fR] -[\c -.BI \-g \ pwlen\fR] -[\c -.BI \-H \ none\fR\||\|\fIcrypt\fR\||\|\fImd5\fR\||\|\fIsmd5\fR\||\|\fIsha\fR\||\|\fIssha] -[\c .BI \-h \ ldaphost\fR] [\c -.BR \-K ] -[\c -.BR \-k ] -[\c -.BI \-l \ searchtime\fR] -[\c .BR \-n ] [\c -.BI \-P \ 2\fR\||\|\fI3\fR] -[\c .BI \-p \ ldapport\fR] [\c -.BI \-s \ base\fR\||\|\fIone\fR\||\|\fIsub\fR] -[\c -.BI \-t \ targetdn\fR] +.BI \-s \ newPasswd\fR] [\c .BR \-v ] [\c .BR \-W ] [\c .BI \-w \ passwd\fR] -[\c -.BI \-z \ searchsize\fR] -[\fIfilter\fR] .SH DESCRIPTION .B ldappasswd -is a tool to modify the password of one or more LDAP entries. -Multiple entries can be specified using a search filter. +is a tool to set the password of an LDAP user. It is neither designed nor intended to be a replacement for .BR passwd (1) and should not be installed as such. .LP .B ldappasswd -works by specifying a single target dn or by using a search filter. -Matching entries will be modified with the new password. +sets the password of associated with the user associated with the +bind DN. If the new password is not specified on the command line, the user will be prompted to enter it. -The new password will be hashed using -.I crypt -or any other supported hashing algorithm. -For hashing algorithms other than -.I crypt -or -.IR none , -the stored password will be base64 encoded. -Salts are only generated for crypt and are based on the least -significant bits of the current time and other psuedo randomness. .SH OPTIONS .TP -.BI \-a \ passwdattribute -Specify the LDAP attribute to change. The default is "userPassword". -.TP -.BI \-b \ searchbase -Use \fIsearchbase\fP as the starting point for the search instead of -the default. -.TP .BI \-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. +Use \fIbinddn\fP to bind to the LDAP directory. \fIbinddn\fP should +be a string-represented DN as defined in RFC 2253. +This flag is not optional. .TP .BI \-d \ debuglevel Set the LDAP debugging level to \fIdebuglevel\fP. .B ldappasswd must be compiled with LDAP_DEBUG defined for this option to have any effect. .TP -.BI \-g \ pwlen -Auto-generate passwords of length \fIpwlen\fR. -Passwords will be displayed when using verbose, -.BR -vvv . -.TP -.B \-H \fInone\fR\||\|\fIcrypt\fR\||\|\fImd5\fR\||\|\fIsmd5\fR\||\|\fIsha\fR\||\|\fIssha -Specify the hashing algorithm used to store the password. The default is -.IR crypt . -.TP .BI \-h \ ldaphost Specify an alternate host on which the ldap server is running. .TP -.B \-K -Same as -k, but only does step 1 of the kerberos bind. -This is useful when connecting to a slapd and there is no x500dsa.hostname principal registered with your kerberos servers. -.TP -.B \-k -Use Kerberos authentication instead of simple authentication. -It is assumed that you already have a valid ticket granting ticket. -.B ldappasswd -must be compiled with KERBEROS defined for this option to have any effect. -.TP -.BI \-l \ searchtime -Specify a maximum query time in seconds. -.TP .B \-n -Make no modifications. (Can be useful when used in conjunction with +Do not set password. (Can be useful when used in conjunction with .BR \-v \ or .BR \-d ) .TP -.BI \-P \ 2\fR\||\|\fI3 -Specify the LDAP protocol version to use. +.BI \-s \ newPasswd +Set the user password to \fInewPasswd\fP. .TP .BI \-p \ ldapport Specify an alternate port on which the ldap server is running. .TP -.BI \-s \ base\fR\||\|\fIone\fR\||\|\fIsub\fR -Specify the scope of the search. The default is -.IR base . -.TP -.B \-t \fR[\fItargetdn\fR] -Specify the target dn to modify. -If an argument is not given, the target dn will be the binddn. -.TP .B \-v -The more v's the more verbose. +Increase the verbosity of output. Can be specified multiple times. .TP .BI \-W -Prompt for simple authentication. +Prompt for bind password. This is used instead of specifying the password on the command line. .TP .BI \-w \ passwd -Use \fIpasswd\fP as the password for simple authentication. -.TP -.BI \-z \ searchsize -Specify a maximum query size. -.SH AUTHOR -David E. Storey -.SH "SEE ALSO" -.BR ldapadd (1), -.BR ldapdelete (1), -.BR ldapmodrdn (1), -.BR ldapsearch (1) +Use \fIpasswd\fP as the password to bind with. +.SH SEE ALSO +.BR ldap_bind (3) +.SH BUGS +No transport security layer is provided. +.SH ACKNOWLEDGEMENTS +.B OpenLDAP +is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). +.B OpenLDAP +is derived from University of Michigan LDAP 3.3 Release. diff --git a/doc/man/man3/ldap_url.3 b/doc/man/man3/ldap_url.3 index a100792609..9acdd89f37 100644 --- a/doc/man/man3/ldap_url.3 +++ b/doc/man/man3/ldap_url.3 @@ -74,10 +74,10 @@ LDAP URLs look like this: where: \fIhostport\fP is a host name with an optional ":portnumber" - \fIdn\f is the base DN to be used for an LDAP search operation + \fIdn\fP is the base DN to be used for an LDAP search operation \fIattributes\fP is a comma separated list of attributes to be retrieved \fIscope\fP is one of these three strings: base one sub (default=base) - \fIfilter\f is LDAP search filter as used in a call to ldap_search(3) + \fIfilter\fP is LDAP search filter as used in a call to ldap_search(3) e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich .fi diff --git a/include/ldap.h b/include/ldap.h index 5af2eb9937..3ba432e109 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -104,8 +104,6 @@ LDAP_BEGIN_DECL /* 0x34 - 0x0fff not defined by current draft */ -/* extended options - none */ - /* private and experimental options */ #define LDAP_OPT_DNS 0x4001 /* use DN & DNS */ @@ -172,7 +170,7 @@ typedef struct ldapcontrol { #define LDAP_CONTROL_MANAGEDSAIT "2.16.840.1.113730.3.4.2" /* Experimental Controls */ -#define LDAP_CONTROL_X_CHANGE_PASSWD "1.3.6.1.4.1.4203.666.5.1" +#define LDAP_CONTROL_X_MODIFY_PASSWD "1.3.6.1.4.1.4203.666.5.1" /* LDAP Unsolicited Notifications */ @@ -181,6 +179,7 @@ typedef struct ldapcontrol { /* LDAP Extended Operations */ +#define LDAP_EXOP_X_MODIFY_PASSWD "1.3.6.1.4.1.4203.666.6.1" /* diff --git a/include/lutil.h b/include/lutil.h index 2a207d43da..e26374d6b3 100644 --- a/include/lutil.h +++ b/include/lutil.h @@ -58,10 +58,15 @@ lutil_entropy LDAP_P(( /* passwd.c */ LIBLUTIL_F( int ) lutil_passwd LDAP_P(( - const char *cred, - const char *passwd, + const char *passwd, /* stored password */ + const char *cred, /* user supplied value */ const char **methods )); +LIBLUTIL_F( char * ) +lutil_passwd_generate LDAP_P(( + const char *passwd, + const char *method )); + LIBLUTIL_F (const char *) lutil_passwd_schemes[]; LIBLUTIL_F( int ) diff --git a/libraries/libldif/line64.c b/libraries/libldif/line64.c index b02cf8f4b2..edec31540d 100644 --- a/libraries/libldif/line64.c +++ b/libraries/libldif/line64.c @@ -405,8 +405,10 @@ ldif_sput( if ( type == LDIF_PUT_VALUE && isgraph( val[0] ) && val[0] != ':' && val[0] != '<' && isgraph( val[vlen-1] ) +#ifndef LDAP_PASSWD_DEBUG && strcasecmp( name, "userPassword" ) != 0 /* encode userPassword */ && strcasecmp( name, "2.5.4.35" ) != 0 /* encode userPassword */ +#endif ) { int b64 = 0; diff --git a/libraries/liblutil/passwd.c b/libraries/liblutil/passwd.c index 4960add60d..89ae997be9 100644 --- a/libraries/liblutil/passwd.c +++ b/libraries/liblutil/passwd.c @@ -21,6 +21,8 @@ #include #include +#include + #include "lutil_md5.h" #include "lutil_sha1.h" #include "lutil.h" @@ -32,60 +34,148 @@ # include #endif -static int is_allowed_scheme( - const char* scheme, - const char** schemes ) -{ - int i; +struct pw_scheme; - if(schemes == NULL) { - return 1; - } +typedef int (*PASSWD_CHK_FUNC)( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); - for(i=0; schemes[i] != NULL; i++) { - if(strcasecmp(scheme, schemes[i]) == 0) { - return 1; - } - } +typedef char * (*PASSWD_GEN_FUNC) ( + const struct pw_scheme *scheme, + const char *passwd ); - return 0; -} +struct pw_scheme { + char *name; + size_t namelen; + PASSWD_CHK_FUNC chk_fn; + PASSWD_GEN_FUNC gen_fn; +}; + +/* password check routines */ +static int chk_md5( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +static int chk_smd5( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +static int chk_ssha1( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +static int chk_sha1( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +static int chk_crypt( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +static int chk_unix( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + + +/* password generation routines */ +static char *gen_sha1( + const struct pw_scheme *scheme, + const char *passwd ); + +static char *gen_ssha1( + const struct pw_scheme *scheme, + const char *passwd ); + +static char *gen_smd5( + const struct pw_scheme *scheme, + const char *passwd ); + +static char *gen_md5( + const struct pw_scheme *scheme, + const char *passwd ); + +static char *gen_crypt( + const struct pw_scheme *scheme, + const char *passwd ); + + +static const struct pw_scheme pw_schemes[] = +{ + { "{SSHA}", sizeof("{SSHA}")-1, chk_ssha1, gen_ssha1 }, + { "{SHA}", sizeof("{SHA}")-1, chk_sha1, gen_sha1 }, + + { "{SMD5}", sizeof("{SMD5}")-1, chk_smd5, gen_smd5 }, + { "{MD5}", sizeof("{MD5}")-1, chk_md5, gen_md5 }, -const char *lutil_passwd_schemes[] = { #ifdef SLAPD_CRYPT - "{CRYPT}", + { "{CRYPT}", sizeof("{CRYPT}")-1, chk_crypt, gen_crypt }, #endif - "{MD5}", "{SMD5}", - "{SHA}", "{SSHA}", # if defined( HAVE_GETSPNAM ) \ || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) ) - "{UNIX}", + { "{UNIX}", sizeof("{UNIX}")-1, chk_unix, NULL }, #endif + #ifdef SLAPD_CLEARTEXT - "{CLEARTEXT}", /* psuedo scheme */ + /* psuedo scheme */ + { "{CLEARTEXT}", 0, NULL, NULL }, #endif + NULL, }; -int lutil_passwd_scheme( char *scheme ) { - return is_allowed_scheme( scheme, lutil_passwd_schemes ); +static const struct pw_scheme *get_scheme( + const char* scheme ) +{ + int i; + + for( i=0; pw_schemes[i].name != NULL; i++) { + if( pw_schemes[i].namelen == 0 ) continue; + + if( strncasecmp(scheme, pw_schemes[i].name, + pw_schemes[i].namelen) == 0 ) + { + return &pw_schemes[i]; + } + } + + return NULL; } -static const char *passwd_scheme( - const char* passwd, + +static int is_allowed_scheme( const char* scheme, const char** schemes ) { - int len; + int i; - if( !is_allowed_scheme( scheme, schemes ) ) { - return NULL; + if( schemes == NULL ) return 1; + + for( i=0; schemes[i] != NULL; i++ ) { + if( strcasecmp( scheme, schemes[i] ) == 0 ) { + return 1; + } } + return 0; +} - len = strlen(scheme); +static const char *passwd_scheme( + const struct pw_scheme *scheme, + const char* passwd, + const char** allowed ) +{ + if( !is_allowed_scheme( scheme->name, allowed ) ) { + return NULL; + } - if( strncasecmp( passwd, scheme, len ) == 0 ) { - return &passwd[len]; + if( strncasecmp( passwd, scheme->name, scheme->namelen ) == 0 ) { + return &passwd[scheme->namelen]; } return NULL; @@ -96,146 +186,376 @@ static const char *passwd_scheme( */ int lutil_passwd( - const char *cred, - const char *passwd, - const char **schemes) + const char *passwd, /* stored passwd */ + const char *cred, /* user cred */ + const char **schemes ) { - const char *p; + int i; if (cred == NULL || passwd == NULL) { return -1; } - if ((p = passwd_scheme( passwd, "{MD5}", schemes )) != NULL ) { - lutil_MD5_CTX MD5context; - unsigned char MD5digest[16]; - char base64digest[LUTIL_BASE64_ENCODE_LEN(16)]; - - lutil_MD5Init(&MD5context); - lutil_MD5Update(&MD5context, - (const unsigned char *)cred, strlen(cred)); - lutil_MD5Final(MD5digest, &MD5context); + for( i=0; pw_schemes[i].name != NULL; i++ ) { + if( pw_schemes[i].chk_fn ) { + const char *p = passwd_scheme( &pw_schemes[i], + passwd, schemes ); - if ( lutil_b64_ntop(MD5digest, sizeof(MD5digest), - base64digest, sizeof(base64digest)) < 0) - { - return ( 1 ); + if( p != NULL ) { + return (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred ); + } } + } - return( strcmp(p, base64digest) ); +#ifdef SLAPD_CLEARTEXT + if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) { + return strcmp( cred, passwd ); + } +#else + return 1; +#endif - } else if ((p = passwd_scheme( passwd, "{SHA}", schemes )) != NULL ) { - lutil_SHA1_CTX SHA1context; - unsigned char SHA1digest[20]; - char base64digest[LUTIL_BASE64_ENCODE_LEN(20)]; +} - lutil_SHA1Init(&SHA1context); - lutil_SHA1Update(&SHA1context, - (const unsigned char *) cred, strlen(cred)); - lutil_SHA1Final(SHA1digest, &SHA1context); +char * lutil_passwd_generate( + const char * passwd, + const char * method ) +{ + const struct pw_scheme *sc = get_scheme( method ); - if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest), - base64digest, sizeof(base64digest)) < 0) - { - return ( 1 ); + if( sc == NULL ) return NULL; + if( ! sc->gen_fn ) return NULL; + + return (sc->gen_fn)( sc, passwd ); +} + +static char * pw_string( + const struct pw_scheme *sc, + const char *passwd) +{ + size_t pwlen = strlen( passwd ); + char *pw = ber_memalloc( sc->namelen + pwlen + 1 ); + + if( pw == NULL ) return NULL; + + memcpy( pw, sc->name, sc->namelen ); + memcpy( &pw[sc->namelen], passwd, pwlen ); + pw[sc->namelen + pwlen] = '\0'; + + return pw; +} + +static char * pw_string64( + const struct pw_scheme *sc, + const unsigned char *hash, size_t hashlen, + const unsigned char *salt, size_t saltlen ) +{ + int rc; + char *string = NULL; + size_t b64len; + size_t len = hashlen + saltlen; + char *b64; + + if( saltlen ) { + /* need to base64 combined string */ + string = ber_memalloc( hashlen + saltlen ); + + if( string == NULL ) { + return NULL; } - return( strcmp(p, base64digest) ); + memcpy( string, hash, len ); + memcpy( &string[len], salt, saltlen ); + + } else { + string = (char *) hash; + } + + b64len = LUTIL_BASE64_ENCODE_LEN( len ) + 1; + b64 = ber_memalloc( b64len + sc->namelen ); + + if( b64 == NULL ) { + if( saltlen ) ber_memfree( string ); + return NULL; + } - } else if ((p = passwd_scheme( passwd, "{SSHA}", schemes )) != NULL ) { - lutil_SHA1_CTX SHA1context; - unsigned char SHA1digest[20]; - int pw_len = strlen(p); - int rc; - unsigned char *orig_pass = NULL; + memcpy(b64, sc->name, sc->namelen); + + rc = lutil_b64_ntop( string, len, &b64[sc->namelen], b64len ); + + if( saltlen ) ber_memfree( string ); + + if( rc < 0 ) { + free( b64 ); + return NULL; + } + + return b64; +} + +/* PASSWORD CHECK ROUTINES */ + +static int chk_ssha1( + const struct pw_scheme *sc, + const char* passwd, + const char* cred ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[20]; + int pw_len = strlen(passwd); + int rc; + unsigned char *orig_pass = NULL; - /* base64 un-encode password */ - orig_pass = (unsigned char *) malloc( (size_t) ( - LUTIL_BASE64_DECODE_LEN(pw_len) + 1) ); - if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0) - { - free(orig_pass); - return ( 1 ); - } + /* base64 un-encode password */ + orig_pass = (unsigned char *) malloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(pw_len) + 1) ); + + if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) { + free(orig_pass); + return 1; + } - /* hash credentials with salt */ - lutil_SHA1Init(&SHA1context); - lutil_SHA1Update(&SHA1context, - (const unsigned char *) cred, strlen(cred)); - lutil_SHA1Update(&SHA1context, - (const unsigned char *) orig_pass + sizeof(SHA1digest), - rc - sizeof(SHA1digest)); - lutil_SHA1Final(SHA1digest, &SHA1context); + /* hash credentials with salt */ + lutil_SHA1Init(&SHA1context); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) cred, strlen(cred)); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) &orig_pass[sizeof(SHA1digest)], + rc - sizeof(SHA1digest)); + lutil_SHA1Final(SHA1digest, &SHA1context); - /* compare */ - rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); - free(orig_pass); - return(rc); - - } else if ((p = passwd_scheme( passwd, "{SMD5}", schemes )) != NULL ) { - lutil_MD5_CTX MD5context; - unsigned char MD5digest[16]; - int pw_len = strlen(p); - int rc; - unsigned char *orig_pass = NULL; - - /* base64 un-encode password */ - orig_pass = (unsigned char *) malloc( (size_t) ( - LUTIL_BASE64_DECODE_LEN(pw_len) + 1) ); - if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0) - { - free(orig_pass); - return ( 1 ); - } + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); + free(orig_pass); + return rc; +} - /* hash credentials with salt */ - lutil_MD5Init(&MD5context); - lutil_MD5Update(&MD5context, - (const unsigned char *) cred, strlen(cred)); - lutil_MD5Update(&MD5context, - (const unsigned char *) orig_pass + sizeof(MD5digest), - rc - sizeof(MD5digest)); - lutil_MD5Final(MD5digest, &MD5context); - - /* compare */ - rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); +static int chk_sha1( + const struct pw_scheme *sc, + const char* passwd, + const char* cred ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[20]; + char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(SHA1digest))+1]; + + lutil_SHA1Init(&SHA1context); + lutil_SHA1Update(&SHA1context, + (const unsigned char *) cred, strlen(cred)); + lutil_SHA1Final(SHA1digest, &SHA1context); + + if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest), + base64digest, sizeof(base64digest)) < 0) + { + return 1; + } + + return strcmp(passwd, base64digest); +} + +static int chk_smd5( + const struct pw_scheme *sc, + const char* passwd, + const char* cred ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[16]; + int pw_len = strlen(passwd); + int rc; + unsigned char *orig_pass = NULL; + + /* base64 un-encode password */ + orig_pass = (unsigned char *) malloc( (size_t) ( + LUTIL_BASE64_DECODE_LEN(pw_len) + 1) ); + + if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) { free(orig_pass); - return ( rc ); + return 1; + } + + /* hash credentials with salt */ + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *) cred, strlen(cred)); + lutil_MD5Update(&MD5context, + (const unsigned char *) &orig_pass[sizeof(MD5digest)], + rc - sizeof(MD5digest)); + lutil_MD5Final(MD5digest, &MD5context); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); + free(orig_pass); + return rc; +} + +static int chk_md5( + const struct pw_scheme *sc, + const char* passwd, + const char* cred ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[16]; + char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(MD5digest))+1]; + + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *)cred, strlen(cred)); + lutil_MD5Final(MD5digest, &MD5context); + + if ( lutil_b64_ntop(MD5digest, sizeof(MD5digest), + base64digest, sizeof(base64digest)) < 0 ) + { + return 1; + } + + return strcmp(passwd, base64digest); +} #ifdef SLAPD_CRYPT - } else if ((p = passwd_scheme( passwd, "{CRYPT}", schemes )) != NULL ) { - return( strcmp(p, crypt(cred, p)) ); +static int chk_crypt( + const struct pw_scheme *sc, + const char* passwd, + const char* cred ) +{ + return strcmp(passwd, crypt(cred, passwd)); +} # if defined( HAVE_GETSPNAM ) \ || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) ) - } else if ((p = passwd_scheme( passwd, "{UNIX}", schemes )) != NULL ) { - +static int chk_unix( + const struct pw_scheme *sc, + const char* cred, + const char* p ) +{ # ifdef HAVE_GETSPNAM - struct spwd *spwd = getspnam(p); + struct spwd *spwd = getspnam(p); - if(spwd == NULL) { - return 1; /* not found */ - } + if(spwd == NULL) { + return 1; /* not found */ + } - return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp)); + return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp)); # else - struct passwd *pwd = getpwnam(p); + struct passwd *pwd = getpwnam(p); - if(pwd == NULL) { - return 1; /* not found */ - } + if(pwd == NULL) { + return 1; /* not found */ + } - return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd)); + return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd)); # endif # endif +} #endif + +/* PASSWORD CHECK ROUTINES */ +static char *gen_ssha1( + const struct pw_scheme *scheme, + const char *passwd ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[20]; + unsigned char salt[4]; + + if( lutil_entropy( salt, sizeof(salt)) < 0 ) { + return NULL; } -#ifdef SLAPD_CLEARTEXT - return is_allowed_scheme("{CLEARTEXT}", schemes ) && - strcmp(passwd, cred) != 0; -#else - return( 1 ); -#endif + lutil_SHA1Init( &SHA1context ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)passwd, strlen(passwd) ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)salt, sizeof(salt) ); + lutil_SHA1Final( SHA1digest, &SHA1context ); + + return pw_string64( scheme, + SHA1digest, sizeof(SHA1digest), + salt, sizeof(salt)); +} + +static char *gen_sha1( + const struct pw_scheme *scheme, + const char *passwd ) +{ + lutil_SHA1_CTX SHA1context; + unsigned char SHA1digest[20]; + + lutil_SHA1Init( &SHA1context ); + lutil_SHA1Update( &SHA1context, + (const unsigned char *)passwd, strlen(passwd) ); + lutil_SHA1Final( SHA1digest, &SHA1context ); + + return pw_string64( scheme, + SHA1digest, sizeof(SHA1digest), + NULL, 0); +} + +static char *gen_smd5( + const struct pw_scheme *scheme, + const char *passwd ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[16]; + unsigned char salt[4]; + + if( lutil_entropy( salt, sizeof(salt)) < 0 ) { + return NULL; + } + + lutil_MD5Init( &MD5context ); + lutil_MD5Update( &MD5context, + (const unsigned char *) passwd, strlen(passwd) ); + + lutil_MD5Update( &MD5context, + (const unsigned char *) salt, sizeof(salt) ); + + lutil_MD5Final( MD5digest, &MD5context ); + + return pw_string64( scheme, + MD5digest, sizeof(MD5digest), + salt, sizeof(salt) ); +} + +static char *gen_md5( + const struct pw_scheme *scheme, + const char *passwd ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[16]; + + lutil_MD5Init( &MD5context ); + lutil_MD5Update( &MD5context, + (const unsigned char *) passwd, strlen(passwd) ); + + lutil_MD5Final( MD5digest, &MD5context ); + + return pw_string64( scheme, + MD5digest, sizeof(MD5digest), + NULL, 0 ); +} + +#ifdef SLAPD_CRYPT +static char *gen_crypt( + const struct pw_scheme *scheme, + const char *passwd ) +{ + static const unsigned char crypt64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./"; + + char *hash = NULL; + unsigned char salt[2]; + if( lutil_entropy( salt, sizeof(salt)) < 0 ) { + return NULL; + } + + salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ]; + salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ]; + + hash = crypt( passwd, salt ); + + if( hash = NULL ) return NULL; + + return pw_string( scheme, hash ); } +#endif diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 093072677b..9bc2133841 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -147,6 +147,14 @@ do_add( Connection *conn, Operation *op ) return rc; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + if ( global_readonly || be->be_readonly ) { Debug( LDAP_DEBUG_ANY, "do_add: database is read-only\n", 0, 0, 0 ); diff --git a/servers/slapd/back-bdb2/init.c b/servers/slapd/back-bdb2/init.c index 8d8dcfd127..d3b243f2ca 100644 --- a/servers/slapd/back-bdb2/init.c +++ b/servers/slapd/back-bdb2/init.c @@ -55,6 +55,14 @@ bdb2_back_initialize( { int ret; + static char *controls[] = { + LDAP_CONTROL_MANAGEDSAIT, + /* LDAP_CONTROL_X_CHANGE_PASSWD, */ + NULL + }; + + bi->bi_controls = controls; + bi->bi_open = bdb2_back_open; bi->bi_config = bdb2_back_config; bi->bi_close = bdb2_back_close; @@ -76,6 +84,8 @@ bdb2_back_initialize( bi->bi_op_delete = bdb2_back_delete; bi->bi_op_abandon = bdb2_back_abandon; + bi->bi_extended = 0; + bi->bi_entry_release_rw = bdb2_back_entry_release_rw; bi->bi_acl_group = bdb2_back_group; diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index e1d80f76e6..830c833e8d 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -72,6 +72,8 @@ ldap_back_initialize( bi->bi_op_delete = ldap_back_delete; bi->bi_op_abandon = 0; + bi->bi_extended = 0; + bi->bi_acl_group = 0; bi->bi_connection_init = 0; diff --git a/servers/slapd/back-ldbm/Makefile.in b/servers/slapd/back-ldbm/Makefile.in index 7fb735cf29..15211cb0f7 100644 --- a/servers/slapd/back-ldbm/Makefile.in +++ b/servers/slapd/back-ldbm/Makefile.in @@ -3,11 +3,13 @@ SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c entry.c id2entry.c \ index.c id2children.c nextid.c abandon.c compare.c group.c \ modify.c modrdn.c delete.c init.c config.c bind.c attr.c \ - filterindex.c unbind.c close.c alias.c tools.c + filterindex.c unbind.c close.c alias.c tools.c \ + extended.c passwd.c OBJS = idl.lo add.lo search.lo cache.lo dbcache.lo dn2id.lo entry.lo id2entry.lo \ index.lo id2children.lo nextid.lo abandon.lo compare.lo group.lo \ modify.lo modrdn.lo delete.lo init.lo config.lo bind.lo attr.lo \ - filterindex.lo unbind.lo close.lo alias.lo tools.lo + filterindex.lo unbind.lo close.lo alias.lo tools.lo \ + extended.lo passwd.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-ldbm/extended.c b/servers/slapd/back-ldbm/extended.c new file mode 100644 index 0000000000..eb55797d8f --- /dev/null +++ b/servers/slapd/back-ldbm/extended.c @@ -0,0 +1,51 @@ +/* extended.c - ldbm backend extended routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" + +struct exop { + char *oid; + SLAP_EXTENDED_FN extended; +} exop_table[] = { + { LDAP_EXOP_X_MODIFY_PASSWD, ldbm_back_exop_passwd }, + { NULL, NULL } +}; + +int +ldbm_back_extended( + Backend *be, + Connection *conn, + Operation *op, + char *oid, + struct berval *reqdata, + struct berval **rspdata, + char** text +) +{ + int i; + + for( i=0; exop_table[i].oid != NULL; i++ ) { + if( strcmp( exop_table[i].oid, oid ) == 0 ) { + return (exop_table[i].extended)( + be, conn, op, + oid, reqdata, rspdata, text ); + } + } + + *text = ch_strdup("not supported within naming context"); + return LDAP_OPERATIONS_ERROR; +} + diff --git a/servers/slapd/back-ldbm/external.h b/servers/slapd/back-ldbm/external.h index c8a1b25d5f..24ca3560a8 100644 --- a/servers/slapd/back-ldbm/external.h +++ b/servers/slapd/back-ldbm/external.h @@ -22,6 +22,13 @@ extern int ldbm_back_db_destroy LDAP_P(( BackendDB *bd )); extern int ldbm_back_db_config LDAP_P(( BackendDB *bd, const char *fname, int lineno, int argc, char **argv )); +extern int ldbm_back_extended LDAP_P(( BackendDB *bd, + Connection *conn, Operation *op, + char *reqoid, + struct berval *reqdata, + struct berval **rspdata, + char **text )); + extern int ldbm_back_bind LDAP_P(( BackendDB *bd, Connection *conn, Operation *op, char *dn, char *ndn, int method, char* mech, diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c index e399f676ab..7d59f5dde0 100644 --- a/servers/slapd/back-ldbm/init.c +++ b/servers/slapd/back-ldbm/init.c @@ -35,6 +35,14 @@ ldbm_back_initialize( BackendInfo *bi ) { + static char *controls[] = { + LDAP_CONTROL_MANAGEDSAIT, + /* LDAP_CONTROL_X_CHANGE_PASSWD, */ + NULL + }; + + bi->bi_controls = controls; + bi->bi_open = ldbm_back_open; bi->bi_config = 0; bi->bi_close = ldbm_back_close; @@ -56,6 +64,8 @@ ldbm_back_initialize( bi->bi_op_delete = ldbm_back_delete; bi->bi_op_abandon = ldbm_back_abandon; + bi->bi_extended = ldbm_back_extended; + bi->bi_entry_release_rw = ldbm_back_entry_release_rw; bi->bi_acl_group = ldbm_back_group; diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index fa55df90be..b3f104fcc9 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -39,9 +39,7 @@ int ldbm_modify_internal( Attribute *save_attrs; if ( !acl_check_modlist( be, conn, op, e, modlist )) { - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - NULL, NULL, NULL, NULL ); - return -1; + return LDAP_INSUFFICIENT_ACCESS; } save_attrs = e->e_attrs; @@ -82,9 +80,7 @@ int ldbm_modify_internal( attrs_free( e->e_attrs ); e->e_attrs = save_attrs; /* unlock entry, delete from cache */ - send_ldap_result( conn, op, err, - NULL, NULL, NULL, NULL ); - return -1; + return err; } } @@ -94,7 +90,7 @@ int ldbm_modify_internal( attrs_free( e->e_attrs ); e->e_attrs = save_attrs; ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - return -1; + return SLAPD_ABANDON; } ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); @@ -103,9 +99,7 @@ int ldbm_modify_internal( attrs_free( e->e_attrs ); e->e_attrs = save_attrs; Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 ); - send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, - NULL, NULL, NULL, NULL ); - return -1; + return LDAP_OBJECT_CLASS_VIOLATION; } /* check for abandon */ @@ -114,7 +108,7 @@ int ldbm_modify_internal( attrs_free( e->e_attrs ); e->e_attrs = save_attrs; ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - return -1; + return SLAPD_ABANDON; } ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); @@ -143,20 +137,10 @@ int ldbm_modify_internal( /* modify indexes */ if ( index_add_mods( be, modlist, e->e_id ) != 0 ) { /* our indices are likely hosed */ - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, - NULL, NULL, NULL, NULL ); - return -1; + return LDAP_OPERATIONS_ERROR; } - /* check for abandon */ - ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); - if ( op->o_abandon ) { - ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - return -1; - } - ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - - return 0; + return LDAP_SUCCESS; } @@ -170,6 +154,7 @@ ldbm_back_modify( LDAPModList *modlist ) { + int rc; struct ldbminfo *li = (struct ldbminfo *) be->be_private; Entry *matched; Entry *e; @@ -221,7 +206,14 @@ ldbm_back_modify( } /* Modify the entry */ - if ( ldbm_modify_internal( be, conn, op, ndn, modlist, e ) != 0 ) { + rc = ldbm_modify_internal( be, conn, op, ndn, modlist, e ); + + if( rc != LDAP_SUCCESS ) { + if( rc != SLAPD_ABANDON ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + goto error_return; } @@ -234,6 +226,7 @@ ldbm_back_modify( send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); + cache_return_entry_w( &li->li_cache, e ); return( 0 ); diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index 6152c952a4..ac9f17d699 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -453,8 +453,13 @@ ldbm_back_modrdn( } /* modify memory copy of entry */ - if ( ldbm_modify_internal( be, conn, op, dn, &mod[0], e ) - != 0 ) { + rc = ldbm_modify_internal( be, conn, op, dn, &mod[0], e ); + + if( rc != LDAP_SUCCESS ) { + if( rc != SLAPD_ABANDON ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } goto return_results; } diff --git a/servers/slapd/back-ldbm/passwd.c b/servers/slapd/back-ldbm/passwd.c new file mode 100644 index 0000000000..355405bbda --- /dev/null +++ b/servers/slapd/back-ldbm/passwd.c @@ -0,0 +1,109 @@ +/* extended.c - ldbm backend extended routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" + +int +ldbm_back_exop_passwd( + Backend *be, + Connection *conn, + Operation *op, + char *oid, + struct berval *reqdata, + struct berval **rspdata, + char** text +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + int rc = LDAP_OPERATIONS_ERROR; + Entry *e; + struct berval *cred = NULL; + + assert( oid != NULL ); + assert( strcmp( LDAP_EXOP_X_MODIFY_PASSWD, oid ) == 0 ); + + Debug( LDAP_DEBUG_ARGS, "==> ldbm_back_exop_passwd: dn: %s\n", + op->o_dn, 0, 0 ); + + + cred = slap_passwd_generate( reqdata ); + if( cred == NULL || cred->bv_len == 0 ) { + *text = ch_strdup("password generation failed"); + return LDAP_OPERATIONS_ERROR; + } + + Debug( LDAP_DEBUG_TRACE, "passwd: %s\n", cred->bv_val, 0, 0 ); + + e = dn2entry_w( be, op->o_ndn, NULL ); + + if( e == NULL ) { + *text = ch_strdup("could not locate authorization entry"); + return LDAP_OPERATIONS_ERROR; + } + + if( ! access_allowed( be, conn, op, e, "entry", NULL, ACL_WRITE ) ) { + *text = ch_strdup("access to authorization entry denied"); + rc = LDAP_INSUFFICIENT_ACCESS; + goto done; + } + + if( is_entry_alias( e ) ) { + /* entry is an alias, don't allow operation */ + *text = ch_strdup("authorization entry is alias"); + rc = LDAP_ALIAS_PROBLEM; + goto done; + } + + if( is_entry_referral( e ) ) { + /* entry is an referral, don't allow operation */ + *text = ch_strdup("authorization entry is referral"); + goto done; + } + + { + LDAPModList ml; + struct berval *vals[2]; + + vals[0] = cred; + vals[1] = NULL; + + ml.ml_type = ch_strdup("userPassword"); + ml.ml_bvalues = vals; + ml.ml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + ml.ml_next = NULL; + + rc = ldbm_modify_internal( be, + conn, op, op->o_ndn, &ml, e ); + + ch_free(ml.ml_type); + } + + if( rc == LDAP_SUCCESS ) { + /* change the entry itself */ + if( id2entry_add( be, e ) != 0 ) { + rc = LDAP_OPERATIONS_ERROR; + } + } + +done: + cache_return_entry_w( &li->li_cache, e ); + + if( cred != NULL ) { + ber_bvfree( cred ); + } + + return rc; +} diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h index 1b466f4eb6..c6aeaa519f 100644 --- a/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -144,13 +144,16 @@ int index_change_values LDAP_P(( Backend *be, unsigned int op )); /* - * kerberos.c + * passwd.c */ - -#ifdef HAVE_KERBEROS -/* krbv4_ldap_auth LDAP_P(( Backend *be, struct berval *cred, AUTH_DAT *ad )); */ -#endif +extern int ldbm_back_exop_passwd LDAP_P(( BackendDB *bd, + Connection *conn, Operation *op, + char *oid, + struct berval *reqdata, + struct berval **rspdata, + char **text )); + /* * modify.c * These prototypes are placed here because they are used by modify and @@ -166,9 +169,11 @@ int index_change_values LDAP_P(( Backend *be, int add_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn )); int delete_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn )); int replace_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn )); + +/* returns LDAP error code indicating error OR SLAPD_ABANDON */ int ldbm_modify_internal LDAP_P((Backend *be, Connection *conn, Operation *op, - char *dn, LDAPModList *mods, Entry *e)); + char *dn, LDAPModList *mods, Entry *e )); /* * nextid.c diff --git a/servers/slapd/back-passwd/init.c b/servers/slapd/back-passwd/init.c index 609231dba4..ac41c382f4 100644 --- a/servers/slapd/back-passwd/init.c +++ b/servers/slapd/back-passwd/init.c @@ -51,6 +51,8 @@ passwd_back_initialize( bi->bi_op_delete = 0; bi->bi_op_abandon = 0; + bi->bi_extended = 0; + bi->bi_acl_group = 0; bi->bi_connection_init = 0; diff --git a/servers/slapd/back-perl/init.c b/servers/slapd/back-perl/init.c index c62391f468..1fdeb55ce3 100644 --- a/servers/slapd/back-perl/init.c +++ b/servers/slapd/back-perl/init.c @@ -96,6 +96,8 @@ perl_back_initialize( bi->bi_op_delete = perl_back_delete; bi->bi_op_abandon = 0; + bi->bi_extended = 0; + bi->bi_acl_group = 0; bi->bi_connection_init = 0; diff --git a/servers/slapd/back-shell/init.c b/servers/slapd/back-shell/init.c index 57c3742c4e..f86ccccb0d 100644 --- a/servers/slapd/back-shell/init.c +++ b/servers/slapd/back-shell/init.c @@ -51,6 +51,8 @@ shell_back_initialize( bi->bi_op_delete = shell_back_delete; bi->bi_op_abandon = shell_back_abandon; + bi->bi_extended = 0; + bi->bi_acl_group = 0; bi->bi_connection_init = 0; diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index a7a6b2c9f4..d1a71cc491 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -506,14 +506,14 @@ be_isroot_pw( Backend *be, const char *ndn, struct berval *cred ) int result; if ( ! be_isroot( be, ndn ) ) { - return( 0 ); + return 0; } #ifdef SLAPD_CRYPT ldap_pvt_thread_mutex_lock( &crypt_mutex ); #endif - result = lutil_passwd( cred->bv_val, be->be_root_pw, NULL ); + result = lutil_passwd( be->be_root_pw, cred->bv_val, NULL ); #ifdef SLAPD_CRYPT ldap_pvt_thread_mutex_unlock( &crypt_mutex ); @@ -584,6 +584,29 @@ backend_connection_destroy( return 0; } +int +backend_check_controls( + Backend *be, + Connection *conn, + Operation *op ) +{ + LDAPControl **ctrls; + ctrls = op->o_ctrls; + if( ctrls == NULL ) { + return LDAP_SUCCESS; + } + + for( ; *ctrls != NULL ; ctrls++ ) { + if( (*ctrls)->ldctl_iscritical && + !charray_inlist( be->be_controls, (*ctrls)->ldctl_oid ) ) + { + return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + } + } + + return LDAP_SUCCESS; +} + int backend_group( Backend *be, diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 449c820b8f..9be3d11c8a 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -68,6 +68,8 @@ do_bind( conn->c_dn = NULL; } + conn->c_authz_backend = NULL; + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); if ( op->o_dn != NULL ) { @@ -281,14 +283,28 @@ do_bind( goto cleanup; } + conn->c_authz_backend = be; + + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + if ( be->be_bind ) { + int ret; /* alias suffix */ char *edn = NULL; /* deref suffix alias if appropriate */ ndn = suffix_alias( be, ndn ); - if ( (*be->be_bind)( be, conn, op, dn, ndn, method, mech, &cred, &edn ) == 0 ) { + ret = (*be->be_bind)( be, conn, op, dn, ndn, + method, mech, &cred, &edn ); + + if ( ret == 0 ) { ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_cdn = dn; diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 86bdaff74d..0454281b71 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -99,6 +99,14 @@ do_compare( goto cleanup; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + /* deref suffix alias if appropriate */ ndn = suffix_alias( be, ndn ); diff --git a/servers/slapd/config.c b/servers/slapd/config.c index cee2fe9e3d..1c72b121af 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -34,6 +34,7 @@ int global_lastmod = ON; int global_idletimeout = 0; char *global_realm = NULL; char *ldap_srvtab = ""; +char *default_passwd_hash; char *slapd_pid_file = NULL; char *slapd_args_file = NULL; @@ -171,6 +172,24 @@ read_config( const char *fname ) slapd_args_file = ch_strdup( cargv[1] ); + /* default password hash */ + } else if ( strcasecmp( cargv[0], "password-hash" ) == 0 ) { + if ( cargc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing realm in \"password-hash \" line\n", + fname, lineno, 0 ); + return( 1 ); + } + if ( default_passwd_hash != NULL ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: already set default password_hash!\n", + fname, lineno, 0 ); + return 1; + + } else { + default_passwd_hash = ch_strdup( cargv[1] ); + } + /* set DIGEST realm */ } else if ( strcasecmp( cargv[0], "digest-realm" ) == 0 ) { if ( cargc < 2 ) { diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index f906b4068d..c5cdb803d4 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -21,7 +21,7 @@ char *supportedControls[] = { LDAP_CONTROL_MANAGEDSAIT, - LDAP_CONTROL_X_CHANGE_PASSWD, +/* LDAP_CONTROL_X_CHANGE_PASSWD, */ NULL }; diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index 87f4672919..77b2f4098a 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -86,6 +86,14 @@ do_delete( goto cleanup; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + if ( global_readonly || be->be_readonly ) { Debug( LDAP_DEBUG_ANY, "do_delete: database is read-only\n", 0, 0, 0 ); diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c index 0f0d3ed01b..2abf5407f6 100644 --- a/servers/slapd/extended.c +++ b/servers/slapd/extended.c @@ -32,39 +32,26 @@ #include "slap.h" -#ifdef SLAPD_EXTERNAL_EXTENSIONS - -typedef struct extensions_cookie_t { - Connection *conn; - Operation *op; -} extensions_cookie_t; - #define MAX_OID_LENGTH 128 -typedef struct extensions_list_t { - struct extensions_list_t *next; +typedef struct extop_list_t { + struct extop_list_t *next; char *oid; - int (*ext_main)(int (*)(), void *, char *reqoid, struct berval *reqdata, char **rspoid, struct berval *rspdata, char **text); -} extensions_list_t; - -extensions_list_t *supp_ext_list = NULL; - -extensions_list_t *find_extension (extensions_list_t *list, char *oid); -int extensions_callback (extensions_cookie_t *cookie, int msg, int arg, void *argp); + SLAP_EXTOP_MAIN_FN ext_main; +} extop_list_t; -#else +extop_list_t *supp_ext_list = NULL; -char *supportedExtensions[] = { - NULL -}; -#endif +static extop_list_t *find_extop( extop_list_t *list, char *oid ); +static int extop_callback( + Connection *conn, Operation *op, + int msg, int arg, void *argp); char * -get_supported_extension (int index) +get_supported_extop (int index) { -#ifdef SLAPD_EXTERNAL_EXTENSIONS - extensions_list_t *ext; + extop_list_t *ext; /* linear scan is slow, but this way doesn't force a * big change on root_dse.c, where this routine is used. @@ -73,9 +60,6 @@ get_supported_extension (int index) if (ext == NULL) return(NULL); return(ext->oid); -#else - return(supportedExtensions[index]); -#endif } int @@ -85,21 +69,18 @@ do_extended( ) { int rc = LDAP_SUCCESS; - char* reqoid ; - struct berval reqdata; + char* oid; + struct berval *reqdata; ber_tag_t tag; ber_len_t len; -#ifdef SLAPD_EXTERNAL_EXTENSIONS - extensions_list_t *ext; - char *rspoid, *text; - struct berval rspdata; - extensions_cookie_t cookie; -#endif + extop_list_t *ext; + char *text; + struct berval *rspdata; Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 ); - reqoid = NULL; - reqdata.bv_val = NULL; + oid = NULL; + reqdata = NULL; if( op->o_protocol < LDAP_VERSION3 ) { Debug( LDAP_DEBUG_ANY, "do_extended: protocol version (%d) too low\n", @@ -110,7 +91,7 @@ do_extended( goto done; } - if ( ber_scanf( op->o_ber, "{a" /*}*/, &reqoid ) == LBER_ERROR ) { + if ( ber_scanf( op->o_ber, "{a" /*}*/, &oid ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, "decoding error" ); @@ -118,23 +99,18 @@ do_extended( goto done; } -#ifdef SLAPD_EXTERNAL_EXTENSIONS - if( !(ext = find_extension(supp_ext_list, reqoid)) ) -#else - if( !charray_inlist( supportedExtensions, reqoid ) ) -#endif - { + if( !(ext = find_extop(supp_ext_list, oid)) ) { Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n", - reqoid, 0 ,0 ); + oid, 0 ,0 ); send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, - NULL, "unsuppored extended operation", NULL, NULL ); + NULL, "unsupported extended operation", NULL, NULL ); goto done; } tag = ber_peek_tag( op->o_ber, &len ); if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) { - if( ber_scanf( op->o_ber, "o", &reqdata ) == LBER_ERROR ) { + if( ber_scanf( op->o_ber, "O", &reqdata ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, "decoding error" ); @@ -148,99 +124,70 @@ do_extended( return rc; } - Debug( LDAP_DEBUG_ARGS, "do_extended: oid \"%s\"\n", reqoid, 0 ,0 ); + Debug( LDAP_DEBUG_ARGS, "do_extended: oid=%s\n", oid, 0 ,0 ); -#ifdef SLAPD_EXTERNAL_EXTENSIONS - cookie.conn = conn; - cookie.op = op; - rspoid = NULL; - rspdata.bv_len = 0; - rspdata.bv_val = NULL; + rspdata = NULL; text = NULL; - rc = (ext->ext_main)(extensions_callback, &cookie, reqoid, &reqdata, &rspoid, &rspdata, &text); - send_ldap_extended(conn, op, rc, NULL, text, rspoid, rspdata.bv_val ? &rspdata : NULL); + rc = (ext->ext_main)( extop_callback, conn, op, + oid, reqdata, &rspdata, &text ); - if (rspoid != NULL) - free(rspoid); - if ( rspdata.bv_val != NULL ) - free(rspdata.bv_val); - if ( text != NULL ) - free(text); + if( rc != SLAPD_ABANDON ) { + send_ldap_extended( conn, op, rc, NULL, text, + oid, rspdata ); + } -#else - send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, - NULL, "unsupported extended operation", NULL, NULL ); + if ( rspdata != NULL ) + ber_bvfree( rspdata ); -#endif + if ( text != NULL ) + free(text); done: - if ( reqoid != NULL ) { - free( reqoid ); + if ( reqdata != NULL ) { + ber_bvfree( reqdata ); } - if ( reqdata.bv_val != NULL ) { - free( reqdata.bv_val ); + if ( oid != NULL ) { + free( oid ); } return rc; } -#ifdef SLAPD_EXTERNAL_EXTENSIONS - int -load_extension ( - const void *module, - const char *file_name -) +load_extop( + const char *ext_oid, + SLAP_EXTOP_MAIN_FN ext_main ) { - extensions_list_t *ext; - int (*ext_getoid)(int index, char *oid, int blen); + extop_list_t *ext; int rc; - ext = ch_calloc(1, sizeof(extensions_list_t)); + if( ext_oid == NULL || *ext_oid == '\0' ) return -1; + if(!ext_main) return -1; + + ext = ch_calloc(1, sizeof(extop_list_t)); if (ext == NULL) return(-1); - ext->oid = ch_malloc(MAX_OID_LENGTH); + ext->oid = ch_strdup( ext_oid ); if (ext->oid == NULL) { free(ext); return(-1); } - ext->ext_main = module_resolve(module, "ext_main"); - if (ext->ext_main == NULL) { - free(ext->oid); - free(ext); - return(-1); - } - - ext_getoid = module_resolve(module, "ext_getoid"); - if (ext_getoid == NULL) { - free(ext->oid); - free(ext); - return(-1); - } - rc = (ext_getoid)(0, ext->oid, MAX_OID_LENGTH); - if (rc != 0) { - free(ext->oid); - free(ext); - return(rc); - } - if (*ext->oid == 0) { - free(ext->oid); - free(ext); - return(-1); - } - + ext->ext_main = ext_main; ext->next = supp_ext_list; + supp_ext_list = ext; + return(0); } -extensions_list_t * -find_extension (extensions_list_t *list, char *oid) + +static extop_list_t * +find_extop( extop_list_t *list, char *oid ) { - extensions_list_t *ext; + extop_list_t *ext; for (ext = list; ext; ext = ext->next) { if (strcmp(ext->oid, oid) == 0) @@ -250,38 +197,37 @@ find_extension (extensions_list_t *list, char *oid) } int -extensions_callback (extensions_cookie_t *cookie, int msg, int arg, void *argp) +extop_callback( + Connection *conn, Operation *op, + int msg, int arg, void *argp) { - if (cookie == NULL) - return(-1); - if (argp == NULL) return(-1); switch (msg) { - case 0: /* SLAPD_EXT_GETVERSION */ + case SLAPD_EXTOP_GETVERSION: *(int *)argp = 1; return(0); - case 1: /* SLAPD_EXT_GETPROTO */ - *(int *)argp = cookie->op->o_protocol; + case SLAPD_EXTOP_GETPROTO: + *(int *)argp = op->o_protocol; return(0); - case 2: /* SLAPD_EXT_GETAUTH */ - *(int *)argp = cookie->op->o_authtype; + case SLAPD_EXTOP_GETAUTH: + *(int *)argp = op->o_authtype; return(0); - case 3: /* SLAPD_EXT_GETDN */ - *(char **)argp = cookie->op->o_dn; + case SLAPD_EXTOP_GETDN: + *(char **)argp = op->o_dn; return(0); - case 4: /* SLAPD_EXT_GETCLIENT */ - if (cookie->conn->c_peer_domain != NULL && *cookie->conn->c_peer_domain != 0) { - *(char **)argp = cookie->conn->c_peer_domain; + case SLAPD_EXTOP_GETCLIENT: + if (conn->c_peer_domain != NULL && *conn->c_peer_domain != 0) { + *(char **)argp = conn->c_peer_domain; return(0); } - if (cookie->conn->c_peer_name != NULL && *cookie->conn->c_peer_name != 0) { - *(char **)argp = cookie->conn->c_peer_name; + if (conn->c_peer_name != NULL && *conn->c_peer_name != 0) { + *(char **)argp = conn->c_peer_name; return(0); } break; @@ -291,6 +237,3 @@ extensions_callback (extensions_cookie_t *cookie, int msg, int arg, void *argp) } return(-1); } - -#endif - diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 510816798a..f9020726bc 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -137,6 +137,8 @@ int slap_startup( Backend *be ) rc = sasl_init(); } + slap_passwd_init(); + return rc; } diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index 7d1fc71abd..2eea03e3ef 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -178,6 +178,14 @@ do_modify( goto cleanup; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + if ( global_readonly || be->be_readonly ) { Debug( LDAP_DEBUG_ANY, "do_modify: database is read-only\n", 0, 0, 0 ); diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 2292789bea..0467e54dc6 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -172,6 +172,14 @@ do_modrdn( goto cleanup; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + if ( global_readonly || be->be_readonly ) { Debug( LDAP_DEBUG_ANY, "do_modrdn: database is read-only\n", 0, 0, 0 ); diff --git a/servers/slapd/module.c b/servers/slapd/module.c index 71d93a300f..984f904948 100644 --- a/servers/slapd/module.c +++ b/servers/slapd/module.c @@ -7,19 +7,25 @@ #include -int load_null (const void *module, const char *file_name); -int load_extension (const void *module, const char *file_name); +typedef int (*MODULE_INIT_FN)( + int argc, + char *argv[]); +typedef int (*MODULE_LOAD_FN)( + const void *module, + const char *filename); +typedef int (*MODULE_TERM_FN)(void); + struct module_regtable_t { char *type; - int (*proc)(const void *module, const char *file_name); + MODULE_LOAD_FN proc; } module_regtable[] = { - { "null", load_null }, + { "null", load_null_module }, #ifdef SLAPD_EXTERNAL_EXTENSIONS - { "extension", load_extension }, + { "extension", load_extop_module }, #endif - { NULL, NULL } - }; + { NULL, NULL } +}; typedef struct module_loaded_t { struct module_loaded_t *next; @@ -28,7 +34,7 @@ typedef struct module_loaded_t { module_loaded_t *module_list = NULL; -int module_unload (module_loaded_t *module); +static int module_unload (module_loaded_t *module); int module_init (void) { @@ -60,7 +66,7 @@ int module_load(const char* file_name, int argc, char *argv[]) module_loaded_t *module = NULL; const char *error; int rc; - int (*initialize) LDAP_P((int argc, char *argv[])); + MODULE_INIT_FN initialize; module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t)); if (module == NULL) { @@ -153,10 +159,10 @@ void *module_resolve (const void *module, const char *name) return(lt_dlsym(((module_loaded_t *)module)->lib, name)); } -int module_unload (module_loaded_t *module) +static int module_unload (module_loaded_t *module) { module_loaded_t *mod; - int (*terminate) LDAP_P((void)); + MODULE_TERM_FN terminate; if (module != NULL) { /* remove module from tracking list */ @@ -188,5 +194,25 @@ int load_null (const void *module, const char *file_name) return 0; } +#ifdef SLAPD_EXTERNAL_EXTENSIONS +int +load_extop_module ( + const void *module, + const char *file_name +) +{ + ext_main = module_resolve(module, "ext_main"); + if (ext_main == NULL) { + return(-1); + } + + ext_getoid = module_resolve(module, "ext_getoid"); + if (ext_getoid == NULL) { + return(-1); + } + + return load_extop( ext_main, ext_getoid ); +} +#endif /* SLAPD_EXTERNAL_EXTENSIONS */ #endif /* SLAPD_MODULES */ diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c index 05d341cb9f..b06cd71e05 100644 --- a/servers/slapd/passwd.c +++ b/servers/slapd/passwd.c @@ -18,39 +18,131 @@ #include +static int passwd_main( + SLAP_EXTOP_CALLBACK_FN ext_callback, + Connection *conn, Operation *op, char *oid, + struct berval *reqdata, struct berval **rspdata, char **text ) +{ + int rc; + BerElement *ber; + struct berval *cred = NULL; + ber_int_t type; + + assert( oid != NULL ); + assert( strcmp( LDAP_EXOP_X_MODIFY_PASSWD, oid ) == 0 ); + + if( op->o_dn == NULL || op->o_dn[0] == '\0' ) { + *text = ch_strdup("only authenicated users may change passwords"); + return LDAP_STRONG_AUTH_REQUIRED; + } + + if( reqdata == NULL || reqdata->bv_len == 0 ) { + *text = ch_strdup("data missing"); + return LDAP_PROTOCOL_ERROR; + } + + ber = ber_init( reqdata ); + + if( ber == NULL ) { + *text = ch_strdup("password decoding error"); + return LDAP_PROTOCOL_ERROR; + } + + rc = ber_scanf(ber, "{iO}", &type, &cred ); + ber_free( ber, 1 ); + + if( rc == LBER_ERROR ) { + *text = ch_strdup("data decoding error"); + return LDAP_PROTOCOL_ERROR; + } + + if( cred == NULL || cred->bv_len == 0 ) { + *text = ch_strdup("password missing"); + return LDAP_PROTOCOL_ERROR; + } + + if( type != 0 ) { + ber_bvfree( cred ); + *text = ch_strdup("password type unknown"); + return LDAP_PROTOCOL_ERROR; + } + + if( conn->c_authz_backend != NULL && + conn->c_authz_backend->be_extended ) + { + rc = conn->c_authz_backend->be_extended( + conn->c_authz_backend, + conn, op, + oid, cred, rspdata, text ); + + } else { + *text = ch_strdup("operation not supported for current user"); + rc = LDAP_UNWILLING_TO_PERFORM; + } + + ber_bvfree( cred ); + return rc; +} + +int +slap_passwd_init( void ) +{ + return load_extop( LDAP_EXOP_X_MODIFY_PASSWD, passwd_main ); +} int slap_passwd_check( Attribute *a, - struct berval *cred -) + struct berval *cred ) { int i; for ( i = 0; a->a_vals[i] != NULL; i++ ) { - if ( a->a_syntax == SYNTAX_BIN ) { - int result; + int result; #ifdef SLAPD_CRYPT - ldap_pvt_thread_mutex_lock( &crypt_mutex ); + ldap_pvt_thread_mutex_lock( &crypt_mutex ); #endif - result = lutil_passwd( - (char*) cred->bv_val, - (char*) a->a_vals[i]->bv_val, - NULL ); + result = lutil_passwd( + a->a_vals[i]->bv_val, + cred->bv_val, + NULL ); #ifdef SLAPD_CRYPT - ldap_pvt_thread_mutex_unlock( &crypt_mutex ); + ldap_pvt_thread_mutex_unlock( &crypt_mutex ); #endif - return result; - - } else { - if ( value_cmp( a->a_vals[i], cred, a->a_syntax, 1 ) == 0 ) { - return( 0 ); - } - } + return result; } return( 1 ); } + +struct berval * slap_passwd_generate( + struct berval * cred ) +{ + char* hash = default_passwd_hash ? default_passwd_hash : "{SSHA}"; + + struct berval *new = ber_memalloc( sizeof(struct berval) ); + + if( new == NULL ) return NULL; + +#ifdef SLAPD_CRYPT + ldap_pvt_thread_mutex_lock( &crypt_mutex ); +#endif + + new->bv_val = lutil_passwd_generate( cred->bv_val , hash ); + +#ifdef SLAPD_CRYPT + ldap_pvt_thread_mutex_unlock( &crypt_mutex ); +#endif + + if( new->bv_val == NULL ) { + ber_bvfree( new ); + return NULL; + } + + new->bv_len = strlen( new->bv_val ); + + return new; +} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 9c33731773..e2d2bd8c0c 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -100,9 +100,13 @@ LIBSLAPD_F (int) be_entry_release_rw LDAP_P(( Backend *be, Entry *e, int rw )); #define be_entry_release_r( be, e ) be_entry_release_rw( be, e, 0 ) #define be_entry_release_w( be, e ) be_entry_release_rw( be, e, 1 ) - LIBSLAPD_F (int) backend_unbind LDAP_P((Connection *conn, Operation *op)); +LIBSLAPD_F( int ) backend_check_controls LDAP_P(( + Backend *be, + Connection *conn, + Operation *op )); + LIBSLAPD_F (int) backend_connection_init LDAP_P((Connection *conn)); LIBSLAPD_F (int) backend_connection_destroy LDAP_P((Connection *conn)); @@ -239,8 +243,32 @@ LIBSLAPD_F (int) entry_id_cmp LDAP_P(( Entry *a, Entry *b )); * extended.c */ -LIBSLAPD_F (int) load_extension LDAP_P((const void *module, const char *file_name)); -LIBSLAPD_F (char *) get_supported_extension LDAP_P((int index)); +#define SLAPD_EXTOP_GETVERSION 0 +#define SLAPD_EXTOP_GETPROTO 1 +#define SLAPD_EXTOP_GETAUTH 2 +#define SLAPD_EXTOP_GETDN 3 +#define SLAPD_EXTOP_GETCLIENT 4 + +typedef int (*SLAP_EXTOP_CALLBACK_FN) LDAP_P(( + Connection *conn, Operation *op, + int msg, int arg, void *argp )); + +typedef int (*SLAP_EXTOP_MAIN_FN) LDAP_P(( + SLAP_EXTOP_CALLBACK_FN, + Connection *conn, Operation *op, + char * oid, + struct berval * reqdata, + struct berval ** rspdata, + char ** text )); + +typedef int (*SLAP_EXTOP_GETOID_FN) LDAP_P(( + int index, char *oid, int blen )); + +LIBSLAPD_F (int) load_extop LDAP_P(( + const char *ext_oid, + SLAP_EXTOP_MAIN_FN ext_main )); + +LIBSLAPD_F (char *) get_supported_extop LDAP_P((int index)); /* * filter.c @@ -268,13 +296,23 @@ LIBSLAPD_F (int) lock_fclose LDAP_P(( FILE *fp, FILE *lfp )); */ #ifdef SLAPD_MODULES + LIBSLAPD_F (int) module_init LDAP_P(( void )); LIBSLAPD_F (int) module_kill LDAP_P(( void )); -LIBSLAPD_F (int) module_load LDAP_P(( const char* file_name, int argc, char *argv[] )); +LIBSLAPD_F (int) load_null_module( + const void *module, const char *file_name); +LIBSLAPD_F (int) load_extop_module( + const void *module, const char *file_name); + +LIBSLAPD_F (int) module_load LDAP_P(( + const char* file_name, + int argc, char *argv[] )); LIBSLAPD_F (int) module_path LDAP_P(( const char* path )); -LIBSLAPD_F (void) *module_resolve LDAP_P((const void *module, const char *name)); +LIBSLAPD_F (void) *module_resolve LDAP_P(( + const void *module, const char *name)); + #endif /* SLAPD_MODULES */ /* @@ -445,6 +483,8 @@ LIBSLAPD_F (void) slap_init_user LDAP_P(( char *username, char *groupname )); LIBSLAPD_F (int) slap_passwd_check( Attribute *attr, struct berval *cred ); +LIBSLAPD_F (struct berval *) slap_passwd_generate( + struct berval *cred ); /* * kerberos.c @@ -470,6 +510,7 @@ LIBSLAPD_F (int) global_lastmod; LIBSLAPD_F (int) global_idletimeout; LIBSLAPD_F (int) global_schemacheck; LIBSLAPD_F (char) *global_realm; +LIBSLAPD_F (char) *default_passwd_hash; LIBSLAPD_F (int) lber_debug; LIBSLAPD_F (int) ldap_syslog; diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 37faa5181e..3c142748d4 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -241,7 +241,7 @@ send_ldap_response( const char *text, struct berval **ref, const char *resoid, - struct berval *resdata, + struct berval *data, LDAPControl **ctrls ) { @@ -281,9 +281,8 @@ send_ldap_response( rc = ber_printf( ber, "s", resoid ); } - if( rc != -1 && resdata != NULL ) { - rc = ber_printf( ber, "O", resdata ); - + if( rc != -1 && data != NULL ) { + rc = ber_printf( ber, "O", data ); } if( rc != -1 ) { diff --git a/servers/slapd/root_dse.c b/servers/slapd/root_dse.c index 8b296ecc7f..5d688c936d 100644 --- a/servers/slapd/root_dse.c +++ b/servers/slapd/root_dse.c @@ -74,7 +74,7 @@ root_dse_info( Connection *conn, Operation *op, char **attrs, int attrsonly ) } /* supportedExtension */ - for ( i=0; (val.bv_val = get_supported_extension(i)) != NULL; i++ ) { + for ( i=0; (val.bv_val = get_supported_extop(i)) != NULL; i++ ) { val.bv_len = strlen( val.bv_val ); attr_merge( e, "supportedExtension", vals ); } diff --git a/servers/slapd/search.c b/servers/slapd/search.c index 233da67a2d..10e6d67b27 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -204,6 +204,14 @@ do_search( goto return_results; } + /* make sure this backend recongizes critical controls */ + rc = backend_check_controls( be, conn, op ) ; + + if( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, + NULL, NULL, NULL, NULL ); + } + /* deref the base if needed */ nbase = suffix_alias( be, nbase ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 5435af855c..b9f7ea5de4 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -66,6 +66,9 @@ LDAP_BEGIN_DECL #define MAXREMATCHES 10 +/* psuedo error code to indicating abandoned operation */ +#define SLAPD_ABANDON -1 + /* XXYYZ: these macros assume 'x' is an ASCII x */ #define DNSEPARATOR(c) ((c) == ',' || (c) == ';') #define SEPARATOR(c) ((c) == ',' || (c) == ';' || (c) == '+') @@ -482,9 +485,13 @@ struct slap_backend_db { #define be_modrdn bd_info->bi_op_modrdn #define be_search bd_info->bi_op_search +#define be_extended bd_info->bi_extended + #define be_release bd_info->bi_entry_release_rw #define be_group bd_info->bi_acl_group +#define be_controls bd_info->bi_controls + #define be_connection_init bd_info->bi_connection_init #define be_connection_destroy bd_info->bi_connection_destroy @@ -524,6 +531,15 @@ struct slap_backend_db { void *be_private; /* anything the backend database needs */ }; +typedef int (*SLAP_EXTENDED_FN) LDAP_P(( + Backend *be, + struct slap_conn *conn, + struct slap_op *op, + char *oid, + struct berval * reqdata, + struct berval ** rspdata, + char** text )); + struct slap_backend_info { char *bi_type; /* type of backend */ @@ -615,6 +631,9 @@ struct slap_backend_info { struct slap_conn *c, struct slap_op *o, ber_int_t msgid)); + /* Extended Operations Helper */ + SLAP_EXTENDED_FN bi_extended; + /* Auxilary Functions */ int (*bi_entry_release_rw) LDAP_P((BackendDB *bd, Entry *e, int rw)); @@ -642,6 +661,8 @@ struct slap_backend_info { #define SLAP_INDEX_ADD_OP 0x0001 #define SLAP_INDEX_DELETE_OP 0x0002 + char **bi_controls; /* supported controls */ + unsigned int bi_nDB; /* number of databases of this type */ void *bi_private; /* anything the backend type needs */ }; @@ -662,9 +683,19 @@ typedef struct slap_op { time_t o_time; /* time op was initiated */ int o_bind_in_progress; /* multi-step bind in progress */ +#ifdef SLAP_AUTHZID + /* should only be used for reporting purposes */ + char *o_authc_dn; /* authentication DN */ + /* should be used as the DN of the User */ + char *o_authz_dn; /* authorization DN */ + char *o_authz_ndn; /* authorizaiton NDN */ + +#else char *o_dn; /* dn bound when op was initiated */ char *o_ndn; /* normalized dn bound when op was initiated */ +#endif + ber_int_t o_protocol; /* version of the LDAP protocol used by client */ ber_tag_t o_authtype; /* auth method used to bind dn */ /* values taken from ldap.h */ @@ -709,19 +740,35 @@ typedef struct slap_conn { char *c_peer_name; /* peer name (trans=addr:port) */ char *c_sock_name; /* sock name (trans=addr:port) */ + /* only can be changed by binding thread */ + int c_bind_in_progress; /* multi-op bind in progress */ #ifdef HAVE_CYRUS_SASL sasl_conn_t *c_sasl_context; #endif + void *c_authstate; /* SASL state data */ - /* only can be changed by binding thread */ - int c_bind_in_progress; /* multi-op bind in progress */ + Backend *c_authc_backend; + + /* authorization backend */ + Backend *c_authz_backend; + +#ifdef SLAP_AUTHZID + /* authentication backend */ + /* should only be used for reporting purposes */ + char *c_authc_dn; /* authentication DN */ + /* should be used as the DN of the User */ + char *c_authz_dn; /* authorization DN */ + char *c_authz_ndn; /* authorization NDN */ + +#else char *c_cdn; /* DN provided by the client */ char *c_dn; /* DN bound to this conn */ +#endif + ber_int_t c_protocol; /* version of the LDAP protocol used by client */ ber_tag_t c_authtype;/* auth method used to bind c_dn */ char *c_authmech; /* SASL mechanism used to bind c_dn */ - void *c_authstate; /* SASL state data */ Operation *c_ops; /* list of operations being processed */ Operation *c_pending_ops; /* list of pending operations */ diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 00473ec404..49baf569b9 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -53,7 +53,9 @@ SLAPD_OBJS = ../config.o ../ch_malloc.o ../backend.o ../charray.o \ ../module.o ../aclparse.o ../schema.o ../filterentry.o \ ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \ ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \ - ../controls.o ../schemaparse.o ../kerberos.o ../passwd.o + ../controls.o ../schemaparse.o ../kerberos.o ../passwd.o \ + ../extended.o + SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o EDB2LDIFSRCS = edb2ldif.c ldapsyntax.c