From: "Kelley L." To: Christian Wiese cc: djb-qmail Subject: Re: Probs w. CHECKPASSWORD Date: Fri, 12 Dec 1997 17:53:48 -0500 (EST) On Fri, 12 Dec 1997, Christian Wiese wrote: > You're right, I made an upgrade to RedHat 5.0It would be very nice if > you send me your checkpassword.c > I've include a patch, you should be able to apply, to a RedHat 5.0 (i386, don't know about alphas or sparcs) It also makes a file qmail-pop3, which needs to be put in the /etc/pam.d directory. You can comment out the first line of qmail-pop3, I have it in there, if I want to disallow certain people from getting e-mail, the late payers, that you know will pay you, but you want them to squirm a little... to use it you need to create a file in /etc called no_mail, any username in that file, will not be able to pop their mail. . ;) The patch should work on RedHat 4.2, You would just comment out the -lcrypt line in the Makefile. This isn't very portable, I stripped out most everything that wasn't needed for RedHat. later Kelley PS- If this message is too long, I apologize and reprimand me accordingly, the powers that be.. ---[Cut here]------- diff -ur orig/Makefile checkpw/Makefile --- orig/Makefile Fri Dec 12 16:02:24 1997 +++ checkpw/Makefile Fri Dec 12 16:07:13 1997 @@ -2,17 +2,21 @@ # SHADOWLIBS=-lshadow # SHADOWOPTS=-DPW_SHADOW # To use shadow passwords under Solaris, uncomment the SHADOWOPTS line. +PAM_LIBS= -lpam -ldl -lcrypt CC=cc $(SHADOWOPTS) LD=cc -s +OBJS=checkpassword.o log_pam.o all: checkpassword -checkpassword: checkpassword.o - $(LD) -o checkpassword checkpassword.o $(SHADOWLIBS) +checkpassword: $(OBJS) + $(LD) -o checkpassword $(OBJS) $(SHADOWLIBS) $(PAM_LIBS) -checkpassword.o: checkpassword.c - $(CC) -c checkpassword.c +#checkpassword.o: checkpassword.c +# $(CC) -c checkpassword.c +#log_pam.o: log_pam.c +# $(CC) -c log_pam.c shar: FILES shar -m `cat FILES` > checkpassword.shar diff -ur orig/checkpassword.c checkpw/checkpassword.c --- orig/checkpassword.c Fri Dec 12 16:02:24 1997 +++ checkpw/checkpassword.c Fri Dec 12 16:13:50 1997 @@ -1,10 +1,4 @@ #include -#ifdef PW_SHADOW -#include -#endif -#ifdef AIX -#include -#endif #include extern int errno; extern char *crypt(); @@ -30,12 +24,6 @@ char **argv; { struct passwd *pw; -#ifdef PW_SHADOW - struct spwd *spw; -#endif -#ifdef AIX - struct userpw *spw; -#endif char *login; char *password; char *stored; @@ -71,26 +59,14 @@ pw = getpwnam(login); if (!pw) _exit(1); /* XXX: unfortunately getpwnam() hides temporary errors */ -#ifdef PW_SHADOW - spw = getspnam(login); - if (!spw) _exit(1); /* XXX: again, temp hidden */ - stored = spw->sp_pwdp; -#else -#ifdef AIX - spw = getuserpw(login); - if (!spw) _exit(1); /* XXX: and again */ - stored = spw->upw_passwd; -#else - stored = pw->pw_passwd; -#endif -#endif - - encrypted = crypt(password,stored); +/* if (!*stored || strcmp(encrypted,stored)) _exit(1); */ + if (!pam_pop3_check(login,password)) + { + for (i = 0;i < sizeof(up);++i) up[i] = 0; + _exit(1); + } for (i = 0;i < sizeof(up);++i) up[i] = 0; - - if (!*stored || strcmp(encrypted,stored)) _exit(1); - if (setgid(pw->pw_gid) == -1) _exit(1); if (setuid(pw->pw_uid) == -1) _exit(1); if (chdir(pw->pw_dir) == -1) _exit(111); diff -ur orig/log_pam.c checkpw/log_pam.c --- orig/log_pam.c Fri Dec 12 16:16:09 1997 +++ checkpw/log_pam.c Fri Dec 12 16:07:13 1997 @@ -0,0 +1,126 @@ +/* + * Program: Pluggable Authentication Modules login services + * + * Author: Michael K. Johnson + * Red Hat Software + * Internet: johnsonm@redhat.com + * + * + */ +/* + * This majority of this code was lifted from the src.rpm for imap + * in the RedHat-4.2 updates directory + * by Kelley Lingerfelt redhat@cococo.net + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* Static variables used to communicate between the conversation function + * and the server_login function + */ +static char *PAM_username; +static char *PAM_password; +static int PAM_error = 0; + +/* for compability with older pam stuff, before the stupid transposition */ +#ifndef PAM_CRED_ESTABLISH +#define PAM_CRED_ESTABLISH 0x0002U +#endif + +/* PAM conversation function + * Here we assume (for now, at least) that echo on means login name, and + * echo off means password. + */ +static int PAM_conv (int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) { + int count = 0, replies = 0; + struct pam_response *reply = NULL; + int size = sizeof(struct pam_response); + + #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \ + if (!reply) return PAM_CONV_ERR; \ + size += sizeof(struct pam_response) + #define COPY_STRING(s) (s) ? strdup(s) : (char *)NULL + + for (count = 0; count < num_msg; count++) { + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + GET_MEM; + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies++].resp = COPY_STRING(PAM_username); + /* PAM frees resp */ + break; + case PAM_PROMPT_ECHO_OFF: + GET_MEM; + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies++].resp = COPY_STRING(PAM_password); + /* PAM frees resp */ + break; + case PAM_TEXT_INFO: + /* ignore it... */ + break; + case PAM_ERROR_MSG: + default: + /* Must be an error of some sort... */ + free (reply); + PAM_error = 1; + return PAM_CONV_ERR; + } + } + if (reply) *resp = reply; + return PAM_SUCCESS; +} +static struct pam_conv PAM_conversation = { + &PAM_conv, + NULL +}; + +/* Server log in + * Accepts: user name string + * password string + * Returns: T if password validated, NIL otherwise + */ +int pam_pop3_check (char *user, char *pass) +{ + pam_handle_t *pamh; + int pam_error; +/* char tmp[MAILTMPLEN]; */ + struct passwd *pw = getpwnam (user); + + /* Now use PAM to do authentication. For now, we won't worry about + * session logging, only authentication. Bail out if there are any + * errors. Since this is a limited protocol, and an even more limited + * function within a server speaking this protocol, we can't be as + * verbose as would otherwise make sense. It would be nice if we + * could return a string for the server to pass the the client and/or + * log, but that doesn't exist right now. If it is ever added, PAM + * could make good use of it. + * Query: should we be using PAM_SILENT to shut PAM up? + */ + #define PAM_BAIL if (PAM_error || (pam_error != PAM_SUCCESS)) { \ + pam_end(pamh, 0); return 0; \ + } + PAM_password = pass; + PAM_username = user; + pam_error = pam_start("qmail-pop3", user, &PAM_conversation, &pamh); + PAM_BAIL; + pam_error = pam_authenticate(pamh, 0); + PAM_BAIL; + pam_error = pam_acct_mgmt(pamh, 0); + PAM_BAIL; + pam_error = pam_setcred(pamh, PAM_CRED_ESTABLISH); + PAM_BAIL; + + pam_end(pamh, PAM_SUCCESS); + /* If this point is reached, the user has been authenticated. */ + return 1; +} diff -ur orig/qmail-pop3 checkpw/qmail-pop3 --- orig/qmail-pop3 Fri Dec 12 17:20:03 1997 +++ checkpw/qmail-pop3 Fri Dec 12 17:24:08 1997 @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth required /lib/security/pam_listfile.so onerr=fail item=user sense=deny file=/etc/no_mail +auth required /lib/security/pam_pwdb.so shadow nullok +account required /lib/security/pam_pwdb.so .