From: <peter@p12n.org>
Subject: Replace some sprintf with snprintf, and strcpy with strncpy.
 I haven't attempted to prove that any of these are exploitable,
 but it looks as though some may well be.
 .
 Note also that I haven't done any kind of formal audit.

diff -urNad xsok-1.02/src/X-gfx.c xsok-1.02/src/X-gfx.c
--- xsok-1.02/src/X-gfx.c
+++ xsok-1.02/src/X-gfx.c
@@ -86,10 +86,10 @@
     char s[MAXXSOKDIRLEN+14];
     screen = DefaultScreen(dpy);
     gc = XDefaultGC(dpy, screen);
-    sprintf(s, "%s/floor.xpm", xpmdir);
+    snprintf(s, sizeof(s), "%s/floor.xpm", xpmdir);
     if ((retcode = XpmReadFileToPixmap(dpy, RootWindow(dpy, screen),
 				       s,  &floor, 0, NULL)) == XpmSuccess) {
-	sprintf(s, "%s/objects.xpm", xpmdir);
+	snprintf(s, sizeof(s), "%s/objects.xpm", xpmdir);
 	retcode = XpmReadFileToPixmap(dpy, RootWindow(dpy, screen), s, &objd,
 			    &objclip, NULL);
     }
diff -urNad xsok-1.02/src/X-sound_SUN.c xsok-1.02/src/X-sound_SUN.c
--- xsok-1.02/src/X-sound_SUN.c
+++ xsok-1.02/src/X-sound_SUN.c
@@ -28,7 +28,8 @@
 	    return;		/* cannot open /dev/audio */
 	}
 	XSync(dpy, 0);	/* text first! */
-	sprintf(fullname, "%s/audio/%s.au", xsokdir, filename);
+	snprintf(fullname, sizeof(fullname), "%s/audio/%s.au",
+		 xsokdir, filename);
 	if (!(fp = fopen(fullname, "rb"))) {
 	    fclose(fsnd);
 	    return;
diff -urNad xsok-1.02/src/Xaw-help.c xsok-1.02/src/Xaw-help.c
--- xsok-1.02/src/Xaw-help.c
+++ xsok-1.02/src/Xaw-help.c
@@ -36,8 +36,8 @@
     Arg Args[2];
     int i = atoi(s+4);
 
-    sprintf(filename, "%s/%s/%s.help", xsokdir, langdir,
-	    i ? rulepool[i-1] : keyfilename);
+    snprintf(filename, sizeof(filename), "%s/%s/%s.help", xsokdir, langdir,
+             i ? rulepool[i-1] : keyfilename);
     XtSetArg(Args[0], XtNstring, filename);
     XtSetArg(Args[1], XtNtype, XawAsciiFile);
     XtSetValues(helptext, Args, 2);
@@ -62,9 +62,9 @@
     {   const char **rp;
 	for (rp = rulepool; *rp; ++rp) {
 	    char n[8], s[40];
-	    sprintf(n, "Help%u", (unsigned int)(rp-rulepool+1));
+	    snprintf(n, sizeof(n), "Help%u", (unsigned int)(rp-rulepool+1));
 	    XtSetArg(Args[0], XtNlabel, s);
-	    sprintf(s, TXT_HELP_RULES, *rp);
+	    snprintf(s, sizeof(s), TXT_HELP_RULES, *rp);
 	    w = XtCreateManagedWidget(n, smeBSBObjectClass, topicsmenu, Args, 1);
 	    XtAddCallback(w, XtNcallback, selecttopic, NULL);
 	}
diff -urNad xsok-1.02/src/Xaw-main.c xsok-1.02/src/Xaw-main.c
--- xsok-1.02/src/Xaw-main.c
+++ xsok-1.02/src/Xaw-main.c
@@ -36,8 +36,8 @@
 	    memset(last_message, ' ', sizeof(last_message)-1);
 	    last_message[sizeof(last_message)-1] = '\0';
 	} else
-	    vsprintf(last_message, str, args);
-	
+	    vsnprintf(last_message, sizeof(last_message), str, args);
+
 	XtSetArg(Args, XtNlabel, last_message);
 	XtSetValues(messagebox, &Args, 1);
     }
