#! /bin/sh /usr/share/dpatch/dpatch-run
## 02_avoid_buffer_overflows.dpatch by Daniel Kahn Gillmor <dkg@fifthhorseman.net>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Cleaning up all strcpy, strcat, and sprintf invocations to avoid
## DP: common buffer overflows at least.

@DPATCH@
diff -urNad tweak~/actions.c tweak/actions.c
--- tweak~/actions.c	2007-03-14 00:42:05.000000000 -0400
+++ tweak/actions.c	2008-03-16 20:06:29.796165664 -0400
@@ -139,14 +139,14 @@
     if (!backed_up) {
 	if (!backup_file()) {
 	    display_beep();
-	    strcpy (message, "Unable to back up file!");
+	    strncpy (message, "Unable to back up file!", sizeof(message) - 1);
 	    return;
 	}
 	backed_up = TRUE;
     }
     if (!save_file()) {
 	display_beep();
-	strcpy (message, "Unable to save file!");
+	strncpy (message, "Unable to save file!", sizeof(message) - 1);
 	return;
     }
     modified = FALSE;
@@ -292,7 +292,7 @@
 static void act_togins(void) {
     if (look_mode || fix_mode) {
 	display_beep();
-	sprintf(message, "Can't engage Insert mode when in %s mode",
+	snprintf(message, sizeof(message), "Can't engage Insert mode when in %s mode",
 		(look_mode ? "LOOK" : "FIX"));
 	insert_mode = FALSE;	       /* safety! */
     } else
@@ -312,7 +312,7 @@
 
     if (look_mode) {
 	display_beep();
-	strcpy (message, "Can't modify file in LOOK mode");
+	strncpy (message, "Can't modify file in LOOK mode", sizeof(message - 1));
 	return;
     }
 
@@ -325,14 +325,14 @@
 	    last_char -= 'a'-10;
 	else {
 	    display_beep();
-	    strcpy(message, "Not a valid character when in hex editing mode");
+	    strncpy(message, "Not a valid character when in hex editing mode", sizeof(message) - 1);
 	    return;
 	}
     }
 
     if ( (!insert || edit_type == 2) && cur_pos == file_size) {
 	display_beep();
-	strcpy(message, "End of file reached");
+	strncpy(message, "End of file reached", sizeof(message) - 1);
 	return;
     }
 
@@ -365,7 +365,7 @@
 	modified = TRUE;
     } else {
 	display_beep();
-	strcpy(message, "End of file reached");
+	strncpy(message, "End of file reached", sizeof(message) - 1);
     }
     act_right();
 }
