Add a -R flag to tftpd for a read only mode. This allows for a tighter
pledge than currently possible because by default existing files can be
overwritten (but no new files created). Perhaps read only should be the
default since it is surprising that tftp can overwrite by default.

- Matthew Martin



Index: tftpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/tftpd/tftpd.8,v
retrieving revision 1.5
diff -u -p -r1.5 tftpd.8
--- tftpd.8     18 Jul 2015 05:32:56 -0000      1.5
+++ tftpd.8     24 Jan 2016 08:49:11 -0000
@@ -37,7 +37,7 @@
 .Nd DARPA Trivial File Transfer Protocol daemon
 .Sh SYNOPSIS
 .Nm tftpd
-.Op Fl 46cdv
+.Op Fl 46cdRv
 .Op Fl l Ar address
 .Op Fl p Ar port
 .Op Fl r Ar socket
@@ -113,6 +113,8 @@ listens on the port indicated in the
 .Ql tftp
 service description; see
 .Xr services 5 .
+.It Fl R
+Only allow read requests.
 .It Fl r Ar socket
 Issue filename rewrite requests to the specified UNIX domain socket.
 .Nm
Index: tftpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/tftpd/tftpd.c,v
retrieving revision 1.34
diff -u -p -r1.34 tftpd.c
--- tftpd.c     14 Dec 2015 16:34:55 -0000      1.34
+++ tftpd.c     24 Jan 2016 08:49:11 -0000
@@ -268,6 +268,7 @@ usage(void)
 }
 
 int              cancreate = 0;
+int              readonly = 0;
 int              verbose = 0;
 
 int
@@ -286,7 +287,7 @@ main(int argc, char *argv[])
        char *port = "tftp";
        int family = AF_UNSPEC;
 
-       while ((c = getopt(argc, argv, "46cdl:p:r:v")) != -1) {
+       while ((c = getopt(argc, argv, "46cdl:p:Rr:v")) != -1) {
                switch (c) {
                case '4':
                        family = AF_INET;
@@ -296,6 +297,7 @@ main(int argc, char *argv[])
                        break;
                case 'c':
                        cancreate = 1;
+                       readonly = 0;
                        break;
                case 'd':
                        verbose = debug = 1;
@@ -306,6 +308,10 @@ main(int argc, char *argv[])
                case 'p':
                        port = optarg;
                        break;
+               case 'R':
+                       readonly = 1;
+                       cancreate = 0;
+                       break;
                case 'r':
                        rewrite = optarg;
                        break;
@@ -358,8 +364,13 @@ main(int argc, char *argv[])
            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                errx(1, "can't drop privileges");
 
-       if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) == -1)
-               err(1, "pledge");
+       if (readonly) {
+               if (pledge("stdio rpath dns inet", NULL) == -1)
+                       err(1, "pledge");
+       } else {
+               if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) == 
-1)
+                       err(1, "pledge");
+       }
 
        event_init();
 
@@ -966,7 +977,7 @@ validate_access(struct tftp_client *clie
                        if ((stbuf.st_mode & (S_IRUSR >> 6)) == 0)
                                return (EACCESS);
                } else {
-                       if ((stbuf.st_mode & (S_IWUSR >> 6)) == 0)
+                       if (readonly || (stbuf.st_mode & (S_IWUSR >> 6)) == 0)
                                return (EACCESS);
                }
        }

Reply via email to