changeset 258:306499676384

* add -g (dbclient) and -a (dropbear) options for allowing non-local hosts to connect to forwarded ports. Rearranged various some of the tcp listening code. * changed to /* */ style brackets in svr-authpam.c
author Matt Johnston <matt@ucc.asn.au>
date Sun, 04 Dec 2005 16:13:11 +0000
parents 63601217f5ab
children c049490e43fe
files cli-runopts.c cli-tcpfwd.c dbclient.1 dbutil.c dropbear.8 runopts.h svr-authpam.c svr-main.c svr-runopts.c svr-tcpfwd.c tcp-accept.c tcpfwd.h
diffstat 12 files changed, 111 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/cli-runopts.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/cli-runopts.c	Sun Dec 04 16:13:11 2005 +0000
@@ -47,6 +47,7 @@
 					"Usage: %s [options] [user@]host\n"
 					"Options are:\n"
 					"-p <remoteport>\n"
+					"-l <username>\n"
 					"-t    Allocate a pty\n"
 					"-T    Don't allocate a pty\n"
 #ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -54,11 +55,11 @@
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
 					"-L <listenport:remotehost:remoteport> Local port forwarding\n"
+					"-g    Allow remote hosts to connect to forwarded ports\n"
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 					"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
 #endif
-					"-l <username>\n"
 #ifdef DEBUG_TRACE
 					"-v    verbose\n"
 #endif
@@ -93,12 +94,11 @@
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
 	cli_opts.localfwds = NULL;
+	opts.listen_fwd_all = 0;
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 	cli_opts.remotefwds = NULL;
 #endif
-	opts.nolocaltcp = 0;
-	opts.noremotetcp = 0;
 	/* not yet
 	opts.ipv4 = 1;
 	opts.ipv6 = 1;
@@ -167,6 +167,9 @@
 				case 'L':
 					nextislocal = 1;
 					break;
+				case 'g':
+					opts.listen_fwd_all = 1;
+					break;
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 				case 'R':
--- a/cli-tcpfwd.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/cli-tcpfwd.c	Sun Dec 04 16:13:11 2005 +0000
@@ -95,9 +95,17 @@
 				remoteport));
 
 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
+
 	tcpinfo->sendaddr = m_strdup(remoteaddr);
 	tcpinfo->sendport = remoteport;
+
+	if (opts.listen_fwd_all) {
+		tcpinfo->listenaddr = m_strdup("");
+	} else {
+		tcpinfo->listenaddr = m_strdup("localhost");
+	}
 	tcpinfo->listenport = listenport;
+
 	tcpinfo->chantype = &cli_chan_tcplocal;
 
 	ret = listen_tcpfwd(tcpinfo);
@@ -113,13 +121,20 @@
 #ifdef  ENABLE_CLI_REMOTETCPFWD
 static void send_msg_global_request_remotetcp(int port) {
 
+	char* listenspec = NULL;
 	TRACE(("enter send_msg_global_request_remotetcp"))
 
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
 	buf_putstring(ses.writepayload, "tcpip-forward", 13);
 	buf_putbyte(ses.writepayload, 0);
-	buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */
+	if (opts.listen_fwd_all) {
+		listenspec = "";
+	} else {
+		listenspec = "localhost";
+	}
+	/* TODO: IPv6? */;
+	buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
 	buf_putint(ses.writepayload, port);
 
 	encrypt_packet();
--- a/dbclient.1	Wed Nov 30 10:11:24 2005 +0000
+++ b/dbclient.1	Sun Dec 04 16:13:11 2005 +0000
@@ -59,6 +59,11 @@
 .TP
 .B \-T
 Don't allocate a pty.
+.TP
+.B \-g
+Allow non-local hosts to connect to forwarded ports. Applies to -L and -R
+forwarded ports, though remote connections to -R forwarded ports may be limited
+by the ssh server.
 .SH AUTHOR
 Matt Johnston ([email protected]).
 .br
--- a/dbutil.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/dbutil.c	Sun Dec 04 16:13:11 2005 +0000
@@ -177,8 +177,9 @@
 
 }
 
-/* Listen on address:port. Unless address is NULL, in which case listen on
- * everything. If called with address == "", we'll listen on localhost/loopback.
+/* Listen on address:port. 
+ * Special cases are address of "" listening on everything,
+ * and address of NULL listening on localhost only.
  * Returns the number of sockets bound on success, or -1 on failure. On
  * failure, if errstring wasn't NULL, it'll be a newly malloced error
  * string.*/
