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,48 +114,33 @@ 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]); + if( newpw == NULL ) { + /* prompt for new password */ + char *cknewpw; + newpw = strdup(getpass("New password: ")); + cknewpw = getpass("Re-enter new password: "); - /* check for target(s) */ - if (!filtpattern && !targetdn) - targetdn = binddn; + 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) - bindpw = strdup (getpass ("Enter LDAP password: ")); - - /* handle new password */ - if (!newpw) - { - char *cknewpw; - 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 (want_bindpw) { + fprintf( stderr, "Bind DN: %s\n", binddn ); + bindpw = strdup( getpass("Enter bind password: ")); } if ( 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; + ber_printf( ber, "{es}", + (ber_int_t) 0, + newpw ); - /* 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 ); - } + rc = ber_flatten( ber, &bv ); - 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); - } - } + 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( +struct pw_scheme; + +typedef int (*PASSWD_CHK_FUNC)( + const struct pw_scheme *scheme, + const char *passwd, + const char *cred ); + +typedef char * (*PASSWD_GEN_FUNC) ( + const struct pw_scheme *scheme, + const char *passwd ); + +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 }, + +#ifdef SLAPD_CRYPT + { "{CRYPT}", sizeof("{CRYPT}")-1, chk_crypt, gen_crypt }, +#endif +# if defined( HAVE_GETSPNAM ) \ + || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) ) + { "{UNIX}", sizeof("{UNIX}")-1, chk_unix, NULL }, +#endif + +#ifdef SLAPD_CLEARTEXT + /* psuedo scheme */ + { "{CLEARTEXT}", 0, NULL, NULL }, +#endif + + NULL, +}; + +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 int is_allowed_scheme( const char* scheme, const char** schemes ) { int i; - if(schemes == NULL) { - return 1; - } + if( schemes == NULL ) return 1; - for(i=0; schemes[i] != NULL; i++) { - if(strcasecmp(scheme, schemes[i]) == 0) { + for( i=0; schemes[i] != NULL; i++ ) { + if( strcasecmp( scheme, schemes[i] ) == 0 ) { return 1; } } - return 0; } -const char *lutil_passwd_schemes[] = { -#ifdef SLAPD_CRYPT - "{CRYPT}", -#endif - "{MD5}", "{SMD5}", - "{SHA}", "{SSHA}", -# if defined( HAVE_GETSPNAM ) \ - || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) ) - "{UNIX}", -#endif -#ifdef SLAPD_CLEARTEXT - "{CLEARTEXT}", /* psuedo scheme */ -#endif - NULL, -}; - -int lutil_passwd_scheme( char *scheme ) { - return is_allowed_scheme( scheme, lutil_passwd_schemes ); -} - static const char *passwd_scheme( + const struct pw_scheme *scheme, const char* passwd, - const char* scheme, - const char** schemes ) + const char** allowed ) { - int len; - - if( !is_allowed_scheme( scheme, schemes ) ) { + if( !is_allowed_scheme( scheme->name, allowed ) ) { return NULL; } - len = strlen(scheme); - - 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)]; + 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 ); - 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 ); + if( p != NULL ) { + return (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred ); + } } - - return( strcmp(p, base64digest) ); - - } 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); - - if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest), - base64digest, sizeof(base64digest)) < 0) - { - return ( 1 ); - } - - return( strcmp(p, base64digest) ); - - } 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; - - /* 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 ); - } - - /* 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 ); - } - - /* 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 ); - -#ifdef SLAPD_CRYPT - } else if ((p = passwd_scheme( passwd, "{CRYPT}", schemes )) != NULL ) { - return( strcmp(p, crypt(cred, p)) ); - -# if defined( HAVE_GETSPNAM ) \ - || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) ) - } else if ((p = passwd_scheme( passwd, "{UNIX}", schemes )) != NULL ) { - -# ifdef HAVE_GETSPNAM - struct spwd *spwd = getspnam(p); - - if(spwd == NULL) { - return 1; /* not found */ - } - - return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp)); -# else - struct passwd *pwd = getpwnam(p); - - if(pwd == NULL) { - return 1; /* not found */ - } - - return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd)); -# endif -# endif -#endif } #ifdef SLAPD_CLEARTEXT - return is_allowed_scheme("{CLEARTEXT}", schemes ) && - strcmp(passwd, cred) != 0; + if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) { + return strcmp( cred, passwd ); + } #else - return( 1 ); + return 1; #endif } + +char * lutil_passwd_generate( + const char * passwd, + const char * method ) +{ + const struct pw_scheme *sc = get_scheme( method ); + + 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; + } + + 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; + } + + 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(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); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); + free(orig_pass); + return rc; +} + +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 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 +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 ) ) +static int chk_unix( + const struct pw_scheme *sc, + const char* cred, + const char* p ) +{ +# ifdef HAVE_GETSPNAM + struct spwd *spwd = getspnam(p); + + if(spwd == NULL) { + return 1; /* not found */ + } + + return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp)); +# else + struct passwd *pwd = getpwnam(p); + + if(pwd == NULL) { + return 1; /* not found */ + } + + 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; + } + + 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; + SLAP_EXTOP_MAIN_FN ext_main; +} extop_list_t; -extensions_list_t *supp_ext_list = NULL; +extop_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); - -#else - -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( rc != SLAPD_ABANDON ) { + send_ldap_extended( conn, op, rc, NULL, text, + oid, rspdata ); + } + + if ( rspdata != NULL ) + ber_bvfree( rspdata ); - if (rspoid != NULL) - free(rspoid); - if ( rspdata.bv_val != NULL ) - free(rspdata.bv_val); if ( text != NULL ) free(text); -#else - send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR, - NULL, "unsupported extended operation", NULL, NULL ); - -#endif - 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