diff -dPNur courier-authlib-0.60.6/authvchkpw.c courier-authlib-0.60.6-new/authvchkpw.c --- courier-authlib-0.60.6/authvchkpw.c 1970-01-01 01:00:00.000000000 +0100 +++ courier-authlib-0.60.6-new/authvchkpw.c 2008-09-16 23:37:21.000000000 +0200 @@ -0,0 +1,242 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. See COPYING for +** distribution information. +*/ + +#if HAVE_CONFIG_H +#include "courier_auth_config.h" +#endif +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include "auth.h" +#include "authstaticlist.h" +#include "courierauthdebug.h" +#include "vpopmail_config.h" +#include +#include + +static const char rcsid[]="$Id: authvchkpw.c,v 1.29 2007/10/07 02:50:45 mrsam Exp $"; + + +extern int auth_vchkpw_pre(const char *userid, const char *service, + int (*callback)(struct authinfo *, void *), + void *arg); + +extern FILE *authvchkpw_file(const char *, const char *); + +static int auth_vchkpw_login(const char *service, char *authdata, + int (*callback_func)(struct authinfo *, void *), void *callback_arg); + +struct callback_info { + const char *pass; + int (*callback_func)(struct authinfo *, void *); + void *callback_arg; + }; + +static int callback_vchkpw(struct authinfo *a, void *p) +{ +struct callback_info *i=(struct callback_info *)p; + + /* exit with perm failure if the supplied password is empty, + * or if the supplied password doesnt match the retrieved password */ + if (a->passwd == 0) + { + DPRINTF("no password supplied"); + return (-1); + } + + if (authcheckpassword(i->pass, a->passwd)) + return (-1); + + a->clearpasswd=i->pass; + return (*i->callback_func)(a, i->callback_arg); +} + +#if HAVE_HMACLIB + +#include "libhmac/hmac.h" +#include "cramlib.h" + +static int auth_vchkpw_login(const char *service, char *authdata, + int (*callback_func)(struct authinfo *, void *), void *callback_arg); + +static int auth_vchkpw_cram(const char *service, + const char *authtype, char *authdata, + int (*callback_func)(struct authinfo *, void *), + void *callback_arg) +{ + struct cram_callback_info cci; + + if (auth_get_cram(authtype, authdata, &cci)) + return (-1); + + cci.callback_func=callback_func; + cci.callback_arg=callback_arg; + + return auth_vchkpw_pre(cci.user, service, &auth_cram_callback, &cci); +} +#endif + +int auth_vchkpw(const char *service, const char *authtype, char *authdata, + int (*callback_func)(struct authinfo *, void *), + void *callback_arg) +{ + if (strcmp(authtype, AUTHTYPE_LOGIN) == 0) + return (auth_vchkpw_login(service, authdata, + callback_func, callback_arg)); + +#if HAVE_HMACLIB + return (auth_vchkpw_cram(service, authtype, authdata, + callback_func, callback_arg)); +#else + errno=EPERM; + return (-1); +#endif + +} + + + +static int auth_vchkpw_login(const char *service, char *authdata, + int (*callback_func)(struct authinfo *, void *), void *callback_arg) +{ +char *user, *pass; +struct callback_info ci; +int rc; + /* Make sure that we have been supplied with the correct + * AUTHDATA format which is : useridpassword + */ + if ( (user=strtok(authdata, "\n")) == 0 || (pass=strtok(0, "\n")) == 0) + { + /* login syntax was invalid */ + errno=EPERM; + return (-1); + } + + ci.pass=pass; + ci.callback_func=callback_func; + ci.callback_arg=callback_arg; + + /* auth_vchkpw_pre() does this : + * - lookup the passwd entry for this user from the auth backend + * - check to see if this user is permitted to use this service type + * If successful it will populate the ci struct with the + * user's passwd entry. Return value of function will be 0. + * If unsuccessful (eg user doesnt exist, or is not permitted to + * use this auth method), it will return : + * <0 on a permanent failure (eg user doesnt exist) + * >0 on a temp failure + */ + rc=auth_vchkpw_pre(user, service, &callback_vchkpw, &ci); + + if (rc) + return rc; + + /* user has been successfully auth'ed at this point */ + +#if 0 + /* + ** sam - new courier-authlib never receives TCPREMOTEIP, at this + ** time. + */ + +#ifdef HAVE_OPEN_SMTP_RELAY + if ( (strcmp("pop3", service)==0) || (strcmp("imap", service)==0) ) { + /* Michael Bowe 13th August 2003 + * + * There is a problem here because open_smtp_relay needs + * to get the user's ip from getenv("TCPREMOTEIP"). + * If we run --with-authvchkpw --without-authdaemon, + * then this var is available. + * But if we run --with-authvchkpw --with-authdaemon, + * then TCPREMOTEIP is null + * + * If TCPREMOTEIP isnt available, then open_smtp_relay() + * will just return() back immediately. + */ + open_smtp_relay(); + } +#endif +#endif + + return 0; +} + +static void authvchkpwclose() +{ +} + +static int auth_vchkpw_changepass(const char *service, + const char *username, + const char *pass, + const char *npass) +{ +struct vqpasswd *vpw; +char User[256]; +char Domain[256]; + + /* Take the supplied userid, and split it out into the user and domain + * parts. (If a domain was not supplied, then set the domain to be + * the default domain) + */ + /* WARNING: parse_email lowercases the username in place - not const!! */ + if ( parse_email(username, User, Domain, 256) != 0) { + /* Failed to successfully extract user and domain. + * So now exit with a permanent failure code + */ + return(-1); + } + + /* check to see if domain exists. + * If you pass an alias domain to vget_assign, it will change it + * to be the real domain on return from the function + */ + if ( vget_assign(Domain,NULL,0,NULL,NULL) ==NULL ) { + /* domain doesnt exist */ + return (-1); + } + + if ( (vpw=vauth_getpw(User, Domain)) == NULL) { + /* That user doesnt exist in the auth backend */ + errno=ENOENT; + return (-1); + } + + /* Exit if any of the following : + * - user's password field in the passwd entry is empty + * - supplied current password doesnt match stored password + */ + if (vpw->pw_passwd == 0 || authcheckpassword(pass, vpw->pw_passwd)) { + errno=EPERM; + return (-1); + } + + /* save the new password into the auth backend */ + if ( vpasswd(User, Domain, (char *)npass, 0) != 0 ) { + /* password set failed */ + return (-1); + }; + + return (0); +} + +struct authstaticinfo authvchkpw_info={ + "authvchkpw", + auth_vchkpw, + auth_vchkpw_pre, + authvchkpwclose, + auth_vchkpw_changepass, + authvchkpwclose, + NULL}; + + +struct authstaticinfo *courier_authvchkpw_init() +{ + return &authvchkpw_info; +} diff -dPNur courier-authlib-0.60.6/authvchkpwlib.c courier-authlib-0.60.6-new/authvchkpwlib.c --- courier-authlib-0.60.6/authvchkpwlib.c 1970-01-01 01:00:00.000000000 +0100 +++ courier-authlib-0.60.6-new/authvchkpwlib.c 2008-09-16 23:37:21.000000000 +0200 @@ -0,0 +1,33 @@ +/* +** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for +** distribution information. +*/ + +#if HAVE_CONFIG_H +#include "courier_auth_config.h" +#endif +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include "auth.h" + +static const char rcsid[]="$Id: authvchkpwlib.c,v 1.8 2004/10/21 00:10:49 mrsam Exp $"; + +char *authvchkpw_isvirtual(char *c) +{ +char *p; + + if ((p=strchr(c, '@')) != 0) return (p); +#if 0 + if ((p=strchr(c, '%')) != 0) return (p); +#endif + if ((p=strchr(c, ':')) != 0) return (p); + return (0); +} diff -dPNur courier-authlib-0.60.6/configure.in courier-authlib-0.60.6-new/configure.in --- courier-authlib-0.60.6/configure.in 2008-06-08 18:40:36.000000000 +0200 +++ courier-authlib-0.60.6-new/configure.in 2008-09-16 23:58:51.000000000 +0200 @@ -564,6 +564,84 @@ dnl ######################################################################### +dnl Prepare authvchkpw module if vchkpw is installed. + +dnl ######################################################################### + +changequote(<<,>>) + +vpopmail_home=`$PERL -e '@a=getpwnam("vpopmail"); print "$a[7]";'` + +changequote([,]) + +AC_ARG_WITH(authvchkpw, +[ --without-authvchkpw Do not include the authvchkpw module ], + doauthvchkpw="$withval", + doauthvchkpw=no + if test "$vpopmail_home" != "" + then + doauthvchkpw=yes + fi) + +if test "$doauthvchkpw" = "no" +then + HAVE_VCHKPW=0 + vpopmail_home=. +else + HAVE_VCHKPW=1 + + + cat < header file. */ /* #undef HAVE_PAM_PAM_APPL_H */ @@ -118,6 +121,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 +/* Whether -lvpopmail has the vset_lastauth() function */ +/* #undef HAVE_VSET_LASTAUTH */ + /* Whether we must a prototype for crypt() */ #define NEED_CRYPT_PROTOTYPE 0 diff -dPNur courier-authlib-0.60.6/courier_auth_config.h.in courier-authlib-0.60.6-new/courier_auth_config.h.in --- courier-authlib-0.60.6/courier_auth_config.h.in 2008-06-08 18:41:02.000000000 +0200 +++ courier-authlib-0.60.6-new/courier_auth_config.h.in 2008-09-16 23:37:21.000000000 +0200 @@ -60,6 +60,9 @@ /* Whether header installation directory is nontstandard */ #undef HAVE_NOSTDHEADERDIR +/* Whether -lvpopmail has the open_smtp_relay() function */ +#undef HAVE_OPEN_SMTP_RELAY + /* Define to 1 if you have the header file. */ #undef HAVE_PAM_PAM_APPL_H @@ -117,6 +120,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Whether -lvpopmail has the vset_lastauth() function */ +#undef HAVE_VSET_LASTAUTH + /* Whether we must a prototype for crypt() */ #undef NEED_CRYPT_PROTOTYPE diff -dPNur courier-authlib-0.60.6/Makefile.am courier-authlib-0.60.6-new/Makefile.am --- courier-authlib-0.60.6/Makefile.am 2008-06-08 18:40:36.000000000 +0200 +++ courier-authlib-0.60.6-new/Makefile.am 2008-09-16 23:35:56.000000000 +0200 @@ -12,7 +12,7 @@ modules=@LIBAUTHUSERDB@ \ @LIBAUTHPAM@ @LIBAUTHPWD@ @LIBAUTHSHADOW@ \ @LIBAUTHPGSQL@ @LIBAUTHLDAP@ @LIBAUTHMYSQL@ \ - @LIBAUTHCUSTOM@ @LIBAUTHPIPE@ + @LIBAUTHCUSTOM@ @LIBAUTHPIPE@ @LIBAUTHVCHKPW@ pkglibexecdir=$(libexecdir)/courier-authlib pkglibexec_SCRIPTS=authsystem.passwd @@ -30,7 +30,8 @@ libauthldap.la \ libauthmysql.la \ libauthcustom.la \ - libauthpipe.la + libauthpipe.la \ + libauthvchkpw.la CLEANFILES=authldaprc.h authmysqlrc.h authdaemonrc.h \ authpgsqlrc.h authpiperc.h authdaemon \ @@ -111,6 +112,7 @@ libauthpgsql_la_LIBADD=$(commonlibadd) $(libauthpgsql_t) libauthpgsql_la_LDFLAGS=$(commonldflags) + authpgsqllib.lo: authpgsqllib.c authpgsqlrc.h if HAVE_AUTHPGSQL @@ -223,7 +225,21 @@ echo "#define PIPE_PROGRAM \"@authProg@\"" >authpiperc.h +# The vpopmail module +libauthvchkpw_t = @VPOPMAILLIBS@ @LIBM@ +libauthvchkpw_la_SOURCES=authvchkpw.c authvchkpwlib.c preauthvchkpw.c +libauthvchkpw_la_DEPENDENCIES = $(commonlibdep) +libauthvchkpw_la_LIBADD = $(commonlibadd) +libauthvchkpw_la_LDFLAGS = $(commonldflags) $(libauthvchkpw_t) + +authvchkpw.lo: authvchkpw.c vpopmail_config.h +preauthvchkpw.lo: preauthvchkpw.c vpopmail_config.h + +vpopmail_config.h: + echo '#include "@vpopmail_home@/include/config.h"' >vpopmail_config.h + # + # AUTHMODULES should be listed in the best authentication order # @@ -415,7 +431,9 @@ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) userdb/userdbpw \ $(DESTDIR)$(sbindir)/userdbpw ; \ $(INSTALL_SCRIPT) userdb-test-cram-md5.pl \ - $(DESTDIR)$(sbindir)/userdb-test-cram-md5 + $(DESTDIR)$(sbindir)/userdb-test-cram-md5 ; \ + $(INSTALL_SCRIPT) userdb/vchkpw2userdb \ + $(DESTDIR)$(sbindir)/vchkpw2userdb uninstall-hook: uninstall-authldaprc uninstall-authdaemonrc uninstall-authmysqlrc uninstall-authpgsqlrc rm -f $(DESTDIR)$(pkglibexecdir)/authdaemond @@ -425,7 +443,8 @@ $(DESTDIR)$(sbindir)/makeuserdb \ $(DESTDIR)$(sbindir)/userdb \ $(DESTDIR)$(sbindir)/userdbpw \ - $(DESTDIR)$(sbindir)/userdb-test-cram-md5 + $(DESTDIR)$(sbindir)/userdb-test-cram-md5 \ + $(DESTDIR)$(sbindir)/vchkpw2userdb authlib.html: authlib.html.in CONFIG_FILES=authlib.html CONFIG_HEADERS= $(SHELL) ./config.status diff -dPNur courier-authlib-0.60.6/preauthvchkpw.c courier-authlib-0.60.6-new/preauthvchkpw.c --- courier-authlib-0.60.6/preauthvchkpw.c 1970-01-01 01:00:00.000000000 +0100 +++ courier-authlib-0.60.6-new/preauthvchkpw.c 2008-09-16 23:37:21.000000000 +0200 @@ -0,0 +1,159 @@ +/* +** Copyright 1998 - 2001 Double Precision, Inc. See COPYING for +** distribution information. +*/ + +#if HAVE_CONFIG_H +#include "courier_auth_config.h" +#endif +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include "auth.h" +#include "courierauthdebug.h" +#include +#include +#include "vpopmail_config.h" + +/* make use of pw_flags only if available */ +#ifndef VQPASSWD_HAS_PW_FLAGS +#define pw_flags pw_gid +#endif + +extern FILE *authvchkpw_file(const char *, const char *); + +static const char rcsid[]="$Id: preauthvchkpw.c,v 1.26 2007/04/22 18:53:30 mrsam Exp $"; + +/* This function is called by the auth_vchkpw() function + * + * This function does the following : + * - extract the username and domain from the supplied userid + * - lookup the passwd entry for that user from the auth backend + * - populate *and return) a courier authinfo structure with the values + * from the vpopmail passwd entry + * + * Return -1 on perm failure + * Return 0 on success + * Return 1 on temp failure + * + */ + +int auth_vchkpw_pre( + const char *userid, + const char *service, + int (*callback)(struct authinfo *, void *), + void *arg) +{ +struct vqpasswd *vpw; +static uid_t uid; +gid_t gid; +struct authinfo auth; +static char User[256]; +static char Domain[256]; +static char options[80]; + + /* Make sure the auth struct is empty */ + memset(&auth, 0, sizeof(auth)); + + /* Take the supplied userid, and split it out into the user and domain + * parts. (If a domain was not supplied, then set the domain to be + * the default domain) + */ + if ( parse_email(userid, User, Domain, 256) != 0) { + /* Failed to successfully extract user and domain. + * So now exit with a permanent failure code + */ + DPRINTF("vchkpw: unable to split into user and domain"); + return(-1); + } + + /* Check to see if the domain exists. + * If so, on return vget_assign will : + * Rewrite Domain to be the real domain if it was sent as an alias domain + * Retrieve the domain's uid and gid + */ + if ( vget_assign(Domain,NULL,0,&uid, &gid) == NULL ) { + /* Domain does not exist + * So now exit with a permanent failure code */ + DPRINTF("vchkpw: domain does not exist"); + return (-1); + } + + /* Try and retrieve the user's passwd entry from the auth backend */ + if ( (vpw=vauth_getpw(User, Domain)) == NULL) { + /* User does not exist + * So now exit with a permanent failure code + */ + DPRINTF("vchkpw: user does not exist"); + return (-1); + } + + /* Check to see if the user has been allocated a dir yet. + * Some of the vpopmail backends (eg mysql) allow users to + * be manually inserted into the auth backend but without + * allocating a dir. A dir will be created when the user + * first trys to auth (or when they 1st receive mail) + */ + if (vpw->pw_dir == NULL || strlen(vpw->pw_dir) == 0 ) { + /* user does not have a dir allocated yet */ + if ( make_user_dir(User, Domain, uid, gid) == NULL) { + /* Could not allocate a user dir at this time + * so exit with a temp error code + */ + DPRINTF("vchkpw: make_user_dir failed"); + return(1); + } + /* We have allocated the user a dir now. + * Go and grab the updated passwd entry + */ + if ( (vpw=vauth_getpw(User, Domain)) == NULL ) { + /* Could not get the passwd entry + * So exit with a permanent failure code + */ + DPRINTF("vchkpw: could not get the password entry"); + return(-1); + } + } + + snprintf(options, sizeof(options), + "disablewebmail=%d,disablepop3=%d,disableimap=%d", + vpw->pw_flags & NO_WEBMAIL ? 1 : 0, + vpw->pw_flags & NO_POP ? 1 : 0, + vpw->pw_flags & NO_IMAP ? 1 : 0); + +#ifdef HAVE_VSET_LASTAUTH + /* if we are keeping track of their last auth time, + * then store this value now. Note that this isnt + * consistent with the authentication via vchkpw + * because it only stores the lastauth attempt + * after the password has been verified. Here we are + * logging it after the user has been found to exist, + * but before the password has been verified. We could + * do the logging inside authvchkpw.c, but that would + * be a lot harder because we would have to go and + * parse_email() again there before calling vset_lastauth() + */ + vset_lastauth(User, Domain, service); +#endif + + /* save the user's passwd fields into the appropriate + * courier structure + */ + /*auth.sysusername = userid;*/ + auth.sysuserid = &uid; + auth.sysgroupid = gid; + auth.homedir = vpw->pw_dir; + auth.address = userid; + auth.fullname = vpw->pw_gecos; + auth.passwd = vpw->pw_passwd; + auth.clearpasswd = vpw->pw_clear_passwd; + auth.options = options; + courier_authdebug_authinfo("DEBUG: authvchkpw: ", &auth, 0, vpw->pw_passwd); + + return ((*callback)(&auth, arg)); +} diff -dPNur courier-authlib-0.60.6/userdb/configure.in courier-authlib-0.60.6-new/userdb/configure.in --- courier-authlib-0.60.6/userdb/configure.in 2008-05-08 19:20:40.000000000 +0200 +++ courier-authlib-0.60.6-new/userdb/configure.in 2008-09-17 00:28:32.000000000 +0200 @@ -165,4 +165,4 @@ AM_CONDITIONAL(HAVE_SGML, test -d ${srcdir}/../docbook) -AC_OUTPUT(Makefile userdb.pl makeuserdb pw2userdb) +AC_OUTPUT(Makefile userdb.pl makeuserdb pw2userdb vchkpw2userdb) diff -dPNur courier-authlib-0.60.6/userdb/Makefile.am courier-authlib-0.60.6-new/userdb/Makefile.am --- courier-authlib-0.60.6/userdb/Makefile.am 2008-05-08 19:20:40.000000000 +0200 +++ courier-authlib-0.60.6-new/userdb/Makefile.am 2008-09-17 00:11:59.000000000 +0200 @@ -11,7 +11,7 @@ userdb.html.in userdb.8.in \ userdbpw.html.in userdbpw.8.in -noinst_SCRIPTS=makeuserdb pw2userdb dummy +noinst_SCRIPTS=makeuserdb pw2userdb vchkpw2userdb dummy noinst_PROGRAMS=userdbpw noinst_DATA=makeuserdb.html userdb.html userdbpw.html diff -dPNur courier-authlib-0.60.6/userdb/vchkpw2userdb.in courier-authlib-0.60.6-new/userdb/vchkpw2userdb.in --- courier-authlib-0.60.6/userdb/vchkpw2userdb.in 1970-01-01 01:00:00.000000000 +0100 +++ courier-authlib-0.60.6-new/userdb/vchkpw2userdb.in 2008-09-16 23:37:21.000000000 +0200 @@ -0,0 +1,80 @@ +#! @PERL@ +# +# Convert vchkpw to userdb format. +# +# $Id: vchkpw2userdb.in,v 1.4 2000/02/16 01:12:13 mrsam Exp $ +# +# Copyright 1998 - 1999 Double Precision, Inc. See COPYING for +# distribution information. + +use Getopt::Long; + +die "Invalid options.\n" unless + GetOptions("vpopmailhome=s" => \$vpopmailhome, + "todir=s" => \$todir); + +if ( ! ( $vpopmailhome =~ /./ )) +{ + (undef, undef, undef, undef, undef, undef, undef, $vpopmailhome) + = getpwnam("vpopmail"); + + die "Cannot find vpopmail home.\n" unless $vpopmailhome =~ /./; +} + +-d "$vpopmailhome" || die "$vpopmailhome: not found.\n"; + +if ( $todir =~ /./ ) +{ + -d "$todir" || mkdir($todir, 0700) || die "$!\n"; +} + +$bindir=$0; + +if ($bindir =~ /^(.*)\/[^\/]*$/ ) +{ + $bindir=$1; +} +else +{ + $bindir="."; +} + +die "Unable to locate pw2userdb.\n" unless -f "$bindir/pw2userdb"; + +$redir=""; + +if ( $todir =~ /./ ) +{ + $redir=">$todir/users-vpasswd"; + -d "$todir/domains" || mkdir("$todir/domains", 0700) || die "$!\n"; +} + +if ( -f "$vpopmailhome/users/vpasswd") +{ + $rc=system ("$bindir/pw2userdb --vpopuid --passwd='$vpopmailhome/users/vpasswd' --noshadow --nouid $redir"); + exit $rc / 256 if $rc; +} + +if ( opendir(DIR, "$vpopmailhome/domains")) +{ + while ($domain=readdir(DIR)) + { + $domainopt="--domain='$domain'"; + $domainopt="" if $domain eq "default"; + next if $domain eq "." || $domain eq ".."; + next unless -f "$vpopmailhome/domains/$domain/vpasswd"; + $redir=""; + if ( $todir =~ /./ ) + { + $redir=">$todir/domains/$domain"; + $redir=">$todir/users-default" + if $domain eq "default"; + } + + $rc=system ("$bindir/pw2userdb --passwd='$vpopmailhome/domains/$domain/vpasswd' --vpopuid --noshadow --nouid $domainopt $redir"); + + exit $rc / 256 if $rc != 0; + } + close(DIR); +} +