Port ftpd to utmpx.

Unfortunately I have to partially wreck its functionality, though. ftpd
used to keep a file descriptor to the wtmp, which allowed it to work
from within a chroot. The current utmpx implementation doesn't offer a
way to do this. Maybe we can address this in the future, if it turns out
to be a real issue.
This commit is contained in:
Ed Schouten 2010-01-13 18:28:41 +00:00
parent 960aa5e071
commit 80643af02b
2 changed files with 38 additions and 52 deletions
libexec/ftpd

@ -173,8 +173,7 @@ static struct ftphost {
char remotehost[NI_MAXHOST]; char remotehost[NI_MAXHOST];
char *ident = NULL; char *ident = NULL;
static char ttyline[20]; static char wtmpid[20];
char *tty = ttyline; /* for klogin */
#ifdef USE_PAM #ifdef USE_PAM
static int auth_pam(struct passwd**, const char*); static int auth_pam(struct passwd**, const char*);
@ -584,8 +583,7 @@ gotchild:
data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1); data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
/* set this here so klogin can use it... */ (void)snprintf(wtmpid, sizeof(wtmpid), "%xftpd", getpid());
(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
/* Try to handle urgent data inline */ /* Try to handle urgent data inline */
#ifdef SO_OOBINLINE #ifdef SO_OOBINLINE
@ -1180,8 +1178,8 @@ end_login(void)
#endif #endif
(void) seteuid(0); (void) seteuid(0);
if (logged_in && dowtmp) if (logged_in && dowtmp && !dochroot)
ftpd_logwtmp(ttyline, "", NULL); ftpd_logwtmp(wtmpid, "", NULL);
pw = NULL; pw = NULL;
#ifdef LOGIN_CAP #ifdef LOGIN_CAP
setusercontext(NULL, getpwuid(0), 0, setusercontext(NULL, getpwuid(0), 0,
@ -1476,9 +1474,16 @@ skip:
} }
#endif #endif
/* open wtmp before chroot */ dochroot =
if (dowtmp) checkuser(_PATH_FTPCHROOT, pw->pw_name, 1, &residue)
ftpd_logwtmp(ttyline, pw->pw_name, #ifdef LOGIN_CAP /* Allow login.conf configuration as well */
|| login_getcapbool(lc, "ftp-chroot", 0)
#endif
;
chrootdir = NULL;
if (dowtmp && !dochroot)
ftpd_logwtmp(wtmpid, pw->pw_name,
(struct sockaddr *)&his_addr); (struct sockaddr *)&his_addr);
logged_in = 1; logged_in = 1;
@ -1491,13 +1496,6 @@ skip:
if (statfd < 0) if (statfd < 0)
stats = 0; stats = 0;
dochroot =
checkuser(_PATH_FTPCHROOT, pw->pw_name, 1, &residue)
#ifdef LOGIN_CAP /* Allow login.conf configuration as well */
|| login_getcapbool(lc, "ftp-chroot", 0)
#endif
;
chrootdir = NULL;
/* /*
* For a chrooted local user, * For a chrooted local user,
* a) see whether ftpchroot(5) specifies a chroot directory, * a) see whether ftpchroot(5) specifies a chroot directory,
@ -2732,9 +2730,9 @@ void
dologout(int status) dologout(int status)
{ {
if (logged_in && dowtmp) { if (logged_in && dowtmp && !dochroot) {
(void) seteuid(0); (void) seteuid(0);
ftpd_logwtmp(ttyline, "", NULL); ftpd_logwtmp(wtmpid, "", NULL);
} }
/* beware of flushing buffers after a SIGPIPE */ /* beware of flushing buffers after a SIGPIPE */
_exit(status); _exit(status);

@ -46,47 +46,35 @@ __FBSDID("$FreeBSD$");
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h> #include <libutil.h>
#include <time.h>
#include <timeconv.h>
#include <netdb.h>
#include <utmp.h>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <libutil.h> #include <unistd.h>
#include <utmpx.h>
#include "extern.h" #include "extern.h"
static int fd = -1;
/*
* Modified version of logwtmp that holds wtmp file open
* after first call, for use with ftp (which may chroot
* after login, but before logout).
*/
void void
ftpd_logwtmp(line, name, addr) ftpd_logwtmp(char *id, char *user, struct sockaddr *addr)
char *line, *name;
struct sockaddr *addr;
{ {
struct utmp ut; struct utmpx ut;
struct stat buf;
char host[UT_HOSTSIZE];
if (addr == NULL) memset(&ut, 0, sizeof(ut));
host[0] = '\0';
else
realhostname_sa(host, sizeof(host), addr, addr->sa_len);
if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) if (*user != '\0') {
return; /* Log in. */
if (fstat(fd, &buf) == 0) { ut.ut_type = USER_PROCESS;
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); (void)strncpy(ut.ut_user, user, sizeof(ut.ut_user));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); if (addr != NULL)
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); realhostname_sa(ut.ut_host, sizeof(ut.ut_host),
ut.ut_time = _time_to_time32(time(NULL)); addr, addr->sa_len);
if (write(fd, &ut, sizeof(struct utmp)) != } else {
sizeof(struct utmp)) /* Log out. */
(void)ftruncate(fd, buf.st_size); ut.ut_type = DEAD_PROCESS;
} }
ut.ut_pid = getpid();
gettimeofday(&ut.ut_tv, NULL);
(void)strncpy(ut.ut_id, id, sizeof(ut.ut_id));
pututxline(&ut);
} }