- stevesk@cvs.openbsd.org 2001/04/12 20:09:38
     [misc.c misc.h readconf.c servconf.c ssh.c sshd.c]
     robust port validation; ok markus@ jakob@
diff --git a/ChangeLog b/ChangeLog
index 50dfec1..574fb44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,9 @@
    - markus@cvs.openbsd.org 2001/04/12 19:39:27
      [readconf.c]
      typo
+   - stevesk@cvs.openbsd.org 2001/04/12 20:09:38
+     [misc.c misc.h readconf.c servconf.c ssh.c sshd.c]
+     robust port validation; ok markus@ jakob@
  - (bal) Added openbsd-compat/inet_ntop.[ch] since HP/UX (and others)
    lack it.
 
@@ -5038,4 +5041,4 @@
  - Wrote replacements for strlcpy and mkdtemp
  - Released 1.0pre1
 
-$Id: ChangeLog,v 1.1104 2001/04/12 23:36:05 mouring Exp $
+$Id: ChangeLog,v 1.1105 2001/04/12 23:39:26 mouring Exp $
diff --git a/misc.c b/misc.c
index 495b029..feeacb8 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: misc.c,v 1.4 2001/02/28 17:52:54 deraadt Exp $	*/
+/*	$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $	*/
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: misc.c,v 1.4 2001/02/28 17:52:54 deraadt Exp $");
+RCSID("$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $");
 
 #include "misc.h"
 #include "log.h"
@@ -116,6 +116,21 @@
 	return copy;
 }
 
+int a2port(const char *s)
+{
+	long port;
+	char *endp;
+
+	errno = 0;
+	port = strtol(s, &endp, 0);
+	if (s == endp || *endp != '\0' ||
+	    (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
+	    port <= 0 || port > 65535)
+		return 0;
+
+	return port;
+}
+
 mysig_t
 mysignal(int sig, mysig_t act)
 {
diff --git a/misc.h b/misc.h
index 3204b62..2346a5e 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: misc.h,v 1.3 2001/02/22 21:59:44 markus Exp $	*/
+/*	$OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $	*/
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -22,6 +22,13 @@
 
 struct passwd * pwcopy(struct passwd *pw);
 
+/*
+ * Convert ASCII string to TCP/IP port number.
+ * Port must be >0 and <=65535.
+ * Return 0 if invalid.
+ */
+int a2port(const char *s);
+
 /* wrapper for signal interface */
 typedef void (*mysig_t)(int);
 mysig_t mysignal(int sig, mysig_t act);
diff --git a/readconf.c b/readconf.c
index 144a760..241185c 100644
--- a/readconf.c
+++ b/readconf.c
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.73 2001/04/12 19:39:27 markus Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.74 2001/04/12 20:09:37 stevesk Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -555,10 +555,10 @@
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
-		if (arg[0] < '0' || arg[0] > '9')
+		fwd_port = a2port(arg);
+		if (fwd_port == 0)
 			fatal("%.200s line %d: Badly formatted port number.",
 			      filename, linenum);
-		fwd_port = atoi(arg);
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing second argument.",
@@ -574,10 +574,10 @@
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
-		if (arg[0] < '0' || arg[0] > '9')
+		fwd_port = a2port(arg);
+		if (fwd_port == 0)
 			fatal("%.200s line %d: Badly formatted port number.",
 			      filename, linenum);
-		fwd_port = atoi(arg);
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing second argument.",
@@ -594,10 +594,10 @@
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing port argument.",
 			    filename, linenum);
-		if (arg[0] < '0' || arg[0] > '9')
+		fwd_port = a2port(arg);
+		if (fwd_port == 0)
 			fatal("%.200s line %d: Badly formatted port number.",
 			    filename, linenum);
-		fwd_port = atoi(arg);
 		add_local_forward(options, fwd_port, "socks4", 0);
 		break;
 
diff --git a/servconf.c b/servconf.c
index 8e876d1..f3d5068 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.75 2001/04/12 19:15:25 markus Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.76 2001/04/12 20:09:37 stevesk Exp $");
 
 #ifdef KRB4
 #include <krb.h>
@@ -31,8 +31,7 @@
 #include "kex.h"
 #include "mac.h"
 
-/* add listen address */
-void add_listen_addr(ServerOptions *options, char *addr, char *port);
+void add_listen_addr(ServerOptions *options, char *addr, u_short port);
 void add_one_listen_addr(ServerOptions *options, char *addr, u_short port);
 
 /* AF_UNSPEC or AF_INET or AF_INET6 */
@@ -117,7 +116,7 @@
 	if (options->num_ports == 0)
 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
 	if (options->listen_addrs == NULL)
-		add_listen_addr(options, NULL, NULL);
+		add_listen_addr(options, NULL, 0);
 	if (options->pid_file == NULL)
 		options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
 	if (options->server_key_bits == -1)
@@ -312,21 +311,18 @@
 	return sBadOption;
 }
 
