[syslinux] truncated files on write with tftpd-hpa

Alan Sundell asundell+syslinux at fas.harvard.edu
Wed Jul 9 12:49:33 PDT 2003


On Wed, Jul 09, 2003 at 03:46:34PM -0400, Alan Sundell wrote:
> I've attached the two patches to this message.  They are, as I said,
> quick and dirty, but they should give you an idea of what I'm talking
> about.

I am an idiot.  Now they are attached. :)

--Alan
-------------- next part --------------
diff -ur ../prod/tftp-hpa-0.34/tftpd/tftpd.c tftp-hpa-0.34-late-truncate/tftpd/tftpd.c
--- ../prod/tftp-hpa-0.34/tftpd/tftpd.c	Sat Apr 12 02:54:58 2003
+++ tftp-hpa-0.34-late-truncate/tftpd/tftpd.c	Fri May  9 16:20:08 2003
@@ -1085,7 +1085,6 @@
    */
   wmode = O_WRONLY |
     (cancreate ? O_CREAT : 0) |
-    (unixperms ? O_TRUNC : 0) |
     (pf->f_convert ? O_TEXT : O_BINARY);
   rmode = O_RDONLY |
     (pf->f_convert ? O_TEXT : O_BINARY);
@@ -1122,14 +1121,6 @@
 	*errmsg = "File must have global write permissions";
 	return (EACCESS);
       }
-
-      /* We didn't get to truncate the file at open() time */
-#ifdef HAVE_FTRUNCATE
-      if ( ftruncate(fd, (off_t)0) ) {
-	*errmsg = "Cannot reset file size";
-	return(EACCESS);
-      }
-#endif
     }
     tsize = 0;
     tsize_ok = 1;
@@ -1261,6 +1252,9 @@
   static struct tftphdr *ap;    /* ack buffer */
   static u_short block = 0;
   static int acksize;
+#ifdef HAVE_FTRUNCATE
+  static int truncated = 0;
+#endif
   u_short dp_opcode, dp_block;
 
   dp = w_init();
@@ -1289,6 +1283,18 @@
       if (n < 0) {		/* really? */
 	syslog(LOG_WARNING, "tftpd: read: %m");
 	goto abort;
+#ifdef HAVE_FTRUNCATE
+      /* truncate the file after the first successful ACK.
+       * FIXME: what do we do if we don't have ftruncate? */
+      } else if (!truncated) {
+          /* We don't want to truncate the file at open() time to avoid
+           * data loss in case this was a re-transmitted WRQ */
+          if ( ftruncate(fileno(file), (off_t)0) ) {
+            syslog(LOG_WARNING, "tftpd: truncate: %m");
+            goto abort;
+          }
+          truncated++;
+#endif
       }
       dp_opcode = ntohs((u_short)dp->th_opcode);
       dp_block = ntohs((u_short)dp->th_block);
-------------- next part --------------
diff -ur ../prod/tftp-hpa-0.34/tftpd/tftpd.c tftp-hpa-0.34-track-requestors/tftpd/tftpd.c
--- ../prod/tftp-hpa-0.34/tftpd/tftpd.c	Sat Apr 12 02:54:58 2003
+++ tftp-hpa-0.34-track-requestors/tftpd/tftpd.c	Fri May  9 18:22:13 2003
@@ -108,6 +108,11 @@
 
 int verbosity = 0;
 
+#ifdef TRACK_REQUESTS
+static struct sockrecord *srbase = NULL;
+int check_recent (struct sockaddr_in *sa);
+#endif
+
 struct formats;
 #ifdef WITH_REGEX
 static struct rule *rewrite_rules = NULL;
@@ -567,6 +572,15 @@
       memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, sizeof bindaddr.sin_addr);
     }
 
+#ifdef TRACK_REQUESTS
+    /* before forking, check to see if we've seen this address recently */
+    if (check_recent(&from)) {
+      syslog(LOG_WARNING, "received duplicate request from %s:%d",
+              inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+      continue;
+    }
+#endif
+
     /*
      * Now that we have read the request packet from the UDP
      * socket, we fork and go back to listening to the socket.
@@ -684,6 +698,64 @@
   exit(0);
 }
 
+#ifdef TRACK_REQUESTS
+int
+check_recent(struct sockaddr_in *sa)
+{
+    struct sockrecord *srcurrent, *srprev;
+    time_t expired;
+
+    /* determine the time at which records expire */
+    expired = time(NULL) - KEEP_RECORDS;
+
+    srprev = NULL;
+    srcurrent = srbase;
+    /* otherwise, loop through the list, looking for duplicates */
+    while (srcurrent) {
+        syslog(LOG_NOTICE, "examining srcurrent record for %s:%d",
+                inet_ntoa(srcurrent->sin.sin_addr),
+                ntohs(srcurrent->sin.sin_port));
+        /* remove expired entries */
+        if (srcurrent->time < expired) {
+            syslog(LOG_NOTICE, "srcurrent record for %s:%d is expired",
+                    inet_ntoa(srcurrent->sin.sin_addr),
+                    ntohs(srcurrent->sin.sin_port));
+            if (srprev) {
+                /* link the next entry to the ->next of the previous entry */
+                srprev->next = srcurrent->next;
+                free(srcurrent);
+                srcurrent = srprev->next;
+            } else {
+                /* link the next entry to the base */
+                srbase = srcurrent->next;
+                free(srcurrent);
+                srcurrent = srbase;
+            }
+            continue;
+        }
+        /* see if our entry matches this one */
+        if (!memcmp(&srcurrent->sin, sa, sizeof(struct sockaddr_in)))
+            return 1;
+
+        /* otherwise, remember srprev for removals */
+        srprev = srcurrent;
+        srcurrent = srcurrent->next;
+    }
+
+    /* set up a new record at the head of the list */
+    srcurrent = (struct sockrecord *) malloc (sizeof (struct sockrecord));
+    memcpy (&srcurrent->sin, sa, sizeof(struct sockaddr_in));
+    srcurrent->time = time(NULL);
+
+    syslog(LOG_NOTICE, "adding record for %s:%d",
+            inet_ntoa(srcurrent->sin.sin_addr),
+            ntohs(srcurrent->sin.sin_port));
+    srcurrent->next = srbase;
+    srbase = srcurrent;
+    return 0;
+}
+#endif
+
 char   *rewrite_access(char *, int, const char **);
 int	validate_access(char *, int, struct formats *, const char **);
 void	tftp_sendfile(struct formats *, struct tftphdr *, int);
diff -ur ../prod/tftp-hpa-0.34/tftpd/tftpd.h tftp-hpa-0.34-track-requestors/tftpd/tftpd.h
--- ../prod/tftp-hpa-0.34/tftpd/tftpd.h	Mon Nov 12 05:03:04 2001
+++ tftp-hpa-0.34-track-requestors/tftpd/tftpd.h	Mon Jun  9 14:11:25 2003
@@ -24,4 +24,13 @@
 
 extern int verbosity;
 
+#ifdef TRACK_REQUESTS
+#define KEEP_RECORDS 60
+struct sockrecord {
+        struct sockaddr_in      sin;
+        time_t                  time;
+        struct sockrecord       *next;
+};
+#endif
+
 #endif


More information about the Syslinux mailing list