@@ -46,7 +46,8 @@
 void SetTitle(void) {
     if (XtWindow(toplevel)) {
 	static char windowname[48];
-	sprintf(windowname, "%s - Level %d", game.type, game.level);
+	snprintf(windowname, sizeof(windowname), "%s - Level %d",
+		 game.type, game.level);
 	/* printf("SetTitle(): toplevel = %p, window = %x\n",
 	   toplev, XtWindow(toplevel)); */
 	XStoreName(dpy, XtWindow(toplevel), windowname);
@@ -248,7 +249,7 @@
 static void read_gametypes(void) {
     char filename[256], s[80];
     FILE *fp;
-    sprintf(filename, "%s/gametypes", xsokdir);
+    snprintf(filename, sizeof(filename), "%s/gametypes", xsokdir);
     if ((fp = fopen(filename, "r"))) {
 	int i;
 	for (i = 3; i < 15; ++i) {
diff -urNad xsok-1.02/src/commands.c xsok-1.02/src/commands.c
--- xsok-1.02/src/commands.c
+++ xsok-1.02/src/commands.c
@@ -186,7 +186,8 @@
     char filename[MAXSAVEFILELEN];
     static const char **p, *extensions[] = { "sv", "bs", "mp", "mm", "sav", "sol", NULL };
     for (p = extensions; *p; ++p) {
-	sprintf(filename, "%s/%s.%02d.%s", savedir, game.type, game.level, *p);
+	snprintf(filename, sizeof(filename), "%s/%s.%02d.%s",
+		 savedir, game.type, game.level, *p);
 	if (!access(filename, R_OK)) {
 	    load_game(filename);
 	    return;
diff -urNad xsok-1.02/src/loadsave.c xsok-1.02/src/loadsave.c
--- xsok-1.02/src/loadsave.c
+++ xsok-1.02/src/loadsave.c
@@ -103,7 +103,7 @@
     for (i = 100; i < 300; ++i)
 	    highscore[i] = 0x7fffffff;
 
-    sprintf(filename, "%s/%s.score", savedir, game.type);
+    snprintf(filename, sizeof(filename), "%s/%s.score", savedir, game.type);
     if ((fp = fopen(filename, "rb"))) {
 	long p[300];
 	unsigned char s[1200];
@@ -119,7 +119,7 @@
 void WriteHighscores(void) {
     FILE *fp;
     char filename[MAXSAVEFILELEN];
-    sprintf(filename, "%s/%s.score", savedir, game.type);
+    snprintf(filename, sizeof(filename), "%s/%s.score", savedir, game.type);
     if ((fp = fopen(filename, "wb"))) {
 	int i;
 	long p[300];
@@ -212,7 +212,8 @@
     unsigned char p[4 * NARGS];
 
     compute_score();
-    sprintf(filename, "%s/%s.%02d.%s", savedir, game.type, game.level, ext);
+    snprintf(filename, sizeof(filename), "%s/%s.%02d.%s",
+	     savedir, game.type, game.level, ext);
     remove(filename);	/* kill any old one first! */
     if (!(fp = fopen(filename, "wb"))) {
 	show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_OPEN);
@@ -264,8 +265,10 @@
 void link_game(const char *old, const char *ext) {
     char file1[MAXSAVEFILELEN], file2[MAXSAVEFILELEN];
 
-    sprintf(file1, "%s/%s.%02d.%s", savedir, game.type, game.level, old);
-    sprintf(file2, "%s/%s.%02d.%s", savedir, game.type, game.level, ext);
+    snprintf(file1, sizeof(file1), "%s/%s.%02d.%s",
+	     savedir, game.type, game.level, old);
+    snprintf(file2, sizeof(file2), "%s/%s.%02d.%s",
+	     savedir, game.type, game.level, ext);
     remove(file2);	/* kill any old one first! */
     if (link(file1, file2))
 	show_message(TXT_SAVE_ERR_LINK);
diff -urNad xsok-1.02/src/messages.c xsok-1.02/src/messages.c
--- xsok-1.02/src/messages.c
+++ xsok-1.02/src/messages.c
@@ -73,7 +73,7 @@
     int i;
     char line[256];
     if (*filename != '/') {
-	sprintf(line, "%s/%s/%s", xsokdir, langdir, filename);
+	snprintf(line, sizeof(line), "%s/%s/%s", xsokdir, langdir, filename);
 	filename = line;
     }
     if (!(fp = fopen(filename, "r")))
@@ -189,7 +189,7 @@
 
     cmd[1] = '\0';	/* 1-char commands currently */
     if (*filename != '/') {
-	sprintf(line, "%s/%s/%s", xsokdir, langdir, filename);
+	snprintf(line, sizeof(line), "%s/%s/%s", xsokdir, langdir, filename);
 	filename = line;
     }
     /* printf("reading keyboard file \"%s\"\n", filename); */
diff -urNad xsok-1.02/src/parse.c xsok-1.02/src/parse.c
--- xsok-1.02/src/parse.c
+++ xsok-1.02/src/parse.c
@@ -60,7 +60,7 @@
     FILE *fp;
     char s[MAXXSOKDIRLEN+14];
 
-    sprintf(s, "%s/%s.def", xsokdir, game.type);
+    snprintf(s, sizeof(s), "%s/%s.def", xsokdir, game.type);
     if (!(fp = fopen(s, "r")))
 	fatal("Cannot open definition file for %s\n", game.type);
 
@@ -80,7 +80,7 @@
     maxlevel = 99;
     pushcost = 10;
     movecost = 1;
-    sprintf(s, "%s/%s/definitions", xsokdir, game.type);
+    snprintf(s, sizeof(s), "%s/%s/definitions", xsokdir, game.type);
     if (!(fp = fopen(s, "r")))
 	fp = def_open(";WALLS\n");
     numabbrevs = nwalls = nobjects = 0;
@@ -165,7 +165,7 @@
     struct objects *ip;
     char s[MAXXSOKDIRLEN+20];
 
-    sprintf(s, "%s/%s/screen.%02d", xsokdir, game.type, game.level);
+    snprintf(s, sizeof(s), "%s/%s/screen.%02d", xsokdir, game.type, game.level);
     if (!(fp = fopen(s, "r"))) {
 	sprintf(s, ";LEVEL %d\n", game.level);
 	fp = def_open(s);
diff -urNad xsok-1.02/src/showscore.c xsok-1.02/src/showscore.c
--- xsok-1.02/src/showscore.c
+++ xsok-1.02/src/showscore.c
@@ -26,11 +26,12 @@
     for (i = 100; i < 300; ++i)
 	    highscore[i] = 0x7fffffff;
 
-    strcpy(base_name, levelfile);
+    strncpy(base_name, levelfile, sizeof(base_name));
+    base_name[sizeof(base_name)-1] = '\0';
     if (!(s = strchr(base_name, '.')))
 	return;
-    strcpy(s+1, "score");
-    sprintf(filename, "%s/%s", XSOKSAVE, base_name);
+    *s = '\0';
+    snprintf(filename, sizeof(filename), "%s/%s.score", XSOKSAVE, base_name);
     if ((fp = fopen(filename, "rb"))) {
 	long p[300];
 	unsigned char ss[1200];
diff -urNad xsok-1.02/src/tools.c xsok-1.02/src/tools.c
--- xsok-1.02/src/tools.c
+++ xsok-1.02/src/tools.c
@@ -61,7 +61,8 @@
 }
 
 char *strsav(const char *txt) {
-    char *p = malloc_(1 + strlen(txt));
-    strcpy(p, txt);
+    size_t s = strlen(txt) + 1;
+    char *p = malloc_(s);
+    memcpy(p, txt, s);
     return p;
 }
diff -urNad xsok-1.02/src/username.c xsok-1.02/src/username.c
--- xsok-1.02/src/username.c
+++ xsok-1.02/src/username.c
@@ -28,11 +28,8 @@
 
 void buildusername(const char *name) {
     if (name) {
-	if (strlen(name) > 255) {
-	    strncpy(username, name, 255);
-	    username[256] = '\0';
-	} else
-	    strcpy(username, name);
+	strncpy(username, name, 255);
+	username[255] = '\0';
     } else {
 	struct passwd *pp;
 	const char *realname, *loginname;
@@ -57,16 +54,19 @@
 	if (uname(&buf))
 	    strcpy(buf.nodename, "unknown");
 #ifdef BSD_NETKIT
-	if ((hp = gethostbyname(buf.nodename)))
-	    strcpy(fqdn, hp->h_name);
+	if ((hp = gethostbyname(buf.nodename))) {
+	    strncpy(fqdn, hp->h_name, sizeof(fqdn)-1);
+	    fqdn[sizeof(fqdn)-1] = '\0';
+	}
 	else
 #endif
-	    sprintf(fqdn, "%s.(unknown)", buf.nodename);
+	    snprintf(fqdn, sizeof(fqdn), "%s.(unknown)", buf.nodename);
 
 	if (realname)
-	    sprintf(username, "%s (%s@%s)", realname, loginname, fqdn);
+	    snprintf(username, sizeof(username),
+		     "%s (%s@%s)", realname, loginname, fqdn);
 	else
-	    sprintf(username, "%s@%s", loginname, fqdn);
+	    snprintf(username, sizeof(username), "%s@%s", loginname, fqdn);
     }
 }
 
