Merge branch 'debian'
[hcoop/debian/courier-authlib.git] / authldaplib.c
diff --git a/authldaplib.c b/authldaplib.c
deleted file mode 100644 (file)
index 39b0245..0000000
+++ /dev/null
@@ -1,2067 +0,0 @@
-/*
- * authldap.c - 
- *
- * courier-imap - 
- * 
- * Copyright 1999 Luc Saillard <luc.saillard@alcove.fr>.
- *
- * This module use a server LDAP to authenticate user.
- * See the README.ldap
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
- *
- * See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301, USA.
- */
-
-/*
- * Modified 28/11/2001 Iustin Pop <iusty@intensit.de>
- * There was a bug regarding the LDAP_TLS option: if both LDAP_TLS
- * and was LDAP_AUTHBIND were enabled, the ldap_start_tls function
- * was called only for the first connection, resulting in the fact
- * that the bind for checking the password was done without TLS,
- * sending the password in clear text over the network. Detected 
- * when using OpenLDAP with "security ssf=128" (which disalows any 
- * clear-text communication).
-*/
-
-/*
-   Modified 01/21/2000 James Golovich <james@wwnet.net>
-
-1. If LDAP_AUTHBIND is set in the config file, then the ldap server will
-handle passwords via authenticated binds, instead of checking these
-internally.
-2. Changed paramaters for authldap_get to include pass.
-
-*/
-
-/*
-   Modified 12/31/99 Sam Varshavchik:
-
-1. read_env reads from a configuration file, instead of the environment
-2. read_config appropriately modified.
-3. If 'user' contains the @ character, domain from config is NOT appended.
-4. added 'homeDir' attribute.  Use 'homeDir' instead of mailDir, and put
-   mailDir into MAILDIR=
-5. read_config renamed to authldap_read_config
-6. get_user_info renamed to authldap_get
-7. Added authldap_free_config, to clean up all the allocated memory
-   (required for preauthldap).
-8. Output LDAP attributes are defined in the configuration file as well.
-9. Allow both plaintext and crypted passwords to be read from LDAP.
-10. Added GLOB_UID GLOB_GID, as well as UID and GID params.
-
-2/19/2000 Sam.
-
-Rewrite to allow this code to be used in a long-running authentication daemon
-(for Courier).  authldap_get renamed to authldapcommon, will initialize and
-maintain a persistent connection.  Password checking moved entirely to
-authldap.c.  authldapclose() will unbind and close the connection.
-
-connection gets closed and reopened automatically after a protocol error.
-
-error return from authldapcommon will indicate whether this is a transient,
-or a permanent failure.
-
-authldap_free_config removed - no longer required.
-
-*/
-
-#if HAVE_CONFIG_H
-#include "courier_auth_config.h"
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
-#include <time.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_LBER_H
-#include <lber.h>
-#endif
-#if HAVE_LDAP_H
-#include <ldap.h>
-#if LDAP_VENDOR_VERSION > 20000
-#define OPENLDAPV2
-#endif
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#include "authldap.h"
-#include "auth.h"
-#include "authldaprc.h"
-#include "courierauthdebug.h"
-
-#define err courier_auth_err
-
-#ifndef DEBUG_LDAP
-#define DEBUG_LDAP 0
-#endif
-
-#ifndef        LDAP_OPT_SUCCESS
-#define LDAP_OPT_SUCCESS LDAP_SUCCESS
-#endif
-
-static char **l_get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
-{
-       struct berval **p=ldap_get_values_len(ld, entry, attribut);
-       int i, n;
-       char **a;
-
-       if (!p)
-               return NULL;
-
-       n=ldap_count_values_len(p);
-
-
-       a=malloc((n + 1) * sizeof(char *));
-
-       if (!a)
-       {
-               DPRINTF("malloc failed");
-               ldap_value_free_len(p);
-               return NULL;
-       }
-
-       for (i=0; i<n; i++)
-       {
-               if ((a[i]=malloc(p[i]->bv_len+1)) == NULL)
-               {
-                       DPRINTF("malloc failed");
-                       while (i--)
-                       {
-                               free(a[i]);
-                       }
-                       free(a);
-                       ldap_value_free_len(p);
-                       return NULL;
-               }
-
-               memcpy(a[i], p[i]->bv_val, p[i]->bv_len);
-               a[i][p[i]->bv_len]=0;
-       }
-
-       ldap_value_free_len(p);
-       a[i]=NULL;
-       return a;
-}
-
-static void l_value_free(char **p)
-{
-       int i;
-
-       for (i=0; p[i]; ++i)
-               free(p[i]);
-       free(p);
-}
-
-static int l_count_values(char **p)
-{
-       int i;
-
-       for (i=0; p[i]; ++i)
-               ;
-       return i;
-}
-
-static int l_unbind(LDAP *ld)
-{
-       return ldap_unbind_ext(ld, NULL, NULL);
-}
-
-static int l_simple_bind_s(LDAP *ld,
-                          const char *who,
-                          const char *passwd)
-{
-       struct berval cred;
-
-       cred.bv_len=passwd ? strlen(passwd):0;
-       cred.bv_val=(char *)passwd;
-
-       return ldap_sasl_bind_s(ld, who, NULL, &cred, NULL, NULL, NULL);
-}
-
-static int l_search_st(LDAP *ld,
-                      const char *base,
-                      int scope,
-                      const char *filter,
-                      char **attrs,
-                      int attrsonly,
-                      struct timeval *timeout,
-                      LDAPMessage **res)
-{
-       return ldap_search_ext_s(ld, base, scope, filter, attrs,
-                                attrsonly,
-                                NULL, NULL,
-                                timeout,
-                                100,
-                                res);
-}
-
-static int l_modify_s(LDAP *ld,
-                     const char *dn,
-                     LDAPMod **mods)
-{
-       return ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
-}
-
-static int l_search(LDAP *ld,
-                   const char *base,
-                   int scope,
-                   const char *filter,
-                   char **attrs,
-                   int attrsonly)
-{
-       struct timeval tv;
-       int msgid;
-
-       tv.tv_sec=60*60;
-       tv.tv_usec=0;
-
-       if (ldap_search_ext(ld, base, scope, filter, attrs, attrsonly,
-                           NULL, NULL, &tv, 1000000, &msgid) !=
-           LDAP_SUCCESS)
-               return -1;
-
-       return msgid;
-}
-
-struct ldap_info
-{
-       const char *uri;
-       const char *binddn;
-       const char *bindpw;
-       const char *basedn;
-       const char *mail;
-        const char *filter;
-        const char *enumerate_filter;
-       const char *domain;
-
-       uid_t uid;
-       gid_t gid;
-       int   timeout;
-       int   authbind;
-        int   initbind;
-       int   deref;
-       int   protocol_version;
-       int   tls;
-
-       const char *mailroot;
-
-       char **auxoptions;
-       char **auxnames;
-       const char **attrlist;
-
-       /* Optional emailmap to handle */
-
-       const char *emailmap;
-       const char *emailmap_basedn;
-       const char *emailmap_handle;
-       const char *emailmap_handle_lookup;
-};
-
-/*
-** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
-** too.  See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
-** information.  To work around the bug, the first time a connection fails
-** we stop trying for 60 seconds.  After 60 seconds we kill the process,
-** and let the parent process restart it.
-**
-** We'll control this behavior via LDAP_MEMORY_LEAK.  Set it to ZERO to turn
-** off this behavior (whenever OpenLDAP gets fixed).
-*/
-
-static time_t ldapfailflag=0;
-
-static void ldapconnfailure()
-{
-       const char *p=getenv("LDAP_MEMORY_LEAK");
-
-       if (!p)
-       {
-#ifdef LDAP_VENDOR_NAME
-#ifdef LDAP_VENDOR_VERSION
-#define DO_OPENLDAP_CHECK
-#endif
-#endif
-
-#ifdef DO_OPENLDAP_CHECK
-
-               /* It's supposed to be fixed in 20019 */
-
-               if (strcmp(LDAP_VENDOR_NAME, "OpenLDAP") == 0 &&
-                   LDAP_VENDOR_VERSION < 20019)
-                       p="1";
-               else
-                       p="0";
-#else
-               p="0";
-#endif
-       }
-
-       if (atoi(p) && !ldapfailflag)
-       {
-               time(&ldapfailflag);
-               ldapfailflag += 60;
-       }
-}
-
-static int ldapconncheck()
-{
-       time_t t;
-
-       if (!ldapfailflag)
-               return (0);
-
-       time(&t);
-
-       if (t >= ldapfailflag)
-               exit(0);
-       return (1);
-}
-
-static int read_env(const char *env, const char **copy,
-       const char *errstr, int needit, const char *value_default);
-static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
-       char **copy, const char *username);
-
-/*
- * Function: read_env
- * Copy the environnement $env and copy to $copy if not null
- * if needit is false, and env doesn't exist, copy $value_default to $copy
- * INPUT:
- *   $env: pointer to the environnement name
- *   $copy: where the value go
- *   $err: print a nice message when $env not_found and $needit is true
- *   $needit: if $needit is true and $value not found, return a error
- *   $value_default: the default value when $needit is false and $env doesn't exists
- * OUTPUT:
- *   boolean
- */
-static int read_env(const char *env, const char **copy,
-       const char *errstr, int needit, const char *value_default)
-{
-static char *ldapauth=0;
-static size_t ldapauth_size=0;
-size_t i;
-char   *p=0;
-int    l=strlen(env);
-
-       if (!ldapauth)
-       {
-       FILE    *f=fopen(AUTHLDAPRC, "r");
-       struct  stat    buf;
-
-               if (!f) return (0);
-               if (fstat(fileno(f), &buf) ||
-                       (ldapauth=malloc(buf.st_size+2)) == 0)
-               {
-                       fclose(f);
-                       return (0);
-               }
-               if (fread(ldapauth, buf.st_size, 1, f) != 1)
-               {
-                       free(ldapauth);
-                       ldapauth=0;
-                       fclose(f);
-                       return (0);
-               }
-               ldapauth[ldapauth_size=buf.st_size]=0;
-
-               for (i=0; i<ldapauth_size; i++)
-                       if (ldapauth[i] == '\n')
-                               ldapauth[i]=0;
-               fclose(f);
-       }
-
-       for (i=0; i<ldapauth_size; )
-       {
-               p=ldapauth+i;
-               if (memcmp(p, env, l) == 0 &&
-                       isspace((int)(unsigned char)p[l]))
-               {
-                       p += l;
-                       while (*p && *p != '\n' &&
-                               isspace((int)(unsigned char)*p))
-                               ++p;
-                       break;
-               }
-
-               while (i < ldapauth_size)
-                       if (ldapauth[i++] == 0) break;
-       }
-
-       if (i < ldapauth_size)
-       {
-               *copy= p;
-               return (1);
-       }
-
-       if (needit)
-       {
-               err("%s", errstr);
-               return 0;
-       }
-
-       *copy=0;
-       if (value_default)
-               *copy=value_default;
-
-       return 1;
-}
-
-/*
- * Function: authldap_read_config
- *   Read Configuration from the environnement table
- * INPUT:
- *   $ldap: a structure where we place information
- * OUTPUT:
- *   boolean
- */
-static int authldap_read_config(struct ldap_info *ldap)
-{
-       struct passwd *pwent;
-       struct group  *grent;
-       const char *p;
-       size_t i, pass;
-
-       for (i=0; ldap->auxoptions && ldap->auxoptions[i]; i++)
-               free(ldap->auxoptions[i]);
-       for (i=0; ldap->auxnames && ldap->auxnames[i]; i++)
-               free(ldap->auxnames[i]);
-
-       if (ldap->attrlist)
-               free(ldap->attrlist);
-       if (ldap->auxnames)
-               free(ldap->auxnames);
-       if (ldap->auxoptions)
-               free(ldap->auxoptions);
-
-       memset(ldap,0,sizeof(struct ldap_info));
-       
-       if (!read_env("LDAP_URI",&ldap->uri,
-                     "You need to specify LDAP_URI in config file",1,NULL))
-               return 0;
-
-       if (!read_env("LDAP_AUTHBIND", &p, "", 0, ""))
-               return (0);
-
-       if (p)
-               sscanf(p,"%d",&ldap->authbind);
-
-       if (!read_env("LDAP_INITBIND", &p, "", 0, "1"))
-               return (0);
-
-       if (p)
-               sscanf(p,"%d",&ldap->initbind);
-
-       if (!read_env("LDAP_BASEDN",&ldap->basedn,
-                     "You need to specify a basedn in config file",1,NULL))
-               return 0;
-       if (!read_env("LDAP_BINDDN",&ldap->binddn,
-                     "You need to specify a BINDDN in config file",0,NULL))
-               return 0;
-       if (!read_env("LDAP_BINDPW",&ldap->bindpw,
-                     "You need to specify a password for the BINDDN in config file",0,NULL))
-               return 0;
-       if (!read_env("LDAP_MAIL",&ldap->mail,
-                     "You need to specify a attribute for mail in config file",0,"mail"))
-               return 0;
-       if (!read_env("LDAP_DOMAIN",&ldap->domain,
-                     "You need to specify a domain for mail in config file",0,""))
-               return 0;
-
-       p=0;
-       ldap->uid=0;
-       if (!read_env("LDAP_GLOB_UID", &p, "", 0, ""))
-               return (0);
-
-       if (p && *p)
-       {
-               unsigned long n;
-
-               if (sscanf(p, "%lu", &n) == 1)
-                       ldap->uid=(uid_t)n;
-               else
-               {
-                       pwent=getpwnam(p);
-                       if (!pwent)
-                       {
-                               err("authldap: INVALID LDAP_GLOB_UID");
-                               return (0);
-                       }
-                       ldap->uid=pwent->pw_uid;
-               }
-       }
-
-       ldap->gid=0;
-       p=0;
-       if (!read_env("LDAP_GLOB_GID", &p, "", 0, ""))
-               return (0);
-
-       if (p && *p)
-       {
-               unsigned long n;
-
-               if (sscanf(p, "%lu", &n) == 1)
-                       ldap->gid=(gid_t)n;
-               else
-               {
-                       grent=getgrnam(p);
-                       if (!grent)
-                       {
-                               err("authldap: INVALID LDAP_GLOB_GID");
-                               return (0);
-                       }
-                       ldap->gid=grent->gr_gid;
-               }
-       }
-
-       ldap->timeout=5;
-       p=0;
-       if (read_env("LDAP_TIMEOUT", &p, "", 0, "") && p)
-       {
-               sscanf(p,"%d",&ldap->timeout);
-       }
-
-       ldap->tls=0;
-       p=0;
-       if (read_env("LDAP_TLS", &p, "", 0, "") && p)
-       {
-               ldap->tls=atoi(p);
-       }
-
-       ldap->filter=0;
-       p=0;
-       if (read_env("LDAP_FILTER", &p, "", 0, "") && p && strlen (p))
-       {
-               ldap->filter=p;
-       }
-
-       ldap->enumerate_filter=0;
-       p=0;
-       if (read_env("LDAP_ENUMERATE_FILTER", &p, "", 0, "") && p && strlen (p))
-       {
-               ldap->enumerate_filter=p;
-       }
-       else if (ldap->filter)
-       {
-               ldap->enumerate_filter=ldap->filter;
-       }
-       else
-       {
-               ldap->enumerate_filter = malloc(strlen(ldap->mail)+3);
-               if (!ldap->enumerate_filter)
-               {
-                       perror("CRIT: authldap: malloc failed");
-                       return 0;
-               }
-               sprintf((char *)ldap->enumerate_filter, "%s=*", ldap->mail);
-       }
-
-       ldap->deref = LDAP_DEREF_NEVER; 
-       ldap->protocol_version = 0;     /* use API default */
-       p=0;
-       if (!read_env("LDAP_DEREF", &p, "", 0, ""))
-               return (0);
-       if (p)
-       {
-#ifndef LDAP_OPT_DEREF
-               err("authldaplib: LDAP_OPT_DEREF not available, ignored");
-#endif
-               if (!strcasecmp (p, "never"))
-                       ldap->deref = LDAP_DEREF_NEVER;
-               else if (!strcasecmp (p, "searching"))
-                       ldap->deref = LDAP_DEREF_SEARCHING;
-               else if (!strcasecmp (p, "finding"))
-                       ldap->deref = LDAP_DEREF_FINDING;
-               else if (!strcasecmp (p, "always"))
-                       ldap->deref = LDAP_DEREF_ALWAYS; 
-       }
-
-       if (!read_env("LDAP_PROTOCOL_VERSION", &p, 0, 0, 0))
-               return (0);
-       if (p)
-       {
-       int lpv = atoi(p);
-#ifndef LDAP_OPT_PROTOCOL_VERSION
-               err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
-#endif
-               if (lpv == 0
-#ifdef LDAP_VERSION_MIN
-                       || lpv < LDAP_VERSION_MIN
-#endif
-#ifdef LDAP_VERSION_MAX
-                       || lpv > LDAP_VERSION_MAX
-#endif
-               )
-                       err("authldaplib: illegal protocol version ignored");
-               else
-                       ldap->protocol_version = lpv;
-       }
-
-       if (!read_env("LDAP_MAILROOT",&ldap->mailroot,"",0,NULL)
-           || ldap->mailroot == NULL || ldap->mailroot[0] == 0)
-               ldap->mailroot=NULL;
-
-       if (!read_env("LDAP_EMAILMAP", &ldap->emailmap, "", 0, "") ||
-           !read_env("LDAP_EMAILMAP_BASEDN", &ldap->emailmap_basedn, "", 0, "") ||
-           !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap->emailmap_handle, "", 0, "")||
-           !read_env("LDAP_EMAILMAP_MAIL",
-                     &ldap->emailmap_handle_lookup, "", 0, ""))
-               return (0);
-
-
-       for (pass=0; pass<2; pass++)
-       {
-               if (pass)
-               {
-                       if ((ldap->auxnames=malloc((i+1)*sizeof(char *)))
-                           == NULL ||
-                           (ldap->auxoptions=malloc((i+1)*sizeof(char *)))
-                           == NULL)
-                       {
-                               perror("CRIT: authldap: malloc failed");
-                               if (ldap->auxnames)
-                                       ldap->auxnames[0]=0;
-                               return 0;
-                       }
-               }
-               i=0;
-
-               if (pass)
-               {
-                       ldap->auxnames[0]=NULL;
-                       ldap->auxoptions[0]=NULL;
-               }
-
-               if (!read_env("LDAP_AUXOPTIONS", &p, "", 0, NULL)
-                   || p == NULL || *p == 0)
-                       p=NULL;
-
-               while (p && *p)
-               {
-                       size_t n;
-
-                       if (*p == ',')
-                       {
-                               ++p;
-                               continue;
-                       }
-
-                       for (n=0; p[n] && p[n] != ',' && p[n] != '='; n++)
-                               ;
-
-                       if (pass)
-                       {
-                               if ((ldap->auxoptions[i]=malloc(n+1)) == NULL)
-                               {
-                                       perror("CRIT: authldap: malloc failed");
-                                       return 0;
-                               }
-
-                               memcpy(ldap->auxoptions[i], p, n);
-                               ldap->auxoptions[i][n]=0;
-                               ldap->auxoptions[i+1]=NULL;
-                       }
-
-                       p += n;
-
-                       if (*p == '=') ++p;
-
-                       for (n=0; p[n] && p[n] != ','; n++)
-                               ;
-
-                       if (pass)
-                       {
-                               if (n == 0)
-                               {
-                                       if ((ldap->auxnames[i]=
-                                            strdup(ldap->auxoptions[i]))
-                                           == NULL)
-                                       {
-                                               perror("CRIT: authldap: malloc failed");
-                                               return 0;
-                                       }
-                               }
-                               else if ((ldap->auxnames[i]=malloc(n+1)) == NULL)
-                               {
-                                       perror("CRIT: authldap: malloc failed");
-                                       return 0;
-                               }
-                               else
-                               {
-                                       memcpy(ldap->auxnames[i], p, n);
-                                       ldap->auxnames[i][n]=0;
-                                       ldap->auxnames[i+1]=NULL;
-                               }
-                       }
-                       p += n;
-                       ++i;
-               }
-       }
-
-       if ((ldap->attrlist=malloc((i+20)*sizeof(const char *))) == NULL)
-       {
-               perror("CRIT: authldap: malloc failed");
-               return 0;
-       }
-
-       return 1;
-}
-
-static void get_error(LDAP *ld, LDAPMessage *entry,
-                     const char *func,
-                     const char *attribut)
-{
-#if HAVE_LDAP_PARSE_RESULT
-
-       int errcode;
-       char *nmatched;
-       char *errmsg;
-               
-
-       if (ldap_parse_result(ld, entry, &errcode, &nmatched,
-                             &errmsg, NULL, NULL, 0)
-           != LDAP_SUCCESS)
-       {
-               DPRINTF("ldap_parseresult failed");
-       }
-       else
-       {
-               if (errcode && errcode != LDAP_DECODING_ERROR &&
-                   errcode != LDAP_NO_RESULTS_RETURNED)
-               {
-                       DPRINTF("get_values attribute %s: %s",
-                               attribut,
-                               errmsg ? errmsg:"unknown error");
-               }
-
-               if (errmsg)
-                       ldap_memfree(errmsg);
-               if (nmatched)
-                       ldap_memfree(nmatched);
-       }
-#else
-#if HAVE_LDAP_RESULT2ERROR
-       int ld_errno = ldap_result2error(ld,entry,0);
-       if (ld_errno && ld_errno != LDAP_DECODING_ERROR
-           && ld_errno != LDAP_NO_RESULTS_RETURNED)
-       {
-               DPRINTF("get_values attribute %s: %s", attribut,
-                       ldap_err2string(ld_errno));
-       }
-#else
-       if (ld->ld_errno != LDAP_DECODING_ERROR
-           && ld->ld_errno != LDAP_NO_RESULTS_RETURNED)
-       {
-               DPRINTF("get_values attribute %s: %s", attribut,
-                       ldap_err2string(ld->ld_errno));
-       }
-#endif
-#endif
-}
-
-static char **get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
-{
-       char ** values;
-       values=l_get_values(ld,entry, (char *)attribut);
-
-       if (values==NULL)
-       {
-               get_error(ld, entry, "get_values", attribut);
-       }
-
-       return values;
-}
-
-
-
-/*
- * Function: copy_value
- *   Copy value from a LDAP attribute to $copy
- * INPUT:
- *   $ld:       the connection with the LDAP server
- *   $entry:    the entry who contains attributes
- *   $attribut: this attribut
- *   $copy:     where data can go
- * OUTPUT:
- *   void
- */
-static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
-                      char **copy, const char *username)
-{
-       char ** values;
-       values=l_get_values(ld,entry, attribut);
-
-       if (values==NULL)
-       {
-               get_error(ld, entry, "copy_value ", attribut);
-               *copy=NULL;
-               return;
-       }
-  /* We accept only attribute with one value */
-       else if (l_count_values(values)>1)
-        {
-                *copy=strdup(values[0]);
-                fprintf(stderr, "WARN: authldaplib: duplicate attribute %s for %s\n",
-                       attribut,
-                       username);
-                *copy=NULL;
-        }
-  /* We accept only attribute with one value */
-       else if (l_count_values(values)!=1)
-        {
-                *copy=NULL;
-        }
-  else
-        {
-                *copy=strdup(values[0]);
-        }
-#if DEBUG_LDAP
-  DPRINTF("copy_value %s: %s",attribut,values[0]);
-#endif
-  l_value_free(values);
-}
-
-static struct ldap_info my_ldap;
-static LDAP *my_ldap_fp=0;
-static LDAP *bindp=0;  /* for checking passwords with AUTHBIND */
-
-void authldapclose()
-{
-       if (my_ldap_fp)
-       {
-               l_unbind(my_ldap_fp);
-               my_ldap_fp=0;
-       }
-       if (bindp)
-       {
-               l_unbind(bindp);
-               bindp=0;
-       }
-}
-
-static int ldaperror(int rc)
-{
-#ifdef OPENLDAPV2
-       if (rc && !LDAP_NAME_ERROR(rc))
-#else
-       if (rc && !NAME_ERROR(rc))
-#endif
-       {
-               /* If there was a protocol error, close the connection */
-               authldapclose();
-               ldapconnfailure();
-       }
-       return (rc);
-}
-
-/* This function takes a ldap connection and 
- * tries to enable TLS on it.
-*/
-static int enable_tls_on(LDAP *conn) {
-#if HAVE_LDAP_TLS
-       int version;
-       int ldrc;
-
-       if (ldaperror(ldrc=ldap_get_option (conn,
-                                   LDAP_OPT_PROTOCOL_VERSION,
-                                   &version))
-           != LDAP_SUCCESS)
-       {
-               const char *s=ldap_err2string(ldrc);
-
-               err("ldap_get_option failed: %s", s);
-               return (-1);
-       }
-
-       if (version < LDAP_VERSION3)
-       {
-               version = LDAP_VERSION3;
-               (void)ldap_set_option (conn,
-                                      LDAP_OPT_PROTOCOL_VERSION,
-                                      &version);
-       }
-
-       if (ldaperror(ldrc=ldap_start_tls_s(conn, NULL, NULL))
-           != LDAP_SUCCESS)
-       {
-               const char *s=ldap_err2string(ldrc);
-
-               err("ldap_start_tls_s failed: %s", s);
-               return (-1);
-       }
-       return 0;
-#else
-       err("authldaplib: TLS not available");
-       return (-1);
-#endif
-}
-
-static LDAP *ldapconnect()
-{
-LDAP   *p=NULL;
-
-#if DEBUG_LDAP
-       DPRINTF("URI:      %s",my_ldap.uri);
-       DPRINTF("UID:      %d",my_ldap.uid);
-       DPRINTF("GID:      %d",my_ldap.gid);
-#endif
-
-       if (ldapconncheck())
-       {
-               DPRINTF("authldaplib: timing out after failed connection");
-               return (NULL);
-       }
-
-       ldap_initialize(&p, my_ldap.uri);
-
-       if (p==NULL)
-       {
-               err("cannot connect to LDAP server (%s): %s",
-                       my_ldap.uri, strerror(errno));
-               ldapconnfailure();
-       }
-#ifdef LDAP_OPT_NETWORK_TIMEOUT
-       if (my_ldap.timeout > 0)
-               ldap_set_option (p, LDAP_OPT_NETWORK_TIMEOUT, &my_ldap.timeout);
-#endif
-#if DEBUG_LDAP
-       DPRINTF("ldapconnect end");
-#endif
-       return (p);
-}
-
-static int ldapopen()
-{
-int     ldrc;
-
-       if (my_ldap_fp) return (0);
-
-       if (authldap_read_config(&my_ldap) == 0)
-       {
-               err("authldaplib: error in LDAP configuration file, aborting");
-               return (1);
-       }
-
-       my_ldap_fp=ldapconnect();
-
-       if (!my_ldap_fp)
-       {
-               return (1);
-       }
-
-#ifdef LDAP_OPT_PROTOCOL_VERSION
-
-       /* Set protocol version if selected */
-       if (my_ldap.protocol_version &&
-               ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_PROTOCOL_VERSION,
-               (void *) & my_ldap.protocol_version)) != LDAP_SUCCESS)
-         {
-               const char *s=ldap_err2string(ldrc);
-
-               err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
-                       my_ldap.protocol_version, s);
-               authldapclose();
-               ldapconnfailure();
-               return (-1);
-         }
-       if (my_ldap.protocol_version)
-       {
-               DPRINTF("selected ldap protocol version %d", my_ldap.protocol_version);
-       }
-#endif
-
-       if (my_ldap.tls && enable_tls_on(my_ldap_fp))
-       {
-               authldapclose();
-               ldapconnfailure();
-               return (-1);
-       }
-
-#ifdef LDAP_OPT_DEREF
-
-       /* Set dereferencing mode */
-       if (ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_DEREF,
-                                        (void *) & my_ldap.deref)) != LDAP_SUCCESS)
-       {
-               const char *s=ldap_err2string(ldrc);
-
-               err("ldap_set_option(DEREF) failed: %s", s);
-               authldapclose();
-               ldapconnfailure();
-               return (-1);
-       }
-#endif
-
-       if(my_ldap.initbind)
-       {
-               /* Bind to server */
-               if (courier_authdebug_login_level >= 2)
-               {
-                       DPRINTF("binding to LDAP server as DN '%s', password '%s'",
-                               my_ldap.binddn ? my_ldap.binddn : "<null>",
-                               my_ldap.bindpw ? my_ldap.bindpw : "<null>");
-               }
-               else
-               {
-                       DPRINTF("binding to LDAP server as DN '%s'",
-                               my_ldap.binddn ? my_ldap.binddn : "<null>");
-               }
-
-               if (ldaperror(ldrc = l_simple_bind_s(my_ldap_fp,
-                                                    my_ldap.binddn,
-                                                    my_ldap.bindpw))
-                   != LDAP_SUCCESS)
-               {
-                       const char *s=ldap_err2string(ldrc);
-
-                       err("ldap_simple_bind_s failed: %s", s);
-                       authldapclose();
-                       ldapconnfailure();
-                       return (-1);
-               }
-       }
-       return (0);
-}
-
-static int auth_ldap_do(const char *, const char *, const char *,
-                       int (*)(struct authinfo *, void *),
-                        void *arg, const char *);
-
-int auth_ldap_changepw(const char *dummy, const char *user,
-                      const char *pass,
-                      const char *newpass)
-{
-       return auth_ldap_do("authlib", user, pass, NULL, NULL, newpass);
-}
-
-/*
- * Function: authldapcommon
- *   Get information from the LDAP server ($ldap) for this $user
- * INPUT:
- *   $user: the login name
- *   $pass: the login password (NULL if we don't want to check the pw)
- *   callback - callback function with filled in authentication info
- *   arg - extra argument for the callback function.
- * OUTPUT:
- *   < 0 - authentication failure
- *   > 0 - temporary failure
- *   else return code from the callback function.
- */
-
-int authldapcommon(const char *service,
-                  const char *user, const char *pass,
-                  int (*callback)(struct authinfo *, void *),
-                  void *arg)
-{
-       return (auth_ldap_do(service, user, pass, callback, arg, NULL));
-}
-
-static int auth_ldap_do2(const char *service,
-                        const char *user, const char *pass,
-                       int (*callback)(struct authinfo *, void *),
-                        void *arg, const char *newpass);
-
-static int auth_ldap_retry(const char *service,
-                          const char *user, const char *pass,
-                          int (*callback)(struct authinfo *, void *),
-                          void *arg, const char *newpass);
-
-static int auth_ldap_do(const char *service,
-                       const char *user, const char *pass,
-                       int (*callback)(struct authinfo *, void *),
-                        void *arg, const char *newpass)
-{
-       int rc=auth_ldap_retry(service, user, pass, callback, arg, newpass);
-
-       if (rc > 0)
-               rc=auth_ldap_retry(service, user, pass, callback, arg,
-                                  newpass);
-
-       return rc;
-}
-
-static int auth_ldap_retry(const char *service,
-                          const char *user, const char *pass,
-                          int (*callback)(struct authinfo *, void *),
-                          void *arg, const char *newpass)
-{
-       char *q;
-       int i;
-
-       q=courier_auth_ldap_escape(user);
-
-       if (!q)
-       {
-               perror("malloc");
-               return 1;
-       }
-
-       i=auth_ldap_do2(service, q, pass, callback, arg, newpass);
-       free(q);
-       return (i);
-}
-
-
-static int auth_ldap_do3(const char *service,
-                        const char *attrname,
-                        const char *user, const char *pass,
-                        int (*callback)(struct authinfo *, void *),
-                        void *arg, const char *newpass, const char *authaddr);
-
-static char *emailmap_get_search_string(const char *str, const char *email);
-
-static int auth_ldap_do2(const char *service,
-                        const char *user, const char *pass,
-                        int (*callback)(struct authinfo *, void *),
-                        void *arg, const char *newpass)
-{
-       char *srch;
-       struct timeval tv;
-       const char *attributes[2];
-       LDAPMessage *result, *entry;
-       int cnt;
-       char *v;
-       const char *aname;
-
-       if (ldapopen()) return (-1);
-
-       if (my_ldap.emailmap[0] == 0 || strchr(user, '@') == NULL)
-               return (auth_ldap_do3(service, my_ldap.mail,
-                                     user, pass, callback, arg, newpass,
-                                     user));
-       /* Mapping is not enabled */
-
-       srch=emailmap_get_search_string(my_ldap.emailmap, user);
-
-       if (!srch)
-       {
-               perror("CRIT: authldaplib: malloc");
-               exit(1);
-       }
-       DPRINTF("using emailmap search: %s", srch);
-
-       tv.tv_sec=my_ldap.timeout;
-       tv.tv_usec=0;
-
-       attributes[0]=my_ldap.emailmap_handle;
-
-       if (!attributes[0][0])
-               attributes[0]="handle";
-       attributes[1]=NULL;
-
-       if (ldaperror(l_search_st(my_ldap_fp,
-                                 (char *)(my_ldap.emailmap_basedn[0] ?
-                                          my_ldap.emailmap_basedn
-                                          :my_ldap.basedn),
-                                 LDAP_SCOPE_SUBTREE,
-                                 srch, (char **)attributes, 0,
-                                 &tv, &result))
-           != LDAP_SUCCESS)
-       {
-               free(srch);
-
-               DPRINTF("ldap_search_st failed");
-               if (my_ldap_fp) return (-1);
-               return (1);
-       }
-
-       if ((cnt=ldap_count_entries(my_ldap_fp, result)) != 1)
-       {
-               if (cnt)
-                       err("emailmap: %d entries returned from search %s (but we need exactly 1)",
-                              cnt, srch);
-               free(srch);
-               ldap_msgfree(result);
-               return -1;
-       }
-       free(srch);
-
-       entry=ldap_first_entry(my_ldap_fp, result);
-
-       if (!entry)
-       {
-               ldap_msgfree(result);
-
-               err("authldap: unexpected NULL from ldap_first_entry");
-               return -1;
-       }
-
-       copy_value(my_ldap_fp, entry, attributes[0], &v, user);
-
-       if (!v)
-       {
-               DPRINTF("emailmap: empty attribute");
-               ldap_msgfree(result);
-               return (-1);
-       }
-
-       aname=my_ldap.emailmap_handle_lookup;
-       if (aname[0] == 0)
-               aname=my_ldap.mail;
-
-       DPRINTF("emailmap results: aname=%s, handle=%s", aname, v);
-
-       cnt=auth_ldap_do3(service,
-                         aname, v, pass, callback, arg, newpass, user);
-
-       ldap_msgfree(result);
-       free(v);
-       return (cnt);
-}
-
-static int auth_ldap_do3(const char *service,
-                        const char *attrname,
-                        const char *user, const char *pass,
-                        int (*callback)(struct authinfo *, void *),
-                        void *arg, const char *newpass,
-                        const char *authaddr)
-{
-       char *newpass_crypt=0;
-       const char *attributes[10];
-       struct timeval timeout;
-
-       LDAPMessage *result;
-       LDAPMessage *entry;
-       char *filter, *dn;
-       int i, j;
-
-       struct authinfo auth;
-       char *homeDir=0;
-       char *mailDir=0;
-       char *userPassword=0;
-       char *cryptPassword=0;
-       char *options=0;
-       char *cn=0;
-       uid_t au;
-       gid_t ag;
-       int rc;
-       char *quota=0;
-        int additionalFilter = 0;
-        int hasAdditionalFilter = 0;
-
-        hasAdditionalFilter = my_ldap.filter != 0;
-
-       memset(&auth, 0, sizeof(auth));
-
-        if (hasAdditionalFilter)
-        {
-            /* To add the additional filter, we need to add on the
-             * additional size for "(&)" and the other filter.  So
-             * filter+3
-             */
-            additionalFilter = strlen(my_ldap.filter) + 3;
-        }
-
-       if ((filter=malloc(additionalFilter+strlen(attrname)+strlen(user)+
-                          (my_ldap.domain ? strlen(my_ldap.domain):0)+
-                          sizeof ("(=@)"))) == 0)
-       {
-               perror("malloc");
-               return 1;
-       }
-        strcpy(filter, "\0");
-
-        if (hasAdditionalFilter)
-        {
-            strcat(filter, "(&");
-            strcat(filter, my_ldap.filter);
-        }
-
-        strcat(strcat(strcat(strcat(filter, "("), attrname), "="), user);
-       if ( my_ldap.domain && my_ldap.domain[0] && strchr(user, '@') == 0 )
-               strcat(strcat(filter, "@"), my_ldap.domain);
-       strcat(filter, ")");
-        
-        if (hasAdditionalFilter)
-        {
-            strcat(filter, ")");
-        }
-
-       DPRINTF("using search filter: %s", filter);
-
-       timeout.tv_sec=my_ldap.timeout;
-       timeout.tv_usec=0;
-
-       read_env("LDAP_HOMEDIR", &attributes[0], "", 0, "homeDir");
-       read_env(service && strcmp(service, "courier") == 0
-                ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR",
-                &attributes[1], "", 0, 0);
-       read_env("LDAP_FULLNAME", &attributes[2], "", 0, "cn");
-       read_env("LDAP_CLEARPW", &attributes[3], "", 0, 0);
-       read_env("LDAP_CRYPTPW", &attributes[4], "", 0, 0);
-       read_env("LDAP_UID", &attributes[5], "", 0, 0);
-       read_env("LDAP_GID", &attributes[6], "", 0, 0);
-       attributes[7]=my_ldap.mail;
-       read_env("LDAP_MAILDIRQUOTA", &attributes[8], "", 0, 0);
-
-       j=0;
-       for (i=0; i<9; i++)
-       {
-               if (attributes[i])
-                       my_ldap.attrlist[j++]=attributes[i];
-       }
-
-       for (i=0; my_ldap.auxoptions[i]; i++)
-               my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
-
-       my_ldap.attrlist[j]=0;
-
-       if (ldaperror(l_search_st(my_ldap_fp,
-                                 (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
-                                 filter, (char **)my_ldap.attrlist, 0,
-                                 &timeout, &result))
-                     != LDAP_SUCCESS)
-       {
-               DPRINTF("ldap_search_st() failed");
-               free(filter);
-
-               if (my_ldap_fp) return (-1);
-               return (1);
-       }
-
-       free(filter);
-
-       /* If we are more than one result, reject */
-       if (ldap_count_entries(my_ldap_fp,result)!=1)
-       {
-               DPRINTF("number of entries returned: %d (but we need exactly 1)",
-                       ldap_count_entries(my_ldap_fp,result));
-               ldap_msgfree(result);
-               return -1;
-       }
-
-       dn = ldap_get_dn(my_ldap_fp, result);
-
-       DPRINTF("one entry returned, DN: %s", dn ? dn : "<null>");
-
-       if (dn == NULL) 
-       {
-               DPRINTF("ldap_get_dn failed");
-               return -1;
-       }
-
-       /* Get the pointer on this result */
-       entry=ldap_first_entry(my_ldap_fp,result);
-       if (entry==NULL)
-       {
-               DPRINTF("ldap_first_entry failed");
-               free(dn);
-               return -1;
-       }
-
-#if DEBUG_LDAP
-       DPRINTF("after ldap_first_entry");
-#endif
-
-       /* print all the raw attributes */
-       if (courier_authdebug_login_level >= 2)
-       {
-       char *attr;
-       BerElement *berptr = 0;
-
-               attr = ldap_first_attribute(my_ldap_fp, entry, &berptr);
-               if (attr)
-               {
-                       DPRINTF("raw ldap entry returned:");
-               }
-
-               while (attr)
-               {
-               char **av, **ap;
-               
-                       av = l_get_values(my_ldap_fp, entry, attr);
-                       ap = av;
-                       if (av)
-                       {
-                               while(*ap)
-                               {
-                                       DPRINTF("| %s: %s", attr, *ap);
-                                       ap++;
-                               }
-                               l_value_free(av);
-                       }
-                       ldap_memfree(attr);
-                       attr = ldap_next_attribute(my_ldap_fp, entry, berptr);
-               }
-               
-               ber_free(berptr, 0);
-       }
-
-       /* Copy the directory and the password into struct */
-       copy_value(my_ldap_fp,entry,attributes[0],&homeDir, user);
-       if (attributes[1])
-               copy_value(my_ldap_fp,entry,attributes[1],&mailDir, user);
-       copy_value(my_ldap_fp,entry,attributes[2],&cn, user);
-       if (attributes[3])
-               copy_value(my_ldap_fp,entry,attributes[3],&userPassword, user);
-       if (attributes[4])
-               copy_value(my_ldap_fp,entry,attributes[4],&cryptPassword, user);
-
-       au=my_ldap.uid;
-       ag=my_ldap.gid;
-       if (attributes[5])
-       {
-               char *p=0;
-               unsigned long n;
-
-               copy_value(my_ldap_fp, entry, attributes[5], &p, user);
-               if (p) {
-                       if (sscanf(p, "%lu", &n) > 0)
-                               au= (uid_t)n;
-                       free(p);
-               }
-#if DEBUG_LDAP
-               DPRINTF("au= %d",au);
-#endif
-       }
-
-       if (attributes[6])
-       {
-               char *p=0;
-               unsigned long n;
-
-               copy_value(my_ldap_fp, entry, attributes[6], &p, user);
-               if (p) {
-                       if (sscanf(p, "%lu", &n) > 0)
-                               ag= (gid_t)n;
-                       free(p);
-               }
-#if DEBUG_LDAP
-               DPRINTF("ag= %d",ag);
-#endif
-       }
-
-       if (attributes[8])
-               copy_value(my_ldap_fp,entry,attributes[8],&quota, user);
-
-       if (homeDir != 0 && my_ldap.mailroot != 0 && *my_ldap.mailroot)
-       {
-               char *new_mailroot=malloc(strlen(homeDir)+
-                                         strlen(my_ldap.mailroot)+2);
-
-               if (!new_mailroot)
-               {
-                       perror("CRIT: authldap: malloc failed");
-                       rc= -1;
-               }
-               else
-               {
-                       strcat(strcat(strcpy(new_mailroot, my_ldap.mailroot),
-                                     "/"), homeDir);
-                       free(homeDir);
-                       homeDir=new_mailroot;
-               }
-       }
-
-       j=1;
-
-       for (i=0; my_ldap.auxoptions[i]; i++)
-       {
-               char *val;
-
-               copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i], &val,
-                          user);
-
-               if (!val)
-                       continue;
-
-               j += 2 + strlen(my_ldap.auxnames[i]) +
-                       strlen(val);
-               free(val);
-       }
-
-       options=malloc(j);
-
-       if (!options)
-       {
-               perror("CRIT: authldap: malloc failed");
-               rc= -1;
-       }
-       else
-       {
-               *options=0;
-
-               for (i=0; my_ldap.auxoptions[i]; i++)
-               {
-                       char *val;
-
-                       copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
-                                  &val,
-                                  user);
-
-                       if (!val)
-                               continue;
-
-                       if (*options)
-                               strcat(options, ",");
-                       strcat(options, my_ldap.auxnames[i]);
-                       strcat(options, "=");
-                       strcat(options, val);
-                       free(val);
-               }
-       }
-
-
-       auth.sysuserid= &au;
-       auth.sysgroupid= ag;
-       auth.homedir=homeDir;
-       auth.address=authaddr;
-       auth.fullname=cn;
-       auth.maildir=mailDir;
-       auth.clearpasswd=userPassword;
-       auth.passwd=cryptPassword;
-       auth.quota=quota;
-       auth.options=options && *options ? options:NULL;
-
-       if (homeDir == 0)
-               auth.homedir="";
-
-       rc=0;
-
-       if (au == 0 || ag == 0)
-       {
-               err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
-                      user, au, ag);
-               rc= 1;
-       }
-
-       courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth,
-               userPassword, cryptPassword);
-
-       if (pass)
-       {
-               if (my_ldap.authbind) 
-               {
-                       if (!bindp)
-                       {
-                               bindp=ldapconnect();
-
-                               if (!bindp)
-                               {
-                                       DPRINTF("ldapconnect failed");
-                                       rc=1;
-                               }
-                               else
-#ifdef LDAP_OPT_PROTOCOL_VERSION
-                               /* Set protocol version */
-                               if (my_ldap.protocol_version &&
-                                       ldap_set_option(bindp, LDAP_OPT_PROTOCOL_VERSION,
-                                       (void *) & my_ldap.protocol_version) != LDAP_OPT_SUCCESS)
-                                 {
-                                       err("ldap_set_option(PROTOCOL_VERSION %d) failed",
-                                               my_ldap.protocol_version);
-                                       rc = 1;
-                                 }
-                               else
-#endif
-                               if(my_ldap.tls && enable_tls_on(bindp)) {
-                                       err("authldaplib: LDAP_TLS enabled but I'm unable to start tls, check your config");
-                                       rc = 1;
-                               }
-                       }
-
-                       if (bindp)
-                       {
-                               if (rc == 0)
-                               {
-                               int ldrc;
-                                       DPRINTF("rebinding with DN '%s' to validate password", dn);
-                                       ldrc = l_simple_bind_s(bindp, dn, pass);
-                                       switch (ldrc)
-                                       {
-                                       case LDAP_SUCCESS:
-                                               DPRINTF("authentication bind successful");
-                                               break;
-                                       case LDAP_INVALID_CREDENTIALS:
-                                               DPRINTF("authentication bind failed, invalid credentials");
-                                               rc = -1;
-                                               break;
-                                       default:
-                                               DPRINTF("authentication bind failed, some other problem: %s",
-                                                       ldap_err2string(ldrc));
-                                               rc = 1;
-                                               break;
-                                       }
-                               }
-                               /* Drop the connection if there was a fatal
-                                  error or if we are using historic LDAP v2,
-                                  which didn't support rebinding on same conn */
-                               if (rc > 0 || my_ldap.protocol_version == 2)
-                               {
-                                       l_unbind(bindp);
-                                       bindp=0;
-                               }
-                       }
-
-                       if (rc == 0 && newpass)
-                       {
-                               if ((newpass_crypt=authcryptpasswd(newpass,
-                                                                  auth.passwd)
-                                    ) == 0)
-                                       rc= -1;
-                       }
-               }
-               else
-               {
-                       if (auth.clearpasswd)
-                       {
-                               if (strcmp(pass,auth.clearpasswd))
-                               {
-                                       if (courier_authdebug_login_level >= 2)
-                                       {
-                                               DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
-                                                       pass, auth.clearpasswd);
-                                       }
-                                       else
-                                       {
-                                               DPRINTF("supplied password does not match clearpasswd");
-                                       }
-                                       rc= -1;
-                               }
-                       }
-                       else
-                       {
-                               const char *p=auth.passwd;
-
-                               if (!p)
-                               {
-                                       DPRINTF("no password to compare against!");
-                                       rc= -1;
-                               }
-                               else if (authcheckpassword(pass, p))
-                                       rc= -1;
-                       }
-
-                       if (rc == 0 && newpass && auth.passwd)
-                       {
-                               if ((newpass_crypt=authcryptpasswd(newpass,
-                                                                  auth.passwd)
-                                    ) == 0)
-                                       rc= -1;
-                       }
-               }
-        }
-
-       if (rc == 0 && newpass)
-       {
-               LDAPMod *mods[3];
-               int mod_index=0;
-
-               LDAPMod mod_clear, mod_crypt;
-               char *mod_clear_vals[2], *mod_crypt_vals[2];
-
-               if (attributes[3])
-               {
-                       mods[mod_index]= &mod_clear;
-                       mod_clear.mod_op=LDAP_MOD_REPLACE;
-                       mod_clear.mod_type=(char *)attributes[3];
-                       mod_clear.mod_values=mod_clear_vals;
-
-                       mod_clear_vals[0]=(char *)newpass;
-                       mod_clear_vals[1]=NULL;
-                       ++mod_index;
-               }
-
-               if (attributes[4] && newpass_crypt)
-               {
-                       mods[mod_index]= &mod_crypt;
-                       mod_crypt.mod_op=LDAP_MOD_REPLACE;
-                       mod_crypt.mod_type=(char *)attributes[4];
-                       mod_crypt.mod_values=mod_crypt_vals;
-
-                       mod_crypt_vals[0]=newpass_crypt;
-                       mod_crypt_vals[1]=NULL;
-                       ++mod_index;
-               }
-               if (mod_index == 0)
-                       rc= -1;
-               else
-               {
-                       int ld_errno;
-                       mods[mod_index]=0;
-
-                       /* On a system which uses LDAP_AUTHBIND, we probably
-                          want to use the user's credentials (bindp) rather
-                          than the search credentials (my_ldap_fp) for
-                          performing the password update. (May not always be
-                          true, ideally it would be configurable) */
-                       ld_errno = l_modify_s(bindp? bindp:my_ldap_fp, dn, mods);
-                       if (ld_errno != LDAP_SUCCESS)
-                       {
-                               rc= -1;
-                               DPRINTF("LDAP modify failed: %s",
-                                       ldap_err2string(ld_errno));
-                       }
-               }
-       }
-
-       if (newpass_crypt)
-               free(newpass_crypt);
-       free (dn);
-#if DEBUG_LDAP
-       DPRINTF("before callback rc=%d",rc);
-#endif
-
-       if (rc == 0 && callback)
-       {
-               if (!auth.clearpasswd)
-                       auth.clearpasswd=pass;
-               rc= (*callback)(&auth, arg);
-#if DEBUG_LDAP
-               DPRINTF("after callback rc=%d",rc);
-#endif
-       }
-
-       ldap_msgfree(result);
-       if (options)    free(options);
-       if (homeDir)    free(homeDir);
-       if (mailDir)    free(mailDir);
-       if (userPassword)       free(userPassword);
-       if (cryptPassword)      free(cryptPassword);
-       if (cn)         free(cn);
-       if (quota)      free(quota);
-       return (rc);
-}
-
-/**
- ** Create an emailmap search string.  I'm going to wrap this into an external
- ** variable, so I'll use generic coding here.
- */
-
-struct varlist {
-       const char *varname;
-       int varname_len;
-       const char *varvalue;
-       int varvalue_len;
-} ;
-
-static char *var_expand(const char *, const struct varlist *);
-
-static char *emailmap_get_search_string(const char *str, const char *email)
-{
-       struct varlist vl[3];
-       const char *realmptr=strrchr(email, '@');/* Guaranteed nonNULL */
-
-       static const char userid[]="user";
-       static const char realm[]="realm";
-
-       vl[0].varname=userid;
-       vl[0].varname_len=sizeof(userid)-1;
-       vl[0].varvalue=email;
-       vl[0].varvalue_len=realmptr - email;
-       vl[1].varname=realm;
-       vl[1].varname_len=sizeof(realm)-1;
-       vl[1].varvalue=realmptr+1;
-       vl[1].varvalue_len=strlen(vl[1].varvalue);
-       vl[2].varname=NULL;
-
-       return (var_expand(str, vl));
-}
-
-static char *var_expand(const char *str, const struct varlist *vl)
-{
-       const char *p;
-       int cnt;
-       int pass;
-       char *q, *r;
-
-       cnt=0;
-       q=NULL;
-
-       /*
-       ** Pass 1 - count expanded string length, allocate buffer,
-       ** Pass 2 - generate the string.
-       */
-
-       for (pass=0; pass<2; pass++)
-       {
-               if (pass)
-               {
-                       if ((q=malloc(cnt)) == NULL)
-                               return (NULL);
-               }
-               r=q;
-               cnt=1;
-
-               p=str;
-
-               while (*p)
-               {
-                       if (*p == '@')
-                       {
-                               int j;
-
-                               for (j=0; vl[j].varname; j++)
-                               {
-                                       if (memcmp(vl[j].varname, p+1,
-                                                  vl[j].varname_len) == 0
-                                           && p[vl[j].varname_len+1] == '@')
-                                               break;
-                               }
-
-                               if (vl[j].varname)
-                               {
-                                       p += vl[j].varname_len+2;
-
-                                       if (r)
-                                       {
-                                               memcpy(r, vl[j].varvalue,
-                                                      vl[j].varvalue_len);
-                                               r += vl[j].varvalue_len;
-                                       }
-                                       cnt += vl[j].varvalue_len;
-                                       continue;
-                               }
-                       }
-
-                       if (r)
-                               *r++ = *p;
-                       ++p;
-                       ++cnt;
-               }
-               if (r)
-                       *r=0;
-       }
-
-       return (q);
-}
-
-void auth_ldap_enumerate( void(*cb_func)(const char *name,
-                                        uid_t uid,
-                                        gid_t gid,
-                                        const char *homedir,
-                                        const char *maildir,
-                                        const char *options,
-                                        void *void_arg),
-                          void *void_arg)
-{
-       const char *attributes[5];
-
-       int i, j;
-       int msgid;
-
-       if (ldapopen())
-       {
-               (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
-               return;
-       }
-
-       read_env("LDAP_MAIL", &attributes[0], "", 0, "mail");
-       read_env("LDAP_UID", &attributes[1], "", 0, 0);
-       read_env("LDAP_GID", &attributes[2], "", 0, 0);
-       read_env("LDAP_HOMEDIR", &attributes[3], "", 0, "homeDir");
-       read_env("LDAP_MAILDIR", &attributes[4], "", 0, 0);
-
-       j=0;
-       for (i=0; i<5; i++)
-       {
-               if (attributes[i])
-                       my_ldap.attrlist[j++]=attributes[i];
-       }
-
-       for (i=0; my_ldap.auxoptions[i]; i++)
-               my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
-
-       my_ldap.attrlist[j]=0;
-
-       DPRINTF("ldap_search: basedn='%s', filter='%s'",
-               my_ldap.basedn, my_ldap.enumerate_filter);
-       if ((msgid = l_search(my_ldap_fp, (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
-                             my_ldap.enumerate_filter,
-                             (char **)my_ldap.attrlist, 0)) < 0)
-       {
-               DPRINTF("ldap_search failed");
-               return;
-       }
-
-       while(1) /* process results as they come in */
-       {
-               struct timeval timeout;
-               LDAPMessage *result;
-               LDAPMessage *entry;
-               int ldrc;
-
-               timeout.tv_sec=my_ldap.timeout;
-               timeout.tv_usec=0;
-               ldrc = ldap_result(my_ldap_fp, msgid, 0, &timeout, &result);
-               switch (ldrc)
-               {
-               case -1:
-                       DPRINTF("error in ldap_result");
-                       ldap_msgfree(result);
-                       return;
-               case 0:
-                       DPRINTF("timeout waiting for search result");
-                       ldap_msgfree(result);
-                       return;
-               case LDAP_RES_SEARCH_ENTRY:
-                       break; /* deal with below */
-               case LDAP_RES_SEARCH_RESULT:
-                       if (ldap_parse_result(my_ldap_fp, result, &ldrc,
-                               NULL, NULL, NULL, NULL, 0) != LDAP_SUCCESS)
-                       {
-                               DPRINTF("ldap_parse_result failed");
-                               ldap_msgfree(result);
-                               return;
-                       }
-                       ldap_msgfree(result);
-                       if (ldrc != LDAP_SUCCESS)
-                       {
-                               DPRINTF("ldap search failure result: %s",
-                                       ldap_err2string(ldrc));
-                               return;
-                       }
-                       /* Search successfully completed */
-                       (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
-                       return;
-               default:
-                       DPRINTF("ldap result type 0x%02X ignored", ldrc);
-                       ldap_msgfree(result);
-                       continue;
-               }
-
-               entry = ldap_first_entry(my_ldap_fp, result);
-               while (entry)
-               {
-                       char **names = get_values(my_ldap_fp, entry, attributes[0]);
-                       int n;
-
-                       if (names == NULL)
-                       {
-                               entry = ldap_next_entry(my_ldap_fp, entry);
-                               continue;
-                       }
-
-                       n=l_count_values(names);
-                       if (n > 0)
-                       {
-                               const char *name = names[0] ? names[0] : "<null>";
-                               int i,j;
-                               char *uid_s=NULL;
-                               char *gid_s=NULL;
-                               char *homedir;
-                               char *maildir;
-                               char *options;
-                               uid_t uid=my_ldap.uid;
-                               gid_t gid=my_ldap.gid;
-
-                               if (attributes[1])
-                               {
-                                       copy_value(my_ldap_fp, entry, attributes[1],
-                                                  &uid_s,
-                                                  name);
-                               }
-
-                               if (attributes[2])
-                               {
-                                       copy_value(my_ldap_fp, entry, attributes[2],
-                                                  &gid_s, name);
-                               }
-
-                               copy_value(my_ldap_fp, entry, attributes[3],
-                                          &homedir, name);
-                               copy_value(my_ldap_fp, entry, attributes[4],
-                                          &maildir, name);
-
-                               if (uid_s)
-                                       uid=atol(uid_s);
-                               if (gid_s)
-                                       gid=atol(gid_s);
-
-                               j=1;
-
-                               for (i=0; my_ldap.auxoptions[i]; i++)
-                               {
-                                       char *val;
-
-                                       copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
-                                                  &val, name);
-
-                                       if (!val)
-                                               continue;
-
-                                       j += 2 + strlen(my_ldap.auxnames[i]) +
-                                               strlen(val);
-                                       free(val);
-                               }
-
-                               options=malloc(j);
-
-                               if (!options)
-                               {
-                                       l_value_free(names);
-                                       perror("CRIT: auth_ldap_enumerate: malloc failed");
-                                       return;
-                               }
-                               *options=0;
-
-                               for (i=0; my_ldap.auxoptions[i]; i++)
-                               {
-                                       char *val;
-
-                                       copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
-                                                  &val, name);
-
-                                       if (!val)
-                                               continue;
-
-                                       if (*options)
-                                               strcat(options, ",");
-                                       strcat(options, my_ldap.auxnames[i]);
-                                       strcat(options, "=");
-                                       strcat(options, val);
-                                       free(val);
-                               }
-
-                               for (j = 0; j < n; j++)
-                               {
-                                       name=names[j];
-
-                                       if (name && homedir)
-                                               (*cb_func)(name, uid, gid, homedir,
-                                                          maildir, options, void_arg);
-                               }
-
-                               if (uid_s)
-                                       free(uid_s);
-                               if (gid_s)
-                                       free(gid_s);
-                               if (homedir)
-                                       free(homedir);
-                               if (maildir)
-                                       free(maildir);
-                               if (options)
-                                       free(options);
-                       }
-                       l_value_free(names);
-
-                       entry = ldap_next_entry(my_ldap_fp, entry);
-               }
-
-               ldap_msgfree(result);
-       }
-}