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);