* implement -u user and -g group - to specify the username and/or

group to run as.
  if -u isn't given, user defaults to "nobody".
  if -g isn't given, group defaults to the primary group of user.
  doesn't try and change uid or gid if they're already set ok.
  should solve PR 4218.
* deprecate register
* deprecate trailing \n in syslog messages
This commit is contained in:
lukem 1998-07-29 11:31:22 +00:00
parent 19e9da1bad
commit 15b3c2bfae
2 changed files with 143 additions and 46 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: tftpd.8,v 1.7 1998/06/08 12:41:43 lukem Exp $
.\" $NetBSD: tftpd.8,v 1.8 1998/07/29 11:31:22 lukem Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -33,7 +33,7 @@
.\"
.\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dd July 29, 1998
.Dt TFTPD 8
.Os BSD 4.2
.Sh NAME
@ -43,9 +43,11 @@
Internet Trivial File Transfer Protocol server
.Sh SYNOPSIS
.Nm
.Op Fl s Ar directory
.Op Fl g Ar group
.Op Fl l
.Op Fl n
.Op Fl s Ar directory
.Op Fl u Ar user
.Op Ar directory ...
.Sh DESCRIPTION
.Nm
@ -92,17 +94,27 @@ The given directories are also treated as a search path for
relative filename requests.
.Pp
The options are:
.Bl -tag -width Ds
.Bl -tag -width "directory"
.It Fl g Ar group
Change gid to that of
.Ar group
on startup.
If this isn't specified, the gid is set to that of the
.Ar user
specified with
.Fl u .
.It Fl l
Logs all requests using
.Xr syslog 3 .
.It Fl n
Suppresses negative acknowledgement of requests for nonexistent
relative filenames.
.It Fl s
.It Fl s Ar directory
.Nm
will
.Xr chroot 2
to
.Ar directory
on startup.
This is recommended for security reasons (so that files other than
those in the
@ -116,6 +128,21 @@ to
.Sq \&.
under
.Pa /tftpboot .
.It Fl u Ar user
Change uid to that of
.Ar user
on startup.
If
.Fl u
isn't given,
.Ar user
defaults to
.Dq nobody .
If
.Fl g
isn't also given, change the gid to that of
.Ar user
as well.
.El
.Pp
.Sh SEE ALSO
@ -131,6 +158,13 @@ The
.Fl s
flag appeared in
.Nx 1.0 .
.Pp
The
.Fl g
and
.Fl u
flags appeared in
.Nx 1.4 .
.Sh SECURITY CONSIDERATIONS
You are
.Em strongly

View File

@ -1,4 +1,4 @@
/* $NetBSD: tftpd.c,v 1.13 1998/07/26 15:02:27 mycroft Exp $ */
/* $NetBSD: tftpd.c,v 1.14 1998/07/29 11:31:22 lukem Exp $ */
/*
* Copyright (c) 1983, 1993
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: tftpd.c,v 1.13 1998/07/26 15:02:27 mycroft Exp $");
__RCSID("$NetBSD: tftpd.c,v 1.14 1998/07/29 11:31:22 lukem Exp $");
#endif
#endif /* not lint */
@ -66,7 +66,9 @@ __RCSID("$NetBSD: tftpd.c,v 1.13 1998/07/26 15:02:27 mycroft Exp $");
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
@ -77,9 +79,7 @@ __RCSID("$NetBSD: tftpd.c,v 1.13 1998/07/26 15:02:27 mycroft Exp $");
#include "tftpsubs.h"
/* XXX svr4 defines UID_NOBODY and GID_NOBODY constants in <sys/param.h> */
#define UID_NOBODY 32767
#define GID_NOBODY 32766
#define DEFAULTUSER "nobody"
#define TIMEOUT 5
@ -140,7 +140,9 @@ struct formats {
static void
usage()
{
syslog(LOG_ERR, "Usage: %s [-s] [directory ...]\n", __progname);
syslog(LOG_ERR,
"Usage: %s [-ln] [-u user] [-g group] [-s directory] [directory ...]",
__progname);
exit(1);
}
@ -149,16 +151,31 @@ main(argc, argv)
int argc;
char **argv;
{
register struct tftphdr *tp;
register int n = 0;
struct passwd *pwent;
struct group *grent;
struct tftphdr *tp;
int n = 0;
int ch, on;
int fd = 0;
struct sockaddr_in sin;
char *tgtuser, *tgtgroup, *ep;
uid_t curuid, tgtuid;
gid_t curgid, tgtgid;
long nid;
openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
tgtuser = DEFAULTUSER;
tgtgroup = NULL;
curuid = getuid();
curgid = getgid();
while ((ch = getopt(argc, argv, "lns:")) != -1)
while ((ch = getopt(argc, argv, "g:lns:u:")) != -1)
switch (ch) {
case 'g':
tgtgroup = optarg;
break;
case 'l':
logging = 1;
break;
@ -172,6 +189,10 @@ main(argc, argv)
securedir = optarg;
break;
case 'u':
tgtuser = optarg;
break;
default:
usage();
break;
@ -191,42 +212,84 @@ main(argc, argv)
}
}
if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0'))
usage();
nid = (strtol(tgtuser, &ep, 10));
if (*ep == '\0') {
if (nid > UID_MAX) {
syslog(LOG_ERR, "uid %ld is too large", nid);
exit(1);
}
pwent = getpwuid((uid_t)nid);
} else
pwent = getpwnam(tgtuser);
if (pwent == NULL) {
syslog(LOG_ERR, "unknown user `%s'", tgtuser);
exit(1);
}
tgtuid = pwent->pw_uid;
tgtgid = pwent->pw_gid;
if (tgtgroup != NULL) {
nid = (strtol(tgtgroup, &ep, 10));
if (*ep == '\0') {
if (nid > GID_MAX) {
syslog(LOG_ERR, "gid %ld is too large", nid);
exit(1);
}
grent = getgrgid((gid_t)nid);
} else
grent = getgrnam(tgtgroup);
if (grent != NULL)
tgtgid = grent->gr_gid;
else {
syslog(LOG_ERR, "unknown group `%s'", tgtgroup);
exit(1);
}
}
if (secure) {
if (chdir(securedir) < 0) {
syslog(LOG_ERR, "chdir %s: %m", securedir);
exit(1);
}
if (chroot(".")) {
syslog(LOG_ERR, "chroot: %m\n");
syslog(LOG_ERR, "chroot: %m");
exit(1);
}
}
if (setgid(GID_NOBODY)) {
syslog(LOG_ERR, "setgid: %m");
exit(1);
syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)",
tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)" , tgtgid);
if (curgid != tgtgid) {
if (setgid(tgtgid)) {
syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid);
exit(1);
}
if (setgroups(0, NULL)) {
syslog(LOG_ERR, "setgroups: %m");
exit(1);
}
}
if (setgroups(0, NULL)) {
syslog(LOG_ERR, "setgroups: %m");
exit(1);
}
if (setuid(UID_NOBODY)) {
syslog(LOG_ERR, "setuid: %m");
exit(1);
if (curuid != tgtuid) {
if (setuid(tgtuid)) {
syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid);
exit(1);
}
}
on = 1;
if (ioctl(fd, FIONBIO, &on) < 0) {
syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
exit(1);
}
fromlen = sizeof (from);
n = recvfrom(fd, buf, sizeof (buf), 0,
(struct sockaddr *)&from, &fromlen);
if (n < 0) {
syslog(LOG_ERR, "recvfrom: %m\n");
syslog(LOG_ERR, "recvfrom: %m");
exit(1);
}
/*
@ -273,7 +336,7 @@ main(argc, argv)
}
}
if (pid < 0) {
syslog(LOG_ERR, "fork: %m\n");
syslog(LOG_ERR, "fork: %m");
exit(1);
} else if (pid != 0) {
exit(0);
@ -286,17 +349,17 @@ main(argc, argv)
close(1);
peer = socket(AF_INET, SOCK_DGRAM, 0);
if (peer < 0) {
syslog(LOG_ERR, "socket: %m\n");
syslog(LOG_ERR, "socket: %m");
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
syslog(LOG_ERR, "bind: %m\n");
syslog(LOG_ERR, "bind: %m");
exit(1);
}
if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
syslog(LOG_ERR, "connect: %m\n");
syslog(LOG_ERR, "connect: %m");
exit(1);
}
tp = (struct tftphdr *)buf;
@ -314,9 +377,9 @@ tftp(tp, size)
struct tftphdr *tp;
int size;
{
register char *cp;
char *cp;
int first = 1, ecode;
register struct formats *pf;
struct formats *pf;
char *filename, *mode = NULL; /* XXX gcc */
filename = cp = tp->th_stuff;
@ -494,8 +557,8 @@ sendfile(pf)
struct formats *pf;
{
struct tftphdr *dp;
register struct tftphdr *ap; /* ack packet */
register int size, n;
struct tftphdr *ap; /* ack packet */
int size, n;
volatile int block;
signal(SIGALRM, timer);
@ -515,7 +578,7 @@ sendfile(pf)
send_data:
if (send(peer, dp, size + 4, 0) != size + 4) {
syslog(LOG_ERR, "tftpd: write: %m\n");
syslog(LOG_ERR, "tftpd: write: %m");
goto abort;
}
read_ahead(file, pf->f_convert);
@ -524,7 +587,7 @@ send_data:
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
alarm(0);
if (n < 0) {
syslog(LOG_ERR, "tftpd: read: %m\n");
syslog(LOG_ERR, "tftpd: read: %m");
goto abort;
}
ap->th_opcode = ntohs((u_short)ap->th_opcode);
@ -564,8 +627,8 @@ recvfile(pf)
struct formats *pf;
{
struct tftphdr *dp;
register struct tftphdr *ap; /* ack buffer */
register int n, size;
struct tftphdr *ap; /* ack buffer */
int n, size;
volatile int block;
signal(SIGALRM, timer);
@ -580,7 +643,7 @@ recvfile(pf)
(void) setjmp(timeoutbuf);
send_ack:
if (send(peer, ackbuf, 4, 0) != 4) {
syslog(LOG_ERR, "tftpd: write: %m\n");
syslog(LOG_ERR, "tftpd: write: %m");
goto abort;
}
write_behind(file, pf->f_convert);
@ -589,7 +652,7 @@ send_ack:
n = recv(peer, dp, PKTSIZE, 0);
alarm(0);
if (n < 0) { /* really? */
syslog(LOG_ERR, "tftpd: read: %m\n");
syslog(LOG_ERR, "tftpd: read: %m");
goto abort;
}
dp->th_opcode = ntohs((u_short)dp->th_opcode);
@ -654,7 +717,7 @@ errtomsg(error)
int error;
{
static char buf[20];
register const struct errmsg *pe;
const struct errmsg *pe;
if (error == 0)
return "success";
@ -675,9 +738,9 @@ static void
nak(error)
int error;
{
register struct tftphdr *tp;
struct tftphdr *tp;
int length;
register const struct errmsg *pe;
const struct errmsg *pe;
tp = (struct tftphdr *)buf;
tp->th_opcode = htons((u_short)ERROR);
@ -695,7 +758,7 @@ nak(error)
tp->th_msg[length] = '\0';
length += 5;
if (send(peer, buf, length, 0) != length)
syslog(LOG_ERR, "nak: %m\n");
syslog(LOG_ERR, "nak: %m");
}
static char *