/* * Alternative checkpassword for QPopup by Jedi/Sector One * * Format of the configuration file is : * pop_login:crypted_password:real_login:path * * Syslog logging added by Paul Gregg Dec 1997 * compile by: gcc -o checkpoppasswd checkpoppasswd.c -lcrypt * Original URL of this file: http://www.pgregg.com/projects/ */ #include "../main.h" #ifndef CONFIG_FILE # error Constant CONFIG_FILE not defined. Define in ../main.h. #endif #include #include #include #include #include #include #include #include #ifndef SYSLOG_LEVEL # error SYSLOG_LEVEL not defined #else # if SYSLOG_LEVEL >= 1 # include # endif #endif #ifndef LINE_MAX # define LINE_MAX 2048 #endif #ifndef LOGIN_MAX # define LOGIN_MAX 16 #endif extern int errno; extern char *crypt(); /* extern char *malloc(); */ extern char **environ; extern char *login; extern char *password; extern char remotehost[BUFLEN]; extern char remoteip[BUFLEN]; extern char remoteinfo[BUFLEN]; static char *str1e2(char *name, char *value) { char *nv; nv = malloc(strlen(name) + strlen(value) + 2); if (!nv) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 111 at point 1"); #endif exit(111); } strcpy(nv,name); strcat(nv,"="); strcat(nv,value); return nv; } static struct newpw { char *pw_passwd; char *pw_dir; char *pw_name; char *pw_shell; uid_t pw_uid; gid_t pw_gid; char *pw_real; } *newgetpwnam(char *newlogin) { static char line[LINE_MAX + 1]; static struct newpw npw; struct passwd *pw; char *tlogin = NULL; FILE *fp; if ((fp = fopen(CONFIG_FILE, "rt")) == NULL) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 2 at point 2"); #endif exit(2); } /* TODO: * * Fix problem, when line is longer than LINE_MAX. * Allow to use empty (but only empty) lines in config file. * * Nepto [17/4/2002] */ while (fgets(line, LINE_MAX, fp) != NULL) { char *linepnt; if ((linepnt = strchr(line, '\n')) != NULL) *linepnt = 0; if ((linepnt = strtok(line, ":")) == NULL) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: invalid line, aborting"); #endif exit(2); } if (strcmp(linepnt, newlogin) == 0) { npw.pw_real = linepnt; if ((linepnt = strtok(NULL, ":")) == NULL) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 2 at point 4"); #endif exit(2); } npw.pw_passwd = linepnt; if ((linepnt = strtok(NULL, ":")) == NULL) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 2 at point 5"); #endif exit(2); } *(linepnt - 1) = 0; tlogin = linepnt; if ((linepnt = strtok(NULL, ":")) == NULL) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 2 at point 6"); #endif exit(2); } npw.pw_dir = linepnt; break; } } fclose(fp); if (tlogin == NULL) { return NULL; } pw = getpwnam(tlogin); if (!pw) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 1 at point 8"); #endif exit(1); /* XXX: unfortunately getpwnam() hides temporary errors */ } npw.pw_name = tlogin; npw.pw_shell = pw->pw_shell; npw.pw_uid = pw->pw_uid; npw.pw_gid = pw->pw_gid; return &npw; } int main_user(int argc, char **argv, char *envp[]) { struct newpw *pw; char *stored; char *encrypted; char **newenv; int numenv; /* Here we have global variables: 1. login 2. password */ pw = newgetpwnam(login); if (! pw) { #if SYSLOG_LEVEL >= 3 syslog(SYSLOG_INFO, "user: FAILED: unknown username: %s", login); #endif return -1; } stored = pw->pw_passwd; encrypted = crypt(password, stored); if (!*stored || strcmp(encrypted,stored)) { #if SYSLOG_LEVEL >= 3 syslog(SYSLOG_INFO, "user: FAILED: %s [%s]" " - password incorrect (%s) from %s@%s [%s]", login, pw->pw_real, password, remoteinfo, remotehost, remoteip); #endif return -1; } nuke_dynamic_string(&login); nuke_dynamic_string(&password); if (!pw->pw_uid) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 1 at point 15"); #endif exit(1); } /* pgregg - always use 888 if (setgid(888) == -1) { */ if (setgid(pw->pw_gid) == -1) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 1 at point 16"); #endif exit(1); } if (setuid(pw->pw_uid) == -1) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 1 at point 17"); #endif exit(1); } if (chdir(pw->pw_dir) == -1) { #if SYSLOG_LEVEL >= 3 syslog(SYSLOG_INFO, "user: FAILED: %s" " - unable to change to Mail directory: %s", pw->pw_real, pw->pw_dir); #endif exit(111); } if (getuid() < 500) { #if SYSLOG_LEVEL >= 3 syslog(SYSLOG_INFO, "user: DENIED: POP3 user's UID < 500"); #endif exit(1); } numenv = 0; while (environ[numenv]) ++numenv; newenv = (char **) malloc((numenv + 4) * sizeof(char *)); if (!newenv) { #if SYSLOG_LEVEL >= 1 syslog(SYSLOG_ERROR, "user: exit 111 at point 20 (%s)", argv[1]); #endif exit(111); } { register int i; 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("SHELL",pw->pw_shell); newenv[numenv] = 0; environ = newenv; #if SYSLOG_LEVEL >= 3 syslog(SYSLOG_INFO, "user:" " POP3 user %s : %s logged in from %s@%s [%s]", pw->pw_real, pw->pw_dir, remoteinfo, remotehost, remoteip); #endif execvp(argv[1],argv + 1); exit(111); return 0; }