Note that a newer, better version of this is available from http://www.palomine.net/qmail/checkcdb.tar.gz. It's functionally identical to this version, but the alternate user file is stored in a cdb database, rather than a flat text file, for *much* faster lookups. Apply this patch to checkpassword.c from DJB's checkpassword-0.81 package. By Chris Johnson , based on a similar implementation by Jedi/Sector One . This version of checkpassword allows an alternate pop user password file, consisting of lines of the format: pop_login:crypted_password:real_login:path For example: joe:I5zMOM3LREGQA:popuser:/var/qmail/popboxes/joe It looks for the user first in the system password file. If the user isn't found there, it looks in /var/qmail/users/poppasswd. --- checkpassword.c.orig Sat Nov 21 15:29:52 1998 +++ checkpassword.c Sun Mar 28 17:11:13 1999 @@ -1,3 +1,12 @@ +#define CONFIG_FILE "/var/qmail/users/poppasswd" + +#ifndef LINE_MAX +#define LINE_MAX 2048 +#endif + +#include +#include + #include extern int errno; extern char *crypt(); @@ -15,6 +24,7 @@ #include static struct passwd *pw; static char *stored; +static char *userdir; #include "hasspnam.h" #ifdef HASGETSPNAM @@ -31,29 +41,56 @@ void doit(login) char *login; { + static char line[LINE_MAX + 1]; + FILE *fp; + char *lineptr, *newlogin = NULL; + pw = getpwnam(login); - if (pw) + if (pw) { stored = pw->pw_passwd; - else { - if (errno == error_txtbsy) _exit(111); - _exit(1); - } + userdir = pw->pw_dir; #ifdef HASUSERPW - upw = getuserpw(login); - if (upw) - stored = upw->upw_passwd; - else - if (errno == error_txtbsy) _exit(111); + upw = getuserpw(login); + if (upw) + stored = upw->upw_passwd; + else + if (errno == error_txtbsy) _exit(111); #endif #ifdef HASGETSPNAM - spw = getspnam(login); - if (spw) - stored = spw->sp_pwdp; - else + spw = getspnam(login); + if (spw) + stored = spw->sp_pwdp; + else + if (errno == error_txtbsy) _exit(111); +#endif + + return; + } + if (errno == error_txtbsy) _exit(111); + + if (!(fp = fopen(CONFIG_FILE, "r"))) _exit(2); + while (fgets(line, LINE_MAX, fp)) { + if (!(lineptr = strtok(line, ":"))) _exit(2); + if (strcmp(lineptr, login) == 0) { + if (!(lineptr = strtok(NULL, ":"))) _exit(2); + stored = lineptr; + if (!(lineptr = strtok(NULL, ":"))) _exit(2); + newlogin = lineptr; + if (!(lineptr = strtok(NULL, ":"))) _exit(2); + userdir = lineptr; + if (lineptr = strchr(userdir, '\n')) *lineptr = '\0'; + break; + } + } + fclose(fp); + if (!newlogin) _exit(1); + pw = getpwnam(newlogin); + if (!pw) { if (errno == error_txtbsy) _exit(111); -#endif + _exit(1); + } } char *str1e2(name,value) char *name; char *value; @@ -114,7 +151,7 @@ if (prot_gid((int) pw->pw_gid) == -1) _exit(1); if (prot_uid((int) pw->pw_uid) == -1) _exit(1); - if (chdir(pw->pw_dir) == -1) _exit(111); + if (chdir(userdir) == -1) _exit(111); numenv = 0; while (environ[numenv]) ++numenv; @@ -122,7 +159,7 @@ if (!newenv) _exit(111); for (i = 0;i < numenv;++i) newenv[i] = environ[i]; newenv[numenv++] = str1e2("USER",pw->pw_name); - newenv[numenv++] = str1e2("HOME",pw->pw_dir); + newenv[numenv++] = str1e2("HOME",userdir); newenv[numenv++] = str1e2("SHELL",pw->pw_shell); newenv[numenv] = 0; environ = newenv;