-.\" $OpenBSD: tftpd.8,v 1.8 2019/03/04 01:06:03 dlg Exp $
+.\" $OpenBSD: tftpd.8,v 1.9 2022/10/04 23:33:22 kn Exp $
.\"
.\" Copyright (c) 1983, 1991 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91
.\"
-.Dd $Mdocdate: March 4 2019 $
+.Dd $Mdocdate: October 4 2022 $
.Dt TFTPD 8
.Os
.Sh NAME
.Nd Trivial File Transfer Protocol daemon
.Sh SYNOPSIS
.Nm tftpd
-.Op Fl 46cdiv
+.Op Fl 46cdivw
.Op Fl l Ar address
.Op Fl p Ar port
.Op Fl r Ar socket
Due to the lack of authentication information,
.Nm
will allow only publicly readable files to be accessed.
+By default files may only be read, unless the
+.Fl w
+option is specified.
Files may be written only if they already exist and are publicly writable,
unless the
.Fl c
-flag is specified
-.Pq see below .
+flag is specified.
Note that this extends the concept of
.Dq public
to include
otherwise uploaded files must already exist.
Files are created with default permissions
allowing anyone to read or write to them.
+.Pp
+This option implies
+.Fl w .
.It Fl d
Do not daemonize.
If this option is specified,
on startup;
the remote host is not expected to pass the directory
as part of the file name to transfer.
+.It Fl w
+Allow files to be written to.
.El
.Sh SEE ALSO
.Xr tftp 1 ,
-/* $OpenBSD: tftpd.c,v 1.48 2022/10/04 07:05:28 kn Exp $ */
+/* $OpenBSD: tftpd.c,v 1.49 2022/10/04 23:33:22 kn Exp $ */
/*
* Copyright (c) 2012 David Gwynne <dlg@uq.edu.au>
usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-46cdiv] [-l address] [-p port] [-r socket]"
+ fprintf(stderr, "usage: %s [-46cdivw] [-l address] [-p port] [-r socket]"
" directory\n", __progname);
exit(1);
}
int cancreate = 0;
+int canwrite = 0;
int verbose = 0;
int debug = 0;
int iflag = 0;
int family = AF_UNSPEC;
int devnull = -1;
- while ((c = getopt(argc, argv, "46cdil:p:r:v")) != -1) {
+ while ((c = getopt(argc, argv, "46cdil:p:r:vw")) != -1) {
switch (c) {
case '4':
family = AF_INET;
family = AF_INET6;
break;
case 'c':
- cancreate = 1;
+ canwrite = cancreate = 1;
break;
case 'd':
verbose = debug = 1;
case 'v':
verbose = 1;
break;
+ case 'w':
+ canwrite = 1;
+ break;
default:
usage();
/* NOTREACHED */
if (cancreate) {
if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) == -1)
lerr(1, "pledge");
- } else {
+ } else if (canwrite) {
if (pledge("stdio rpath wpath fattr dns inet", NULL) == -1)
lerr(1, "pledge");
+ } else {
+ if (pledge("stdio rpath dns inet", NULL) == -1)
+ lerr(1, "pledge");
}
event_init();
const char *errstr, *filename;
char rewritten[PATH_MAX];
+ if (!canwrite && mode != RRQ)
+ return (EACCESS);
+
if (strcmp(requested, SEEDPATH) == 0) {
char *buf;
if (mode != RRQ)