@@ -198,11 +199,17 @@
 	hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
 	hints.ai_socktype = SOCK_STREAM;
 
-	if (address && address[0] == '\0') {
+	// for calling getaddrinfo:
+	// address == NULL and !AI_PASSIVE: local loopback
+	// address == NULL and AI_PASSIVE: all interfaces
+	// address != NULL: whatever the address says
+	if (!address) {
 		TRACE(("dropbear_listen: local loopback"))
-		address = NULL;
 	} else {
-		TRACE(("dropbear_listen: not local loopback"))
+		if (address[0] == '\0') {
+			TRACE(("dropbear_listen: all interfaces"))
+			address = NULL;
+		}
 		hints.ai_flags = AI_PASSIVE;
 	}
 	err = getaddrinfo(address, port, &hints, &res0);
--- a/dropbear.8	Wed Nov 30 10:11:24 2005 +0000
+++ b/dropbear.8	Sun Dec 04 16:13:11 2005 +0000
@@ -71,6 +71,9 @@
 .B dropbear
 under TCP/IP servers like inetd, tcpsvd, or tcpserver.
 In program mode the \-F option is implied, and \-p options are ignored.
+.TP
+.B \-a
+Allow remote hosts to connect to forwarded ports.
 .SH AUTHOR
 Matt Johnston ([email protected]).
 .br
--- a/runopts.h	Wed Nov 30 10:11:24 2005 +0000
+++ b/runopts.h	Sun Dec 04 16:13:11 2005 +0000
@@ -33,8 +33,9 @@
 
 typedef struct runopts {
 
-	int nolocaltcp;
-	int noremotetcp;
+#if defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
+	int listen_fwd_all;
+#endif
 
 } runopts;
 
@@ -73,6 +74,13 @@
 	int noauthpass;
 	int norootpass;
 
+#ifdef ENABLE_SVR_REMOTETCPFWD
+	int noremotetcp;
+#endif
+#ifdef ENABLE_SVR_LOCALTCPFWD
+	int nolocaltcp;
+#endif
+
 	sign_key *hostkey;
 	buffer * banner;
 
@@ -83,7 +91,6 @@
 void svr_getopts(int argc, char ** argv);
 void loadhostkeys();
 
-/* Uncompleted XXX matt */
 typedef struct cli_runopts {
 
 	char *progname;
@@ -103,7 +110,6 @@
 #ifdef ENABLE_CLI_LOCALTCPFWD
 	struct TCPFwdList * localfwds;
 #endif
-	/* XXX TODO */
 
 } cli_runopts;
 
--- a/svr-authpam.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/svr-authpam.c	Sun Dec 04 16:13:11 2005 +0000
@@ -59,7 +59,7 @@
 
 	const char* message = (*msg)->msg;
 
-	// make a copy we can strip
+	/* make a copy we can strip */
 	char * compare_message = m_strdup(message);
 
 	TRACE(("enter pamConvFunc"))
@@ -80,14 +80,14 @@
 	}
 
 
-	// Make the string lowercase.
+	/* Make the string lowercase. */
 	msg_len = strlen(compare_message);
 	for (i = 0; i < msg_len; i++) {
 		compare_message[i] = tolower(compare_message[i]);
 	}
 
-	// If the string ends with ": ", remove the space.
-	// ie "login: " vs "login:"
+	/* If the string ends with ": ", remove the space. 
+	   ie "login: " vs "login:" */
 	if (msg_len > 2 
 			&& compare_message[msg_len-2] == ':' 
 			&& compare_message[msg_len-1] == ' ') {
@@ -99,9 +99,9 @@
 		case PAM_PROMPT_ECHO_OFF:
 
 			if (!(strcmp(compare_message, "password:") == 0)) {
-				// We don't recognise the prompt as asking for a password,
-				// so can't handle it. Add more above as required for
-				// different pam modules/implementations
+				/* We don't recognise the prompt as asking for a password,
+				   so can't handle it. Add more above as required for
+				   different pam modules/implementations */
 				dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
 						compare_message);
 				rc = PAM_CONV_ERR;
@@ -125,9 +125,9 @@
 
 			if (!((strcmp(compare_message, "login:" ) == 0) 
 				|| (strcmp(compare_message, "please enter username:") == 0))) {
-				// We don't recognise the prompt as asking for a username,
-				// so can't handle it. Add more above as required for
-				// different pam modules/implementations
+				/* We don't recognise the prompt as asking for a username,
+				   so can't handle it. Add more above as required for
+				   different pam modules/implementations */
 				dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
 						compare_message);
 				rc = PAM_CONV_ERR;
--- a/svr-main.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/svr-main.c	Sun Dec 04 16:13:11 2005 +0000
@@ -375,7 +375,7 @@
 
 		TRACE(("listening on '%s'", svr_opts.ports[i]))
 
-		nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos], 
+		nsock = dropbear_listen("", svr_opts.ports[i], &sock[sockpos], 
 				sockcount - sockpos,
 				&errstring, maxfd);
 