-/*
- * add listen address
- */
 void
-add_listen_addr(ServerOptions *options, char *addr, char *port)
+add_listen_addr(ServerOptions *options, char *addr, u_short port)
 {
 	int i;
 
 	if (options->num_ports == 0)
 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
-	if (port == NULL)
+	if (port == 0)
 		for (i = 0; i < options->num_ports; i++)
 			add_one_listen_addr(options, addr, options->ports[i]);
 	else
-		add_one_listen_addr(options, addr, atoi(port));
+		add_one_listen_addr(options, addr, port);
 }
 
 void
@@ -400,7 +396,10 @@
 			if (!arg || *arg == '\0')
 				fatal("%s line %d: missing port number.",
 				    filename, linenum);
-			options->ports[options->num_ports++] = atoi(arg);
+			options->ports[options->num_ports++] = a2port(arg);
+			if (options->ports[options->num_ports-1] == 0)
+				fatal("%s line %d: Badly formatted port number.",
+				    filename, linenum);
 			break;
 
 		case sServerKeyBits:
@@ -438,20 +437,25 @@
 				memmove(p, p+1, strlen(p+1)+1);
 			} else if (((p = strchr(arg, ':')) == NULL) ||
 				    (strchr(p+1, ':') != NULL)) {
-				add_listen_addr(options, arg, NULL);
+				add_listen_addr(options, arg, 0);
 				break;
 			}
 			if (*p == ':') {
+				u_short port;
+
 				p++;
 				if (*p == '\0')
 					fatal("%s line %d: bad inet addr:port usage.",
 					    filename, linenum);
 				else {
 					*(p-1) = '\0';
-					add_listen_addr(options, arg, p);
+					if ((port = a2port(p)) == 0)
+						fatal("%s line %d: bad port number.",
+						    filename, linenum);
+					add_listen_addr(options, arg, port);
 				}
 			} else if (*p == '\0')
-				add_listen_addr(options, arg, NULL);
+				add_listen_addr(options, arg, 0);
 			else
 				fatal("%s line %d: bad inet addr usage.",
 				    filename, linenum);
diff --git a/ssh.c b/ssh.c
index f14fbac..eda4437 100644
--- a/ssh.c
+++ b/ssh.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.112 2001/04/12 19:15:25 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.113 2001/04/12 20:09:37 stevesk Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -247,7 +247,7 @@
 {
 	int i, opt, optind, exit_status, ok;
 	u_short fwd_port, fwd_host_port;
-	char *optarg, *cp, *endofnumber, buf[256];
+	char *optarg, *cp, buf[256];
 	struct stat st;
 	struct passwd *pw;
 	int dummy;
@@ -460,8 +460,8 @@
 			}
 			break;
 		case 'p':
-			options.port = strtol(optarg, &endofnumber, 0);
-			if (optarg == endofnumber) {
+			options.port = a2port(optarg);
+			if (options.port == 0) {
 				fprintf(stderr, "Bad port '%s'\n", optarg);
 				exit(1);
 			}
@@ -493,9 +493,9 @@
 			break;
 
 		case 'D':
-			fwd_port = strtol(optarg, &endofnumber, 0);
-			if (optarg == endofnumber) {
-				fprintf(stderr, "Bad port '%s'\n", optarg);
+			fwd_port = a2port(optarg);
+			if (fwd_port == 0) {
+				fprintf(stderr, "Bad dynamic port '%s'\n", optarg);
 				exit(1);
 			}
 			add_local_forward(&options, fwd_port, "socks4", 0);
diff --git a/sshd.c b/sshd.c
index bde1ac3..eaf3d32 100644
--- a/sshd.c
+++ b/sshd.c
@@ -40,7 +40,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.192 2001/04/11 16:25:30 lebel Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.193 2001/04/12 20:09:38 stevesk Exp $");
 
 #include <openssl/dh.h>
 #include <openssl/bn.h>
@@ -611,7 +611,11 @@
 				fprintf(stderr, "too many ports.\n");
 				exit(1);
 			}
-			options.ports[options.num_ports++] = atoi(optarg);
+			options.ports[options.num_ports++] = a2port(optarg);
+			if (options.ports[options.num_ports-1] == 0) {
+				fprintf(stderr, "Bad port number.\n");
+				exit(1);
+			}
 			break;
 		case 'g':
 			options.login_grace_time = atoi(optarg);