Index: auth-pam.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/auth-pam.c,v retrieving revision 1.5 diff -u -r1.5 auth-pam.c --- auth-pam.c 2001/05/09 03:40:37 1.5 +++ auth-pam.c 2001/07/18 20:42:46 @@ -124,8 +124,12 @@ } reply[count].resp = xstrdup(pampasswd); } else { + /* + * XXX Options should be available + * here + */ reply[count].resp = - xstrdup(read_passphrase((*msg)[count].msg, 1)); + xstrdup(read_passphrase((*msg)[count].msg, 1, 0)); } reply[count].resp_retcode = PAM_SUCCESS; break; Index: auth-rsa.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/auth-rsa.c,v retrieving revision 1.8 diff -u -r1.8 auth-rsa.c --- auth-rsa.c 2001/05/04 04:14:22 1.8 +++ auth-rsa.c 2001/07/05 12:53:04 @@ -130,6 +130,9 @@ u_long linenum = 0; struct stat st; RSA *pk; + /* Information on file permissions failure */ + int fail = 0; + char buf[1024]; /* no user given */ if (pw == NULL) @@ -153,13 +156,9 @@ if (!f) { /* Restore the privileged uid. */ restore_uid(); - packet_send_debug("Could not open %.900s for reading.", file); - packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); return 0; } if (options.strict_modes) { - int fail = 0; - char buf[1024]; /* Check open file in order to avoid open/stat races */ if (fstat(fileno(f), &st) < 0 || (st.st_uid != 0 && st.st_uid != pw->pw_uid) || @@ -188,7 +187,6 @@ if (fail) { fclose(f); log("%s", buf); - packet_send_debug("%s", buf); restore_uid(); return 0; } Index: readconf.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/readconf.c,v retrieving revision 1.12 diff -u -r1.12 readconf.c --- readconf.c 2001/05/04 04:14:22 1.12 +++ readconf.c 2001/07/16 16:13:42 @@ -115,7 +115,7 @@ oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, - oHostKeyAlgorithms + oHostKeyAlgorithms, oPreferAskpass, } OpCodes; /* Textual representations of the tokens. */ @@ -184,6 +184,7 @@ { "dynamicforward", oDynamicForward }, { "preferredauthentications", oPreferredAuthentications }, { "hostkeyalgorithms", oHostKeyAlgorithms }, + { "preferaskpass", oPreferAskpass }, { NULL, 0 } }; @@ -658,6 +659,10 @@ *intptr = value; break; + case oPreferAskpass: + intptr = &options->prefer_askpass; + goto parse_flag; + default: fatal("process_config_line: Unimplemented opcode %d", opcode); } @@ -775,6 +780,7 @@ options->num_remote_forwards = 0; options->log_level = (LogLevel) - 1; options->preferred_authentications = NULL; + options->prefer_askpass = -1; } /* @@ -848,7 +854,7 @@ if (options->port == -1) options->port = 0; /* Filled in ssh_connect. */ if (options->connection_attempts == -1) - options->connection_attempts = 4; + options->connection_attempts = 1; if (options->number_of_password_prompts == -1) options->number_of_password_prompts = 3; /* Selected in ssh_login(). */ @@ -893,6 +899,8 @@ options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; if (options->log_level == (LogLevel) - 1) options->log_level = SYSLOG_LEVEL_INFO; + if (options->prefer_askpass == -1) + options->prefer_askpass = 1; /* options->proxy_command should not be set by default */ /* options->user will be set in the main program if appropriate */ /* options->hostname will be set in the main program if appropriate */ Index: readconf.h =================================================================== RCS file: /home/ncvs/src/crypto/openssh/readconf.h,v retrieving revision 1.8 diff -u -r1.8 readconf.h --- readconf.h 2001/05/04 04:14:22 1.8 +++ readconf.h 2001/07/16 16:10:45 @@ -91,6 +91,7 @@ char *system_hostfile2; char *user_hostfile2; char *preferred_authentications; + int prefer_askpass; /* Try using ssh-askpass before the CLI. */ int num_identity_files; /* Number of files for RSA/DSA identities. */ char *identity_files[SSH_MAX_IDENTITY_FILES]; Index: readpass.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/readpass.c,v retrieving revision 1.1.1.5 diff -u -r1.1.1.5 readpass.c --- readpass.c 2001/05/04 03:57:02 1.1.1.5 +++ readpass.c 2001/07/18 20:41:24 @@ -41,15 +41,17 @@ #include "log.h" #include "atomicio.h" #include "ssh.h" +#include -char * -ssh_askpass(char *askpass, char *msg) +static int +ssh_askpass(char *askpass, char *msg, char **phrase) { pid_t pid; size_t len; char *nl, *pass; int p[2], status; char buf[1024]; + int cerr; if (fflush(stdout) != 0) error("ssh_askpass: fflush: %s", strerror(errno)); @@ -66,7 +68,16 @@ if (dup2(p[1], STDOUT_FILENO) < 0) fatal("ssh_askpass: dup2: %s", strerror(errno)); execlp(askpass, askpass, msg, (char *) 0); - fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); + /* ssh-askpass returns + * 0 for accept + * 1 for cancel + * 2 for out-of-memory + * 3 for error + * 4 for timeout + * 127 for internal bug + * Make sure to not conflict with this. + */ + _exit(3); } close(p[1]); len = read(p[0], buf, sizeof buf); @@ -74,14 +85,21 @@ while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) break; - if (len <= 1) - return xstrdup(""); + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + *phrase = xstrdup(""); + return WEXITSTATUS(status); + } + if (len <= 1) { + *phrase = xstrdup(""); + return 0; + } nl = strchr(buf, '\n'); if (nl) *nl = '\0'; pass = xstrdup(buf); memset(buf, 0, sizeof(buf)); - return pass; + *phrase = pass; + return 0; } @@ -95,11 +113,31 @@ * cli_read_passphrase(). This routing remains to maintain * compatibility with existing code. */ -char * -read_passphrase(char *prompt, int from_stdin) +int +read_passphrase(char *prompt, char **response, int from_stdin, + int prefer_askpass) { char *askpass = NULL; int use_askpass = 0, ttyfd; + const char *display; + int ret = 0; + + display = getenv("DISPLAY"); + askpass = getenv(SSH_ASKPASS_ENV); + if (askpass == NULL) + askpass = _PATH_SSH_ASKPASS_DEFAULT; + if (prefer_askpass && display && display[0] == ':') { + /* + * We are using a local display. Thus, it is safer to attempt + * to use askpass than to grab it directly from the tty, as + * askpass avoid X grabbing attacks. + */ + ret = ssh_askpass(askpass, prompt, response); + /* Exit on OK and cancel */ + if (ret == 0 || ret == 1); + return ret; + /* For any failure try the CLI */ + } if (from_stdin) { if (!isatty(STDIN_FILENO)) @@ -112,13 +150,14 @@ use_askpass = 1; } - if (use_askpass && getenv("DISPLAY")) { - if (getenv(SSH_ASKPASS_ENV)) - askpass = getenv(SSH_ASKPASS_ENV); - else - askpass = _PATH_SSH_ASKPASS_DEFAULT; - return ssh_askpass(askpass, prompt); + if (use_askpass && display && ret == 0) { + ret = ssh_askpass(askpass, prompt, response); + /* Exit on OK and cancel */ + if (ret == 0 || ret == 1); + return ret; + /* For any failure try the CLI */ } - return cli_read_passphrase(prompt, from_stdin, 0); + *response = cli_read_passphrase(prompt, from_stdin, 0); + return 0; } Index: readpass.h =================================================================== RCS file: /home/ncvs/src/crypto/openssh/readpass.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 readpass.h --- readpass.h 2001/05/04 03:57:02 1.1.1.1 +++ readpass.h 2001/07/18 20:40:40 @@ -17,4 +17,5 @@ * passphrase (allocated with xmalloc). Exits if EOF is encountered. If * from_stdin is true, the passphrase will be read from stdin instead. */ -char *read_passphrase(char *prompt, int from_stdin); +int read_passphrase(char *prompt, char **response, int from_stdin, + int prefer_askpass); Index: ssh-add.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/ssh-add.c,v retrieving revision 1.5 diff -u -r1.5 ssh-add.c --- ssh-add.c 2001/06/29 16:43:13 1.5 +++ ssh-add.c 2001/07/18 20:43:39 @@ -124,7 +124,10 @@ snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ", comment); for (;;) { - pass = read_passphrase(msg, 1); + /* + * XXX Options should be available here + */ + pass = read_passphrase(msg, 1, 1); if (strcmp(pass, "") == 0) { clear_pass(); xfree(comment); @@ -192,7 +195,8 @@ /* At first, get a connection to the authentication agent. */ ac = ssh_get_authentication_connection(); if (ac == NULL) { - fprintf(stderr, "Could not open a connection to your authentication agent.\n"); + fprintf(stderr, +"Could not open a connection to your authentication agent.\n"); exit(1); } for (i = 1; i < argc; i++) { @@ -212,6 +216,10 @@ no_files = 0; continue; } + if (argv[i][0] == '-') { + fprintf(stderr, "Bad option %s\n", argv[i]); + continue; + } no_files = 0; if (deleting) delete_file(ac, argv[i]); @@ -225,8 +233,14 @@ (u_int)getuid()); ssh_close_authentication_connection(ac); exit(1); + } + if (snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, + _PATH_SSH_CLIENT_IDENTITY) > sizeof buf) { + fprintf(stderr, + "Too long homedir name - internal overflow\n"); + ssh_close_authentication_connection(ac); + exit(1); } - snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY); if (deleting) delete_file(ac, buf); else Index: ssh-keygen.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/ssh-keygen.c,v retrieving revision 1.1.1.7 diff -u -r1.1.1.7 ssh-keygen.c --- ssh-keygen.c 2001/05/04 03:57:03 1.1.1.7 +++ ssh-keygen.c 2001/07/18 20:45:14 @@ -116,7 +116,10 @@ prv = key_load_private(filename, "", NULL); if (prv == NULL) { - pass = read_passphrase("Enter passphrase: ", 1); + /* + * XXX Options should be available here + */ + pass = read_passphrase("Enter passphrase: ", 1, 1); prv = key_load_private(filename, pass, NULL); memset(pass, 0, strlen(pass)); xfree(pass); @@ -473,7 +476,10 @@ if (identity_passphrase) old_passphrase = xstrdup(identity_passphrase); else - old_passphrase = read_passphrase("Enter old passphrase: ", 1); + /* + * XXX Options should be available here + */ + old_passphrase = read_passphrase("Enter old passphrase: ", 1, 1); private = key_load_private(identity_file, old_passphrase , &comment); memset(old_passphrase, 0, strlen(old_passphrase)); xfree(old_passphrase); @@ -489,9 +495,12 @@ passphrase1 = xstrdup(identity_new_passphrase); passphrase2 = NULL; } else { + /* + * XXX Options should be available here + */ passphrase1 = - read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); - passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + read_passphrase("Enter new passphrase (empty for no passphrase): ", 1, 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1, 1); /* Verify that they are the same. */ if (strcmp(passphrase1, passphrase2) != 0) { @@ -552,7 +561,10 @@ else if (identity_new_passphrase) passphrase = xstrdup(identity_new_passphrase); else - passphrase = read_passphrase("Enter passphrase: ", 1); + /* + * XXX Options should be available here + */ + passphrase = read_passphrase("Enter passphrase: ", 1, 1); /* Try to load using the passphrase. */ private = key_load_private(identity_file, passphrase, &comment); if (private == NULL) { @@ -807,9 +819,12 @@ passphrase1 = xstrdup(identity_new_passphrase); else { passphrase_again: + /* + * XXX Options should be available here + */ passphrase1 = - read_passphrase("Enter passphrase (empty for no passphrase): ", 1); - passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + read_passphrase("Enter passphrase (empty for no passphrase): ", 1, 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1, 1); if (strcmp(passphrase1, passphrase2) != 0) { /* The passphrases do not match. Clear them and retry. */ memset(passphrase1, 0, strlen(passphrase1)); Index: ssh.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/ssh.c,v retrieving revision 1.14 diff -u -r1.14 ssh.c --- ssh.c 2001/05/04 04:14:23 1.14 +++ ssh.c 2001/07/15 18:53:51 @@ -238,7 +238,7 @@ int main(int ac, char **av) { - int i, opt, optind, exit_status, ok; + int i, opt, optind, exit_status, cerr; u_short fwd_port, fwd_host_port; char *optarg, *cp, buf[256]; struct stat st; @@ -635,7 +635,7 @@ /* Open a connection to the remote host. */ - ok = ssh_connect(host, &hostaddr, options.port, + cerr = ssh_connect(host, &hostaddr, options.port, options.connection_attempts, original_effective_uid != 0 || !options.use_privileged_port, pw, options.proxy_command); @@ -648,7 +648,7 @@ */ sensitive_data.nkeys = 0; sensitive_data.keys = NULL; - if (ok && (options.rhosts_rsa_authentication || + if (!cerr && (options.rhosts_rsa_authentication || options.hostbased_authentication)) { sensitive_data.nkeys = 3; sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key)); @@ -686,20 +686,19 @@ error("Could not create directory '%.200s'.", buf); /* Check if the connection failed, and try "rsh" if appropriate. */ - if (!ok) { + if (cerr) { + if (!options.fallback_to_rsh) + exit(1); if (options.port != 0) - log("Secure connection to %.100s on port %hu refused%.100s.", - host, options.port, - options.fallback_to_rsh ? "; reverting to insecure method" : ""); + log( +"Secure connection to %.100s on port %hu refused; reverting to insecure method", + host, options.port); else - log("Secure connection to %.100s refused%.100s.", host, - options.fallback_to_rsh ? "; reverting to insecure method" : ""); + log( +"Secure connection to %.100s refused; reverting to insecure method.", host); - if (options.fallback_to_rsh) { - rsh_connect(host, options.user, &command); - fatal("rsh_connect returned"); - } - exit(1); + rsh_connect(host, options.user, &command); + fatal("rsh_connect returned"); } /* load options.identity_files */ load_public_identity_files(); Index: sshconnect.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/sshconnect.c,v retrieving revision 1.17 diff -u -r1.17 sshconnect.c --- sshconnect.c 2001/05/04 04:37:49 1.17 +++ sshconnect.c 2001/07/18 21:06:11 @@ -45,6 +45,28 @@ /* AF_UNSPEC or AF_INET or AF_INET6 */ extern int IPv4or6; +static const char * +sockaddr_ntop(sa) + struct sockaddr *sa; +{ + void *addr; + static char addrbuf[INET6_ADDRSTRLEN]; + + switch (sa->sa_family) { + case AF_INET: + addr = &((struct sockaddr_in *)sa)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)sa)->sin6_addr; + break; + default: + /* This case should be protected against elsewhere */ + abort(); + } + inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); + return addrbuf; +} + /* * Connect to the given ssh server using a proxy command. */ @@ -142,7 +164,8 @@ /* Set the connection file descriptors. */ packet_set_connection(pout[0], pin[1]); - return 1; + /* Indicate OK return */ + return 0; } /* @@ -188,6 +211,12 @@ * second). If proxy_command is non-NULL, it specifies the command (with %h * and %p substituted for host and port, respectively) to use to contact * the daemon. + * Return values: + * 0 for OK + * ECONNREFUSED if we got a "Connection Refused" by the peer on any address + * ECONNABORTED if we failed without a "Connection refused" + * Suitable error messages for the connection failure will already have been + * printed. */ int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, @@ -202,6 +231,13 @@ struct addrinfo hints, *ai, *aitop; struct linger linger; struct servent *sp; + int port_set_locally; + /* + * Did we get only other errors than "Connection refused" (which + * should block fallback to rsh and similar), or did we get at least + * one "Connection refused"? + */ + int full_failure = 1; debug("ssh_connect: getuid %u geteuid %u anon %d", (u_int) getuid(), (u_int) geteuid(), anonymous); @@ -213,7 +249,9 @@ port = ntohs(sp->s_port); else port = SSH_DEFAULT_PORT; - } + port_set_locally = 1; + } else + port_set_locally = 0; /* If a proxy command is given, connect using it. */ if (proxy_command != NULL) return ssh_proxy_connect(host, port, pw, proxy_command); @@ -233,7 +271,7 @@ * will sometimes fail. In general socket code appears to behave * quite magically on many machines. */ - for (attempt = 0; attempt < connection_attempts; attempt++) { + for (attempt = 0; ;) { if (attempt > 0) debug("Trying again..."); @@ -256,6 +294,7 @@ !anonymous && geteuid() == 0, ai->ai_family); if (sock < 0) + /* Any error is already output */ continue; /* Connect to the host. We use the user's uid in the @@ -269,7 +308,17 @@ restore_uid(); break; } else { - debug("connect: %.100s", strerror(errno)); + if (errno == ECONNREFUSED) + full_failure = 0; + if (port_set_locally) + log("ssh: connect to address %s: %s", + sockaddr_ntop(ai->ai_addr), + strerror(errno)); + else + log( +"ssh: connect to address %s port %s: %s", + sockaddr_ntop(ai->ai_addr), strport, + strerror(errno)); restore_uid(); /* * Close the failed socket; there appear to @@ -284,6 +333,9 @@ if (ai) break; /* Successful connection. */ + attempt++; + if (attempt >= connection_attempts) + break; /* Sleep a moment before retrying. */ sleep(1); } @@ -292,7 +344,7 @@ /* Return failure if we didn't get a successful connection. */ if (attempt >= connection_attempts) - return 0; + return full_failure ? ECONNABORTED : ECONNREFUSED; debug("Connection established."); @@ -314,7 +366,7 @@ /* Set the connection. */ packet_set_connection(sock, sock); - return 1; + return 0; } /* @@ -672,7 +724,10 @@ * If strict host key checking is in use, the user will have * to edit the key manually and we can only abort. */ - if (options.strict_host_key_checking) + if (options.strict_host_key_checking == 2) { + if (!read_yes_or_no("Do you want to continue connecting in spite of the changed key (yes/no)? ", -1)) + fatal("Connection aborted by user."); + } else if (options.strict_host_key_checking) fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host); /* Index: sshconnect1.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/sshconnect1.c,v retrieving revision 1.11 diff -u -r1.11 sshconnect1.c --- sshconnect1.c 2001/07/07 14:19:53 1.11 +++ sshconnect1.c 2001/07/18 20:46:53 @@ -260,15 +260,18 @@ */ private = key_load_private_type(KEY_RSA1, authfile, "", NULL); if (private == NULL) { + int cancelled = 0; char buf[300]; snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", comment); if (!options.batch_mode) - passphrase = read_passphrase(buf, 0); + cancelled = read_passphrase(buf, &passphrase, 0, + options.prefer_askpass) != 0; else { debug("Will not query passphrase for %.100s in batch mode.", comment); passphrase = xstrdup(""); + cancelled = 1; } /* Load the authentication file using the pasphrase. */ @@ -276,7 +279,8 @@ if (private == NULL) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - error("Bad passphrase."); + if (!cancelled) + error("Bad passphrase."); /* Send a dummy response packet to avoid protocol error. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); @@ -654,7 +658,8 @@ if (options.cipher == SSH_CIPHER_NONE) log("WARNING: Encryption is disabled! " "Reponse will be transmitted in clear text."); - response = read_passphrase(prompt, 0); + (void)read_passphrase(prompt, &response, 0, + options.prefer_askpass); if (strcmp(response, "") == 0) { xfree(response); break; @@ -691,7 +696,9 @@ 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 (read_passphrase(prompt, &password, 0, + options.prefer_askpass) != 0) + break; packet_start(SSH_CMSG_AUTH_PASSWORD); ssh_put_password(password); memset(password, 0, strlen(password)); Index: sshconnect2.c =================================================================== RCS file: /home/ncvs/src/crypto/openssh/sshconnect2.c,v retrieving revision 1.3 diff -u -r1.3 sshconnect2.c --- sshconnect2.c 2001/05/04 04:14:23 1.3 +++ sshconnect2.c 2001/07/18 20:47:44 @@ -451,7 +451,8 @@ snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", authctxt->server_user, authctxt->host); - password = read_passphrase(prompt, 0); + if (read_passphrase(prompt, &password, 0, options.prefer_askpass) != 0) + return 0; packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); @@ -615,7 +616,8 @@ snprintf(prompt, sizeof prompt, "Enter passphrase for key '%.100s': ", filename); for (i = 0; i < options.number_of_password_prompts; i++) { - passphrase = read_passphrase(prompt, 0); + (void)read_passphrase(prompt, &passphrase, 0, + options.prefer_askpass); if (strcmp(passphrase, "") != 0) { private = key_load_private_type(KEY_UNSPEC, filename, passphrase, NULL);