--- a/svr-runopts.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/svr-runopts.c	Sun Dec 04 16:13:11 2005 +0000
@@ -63,13 +63,14 @@
 					"-s		Disable password logins\n"
 					"-g		Disable password logins for root\n"
 #endif
-#ifndef DISABLE_LOCALTCPFWD
+#ifdef ENABLE_SVR_LOCALTCPFWD
 					"-j		Disable local port forwarding\n"
 #endif
-#ifndef DISABLE_REMOTETCPFWD
+#ifdef ENABLE_SVR_REMOTETCPFWD
 					"-k		Disable remote port forwarding\n"
+					"-a		Allow connections to forwarded ports from any host\n"
 #endif
-					"-p port	Listen on specified tcp port, up to %d can be specified\n"
+					"-p port		Listen on specified tcp port, up to %d can be specified\n"
 					"		(default %s if none specified)\n"
 #ifdef INETD_MODE
 					"-i		Start for inetd\n"
@@ -104,8 +105,8 @@
 	svr_opts.inetdmode = 0;
 	svr_opts.portcount = 0;
 	svr_opts.hostkey = NULL;
-	opts.nolocaltcp = 0;
-	opts.noremotetcp = 0;
+	svr_opts.nolocaltcp = 0;
+	svr_opts.noremotetcp = 0;
 	/* not yet
 	opts.ipv4 = 1;
 	opts.ipv6 = 1;
@@ -116,6 +117,9 @@
 #ifndef DISABLE_SYSLOG
 	svr_opts.usingsyslog = 1;
 #endif
+#ifdef ENABLE_SVR_REMOTETCPFWD
+	opts.listen_fwd_all = 0;
+#endif
 
 	for (i = 1; i < (unsigned int)argc; i++) {
 		if (next) {
@@ -152,12 +156,15 @@
 #endif
 #ifndef DISABLE_LOCALTCPFWD
 				case 'j':
-					opts.nolocaltcp = 1;
+					svr_opts.nolocaltcp = 1;
 					break;
 #endif
 #ifndef DISABLE_REMOTETCPFWD
 				case 'k':
-					opts.noremotetcp = 1;
+					svr_opts.noremotetcp = 1;
+					break;
+				case 'a':
+					opts.listen_fwd_all = 1;
 					break;
 #endif
 #ifdef INETD_MODE
--- a/svr-tcpfwd.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/svr-tcpfwd.c	Sun Dec 04 16:13:11 2005 +0000
@@ -72,7 +72,7 @@
 
 	TRACE(("enter recv_msg_global_request_remotetcp"))
 
-	if (opts.noremotetcp) {
+	if (svr_opts.noremotetcp) {
 		TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
 		goto out;
 	}
@@ -129,9 +129,9 @@
 	const struct TCPListener *info1 = (struct TCPListener*)typedata1;
 	const struct TCPListener *info2 = (struct TCPListener*)typedata2;
 
-	return (info1->sendport == info2->sendport)
+	return (info1->listenport == info2->listenport)
 			&& (info1->chantype == info2->chantype)
-			&& (strcmp(info1->sendaddr, info2->sendaddr) == 0);
+			&& (strcmp(info1->listenaddr, info2->listenaddr) == 0);
 }
 
 static int svr_cancelremotetcp() {
@@ -153,8 +153,10 @@
 
 	port = buf_getint(ses.payload);
 
-	tcpinfo.sendaddr = bindaddr;
-	tcpinfo.sendport = port;
+	tcpinfo.sendaddr = NULL;
+	tcpinfo.sendport = 0;
+	tcpinfo.listenaddr = bindaddr;
+	tcpinfo.listenport = port;
 	listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
 	if (listener) {
 		remove_listener( listener );
@@ -177,7 +179,6 @@
 
 	TRACE(("enter remotetcpreq"))
 
-	/* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */
 	bindaddr = buf_getstring(ses.payload, &addrlen);
 	if (addrlen > MAX_IP_LEN) {
 		TRACE(("addr len too long: %d", addrlen))
@@ -202,20 +203,19 @@
 	}
 
 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
