* 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:
parent
19e9da1bad
commit
15b3c2bfae
@ -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
|
||||
|
@ -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 *
|
||||
|
Loading…
Reference in New Issue
Block a user