.netrc and SSH

samtregar on 2003-01-17T23:20:29

I admit it, I use a .netrc file. If you're not familiar with obsolete UNIX technology, a .netrc file contains machine names, usernames and passwords that programs can use to automate logins. Traditionally ftp has supported .netrc and so does fetchmail. From a security point of view it's pure madness since it means a breakin into one account turns into a breakin on all accounts listed in the .netrc.

I got started using .netrc via Emacs' ange-ftp mode. The ange-ftp mode allows you to edit files via FTP as though they were local. This is all just great, except that every time I open a file with ange-ftp for the first time it prompts for a password. I quickly got tired of that and started looking around for a solution.

Then it hit me that if I was bold enough to store my account passwords in a plaintext on my hard drive, then why shouldn't I get the maximum benefit from the mistake? Why should I type my passwords on those machines at all?

Thus was born my .netrc patch for OpenSSH. I just ported it to OpenSSH 3.5p1 and it occured to me that I might not be the only person that could benefit from it. Just apply it with "patch -p1" inside the 3.5p1 sources, compile it and put a line like this in your ~/.ssh/config:

netrcfile /home/sam/.netrc

Now whenever you ssh to a machine in your .netrc you won't even see a login prompt. Goodbye security and hello slack!

(BTW: I do realize that SSH supports some crazy public key system for automatic logins. I must be too dumb to use it though, because I've tried to set it up a couple times with no success.)

-sam

diff -ru openssh-3.5p1/readconf.c openssh-3.5p1.new/readconf.c
--- openssh-3.5p1/readconf.c	Tue Jul  9 10:06:40 2002
+++ openssh-3.5p1.new/readconf.c	Fri Jan 17 14:57:43 2003
@@ -114,7 +114,7 @@
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
-	oDeprecated
+	oDeprecated, oNetrcFile
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -186,6 +186,7 @@
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+        { "netrcfile", oNetrcFile },
 	{ NULL, oBadOption }
 };
 
@@ -448,6 +449,10 @@
 			*charptr = xstrdup(arg);
 		break;
 
+        case oNetrcFile:
+                charptr = &options->netrcfile;
+                goto parse_string; 
+
 	case oGlobalKnownHostsFile:
 		charptr = &options->system_hostfile;
 		goto parse_string;
@@ -790,6 +795,7 @@
 	options->clear_forwardings = -1;
 	options->log_level = SYSLOG_LEVEL_NOT_SET;
 	options->preferred_authentications = NULL;
+        options->netrcfile = NULL;
 	options->bind_address = NULL;
 	options->smartcard_device = NULL;
 	options->no_host_authentication_for_localhost = - 1;
diff -ru openssh-3.5p1/readconf.h openssh-3.5p1.new/readconf.h
--- openssh-3.5p1/readconf.h	Sun Jun  9 16:04:03 2002
+++ openssh-3.5p1.new/readconf.h	Fri Jan 17 14:58:29 2003
@@ -100,6 +100,10 @@
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
 	int	clear_forwardings;
 	int	no_host_authentication_for_localhost;
+
+        /* Netrc File */
+        char   *netrcfile;
+
 }       Options;
 
 
diff -ru openssh-3.5p1/sshconnect1.c openssh-3.5p1.new/sshconnect1.c
--- openssh-3.5p1/sshconnect1.c	Tue Aug 20 14:41:16 2002
+++ openssh-3.5p1.new/sshconnect1.c	Fri Jan 17 15:00:56 2003
@@ -918,18 +918,47 @@
  * Tries to authenticate with plain passwd authentication.
  */
 static int
-try_password_authentication(char *prompt)
+try_password_authentication(char *prompt, const char *server_user, const char *host)
 {
 	int type, i;
-	char *password;
+	char *password = NULL;
 
+        // try netrc if available
+        if (options.netrcfile) {
+          FILE *file;
+          char line[256];
+          char *machine, *login;
+
+          file = fopen(options.netrcfile, "r");
+          if (!file) error("Unable to open netrc file.");
+
+          // parse through file line-by-line
+          while(!feof(file)) {
+            fgets(line, 254, file);
+            if (!line) break;
+
+            // get line
+            if (sscanf(line, "machine %as login %as password %as", &machine, &login, &password)) {
+              if (!strcmp(host, machine) &&
+                  !strcmp(server_user, login)) {
+                break;
+              } else {
+                password = NULL;
+              }
+            }
+          }
+          fclose(file);
+        }
+
+ 
 	debug("Doing password authentication.");
 	if (options.cipher == SSH_CIPHER_NONE)
 		log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
 	for (i = 0; i < options.number_of_password_prompts; i++) {
 		if (i != 0)
 			error("Permission denied, please try again.");
-		password = read_passphrase(prompt, 0);
+                if (password == NULL)
+                  password = read_passphrase(prompt, 0);
 		packet_start(SSH_CMSG_AUTH_PASSWORD);
 		ssh_put_password(password);
 		memset(password, 0, strlen(password));
@@ -1263,7 +1292,7 @@
 
 		snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
 		    server_user, host);
-		if (try_password_authentication(prompt))
+		if (try_password_authentication(prompt, server_user, host))
 			goto success;
 	}
 	/* All authentication methods have failed.  Exit with an error message. */
diff -ru openssh-3.5p1/sshconnect2.c openssh-3.5p1.new/sshconnect2.c
--- openssh-3.5p1/sshconnect2.c	Thu Oct  3 01:45:55 2002
+++ openssh-3.5p1.new/sshconnect2.c	Fri Jan 17 15:07:49 2003
@@ -445,7 +445,7 @@
 {
 	static int attempt = 0;
 	char prompt[150];
-	char *password;
+	char *password = NULL;
 
 	if (attempt++ >= options.number_of_password_prompts)
 		return 0;
@@ -455,7 +455,40 @@
 
 	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
 	    authctxt->server_user, authctxt->host);
-	password = read_passphrase(prompt, 0);
+
+        // try netrc if available
+        if (options.netrcfile) {
+          FILE *file;
+          char line[256];
+          char *machine, *login;
+
+          file = fopen(options.netrcfile, "r");
+          if (!file) error("Unable to open netrc file.");
+
+          // parse through file line-by-line
+          while(!feof(file)) {
+            fgets(line, 254, file);
+            if (!line) break;
+
+            // get line
+            if (sscanf(line, "machine %as login %as password %as", &machine, &login, &password)) {
+              if (!strcmp(authctxt->host, machine) &&
+                  !strcmp(authctxt->server_user, login)) {
+                break;
+              } else {
+                password = NULL;
+              }
+            }
+          }
+          fclose(file);
+        }
+
+        if (password == NULL) {
+          snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
+                   authctxt->server_user, authctxt->host);
+          password = read_passphrase(prompt, 0);
+        }
+
 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
 	packet_put_cstring(authctxt->server_user);
 	packet_put_cstring(authctxt->service);


Good SSH Key Management Intoduction

zengargoyle on 2003-03-22T04:12:05

http://www-106.ibm.com/developerworks/library/l-keyc.html

the whole series is worth the free registration.