- guenther@cvs.openbsd.org 2013/06/17 04:48:42
     [scp.c]
     Handle time_t values as long long's when formatting them and when
     parsing them from remote servers.
     Improve error checking in parsing of 'T' lines.

     ok dtucker@ deraadt@
diff --git a/scp.c b/scp.c
index 9b5959d..ca7948f 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.175 2013/06/04 19:12:23 dtucker Exp $ */
+/* $OpenBSD: scp.c,v 1.176 2013/06/17 04:48:42 guenther Exp $ */
 /*
  * scp - secure remote copy.  This is basically patched BSD rcp which
  * uses ssh to do the data transfer (instead of using rcmd).
@@ -550,6 +550,24 @@
 	return 0;
 }
 
+static int
+do_times(int fd, int verb, const struct stat *sb)
+{
+	/* strlen(2^64) == 20; strlen(10^6) == 7 */
+	char buf[(20 + 7 + 2) * 2 + 2];
+
+	(void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
+	    (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
+	    (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
+	if (verb) {
+		fprintf(stderr, "File mtime %lld atime %lld\n",
+		    (long long)sb->st_mtime, (long long)sb->st_atime);
+		fprintf(stderr, "Sending file timestamps: %s", buf);
+	}
+	(void) atomicio(vwrite, fd, buf, strlen(buf));
+	return (response());
+}
+
 void
 toremote(char *targ, int argc, char **argv)
 {
@@ -774,21 +792,7 @@
 			++last;
 		curfile = last;
 		if (pflag) {
-			/*
-			 * Make it compatible with possible future
-			 * versions expecting microseconds.
-			 */
-			(void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
-			    (u_long) (stb.st_mtime < 0 ? 0 : stb.st_mtime),
-			    (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime));
-			if (verbose_mode) {
-				fprintf(stderr, "File mtime %ld atime %ld\n",
-				    (long)stb.st_mtime, (long)stb.st_atime);
-				fprintf(stderr, "Sending file timestamps: %s",
-				    buf);
-			}
-			(void) atomicio(vwrite, remout, buf, strlen(buf));
-			if (response() < 0)
+			if (do_times(remout, verbose_mode, &stb) < 0)
 				goto next;
 		}
 #define	FILEMODEMASK	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
@@ -862,11 +866,7 @@
 	else
 		last++;
 	if (pflag) {
-		(void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
-		    (u_long) statp->st_mtime,
-		    (u_long) statp->st_atime);
-		(void) atomicio(vwrite, remout, path, strlen(path));
-		if (response() < 0) {
+		if (do_times(remout, verbose_mode, statp) < 0) {
 			closedir(dirp);
 			return;
 		}
@@ -912,6 +912,7 @@
 	int amt, exists, first, ofd;
 	mode_t mode, omode, mask;
 	off_t size, statbytes;
+	unsigned long long ull;
 	int setimes, targisdir, wrerrno = 0;
 	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
 	struct timeval tv[2];
@@ -970,17 +971,29 @@
 		if (*cp == 'T') {
 			setimes++;
 			cp++;
-			mtime.tv_sec = strtol(cp, &cp, 10);
+			if (!isdigit((unsigned char)*cp))
+				SCREWUP("mtime.sec not present");
+			ull = strtoull(cp, &cp, 10);
 			if (!cp || *cp++ != ' ')
 				SCREWUP("mtime.sec not delimited");
+			if ((time_t)ull < 0 || (time_t)ull != ull)
+				setimes = 0;	/* out of range */
+			mtime.tv_sec = ull;
 			mtime.tv_usec = strtol(cp, &cp, 10);
-			if (!cp || *cp++ != ' ')
+			if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
+			    mtime.tv_usec > 999999)
 				SCREWUP("mtime.usec not delimited");
-			atime.tv_sec = strtol(cp, &cp, 10);
+			if (!isdigit((unsigned char)*cp))
+				SCREWUP("atime.sec not present");
+			ull = strtoull(cp, &cp, 10);
 			if (!cp || *cp++ != ' ')
 				SCREWUP("atime.sec not delimited");
+			if ((time_t)ull < 0 || (time_t)ull != ull)
+				setimes = 0;	/* out of range */
+			atime.tv_sec = ull;
 			atime.tv_usec = strtol(cp, &cp, 10);
-			if (!cp || *cp++ != '\0')
+			if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
+			    atime.tv_usec > 999999)
 				SCREWUP("atime.usec not delimited");
 			(void) atomicio(vwrite, remout, "", 1);
 			continue;