From 0b2fe68756570c146bda89ff69a3d209aac9f8be Mon Sep 17 00:00:00 2001 From: markm Date: Sun, 19 Sep 1999 22:05:32 +0000 Subject: Fix for new Kerberos4. Make a fist cut at PAM-ising while I'm here. --- libexec/ftpd/Makefile | 12 ++-- libexec/ftpd/ftpd.c | 160 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 145 insertions(+), 27 deletions(-) (limited to 'libexec/ftpd') diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile index bd5453f..ad5d142 100644 --- a/libexec/ftpd/Makefile +++ b/libexec/ftpd/Makefile @@ -17,13 +17,11 @@ LSDIR= ../../bin/ls SRCS+= ls.c cmp.c print.c stat_flags.c util.c CFLAGS+=-DINTERNAL_LS -Dmain=ls_main -I${.CURDIR}/${LSDIR} -.if exists(${DESTDIR}/usr/lib/libkrb.a) && defined(MAKE_KERBEROS4) -.PATH: ${.CURDIR}/../../lib/libpam/modules/pam_kerberosIV -SRCS+= klogin.c -LDADD+= -lkrb -ldes -lcom_err -DPADD+= ${LIBKRB} ${LIBDES} ${LIBCOM_ERR} -CFLAGS+=-DKERBEROS -DISTRIBUTION= krb +.if defined(NOPAM) +CFLAGS+=-DNOPAM +.else +DPADD+= ${LIBPAM} +LDADD+= ${MINUSLPAM} .endif .include diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 52321ef..0f9d20c 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -94,6 +94,10 @@ static const char rcsid[] = #include #endif +#if !defined(NOPAM) +#include +#endif + #include "pathnames.h" #include "extern.h" @@ -168,19 +172,13 @@ char *ident = NULL; static char ttyline[20]; char *tty = ttyline; /* for klogin */ -#ifdef KERBEROS -int klogin __P((struct passwd *, char *, char *, char *)); +#if !defined(NOPAM) +static int auth_pam __P((struct passwd**, const char*)); #endif struct in_addr bind_address; char *pid_file = NULL; -#if defined(KERBEROS) -int notickets = 1; -int noticketsdontcomplain = 1; -char *krbtkfile_env = NULL; -#endif - /* * Timeout intervals for retrying connections * to hosts that don't accept PORT cmds. This @@ -914,6 +912,132 @@ end_login() dochroot = 0; } +#if !defined(NOPAM) + +/* + * the following code is stolen from imap-uw PAM authentication module and + * login.c + */ +#define COPY_STRING(s) (s ? strdup(s) : NULL) + +struct cred_t { + const char *uname; /* user name */ + const char *pass; /* password */ +}; +typedef struct cred_t cred_t; + +static int +auth_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata) +{ + int i; + cred_t *cred = (cred_t *) appdata; + struct pam_response *reply = + malloc(sizeof(struct pam_response) * num_msg); + + for (i = 0; i < num_msg; i++) { + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_ON: /* assume want user name */ + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = COPY_STRING(cred->uname); + /* PAM frees resp. */ + break; + case PAM_PROMPT_ECHO_OFF: /* assume want password */ + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = COPY_STRING(cred->pass); + /* PAM frees resp. */ + break; + case PAM_TEXT_INFO: + case PAM_ERROR_MSG: + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = NULL; + break; + default: /* unknown message style */ + free(reply); + return PAM_CONV_ERR; + } + } + + *resp = reply; + return PAM_SUCCESS; +} + +/* + * Attempt to authenticate the user using PAM. Returns 0 if the user is + * authenticated, or 1 if not authenticated. If some sort of PAM system + * error occurs (e.g., the "/etc/pam.conf" file is missing) then this + * function returns -1. This can be used as an indication that we should + * fall back to a different authentication mechanism. + */ +static int +auth_pam(struct passwd **ppw, const char *pass) +{ + pam_handle_t *pamh = NULL; + const char *tmpl_user; + const void *item; + int rval; + int e; + cred_t auth_cred = { (*ppw)->pw_name, pass }; + struct pam_conv conv = { &auth_conv, &auth_cred }; + + e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh); + if (e != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); + return -1; + } + + e = pam_authenticate(pamh, 0); + switch (e) { + case PAM_SUCCESS: + /* + * With PAM we support the concept of a "template" + * user. The user enters a login name which is + * authenticated by PAM, usually via a remote service + * such as RADIUS or TACACS+. If authentication + * succeeds, a different but related "template" name + * is used for setting the credentials, shell, and + * home directory. The name the user enters need only + * exist on the remote authentication server, but the + * template name must be present in the local password + * database. + * + * This is supported by two various mechanisms in the + * individual modules. However, from the application's + * point of view, the template user is always passed + * back as a changed value of the PAM_USER item. + */ + if ((e = pam_get_item(pamh, PAM_USER, &item)) == + PAM_SUCCESS) { + tmpl_user = (const char *) item; + if (strcmp((*ppw)->pw_name, tmpl_user) != 0) + *ppw = getpwnam(tmpl_user); + } else + syslog(LOG_ERR, "Couldn't get PAM_USER: %s", + pam_strerror(pamh, e)); + rval = 0; + break; + + case PAM_AUTH_ERR: + case PAM_USER_UNKNOWN: + case PAM_MAXTRIES: + rval = 1; + break; + + default: + syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e)); + rval = -1; + break; + } + + if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); + rval = -1; + } + return rval; +} + +#endif /* !defined(NOPAM) */ + void pass(passwd) char *passwd; @@ -934,9 +1058,9 @@ pass(passwd) rval = 1; /* failure below */ goto skip; } -#if defined(KERBEROS) - rval = klogin(pw, "", hostname, passwd); - if (rval == 0) +#if !defined(NOPAM) + rval = auth_pam(&pw, passwd); + if (rval >= 0) goto skip; #endif #ifdef SKEY @@ -953,7 +1077,7 @@ pass(passwd) skip: /* * If rval == 1, the user failed the authentication check - * above. If rval == 0, either Kerberos or local authentication + * above. If rval == 0, either PAM or local authentication * succeeded. */ if (rval) { @@ -1085,14 +1209,14 @@ skip: if (thishost != firsthost) snprintf(proctitle, sizeof(proctitle), "%s: anonymous(%s)/%.*s", remotehost, hostname, - sizeof(proctitle) - sizeof(remotehost) - - sizeof(": anonymous/"), passwd); + (int)(sizeof(proctitle) - sizeof(remotehost) - + sizeof(": anonymous/")), passwd); else #endif snprintf(proctitle, sizeof(proctitle), "%s: anonymous/%.*s", remotehost, - sizeof(proctitle) - sizeof(remotehost) - - sizeof(": anonymous/"), passwd); + (int)(sizeof(proctitle) - sizeof(remotehost) - + sizeof(": anonymous/")), passwd); setproctitle("%s", proctitle); #endif /* SETPROCTITLE */ if (logging) @@ -1937,10 +2061,6 @@ dologout(status) if (logged_in) { (void) seteuid((uid_t)0); ftpd_logwtmp(ttyline, "", ""); -#if defined(KERBEROS) - if (!notickets && krbtkfile_env) - unlink(krbtkfile_env); -#endif } /* beware of flushing buffers after a SIGPIPE */ _exit(status); -- cgit v1.1