[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