-	tcpinfo->sendaddr = bindaddr;
-	tcpinfo->sendport = port;
+	tcpinfo->sendaddr = NULL;
+	tcpinfo->sendport = 0;
+	tcpinfo->listenaddr = bindaddr;
 	tcpinfo->listenport = port;
 	tcpinfo->chantype = &svr_chan_tcpremote;
 
-	/* Note: bindaddr is actually ignored by listen_tcpfwd, since
-	 * we only want to bind to localhost */
 	ret = listen_tcpfwd(tcpinfo);
 
 out:
 	if (ret == DROPBEAR_FAILURE) {
 		/* we only free it if a listener wasn't created, since the listener
 		 * has to remember it if it's to be cancelled */
-		m_free(tcpinfo->sendaddr);
+		m_free(tcpinfo->listenaddr);
 		m_free(tcpinfo);
 	}
 	TRACE(("leave remotetcpreq"))
@@ -235,7 +235,7 @@
 	int len;
 	int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
 
-	if (opts.nolocaltcp) {
+	if (svr_opts.nolocaltcp) {
 		TRACE(("leave newtcpdirect: local tcp forwarding disabled"))
 		goto out;
 	}
--- a/tcp-accept.c	Wed Nov 30 10:11:24 2005 +0000
+++ b/tcp-accept.c	Sun Dec 04 16:13:11 2005 +0000
@@ -39,6 +39,7 @@
 	struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
 
 	m_free(tcpinfo->sendaddr);
+	m_free(tcpinfo->listenaddr);
 	m_free(tcpinfo);
 }
 
@@ -65,10 +66,14 @@
 
 	if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
 
-		buf_putstring(ses.writepayload, tcpinfo->sendaddr, 
-				strlen(tcpinfo->sendaddr));
-		buf_putint(ses.writepayload, tcpinfo->sendport);
+		// address that was connected
+		buf_putstring(ses.writepayload, tcpinfo->listenaddr, 
+				strlen(tcpinfo->listenaddr));
+		// port that was connected
+		buf_putint(ses.writepayload, tcpinfo->listenport);
+		// originator ip
 		buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
+		// originator port
 		buf_putint(ses.writepayload, atol(portstring));
 
 		encrypt_packet();
@@ -86,16 +91,21 @@
 	struct Listener *listener = NULL;
 	int nsocks;
 	char* errstring = NULL;
+	// listen_spec = NULL indicates localhost
+	const char* listen_spec = NULL;
 
 	TRACE(("enter listen_tcpfwd"))
 
 	/* first we try to bind, so don't need to do so much cleanup on failure */
 	snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport);
 
-	/* XXX Note: we're just listening on localhost, no matter what they tell
-	 * us. If someone wants to make it listen otherways, then change
-	 * the "" argument. but that requires UI changes too */
-	nsocks = dropbear_listen("", portstring, socks, 
+	/* a listenaddr of "" will indicate all interfaces */
+	if (opts.listen_fwd_all 
+			&& (strcmp(tcpinfo->listenaddr, "localhost") != 0) ) {
+		listen_spec = tcpinfo->listenaddr;
+	}
+
+	nsocks = dropbear_listen(listen_spec, portstring, socks, 
 			DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
 	if (nsocks < 0) {
 		dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
--- a/tcpfwd.h	Wed Nov 30 10:11:24 2005 +0000
+++ b/tcpfwd.h	Sun Dec 04 16:13:11 2005 +0000
@@ -28,16 +28,15 @@
 
 struct TCPListener {
 
-	/* sendaddr/sendport are what we send in the channel init request. For a 
-	 * forwarded-tcpip request, it's the addr/port we were binding to.
-	 * For a direct-tcpip request, it's the addr/port we want the other
+	/* For a direct-tcpip request, it's the addr/port we want the other
 	 * end to connect to */
-	
 	unsigned char *sendaddr;
 	unsigned int sendport;
 
-	/* This is for direct-tcpip (ie the client listening), and specifies the
-	 * port to listen on. Is unspecified for the server */
+	/* This is the address/port that we listen on. The address has special
+	 * meanings as per the rfc, "" for all interfaces, "localhost" for 
+	 * localhost, or a normal interface name. */
+	unsigned char *listenaddr;
 	unsigned int listenport;
 
 	const struct ChanType *chantype;