@@ -373,7 +373,7 @@
 static void act_delete(void) {
     if (!insert_mode || (edit_type!=2 && cur_pos==0)) {
 	display_beep();
-	strcpy (message, "Can't delete while not in Insert mode");
+	strncpy (message, "Can't delete while not in Insert mode", sizeof(message) - 1);
     } else if (cur_pos > 0 || edit_type == 2) {
 	act_left();
 	buf_delete (filedata, 1, cur_pos);
@@ -386,7 +386,7 @@
 static void act_delch(void) {
     if (!insert_mode) {
 	display_beep();
-	strcpy (message, "Can't delete while not in Insert mode");
+	strncpy (message, "Can't delete while not in Insert mode", sizeof(message) - 1);
     } else if (cur_pos < file_size) {
 	buf_delete (filedata, 1, cur_pos);
 	file_size--;
@@ -398,7 +398,7 @@
 static void act_mark (void) {
     if (look_mode) {
 	display_beep();
-	strcpy (message, "Can't cut or paste in LOOK mode");
+	strncpy (message, "Can't cut or paste in LOOK mode", sizeof(message) - 1);
 	marking = FALSE;	       /* safety */
 	return;
     }
@@ -411,12 +411,12 @@
 
     if (!marking || mark_point==cur_pos) {
 	display_beep();
-	strcpy (message, "Set mark first");
+	strncpy (message, "Set mark first", sizeof(message) - 1);
 	return;
     }
     if (!insert_mode) {
 	display_beep();
-	strcpy (message, "Can't cut while not in Insert mode");
+	strncpy (message, "Can't cut while not in Insert mode", sizeof(message) - 1);
 	return;
     }
     marktop = cur_pos;
@@ -444,7 +444,7 @@
 
     if (!marking) {
 	display_beep();
-	strcpy (message, "Set mark first");
+	strncpy (message, "Set mark first", sizeof(message) - 1);
 	return;
     }
     marktop = cur_pos;
@@ -466,7 +466,7 @@
     if (!insert_mode) {
 	if (cur_pos + cutsize > file_size) {
 	    display_beep();
-	    strcpy (message, "Too close to end of file to paste");
+	    strncpy (message, "Too close to end of file to paste", sizeof(message) - 1);
 	    return;
 	}
 	buf_delete (filedata, cutsize, cur_pos);
@@ -500,13 +500,13 @@
     position = parse_num (buffer, &error);
     if (error) {
 	display_beep();
-	strcpy (message, "Unable to parse position value");
+	strncpy (message, "Unable to parse position value", sizeof(message) - 1);
 	return;
     }
 
     if (position < 0 || position > file_size) {
 	display_beep();
-	strcpy (message, "Position is outside bounds of file");
+	strncpy (message, "Position is outside bounds of file", sizeof(message) - 1);
 	return;
     }
 
@@ -537,7 +537,7 @@
     if (!get_str(last_search ? withdef : withoutdef, buffer, TRUE))
 	return 0;		       /* user break */
     if (!last_search && !*buffer) {
-	strcpy (message, "Search aborted.");
+	strncpy (message, "Search aborted.", sizeof(message) - 1);
 	return 0;
     }
 
@@ -547,7 +547,7 @@
 	len = parse_quoted (buffer);
 	if (len == -1) {
 	    display_beep();
-	    strcpy (message, "Invalid escape sequence in search string");
+	    strncpy (message, "Invalid escape sequence in search string", sizeof(message) - 1);
 	    return 0;
 	}
 	if (last_search)
@@ -597,7 +597,7 @@
 	    }
 	}
     }
-    strcpy (message, "Not found.");
+    strncpy (message, "Not found.", sizeof(message) - 1);
 }
 
 static void act_search_backwards (void) {
@@ -643,7 +643,7 @@
 	    }
 	}
     }
-    strcpy (message, "Not found.");
+    strncpy (message, "Not found.", sizeof(message) - 1);
 }
 
 static void act_recentre (void) {
@@ -660,13 +660,13 @@
     fileoffset_t new_top;
     int error;
 
-    sprintf (prompt, "Enter screen width in bytes (now %"OFF"d): ", width);
+    snprintf (prompt, sizeof(prompt), "Enter screen width in bytes (now %"OFF"d): ", width);
     if (!get_str (prompt, buffer, FALSE))
 	return;
     w = parse_num (buffer, &error);
     if (error) {
 	display_beep();
-	strcpy (message, "Unable to parse width value");
+	strncpy (message, "Unable to parse width value", sizeof(message) - 1);
 	return;
     }
     if (w > 0) {
@@ -686,14 +686,14 @@
     fileoffset_t new_top;
     int error;
 
-    sprintf (prompt, "Enter start-of-file offset in bytes (now %"OFF"d): ",
+    snprintf (prompt, sizeof(prompt), "Enter start-of-file offset in bytes (now %"OFF"d): ",
 	     realoffset);
     if (!get_str (prompt, buffer, FALSE))
 	return;
     o = parse_num (buffer, &error);
     if (error) {
 	display_beep();
-	strcpy (message, "Unable to parse offset value");
+	strncpy (message, "Unable to parse offset value", sizeof(message) - 1);
 	return;
     }
     if (o >= 0) {
diff -urNad tweak~/keytab.c tweak/keytab.c
--- tweak~/keytab.c	2007-03-14 00:42:05.000000000 -0400
+++ tweak/keytab.c	2008-03-16 20:06:29.796165664 -0400
@@ -60,17 +60,18 @@
 
 /*
  * Format an ASCII code into a printable description of the key stroke.
+ * should use no more than 8 chars -- make sure s has room for 8 chars!
  */
 static void strkey (char *s, int k) {
     k &= 255;			       /* force unsigned */
     if (k==27)
-	strcpy(s, " ESC");
+	strncpy(s, " ESC", 8);
     else if (k<32 || k==127)
-	sprintf(s, " ^%c", k ^ 64);
+	snprintf(s, 8, " ^%c", k ^ 64);
     else if (k<127)
-	sprintf(s, " %c", k);
+	snprintf(s, 8, " %c", k);
     else
-	sprintf(s, " <0x%2X>", k);
+	snprintf(s, 8, " <0x%2X>", k);
 }
 
 /*
@@ -88,7 +89,7 @@
 #if defined(unix) && !defined(GO32)
     safe_update = FALSE;
 #endif
-    strcpy(message, "Unknown key sequence");
+    strncpy(message, "Unknown key sequence", sizeof(message));
     strkey(message+strlen(message), last_char);
     kt = base[(unsigned char) last_char];
     if (!kt) {
diff -urNad tweak~/main.c tweak/main.c
--- tweak~/main.c	2008-03-16 20:06:29.296137168 -0400
+++ tweak/main.c	2008-03-16 20:06:29.796165664 -0400
@@ -318,7 +318,7 @@
 void fix_offset(void) {
     if (3*width+11 > display_cols) {
 	width = (display_cols-11) / 3;
-	sprintf (message, "Width reduced to %"OFF"d to fit on the screen", width);
+	snprintf (message, sizeof(message), "Width reduced to %"OFF"d to fit on the screen", width);
     }
     if (4*width+14 > display_cols) {
 	ascii_enabled = FALSE;
@@ -347,7 +347,7 @@
     display_define_colour(COL_INVALID, 11, 0, FALSE);
 
     for (i=0; i<256; i++) {
-	sprintf(hex[i], "%02X", i);
+	snprintf(hex[i], 3, "%02X", i);
 	toprint[i] = (i>=32 && i<127 ? i : '.');
     }
 }
@@ -384,12 +384,12 @@
 	    }
 	    fclose (fp);
 	    assert(file_size == buf_length(filedata));
-	    sprintf(message, "loaded %s (size %"OFF"d == 0x%"OFF"X).",
+	    snprintf(message, sizeof(message), "loaded %s (size %"OFF"d == 0x%"OFF"X).",
 		    fname, file_size, file_size);
 	} else {
 	    filedata = buf_new_from_file(fp);
 	    file_size = buf_length(filedata);
-	    sprintf(message, "opened %s (size %"OFF"d == 0x%"OFF"X).",
+	    snprintf(message, sizeof(message), "opened %s (size %"OFF"d == 0x%"OFF"X).",
 		    fname, file_size, file_size);
 	}
 	new_file = FALSE;
@@ -400,7 +400,7 @@
 	    exit (1);
 	}
 	filedata = buf_new_empty();
-	sprintf(message, "New file %s.", fname);
+	snprintf(message, sizeof(message), "New file %s.", fname);
 	new_file = TRUE;
     }
 }
@@ -445,9 +445,10 @@
 
     if (new_file)
 	return TRUE;		       /* unnecessary - pretend it's done */
-    strcpy (backup_name, filename);
+    backup_name[sizeof(backup_name) - 1] = '\0'; /* ensure null termination */
+    strncpy (backup_name, filename, sizeof(backup_name) - 1);
 #if defined(unix) && !defined(GO32)
-    strcat (backup_name, ".bak");
+    strncat (backup_name, ".bak", sizeof(backup_name) - (strlen(backup_name) + 1));
 #elif defined(MSDOS)
     {
 	char *p, *q;
@@ -605,7 +606,7 @@
 	int slen;
 	display_moveto (display_rows-2, 0);
 	display_set_colour(COL_STATUS);
-	sprintf(status, statfmt,
+	snprintf(status, sizeof(status), statfmt,
 		(modified ? "**" : "  "),
 		filename,
 		(insert_mode ? "(Insert)" :
@@ -691,7 +692,7 @@
 	} else if (c == 27 || c == 7) {
 	    display_beep();
 	    display_post_error();
-	    strcpy (message, "User Break!");
+	    strncpy (message, "User Break!", sizeof(message));
 	    return FALSE;
 	}
 
@@ -760,7 +761,7 @@
     init();
 #else
     display_beep();
-    strcpy(message, "Suspend function not yet implemented.");
+    strncpy(message, "Suspend function not yet implemented.", sizeof(message));
 #endif
 }
 
diff -urNad tweak~/rcfile.c tweak/rcfile.c
--- tweak~/rcfile.c	2007-03-14 00:42:05.000000000 -0400
+++ tweak/rcfile.c	2008-03-16 20:08:05.301608209 -0400
@@ -148,11 +148,12 @@
     int lineno = 0;
     int errors = FALSE, errors_here;
 
+    rcname[sizeof(rcname) - 1] = '\0'; /* ensure null termination */
 #if defined(unix) && !defined(GO32)
     rcname[0] = '\0';
     if (getenv("HOME"))
-	strcpy (rcname, getenv("HOME"));
-    strcat (rcname, "/.tweakrc");
+	strncpy (rcname, getenv("HOME"), sizeof(rcname) - 1);
+    strncat (rcname, "/.tweakrc", sizeof(rcname) - (1 + strlen(rcname)));
 #elif defined(MSDOS)
     /*
      * Use environment variable TWEAKRC if set. Otherwise, look for
@@ -160,19 +161,19 @@
      * and failing everything else, try C:\TWEAK\TWEAK.RC.
      */
     if (getenv("TWEAKRC"))
-	strcpy (rcname, getenv("TWEAKRC"));
+	strncpy (rcname, getenv("TWEAKRC"), sizeof(rcname) - 1);
     else {
 	if ( (q = strrchr(pname, '\\')) != NULL) {
 	    FILE *tempfp;
 
 	    strncpy (rcname, pname, q+1-pname);
-	    strcpy (rcname+(q+1-pname), "TWEAK.RC");
+	    strncpy (rcname+(q+1-pname), "TWEAK.RC", sizeof(rcname) - (2+q-pname));
 	    if ( (tempfp = fopen(rcname, "r")) != NULL)
 		fclose (tempfp);
 	    else
-		strcpy (rcname, "C:\\TWEAK\\TWEAK.RC");
+		strncpy (rcname, "C:\\TWEAK\\TWEAK.RC", sizeof(rcname-1));
 	} else
-	    strcpy (rcname, "C:\\TWEAK\\TWEAK.RC");
+	    strncpy (rcname, "C:\\TWEAK\\TWEAK.RC", sizeof(rcname-1));
     }
 #endif
 
@@ -197,7 +198,7 @@
 	} else {
 	    if (!*p)
 		break;
-	    strcpy (rcbuffer, *p++);
+	    strncpy (rcbuffer, *p++, sizeof(rcbuffer));
 	}
 	lineno++;
 	errors_here = FALSE;
diff -urNad tweak~/slang.c tweak/slang.c
--- tweak~/slang.c	2007-03-14 00:42:05.000000000 -0400
+++ tweak/slang.c	2008-03-16 20:06:29.796165664 -0400
@@ -125,7 +125,7 @@
         bg = 0;
     }
 
-    sprintf(cname, "colour%d", colour);
+    snprintf(cname, sizeof(cname), "colour%d", colour);
 
     SLtt_set_color(colour, cname, colours[fg], colours[bg]);
 }
