- More reformatting merged from OpenBSD CVS

- Merged OpenBSD CVS changes:
   - [channels.c]
     report from mrwizard@psu.edu via djm@ibs.com.au
   - [channels.c]
     set SO_REUSEADDR and SO_LINGER for forwarded ports.
     chip@valinux.com via damien@ibs.com.au
   - [nchan.c]
     it's not an error() if shutdown_write failes in nchan.
   - [readconf.c]
     remove dead #ifdef-0-code
   - [readconf.c servconf.c]
     strcasecmp instead of tolower
   - [scp.c]
     progress meter overflow fix from damien@ibs.com.au
   - [ssh-add.1 ssh-add.c]
     SSH_ASKPASS support
   - [ssh.1 ssh.c]
     postpone fork_after_authentication until command execution,
     request/patch from jahakala@cc.jyu.fi via damien@ibs.com.au
     plus: use daemon() for backgrounding
This commit is contained in:
Damien Miller 1999-11-25 11:54:57 +11:00
parent 9072e18896
commit 5428f646ad
61 changed files with 2681 additions and 1798 deletions

View File

@ -11,7 +11,7 @@
#ifndef HAVE_PAM #ifndef HAVE_PAM
RCSID("$Id: auth-passwd.c,v 1.6 1999/11/24 13:26:21 damien Exp $"); RCSID("$Id: auth-passwd.c,v 1.7 1999/11/25 00:54:57 damien Exp $");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
@ -39,14 +39,10 @@ auth_password(struct passwd * pw, const char *password)
struct spwd *spw; struct spwd *spw;
#endif #endif
if (pw->pw_uid == 0 && options.permit_root_login == 2) { if (pw->pw_uid == 0 && options.permit_root_login == 2)
/* Server does not permit root login with password */
return 0; return 0;
} if (*password == '\0' && options.permit_empty_passwd == 0)
if (*password == '\0' && options.permit_empty_passwd == 0) {
/* Server does not permit empty password login */
return 0; return 0;
}
/* deny if no user. */ /* deny if no user. */
if (pw == NULL) if (pw == NULL)
return 0; return 0;
@ -74,8 +70,10 @@ auth_password(struct passwd * pw, const char *password)
#endif #endif
#if defined(KRB4) #if defined(KRB4)
/* Support for Kerberos v4 authentication - Dug Song /*
<dugsong@UMICH.EDU> */ * Support for Kerberos v4 authentication
* - Dug Song <dugsong@UMICH.EDU>
*/
if (options.kerberos_authentication) { if (options.kerberos_authentication) {
AUTH_DAT adata; AUTH_DAT adata;
KTEXT_ST tkt; KTEXT_ST tkt;
@ -86,8 +84,10 @@ auth_password(struct passwd * pw, const char *password)
char realm[REALM_SZ]; char realm[REALM_SZ];
int r; int r;
/* Try Kerberos password authentication only for non-root /*
users and only if Kerberos is installed. */ * Try Kerberos password authentication only for non-root
* users and only if Kerberos is installed.
*/
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
/* Set up our ticket file. */ /* Set up our ticket file. */
@ -144,14 +144,17 @@ auth_password(struct passwd * pw, const char *password)
goto kerberos_auth_failure; goto kerberos_auth_failure;
} }
} else if (r == KDC_PR_UNKNOWN) { } else if (r == KDC_PR_UNKNOWN) {
/* Allow login if no rcmd service exists, /*
but log the error. */ * Allow login if no rcmd service exists, but
* log the error.
*/
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s " log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
"not registered, or srvtab is wrong?", pw->pw_name, "not registered, or srvtab is wrong?", pw->pw_name,
krb_err_txt[r], KRB4_SERVICE_NAME, phost); krb_err_txt[r], KRB4_SERVICE_NAME, phost);
} else { } else {
/* TGT is bad, forget it. Possibly /*
spoofed! */ * TGT is bad, forget it. Possibly spoofed!
*/
packet_send_debug("WARNING: Kerberos V4 TGT " packet_send_debug("WARNING: Kerberos V4 TGT "
"possibly spoofed for %s: %s", "possibly spoofed for %s: %s",
pw->pw_name, krb_err_txt[r]); pw->pw_name, krb_err_txt[r]);
@ -175,11 +178,8 @@ auth_password(struct passwd * pw, const char *password)
#endif /* KRB4 */ #endif /* KRB4 */
/* Check for users with no password. */ /* Check for users with no password. */
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) { if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
packet_send_debug("Login permitted without a password "
"because the account has no password.");
return 1; return 1;
}
#ifdef HAVE_SHADOW_H #ifdef HAVE_SHADOW_H
spw = getspnam(pw->pw_name); spw = getspnam(pw->pw_name);

View File

@ -15,7 +15,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $"); RCSID("$Id: auth-rh-rsa.c,v 1.7 1999/11/25 00:54:57 damien Exp $");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
@ -23,8 +23,10 @@ RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
#include "uidswap.h" #include "uidswap.h"
#include "servconf.h" #include "servconf.h"
/* Tries to authenticate the user using the .rhosts file and the host using /*
its host key. Returns true if authentication succeeds. */ * Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int int
auth_rhosts_rsa(struct passwd *pw, const char *client_user, auth_rhosts_rsa(struct passwd *pw, const char *client_user,
@ -57,8 +59,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user,
if (host_status != HOST_OK && !options.ignore_user_known_hosts) { if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
struct stat st; struct stat st;
char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid); char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid);
/* Check file permissions of SSH_USER_HOSTFILE, auth_rsa() /*
did already check pw->pw_dir, but there is a race XXX */ * Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
* did already check pw->pw_dir, but there is a race XXX
*/
if (options.strict_modes && if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) && (stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) || ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
@ -91,8 +95,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user,
canonical_hostname); canonical_hostname);
return 0; return 0;
} }
/* We have authenticated the user using .rhosts or /etc/hosts.equiv, and the host using RSA. /*
We accept the authentication. */ * We have authenticated the user using .rhosts or /etc/hosts.equiv,
* and the host using RSA. We accept the authentication.
*/
verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
pw->pw_name, client_user, canonical_hostname); pw->pw_name, client_user, canonical_hostname);

View File

@ -16,7 +16,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $"); RCSID("$Id: auth-rhosts.c,v 1.6 1999/11/25 00:54:57 damien Exp $");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
@ -24,9 +24,11 @@ RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $");
#include "uidswap.h" #include "uidswap.h"
#include "servconf.h" #include "servconf.h"
/* This function processes an rhosts-style file (.rhosts, .shosts, or /*
/etc/hosts.equiv). This returns true if authentication can be granted * This function processes an rhosts-style file (.rhosts, .shosts, or
based on the file, and returns zero otherwise. */ * /etc/hosts.equiv). This returns true if authentication can be granted
* based on the file, and returns zero otherwise.
*/
int int
check_rhosts_file(const char *filename, const char *hostname, check_rhosts_file(const char *filename, const char *hostname,
@ -41,7 +43,6 @@ check_rhosts_file(const char *filename, const char *hostname,
if (!f) if (!f)
return 0; return 0;
/* Go through the file, checking every entry. */
while (fgets(buf, sizeof(buf), f)) { while (fgets(buf, sizeof(buf), f)) {
/* All three must be at least as big as buf to avoid overflows. */ /* All three must be at least as big as buf to avoid overflows. */
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
@ -52,13 +53,17 @@ check_rhosts_file(const char *filename, const char *hostname,
if (*cp == '#' || *cp == '\n' || !*cp) if (*cp == '#' || *cp == '\n' || !*cp)
continue; continue;
/* NO_PLUS is supported at least on OSF/1. We skip it (we /*
don't ever support the plus syntax). */ * NO_PLUS is supported at least on OSF/1. We skip it (we
* don't ever support the plus syntax).
*/
if (strncmp(cp, "NO_PLUS", 7) == 0) if (strncmp(cp, "NO_PLUS", 7) == 0)
continue; continue;
/* This should be safe because each buffer is as big as /*
the whole string, and thus cannot be overwritten. */ * This should be safe because each buffer is as big as the
* whole string, and thus cannot be overwritten.
*/
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) { switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
case 0: case 0:
packet_send_debug("Found empty line in %.100s.", filename); packet_send_debug("Found empty line in %.100s.", filename);
@ -135,10 +140,11 @@ check_rhosts_file(const char *filename, const char *hostname,
return 0; return 0;
} }
/* Tries to authenticate the user using the .shosts or .rhosts file. /*
Returns true if authentication succeeds. If ignore_rhosts is * Tries to authenticate the user using the .shosts or .rhosts file. Returns
true, only /etc/hosts.equiv will be considered (.rhosts and .shosts * true if authentication succeeds. If ignore_rhosts is true, only
are ignored). */ * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
*/
int int
auth_rhosts(struct passwd *pw, const char *client_user) auth_rhosts(struct passwd *pw, const char *client_user)
@ -150,11 +156,13 @@ auth_rhosts(struct passwd *pw, const char *client_user)
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
unsigned int rhosts_file_index; unsigned int rhosts_file_index;
/* Quick check: if the user has no .shosts or .rhosts files,
return failure immediately without doing costly lookups from
name servers. */
/* Switch to the user's uid. */ /* Switch to the user's uid. */
temporarily_use_uid(pw->pw_uid); temporarily_use_uid(pw->pw_uid);
/*
* Quick check: if the user has no .shosts or .rhosts files, return
* failure immediately without doing costly lookups from name
* servers.
*/
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
rhosts_file_index++) { rhosts_file_index++) {
/* Check users .rhosts or .shosts. */ /* Check users .rhosts or .shosts. */
@ -172,7 +180,6 @@ auth_rhosts(struct passwd *pw, const char *client_user)
stat(SSH_HOSTS_EQUIV, &st) < 0) stat(SSH_HOSTS_EQUIV, &st) < 0)
return 0; return 0;
/* Get the name, address, and port of the remote host. */
hostname = get_canonical_hostname(); hostname = get_canonical_hostname();
ipaddr = get_remote_ipaddr(); ipaddr = get_remote_ipaddr();
@ -191,8 +198,10 @@ auth_rhosts(struct passwd *pw, const char *client_user)
return 1; return 1;
} }
} }
/* Check that the home directory is owned by root or the user, and /*
is not group or world writable. */ * Check that the home directory is owned by root or the user, and is
* not group or world writable.
*/
if (stat(pw->pw_dir, &st) < 0) { if (stat(pw->pw_dir, &st) < 0) {
log("Rhosts authentication refused for %.100s: no home directory %.200s", log("Rhosts authentication refused for %.100s: no home directory %.200s",
pw->pw_name, pw->pw_dir); pw->pw_name, pw->pw_dir);
@ -221,10 +230,12 @@ auth_rhosts(struct passwd *pw, const char *client_user)
if (stat(buf, &st) < 0) if (stat(buf, &st) < 0)
continue; continue;
/* Make sure that the file is either owned by the user or /*
by root, and make sure it is not writable by anyone but * Make sure that the file is either owned by the user or by
the owner. This is to help avoid novices accidentally * root, and make sure it is not writable by anyone but the
allowing access to their account by anyone. */ * owner. This is to help avoid novices accidentally
* allowing access to their account by anyone.
*/
if (options.strict_modes && if (options.strict_modes &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) || ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) { (st.st_mode & 022) != 0)) {

View File

@ -16,7 +16,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rsa.c,v 1.9 1999/11/24 13:26:21 damien Exp $"); RCSID("$Id: auth-rsa.c,v 1.10 1999/11/25 00:54:57 damien Exp $");
#include "rsa.h" #include "rsa.h"
#include "packet.h" #include "packet.h"
@ -43,22 +43,27 @@ extern int no_pty_flag;
extern char *forced_command; extern char *forced_command;
extern struct envstring *custom_environment; extern struct envstring *custom_environment;
/* Session identifier that is used to bind key exchange and authentication /*
responses to a particular session. */ * Session identifier that is used to bind key exchange and authentication
* responses to a particular session.
*/
extern unsigned char session_id[16]; extern unsigned char session_id[16];
/* The .ssh/authorized_keys file contains public keys, one per line, in the /*
following format: * The .ssh/authorized_keys file contains public keys, one per line, in the
options bits e n comment * following format:
where bits, e and n are decimal numbers, * options bits e n comment
and comment is any string of characters up to newline. The maximum * where bits, e and n are decimal numbers,
length of a line is 8000 characters. See the documentation for a * and comment is any string of characters up to newline. The maximum
description of the options. * length of a line is 8000 characters. See the documentation for a
*/ * description of the options.
*/
/* Performs the RSA authentication challenge-response dialog with the client, /*
and returns true (non-zero) if the client gave the correct answer to * Performs the RSA authentication challenge-response dialog with the client,
our challenge; returns zero if the client gives a wrong answer. */ * and returns true (non-zero) if the client gave the correct answer to
* our challenge; returns zero if the client gives a wrong answer.
*/
int int
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
@ -128,9 +133,11 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
return 1; return 1;
} }
/* Performs the RSA authentication dialog with the client. This returns /*
0 if the client could not be authenticated, and 1 if authentication was * Performs the RSA authentication dialog with the client. This returns
successful. This may exit if there is a serious protocol violation. */ * 0 if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int int
auth_rsa(struct passwd *pw, BIGNUM *client_n) auth_rsa(struct passwd *pw, BIGNUM *client_n)
@ -204,30 +211,32 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
/* Flag indicating whether authentication has succeeded. */ /* Flag indicating whether authentication has succeeded. */
authenticated = 0; authenticated = 0;
/* Initialize mp-int variables. */
e = BN_new(); e = BN_new();
n = BN_new(); n = BN_new();
/* Go though the accepted keys, looking for the current key. If /*
found, perform a challenge-response dialog to verify that the * Go though the accepted keys, looking for the current key. If
user really has the corresponding private key. */ * found, perform a challenge-response dialog to verify that the
* user really has the corresponding private key.
*/
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
char *cp; char *cp;
char *options; char *options;
linenum++; linenum++;
/* Skip leading whitespace. */ /* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++); for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
/* Skip empty and comment lines. */
if (!*cp || *cp == '\n' || *cp == '#') if (!*cp || *cp == '\n' || *cp == '#')
continue; continue;
/* Check if there are options for this key, and if so, /*
save their starting address and skip the option part * Check if there are options for this key, and if so,
for now. If there are no options, set the starting * save their starting address and skip the option part
address to NULL. */ * for now. If there are no options, set the starting
* address to NULL.
*/
if (*cp < '0' || *cp > '9') { if (*cp < '0' || *cp > '9') {
int quoted = 0; int quoted = 0;
options = cp; options = cp;
@ -258,7 +267,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
/* Check if the we have found the desired key (identified by its modulus). */ /* Check if the we have found the desired key (identified by its modulus). */
if (BN_cmp(n, client_n) != 0) if (BN_cmp(n, client_n) != 0)
continue; /* Wrong key. */ continue;
/* We have found the desired key. */ /* We have found the desired key. */
@ -269,10 +278,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
packet_send_debug("Wrong response to RSA authentication challenge."); packet_send_debug("Wrong response to RSA authentication challenge.");
continue; continue;
} }
/* Correct response. The client has been successfully /*
authenticated. Note that we have not yet processed the * Correct response. The client has been successfully
options; this will be reset if the options cause the * authenticated. Note that we have not yet processed the
authentication to be rejected. */ * options; this will be reset if the options cause the
* authentication to be rejected.
*/
authenticated = 1; authenticated = 1;
/* RSA part of authentication was accepted. Now process the options. */ /* RSA part of authentication was accepted. Now process the options. */
@ -412,7 +423,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
goto next_option; goto next_option;
} }
bad_option: bad_option:
/* Unknown option. */
log("Bad options in %.100s file, line %lu: %.50s", log("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options); SSH_USER_PERMITTED_KEYS, linenum, options);
packet_send_debug("Bad options in %.100s file, line %lu: %.50s", packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
@ -421,8 +431,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
break; break;
next_option: next_option:
/* Skip the comma, and move to the next option /*
(or break out if there are no more). */ * Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (!*options) if (!*options)
fatal("Bugs in auth-rsa.c option processing."); fatal("Bugs in auth-rsa.c option processing.");
if (*options == ' ' || *options == '\t') if (*options == ' ' || *options == '\t')
@ -434,8 +446,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
continue; continue;
} }
} }
/* Break out of the loop if authentication was successful; /*
otherwise continue searching. */ * Break out of the loop if authentication was successful;
* otherwise continue searching.
*/
if (authenticated) if (authenticated)
break; break;
} }
@ -446,7 +460,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
/* Close the file. */ /* Close the file. */
fclose(f); fclose(f);
/* Clear any mp-int variables. */
BN_clear_free(n); BN_clear_free(n);
BN_clear_free(e); BN_clear_free(e);

View File

@ -1,11 +1,15 @@
#include "includes.h" #include "includes.h"
#ifdef SKEY #ifdef SKEY
RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $"); RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include <sha1.h> #ifdef HAVE_OPENSSL
#include <openssl/sha1.h>
#endif
#ifdef HAVE_SSL
#include <ssl/sha1.h>
#endif
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */ /* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */

127
authfd.c
View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: authfd.c,v 1.7 1999/11/24 13:26:21 damien Exp $"); RCSID("$Id: authfd.c,v 1.8 1999/11/25 00:54:57 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
@ -63,9 +63,11 @@ ssh_get_authentication_socket()
return sock; return sock;
} }
/* Closes the agent socket if it should be closed (depends on how it was /*
obtained). The argument must have been returned by * Closes the agent socket if it should be closed (depends on how it was
ssh_get_authentication_socket(). */ * obtained). The argument must have been returned by
* ssh_get_authentication_socket().
*/
void void
ssh_close_authentication_socket(int sock) ssh_close_authentication_socket(int sock)
@ -74,11 +76,13 @@ ssh_close_authentication_socket(int sock)
close(sock); close(sock);
} }
/* Opens and connects a private socket for communication with the /*
authentication agent. Returns the file descriptor (which must be * Opens and connects a private socket for communication with the
shut down and closed by the caller when no longer needed). * authentication agent. Returns the file descriptor (which must be
Returns NULL if an error occurred and the connection could not be * shut down and closed by the caller when no longer needed).
opened. */ * Returns NULL if an error occurred and the connection could not be
* opened.
*/
AuthenticationConnection * AuthenticationConnection *
ssh_get_authentication_connection() ssh_get_authentication_connection()
@ -88,12 +92,13 @@ ssh_get_authentication_connection()
sock = ssh_get_authentication_socket(); sock = ssh_get_authentication_socket();
/* Fail if we couldn't obtain a connection. This happens if we /*
exited due to a timeout. */ * Fail if we couldn't obtain a connection. This happens if we
* exited due to a timeout.
*/
if (sock < 0) if (sock < 0)
return NULL; return NULL;
/* Applocate the connection structure and initialize it. */
auth = xmalloc(sizeof(*auth)); auth = xmalloc(sizeof(*auth));
auth->fd = sock; auth->fd = sock;
buffer_init(&auth->packet); buffer_init(&auth->packet);
@ -103,8 +108,10 @@ ssh_get_authentication_connection()
return auth; return auth;
} }
/* Closes the connection to the authentication agent and frees any associated /*
memory. */ * Closes the connection to the authentication agent and frees any associated
* memory.
*/
void void
ssh_close_authentication_connection(AuthenticationConnection *ac) ssh_close_authentication_connection(AuthenticationConnection *ac)
@ -115,10 +122,12 @@ ssh_close_authentication_connection(AuthenticationConnection *ac)
xfree(ac); xfree(ac);
} }
/* Returns the first authentication identity held by the agent. /*
Returns true if an identity is available, 0 otherwise. * Returns the first authentication identity held by the agent.
The caller must initialize the integers before the call, and free the * Returns true if an identity is available, 0 otherwise.
comment after a successful call (before calling ssh_get_next_identity). */ * The caller must initialize the integers before the call, and free the
* comment after a successful call (before calling ssh_get_next_identity).
*/
int int
ssh_get_first_identity(AuthenticationConnection *auth, ssh_get_first_identity(AuthenticationConnection *auth,
@ -127,8 +136,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
unsigned char msg[8192]; unsigned char msg[8192];
int len, l; int len, l;
/* Send a message to the agent requesting for a list of the /*
identities it can represent. */ * Send a message to the agent requesting for a list of the
* identities it can represent.
*/
msg[0] = 0; msg[0] = 0;
msg[1] = 0; msg[1] = 0;
msg[2] = 0; msg[2] = 0;
@ -149,8 +160,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
len -= l; len -= l;
} }
/* Extract the length, and check it for sanity. (We cannot trust /*
authentication agents). */ * Extract the length, and check it for sanity. (We cannot trust
* authentication agents).
*/
len = GET_32BIT(msg); len = GET_32BIT(msg);
if (len < 1 || len > 256 * 1024) if (len < 1 || len > 256 * 1024)
fatal("Authentication reply message too long: %d\n", len); fatal("Authentication reply message too long: %d\n", len);
@ -182,10 +195,12 @@ ssh_get_first_identity(AuthenticationConnection *auth,
return ssh_get_next_identity(auth, e, n, comment); return ssh_get_next_identity(auth, e, n, comment);
} }
/* Returns the next authentication identity for the agent. Other functions /*
can be called between this and ssh_get_first_identity or two calls of this * Returns the next authentication identity for the agent. Other functions
function. This returns 0 if there are no more identities. The caller * can be called between this and ssh_get_first_identity or two calls of this
must free comment after a successful return. */ * function. This returns 0 if there are no more identities. The caller
* must free comment after a successful return.
*/
int int
ssh_get_next_identity(AuthenticationConnection *auth, ssh_get_next_identity(AuthenticationConnection *auth,
@ -197,8 +212,10 @@ ssh_get_next_identity(AuthenticationConnection *auth,
if (auth->howmany <= 0) if (auth->howmany <= 0)
return 0; return 0;
/* Get the next entry from the packet. These will abort with a /*
fatal error if the packet is too short or contains corrupt data. */ * Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data.
*/
bits = buffer_get_int(&auth->identities); bits = buffer_get_int(&auth->identities);
buffer_get_bignum(&auth->identities, e); buffer_get_bignum(&auth->identities, e);
buffer_get_bignum(&auth->identities, n); buffer_get_bignum(&auth->identities, n);
@ -214,11 +231,13 @@ ssh_get_next_identity(AuthenticationConnection *auth,
return 1; return 1;
} }
/* Generates a random challenge, sends it to the agent, and waits for response /*
from the agent. Returns true (non-zero) if the agent gave the correct * Generates a random challenge, sends it to the agent, and waits for
answer, zero otherwise. Response type selects the style of response * response from the agent. Returns true (non-zero) if the agent gave the
desired, with 0 corresponding to protocol version 1.0 (no longer supported) * correct answer, zero otherwise. Response type selects the style of
and 1 corresponding to protocol version 1.1. */ * response desired, with 0 corresponding to protocol version 1.0 (no longer
* supported) and 1 corresponding to protocol version 1.1.
*/
int int
ssh_decrypt_challenge(AuthenticationConnection *auth, ssh_decrypt_challenge(AuthenticationConnection *auth,
@ -259,8 +278,10 @@ error_cleanup:
buffer_free(&buffer); buffer_free(&buffer);
return 0; return 0;
} }
/* Wait for response from the agent. First read the length of the /*
response packet. */ * Wait for response from the agent. First read the length of the
* response packet.
*/
len = 4; len = 4;
while (len > 0) { while (len > 0) {
l = read(auth->fd, buf + 4 - len, len); l = read(auth->fd, buf + 4 - len, len);
@ -303,8 +324,10 @@ error_cleanup:
if (buf[0] != SSH_AGENT_RSA_RESPONSE) if (buf[0] != SSH_AGENT_RSA_RESPONSE)
fatal("Bad authentication response: %d", buf[0]); fatal("Bad authentication response: %d", buf[0]);
/* Get the response from the packet. This will abort with a fatal /*
error if the packet is corrupt. */ * Get the response from the packet. This will abort with a fatal
* error if the packet is corrupt.
*/
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
response[i] = buffer_get_char(&buffer); response[i] = buffer_get_char(&buffer);
@ -315,8 +338,10 @@ error_cleanup:
return 1; return 1;
} }
/* Adds an identity to the authentication server. This call is not meant to /*
be used by normal applications. */ * Adds an identity to the authentication server. This call is not meant to
* be used by normal applications.
*/
int int
ssh_add_identity(AuthenticationConnection *auth, ssh_add_identity(AuthenticationConnection *auth,
@ -401,8 +426,10 @@ error_cleanup:
return 0; return 0;
} }
/* Removes an identity from the authentication server. This call is not meant /*
to be used by normal applications. */ * Removes an identity from the authentication server. This call is not
* meant to be used by normal applications.
*/
int int
ssh_remove_identity(AuthenticationConnection *auth, RSA *key) ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
@ -431,8 +458,10 @@ error_cleanup:
buffer_free(&buffer); buffer_free(&buffer);
return 0; return 0;
} }
/* Wait for response from the agent. First read the length of the /*
response packet. */ * Wait for response from the agent. First read the length of the
* response packet.
*/
len = 4; len = 4;
while (len > 0) { while (len > 0) {
l = read(auth->fd, buf + 4 - len, len); l = read(auth->fd, buf + 4 - len, len);
@ -480,8 +509,10 @@ error_cleanup:
return 0; return 0;
} }
/* Removes all identities from the agent. This call is not meant /*
to be used by normal applications. */ * Removes all identities from the agent. This call is not meant to be used
* by normal applications.
*/
int int
ssh_remove_all_identities(AuthenticationConnection *auth) ssh_remove_all_identities(AuthenticationConnection *auth)
@ -499,8 +530,10 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
error("Error writing to authentication socket."); error("Error writing to authentication socket.");
return 0; return 0;
} }
/* Wait for response from the agent. First read the length of the /*
response packet. */ * Wait for response from the agent. First read the length of the
* response packet.
*/
len = 4; len = 4;
while (len > 0) { while (len > 0) {
l = read(auth->fd, buf + 4 - len, len); l = read(auth->fd, buf + 4 - len, len);

View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: authfd.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: authfd.h,v 1.4 1999/11/25 00:54:58 damien Exp $"); */
#ifndef AUTHFD_H #ifndef AUTHFD_H
#define AUTHFD_H #define AUTHFD_H
@ -40,33 +40,43 @@ typedef struct {
/* Returns the number of the authentication fd, or -1 if there is none. */ /* Returns the number of the authentication fd, or -1 if there is none. */
int ssh_get_authentication_socket(); int ssh_get_authentication_socket();
/* This should be called for any descriptor returned by /*
ssh_get_authentication_socket(). Depending on the way the descriptor was * This should be called for any descriptor returned by
obtained, this may close the descriptor. */ * ssh_get_authentication_socket(). Depending on the way the descriptor was
* obtained, this may close the descriptor.
*/
void ssh_close_authentication_socket(int authfd); void ssh_close_authentication_socket(int authfd);
/* Opens and connects a private socket for communication with the /*
authentication agent. Returns NULL if an error occurred and the * Opens and connects a private socket for communication with the
connection could not be opened. The connection should be closed by * authentication agent. Returns NULL if an error occurred and the
the caller by calling ssh_close_authentication_connection(). */ * connection could not be opened. The connection should be closed by the
* caller by calling ssh_close_authentication_connection().
*/
AuthenticationConnection *ssh_get_authentication_connection(); AuthenticationConnection *ssh_get_authentication_connection();
/* Closes the connection to the authentication agent and frees any associated /*
memory. */ * Closes the connection to the authentication agent and frees any associated
* memory.
*/
void ssh_close_authentication_connection(AuthenticationConnection * ac); void ssh_close_authentication_connection(AuthenticationConnection * ac);
/* Returns the first authentication identity held by the agent. /*
Returns true if an identity is available, 0 otherwise. * Returns the first authentication identity held by the agent. Returns true
The caller must initialize the integers before the call, and free the * if an identity is available, 0 otherwise. The caller must initialize the
comment after a successful call (before calling ssh_get_next_identity). */ * integers before the call, and free the comment after a successful call
* (before calling ssh_get_next_identity).
*/
int int
ssh_get_first_identity(AuthenticationConnection * connection, ssh_get_first_identity(AuthenticationConnection * connection,
BIGNUM * e, BIGNUM * n, char **comment); BIGNUM * e, BIGNUM * n, char **comment);
/* Returns the next authentication identity for the agent. Other functions /*
can be called between this and ssh_get_first_identity or two calls of this * Returns the next authentication identity for the agent. Other functions
function. This returns 0 if there are no more identities. The caller * can be called between this and ssh_get_first_identity or two calls of this
must free comment after a successful return. */ * function. This returns 0 if there are no more identities. The caller
* must free comment after a successful return.
*/
int int
ssh_get_next_identity(AuthenticationConnection * connection, ssh_get_next_identity(AuthenticationConnection * connection,
BIGNUM * e, BIGNUM * n, char **comment); BIGNUM * e, BIGNUM * n, char **comment);
@ -80,24 +90,30 @@ ssh_decrypt_challenge(AuthenticationConnection * auth,
unsigned int response_type, unsigned int response_type,
unsigned char response[16]); unsigned char response[16]);
/* Adds an identity to the authentication server. This call is not meant to /*
be used by normal applications. This returns true if the identity * Adds an identity to the authentication server. This call is not meant to
was successfully added. */ * be used by normal applications. This returns true if the identity was
int ssh_add_identity(AuthenticationConnection * connection, * successfully added.
RSA * key, const char *comment); */
int
ssh_add_identity(AuthenticationConnection * connection, RSA * key,
const char *comment);
/* Removes the identity from the authentication server. This call is /*
not meant to be used by normal applications. This returns true if the * Removes the identity from the authentication server. This call is not
identity was successfully added. */ * meant to be used by normal applications. This returns true if the
int ssh_remove_identity(AuthenticationConnection * connection, * identity was successfully added.
RSA * key); */
int ssh_remove_identity(AuthenticationConnection * connection, RSA * key);
/* Removes all identities from the authentication agent. This call is not /*
meant to be used by normal applications. This returns true if the * Removes all identities from the authentication agent. This call is not
operation was successful. */ * meant to be used by normal applications. This returns true if the
int ssh_remove_all_identities(AuthenticationConnection * connection); * operation was successful.
*/
int ssh_remove_all_identities(AuthenticationConnection * connection);
/* Closes the connection to the authentication agent. */ /* Closes the connection to the authentication agent. */
void ssh_close_authentication(AuthenticationConnection * connection); void ssh_close_authentication(AuthenticationConnection * connection);
#endif /* AUTHFD_H */ #endif /* AUTHFD_H */

View File

@ -15,7 +15,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: authfile.c,v 1.5 1999/11/25 00:54:58 damien Exp $");
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/bn.h> #include <openssl/bn.h>
@ -33,10 +33,12 @@ RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
/* Version identification string for identity files. */ /* Version identification string for identity files. */
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
/* Saves the authentication (private) key in a file, encrypting it with /*
passphrase. The identification of the file (lowest 64 bits of n) * Saves the authentication (private) key in a file, encrypting it with
will precede the key to provide identification of the key without * passphrase. The identification of the file (lowest 64 bits of n) will
needing a passphrase. */ * precede the key to provide identification of the key without needing a
* passphrase.
*/
int int
save_private_key(const char *filename, const char *passphrase, save_private_key(const char *filename, const char *passphrase,
@ -49,9 +51,10 @@ save_private_key(const char *filename, const char *passphrase,
int cipher_type; int cipher_type;
u_int32_t rand; u_int32_t rand;
/* If the passphrase is empty, use SSH_CIPHER_NONE to ease /*
converting to another cipher; otherwise use * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
SSH_AUTHFILE_CIPHER. */ * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
*/
if (strcmp(passphrase, "") == 0) if (strcmp(passphrase, "") == 0)
cipher_type = SSH_CIPHER_NONE; cipher_type = SSH_CIPHER_NONE;
else else
@ -68,9 +71,11 @@ save_private_key(const char *filename, const char *passphrase,
buf[3] = buf[1]; buf[3] = buf[1];
buffer_append(&buffer, buf, 4); buffer_append(&buffer, buf, 4);
/* Store the private key (n and e will not be stored because they /*
will be stored in plain text, and storing them also in * Store the private key (n and e will not be stored because they
encrypted format would just give known plaintext). */ * will be stored in plain text, and storing them also in encrypted
* format would just give known plaintext).
*/
buffer_put_bignum(&buffer, key->d); buffer_put_bignum(&buffer, key->d);
buffer_put_bignum(&buffer, key->iqmp); buffer_put_bignum(&buffer, key->iqmp);
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
@ -112,11 +117,9 @@ save_private_key(const char *filename, const char *passphrase,
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
buffer_free(&buffer); buffer_free(&buffer);
/* Write to a file. */
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (f < 0) if (f < 0)
return 0; return 0;
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) != if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) { buffer_len(&encrypted)) {
debug("Write to key file %.200s failed: %.100s", filename, debug("Write to key file %.200s failed: %.100s", filename,
@ -131,9 +134,11 @@ save_private_key(const char *filename, const char *passphrase,
return 1; return 1;
} }
/* Loads the public part of the key file. Returns 0 if an error /*
was encountered (the file does not exist or is not readable), and * Loads the public part of the key file. Returns 0 if an error was
non-zero otherwise. */ * encountered (the file does not exist or is not readable), and non-zero
* otherwise.
*/
int int
load_public_key(const char *filename, RSA * pub, load_public_key(const char *filename, RSA * pub,
@ -144,11 +149,9 @@ load_public_key(const char *filename, RSA * pub,
Buffer buffer; Buffer buffer;
char *cp; char *cp;
/* Read data from the file into the buffer. */
f = open(filename, O_RDONLY); f = open(filename, O_RDONLY);
if (f < 0) if (f < 0)
return 0; return 0;
len = lseek(f, (off_t) 0, SEEK_END); len = lseek(f, (off_t) 0, SEEK_END);
lseek(f, (off_t) 0, SEEK_SET); lseek(f, (off_t) 0, SEEK_SET);
@ -170,8 +173,10 @@ load_public_key(const char *filename, RSA * pub,
buffer_free(&buffer); buffer_free(&buffer);
return 0; return 0;
} }
/* Make sure it begins with the id string. Consume the id string /*
from the buffer. */ * Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
debug("Bad key file %.200s.", filename); debug("Bad key file %.200s.", filename);
@ -197,9 +202,12 @@ load_public_key(const char *filename, RSA * pub,
return 1; return 1;
} }
/* Loads the private key from the file. Returns 0 if an error is encountered /*
(file does not exist or is not readable, or passphrase is bad). * Loads the private key from the file. Returns 0 if an error is encountered
This initializes the private key. */ * (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key.
* Assumes we are called under uid of the owner of the file.
*/
int int
load_private_key(const char *filename, const char *passphrase, load_private_key(const char *filename, const char *passphrase,
@ -214,12 +222,11 @@ load_private_key(const char *filename, const char *passphrase,
BIGNUM *aux; BIGNUM *aux;
struct stat st; struct stat st;
/* Read the file into the buffer. */
f = open(filename, O_RDONLY); f = open(filename, O_RDONLY);
if (f < 0) if (f < 0)
return 0; return 0;
/* We assume we are called under uid of the owner of the file */ /* check owner and modes */
if (fstat(f, &st) < 0 || if (fstat(f, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) || (st.st_uid != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) { (st.st_mode & 077) != 0) {
@ -252,8 +259,10 @@ load_private_key(const char *filename, const char *passphrase,
buffer_free(&buffer); buffer_free(&buffer);
return 0; return 0;
} }
/* Make sure it begins with the id string. Consume the id string /*
from the buffer. */ * Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
debug("Bad key file %.200s.", filename); debug("Bad key file %.200s.", filename);

View File

@ -15,7 +15,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: bufaux.c,v 1.6 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: bufaux.c,v 1.7 1999/11/25 00:54:58 damien Exp $");
#include "ssh.h" #include "ssh.h"
@ -54,7 +54,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
buffer_append(buffer, msg, 2); buffer_append(buffer, msg, 2);
/* Store the binary data. */ /* Store the binary data. */
buffer_append(buffer, buf, oi); buffer_append(buffer, buf, oi);
/* Clear the temporary data. */
memset(buf, 0, bin_size); memset(buf, 0, bin_size);
xfree(buf); xfree(buf);
} }

View File

@ -11,15 +11,17 @@
* *
*/ */
/* RCSID("$Id: bufaux.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: bufaux.h,v 1.3 1999/11/25 00:54:58 damien Exp $"); */
#ifndef BUFAUX_H #ifndef BUFAUX_H
#define BUFAUX_H #define BUFAUX_H
#include "buffer.h" #include "buffer.h"
/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed /*
by (bits+7)/8 bytes of binary data, msb first. */ * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
* by (bits+7)/8 bytes of binary data, msb first.
*/
void buffer_put_bignum(Buffer * buffer, BIGNUM * value); void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
/* Retrieves an BIGNUM from the buffer. */ /* Retrieves an BIGNUM from the buffer. */
@ -37,12 +39,14 @@ int buffer_get_char(Buffer * buffer);
/* Stores a character in the buffer. */ /* Stores a character in the buffer. */
void buffer_put_char(Buffer * buffer, int value); void buffer_put_char(Buffer * buffer, int value);
/* Returns an arbitrary binary string from the buffer. The string cannot /*
be longer than 256k. The returned value points to memory allocated * Returns an arbitrary binary string from the buffer. The string cannot be
with xmalloc; it is the responsibility of the calling function to free * longer than 256k. The returned value points to memory allocated with
the data. If length_ptr is non-NULL, the length of the returned data * xmalloc; it is the responsibility of the calling function to free the
will be stored there. A null character will be automatically appended * data. If length_ptr is non-NULL, the length of the returned data will be
to the returned string, and is not counted in length. */ * stored there. A null character will be automatically appended to the
* returned string, and is not counted in length.
*/
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr); char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
/* Stores and arbitrary binary string in the buffer. */ /* Stores and arbitrary binary string in the buffer. */

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: buffer.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: buffer.c,v 1.3 1999/11/25 00:54:58 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "buffer.h" #include "buffer.h"
@ -40,8 +40,10 @@ buffer_free(Buffer *buffer)
xfree(buffer->buf); xfree(buffer->buf);
} }
/* Clears any data from the buffer, making it empty. This does not actually /*
zero the memory. */ * Clears any data from the buffer, making it empty. This does not actually
* zero the memory.
*/
void void
buffer_clear(Buffer *buffer) buffer_clear(Buffer *buffer)
@ -60,9 +62,11 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
memcpy(cp, data, len); memcpy(cp, data, len);
} }
/* Appends space to the buffer, expanding the buffer if necessary. /*
This does not actually copy the data into the buffer, but instead * Appends space to the buffer, expanding the buffer if necessary. This does
returns a pointer to the allocated region. */ * not actually copy the data into the buffer, but instead returns a pointer
* to the allocated region.
*/
void void
buffer_append_space(Buffer *buffer, char **datap, unsigned int len) buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
@ -79,8 +83,10 @@ restart:
buffer->end += len; buffer->end += len;
return; return;
} }
/* If the buffer is quite empty, but all data is at the end, move /*
the data to the beginning and retry. */ * If the buffer is quite empty, but all data is at the end, move the
* data to the beginning and retry.
*/
if (buffer->offset > buffer->alloc / 2) { if (buffer->offset > buffer->alloc / 2) {
memmove(buffer->buf, buffer->buf + buffer->offset, memmove(buffer->buf, buffer->buf + buffer->offset,
buffer->end - buffer->offset); buffer->end - buffer->offset);

View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: buffer.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: buffer.h,v 1.3 1999/11/25 00:54:58 damien Exp $"); */
#ifndef BUFFER_H #ifndef BUFFER_H
#define BUFFER_H #define BUFFER_H
@ -37,9 +37,11 @@ void buffer_clear(Buffer * buffer);
/* Appends data to the buffer, expanding it if necessary. */ /* Appends data to the buffer, expanding it if necessary. */
void buffer_append(Buffer * buffer, const char *data, unsigned int len); void buffer_append(Buffer * buffer, const char *data, unsigned int len);
/* Appends space to the buffer, expanding the buffer if necessary. /*
This does not actually copy the data into the buffer, but instead * Appends space to the buffer, expanding the buffer if necessary. This does
returns a pointer to the allocated region. */ * not actually copy the data into the buffer, but instead returns a pointer
* to the allocated region.
*/
void buffer_append_space(Buffer * buffer, char **datap, unsigned int len); void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
/* Returns the number of bytes of data in the buffer. */ /* Returns the number of bytes of data in the buffer. */
@ -57,8 +59,10 @@ void buffer_consume_end(Buffer * buffer, unsigned int bytes);
/* Returns a pointer to the first used byte in the buffer. */ /* Returns a pointer to the first used byte in the buffer. */
char *buffer_ptr(Buffer * buffer); char *buffer_ptr(Buffer * buffer);
/* Dumps the contents of the buffer to stderr in hex. This intended for /*
debugging purposes only. */ * Dumps the contents of the buffer to stderr in hex. This intended for
* debugging purposes only.
*/
void buffer_dump(Buffer * buffer); void buffer_dump(Buffer * buffer);
#endif /* BUFFER_H */ #endif /* BUFFER_H */

View File

@ -14,14 +14,16 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: canohost.c,v 1.3 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: canohost.c,v 1.4 1999/11/25 00:54:58 damien Exp $");
#include "packet.h" #include "packet.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
/* Return the canonical name of the host at the other end of the socket. /*
The caller should free the returned string with xfree. */ * Return the canonical name of the host at the other end of the socket. The
* caller should free the returned string with xfree.
*/
char * char *
get_remote_hostname(int socket) get_remote_hostname(int socket)
@ -52,19 +54,23 @@ get_remote_hostname(int socket)
else else
strlcpy(name, hp->h_name, sizeof(name)); strlcpy(name, hp->h_name, sizeof(name));
/* Convert it to all lowercase (which is expected by the /*
rest of this software). */ * Convert it to all lowercase (which is expected by the rest
* of this software).
*/
for (i = 0; name[i]; i++) for (i = 0; name[i]; i++)
if (isupper(name[i])) if (isupper(name[i]))
name[i] = tolower(name[i]); name[i] = tolower(name[i]);
/* Map it back to an IP address and check that the given /*
address actually is an address of this host. This is * Map it back to an IP address and check that the given
necessary because anyone with access to a name server * address actually is an address of this host. This is
can define arbitrary names for an IP address. Mapping * necessary because anyone with access to a name server can
from name to IP address can be trusted better (but can * define arbitrary names for an IP address. Mapping from
still be fooled if the intruder has access to the name * name to IP address can be trusted better (but can still be
server of the domain). */ * fooled if the intruder has access to the name server of
* the domain).
*/
hp = gethostbyname(name); hp = gethostbyname(name);
if (!hp) { if (!hp) {
log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
@ -76,8 +82,10 @@ get_remote_hostname(int socket)
if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
== 0) == 0)
break; break;
/* If we reached the end of the list, the address was not /*
there. */ * If we reached the end of the list, the address was not
* there.
*/
if (!hp->h_addr_list[i]) { if (!hp->h_addr_list[i]) {
/* Address not found for the host name. */ /* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
@ -94,16 +102,17 @@ get_remote_hostname(int socket)
check_ip_options: check_ip_options:
/* If IP options are supported, make sure there are none (log and /*
disconnect them if any are found). Basically we are worried * If IP options are supported, make sure there are none (log and
about source routing; it can be used to pretend you are * disconnect them if any are found). Basically we are worried about
somebody (ip-address) you are not. That itself may be "almost * source routing; it can be used to pretend you are somebody
acceptable" under certain circumstances, but rhosts * (ip-address) you are not. That itself may be "almost acceptable"
autentication is useless if source routing is accepted. Notice * under certain circumstances, but rhosts autentication is useless
also that if we just dropped source routing here, the other * if source routing is accepted. Notice also that if we just dropped
side could use IP spoofing to do rest of the interaction and * source routing here, the other side could use IP spoofing to do
could still bypass security. So we exit here if we detect any * rest of the interaction and could still bypass security. So we
IP options. */ * exit here if we detect any IP options.
*/
{ {
unsigned char options[200], *ucp; unsigned char options[200], *ucp;
char text[1024], *cp; char text[1024], *cp;
@ -134,9 +143,11 @@ check_ip_options:
static char *canonical_host_name = NULL; static char *canonical_host_name = NULL;
static char *canonical_host_ip = NULL; static char *canonical_host_ip = NULL;
/* Return the canonical name of the host in the other side of the current /*
connection. The host name is cached, so it is efficient to call this * Return the canonical name of the host in the other side of the current
several times. */ * connection. The host name is cached, so it is efficient to call this
* several times.
*/
const char * const char *
get_canonical_hostname() get_canonical_hostname()
@ -154,8 +165,10 @@ get_canonical_hostname()
return canonical_host_name; return canonical_host_name;
} }
/* Returns the IP-address of the remote host as a string. The returned /*
string need not be freed. */ * Returns the IP-address of the remote host as a string. The returned
* string need not be freed.
*/
const char * const char *
get_remote_ipaddr() get_remote_ipaddr()
@ -163,7 +176,7 @@ get_remote_ipaddr()
struct sockaddr_in from; struct sockaddr_in from;
int fromlen, socket; int fromlen, socket;
/* Check if we have previously retrieved this same name. */ /* Check whether we have chached the name. */
if (canonical_host_ip != NULL) if (canonical_host_ip != NULL)
return canonical_host_ip; return canonical_host_ip;
@ -215,8 +228,10 @@ get_remote_port()
{ {
int socket; int socket;
/* If the connection is not a socket, return 65535. This is /*
intentionally chosen to be an unprivileged port number. */ * If the connection is not a socket, return 65535. This is
* intentionally chosen to be an unprivileged port number.
*/
if (packet_get_connection_in() != packet_get_connection_out()) if (packet_get_connection_in() != packet_get_connection_out())
return 65535; return 65535;

View File

@ -16,7 +16,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: channels.c,v 1.8 1999/11/25 00:54:58 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "packet.h"
@ -37,17 +37,23 @@ RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
/* Max len of agent socket */ /* Max len of agent socket */
#define MAX_SOCKET_NAME 100 #define MAX_SOCKET_NAME 100
/* Pointer to an array containing all allocated channels. The array is /*
dynamically extended as needed. */ * Pointer to an array containing all allocated channels. The array is
* dynamically extended as needed.
*/
static Channel *channels = NULL; static Channel *channels = NULL;
/* Size of the channel array. All slots of the array must always be /*
initialized (at least the type field); unused slots are marked with * Size of the channel array. All slots of the array must always be
type SSH_CHANNEL_FREE. */ * initialized (at least the type field); unused slots are marked with type
* SSH_CHANNEL_FREE.
*/
static int channels_alloc = 0; static int channels_alloc = 0;
/* Maximum file descriptor value used in any of the channels. This is updated /*
in channel_allocate. */ * Maximum file descriptor value used in any of the channels. This is
* updated in channel_allocate.
*/
static int channel_max_fd_value = 0; static int channel_max_fd_value = 0;
/* Name and directory of socket for authentication agent forwarding. */ /* Name and directory of socket for authentication agent forwarding. */
@ -61,15 +67,19 @@ char *x11_saved_proto = NULL;
char *x11_saved_data = NULL; char *x11_saved_data = NULL;
unsigned int x11_saved_data_len = 0; unsigned int x11_saved_data_len = 0;
/* Fake X11 authentication data. This is what the server will be sending /*
us; we should replace any occurrences of this by the real data. */ * Fake X11 authentication data. This is what the server will be sending us;
* we should replace any occurrences of this by the real data.
*/
char *x11_fake_data = NULL; char *x11_fake_data = NULL;
unsigned int x11_fake_data_len; unsigned int x11_fake_data_len;
/* Data structure for storing which hosts are permitted for forward requests. /*
The local sides of any remote forwards are stored in this array to prevent * Data structure for storing which hosts are permitted for forward requests.
a corrupt remote server from accessing arbitrary TCP/IP ports on our * The local sides of any remote forwards are stored in this array to prevent
local network (which might be behind a firewall). */ * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
* network (which might be behind a firewall).
*/
typedef struct { typedef struct {
char *host; /* Host name. */ char *host; /* Host name. */
int port; /* Port number. */ int port; /* Port number. */
@ -79,9 +89,11 @@ typedef struct {
static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
/* Number of permitted host/port pairs in the array. */ /* Number of permitted host/port pairs in the array. */
static int num_permitted_opens = 0; static int num_permitted_opens = 0;
/* If this is true, all opens are permitted. This is the case on the /*
server on which we have to trust the client anyway, and the user could * If this is true, all opens are permitted. This is the case on the server
do anything after logging in anyway. */ * on which we have to trust the client anyway, and the user could do
* anything after logging in anyway.
*/
static int all_opens_permitted = 0; static int all_opens_permitted = 0;
/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */ /* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
@ -95,9 +107,11 @@ channel_set_options(int hostname_in_open)
have_hostname_in_open = hostname_in_open; have_hostname_in_open = hostname_in_open;
} }
/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually /*
called by the server, because the user could connect to any port anyway, * Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
and the server has no way to know but to trust the client anyway. */ * called by the server, because the user could connect to any port anyway,
* and the server has no way to know but to trust the client anyway.
*/
void void
channel_permit_all_opens() channel_permit_all_opens()
@ -105,8 +119,10 @@ channel_permit_all_opens()
all_opens_permitted = 1; all_opens_permitted = 1;
} }
/* Allocate a new channel object and set its type and socket. /*
This will cause remote_name to be freed. */ * Allocate a new channel object and set its type and socket. This will cause
* remote_name to be freed.
*/
int int
channel_allocate(int type, int sock, char *remote_name) channel_allocate(int type, int sock, char *remote_name)
@ -117,6 +133,7 @@ channel_allocate(int type, int sock, char *remote_name)
/* Update the maximum file descriptor value. */ /* Update the maximum file descriptor value. */
if (sock > channel_max_fd_value) if (sock > channel_max_fd_value)
channel_max_fd_value = sock; channel_max_fd_value = sock;
/* XXX set close-on-exec -markus */
/* Do initial allocation if this is the first call. */ /* Do initial allocation if this is the first call. */
if (channels_alloc == 0) { if (channels_alloc == 0) {
@ -124,9 +141,10 @@ channel_allocate(int type, int sock, char *remote_name)
channels = xmalloc(channels_alloc * sizeof(Channel)); channels = xmalloc(channels_alloc * sizeof(Channel));
for (i = 0; i < channels_alloc; i++) for (i = 0; i < channels_alloc; i++)
channels[i].type = SSH_CHANNEL_FREE; channels[i].type = SSH_CHANNEL_FREE;
/*
/* Kludge: arrange a call to channel_stop_listening if we * Kludge: arrange a call to channel_stop_listening if we
terminate with fatal(). */ * terminate with fatal().
*/
fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL); fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
} }
/* Try to find a free slot where to put the new channel. */ /* Try to find a free slot where to put the new channel. */
@ -137,8 +155,7 @@ channel_allocate(int type, int sock, char *remote_name)
break; break;
} }
if (found == -1) { if (found == -1) {
/* There are no free slots. Take last+1 slot and expand /* There are no free slots. Take last+1 slot and expand the array. */
the array. */
found = channels_alloc; found = channels_alloc;
channels_alloc += 10; channels_alloc += 10;
debug("channel: expanding %d", channels_alloc); debug("channel: expanding %d", channels_alloc);
@ -181,8 +198,10 @@ channel_free(int channel)
} }
} }
/* This is called just before select() to add any bits relevant to /*
channels in the select bitmasks. */ * This is called just before select() to add any bits relevant to channels
* in the select bitmasks.
*/
void void
channel_prepare_select(fd_set * readset, fd_set * writeset) channel_prepare_select(fd_set * readset, fd_set * writeset)
@ -248,15 +267,16 @@ redo:
break; break;
case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_X11_OPEN:
/* This is a special state for X11 authentication /*
spoofing. An opened X11 connection (when * This is a special state for X11 authentication
authentication spoofing is being done) remains * spoofing. An opened X11 connection (when
in this state until the first packet has been * authentication spoofing is being done) remains in
completely read. The authentication data in * this state until the first packet has been
that packet is then substituted by the real * completely read. The authentication data in that
data if it matches the fake data, and the * packet is then substituted by the real data if it
channel is put into normal mode. */ * matches the fake data, and the channel is put into
* normal mode.
*/
/* Check if the fixed size part of the packet is in buffer. */ /* Check if the fixed size part of the packet is in buffer. */
if (buffer_len(&ch->output) < 12) if (buffer_len(&ch->output) < 12)
break; break;
@ -303,9 +323,11 @@ redo:
ch->type = SSH_CHANNEL_OPEN; ch->type = SSH_CHANNEL_OPEN;
goto reject; goto reject;
} }
/* Received authentication protocol and data match /*
our fake data. Substitute the fake data with * Received authentication protocol and data match
real data. */ * our fake data. Substitute the fake data with real
* data.
*/
memcpy(ucp + 12 + ((proto_len + 3) & ~3), memcpy(ucp + 12 + ((proto_len + 3) & ~3),
x11_saved_data, x11_saved_data_len); x11_saved_data, x11_saved_data_len);
@ -314,8 +336,10 @@ redo:
goto redo; goto redo;
reject: reject:
/* We have received an X11 connection that has bad /*
authentication information. */ * We have received an X11 connection that has bad
* authentication information.
*/
log("X11 connection rejected because of wrong authentication.\r\n"); log("X11 connection rejected because of wrong authentication.\r\n");
buffer_clear(&ch->input); buffer_clear(&ch->input);
buffer_clear(&ch->output); buffer_clear(&ch->output);
@ -341,8 +365,10 @@ redo:
} }
} }
/* After select, perform any appropriate operations for channels which /*
have events pending. */ * After select, perform any appropriate operations for channels which have
* events pending.
*/
void void
channel_after_select(fd_set * readset, fd_set * writeset) channel_after_select(fd_set * readset, fd_set * writeset)
@ -381,8 +407,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
break; break;
case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_PORT_LISTENER:
/* This socket is listening for connections to a /*
forwarded TCP/IP port. */ * This socket is listening for connections to a
* forwarded TCP/IP port.
*/
if (FD_ISSET(ch->sock, readset)) { if (FD_ISSET(ch->sock, readset)) {
debug("Connection to port %d forwarding to %.100s:%d requested.", debug("Connection to port %d forwarding to %.100s:%d requested.",
ch->listening_port, ch->path, ch->host_port); ch->listening_port, ch->path, ch->host_port);
@ -410,8 +438,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
break; break;
case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_AUTH_SOCKET:
/* This is the authentication agent socket /*
listening for connections from clients. */ * This is the authentication agent socket listening
* for connections from clients.
*/
if (FD_ISSET(ch->sock, readset)) { if (FD_ISSET(ch->sock, readset)) {
int nchan; int nchan;
len = sizeof(addr); len = sizeof(addr);
@ -429,13 +459,16 @@ channel_after_select(fd_set * readset, fd_set * writeset)
break; break;
case SSH_CHANNEL_OPEN: case SSH_CHANNEL_OPEN:
/* This is an open two-way communication channel. /*
It is not of interest to us at this point what * This is an open two-way communication channel. It
kind of data is being transmitted. */ * is not of interest to us at this point what kind
* of data is being transmitted.
*/
/* Read available incoming data and append it to /*
buffer; shutdown socket, if read or write * Read available incoming data and append it to
failes */ * buffer; shutdown socket, if read or write failes
*/
if (FD_ISSET(ch->sock, readset)) { if (FD_ISSET(ch->sock, readset)) {
len = read(ch->sock, buf, sizeof(buf)); len = read(ch->sock, buf, sizeof(buf));
if (len <= 0) { if (len <= 0) {
@ -500,8 +533,7 @@ channel_output_poll()
for (i = 0; i < channels_alloc; i++) { for (i = 0; i < channels_alloc; i++) {
ch = &channels[i]; ch = &channels[i];
/* We are only interested in channels that can have /* We are only interested in channels that can have buffered incoming data. */
buffered incoming data. */
if (ch->type != SSH_CHANNEL_OPEN && if (ch->type != SSH_CHANNEL_OPEN &&
ch->type != SSH_CHANNEL_INPUT_DRAINING) ch->type != SSH_CHANNEL_INPUT_DRAINING)
continue; continue;
@ -509,8 +541,7 @@ channel_output_poll()
/* Get the amount of buffered data for this channel. */ /* Get the amount of buffered data for this channel. */
len = buffer_len(&ch->input); len = buffer_len(&ch->input);
if (len > 0) { if (len > 0) {
/* Send some data for the other side over the /* Send some data for the other side over the secure connection. */
secure connection. */
if (packet_is_interactive()) { if (packet_is_interactive()) {
if (len > 1024) if (len > 1024)
len = 512; len = 512;
@ -527,17 +558,20 @@ channel_output_poll()
} else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) { } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
if (compat13) if (compat13)
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
/* input-buffer is empty and read-socket shutdown: /*
tell peer, that we will not send more data: * input-buffer is empty and read-socket shutdown:
send IEOF */ * tell peer, that we will not send more data: send IEOF
*/
chan_ibuf_empty(ch); chan_ibuf_empty(ch);
} }
} }
} }
/* This is called when a packet of type CHANNEL_DATA has just been received. /*
The message type has already been consumed, but channel number and data * This is called when a packet of type CHANNEL_DATA has just been received.
is still there. */ * The message type has already been consumed, but channel number and data is
* still there.
*/
void void
channel_input_data(int payload_len) channel_input_data(int payload_len)
@ -564,8 +598,10 @@ channel_input_data(int payload_len)
xfree(data); xfree(data);
} }
/* Returns true if no channel has too much buffered data, and false if /*
one or more channel is overfull. */ * Returns true if no channel has too much buffered data, and false if one or
* more channel is overfull.
*/
int int
channel_not_very_much_buffered_data() channel_not_very_much_buffered_data()
@ -615,20 +651,27 @@ channel_input_close()
chan_rcvd_ieof(&channels[channel]); chan_rcvd_ieof(&channels[channel]);
return; return;
} }
/* Send a confirmation that we have closed the channel and no more
data is coming for it. */ /*
* Send a confirmation that we have closed the channel and no more
* data is coming for it.
*/
packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
packet_put_int(channels[channel].remote_id); packet_put_int(channels[channel].remote_id);
packet_send(); packet_send();
/* If the channel is in closed state, we have sent a close /*
request, and the other side will eventually respond with a * If the channel is in closed state, we have sent a close request,
confirmation. Thus, we cannot free the channel here, because * and the other side will eventually respond with a confirmation.
then there would be no-one to receive the confirmation. The * Thus, we cannot free the channel here, because then there would be
channel gets freed when the confirmation arrives. */ * no-one to receive the confirmation. The channel gets freed when
* the confirmation arrives.
*/
if (channels[channel].type != SSH_CHANNEL_CLOSED) { if (channels[channel].type != SSH_CHANNEL_CLOSED) {
/* Not a closed channel - mark it as draining, which will /*
cause it to be freed later. */ * Not a closed channel - mark it as draining, which will
* cause it to be freed later.
*/
buffer_consume(&channels[channel].input, buffer_consume(&channels[channel].input,
buffer_len(&channels[channel].input)); buffer_len(&channels[channel].input));
channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING; channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
@ -678,8 +721,7 @@ channel_input_open_confirmation()
/* Get remote side's id for this channel. */ /* Get remote side's id for this channel. */
remote_channel = packet_get_int(); remote_channel = packet_get_int();
/* Record the remote channel number and mark that the channel is /* Record the remote channel number and mark that the channel is now open. */
now open. */
channels[channel].remote_id = remote_channel; channels[channel].remote_id = remote_channel;
channels[channel].type = SSH_CHANNEL_OPEN; channels[channel].type = SSH_CHANNEL_OPEN;
} }
@ -702,8 +744,10 @@ channel_input_open_failure()
channel_free(channel); channel_free(channel);
} }
/* Stops listening for channels, and removes any unix domain sockets that /*
we might have. */ * Stops listening for channels, and removes any unix domain sockets that we
* might have.
*/
void void
channel_stop_listening() channel_stop_listening()
@ -727,8 +771,10 @@ channel_stop_listening()
} }
} }
/* Closes the sockets of all channels. This is used to close extra file /*
descriptors after a fork. */ * Closes the sockets of all channels. This is used to close extra file
* descriptors after a fork.
*/
void void
channel_close_all() channel_close_all()
@ -778,9 +824,11 @@ channel_still_open()
return 0; return 0;
} }
/* Returns a message describing the currently open forwarded /*
connections, suitable for sending to the client. The message * Returns a message describing the currently open forwarded connections,
contains crlf pairs for newlines. */ * suitable for sending to the client. The message contains crlf pairs for
* newlines.
*/
char * char *
channel_open_message() channel_open_message()
@ -822,16 +870,19 @@ channel_open_message()
return cp; return cp;
} }
/* Initiate forwarding of connections to local port "port" through the secure /*
channel to host:port from remote side. */ * Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side.
*/
void void
channel_request_local_forwarding(int port, const char *host, channel_request_local_forwarding(int port, const char *host,
int host_port) int host_port)
{ {
int ch, sock; int ch, sock, on = 1;
struct sockaddr_in sin; struct sockaddr_in sin;
extern Options options; extern Options options;
struct linger linger;
if (strlen(host) > sizeof(channels[0].path) - 1) if (strlen(host) > sizeof(channels[0].path) - 1)
packet_disconnect("Forward host name too long."); packet_disconnect("Forward host name too long.");
@ -850,6 +901,15 @@ channel_request_local_forwarding(int port, const char *host,
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = htons(port); sin.sin_port = htons(port);
/*
* Set socket options. We would like the socket to disappear as soon
* as it has been closed for whatever reason.
*/
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
/* Bind the socket to the address. */ /* Bind the socket to the address. */
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
packet_disconnect("bind: %.100s", strerror(errno)); packet_disconnect("bind: %.100s", strerror(errno));
@ -866,8 +926,10 @@ channel_request_local_forwarding(int port, const char *host,
channels[ch].listening_port = port; channels[ch].listening_port = port;
} }
/* Initiate forwarding of connections to port "port" on remote host through /*
the secure channel to host:port from local side. */ * Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side.
*/
void void
channel_request_remote_forwarding(int port, const char *host, channel_request_remote_forwarding(int port, const char *host,
@ -890,15 +952,18 @@ channel_request_remote_forwarding(int port, const char *host,
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
/* Wait for response from the remote side. It will send a /*
disconnect message on failure, and we will never see it here. */ * Wait for response from the remote side. It will send a disconnect
* message on failure, and we will never see it here.
*/
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
} }
/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates /*
listening for the port, and sends back a success reply (or disconnect * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
message if there was an error). This never returns if there was an * listening for the port, and sends back a success reply (or disconnect
error. */ * message if there was an error). This never returns if there was an error.
*/
void void
channel_input_port_forward_request(int is_root) channel_input_port_forward_request(int is_root)
@ -915,8 +980,10 @@ channel_input_port_forward_request(int is_root)
if ((port & 0xffff) != port) if ((port & 0xffff) != port)
packet_disconnect("Requested forwarding of nonexistent port %d.", port); packet_disconnect("Requested forwarding of nonexistent port %d.", port);
/* Check that an unprivileged user is not trying to forward a /*
privileged port. */ * Check that an unprivileged user is not trying to forward a
* privileged port.
*/
if (port < IPPORT_RESERVED && !is_root) if (port < IPPORT_RESERVED && !is_root)
packet_disconnect("Requested forwarding of port %d but user is not root.", packet_disconnect("Requested forwarding of port %d but user is not root.",
port); port);
@ -928,9 +995,11 @@ channel_input_port_forward_request(int is_root)
xfree(hostname); xfree(hostname);
} }
/* This is called after receiving PORT_OPEN message. This attempts to connect /*
to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or * This is called after receiving PORT_OPEN message. This attempts to
CHANNEL_OPEN_FAILURE. */ * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
* or CHANNEL_OPEN_FAILURE.
*/
void void
channel_input_port_open(int payload_len) channel_input_port_open(int payload_len)
@ -951,13 +1020,16 @@ channel_input_port_open(int payload_len)
host_port = packet_get_int(); host_port = packet_get_int();
/* Get remote originator name. */ /* Get remote originator name. */
if (have_hostname_in_open) if (have_hostname_in_open) {
originator_string = packet_get_string(&originator_len); originator_string = packet_get_string(&originator_len);
else originator_len += 4; /* size of packet_int */
} else {
originator_string = xstrdup("unknown (remote did not supply name)"); originator_string = xstrdup("unknown (remote did not supply name)");
originator_len = 0; /* no originator supplied */
}
packet_integrity_check(payload_len, packet_integrity_check(payload_len,
4 + 4 + host_len + 4 + 4 + originator_len, 4 + 4 + host_len + 4 + originator_len,
SSH_MSG_PORT_OPEN); SSH_MSG_PORT_OPEN);
/* Check if opening that port is permitted. */ /* Check if opening that port is permitted. */
@ -1040,9 +1112,11 @@ fail:
packet_send(); packet_send();
} }
/* Creates an internet domain socket for listening for X11 connections. /*
Returns a suitable value for the DISPLAY variable, or NULL if an error * Creates an internet domain socket for listening for X11 connections.
occurs. */ * Returns a suitable value for the DISPLAY variable, or NULL if an error
* occurs.
*/
char * char *
x11_create_display_inet(int screen_number) x11_create_display_inet(int screen_number)
@ -1134,9 +1208,11 @@ connect_local_xsocket(unsigned dnr)
} }
/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains /*
the remote channel number. We should do whatever we want, and respond * This is called when SSH_SMSG_X11_OPEN is received. The packet contains
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ * the remote channel number. We should do whatever we want, and respond
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
*/
void void
x11_input_open(int payload_len) x11_input_open(int payload_len)
@ -1152,13 +1228,16 @@ x11_input_open(int payload_len)
remote_channel = packet_get_int(); remote_channel = packet_get_int();
/* Get remote originator name. */ /* Get remote originator name. */
if (have_hostname_in_open) if (have_hostname_in_open) {
remote_host = packet_get_string(&remote_len); remote_host = packet_get_string(&remote_len);
else remote_len += 4;
} else {
remote_host = xstrdup("unknown (remote did not supply name)"); remote_host = xstrdup("unknown (remote did not supply name)");
remote_len = 0;
}
debug("Received X11 open request."); debug("Received X11 open request.");
packet_integrity_check(payload_len, 4 + 4 + remote_len, SSH_SMSG_X11_OPEN); packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN);
/* Try to open a socket for the local X server. */ /* Try to open a socket for the local X server. */
display = getenv("DISPLAY"); display = getenv("DISPLAY");
@ -1166,11 +1245,15 @@ x11_input_open(int payload_len)
error("DISPLAY not set."); error("DISPLAY not set.");
goto fail; goto fail;
} }
/* Now we decode the value of the DISPLAY variable and make a /*
connection to the real X server. */ * Now we decode the value of the DISPLAY variable and make a
* connection to the real X server.
*/
/* Check if it is a unix domain socket. Unix domain displays are /*
in one of the following formats: unix:d[.s], :d[.s], ::d[.s] */ * Check if it is a unix domain socket. Unix domain displays are in
* one of the following formats: unix:d[.s], :d[.s], ::d[.s]
*/
if (strncmp(display, "unix:", 5) == 0 || if (strncmp(display, "unix:", 5) == 0 ||
display[0] == ':') { display[0] == ':') {
/* Connect to the unix domain socket. */ /* Connect to the unix domain socket. */
@ -1187,8 +1270,10 @@ x11_input_open(int payload_len)
/* OK, we now have a connection to the display. */ /* OK, we now have a connection to the display. */
goto success; goto success;
} }
/* Connect to an inet socket. The DISPLAY value is supposedly /*
hostname:d[.s], where hostname may also be numeric IP address. */ * Connect to an inet socket. The DISPLAY value is supposedly
* hostname:d[.s], where hostname may also be numeric IP address.
*/
strncpy(buf, display, sizeof(buf)); strncpy(buf, display, sizeof(buf));
buf[sizeof(buf) - 1] = 0; buf[sizeof(buf) - 1] = 0;
cp = strchr(buf, ':'); cp = strchr(buf, ':');
@ -1197,8 +1282,7 @@ x11_input_open(int payload_len)
goto fail; goto fail;
} }
*cp = 0; *cp = 0;
/* buf now contains the host name. But first we parse the display /* buf now contains the host name. But first we parse the display number. */
number. */
if (sscanf(cp + 1, "%d", &display_number) != 1) { if (sscanf(cp + 1, "%d", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s", error("Could not parse display number from DISPLAY: %.100s",
display); display);
@ -1267,8 +1351,10 @@ fail:
packet_send(); packet_send();
} }
/* Requests forwarding of X11 connections, generates fake authentication /*
data, and enables authentication spoofing. */ * Requests forwarding of X11 connections, generates fake authentication
* data, and enables authentication spoofing.
*/
void void
x11_request_forwarding_with_spoofing(const char *proto, const char *data) x11_request_forwarding_with_spoofing(const char *proto, const char *data)
@ -1293,8 +1379,10 @@ x11_request_forwarding_with_spoofing(const char *proto, const char *data)
/* Save protocol name. */ /* Save protocol name. */
x11_saved_proto = xstrdup(proto); x11_saved_proto = xstrdup(proto);
/* Extract real authentication data and generate fake data of the /*
same length. */ * Extract real authentication data and generate fake data of the
* same length.
*/
x11_saved_data = xmalloc(data_len); x11_saved_data = xmalloc(data_len);
x11_fake_data = xmalloc(data_len); x11_fake_data = xmalloc(data_len);
for (i = 0; i < data_len; i++) { for (i = 0; i < data_len; i++) {
@ -1334,9 +1422,11 @@ auth_request_forwarding()
packet_write_wait(); packet_write_wait();
} }
/* Returns the name of the forwarded authentication socket. Returns NULL /*
if there is no forwarded authentication socket. The returned value * Returns the name of the forwarded authentication socket. Returns NULL if
points to a static buffer. */ * there is no forwarded authentication socket. The returned value points to
* a static buffer.
*/
char * char *
auth_get_socket_name() auth_get_socket_name()
@ -1353,8 +1443,10 @@ cleanup_socket(void)
rmdir(channel_forwarded_auth_socket_dir); rmdir(channel_forwarded_auth_socket_dir);
} }
/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. /*
This starts forwarding authentication requests. */ * This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
* This starts forwarding authentication requests.
*/
void void
auth_input_request_forwarding(struct passwd * pw) auth_input_request_forwarding(struct passwd * pw)
@ -1422,14 +1514,18 @@ auth_input_open_request()
/* Read the remote channel number from the message. */ /* Read the remote channel number from the message. */
remch = packet_get_int(); remch = packet_get_int();
/* Get a connection to the local authentication agent (this may /*
again get forwarded). */ * Get a connection to the local authentication agent (this may again
* get forwarded).
*/
sock = ssh_get_authentication_socket(); sock = ssh_get_authentication_socket();
/* If we could not connect the agent, send an error message back /*
to the server. This should never happen unless the agent dies, * If we could not connect the agent, send an error message back to
because authentication forwarding is only enabled if we have an * the server. This should never happen unless the agent dies,
agent. */ * because authentication forwarding is only enabled if we have an
* agent.
*/
if (sock < 0) { if (sock < 0) {
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(remch); packet_put_int(remch);
@ -1438,9 +1534,11 @@ auth_input_open_request()
} }
debug("Forwarding authentication connection."); debug("Forwarding authentication connection.");
/* Dummy host name. This will be freed when the channel is freed; /*
it will still be valid in the packet_put_string below since the * Dummy host name. This will be freed when the channel is freed; it
channel cannot yet be freed at that point. */ * will still be valid in the packet_put_string below since the
* channel cannot yet be freed at that point.
*/
dummyname = xstrdup("authentication agent connection"); dummyname = xstrdup("authentication agent connection");
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);

View File

@ -1,29 +1,26 @@
/* RCSID("$Id: channels.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: channels.h,v 1.4 1999/11/25 00:54:58 damien Exp $"); */
#ifndef CHANNELS_H #ifndef CHANNELS_H
#define CHANNELS_H #define CHANNELS_H
/* Definitions for channel types. */ /* Definitions for channel types. */
#define SSH_CHANNEL_FREE 0 /* This channel is free #define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
* (unused). */ #define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11
* conn. */
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */ #define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ #define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ #define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
#define SSH_CHANNEL_CLOSED 5 /* waiting for close #define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
* confirmation */
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */ /* SSH_CHANNEL_AUTH_FD 6 authentication fd */
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ #define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */ /* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */ #define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to #define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
* conn */ #define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to
* app */
/* Data structure for channel data. This is iniailized in channel_allocate /*
and cleared in channel_free. */ * Data structure for channel data. This is iniailized in channel_allocate
* and cleared in channel_free.
*/
typedef struct Channel { typedef struct Channel {
int type; /* channel type/state */ int type; /* channel type/state */

View File

@ -12,7 +12,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: cipher.c,v 1.7 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: cipher.c,v 1.8 1999/11/25 00:54:58 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "cipher.h" #include "cipher.h"
@ -121,8 +121,10 @@ detect_cbc_attack(const unsigned char *src,
cipher_attack_detected("CRC-32 CBC insertion attack detected"); cipher_attack_detected("CRC-32 CBC insertion attack detected");
} }
/* Names of all encryption algorithms. These must match the numbers defined /*
int cipher.h. */ * Names of all encryption algorithms.
* These must match the numbers defined in cipher.h.
*/
static char *cipher_names[] = static char *cipher_names[] =
{ {
"none", "none",
@ -134,9 +136,11 @@ static char *cipher_names[] =
"blowfish" "blowfish"
}; };
/* Returns a bit mask indicating which ciphers are supported by this /*
implementation. The bit mask has the corresponding bit set of each * Returns a bit mask indicating which ciphers are supported by this
supported cipher. */ * implementation. The bit mask has the corresponding bit set of each
* supported cipher.
*/
unsigned int unsigned int
cipher_mask() cipher_mask()
@ -158,8 +162,10 @@ cipher_name(int cipher)
return cipher_names[cipher]; return cipher_names[cipher];
} }
/* Parses the name of the cipher. Returns the number of the corresponding /*
cipher, or -1 on error. */ * Parses the name of the cipher. Returns the number of the corresponding
* cipher, or -1 on error.
*/
int int
cipher_number(const char *name) cipher_number(const char *name)
@ -172,8 +178,10 @@ cipher_number(const char *name)
return -1; return -1;
} }
/* Selects the cipher, and keys if by computing the MD5 checksum of the /*
passphrase and using the resulting 16 bytes as the key. */ * Selects the cipher, and keys if by computing the MD5 checksum of the
* passphrase and using the resulting 16 bytes as the key.
*/
void void
cipher_set_key_string(CipherContext *context, int cipher, cipher_set_key_string(CipherContext *context, int cipher,
@ -211,15 +219,18 @@ cipher_set_key(CipherContext *context, int cipher,
/* Initialize the initialization vector. */ /* Initialize the initialization vector. */
switch (cipher) { switch (cipher) {
case SSH_CIPHER_NONE: case SSH_CIPHER_NONE:
/* Has to stay for authfile saving of private key with /*
no passphrase */ * Has to stay for authfile saving of private key with no
* passphrase
*/
break; break;
case SSH_CIPHER_3DES: case SSH_CIPHER_3DES:
/* Note: the least significant bit of each byte of key is /*
parity, and must be ignored by the implementation. 16 * Note: the least significant bit of each byte of key is
bytes of key are used (first and last keys are the * parity, and must be ignored by the implementation. 16
same). */ * bytes of key are used (first and last keys are the same).
*/
if (keylen < 16) if (keylen < 16)
error("Key length %d is insufficient for 3DES.", keylen); error("Key length %d is insufficient for 3DES.", keylen);
des_set_key((void *) padded, context->u.des3.key1); des_set_key((void *) padded, context->u.des3.key1);

View File

@ -11,7 +11,7 @@
* *
*/ */
/* RCSID("$Id: cipher.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: cipher.h,v 1.5 1999/11/25 00:54:58 damien Exp $"); */
#ifndef CIPHER_H #ifndef CIPHER_H
#define CIPHER_H #define CIPHER_H
@ -54,26 +54,34 @@ typedef struct {
} bf; } bf;
} u; } u;
} CipherContext; } CipherContext;
/* Returns a bit mask indicating which ciphers are supported by this /*
implementation. The bit mask has the corresponding bit set of each * Returns a bit mask indicating which ciphers are supported by this
supported cipher. */ * implementation. The bit mask has the corresponding bit set of each
* supported cipher.
*/
unsigned int cipher_mask(); unsigned int cipher_mask();
/* Returns the name of the cipher. */ /* Returns the name of the cipher. */
const char *cipher_name(int cipher); const char *cipher_name(int cipher);
/* Parses the name of the cipher. Returns the number of the corresponding /*
cipher, or -1 on error. */ * Parses the name of the cipher. Returns the number of the corresponding
* cipher, or -1 on error.
*/
int cipher_number(const char *name); int cipher_number(const char *name);
/* Selects the cipher to use and sets the key. If for_encryption is true, /*
the key is setup for encryption; otherwise it is setup for decryption. */ * Selects the cipher to use and sets the key. If for_encryption is true,
* the key is setup for encryption; otherwise it is setup for decryption.
*/
void void
cipher_set_key(CipherContext * context, int cipher, cipher_set_key(CipherContext * context, int cipher,
const unsigned char *key, int keylen, int for_encryption); const unsigned char *key, int keylen, int for_encryption);
/* Sets key for the cipher by computing the MD5 checksum of the passphrase, /*
and using the resulting 16 bytes as the key. */ * Sets key for the cipher by computing the MD5 checksum of the passphrase,
* and using the resulting 16 bytes as the key.
*/
void void
cipher_set_key_string(CipherContext * context, int cipher, cipher_set_key_string(CipherContext * context, int cipher,
const char *passphrase, int for_encryption); const char *passphrase, int for_encryption);
@ -88,8 +96,10 @@ void
cipher_decrypt(CipherContext * context, unsigned char *dest, cipher_decrypt(CipherContext * context, unsigned char *dest,
const unsigned char *src, unsigned int len); const unsigned char *src, unsigned int len);
/* If and CRC-32 attack is detected this function is called. Defaults /*
* to fatal, changed to packet_disconnect in sshd and ssh. */ * If and CRC-32 attack is detected this function is called. Defaults to
extern void (*cipher_attack_detected) (const char *fmt,...); * fatal, changed to packet_disconnect in sshd and ssh.
*/
extern void (*cipher_attack_detected) (const char *fmt, ...);
#endif /* CIPHER_H */ #endif /* CIPHER_H */

View File

@ -15,7 +15,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: clientloop.c,v 1.5 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: clientloop.c,v 1.6 1999/11/25 00:54:58 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -27,22 +27,28 @@ RCSID("$Id: clientloop.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
/* Flag indicating that stdin should be redirected from /dev/null. */ /* Flag indicating that stdin should be redirected from /dev/null. */
extern int stdin_null_flag; extern int stdin_null_flag;
/* Name of the host we are connecting to. This is the name given on the /*
command line, or the HostName specified for the user-supplied name * Name of the host we are connecting to. This is the name given on the
in a configuration file. */ * command line, or the HostName specified for the user-supplied name in a
* configuration file.
*/
extern char *host; extern char *host;
/* Flag to indicate that we have received a window change signal which has /*
not yet been processed. This will cause a message indicating the new * Flag to indicate that we have received a window change signal which has
window size to be sent to the server a little later. This is volatile * not yet been processed. This will cause a message indicating the new
because this is updated in a signal handler. */ * window size to be sent to the server a little later. This is volatile
* because this is updated in a signal handler.
*/
static volatile int received_window_change_signal = 0; static volatile int received_window_change_signal = 0;
/* Terminal modes, as saved by enter_raw_mode. */ /* Terminal modes, as saved by enter_raw_mode. */
static struct termios saved_tio; static struct termios saved_tio;
/* Flag indicating whether we are in raw mode. This is used by enter_raw_mode /*
and leave_raw_mode. */ * Flag indicating whether we are in raw mode. This is used by
* enter_raw_mode and leave_raw_mode.
*/
static int in_raw_mode = 0; static int in_raw_mode = 0;
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */ /* Flag indicating whether the user\'s terminal is in non-blocking mode. */
@ -64,8 +70,7 @@ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
static int quit_pending; /* Set to non-zero to quit the client loop. */ static int quit_pending; /* Set to non-zero to quit the client loop. */
static int escape_char; /* Escape character. */ static int escape_char; /* Escape character. */
/* Returns the user\'s terminal to normal mode if it had been put in raw /* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
mode. */
void void
leave_raw_mode() leave_raw_mode()
@ -127,8 +132,10 @@ enter_non_blocking()
fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL); fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
} }
/* Signal handler for the window change signal (SIGWINCH). This just /*
sets a flag indicating that the window has changed. */ * Signal handler for the window change signal (SIGWINCH). This just sets a
* flag indicating that the window has changed.
*/
void void
window_change_handler(int sig) window_change_handler(int sig)
@ -137,8 +144,10 @@ window_change_handler(int sig)
signal(SIGWINCH, window_change_handler); signal(SIGWINCH, window_change_handler);
} }
/* Signal handler for signals that cause the program to terminate. These /*
signals must be trapped to restore terminal modes. */ * Signal handler for signals that cause the program to terminate. These
* signals must be trapped to restore terminal modes.
*/
void void
signal_handler(int sig) signal_handler(int sig)
@ -152,8 +161,10 @@ signal_handler(int sig)
fatal("Killed by signal %d.", sig); fatal("Killed by signal %d.", sig);
} }
/* Returns current time in seconds from Jan 1, 1970 with the maximum available /*
resolution. */ * Returns current time in seconds from Jan 1, 1970 with the maximum
* available resolution.
*/
double double
get_current_time() get_current_time()
@ -163,9 +174,11 @@ get_current_time()
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
} }
/* This is called when the interactive is entered. This checks if there /*
is an EOF coming on stdin. We must check this explicitly, as select() * This is called when the interactive is entered. This checks if there is
does not appear to wake up when redirecting from /dev/null. */ * an EOF coming on stdin. We must check this explicitly, as select() does
* not appear to wake up when redirecting from /dev/null.
*/
void void
client_check_initial_eof_on_stdin() client_check_initial_eof_on_stdin()
@ -173,13 +186,14 @@ client_check_initial_eof_on_stdin()
int len; int len;
char buf[1]; char buf[1];
/* If standard input is to be "redirected from /dev/null", we /*
simply mark that we have seen an EOF and send an EOF message to * If standard input is to be "redirected from /dev/null", we simply
the server. Otherwise, we try to read a single character; it * mark that we have seen an EOF and send an EOF message to the
appears that for some files, such /dev/null, select() never * server. Otherwise, we try to read a single character; it appears
wakes up for read for this descriptor, which means that we * that for some files, such /dev/null, select() never wakes up for
never get EOF. This way we will get the EOF if stdin comes * read for this descriptor, which means that we never get EOF. This
from /dev/null or similar. */ * way we will get the EOF if stdin comes from /dev/null or similar.
*/
if (stdin_null_flag) { if (stdin_null_flag) {
/* Fake EOF on stdin. */ /* Fake EOF on stdin. */
debug("Sending eof."); debug("Sending eof.");
@ -187,22 +201,22 @@ client_check_initial_eof_on_stdin()
packet_start(SSH_CMSG_EOF); packet_start(SSH_CMSG_EOF);
packet_send(); packet_send();
} else { } else {
/* Enter non-blocking mode for stdin. */
enter_non_blocking(); enter_non_blocking();
/* Check for immediate EOF on stdin. */ /* Check for immediate EOF on stdin. */
len = read(fileno(stdin), buf, 1); len = read(fileno(stdin), buf, 1);
if (len == 0) { if (len == 0) {
/* EOF. Record that we have seen it and send EOF /* EOF. Record that we have seen it and send EOF to server. */
to server. */
debug("Sending eof."); debug("Sending eof.");
stdin_eof = 1; stdin_eof = 1;
packet_start(SSH_CMSG_EOF); packet_start(SSH_CMSG_EOF);
packet_send(); packet_send();
} else if (len > 0) { } else if (len > 0) {
/* Got data. We must store the data in the /*
buffer, and also process it as an escape * Got data. We must store the data in the buffer,
character if appropriate. */ * and also process it as an escape character if
* appropriate.
*/
if ((unsigned char) buf[0] == escape_char) if ((unsigned char) buf[0] == escape_char)
escape_pending = 1; escape_pending = 1;
else { else {
@ -210,13 +224,14 @@ client_check_initial_eof_on_stdin()
stdin_bytes += 1; stdin_bytes += 1;
} }
} }
/* Leave non-blocking mode. */
leave_non_blocking(); leave_non_blocking();
} }
} }
/* Get packets from the connection input buffer, and process them as long /*
as there are packets available. */ * Get packets from the connection input buffer, and process them as long as
* there are packets available.
*/
void void
client_process_buffered_input_packets() client_process_buffered_input_packets()
@ -255,8 +270,10 @@ client_process_buffered_input_packets()
/* Acknowledge the exit. */ /* Acknowledge the exit. */
packet_start(SSH_CMSG_EXIT_CONFIRMATION); packet_start(SSH_CMSG_EXIT_CONFIRMATION);
packet_send(); packet_send();
/* Must wait for packet to be sent since we are /*
exiting the loop. */ * Must wait for packet to be sent since we are
* exiting the loop.
*/
packet_write_wait(); packet_write_wait();
/* Flag that we want to exit. */ /* Flag that we want to exit. */
quit_pending = 1; quit_pending = 1;
@ -300,20 +317,24 @@ client_process_buffered_input_packets()
break; break;
default: default:
/* Any unknown packets received during the actual /*
session cause the session to terminate. This * Any unknown packets received during the actual
is intended to make debugging easier since no * session cause the session to terminate. This is
confirmations are sent. Any compatible * intended to make debugging easier since no
protocol extensions must be negotiated during * confirmations are sent. Any compatible protocol
the preparatory phase. */ * extensions must be negotiated during the
* preparatory phase.
*/
packet_disconnect("Protocol error during session: type %d", packet_disconnect("Protocol error during session: type %d",
type); type);
} }
} }
} }
/* Make packets from buffered stdin data, and buffer them for sending to /*
the connection. */ * Make packets from buffered stdin data, and buffer them for sending to the
* connection.
*/
void void
client_make_packets_from_stdin_data() client_make_packets_from_stdin_data()
@ -339,10 +360,12 @@ client_make_packets_from_stdin_data()
} }
} }
/* Checks if the client window has changed, and sends a packet about it to /*
the server if so. The actual change is detected elsewhere (by a software * Checks if the client window has changed, and sends a packet about it to
interrupt on Unix); this just checks the flag and sends a message if * the server if so. The actual change is detected elsewhere (by a software
appropriate. */ * interrupt on Unix); this just checks the flag and sends a message if
* appropriate.
*/
void void
client_check_window_change() client_check_window_change()
@ -367,8 +390,10 @@ client_check_window_change()
} }
} }
/* Waits until the client can do something (some data becomes available on /*
one of the file descriptors). */ * Waits until the client can do something (some data becomes available on
* one of the file descriptors).
*/
void void
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
@ -382,8 +407,10 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
channel_not_very_much_buffered_data()) channel_not_very_much_buffered_data())
FD_SET(connection_in, readset); FD_SET(connection_in, readset);
/* Read from stdin, unless we have seen EOF or have very much /*
buffered data to send to the server. */ * Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
if (!stdin_eof && packet_not_very_much_data_to_write()) if (!stdin_eof && packet_not_very_much_data_to_write())
FD_SET(fileno(stdin), readset); FD_SET(fileno(stdin), readset);
@ -408,13 +435,14 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
if (channel_max_fd() > max_fd) if (channel_max_fd() > max_fd)
max_fd = channel_max_fd(); max_fd = channel_max_fd();
/* Wait for something to happen. This will suspend the process /*
until some selected descriptor can be read, written, or has * Wait for something to happen. This will suspend the process until
some other event pending. * some selected descriptor can be read, written, or has some other
Note: if you want to implement SSH_MSG_IGNORE messages to fool * event pending. Note: if you want to implement SSH_MSG_IGNORE
traffic analysis, this might be the place to do it: * messages to fool traffic analysis, this might be the place to do
just have a random timeout for the select, and send a random * it: just have a random timeout for the select, and send a random
SSH_MSG_IGNORE packet when the timeout expires. */ * SSH_MSG_IGNORE packet when the timeout expires.
*/
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) { if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
char buf[100]; char buf[100];
@ -446,11 +474,12 @@ client_suspend_self()
buffer_ptr(&stderr_buffer), buffer_ptr(&stderr_buffer),
buffer_len(&stderr_buffer)); buffer_len(&stderr_buffer));
/* Leave raw mode. */
leave_raw_mode(); leave_raw_mode();
/* Free (and clear) the buffer to reduce the amount of data that /*
gets written to swap. */ * Free (and clear) the buffer to reduce the amount of data that gets
* written to swap.
*/
buffer_free(&stdin_buffer); buffer_free(&stdin_buffer);
buffer_free(&stdout_buffer); buffer_free(&stdout_buffer);
buffer_free(&stderr_buffer); buffer_free(&stderr_buffer);
@ -474,7 +503,6 @@ client_suspend_self()
buffer_init(&stdout_buffer); buffer_init(&stdout_buffer);
buffer_init(&stderr_buffer); buffer_init(&stderr_buffer);
/* Re-enter raw mode. */
enter_raw_mode(); enter_raw_mode();
} }
@ -484,8 +512,10 @@ client_process_input(fd_set * readset)
int len, pid; int len, pid;
char buf[8192], *s; char buf[8192], *s;
/* Read input from the server, and add any such data to the buffer /*
of the packet subsystem. */ * Read input from the server, and add any such data to the buffer of
* the packet subsystem.
*/
if (FD_ISSET(connection_in, readset)) { if (FD_ISSET(connection_in, readset)) {
/* Read as much as possible. */ /* Read as much as possible. */
len = read(connection_in, buf, sizeof(buf)); len = read(connection_in, buf, sizeof(buf));
@ -498,9 +528,10 @@ client_process_input(fd_set * readset)
quit_pending = 1; quit_pending = 1;
return; return;
} }
/* There is a kernel bug on Solaris that causes select to /*
sometimes wake up even though there is no data * There is a kernel bug on Solaris that causes select to
available. */ * sometimes wake up even though there is no data available.
*/
if (len < 0 && errno == EAGAIN) if (len < 0 && errno == EAGAIN)
len = 0; len = 0;
@ -520,9 +551,11 @@ client_process_input(fd_set * readset)
/* Read as much as possible. */ /* Read as much as possible. */
len = read(fileno(stdin), buf, sizeof(buf)); len = read(fileno(stdin), buf, sizeof(buf));
if (len <= 0) { if (len <= 0) {
/* Received EOF or error. They are treated /*
similarly, except that an error message is * Received EOF or error. They are treated
printed if it was an error condition. */ * similarly, except that an error message is printed
* if it was an error condition.
*/
if (len < 0) { if (len < 0) {
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf)); buffer_append(&stderr_buffer, buf, strlen(buf));
@ -530,32 +563,35 @@ client_process_input(fd_set * readset)
} }
/* Mark that we have seen EOF. */ /* Mark that we have seen EOF. */
stdin_eof = 1; stdin_eof = 1;
/* Send an EOF message to the server unless there /*
is data in the buffer. If there is data in the * Send an EOF message to the server unless there is
buffer, no message will be sent now. Code * data in the buffer. If there is data in the
elsewhere will send the EOF when the buffer * buffer, no message will be sent now. Code
becomes empty if stdin_eof is set. */ * elsewhere will send the EOF when the buffer
* becomes empty if stdin_eof is set.
*/
if (buffer_len(&stdin_buffer) == 0) { if (buffer_len(&stdin_buffer) == 0) {
packet_start(SSH_CMSG_EOF); packet_start(SSH_CMSG_EOF);
packet_send(); packet_send();
} }
} else if (escape_char == -1) { } else if (escape_char == -1) {
/* Normal successful read, and no escape /*
character. Just append the data to buffer. */ * Normal successful read, and no escape character.
* Just append the data to buffer.
*/
buffer_append(&stdin_buffer, buf, len); buffer_append(&stdin_buffer, buf, len);
stdin_bytes += len; stdin_bytes += len;
} else { } else {
/* Normal, successful read. But we have an escape /*
character and have to process the characters * Normal, successful read. But we have an escape character
one by one. */ * and have to process the characters one by one.
*/
unsigned int i; unsigned int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
unsigned char ch; unsigned char ch;
/* Get one character at a time. */ /* Get one character at a time. */
ch = buf[i]; ch = buf[i];
/* Check if we have a pending escape
character. */
if (escape_pending) { if (escape_pending) {
/* We have previously seen an escape character. */ /* We have previously seen an escape character. */
/* Clear the flag now. */ /* Clear the flag now. */
@ -584,12 +620,16 @@ client_process_input(fd_set * readset)
continue; continue;
case '&': case '&':
/* Detach the program (continue to serve connections, /*
but put in background and no more new connections). */ * Detach the program (continue to serve connections,
* but put in background and no more new connections).
*/
if (!stdin_eof) { if (!stdin_eof) {
/* Sending SSH_CMSG_EOF alone does not always appear /*
to be enough. So we try to send an EOF character * Sending SSH_CMSG_EOF alone does not always appear
first. */ * to be enough. So we try to send an EOF character
* first.
*/
packet_start(SSH_CMSG_STDIN_DATA); packet_start(SSH_CMSG_STDIN_DATA);
packet_put_string("\004", 1); packet_put_string("\004", 1);
packet_send(); packet_send();
@ -646,22 +686,28 @@ Supported escape sequences:\r\n\
default: default:
if (ch != escape_char) { if (ch != escape_char) {
/* Escape character followed by non-special character. /*
Append both to the input buffer. */ * Escape character followed by non-special character.
* Append both to the input buffer.
*/
buf[0] = escape_char; buf[0] = escape_char;
buf[1] = ch; buf[1] = ch;
buffer_append(&stdin_buffer, buf, 2); buffer_append(&stdin_buffer, buf, 2);
stdin_bytes += 2; stdin_bytes += 2;
continue; continue;
} }
/* Note that escape character typed twice /*
falls through here; the latter gets processed * Note that escape character typed twice
as a normal character below. */ * falls through here; the latter gets processed
* as a normal character below.
*/
break; break;
} }
} else { } else {
/* The previous character was not an escape char. Check if this /*
is an escape. */ * The previous character was not an escape char. Check if this
* is an escape.
*/
if (last_was_cr && ch == escape_char) { if (last_was_cr && ch == escape_char) {
/* It is. Set the flag and continue to next character. */ /* It is. Set the flag and continue to next character. */
escape_pending = 1; escape_pending = 1;
@ -669,8 +715,10 @@ Supported escape sequences:\r\n\
} }
} }
/* Normal character. Record whether it was a newline, and append it to the /*
buffer. */ * Normal character. Record whether it was a newline,
* and append it to the buffer.
*/
last_was_cr = (ch == '\r' || ch == '\n'); last_was_cr = (ch == '\r' || ch == '\n');
buf[0] = ch; buf[0] = ch;
buffer_append(&stdin_buffer, buf, 1); buffer_append(&stdin_buffer, buf, 1);
@ -696,8 +744,10 @@ client_process_output(fd_set * writeset)
if (errno == EAGAIN) if (errno == EAGAIN)
len = 0; len = 0;
else { else {
/* An error or EOF was encountered. Put /*
an error message to stderr buffer. */ * An error or EOF was encountered. Put an
* error message to stderr buffer.
*/
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf)); buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf); stderr_bytes += strlen(buf);
@ -717,8 +767,7 @@ client_process_output(fd_set * writeset)
if (errno == EAGAIN) if (errno == EAGAIN)
len = 0; len = 0;
else { else {
/* EOF or error, but can't even print /* EOF or error, but can't even print error message. */
error message. */
quit_pending = 1; quit_pending = 1;
return; return;
} }
@ -728,11 +777,12 @@ client_process_output(fd_set * writeset)
} }
} }
/* Implements the interactive session with the server. This is called /*
after the user has been authenticated, and a command has been * Implements the interactive session with the server. This is called after
started on the remote host. If escape_char != -1, it is the character * the user has been authenticated, and a command has been started on the
used as an escape character for terminating or suspending the * remote host. If escape_char != -1, it is the character used as an escape
session. */ * character for terminating or suspending the session.
*/
int int
client_loop(int have_pty, int escape_char_arg) client_loop(int have_pty, int escape_char_arg)
@ -776,7 +826,6 @@ client_loop(int have_pty, int escape_char_arg)
if (have_pty) if (have_pty)
signal(SIGWINCH, window_change_handler); signal(SIGWINCH, window_change_handler);
/* Enter raw mode if have a pseudo terminal. */
if (have_pty) if (have_pty)
enter_raw_mode(); enter_raw_mode();
@ -787,27 +836,35 @@ client_loop(int have_pty, int escape_char_arg)
while (!quit_pending) { while (!quit_pending) {
fd_set readset, writeset; fd_set readset, writeset;
/* Precess buffered packets sent by the server. */ /* Process buffered packets sent by the server. */
client_process_buffered_input_packets(); client_process_buffered_input_packets();
/* Make packets of buffered stdin data, and buffer them /*
for sending to the server. */ * Make packets of buffered stdin data, and buffer them for
* sending to the server.
*/
client_make_packets_from_stdin_data(); client_make_packets_from_stdin_data();
/* Make packets from buffered channel data, and buffer /*
them for sending to the server. */ * Make packets from buffered channel data, and buffer them
* for sending to the server.
*/
if (packet_not_very_much_data_to_write()) if (packet_not_very_much_data_to_write())
channel_output_poll(); channel_output_poll();
/* Check if the window size has changed, and buffer a /*
message about it to the server if so. */ * Check if the window size has changed, and buffer a message
* about it to the server if so.
*/
client_check_window_change(); client_check_window_change();
if (quit_pending) if (quit_pending)
break; break;
/* Wait until we have something to do (something becomes /*
available on one of the descriptors). */ * Wait until we have something to do (something becomes
* available on one of the descriptors).
*/
client_wait_until_can_do_something(&readset, &writeset); client_wait_until_can_do_something(&readset, &writeset);
if (quit_pending) if (quit_pending)
@ -816,16 +873,19 @@ client_loop(int have_pty, int escape_char_arg)
/* Do channel operations. */ /* Do channel operations. */
channel_after_select(&readset, &writeset); channel_after_select(&readset, &writeset);
/* Process input from the connection and from stdin. /*
Buffer any data that is available. */ * Process input from the connection and from stdin. Buffer
* any data that is available.
*/
client_process_input(&readset); client_process_input(&readset);
/* Process output to stdout and stderr. Output to the /*
connection is processed elsewhere (above). */ * Process output to stdout and stderr. Output to the
* connection is processed elsewhere (above).
*/
client_process_output(&writeset); client_process_output(&writeset);
/* Send as much buffered packet data as possible to the /* Send as much buffered packet data as possible to the sender. */
sender. */
if (FD_ISSET(connection_out, &writeset)) if (FD_ISSET(connection_out, &writeset))
packet_write_poll(); packet_write_poll();
} }
@ -839,8 +899,10 @@ client_loop(int have_pty, int escape_char_arg)
/* Stop listening for connections. */ /* Stop listening for connections. */
channel_stop_listening(); channel_stop_listening();
/* In interactive mode (with pseudo tty) display a message /*
indicating that the connection has been closed. */ * In interactive mode (with pseudo tty) display a message indicating
* that the connection has been closed.
*/
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
buffer_append(&stderr_buffer, buf, strlen(buf)); buffer_append(&stderr_buffer, buf, strlen(buf));
@ -868,7 +930,6 @@ client_loop(int have_pty, int escape_char_arg)
buffer_consume(&stderr_buffer, len); buffer_consume(&stderr_buffer, len);
} }
/* Leave raw mode. */
if (have_pty) if (have_pty)
leave_raw_mode(); leave_raw_mode();

View File

@ -1,5 +1,34 @@
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: compat.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: compat.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"

View File

@ -1,4 +1,32 @@
/* RCSID("$Id: compat.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$Id: compat.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
#ifndef COMPAT_H #ifndef COMPAT_H
#define COMPAT_H #define COMPAT_H

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: compress.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "buffer.h" #include "buffer.h"
@ -23,8 +23,10 @@ RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
static z_stream incoming_stream; static z_stream incoming_stream;
static z_stream outgoing_stream; static z_stream outgoing_stream;
/* Initializes compression; level is compression level from 1 to 9 /*
(as in gzip). */ * Initializes compression; level is compression level from 1 to 9
* (as in gzip).
*/
void void
buffer_compress_init(int level) buffer_compress_init(int level)
@ -53,13 +55,14 @@ buffer_compress_uninit()
deflateEnd(&outgoing_stream); deflateEnd(&outgoing_stream);
} }
/* Compresses the contents of input_buffer into output_buffer. All /*
packets compressed using this function will form a single * Compresses the contents of input_buffer into output_buffer. All packets
compressed data stream; however, data will be flushed at the end of * compressed using this function will form a single compressed data stream;
every call so that each output_buffer can be decompressed * however, data will be flushed at the end of every call so that each
independently (but in the appropriate order since they together * output_buffer can be decompressed independently (but in the appropriate
form a single compression stream) by the receiver. This appends * order since they together form a single compression stream) by the
the compressed data to the output buffer. */ * receiver. This appends the compressed data to the output buffer.
*/
void void
buffer_compress(Buffer * input_buffer, Buffer * output_buffer) buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
@ -106,13 +109,14 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
while (outgoing_stream.avail_out == 0); while (outgoing_stream.avail_out == 0);
} }
/* Uncompresses the contents of input_buffer into output_buffer. All /*
packets uncompressed using this function will form a single * Uncompresses the contents of input_buffer into output_buffer. All packets
compressed data stream; however, data will be flushed at the end of * uncompressed using this function will form a single compressed data
every call so that each output_buffer. This must be called for the * stream; however, data will be flushed at the end of every call so that
same size units that the buffer_compress was called, and in the * each output_buffer. This must be called for the same size units that the
same order that buffers compressed with that. This appends the * buffer_compress was called, and in the same order that buffers compressed
uncompressed data to the output buffer. */ * with that. This appends the uncompressed data to the output buffer.
*/
void void
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer) buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
@ -145,9 +149,11 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR"); fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
/* NOTREACHED */ /* NOTREACHED */
case Z_BUF_ERROR: case Z_BUF_ERROR:
/* Comments in zlib.h say that we should keep /*
calling inflate() until we get an error. This * Comments in zlib.h say that we should keep calling
appears to be the error that we get. */ * inflate() until we get an error. This appears to
* be the error that we get.
*/
return; return;
case Z_MEM_ERROR: case Z_MEM_ERROR:
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR"); fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");

View File

@ -13,34 +13,38 @@
* *
*/ */
/* RCSID("$Id: compress.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: compress.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
#ifndef COMPRESS_H #ifndef COMPRESS_H
#define COMPRESS_H #define COMPRESS_H
/* Initializes compression; level is compression level from 1 to 9 (as in /*
gzip). */ * Initializes compression; level is compression level from 1 to 9 (as in
* gzip).
*/
void buffer_compress_init(int level); void buffer_compress_init(int level);
/* Frees any data structures allocated by buffer_compress_init. */ /* Frees any data structures allocated by buffer_compress_init. */
void buffer_compress_uninit(); void buffer_compress_uninit();
/* Compresses the contents of input_buffer into output_buffer. All /*
packets compressed using this function will form a single * Compresses the contents of input_buffer into output_buffer. All packets
compressed data stream; however, data will be flushed at the end of * compressed using this function will form a single compressed data stream;
every call so that each output_buffer can be decompressed * however, data will be flushed at the end of every call so that each
independently (but in the appropriate order since they together * output_buffer can be decompressed independently (but in the appropriate
form a single compression stream) by the receiver. This appends * order since they together form a single compression stream) by the
the compressed data to the output buffer. */ * receiver. This appends the compressed data to the output buffer.
*/
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer); void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
/* Uncompresses the contents of input_buffer into output_buffer. All /*
packets uncompressed using this function will form a single * Uncompresses the contents of input_buffer into output_buffer. All packets
compressed data stream; however, data will be flushed at the end of * uncompressed using this function will form a single compressed data
every call so that each output_buffer. This must be called for the * stream; however, data will be flushed at the end of every call so that
same size units that the buffer_compress was called, and in the * each output_buffer. This must be called for the same size units that the
same order that buffers compressed with that. This appends the * buffer_compress was called, and in the same order that buffers compressed
uncompressed data to the output buffer. */ * with that. This appends the uncompressed data to the output buffer.
*/
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer); void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
#endif /* COMPRESS_H */ #endif /* COMPRESS_H */

View File

@ -13,13 +13,15 @@
* *
*/ */
/* RCSID("$Id: crc32.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: crc32.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
#ifndef CRC32_H #ifndef CRC32_H
#define CRC32_H #define CRC32_H
/* This computes a 32 bit CRC of the data in the buffer, and returns the /*
CRC. The polynomial used is 0xedb88320. */ * This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
* The polynomial used is 0xedb88320.
*/
unsigned int crc32(const unsigned char *buf, unsigned int len); unsigned int crc32(const unsigned char *buf, unsigned int len);
#endif /* CRC32_H */ #endif /* CRC32_H */

View File

@ -1,5 +1,34 @@
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: fingerprint.c,v 1.3 1999/11/24 00:26:01 deraadt Exp $"); RCSID("$Id: fingerprint.c,v 1.4 1999/11/24 16:15:25 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"

View File

@ -1,4 +1,32 @@
/* RCSID("$Id: fingerprint.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */ /*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$Id: fingerprint.h,v 1.3 1999/11/24 16:15:25 markus Exp $"); */
#ifndef FINGERPRINT_H #ifndef FINGERPRINT_H
#define FINGERPRINT_H #define FINGERPRINT_H

View File

@ -14,16 +14,18 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: hostfile.c,v 1.5 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: hostfile.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
/* Reads a multiple-precision integer in hex from the buffer, and advances the /*
pointer. The integer must already be initialized. This function is * Reads a multiple-precision integer in hex from the buffer, and advances
permitted to modify the buffer. This leaves *cpp to point just beyond * the pointer. The integer must already be initialized. This function is
the last processed (and maybe modified) character. Note that this may * permitted to modify the buffer. This leaves *cpp to point just beyond the
modify the buffer containing the number. */ * last processed (and maybe modified) character. Note that this may modify
* the buffer containing the number.
*/
int int
auth_rsa_read_bignum(char **cpp, BIGNUM * value) auth_rsa_read_bignum(char **cpp, BIGNUM * value)
@ -32,7 +34,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
int len, old; int len, old;
/* Skip any leading whitespace. */ /* Skip any leading whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++); for (; *cp == ' ' || *cp == '\t'; cp++)
;
/* Check that it begins with a hex digit. */ /* Check that it begins with a hex digit. */
if (*cp < '0' || *cp > '9') if (*cp < '0' || *cp > '9')
@ -42,7 +45,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
*cpp = cp; *cpp = cp;
/* Move forward until all hex digits skipped. */ /* Move forward until all hex digits skipped. */
for (; *cp >= '0' && *cp <= '9'; cp++); for (; *cp >= '0' && *cp <= '9'; cp++)
;
/* Compute the length of the hex number. */ /* Compute the length of the hex number. */
len = cp - *cpp; len = cp - *cpp;
@ -51,7 +55,6 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
old = *cp; old = *cp;
*cp = 0; *cp = 0;
/* Parse the number. */ /* Parse the number. */
if (BN_dec2bn(&value, *cpp) == 0) if (BN_dec2bn(&value, *cpp) == 0)
return 0; return 0;
@ -64,8 +67,10 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
return 1; return 1;
} }
/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer /*
over the key. Skips any whitespace at the beginning and at end. */ * Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int int
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
@ -74,7 +79,8 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
char *cp; char *cp;
/* Skip leading whitespace. */ /* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++); for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
/* Get number of bits. */ /* Get number of bits. */
if (*cp < '0' || *cp > '9') if (*cp < '0' || *cp > '9')
@ -91,7 +97,8 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
return 0; return 0;
/* Skip trailing whitespace. */ /* Skip trailing whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++); for (; *cp == ' ' || *cp == '\t'; cp++)
;
/* Return results. */ /* Return results. */
*cpp = cp; *cpp = cp;
@ -99,10 +106,12 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
return 1; return 1;
} }
/* Tries to match the host name (which must be in all lowercase) against the /*
comma-separated sequence of subpatterns (each possibly preceded by ! to * Tries to match the host name (which must be in all lowercase) against the
indicate negation). Returns true if there is a positive match; zero * comma-separated sequence of subpatterns (each possibly preceded by ! to
otherwise. */ * indicate negation). Returns true if there is a positive match; zero
* otherwise.
*/
int int
match_hostname(const char *host, const char *pattern, unsigned int len) match_hostname(const char *host, const char *pattern, unsigned int len)
@ -121,8 +130,10 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
} else } else
negated = 0; negated = 0;
/* Extract the subpattern up to a comma or end. Convert /*
the subpattern to lowercase. */ * Extract the subpattern up to a comma or end. Convert the
* subpattern to lowercase.
*/
for (subi = 0; for (subi = 0;
i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
subi++, i++) subi++, i++)
@ -131,8 +142,7 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
if (subi >= sizeof(sub) - 1) if (subi >= sizeof(sub) - 1)
return 0; return 0;
/* If the subpattern was terminated by a comma, skip the /* If the subpattern was terminated by a comma, skip the comma. */
comma. */
if (i < len && pattern[i] == ',') if (i < len && pattern[i] == ',')
i++; i++;
@ -142,24 +152,25 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
/* Try to match the subpattern against the host name. */ /* Try to match the subpattern against the host name. */
if (match_pattern(host, sub)) { if (match_pattern(host, sub)) {
if (negated) if (negated)
return 0; /* Fail if host matches return 0; /* Fail */
any negated subpattern. */
else else
got_positive = 1; got_positive = 1;
} }
} }
/* Return success if got a positive match. If there was a /*
negative match, we have already returned zero and never get * Return success if got a positive match. If there was a negative
here. */ * match, we have already returned zero and never get here.
*/
return got_positive; return got_positive;
} }
/* Checks whether the given host (which must be in all lowercase) is /*
already in the list of our known hosts. * Checks whether the given host (which must be in all lowercase) is already
Returns HOST_OK if the host is known and has the specified key, * in the list of our known hosts. Returns HOST_OK if the host is known and
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
but used to have a different host key. */ * if the host is known but used to have a different host key.
*/
HostStatus HostStatus
check_host_in_hostfile(const char *filename, const char *host, check_host_in_hostfile(const char *filename, const char *host,
@ -180,9 +191,11 @@ check_host_in_hostfile(const char *filename, const char *host,
/* Cache the length of the host name. */ /* Cache the length of the host name. */
hostlen = strlen(host); hostlen = strlen(host);
/* Return value when the loop terminates. This is set to /*
HOST_CHANGED if we have seen a different key for the host and * Return value when the loop terminates. This is set to
have not found the proper one. */ * HOST_CHANGED if we have seen a different key for the host and have
* not found the proper one.
*/
end_return = HOST_NEW; end_return = HOST_NEW;
/* size of modulus 'n' */ /* size of modulus 'n' */
@ -193,15 +206,15 @@ check_host_in_hostfile(const char *filename, const char *host,
cp = line; cp = line;
linenum++; linenum++;
/* Skip any leading whitespace. */ /* Skip any leading whitespace, comments and empty lines. */
for (; *cp == ' ' || *cp == '\t'; cp++); for (; *cp == ' ' || *cp == '\t'; cp++)
;
/* Ignore comment lines and empty lines. */
if (!*cp || *cp == '#' || *cp == '\n') if (!*cp || *cp == '#' || *cp == '\n')
continue; continue;
/* Find the end of the host name portion. */ /* Find the end of the host name portion. */
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++); for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
;
/* Check if the host name matches. */ /* Check if the host name matches. */
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp))) if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
@ -210,8 +223,10 @@ check_host_in_hostfile(const char *filename, const char *host,
/* Got a match. Skip host name. */ /* Got a match. Skip host name. */
cp = cp2; cp = cp2;
/* Extract the key from the line. This will skip any /*
leading whitespace. Ignore badly formatted lines. */ * Extract the key from the line. This will skip any leading
* whitespace. Ignore badly formatted lines.
*/
if (!auth_rsa_read_key(&cp, &kbits, ke, kn)) if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
continue; continue;
@ -228,21 +243,27 @@ check_host_in_hostfile(const char *filename, const char *host,
fclose(f); fclose(f);
return HOST_OK; return HOST_OK;
} }
/* They do not match. We will continue to go through the /*
file; however, we note that we will not return that it * They do not match. We will continue to go through the
is new. */ * file; however, we note that we will not return that it is
* new.
*/
end_return = HOST_CHANGED; end_return = HOST_CHANGED;
} }
/* Clear variables and close the file. */ /* Clear variables and close the file. */
fclose(f); fclose(f);
/* Return either HOST_NEW or HOST_CHANGED, depending on whether we /*
saw a different key for the host. */ * Return either HOST_NEW or HOST_CHANGED, depending on whether we
* saw a different key for the host.
*/
return end_return; return end_return;
} }
/* Appends an entry to the host file. Returns false if the entry /*
could not be appended. */ * Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
int int
add_host_to_hostfile(const char *filename, const char *host, add_host_to_hostfile(const char *filename, const char *host,

View File

@ -87,8 +87,10 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
#define _PATH_RSH "/usr/bin/rsh" #define _PATH_RSH "/usr/bin/rsh"
#endif /* _PATH_RSH */ #endif /* _PATH_RSH */
/* Define this to use pipes instead of socketpairs for communicating with the /*
client program. Socketpairs do not seem to work on all systems. */ * Define this to use pipes instead of socketpairs for communicating with the
* client program. Socketpairs do not seem to work on all systems.
*/
#define USE_PIPES 1 #define USE_PIPES 1
#endif /* INCLUDES_H */ #endif /* INCLUDES_H */

6
log.c
View File

@ -1,11 +1,9 @@
/* /*
*
* Shared versions of debug(), log(), etc. * Shared versions of debug(), log(), etc.
* */
*/
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: log.c,v 1.5 1999/11/24 00:26:02 deraadt Exp $"); RCSID("$OpenBSD: log.c,v 1.6 1999/11/24 19:53:47 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"

29
login.c
View File

@ -18,7 +18,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: login.c,v 1.4 1999/11/25 00:54:59 damien Exp $");
#include <utmp.h> #include <utmp.h>
#include "ssh.h" #include "ssh.h"
@ -30,12 +30,16 @@ RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
# include <lastlog.h> # include <lastlog.h>
#endif #endif
/* Returns the time when the user last logged in. Returns 0 if the /*
information is not available. This must be called before record_login. * Returns the time when the user last logged in. Returns 0 if the
The host the user logged in from will be returned in buf. */ * information is not available. This must be called before record_login.
* The host the user logged in from will be returned in buf.
*/
/* Returns the time when the user last logged in (or 0 if no previous login /*
is found). The name of the host used last time is returned in buf. */ * Returns the time when the user last logged in (or 0 if no previous login
* is found). The name of the host used last time is returned in buf.
*/
unsigned long unsigned long
get_last_login_time(uid_t uid, const char *logname, get_last_login_time(uid_t uid, const char *logname,
@ -64,8 +68,10 @@ get_last_login_time(uid_t uid, const char *logname,
return ll.ll_time; return ll.ll_time;
} }
/* Records that the user has logged in. I these parts of operating systems /*
were more standardized. */ * Records that the user has logged in. I these parts of operating systems
* were more standardized.
*/
void void
record_login(int pid, const char *ttyname, const char *user, uid_t uid, record_login(int pid, const char *ttyname, const char *user, uid_t uid,
@ -95,9 +101,10 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
/* Update lastlog unless actually recording a logout. */ /* Update lastlog unless actually recording a logout. */
if (strcmp(user, "") != 0) { if (strcmp(user, "") != 0) {
/* It is safer to bzero the lastlog structure first /*
because some systems might have some extra fields in it * It is safer to bzero the lastlog structure first because
(e.g. SGI) */ * some systems might have some extra fields in it (e.g. SGI)
*/
memset(&ll, 0, sizeof(ll)); memset(&ll, 0, sizeof(ll));
/* Update lastlog. */ /* Update lastlog. */

35
match.c
View File

@ -14,12 +14,14 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: match.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: match.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
/* Returns true if the given string matches the pattern (which may contain /*
? and * as wildcards), and zero if it does not match. */ * Returns true if the given string matches the pattern (which may contain ?
* and * as wildcards), and zero if it does not match.
*/
int int
match_pattern(const char *s, const char *pattern) match_pattern(const char *s, const char *pattern)
@ -29,7 +31,6 @@ match_pattern(const char *s, const char *pattern)
if (!*pattern) if (!*pattern)
return !*s; return !*s;
/* Process '*'. */
if (*pattern == '*') { if (*pattern == '*') {
/* Skip the asterisk. */ /* Skip the asterisk. */
pattern++; pattern++;
@ -40,9 +41,11 @@ match_pattern(const char *s, const char *pattern)
/* If next character in pattern is known, optimize. */ /* If next character in pattern is known, optimize. */
if (*pattern != '?' && *pattern != '*') { if (*pattern != '?' && *pattern != '*') {
/* Look instances of the next character in /*
pattern, and try to match starting from * Look instances of the next character in
those. */ * pattern, and try to match starting from
* those.
*/
for (; *s; s++) for (; *s; s++)
if (*s == *pattern && if (*s == *pattern &&
match_pattern(s + 1, pattern + 1)) match_pattern(s + 1, pattern + 1))
@ -50,26 +53,28 @@ match_pattern(const char *s, const char *pattern)
/* Failed. */ /* Failed. */
return 0; return 0;
} }
/* Move ahead one character at a time and try to /*
match at each position. */ * Move ahead one character at a time and try to
* match at each position.
*/
for (; *s; s++) for (; *s; s++)
if (match_pattern(s, pattern)) if (match_pattern(s, pattern))
return 1; return 1;
/* Failed. */ /* Failed. */
return 0; return 0;
} }
/* There must be at least one more character in the /*
string. If we are at the end, fail. */ * There must be at least one more character in the string.
* If we are at the end, fail.
*/
if (!*s) if (!*s)
return 0; return 0;
/* Check if the next character of the string is /* Check if the next character of the string is acceptable. */
acceptable. */
if (*pattern != '?' && *pattern != *s) if (*pattern != '?' && *pattern != *s)
return 0; return 0;
/* Move to the next character, both in string and in /* Move to the next character, both in string and in pattern. */
pattern. */
s++; s++;
pattern++; pattern++;
} }

10
mpaux.h
View File

@ -13,14 +13,16 @@
* precision integers. * precision integers.
*/ */
/* RCSID("$Id: mpaux.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: mpaux.h,v 1.4 1999/11/25 00:54:59 damien Exp $"); */
#ifndef MPAUX_H #ifndef MPAUX_H
#define MPAUX_H #define MPAUX_H
/* Computes a 16-byte session id in the global variable session_id. /*
The session id is computed by concatenating the linearized, msb * Computes a 16-byte session id in the global variable session_id. The
first representations of host_key_n, session_key_n, and the cookie. */ * session id is computed by concatenating the linearized, msb first
* representations of host_key_n, session_key_n, and the cookie.
*/
void void
compute_session_id(unsigned char session_id[16], compute_session_id(unsigned char session_id[16],
unsigned char cookie[8], unsigned char cookie[8],

34
nchan.c
View File

@ -1,5 +1,34 @@
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: nchan.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: nchan.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
@ -173,9 +202,10 @@ chan_send_oclose(Channel *c)
static void static void
chan_shutdown_write(Channel *c) chan_shutdown_write(Channel *c)
{ {
/* shutdown failure is allowed if write failed already */
debug("channel %d: shutdown_write", c->self); debug("channel %d: shutdown_write", c->self);
if (shutdown(c->sock, SHUT_WR) < 0) if (shutdown(c->sock, SHUT_WR) < 0)
error("chan_shutdown_write failed for #%d/fd%d: %.100s", debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
c->self, c->sock, strerror(errno)); c->self, c->sock, strerror(errno));
} }
static void static void

31
nchan.h
View File

@ -1,4 +1,33 @@
/* RCSID("$Id: nchan.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$Id: nchan.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
#ifndef NCHAN_H #ifndef NCHAN_H
#define NCHAN_H #define NCHAN_H

View File

@ -1,3 +1,31 @@
.\"
.\" Copyright (c) 1999 Markus Friedl. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Markus Friedl.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.TL .TL
OpenSSH Channel Close Protocol 1.5 Implementation OpenSSH Channel Close Protocol 1.5 Implementation
.SH .SH

181
packet.c
View File

@ -15,7 +15,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: packet.c,v 1.5 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: packet.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "buffer.h" #include "buffer.h"
@ -29,15 +29,19 @@ RCSID("$Id: packet.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
#include "compress.h" #include "compress.h"
#include "deattack.h" #include "deattack.h"
/* This variable contains the file descriptors used for communicating with /*
the other side. connection_in is used for reading; connection_out * This variable contains the file descriptors used for communicating with
for writing. These can be the same descriptor, in which case it is * the other side. connection_in is used for reading; connection_out for
assumed to be a socket. */ * writing. These can be the same descriptor, in which case it is assumed to
* be a socket.
*/
static int connection_in = -1; static int connection_in = -1;
static int connection_out = -1; static int connection_out = -1;
/* Cipher type. This value is only used to determine whether to pad the /*
packets with zeroes or random data. */ * Cipher type. This value is only used to determine whether to pad the
* packets with zeroes or random data.
*/
static int cipher_type = SSH_CIPHER_NONE; static int cipher_type = SSH_CIPHER_NONE;
/* Protocol flags for the remote side. */ /* Protocol flags for the remote side. */
@ -76,8 +80,10 @@ static int initialized = 0;
/* Set to true if the connection is interactive. */ /* Set to true if the connection is interactive. */
static int interactive_mode = 0; static int interactive_mode = 0;
/* Sets the descriptors used for communication. Disables encryption until /*
packet_set_encryption_key is called. */ * Sets the descriptors used for communication. Disables encryption until
* packet_set_encryption_key is called.
*/
void void
packet_set_connection(int fd_in, int fd_out) packet_set_connection(int fd_in, int fd_out)
@ -171,8 +177,10 @@ packet_get_protocol_flags()
return remote_protocol_flags; return remote_protocol_flags;
} }
/* Starts packet compression from the next packet on in both directions. /*
Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ * Starts packet compression from the next packet on in both directions.
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
void void
packet_start_compression(int level) packet_start_compression(int level)
@ -184,8 +192,10 @@ packet_start_compression(int level)
buffer_compress_init(level); buffer_compress_init(level);
} }
/* Encrypts the given number of bytes, copying from src to dest. /*
bytes is known to be a multiple of 8. */ * Encrypts the given number of bytes, copying from src to dest. bytes is
* known to be a multiple of 8.
*/
void void
packet_encrypt(CipherContext * cc, void *dest, void *src, packet_encrypt(CipherContext * cc, void *dest, void *src,
@ -194,8 +204,10 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
cipher_encrypt(cc, dest, src, bytes); cipher_encrypt(cc, dest, src, bytes);
} }
/* Decrypts the given number of bytes, copying from src to dest. /*
bytes is known to be a multiple of 8. */ * Decrypts the given number of bytes, copying from src to dest. bytes is
* known to be a multiple of 8.
*/
void void
packet_decrypt(CipherContext * cc, void *dest, void *src, packet_decrypt(CipherContext * cc, void *dest, void *src,
@ -206,8 +218,10 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
if ((bytes % 8) != 0) if ((bytes % 8) != 0)
fatal("packet_decrypt: bad ciphertext length %d", bytes); fatal("packet_decrypt: bad ciphertext length %d", bytes);
/* Cryptographic attack detector for ssh - Modifications for packet.c /*
(C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) */ * Cryptographic attack detector for ssh - Modifications for packet.c
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
*/
switch (cc->type) { switch (cc->type) {
case SSH_CIPHER_NONE: case SSH_CIPHER_NONE:
@ -224,9 +238,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
cipher_decrypt(cc, dest, src, bytes); cipher_decrypt(cc, dest, src, bytes);
} }
/* Causes any further packets to be encrypted using the given key. The same /*
key is used for both sending and reception. However, both directions * Causes any further packets to be encrypted using the given key. The same
are encrypted independently of each other. */ * key is used for both sending and reception. However, both directions are
* encrypted independently of each other.
*/
void void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen, packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
@ -283,8 +299,10 @@ packet_put_bignum(BIGNUM * value)
buffer_put_bignum(&outgoing_packet, value); buffer_put_bignum(&outgoing_packet, value);
} }
/* Finalizes and sends the packet. If the encryption key has been set, /*
encrypts the packet before sending. */ * Finalizes and sends the packet. If the encryption key has been set,
* encrypts the packet before sending.
*/
void void
packet_send() packet_send()
@ -294,8 +312,10 @@ packet_send()
unsigned int checksum; unsigned int checksum;
u_int32_t rand = 0; u_int32_t rand = 0;
/* If using packet compression, compress the payload of the /*
outgoing packet. */ * If using packet compression, compress the payload of the outgoing
* packet.
*/
if (packet_compression) { if (packet_compression) {
buffer_clear(&compression_buffer); buffer_clear(&compression_buffer);
/* Skip padding. */ /* Skip padding. */
@ -348,14 +368,18 @@ packet_send()
buffer_clear(&outgoing_packet); buffer_clear(&outgoing_packet);
/* Note that the packet is now only buffered in output. It won\'t /*
be actually sent until packet_write_wait or packet_write_poll * Note that the packet is now only buffered in output. It won\'t be
is called. */ * actually sent until packet_write_wait or packet_write_poll is
* called.
*/
} }
/* Waits until a packet has been received, and returns its type. Note that /*
no other data is processed until this returns, so this function should * Waits until a packet has been received, and returns its type. Note that
not be used during the interactive session. */ * no other data is processed until this returns, so this function should not
* be used during the interactive session.
*/
int int
packet_read(int *payload_len_ptr) packet_read(int *payload_len_ptr)
@ -379,12 +403,16 @@ packet_read(int *payload_len_ptr)
/* If we got a packet, return it. */ /* If we got a packet, return it. */
if (type != SSH_MSG_NONE) if (type != SSH_MSG_NONE)
return type; return type;
/* Otherwise, wait for some data to arrive, add it to the /*
buffer, and try again. */ * Otherwise, wait for some data to arrive, add it to the
* buffer, and try again.
*/
FD_ZERO(&set); FD_ZERO(&set);
FD_SET(connection_in, &set); FD_SET(connection_in, &set);
/* Wait for some data to arrive. */ /* Wait for some data to arrive. */
select(connection_in + 1, &set, NULL, NULL, NULL); select(connection_in + 1, &set, NULL, NULL, NULL);
/* Read data from the socket. */ /* Read data from the socket. */
len = read(connection_in, buf, sizeof(buf)); len = read(connection_in, buf, sizeof(buf));
if (len == 0) if (len == 0)
@ -397,8 +425,10 @@ packet_read(int *payload_len_ptr)
/* NOTREACHED */ /* NOTREACHED */
} }
/* Waits until a packet has been received, verifies that its type matches /*
that given, and gives a fatal error and exits if there is a mismatch. */ * Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
void void
packet_read_expect(int *payload_len_ptr, int expected_type) packet_read_expect(int *payload_len_ptr, int expected_type)
@ -516,8 +546,10 @@ restart:
return (unsigned char) buf[0]; return (unsigned char) buf[0];
} }
/* Buffers the given amount of input characters. This is intended to be /*
used together with packet_read_poll. */ * Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
*/
void void
packet_process_incoming(const char *buf, unsigned int len) packet_process_incoming(const char *buf, unsigned int len)
@ -543,8 +575,10 @@ packet_get_int()
return buffer_get_int(&incoming_packet); return buffer_get_int(&incoming_packet);
} }
/* Returns an arbitrary precision integer from the packet data. The integer /*
must have been initialized before this call. */ * Returns an arbitrary precision integer from the packet data. The integer
* must have been initialized before this call.
*/
void void
packet_get_bignum(BIGNUM * value, int *length_ptr) packet_get_bignum(BIGNUM * value, int *length_ptr)
@ -552,25 +586,27 @@ packet_get_bignum(BIGNUM * value, int *length_ptr)
*length_ptr = buffer_get_bignum(&incoming_packet, value); *length_ptr = buffer_get_bignum(&incoming_packet, value);
} }
/* Returns a string from the packet data. The string is allocated using /*
xmalloc; it is the responsibility of the calling program to free it when * Returns a string from the packet data. The string is allocated using
no longer needed. The length_ptr argument may be NULL, or point to an * xmalloc; it is the responsibility of the calling program to free it when
integer into which the length of the string is stored. */ * no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored.
*/
char char *
*
packet_get_string(unsigned int *length_ptr) packet_get_string(unsigned int *length_ptr)
{ {
return buffer_get_string(&incoming_packet, length_ptr); return buffer_get_string(&incoming_packet, length_ptr);
} }
/* Sends a diagnostic message from the server to the client. This message /*
can be sent at any time (but not while constructing another message). * Sends a diagnostic message from the server to the client. This message
The message is printed immediately, but only if the client is being * can be sent at any time (but not while constructing another message). The
executed in verbose mode. These messages are primarily intended to * message is printed immediately, but only if the client is being executed
ease debugging authentication problems. The length of the formatted * in verbose mode. These messages are primarily intended to ease debugging
message must not exceed 1024 bytes. This will automatically call * authentication problems. The length of the formatted message must not
packet_write_wait. */ * exceed 1024 bytes. This will automatically call packet_write_wait.
*/
void void
packet_send_debug(const char *fmt,...) packet_send_debug(const char *fmt,...)
@ -588,10 +624,12 @@ packet_send_debug(const char *fmt,...)
packet_write_wait(); packet_write_wait();
} }
/* Logs the error plus constructs and sends a disconnect /*
packet, closes the connection, and exits. This function never returns. * Logs the error plus constructs and sends a disconnect packet, closes the
The error message should not contain a newline. The length of the * connection, and exits. This function never returns. The error message
formatted message must not exceed 1024 bytes. */ * should not contain a newline. The length of the formatted message must
* not exceed 1024 bytes.
*/
void void
packet_disconnect(const char *fmt,...) packet_disconnect(const char *fmt,...)
@ -603,8 +641,10 @@ packet_disconnect(const char *fmt,...)
fatal("packet_disconnect called recursively."); fatal("packet_disconnect called recursively.");
disconnecting = 1; disconnecting = 1;
/* Format the message. Note that the caller must make sure the /*
message is of limited size. */ * Format the message. Note that the caller must make sure the
* message is of limited size.
*/
va_start(args, fmt); va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args); vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args); va_end(args);
@ -625,8 +665,7 @@ packet_disconnect(const char *fmt,...)
fatal("Disconnecting: %.100s", buf); fatal("Disconnecting: %.100s", buf);
} }
/* Checks if there is any buffered output, and tries to write some of the /* Checks if there is any buffered output, and tries to write some of the output. */
output. */
void void
packet_write_poll() packet_write_poll()
@ -644,8 +683,10 @@ packet_write_poll()
} }
} }
/* Calls packet_write_poll repeatedly until all pending output data has /*
been written. */ * Calls packet_write_poll repeatedly until all pending output data has been
* written.
*/
void void
packet_write_wait() packet_write_wait()
@ -689,8 +730,10 @@ packet_set_interactive(int interactive, int keepalives)
/* Record that we are in interactive mode. */ /* Record that we are in interactive mode. */
interactive_mode = interactive; interactive_mode = interactive;
/* Only set socket options if using a socket (as indicated by the /*
descriptors being the same). */ * Only set socket options if using a socket (as indicated by the
* descriptors being the same).
*/
if (connection_in != connection_out) if (connection_in != connection_out)
return; return;
@ -701,8 +744,10 @@ packet_set_interactive(int interactive, int keepalives)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
} }
if (interactive) { if (interactive) {
/* Set IP options for an interactive connection. Use /*
IPTOS_LOWDELAY and TCP_NODELAY. */ * Set IP options for an interactive connection. Use
* IPTOS_LOWDELAY and TCP_NODELAY.
*/
int lowdelay = IPTOS_LOWDELAY; int lowdelay = IPTOS_LOWDELAY;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay, if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
sizeof(lowdelay)) < 0) sizeof(lowdelay)) < 0)
@ -711,8 +756,10 @@ packet_set_interactive(int interactive, int keepalives)
sizeof(on)) < 0) sizeof(on)) < 0)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
} else { } else {
/* Set IP options for a non-interactive connection. Use /*
IPTOS_THROUGHPUT. */ * Set IP options for a non-interactive connection. Use
* IPTOS_THROUGHPUT.
*/
int throughput = IPTOS_THROUGHPUT; int throughput = IPTOS_THROUGHPUT;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput, if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
sizeof(throughput)) < 0) sizeof(throughput)) < 0)

118
packet.h
View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: packet.h,v 1.6 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: packet.h,v 1.7 1999/11/25 00:54:59 damien Exp $"); */
#ifndef PACKET_H #ifndef PACKET_H
#define PACKET_H #define PACKET_H
@ -27,10 +27,11 @@
#include <ssl/bn.h> #include <ssl/bn.h>
#endif #endif
/* Sets the socket used for communication. Disables encryption until /*
packet_set_encryption_key is called. It is permissible that fd_in * Sets the socket used for communication. Disables encryption until
and fd_out are the same descriptor; in that case it is assumed to * packet_set_encryption_key is called. It is permissible that fd_in and
be a socket. */ * fd_out are the same descriptor; in that case it is assumed to be a socket.
*/
void packet_set_connection(int fd_in, int fd_out); void packet_set_connection(int fd_in, int fd_out);
/* Puts the connection file descriptors into non-blocking mode. */ /* Puts the connection file descriptors into non-blocking mode. */
@ -42,20 +43,25 @@ int packet_get_connection_in(void);
/* Returns the file descriptor used for output. */ /* Returns the file descriptor used for output. */
int packet_get_connection_out(void); int packet_get_connection_out(void);
/* Closes the connection (both descriptors) and clears and frees /*
internal data structures. */ * Closes the connection (both descriptors) and clears and frees internal
* data structures.
*/
void packet_close(void); void packet_close(void);
/* Causes any further packets to be encrypted using the given key. The same /*
key is used for both sending and reception. However, both directions * Causes any further packets to be encrypted using the given key. The same
are encrypted independently of each other. Cipher types are * key is used for both sending and reception. However, both directions are
defined in ssh.h. */ * encrypted independently of each other. Cipher types are defined in ssh.h.
*/
void void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen, packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
int cipher_type); int cipher_type);
/* Sets remote side protocol flags for the current connection. This can /*
be called at any time. */ * Sets remote side protocol flags for the current connection. This can be
* called at any time.
*/
void packet_set_protocol_flags(unsigned int flags); void packet_set_protocol_flags(unsigned int flags);
/* Returns the remote protocol flags set earlier by the above function. */ /* Returns the remote protocol flags set earlier by the above function. */
@ -64,8 +70,10 @@ unsigned int packet_get_protocol_flags(void);
/* Enables compression in both directions starting from the next packet. */ /* Enables compression in both directions starting from the next packet. */
void packet_start_compression(int level); void packet_start_compression(int level);
/* Informs that the current session is interactive. Sets IP flags for optimal /*
performance in interactive use. */ * Informs that the current session is interactive. Sets IP flags for
* optimal performance in interactive use.
*/
void packet_set_interactive(int interactive, int keepalives); void packet_set_interactive(int interactive, int keepalives);
/* Returns true if the current connection is interactive. */ /* Returns true if the current connection is interactive. */
@ -86,28 +94,35 @@ void packet_put_bignum(BIGNUM * value);
/* Appends a string to packet data. */ /* Appends a string to packet data. */
void packet_put_string(const char *buf, unsigned int len); void packet_put_string(const char *buf, unsigned int len);
/* Finalizes and sends the packet. If the encryption key has been set, /*
encrypts the packet before sending. */ * Finalizes and sends the packet. If the encryption key has been set,
* encrypts the packet before sending.
*/
void packet_send(void); void packet_send(void);
/* Waits until a packet has been received, and returns its type. */ /* Waits until a packet has been received, and returns its type. */
int packet_read(int *payload_len_ptr); int packet_read(int *payload_len_ptr);
/* Waits until a packet has been received, verifies that its type matches /*
that given, and gives a fatal error and exits if there is a mismatch. */ * Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
void packet_read_expect(int *payload_len_ptr, int type); void packet_read_expect(int *payload_len_ptr, int type);
/* Checks if a full packet is available in the data received so far via /*
packet_process_incoming. If so, reads the packet; otherwise returns * Checks if a full packet is available in the data received so far via
SSH_MSG_NONE. This does not wait for data from the connection. * packet_process_incoming. If so, reads the packet; otherwise returns
* SSH_MSG_NONE. This does not wait for data from the connection.
SSH_MSG_DISCONNECT is handled specially here. Also, * SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
SSH_MSG_IGNORE messages are skipped by this function and are never returned * messages are skipped by this function and are never returned to higher
to higher levels. */ * levels.
*/
int packet_read_poll(int *packet_len_ptr); int packet_read_poll(int *packet_len_ptr);
/* Buffers the given amount of input characters. This is intended to be /*
used together with packet_read_poll. */ * Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
*/
void packet_process_incoming(const char *buf, unsigned int len); void packet_process_incoming(const char *buf, unsigned int len);
/* Returns a character (0-255) from the packet data. */ /* Returns a character (0-255) from the packet data. */
@ -116,34 +131,41 @@ unsigned int packet_get_char(void);
/* Returns an integer from the packet data. */ /* Returns an integer from the packet data. */
unsigned int packet_get_int(void); unsigned int packet_get_int(void);
/* Returns an arbitrary precision integer from the packet data. The integer /*
must have been initialized before this call. */ * Returns an arbitrary precision integer from the packet data. The integer
* must have been initialized before this call.
*/
void packet_get_bignum(BIGNUM * value, int *length_ptr); void packet_get_bignum(BIGNUM * value, int *length_ptr);
/* Returns a string from the packet data. The string is allocated using /*
xmalloc; it is the responsibility of the calling program to free it when * Returns a string from the packet data. The string is allocated using
no longer needed. The length_ptr argument may be NULL, or point to an * xmalloc; it is the responsibility of the calling program to free it when
integer into which the length of the string is stored. */ * no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored.
*/
char *packet_get_string(unsigned int *length_ptr); char *packet_get_string(unsigned int *length_ptr);
/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect /*
packet, closes the connection, and exits. This function never returns. * Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
The error message should not contain a newline. The total length of the * packet, closes the connection, and exits. This function never returns.
message must not exceed 1024 bytes. */ * The error message should not contain a newline. The total length of the
* message must not exceed 1024 bytes.
*/
void packet_disconnect(const char *fmt,...); void packet_disconnect(const char *fmt,...);
/* Sends a diagnostic message to the other side. This message /*
can be sent at any time (but not while constructing another message). * Sends a diagnostic message to the other side. This message can be sent at
The message is printed immediately, but only if the client is being * any time (but not while constructing another message). The message is
executed in verbose mode. These messages are primarily intended to * printed immediately, but only if the client is being executed in verbose
ease debugging authentication problems. The total length of the message * mode. These messages are primarily intended to ease debugging
must not exceed 1024 bytes. This will automatically call * authentication problems. The total length of the message must not exceed
packet_write_wait. If the remote side protocol flags do not indicate * 1024 bytes. This will automatically call packet_write_wait. If the
that it supports SSH_MSG_DEBUG, this will do nothing. */ * remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
* this will do nothing.
*/
void packet_send_debug(const char *fmt,...); void packet_send_debug(const char *fmt,...);
/* Checks if there is any buffered output, and tries to write some of the /* Checks if there is any buffered output, and tries to write some of the output. */
output. */
void packet_write_poll(void); void packet_write_poll(void);
/* Waits until all pending output data has been written. */ /* Waits until all pending output data has been written. */

44
pty.c
View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: pty.c,v 1.5 1999/11/25 00:54:59 damien Exp $");
#include "pty.h" #include "pty.h"
#include "ssh.h" #include "ssh.h"
@ -32,10 +32,12 @@ RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
#define O_NOCTTY 0 #define O_NOCTTY 0
#endif #endif
/* Allocates and opens a pty. Returns 0 if no pty could be allocated, /*
or nonzero if a pty was successfully allocated. On success, open file * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
descriptors for the pty and tty sides and the name of the tty side are * nonzero if a pty was successfully allocated. On success, open file
returned (the buffer must be able to hold at least 64 characters). */ * descriptors for the pty and tty sides and the name of the tty side are
* returned (the buffer must be able to hold at least 64 characters).
*/
int int
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
@ -52,8 +54,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
return 1; return 1;
#else /* HAVE_OPENPTY */ #else /* HAVE_OPENPTY */
#ifdef HAVE__GETPTY #ifdef HAVE__GETPTY
/* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates /*
more pty's automagically when needed */ * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
* pty's automagically when needed
*/
char *slave; char *slave;
slave = _getpty(ptyfd, O_RDWR, 0622, 0); slave = _getpty(ptyfd, O_RDWR, 0622, 0);
@ -72,8 +76,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
return 1; return 1;
#else /* HAVE__GETPTY */ #else /* HAVE__GETPTY */
#ifdef HAVE_DEV_PTMX #ifdef HAVE_DEV_PTMX
/* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 /*
also has bsd-style ptys, but they simply do not work.) */ * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
* also has bsd-style ptys, but they simply do not work.)
*/
int ptm; int ptm;
char *pts; char *pts;
@ -103,8 +109,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
close(*ptyfd); close(*ptyfd);
return 0; return 0;
} }
/* Push the appropriate streams modules, as described in Solaris /* Push the appropriate streams modules, as described in Solaris pts(7). */
pts(7). */
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
error("ioctl I_PUSH ptem: %.100s", strerror(errno)); error("ioctl I_PUSH ptem: %.100s", strerror(errno));
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
@ -138,8 +143,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
/* BSD-style pty code. */ /* BSD-style pty code. */
char buf[64]; char buf[64];
int i; int i;
const char *ptymajors = const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
"pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *ptyminors = "0123456789abcdef"; const char *ptyminors = "0123456789abcdef";
int num_minors = strlen(ptyminors); int num_minors = strlen(ptyminors);
int num_ptys = strlen(ptymajors) * num_minors; int num_ptys = strlen(ptymajors) * num_minors;
@ -198,8 +202,10 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
if (setsid() < 0) if (setsid() < 0)
error("setsid: %.100s", strerror(errno)); error("setsid: %.100s", strerror(errno));
/* Verify that we are successfully disconnected from the /*
controlling tty. */ * Verify that we are successfully disconnected from the controlling
* tty.
*/
fd = open("/dev/tty", O_RDWR | O_NOCTTY); fd = open("/dev/tty", O_RDWR | O_NOCTTY);
if (fd >= 0) { if (fd >= 0) {
error("Failed to disconnect from controlling tty."); error("Failed to disconnect from controlling tty.");
@ -208,9 +214,11 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
/* Make it our controlling tty. */ /* Make it our controlling tty. */
#ifdef TIOCSCTTY #ifdef TIOCSCTTY
debug("Setting controlling tty using TIOCSCTTY."); debug("Setting controlling tty using TIOCSCTTY.");
/* We ignore errors from this, because HPSUX defines TIOCSCTTY, /*
but returns EINVAL with these arguments, and there is * We ignore errors from this, because HPSUX defines TIOCSCTTY, but
absolutely no documentation. */ * returns EINVAL with these arguments, and there is absolutely no
* documentation.
*/
ioctl(*ttyfd, TIOCSCTTY, NULL); ioctl(*ttyfd, TIOCSCTTY, NULL);
#endif /* TIOCSCTTY */ #endif /* TIOCSCTTY */
fd = open(ttyname, O_RDWR); fd = open(ttyname, O_RDWR);

24
pty.h
View File

@ -13,23 +13,29 @@
* tty. * tty.
*/ */
/* RCSID("$Id: pty.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: pty.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
#ifndef PTY_H #ifndef PTY_H
#define PTY_H #define PTY_H
/* Allocates and opens a pty. Returns 0 if no pty could be allocated, /*
or nonzero if a pty was successfully allocated. On success, open file * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
descriptors for the pty and tty sides and the name of the tty side are * nonzero if a pty was successfully allocated. On success, open file
returned (the buffer must be able to hold at least 64 characters). */ * descriptors for the pty and tty sides and the name of the tty side are
* returned (the buffer must be able to hold at least 64 characters).
*/
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname); int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
/* Releases the tty. Its ownership is returned to root, and permissions to /*
0666. */ * Releases the tty. Its ownership is returned to root, and permissions to
* 0666.
*/
void pty_release(const char *ttyname); void pty_release(const char *ttyname);
/* Makes the tty the processes controlling tty and sets it to sane modes. /*
This may need to reopen the tty to get rid of possible eavesdroppers. */ * Makes the tty the processes controlling tty and sets it to sane modes.
* This may need to reopen the tty to get rid of possible eavesdroppers.
*/
void pty_make_controlling_tty(int *ttyfd, const char *ttyname); void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
/* Changes the window size associated with the pty. */ /* Changes the window size associated with the pty. */

View File

@ -74,9 +74,11 @@ uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
while (*bufcoded == ' ' || *bufcoded == '\t') while (*bufcoded == ' ' || *bufcoded == '\t')
bufcoded++; bufcoded++;
/* Figure out how many characters are in the input buffer. If this /*
would decode into more bytes than would fit into the output * Figure out how many characters are in the input buffer. If this
buffer, adjust the number of input bytes downwards. */ * would decode into more bytes than would fit into the output
* buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded; bufin = bufcoded;
while (DEC(*(bufin++)) <= MAXVAL); while (DEC(*(bufin++)) <= MAXVAL);
nprbytes = bufin - bufcoded - 1; nprbytes = bufin - bufcoded - 1;

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: readconf.c,v 1.5 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: readconf.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "cipher.h" #include "cipher.h"
@ -158,8 +158,10 @@ static struct {
#define WHITESPACE " \t\r\n" #define WHITESPACE " \t\r\n"
/* Adds a local TCP/IP port forward to options. Never returns if there /*
is an error. */ * Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void void
add_local_forward(Options *options, int port, const char *host, add_local_forward(Options *options, int port, const char *host,
@ -179,8 +181,10 @@ add_local_forward(Options *options, int port, const char *host,
fwd->host_port = host_port; fwd->host_port = host_port;
} }
/* Adds a remote TCP/IP port forward to options. Never returns if there /*
is an error. */ * Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void void
add_remote_forward(Options *options, int port, const char *host, add_remote_forward(Options *options, int port, const char *host,
@ -196,8 +200,10 @@ add_remote_forward(Options *options, int port, const char *host,
fwd->host_port = host_port; fwd->host_port = host_port;
} }
/* Returns the number of the token pointed to by cp of length len. /*
Never returns if the token is not known. */ * Returns the number of the token pointed to by cp of length len. Never
* returns if the token is not known.
*/
static OpCodes static OpCodes
parse_token(const char *cp, const char *filename, int linenum) parse_token(const char *cp, const char *filename, int linenum)
@ -205,7 +211,7 @@ parse_token(const char *cp, const char *filename, int linenum)
unsigned int i; unsigned int i;
for (i = 0; keywords[i].name; i++) for (i = 0; keywords[i].name; i++)
if (strcmp(cp, keywords[i].name) == 0) if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode; return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
@ -213,15 +219,17 @@ parse_token(const char *cp, const char *filename, int linenum)
return oBadOption; return oBadOption;
} }
/* Processes a single option line as used in the configuration files. /*
This only sets those values that have not already been set. */ * Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set.
*/
int int
process_config_line(Options *options, const char *host, process_config_line(Options *options, const char *host,
char *line, const char *filename, int linenum, char *line, const char *filename, int linenum,
int *activep) int *activep)
{ {
char buf[256], *cp, *string, **charptr; char buf[256], *cp, *string, **charptr, *cp2;
int opcode, *intptr, value, fwd_port, fwd_host_port; int opcode, *intptr, value, fwd_port, fwd_host_port;
/* Skip leading whitespace. */ /* Skip leading whitespace. */
@ -229,21 +237,14 @@ process_config_line(Options *options, const char *host,
if (!*cp || *cp == '\n' || *cp == '#') if (!*cp || *cp == '\n' || *cp == '#')
return 0; return 0;
/* Get the keyword. (Each line is supposed to begin with a /* Get the keyword. (Each line is supposed to begin with a keyword). */
keyword). */
cp = strtok(cp, WHITESPACE); cp = strtok(cp, WHITESPACE);
{
char *t = cp;
for (; *t != 0; t++)
if ('A' <= *t && *t <= 'Z')
*t = *t - 'A' + 'a'; /* tolower */
}
opcode = parse_token(cp, filename, linenum); opcode = parse_token(cp, filename, linenum);
switch (opcode) { switch (opcode) {
case oBadOption: case oBadOption:
return -1; /* don't panic, but count bad options */ /* don't panic, but count bad options */
return -1;
/* NOTREACHED */ /* NOTREACHED */
case oForwardAgent: case oForwardAgent:
intptr = &options->forward_agent; intptr = &options->forward_agent;
@ -419,17 +420,11 @@ parse_int:
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (cp[0] < '0' || cp[0] > '9') if (cp[0] < '0' || cp[0] > '9')
fatal("%.200s line %d: Bad number.", filename, linenum); fatal("%.200s line %d: Bad number.", filename, linenum);
#if 0
value = atoi(cp); /* Octal, decimal, or hex format? */
#else value = strtol(cp, &cp2, 0);
{ if (cp == cp2)
char *ptr;
value = strtol(cp, &ptr, 0); /* Octal, decimal, or
hex format? */
if (cp == ptr)
fatal("%.200s line %d: Bad number.", filename, linenum); fatal("%.200s line %d: Bad number.", filename, linenum);
}
#endif
if (*activep && *intptr == -1) if (*activep && *intptr == -1)
*intptr = value; *intptr = value;
break; break;
@ -506,8 +501,7 @@ parse_int:
*activep = 1; *activep = 1;
break; break;
} }
/* Avoid garbage check below, as strtok already returned /* Avoid garbage check below, as strtok already returned NULL. */
NULL. */
return 0; return 0;
case oEscapeChar: case oEscapeChar:
@ -544,9 +538,11 @@ parse_int:
} }
/* Reads the config file and modifies the options accordingly. Options should /*
already be initialized before this call. This never returns if there * Reads the config file and modifies the options accordingly. Options
is an error. If the file does not exist, this returns immediately. */ * should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
*/
void void
read_config_file(const char *filename, const char *host, Options *options) read_config_file(const char *filename, const char *host, Options *options)
@ -563,8 +559,10 @@ read_config_file(const char *filename, const char *host, Options *options)
debug("Reading configuration data %.200s", filename); debug("Reading configuration data %.200s", filename);
/* Mark that we are now processing the options. This flag is /*
turned on/off by Host specifications. */ * Mark that we are now processing the options. This flag is turned
* on/off by Host specifications.
*/
active = 1; active = 1;
linenum = 0; linenum = 0;
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
@ -579,10 +577,12 @@ read_config_file(const char *filename, const char *host, Options *options)
filename, bad_options); filename, bad_options);
} }
/* Initializes options to special values that indicate that they have not /*
yet been set. Read_config_file will only set options with this value. * Initializes options to special values that indicate that they have not yet
Options are processed in the following order: command line, user config * been set. Read_config_file will only set options with this value. Options
file, system config file. Last, fill_default_options is called. */ * are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void void
initialize_options(Options * options) initialize_options(Options * options)
@ -628,8 +628,10 @@ initialize_options(Options * options)
options->log_level = (LogLevel) - 1; options->log_level = (LogLevel) - 1;
} }
/* Called after processing other sources of option data, this fills those /*
options for which no value has been specified with their default values. */ * Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
void void
fill_default_options(Options * options) fill_default_options(Options * options)

View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: readconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: readconf.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
#ifndef READCONF_H #ifndef READCONF_H
#define READCONF_H #define READCONF_H
@ -85,42 +85,53 @@ typedef struct {
} Options; } Options;
/* Initializes options to special values that indicate that they have not /*
yet been set. Read_config_file will only set options with this value. * Initializes options to special values that indicate that they have not yet
Options are processed in the following order: command line, user config * been set. Read_config_file will only set options with this value. Options
file, system config file. Last, fill_default_options is called. */ * are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void initialize_options(Options * options); void initialize_options(Options * options);
/* Called after processing other sources of option data, this fills those /*
options for which no value has been specified with their default values. */ * Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
void fill_default_options(Options * options); void fill_default_options(Options * options);
/* Processes a single option line as used in the configuration files. /*
This only sets those values that have not already been set. * Processes a single option line as used in the configuration files. This
Returns 0 for legal options */ * only sets those values that have not already been set. Returns 0 for legal
* options
*/
int int
process_config_line(Options * options, const char *host, process_config_line(Options * options, const char *host,
char *line, const char *filename, int linenum, char *line, const char *filename, int linenum,
int *activep); int *activep);
/* Reads the config file and modifies the options accordingly. Options should /*
already be initialized before this call. This never returns if there * Reads the config file and modifies the options accordingly. Options
is an error. If the file does not exist, this returns immediately. */ * should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
*/
void void
read_config_file(const char *filename, const char *host, read_config_file(const char *filename, const char *host,
Options * options); Options * options);
/* Adds a local TCP/IP port forward to options. Never returns if there /*
is an error. */ * Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void void
add_local_forward(Options * options, int port, const char *host, add_local_forward(Options * options, int port, const char *host,
int host_port); int host_port);
/* Adds a remote TCP/IP port forward to options. Never returns if there /*
is an error. */ * Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void void
add_remote_forward(Options * options, int port, const char *host, add_remote_forward(Options * options, int port, const char *host,
int host_port); int host_port);
#endif /* READCONF_H */ #endif /* READCONF_H */

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: readpass.c,v 1.2 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: readpass.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -38,10 +38,12 @@ intr_handler(int sig)
kill(getpid(), sig); kill(getpid(), sig);
} }
/* Reads a passphrase from /dev/tty with echo turned off. Returns the /*
passphrase (allocated with xmalloc). Exits if EOF is encountered. * Reads a passphrase from /dev/tty with echo turned off. Returns the
The passphrase if read from stdin if from_stdin is true (as is the * passphrase (allocated with xmalloc). Exits if EOF is encountered. The
case with ssh-keygen). */ * passphrase if read from stdin if from_stdin is true (as is the case with
* ssh-keygen).
*/
char * char *
read_passphrase(const char *prompt, int from_stdin) read_passphrase(const char *prompt, int from_stdin)
@ -53,8 +55,10 @@ read_passphrase(const char *prompt, int from_stdin)
if (from_stdin) if (from_stdin)
f = stdin; f = stdin;
else { else {
/* Read the passphrase from /dev/tty to make it possible /*
to ask it even when stdin has been redirected. */ * Read the passphrase from /dev/tty to make it possible to
* ask it even when stdin has been redirected.
*/
f = fopen("/dev/tty", "r"); f = fopen("/dev/tty", "r");
if (!f) { if (!f) {
/* No controlling terminal and no DISPLAY. Nowhere to read. */ /* No controlling terminal and no DISPLAY. Nowhere to read. */
@ -101,8 +105,10 @@ read_passphrase(const char *prompt, int from_stdin)
*strchr(buf, '\n') = 0; *strchr(buf, '\n') = 0;
/* Allocate a copy of the passphrase. */ /* Allocate a copy of the passphrase. */
cp = xstrdup(buf); cp = xstrdup(buf);
/* Clear the buffer so we don\'t leave copies of the passphrase /*
laying around. */ * Clear the buffer so we don\'t leave copies of the passphrase
* laying around.
*/
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
/* Print a newline since the prompt probably didn\'t have one. */ /* Print a newline since the prompt probably didn\'t have one. */
fprintf(stderr, "\n"); fprintf(stderr, "\n");

10
rsa.c
View File

@ -35,7 +35,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: rsa.c,v 1.4 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: rsa.c,v 1.5 1999/11/25 00:54:59 damien Exp $");
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh.h"
@ -55,9 +55,11 @@ rsa_alive()
return (1); return (1);
} }
/* Generates RSA public and private keys. This initializes the data /*
structures; they should be freed with rsa_clear_private_key and * Generates RSA public and private keys. This initializes the data
rsa_clear_public_key. */ * structures; they should be freed with rsa_clear_private_key and
* rsa_clear_public_key.
*/
void void
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits) rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)

8
rsa.h
View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: rsa.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
#ifndef RSA_H #ifndef RSA_H
#define RSA_H #define RSA_H
@ -33,8 +33,10 @@
/* Calls SSL RSA_generate_key, only copies to prv and pub */ /* Calls SSL RSA_generate_key, only copies to prv and pub */
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits); void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
/* Indicates whether the rsa module is permitted to show messages on /*
the terminal. */ * Indicates whether the rsa module is permitted to show messages on the
* terminal.
*/
void rsa_set_verbose __P((int verbose)); void rsa_set_verbose __P((int verbose));
int rsa_alive __P((void)); int rsa_alive __P((void));

20
scp.c
View File

@ -45,7 +45,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: scp.c,v 1.10 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -97,9 +97,11 @@ char *identity = NULL;
/* This is the port to use in contacting the remote site (is non-NULL). */ /* This is the port to use in contacting the remote site (is non-NULL). */
char *port = NULL; char *port = NULL;
/* This function executes the given command as the specified user on the given /*
host. This returns < 0 if execution fails, and >= 0 otherwise. * This function executes the given command as the specified user on the
This assigns the input and output file descriptors on success. */ * given host. This returns < 0 if execution fails, and >= 0 otherwise. This
* assigns the input and output file descriptors on success.
*/
int int
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
@ -110,8 +112,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
fprintf(stderr, "Executing: host %s, user %s, command %s\n", fprintf(stderr, "Executing: host %s, user %s, command %s\n",
host, remuser ? remuser : "(unspecified)", cmd); host, remuser ? remuser : "(unspecified)", cmd);
/* Reserve two descriptors so that the real pipes won't get /*
descriptors 0 and 1 because that will screw up dup2 below. */ * Reserve two descriptors so that the real pipes won't get
* descriptors 0 and 1 because that will screw up dup2 below.
*/
pipe(reserved); pipe(reserved);
/* Create a socket pair for communicating with ssh. */ /* Create a socket pair for communicating with ssh. */
@ -970,7 +974,7 @@ run_err(const char *fmt,...)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $ * $Id: scp.c,v 1.10 1999/11/25 00:54:59 damien Exp $
*/ */
char * char *
@ -1142,7 +1146,7 @@ progressmeter(int flag)
(void) gettimeofday(&now, (struct timezone *) 0); (void) gettimeofday(&now, (struct timezone *) 0);
cursize = statbytes; cursize = statbytes;
if (totalbytes != 0) { if (totalbytes != 0) {
ratio = cursize * 100.0 / totalbytes; ratio = 100.0 * cursize / totalbytes;
ratio = MAX(ratio, 0); ratio = MAX(ratio, 0);
ratio = MIN(ratio, 100); ratio = MIN(ratio, 100);
} else } else

View File

@ -12,7 +12,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: servconf.c,v 1.6 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: servconf.c,v 1.7 1999/11/25 00:54:59 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "servconf.h" #include "servconf.h"
@ -212,8 +212,10 @@ static struct {
{ NULL, 0 } { NULL, 0 }
}; };
/* Returns the number of the token pointed to by cp of length len. /*
Never returns if the token is not known. */ * Returns the number of the token pointed to by cp of length len. Never
* returns if the token is not known.
*/
static ServerOpCodes static ServerOpCodes
parse_token(const char *cp, const char *filename, parse_token(const char *cp, const char *filename,
@ -222,7 +224,7 @@ parse_token(const char *cp, const char *filename,
unsigned int i; unsigned int i;
for (i = 0; keywords[i].name; i++) for (i = 0; keywords[i].name; i++)
if (strcmp(cp, keywords[i].name) == 0) if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode; return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
@ -254,13 +256,6 @@ read_server_config(ServerOptions *options, const char *filename)
if (!*cp || *cp == '#') if (!*cp || *cp == '#')
continue; continue;
cp = strtok(cp, WHITESPACE); cp = strtok(cp, WHITESPACE);
{
char *t = cp;
for (; *t != 0; t++)
if ('A' <= *t && *t <= 'Z')
*t = *t - 'A' + 'a'; /* tolower */
}
opcode = parse_token(cp, filename, linenum); opcode = parse_token(cp, filename, linenum);
switch (opcode) { switch (opcode) {
case sBadOption: case sBadOption:

View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: servconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */ /* RCSID("$Id: servconf.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
#ifndef SERVCONF_H #ifndef SERVCONF_H
#define SERVCONF_H #define SERVCONF_H
@ -84,12 +84,16 @@ typedef struct {
unsigned int num_deny_groups; unsigned int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS]; char *deny_groups[MAX_DENY_GROUPS];
} ServerOptions; } ServerOptions;
/* Initializes the server options to special values that indicate that they /*
have not yet been set. */ * Initializes the server options to special values that indicate that they
* have not yet been set.
*/
void initialize_server_options(ServerOptions * options); void initialize_server_options(ServerOptions * options);
/* Reads the server configuration file. This only sets the values for those /*
options that have the special value indicating they have not been set. */ * Reads the server configuration file. This only sets the values for those
* options that have the special value indicating they have not been set.
*/
void read_server_config(ServerOptions * options, const char *filename); void read_server_config(ServerOptions * options, const char *filename);
/* Sets values for those values that have not yet been set. */ /* Sets values for those values that have not yet been set. */

View File

@ -33,8 +33,10 @@ static int connection_out; /* Connection to client (output). */
static unsigned int buffer_high;/* "Soft" max buffer size. */ static unsigned int buffer_high;/* "Soft" max buffer size. */
static int max_fd; /* Max file descriptor number for select(). */ static int max_fd; /* Max file descriptor number for select(). */
/* This SIGCHLD kludge is used to detect when the child exits. The server /*
will exit after that, as soon as forwarded connections have terminated. */ * This SIGCHLD kludge is used to detect when the child exits. The server
* will exit after that, as soon as forwarded connections have terminated.
*/
static int child_pid; /* Pid of the child. */ static int child_pid; /* Pid of the child. */
static volatile int child_terminated; /* The child has terminated. */ static volatile int child_terminated; /* The child has terminated. */
@ -87,9 +89,11 @@ process_buffered_input_packets()
break; break;
case SSH_CMSG_EOF: case SSH_CMSG_EOF:
/* Eof from the client. The stdin descriptor to /*
the program will be closed when all buffered * Eof from the client. The stdin descriptor to the
data has drained. */ * program will be closed when all buffered data has
* drained.
*/
debug("EOF received for stdin."); debug("EOF received for stdin.");
packet_integrity_check(payload_len, 0, type); packet_integrity_check(payload_len, 0, type);
stdin_eof = 1; stdin_eof = 1;
@ -140,13 +144,15 @@ process_buffered_input_packets()
break; break;
default: default:
/* In this phase, any unexpected messages cause a /*
protocol error. This is to ease debugging; * In this phase, any unexpected messages cause a
also, since no confirmations are sent messages, * protocol error. This is to ease debugging; also,
unprocessed unknown messages could cause * since no confirmations are sent messages,
strange problems. Any compatible protocol * unprocessed unknown messages could cause strange
extensions must be negotiated before entering * problems. Any compatible protocol extensions must
the interactive session. */ * be negotiated before entering the interactive
* session.
*/
packet_disconnect("Protocol error during session: type %d", packet_disconnect("Protocol error during session: type %d",
type); type);
} }
@ -230,14 +236,18 @@ retry_select:
/* Initialize select() masks. */ /* Initialize select() masks. */
FD_ZERO(readset); FD_ZERO(readset);
/* Read packets from the client unless we have too much buffered /*
stdin or channel data. */ * Read packets from the client unless we have too much buffered
* stdin or channel data.
*/
if (buffer_len(&stdin_buffer) < 4096 && if (buffer_len(&stdin_buffer) < 4096 &&
channel_not_very_much_buffered_data()) channel_not_very_much_buffered_data())
FD_SET(connection_in, readset); FD_SET(connection_in, readset);
/* If there is not too much data already buffered going to the /*
client, try to get some more data from the program. */ * If there is not too much data already buffered going to the
* client, try to get some more data from the program.
*/
if (packet_not_very_much_data_to_write()) { if (packet_not_very_much_data_to_write()) {
if (!fdout_eof) if (!fdout_eof)
FD_SET(fdout, readset); FD_SET(fdout, readset);
@ -249,8 +259,10 @@ retry_select:
/* Set masks for channel descriptors. */ /* Set masks for channel descriptors. */
channel_prepare_select(readset, writeset); channel_prepare_select(readset, writeset);
/* If we have buffered packet data going to the client, mark that /*
descriptor. */ * If we have buffered packet data going to the client, mark that
* descriptor.
*/
if (packet_have_data_to_write()) if (packet_have_data_to_write())
FD_SET(connection_out, writeset); FD_SET(connection_out, writeset);
@ -263,8 +275,10 @@ retry_select:
if (channel_max_fd() > max_fd) if (channel_max_fd() > max_fd)
max_fd = channel_max_fd(); max_fd = channel_max_fd();
/* If child has terminated and there is enough buffer space to /*
read from it, then read as much as is available and exit. */ * If child has terminated and there is enough buffer space to read
* from it, then read as much as is available and exit.
*/
if (child_terminated && packet_not_very_much_data_to_write()) if (child_terminated && packet_not_very_much_data_to_write())
if (max_time_milliseconds == 0) if (max_time_milliseconds == 0)
max_time_milliseconds = 100; max_time_milliseconds = 100;
@ -305,9 +319,10 @@ process_input(fd_set * readset)
verbose("Connection closed by remote host."); verbose("Connection closed by remote host.");
fatal_cleanup(); fatal_cleanup();
} }
/* There is a kernel bug on Solaris that causes select to /*
sometimes wake up even though there is no data * There is a kernel bug on Solaris that causes select to
available. */ * sometimes wake up even though there is no data available.
*/
if (len < 0 && errno == EAGAIN) if (len < 0 && errno == EAGAIN)
len = 0; len = 0;
@ -456,11 +471,12 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
buffer_init(&stdout_buffer); buffer_init(&stdout_buffer);
buffer_init(&stderr_buffer); buffer_init(&stderr_buffer);
/* If we have no separate fderr (which is the case when we have a /*
pty - there we cannot make difference between data sent to * If we have no separate fderr (which is the case when we have a pty
stdout and stderr), indicate that we have seen an EOF from * - there we cannot make difference between data sent to stdout and
stderr. This way we don\'t need to check the descriptor * stderr), indicate that we have seen an EOF from stderr. This way
everywhere. */ * we don\'t need to check the descriptor everywhere.
*/
if (fderr == -1) if (fderr == -1)
fderr_eof = 1; fderr_eof = 1;
@ -471,8 +487,10 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* Process buffered packets from the client. */ /* Process buffered packets from the client. */
process_buffered_input_packets(); process_buffered_input_packets();
/* If we have received eof, and there is no more pending /*
input data, cause a real eof by closing fdin. */ * If we have received eof, and there is no more pending
* input data, cause a real eof by closing fdin.
*/
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
#ifdef USE_PIPES #ifdef USE_PIPES
close(fdin); close(fdin);
@ -484,16 +502,16 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
#endif #endif
fdin = -1; fdin = -1;
} }
/* Make packets from buffered stderr data to send to the /* Make packets from buffered stderr data to send to the client. */
client. */
make_packets_from_stderr_data(); make_packets_from_stderr_data();
/* Make packets from buffered stdout data to send to the /*
client. If there is very little to send, this arranges * Make packets from buffered stdout data to send to the
to not send them now, but to wait a short while to see * client. If there is very little to send, this arranges to
if we are getting more data. This is necessary, as some * not send them now, but to wait a short while to see if we
systems wake up readers from a pty after each separate * are getting more data. This is necessary, as some systems
character. */ * wake up readers from a pty after each separate character.
*/
max_time_milliseconds = 0; max_time_milliseconds = 0;
stdout_buffer_bytes = buffer_len(&stdout_buffer); stdout_buffer_bytes = buffer_len(&stdout_buffer);
if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
@ -510,9 +528,11 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
if (packet_not_very_much_data_to_write()) if (packet_not_very_much_data_to_write())
channel_output_poll(); channel_output_poll();
/* Bail out of the loop if the program has closed its /*
output descriptors, and we have no more data to send to * Bail out of the loop if the program has closed its output
the client, and there is no pending buffered data. */ * descriptors, and we have no more data to send to the
* client, and there is no pending buffered data.
*/
if (fdout_eof && fderr_eof && !packet_have_data_to_write() && if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
if (!channel_still_open()) if (!channel_still_open())
@ -604,11 +624,13 @@ quit:
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
/* Wait for exit confirmation. Note that there might be /*
other packets coming before it; however, the program * Wait for exit confirmation. Note that there might be
has already died so we just ignore them. The client is * other packets coming before it; however, the program has
supposed to respond with the confirmation when it * already died so we just ignore them. The client is
receives the exit status. */ * supposed to respond with the confirmation when it receives
* the exit status.
*/
do { do {
int plen; int plen;
type = packet_read(&plen); type = packet_read(&plen);

View File

@ -9,7 +9,7 @@
.\" .\"
.\" Created: Sat Apr 22 23:55:14 1995 ylo .\" Created: Sat Apr 22 23:55:14 1995 ylo
.\" .\"
.\" $Id: ssh-add.1,v 1.4 1999/11/17 06:29:08 damien Exp $ .\" $Id: ssh-add.1,v 1.5 1999/11/25 00:54:59 damien Exp $
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
.Dt SSH-ADD 1 .Dt SSH-ADD 1
@ -71,8 +71,11 @@ terminal if it was run from a terminal. If
.Nm .Nm
does not have a terminal associated with it but does not have a terminal associated with it but
.Ev DISPLAY .Ev DISPLAY
is set, it and
will open an X11 window to read the passphrase. This is particularly .Ev SSH_ASKPASS
are set, it will execute the program specified by
.Ev SSH_ASKPASS
and open an X11 window to read the passphrase. This is particularly
useful when calling useful when calling
.Nm .Nm
from a from a

161
ssh-add.c
View File

@ -7,7 +7,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $"); RCSID("$Id: ssh-add.c,v 1.14 1999/11/25 00:54:59 damien Exp $");
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh.h"
@ -15,10 +15,6 @@ RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $");
#include "authfd.h" #include "authfd.h"
#include "fingerprint.h" #include "fingerprint.h"
#ifdef USE_EXTERNAL_ASKPASS
int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment);
#endif /* USE_EXTERNAL_ASKPASS */
#ifdef HAVE___PROGNAME #ifdef HAVE___PROGNAME
extern char *__progname; extern char *__progname;
#else /* HAVE___PROGNAME */ #else /* HAVE___PROGNAME */
@ -54,13 +50,53 @@ delete_all(AuthenticationConnection *ac)
fprintf(stderr, "Failed to remove all identitities.\n"); fprintf(stderr, "Failed to remove all identitities.\n");
} }
char *
ssh_askpass(char *askpass, char *msg)
{
pid_t pid;
size_t len;
char *nl, *pass;
int p[2], status;
char buf[1024];
if (askpass == NULL)
fatal("internal error: askpass undefined");
if (pipe(p) < 0)
fatal("ssh_askpass: pipe: %s", strerror(errno));
if ((pid = fork()) < 0)
fatal("ssh_askpass: fork: %s", strerror(errno));
if (pid == 0) {
close(p[0]);
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));
}
close(p[1]);
len = read(p[0], buf, sizeof buf);
close(p[0]);
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
if (len <= 1)
return xstrdup("");
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
pass = xstrdup(buf);
memset(buf, 0, sizeof(buf));
return pass;
}
void void
add_file(AuthenticationConnection *ac, const char *filename) add_file(AuthenticationConnection *ac, const char *filename)
{ {
RSA *key; RSA *key;
RSA *public_key; RSA *public_key;
char *saved_comment, *comment; char *saved_comment, *comment, *askpass = NULL;
char buf[1024], msg[1024];
int success; int success;
int interactive = isatty(STDIN_FILENO);
key = RSA_new(); key = RSA_new();
public_key = RSA_new(); public_key = RSA_new();
@ -70,29 +106,26 @@ add_file(AuthenticationConnection *ac, const char *filename)
} }
RSA_free(public_key); RSA_free(public_key);
if (!interactive && getenv("DISPLAY"))
askpass = getenv("SSH_ASKPASS");
/* At first, try empty passphrase */ /* At first, try empty passphrase */
success = load_private_key(filename, "", key, &comment); success = load_private_key(filename, "", key, &comment);
if (!success) { if (!success) {
printf("Need passphrase for %s (%s).\n", filename, saved_comment); printf("Need passphrase for %.200s\n", filename);
if (!isatty(STDIN_FILENO)) { if (!interactive && askpass == NULL) {
#ifdef USE_EXTERNAL_ASKPASS
int prompts = 3;
while (prompts && !success) {
success = askpass(filename, key, saved_comment, &comment);
prompts--;
}
if (!success) {
xfree(saved_comment); xfree(saved_comment);
return; return;
} }
#else /* !USE_EXTERNAL_ASKPASS */ snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
xfree(saved_comment); for (;;) {
return; char *pass;
#endif /* USE_EXTERNAL_ASKPASS */ if (interactive) {
snprintf(buf, sizeof buf, "%s: ", msg);
pass = read_passphrase(buf, 1);
} else {
pass = ssh_askpass(askpass, msg);
} }
while (!success) {
char *pass = read_passphrase("Enter passphrase: ", 1);
if (strcmp(pass, "") == 0) { if (strcmp(pass, "") == 0) {
xfree(pass); xfree(pass);
xfree(saved_comment); xfree(saved_comment);
@ -103,7 +136,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
xfree(pass); xfree(pass);
if (success) if (success)
break; break;
printf("Bad passphrase.\n"); strlcpy(msg, "Bad passphrase, try again", sizeof msg);
} }
} }
xfree(saved_comment); xfree(saved_comment);
@ -222,85 +255,3 @@ main(int argc, char **argv)
ssh_close_authentication_connection(ac); ssh_close_authentication_connection(ac);
exit(0); exit(0);
} }
#ifdef USE_EXTERNAL_ASKPASS
int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
{
int pipes[2];
char buf[1024];
int tmp;
pid_t child;
FILE *pipef;
/* Check that we are X11-capable */
if (getenv("DISPLAY") == NULL)
exit(1);
if (pipe(pipes) == -1) {
fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
exit(1);
}
if (fflush(NULL) == EOF) {
fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
exit(1);
}
child = fork();
if (child == -1) {
fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
exit(1);
}
if (child == 0) {
/* In child */
close(pipes[0]);
if (dup2(pipes[1], 1) ==-1) {
fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
exit(1);
}
tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment);
/* skip the prompt if it won't fit */
if ((tmp < 0) || (tmp >= sizeof(buf)))
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
else
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
/* Shouldn't get this far */
fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
exit(1);
}
/* In parent */
close(pipes[1]);
if ((pipef = fdopen(pipes[0], "r")) == NULL) {
fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
exit(1);
}
/* Read passphrase back from child, abort if none presented */
if(fgets(buf, sizeof(buf), pipef) == NULL)
exit(1);
fclose(pipef);
if (strchr(buf, '\n'))
*strchr(buf, '\n') = 0;
if (waitpid(child, NULL, 0) == -1) {
fprintf(stderr, "Waiting for child failed: %s\n",
strerror(errno));
exit(1);
}
/* Try password as it was presented */
tmp = load_private_key(filename, buf, key, comment);
memset(buf, 0, sizeof(buf));
return(tmp);
}
#endif /* USE_EXTERNAL_ASKPASS */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $ */ /* $OpenBSD: ssh-agent.c,v 1.23 1999/11/24 19:53:51 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -9,7 +9,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $"); RCSID("$OpenBSD: ssh-agent.c,v 1.23 1999/11/24 19:53:51 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
@ -189,10 +189,12 @@ process_remove_identity(SocketEntry *e)
/* Check if we have the key. */ /* Check if we have the key. */
for (i = 0; i < num_identities; i++) for (i = 0; i < num_identities; i++)
if (BN_cmp(identities[i].key->n, n) == 0) { if (BN_cmp(identities[i].key->n, n) == 0) {
/* We have this key. Free the old key. Since we /*
don\'t want to leave empty slots in the middle * We have this key. Free the old key. Since we
of the array, we actually free the key there * don\'t want to leave empty slots in the middle of
and copy data from the last entry. */ * the array, we actually free the key there and copy
* data from the last entry.
*/
RSA_free(identities[i].key); RSA_free(identities[i].key);
xfree(identities[i].comment); xfree(identities[i].comment);
if (i < num_identities - 1) if (i < num_identities - 1)
@ -291,8 +293,10 @@ process_add_identity(SocketEntry *e)
/* Check if we already have the key. */ /* Check if we already have the key. */
for (i = 0; i < num_identities; i++) for (i = 0; i < num_identities; i++)
if (BN_cmp(identities[i].key->n, k->n) == 0) { if (BN_cmp(identities[i].key->n, k->n) == 0) {
/* We already have this key. Clear and free the /*
new data and return success. */ * We already have this key. Clear and free the new
* data and return success.
*/
RSA_free(k); RSA_free(k);
xfree(identities[num_identities].comment); xfree(identities[num_identities].comment);
@ -511,11 +515,7 @@ main(int ac, char **av)
__progname); __progname);
exit(1); exit(1);
} }
#if defined(__GNU_LIBRARY__)
while ((ch = getopt(ac, av, "+cks")) != -1) {
#else
while ((ch = getopt(ac, av, "cks")) != -1) { while ((ch = getopt(ac, av, "cks")) != -1) {
#endif /* defined(__GNU_LIBRARY__) */
switch (ch) { switch (ch) {
case 'c': case 'c':
if (s_flag) if (s_flag)
@ -579,8 +579,10 @@ main(int ac, char **av)
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
parent_pid); parent_pid);
/* Create socket early so it will exist before command gets run /*
from the parent. */ * Create socket early so it will exist before command gets run from
* the parent.
*/
sock = socket(AF_UNIX, SOCK_STREAM, 0); sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) { if (sock < 0) {
perror("socket"); perror("socket");
@ -597,9 +599,10 @@ main(int ac, char **av)
perror("listen"); perror("listen");
cleanup_exit(1); cleanup_exit(1);
} }
/* Fork, and have the parent execute the command, if any, or /*
present the socket data. The child continues as the * Fork, and have the parent execute the command, if any, or present
authentication agent. */ * the socket data. The child continues as the authentication agent.
*/
pid = fork(); pid = fork();
if (pid == -1) { if (pid == -1) {
perror("fork"); perror("fork");

View File

@ -7,7 +7,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh-keygen.c,v 1.9 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: ssh-keygen.c,v 1.10 1999/11/25 00:54:59 damien Exp $");
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh.h"
@ -20,16 +20,19 @@ RSA *private_key;
/* Generated public key. */ /* Generated public key. */
RSA *public_key; RSA *public_key;
/* Number of bits in the RSA key. This value can be changed on the command /* Number of bits in the RSA key. This value can be changed on the command line. */
line. */
int bits = 1024; int bits = 1024;
/* Flag indicating that we just want to change the passphrase. This can be /*
set on the command line. */ * Flag indicating that we just want to change the passphrase. This can be
* set on the command line.
*/
int change_passphrase = 0; int change_passphrase = 0;
/* Flag indicating that we just want to change the comment. This can be set /*
on the command line. */ * Flag indicating that we just want to change the comment. This can be set
* on the command line.
*/
int change_comment = 0; int change_comment = 0;
int quiet = 0; int quiet = 0;
@ -136,13 +139,10 @@ do_change_passphrase(struct passwd *pw)
if (!have_identity) if (!have_identity)
ask_filename(pw, "Enter file in which the key is"); ask_filename(pw, "Enter file in which the key is");
/* Check if the file exists. */
if (stat(identity_file, &st) < 0) { if (stat(identity_file, &st) < 0) {
perror(identity_file); perror(identity_file);
exit(1); exit(1);
} }
/* Try to load the public key from the file the verify that it is
readable and of the proper format. */
public_key = RSA_new(); public_key = RSA_new();
if (!load_public_key(identity_file, public_key, NULL)) { if (!load_public_key(identity_file, public_key, NULL)) {
printf("%s is not a valid key file.\n", identity_file); printf("%s is not a valid key file.\n", identity_file);
@ -154,19 +154,16 @@ do_change_passphrase(struct passwd *pw)
/* Try to load the file with empty passphrase. */ /* Try to load the file with empty passphrase. */
private_key = RSA_new(); private_key = RSA_new();
if (!load_private_key(identity_file, "", private_key, &comment)) { if (!load_private_key(identity_file, "", private_key, &comment)) {
/* Read passphrase from the user. */
if (identity_passphrase) if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase); old_passphrase = xstrdup(identity_passphrase);
else else
old_passphrase = read_passphrase("Enter old passphrase: ", 1); old_passphrase = read_passphrase("Enter old passphrase: ", 1);
/* Try to load using the passphrase. */
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) { if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
memset(old_passphrase, 0, strlen(old_passphrase)); memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase); xfree(old_passphrase);
printf("Bad passphrase.\n"); printf("Bad passphrase.\n");
exit(1); exit(1);
} }
/* Destroy the passphrase. */
memset(old_passphrase, 0, strlen(old_passphrase)); memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase); xfree(old_passphrase);
} }
@ -230,24 +227,24 @@ do_change_comment(struct passwd *pw)
if (!have_identity) if (!have_identity)
ask_filename(pw, "Enter file in which the key is"); ask_filename(pw, "Enter file in which the key is");
/* Check if the file exists. */
if (stat(identity_file, &st) < 0) { if (stat(identity_file, &st) < 0) {
perror(identity_file); perror(identity_file);
exit(1); exit(1);
} }
/* Try to load the public key from the file the verify that it is /*
readable and of the proper format. */ * Try to load the public key from the file the verify that it is
* readable and of the proper format.
*/
public_key = RSA_new(); public_key = RSA_new();
if (!load_public_key(identity_file, public_key, NULL)) { if (!load_public_key(identity_file, public_key, NULL)) {
printf("%s is not a valid key file.\n", identity_file); printf("%s is not a valid key file.\n", identity_file);
exit(1); exit(1);
} }
private_key = RSA_new(); private_key = RSA_new();
/* Try to load the file with empty passphrase. */
if (load_private_key(identity_file, "", private_key, &comment)) if (load_private_key(identity_file, "", private_key, &comment))
passphrase = xstrdup(""); passphrase = xstrdup("");
else { else {
/* Read passphrase from the user. */
if (identity_passphrase) if (identity_passphrase)
passphrase = xstrdup(identity_passphrase); passphrase = xstrdup(identity_passphrase);
else if (identity_new_passphrase) else if (identity_new_passphrase)
@ -274,7 +271,6 @@ do_change_comment(struct passwd *pw)
RSA_free(private_key); RSA_free(private_key);
exit(1); exit(1);
} }
/* Remove terminating newline from comment. */
if (strchr(new_comment, '\n')) if (strchr(new_comment, '\n'))
*strchr(new_comment, '\n') = 0; *strchr(new_comment, '\n') = 0;
} }
@ -289,13 +285,10 @@ do_change_comment(struct passwd *pw)
xfree(comment); xfree(comment);
exit(1); exit(1);
} }
/* Destroy the passphrase and the private key in memory. */
memset(passphrase, 0, strlen(passphrase)); memset(passphrase, 0, strlen(passphrase));
xfree(passphrase); xfree(passphrase);
RSA_free(private_key); RSA_free(private_key);
/* Save the public key in text format in a file with the same name
but .pub appended. */
strlcat(identity_file, ".pub", sizeof(identity_file)); strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w"); f = fopen(identity_file, "w");
if (!f) { if (!f) {
@ -343,21 +336,18 @@ main(int ac, char **av)
/* check if RSA support exists */ /* check if RSA support exists */
if (rsa_alive() == 0) { if (rsa_alive() == 0) {
extern char *__progname;
fprintf(stderr, fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n", "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname); __progname);
exit(1); exit(1);
} }
/* Get user\'s passwd structure. We need this for the home /* we need this for the home * directory. */
directory. */
pw = getpwuid(getuid()); pw = getpwuid(getuid());
if (!pw) { if (!pw) {
printf("You don't exist, go away!\n"); printf("You don't exist, go away!\n");
exit(1); exit(1);
} }
/* Parse command line arguments. */
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) { while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
switch (opt) { switch (opt) {
case 'b': case 'b':
@ -416,14 +406,8 @@ main(int ac, char **av)
} }
if (print_fingerprint) if (print_fingerprint)
do_fingerprint(pw); do_fingerprint(pw);
/* If the user requested to change the passphrase, do it now.
This function never returns. */
if (change_passphrase) if (change_passphrase)
do_change_passphrase(pw); do_change_passphrase(pw);
/* If the user requested to change the comment, do it now. This
function never returns. */
if (change_comment) if (change_comment)
do_change_comment(pw); do_change_comment(pw);
@ -484,11 +468,10 @@ passphrase_again:
xfree(passphrase2); xfree(passphrase2);
} }
/* Create default commend field for the passphrase. The user can
later edit this field. */
if (identity_comment) { if (identity_comment) {
strlcpy(comment, identity_comment, sizeof(comment)); strlcpy(comment, identity_comment, sizeof(comment));
} else { } else {
/* Create default commend field for the passphrase. */
if (gethostname(hostname, sizeof(hostname)) < 0) { if (gethostname(hostname, sizeof(hostname)) < 0) {
perror("gethostname"); perror("gethostname");
exit(1); exit(1);
@ -515,8 +498,6 @@ passphrase_again:
if (!quiet) if (!quiet)
printf("Your identification has been saved in %s.\n", identity_file); printf("Your identification has been saved in %s.\n", identity_file);
/* Save the public key in text format in a file with the same name
but .pub appended. */
strlcat(identity_file, ".pub", sizeof(identity_file)); strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w"); f = fopen(identity_file, "w");
if (!f) { if (!f) {

4
ssh.1
View File

@ -9,7 +9,7 @@
.\" .\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo .\" Created: Sat Apr 22 21:55:14 1995 ylo
.\" .\"
.\" $Id: ssh.1,v 1.9 1999/11/24 13:26:23 damien Exp $ .\" $Id: ssh.1,v 1.10 1999/11/25 00:54:59 damien Exp $
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
.Dt SSH 1 .Dt SSH 1
@ -293,7 +293,7 @@ disables any escapes and makes the session fully transparent.
.It Fl f .It Fl f
Requests Requests
.Nm .Nm
to go to background after authentication. This is useful to go to background just before command execution. This is useful
if if
.Nm .Nm
is going to ask for passwords or passphrases, but the user is going to ask for passwords or passphrases, but the user

179
ssh.c
View File

@ -11,7 +11,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh.c,v 1.11 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: ssh.c,v 1.12 1999/11/25 00:54:59 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -30,35 +30,43 @@ const char *__progname = "ssh";
/* Flag indicating whether debug mode is on. This can be set on the command line. */ /* Flag indicating whether debug mode is on. This can be set on the command line. */
int debug_flag = 0; int debug_flag = 0;
/* Flag indicating whether to allocate a pseudo tty. This can be set on the command
line, and is automatically set if no command is given on the command line. */
int tty_flag = 0; int tty_flag = 0;
/* Flag indicating that nothing should be read from stdin. This can be set /*
on the command line. */ * Flag indicating that nothing should be read from stdin. This can be set
* on the command line.
*/
int stdin_null_flag = 0; int stdin_null_flag = 0;
/* Flag indicating that ssh should fork after authentication. This is useful /*
so that the pasphrase can be entered manually, and then ssh goes to the * Flag indicating that ssh should fork after authentication. This is useful
background. */ * so that the pasphrase can be entered manually, and then ssh goes to the
* background.
*/
int fork_after_authentication_flag = 0; int fork_after_authentication_flag = 0;
/* General data structure for command line options and options configurable /*
in configuration files. See readconf.h. */ * General data structure for command line options and options configurable
* in configuration files. See readconf.h.
*/
Options options; Options options;
/* Name of the host we are connecting to. This is the name given on the /*
command line, or the HostName specified for the user-supplied name * Name of the host we are connecting to. This is the name given on the
in a configuration file. */ * command line, or the HostName specified for the user-supplied name in a
* configuration file.
*/
char *host; char *host;
/* socket address the host resolves to */ /* socket address the host resolves to */
struct sockaddr_in hostaddr; struct sockaddr_in hostaddr;
/* Flag to indicate that we have received a window change signal which has /*
not yet been processed. This will cause a message indicating the new * Flag to indicate that we have received a window change signal which has
window size to be sent to the server a little later. This is volatile * not yet been processed. This will cause a message indicating the new
because this is updated in a signal handler. */ * window size to be sent to the server a little later. This is volatile
* because this is updated in a signal handler.
*/
volatile int received_window_change_signal = 0; volatile int received_window_change_signal = 0;
/* Value of argv[0] (set in the main program). */ /* Value of argv[0] (set in the main program). */
@ -165,8 +173,10 @@ main(int ac, char **av)
uid_t original_effective_uid; uid_t original_effective_uid;
int plen; int plen;
/* Save the original real uid. It will be needed later /*
(uid-swapping may clobber the real uid). */ * Save the original real uid. It will be needed later (uid-swapping
* may clobber the real uid).
*/
original_real_uid = getuid(); original_real_uid = getuid();
original_effective_uid = geteuid(); original_effective_uid = geteuid();
@ -177,18 +187,21 @@ main(int ac, char **av)
if (setrlimit(RLIMIT_CORE, &rlim) < 0) if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fatal("setrlimit failed: %.100s", strerror(errno)); fatal("setrlimit failed: %.100s", strerror(errno));
} }
/* Use uid-swapping to give up root privileges for the duration of /*
option processing. We will re-instantiate the rights when we * Use uid-swapping to give up root privileges for the duration of
are ready to create the privileged port, and will permanently * option processing. We will re-instantiate the rights when we are
drop them when the port has been created (actually, when the * ready to create the privileged port, and will permanently drop
connection has been made, as we may need to create the port * them when the port has been created (actually, when the connection
several times). */ * has been made, as we may need to create the port several times).
*/
temporarily_use_uid(original_real_uid); temporarily_use_uid(original_real_uid);
/* Set our umask to something reasonable, as some files are /*
created with the default umask. This will make them * Set our umask to something reasonable, as some files are created
world-readable but writable only by the owner, which is ok for * with the default umask. This will make them world-readable but
all files for which we don't set the modes explicitly. */ * writable only by the owner, which is ok for all files for which we
* don't set the modes explicitly.
*/
umask(022); umask(022);
/* Save our own name. */ /* Save our own name. */
@ -387,10 +400,11 @@ main(int ac, char **av)
/* Initialize the command to execute on remote host. */ /* Initialize the command to execute on remote host. */
buffer_init(&command); buffer_init(&command);
/* Save the command to execute on the remote host in a buffer. /*
There is no limit on the length of the command, except by the * Save the command to execute on the remote host in a buffer. There
maximum packet size. Also sets the tty flag if there is no * is no limit on the length of the command, except by the maximum
command. */ * packet size. Also sets the tty flag if there is no command.
*/
if (optind == ac) { if (optind == ac) {
/* No command specified - execute shell on a tty. */ /* No command specified - execute shell on a tty. */
tty_flag = 1; tty_flag = 1;
@ -474,11 +488,15 @@ main(int ac, char **av)
options.rhosts_authentication = 0; options.rhosts_authentication = 0;
options.rhosts_rsa_authentication = 0; options.rhosts_rsa_authentication = 0;
} }
/* If using rsh has been selected, exec it now (without trying /*
anything else). Note that we must release privileges first. */ * If using rsh has been selected, exec it now (without trying
* anything else). Note that we must release privileges first.
*/
if (options.use_rsh) { if (options.use_rsh) {
/* Restore our superuser privileges. This must be done /*
before permanently setting the uid. */ * Restore our superuser privileges. This must be done
* before permanently setting the uid.
*/
restore_uid(); restore_uid();
/* Switch to the original uid permanently. */ /* Switch to the original uid permanently. */
@ -491,8 +509,10 @@ main(int ac, char **av)
/* Restore our superuser privileges. */ /* Restore our superuser privileges. */
restore_uid(); restore_uid();
/* Open a connection to the remote host. This needs root /*
privileges if rhosts_{rsa_}authentication is enabled. */ * Open a connection to the remote host. This needs root privileges
* if rhosts_{rsa_}authentication is enabled.
*/
ok = ssh_connect(host, &hostaddr, options.port, ok = ssh_connect(host, &hostaddr, options.port,
options.connection_attempts, options.connection_attempts,
@ -501,31 +521,38 @@ main(int ac, char **av)
original_real_uid, original_real_uid,
options.proxy_command); options.proxy_command);
/* If we successfully made the connection, load the host private /*
key in case we will need it later for combined rsa-rhosts * If we successfully made the connection, load the host private key
authentication. This must be done before releasing extra * in case we will need it later for combined rsa-rhosts
privileges, because the file is only readable by root. */ * authentication. This must be done before releasing extra
* privileges, because the file is only readable by root.
*/
if (ok) { if (ok) {
host_private_key = RSA_new(); host_private_key = RSA_new();
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL)) if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
host_private_key_loaded = 1; host_private_key_loaded = 1;
} }
/* Get rid of any extra privileges that we may have. We will no /*
longer need them. Also, extra privileges could make it very * Get rid of any extra privileges that we may have. We will no
hard to read identity files and other non-world-readable files * longer need them. Also, extra privileges could make it very hard
from the user's home directory if it happens to be on a NFS * to read identity files and other non-world-readable files from the
volume where root is mapped to nobody. */ * user's home directory if it happens to be on a NFS volume where
* root is mapped to nobody.
/* Note that some legacy systems need to postpone the following */
call to permanently_set_uid() until the private hostkey is
destroyed with RSA_free(). Otherwise the calling user could
ptrace() the process, read the private hostkey and impersonate
the host. OpenBSD does not allow ptracing of setuid processes. */
/*
* Note that some legacy systems need to postpone the following call
* to permanently_set_uid() until the private hostkey is destroyed
* with RSA_free(). Otherwise the calling user could ptrace() the
* process, read the private hostkey and impersonate the host.
* OpenBSD does not allow ptracing of setuid processes.
*/
permanently_set_uid(original_real_uid); permanently_set_uid(original_real_uid);
/* Now that we are back to our own permissions, create ~/.ssh /*
directory if it doesn\'t already exist. */ * Now that we are back to our own permissions, create ~/.ssh
* directory if it doesn\'t already exist.
*/
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR); snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
if (stat(buf, &st) < 0) if (stat(buf, &st) < 0)
if (mkdir(buf, 0755) < 0) if (mkdir(buf, 0755) < 0)
@ -569,15 +596,6 @@ main(int ac, char **av)
/* Close connection cleanly after attack. */ /* Close connection cleanly after attack. */
cipher_attack_detected = packet_disconnect; cipher_attack_detected = packet_disconnect;
/* If requested, fork and let ssh continue in the background. */
if (fork_after_authentication_flag) {
int ret = fork();
if (ret == -1)
fatal("fork failed: %.100s", strerror(errno));
if (ret != 0)
exit(0);
setsid();
}
/* Enable compression if requested. */ /* Enable compression if requested. */
if (options.compression) { if (options.compression) {
debug("Requesting compression at level %d.", options.compression_level); debug("Requesting compression at level %d.", options.compression_level);
@ -653,12 +671,14 @@ main(int ac, char **av)
if (f) if (f)
pclose(f); pclose(f);
#endif /* XAUTH_PATH */ #endif /* XAUTH_PATH */
/* If we didn't get authentication data, just make up some /*
data. The forwarding code will check the validity of * If we didn't get authentication data, just make up some
the response anyway, and substitute this data. The X11 * data. The forwarding code will check the validity of the
server, however, will ignore this fake data and use * response anyway, and substitute this data. The X11
whatever authentication mechanisms it was using * server, however, will ignore this fake data and use
otherwise for the local connection. */ * whatever authentication mechanisms it was using otherwise
* for the local connection.
*/
if (!got_data) { if (!got_data) {
u_int32_t rand = 0; u_int32_t rand = 0;
@ -670,8 +690,10 @@ main(int ac, char **av)
rand >>= 8; rand >>= 8;
} }
} }
/* Got local authentication reasonable information. /*
Request forwarding with authentication spoofing. */ * Got local authentication reasonable information. Request
* forwarding with authentication spoofing.
*/
debug("Requesting X11 forwarding with authentication spoofing."); debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(proto, data); x11_request_forwarding_with_spoofing(proto, data);
@ -728,8 +750,15 @@ main(int ac, char **av)
options.remote_forwards[i].host_port); options.remote_forwards[i].host_port);
} }
/* If a command was specified on the command line, execute the /* If requested, let ssh continue in the background. */
command now. Otherwise request the server to start a shell. */ if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
/*
* If a command was specified on the command line, execute the
* command now. Otherwise request the server to start a shell.
*/
if (buffer_len(&command) > 0) { if (buffer_len(&command) > 0) {
int len = buffer_len(&command); int len = buffer_len(&command);
if (len > 900) if (len > 900)

514
ssh.h
View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: ssh.h,v 1.15 1999/11/24 13:26:23 damien Exp $"); */ /* RCSID("$Id: ssh.h,v 1.16 1999/11/25 00:54:59 damien Exp $"); */
#ifndef SSH_H #ifndef SSH_H
#define SSH_H #define SSH_H
@ -25,9 +25,11 @@
#include "rsa.h" #include "rsa.h"
#include "cipher.h" #include "cipher.h"
/* The default cipher used if IDEA is not supported by the remote host. /*
It is recommended that this be one of the mandatory ciphers (DES, 3DES), * The default cipher used if IDEA is not supported by the remote host. It is
though that is not required. */ * recommended that this be one of the mandatory ciphers (DES, 3DES), though
* that is not required.
*/
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES #define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
/* Cipher used for encrypting authentication files. */ /* Cipher used for encrypting authentication files. */
@ -39,20 +41,28 @@
/* Maximum number of TCP/IP ports forwarded per direction. */ /* Maximum number of TCP/IP ports forwarded per direction. */
#define SSH_MAX_FORWARDS_PER_DIRECTION 100 #define SSH_MAX_FORWARDS_PER_DIRECTION 100
/* Maximum number of RSA authentication identity files that can be specified /*
in configuration files or on the command line. */ * Maximum number of RSA authentication identity files that can be specified
* in configuration files or on the command line.
*/
#define SSH_MAX_IDENTITY_FILES 100 #define SSH_MAX_IDENTITY_FILES 100
/* Major protocol version. Different version indicates major incompatiblity /*
that prevents communication. */ * Major protocol version. Different version indicates major incompatiblity
* that prevents communication.
*/
#define PROTOCOL_MAJOR 1 #define PROTOCOL_MAJOR 1
/* Minor protocol version. Different version indicates minor incompatibility /*
that does not prevent interoperation. */ * Minor protocol version. Different version indicates minor incompatibility
* that does not prevent interoperation.
*/
#define PROTOCOL_MINOR 5 #define PROTOCOL_MINOR 5
/* Name for the service. The port named by this service overrides the default /*
port if present. */ * Name for the service. The port named by this service overrides the
* default port if present.
*/
#define SSH_SERVICE_NAME "ssh" #define SSH_SERVICE_NAME "ssh"
#ifndef ETCDIR #ifndef ETCDIR
@ -63,16 +73,16 @@
#define PIDDIR "/var/run" #define PIDDIR "/var/run"
#endif /* PIDDIR */ #endif /* PIDDIR */
/* System-wide file containing host keys of known hosts. This file should be /*
world-readable. */ * System-wide file containing host keys of known hosts. This file should be
* world-readable.
*/
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts" #define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
/* HOST_KEY_FILE /etc/ssh_host_key, /*
SERVER_CONFIG_FILE /etc/sshd_config, * Of these, ssh_host_key must be readable only by root, whereas ssh_config
and HOST_CONFIG_FILE /etc/ssh_config * should be world-readable.
are all defined in Makefile.in. Of these, ssh_host_key should be readable */
only by root, whereas ssh_config should be world-readable. */
#define HOST_KEY_FILE ETCDIR "/ssh_host_key" #define HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config" #define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define HOST_CONFIG_FILE ETCDIR "/ssh_config" #define HOST_CONFIG_FILE ETCDIR "/ssh_config"
@ -89,73 +99,95 @@ only by root, whereas ssh_config should be world-readable. */
#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass" #define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
#endif /* ASKPASS_PROGRAM */ #endif /* ASKPASS_PROGRAM */
/* The process id of the daemon listening for connections is saved /*
here to make it easier to kill the correct daemon when necessary. */ * The process id of the daemon listening for connections is saved here to
* make it easier to kill the correct daemon when necessary.
*/
#define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid" #define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid"
/* The directory in user\'s home directory in which the files reside. /*
The directory should be world-readable (though not all files are). */ * The directory in user\'s home directory in which the files reside. The
* directory should be world-readable (though not all files are).
*/
#define SSH_USER_DIR ".ssh" #define SSH_USER_DIR ".ssh"
/* Per-user file containing host keys of known hosts. This file need /*
not be readable by anyone except the user him/herself, though this does * Per-user file containing host keys of known hosts. This file need not be
not contain anything particularly secret. */ * readable by anyone except the user him/herself, though this does not
* contain anything particularly secret.
*/
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts" #define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
/* Name of the default file containing client-side authentication key. /*
This file should only be readable by the user him/herself. */ * Name of the default file containing client-side authentication key. This
* file should only be readable by the user him/herself.
*/
#define SSH_CLIENT_IDENTITY ".ssh/identity" #define SSH_CLIENT_IDENTITY ".ssh/identity"
/* Configuration file in user\'s home directory. This file need not be /*
readable by anyone but the user him/herself, but does not contain * Configuration file in user\'s home directory. This file need not be
anything particularly secret. If the user\'s home directory resides * readable by anyone but the user him/herself, but does not contain anything
on an NFS volume where root is mapped to nobody, this may need to be * particularly secret. If the user\'s home directory resides on an NFS
world-readable. */ * volume where root is mapped to nobody, this may need to be world-readable.
*/
#define SSH_USER_CONFFILE ".ssh/config" #define SSH_USER_CONFFILE ".ssh/config"
/* File containing a list of those rsa keys that permit logging in as /*
this user. This file need not be * File containing a list of those rsa keys that permit logging in as this
readable by anyone but the user him/herself, but does not contain * user. This file need not be readable by anyone but the user him/herself,
anything particularly secret. If the user\'s home directory resides * but does not contain anything particularly secret. If the user\'s home
on an NFS volume where root is mapped to nobody, this may need to be * directory resides on an NFS volume where root is mapped to nobody, this
world-readable. (This file is read by the daemon which is running as * may need to be world-readable. (This file is read by the daemon which is
root.) */ * running as root.)
*/
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" #define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
/* Per-user and system-wide ssh "rc" files. These files are executed with /*
/bin/sh before starting the shell or command if they exist. They * Per-user and system-wide ssh "rc" files. These files are executed with
will be passed "proto cookie" as arguments if X11 forwarding with * /bin/sh before starting the shell or command if they exist. They will be
spoofing is in use. xauth will be run if neither of these exists. */ * passed "proto cookie" as arguments if X11 forwarding with spoofing is in
* use. xauth will be run if neither of these exists.
*/
#define SSH_USER_RC ".ssh/rc" #define SSH_USER_RC ".ssh/rc"
#define SSH_SYSTEM_RC ETCDIR "/sshrc" #define SSH_SYSTEM_RC ETCDIR "/sshrc"
/* Ssh-only version of /etc/hosts.equiv. */ /*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv" #define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if /*
rhosts authentication is enabled. */ * Name of the environment variable containing the pathname of the
* authentication socket.
/* Name of the environment variable containing the pathname of the */
authentication socket. */
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK" #define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
/* Name of the environment variable containing the pathname of the /*
authentication socket. */ * Name of the environment variable containing the pathname of the
* authentication socket.
*/
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID" #define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
/* Force host key length and server key length to differ by at least this /*
many bits. This is to make double encryption with rsaref work. */ * Force host key length and server key length to differ by at least this
* many bits. This is to make double encryption with rsaref work.
*/
#define SSH_KEY_BITS_RESERVED 128 #define SSH_KEY_BITS_RESERVED 128
/* Length of the session key in bytes. (Specified as 256 bits in the /*
protocol.) */ * Length of the session key in bytes. (Specified as 256 bits in the
* protocol.)
*/
#define SSH_SESSION_KEY_LENGTH 32 #define SSH_SESSION_KEY_LENGTH 32
/* Name of Kerberos service for SSH to use. */ /* Name of Kerberos service for SSH to use. */
#define KRB4_SERVICE_NAME "rcmd" #define KRB4_SERVICE_NAME "rcmd"
/* Authentication methods. New types can be added, but old types should not /*
be removed for compatibility. The maximum allowed value is 31. */ * Authentication methods. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
*/
#define SSH_AUTH_RHOSTS 1 #define SSH_AUTH_RHOSTS 1
#define SSH_AUTH_RSA 2 #define SSH_AUTH_RSA 2
#define SSH_AUTH_PASSWORD 3 #define SSH_AUTH_PASSWORD 3
@ -167,16 +199,16 @@ only by root, whereas ssh_config should be world-readable. */
#define SSH_PASS_AFS_TOKEN 21 #define SSH_PASS_AFS_TOKEN 21
/* Protocol flags. These are bit masks. */ /* Protocol flags. These are bit masks. */
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes #define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
* screen */ #define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain
* host */
/* Definition of message types. New values can be added, but old values /*
should not be removed or without careful consideration of the consequences * Definition of message types. New values can be added, but old values
for compatibility. The maximum value is 254; value 255 is reserved * should not be removed or without careful consideration of the consequences
for future extension. */ * for compatibility. The maximum value is 254; value 255 is reserved for
/* Message name *//* msg code *//* arguments */ * future extension.
*/
/* Message name */ /* msg code */ /* arguments */
#define SSH_MSG_NONE 0 /* no message */ #define SSH_MSG_NONE 0 /* no message */
#define SSH_MSG_DISCONNECT 1 /* cause (string) */ #define SSH_MSG_DISCONNECT 1 /* cause (string) */
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ #define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
@ -226,45 +258,54 @@ only by root, whereas ssh_config should be world-readable. */
/*------------ definitions for login.c -------------*/ /*------------ definitions for login.c -------------*/
/* Returns the time when the user last logged in. Returns 0 if the /*
information is not available. This must be called before record_login. * Returns the time when the user last logged in. Returns 0 if the
The host from which the user logged in is stored in buf. */ * information is not available. This must be called before record_login.
* The host from which the user logged in is stored in buf.
*/
unsigned long unsigned long
get_last_login_time(uid_t uid, const char *logname, get_last_login_time(uid_t uid, const char *logname,
char *buf, unsigned int bufsize); char *buf, unsigned int bufsize);
/* Records that the user has logged in. This does many things normally /*
done by login(1). */ * Records that the user has logged in. This does many things normally done
* by login(1).
*/
void void
record_login(int pid, const char *ttyname, const char *user, uid_t uid, record_login(int pid, const char *ttyname, const char *user, uid_t uid,
const char *host, struct sockaddr_in * addr); const char *host, struct sockaddr_in * addr);
/* Records that the user has logged out. This does many thigs normally /*
done by login(1) or init. */ * Records that the user has logged out. This does many thigs normally done
* by login(1) or init.
*/
void record_logout(int pid, const char *ttyname); void record_logout(int pid, const char *ttyname);
/*------------ definitions for sshconnect.c ----------*/ /*------------ definitions for sshconnect.c ----------*/
/* Opens a TCP/IP connection to the remote server on the given host. If /*
port is 0, the default port will be used. If anonymous is zero, * Opens a TCP/IP connection to the remote server on the given host. If port
a privileged port will be allocated to make the connection. * is 0, the default port will be used. If anonymous is zero, a privileged
This requires super-user privileges if anonymous is false. * port will be allocated to make the connection. This requires super-user
Connection_attempts specifies the maximum number of tries, one per * privileges if anonymous is false. Connection_attempts specifies the
second. This returns true on success, and zero on failure. If the * maximum number of tries, one per second. This returns true on success,
connection is successful, this calls packet_set_connection for the * and zero on failure. If the connection is successful, this calls
connection. */ * packet_set_connection for the connection.
*/
int int
ssh_connect(const char *host, struct sockaddr_in * hostaddr, ssh_connect(const char *host, struct sockaddr_in * hostaddr,
int port, int connection_attempts, int port, int connection_attempts,
int anonymous, uid_t original_real_uid, int anonymous, uid_t original_real_uid,
const char *proxy_command); const char *proxy_command);
/* Starts a dialog with the server, and authenticates the current user on the /*
server. This does not need any extra privileges. The basic connection * Starts a dialog with the server, and authenticates the current user on the
to the server must already have been established before this is called. * server. This does not need any extra privileges. The basic connection to
If login fails, this function prints an error and never returns. * the server must already have been established before this is called. If
This initializes the random state, and leaves it initialized (it will also * login fails, this function prints an error and never returns. This
have references from the packet module). */ * initializes the random state, and leaves it initialized (it will also have
* references from the packet module).
*/
void void
ssh_login(int host_key_valid, RSA * host_key, const char *host, ssh_login(int host_key_valid, RSA * host_key, const char *host,
@ -272,41 +313,57 @@ ssh_login(int host_key_valid, RSA * host_key, const char *host,
/*------------ Definitions for various authentication methods. -------*/ /*------------ Definitions for various authentication methods. -------*/
/* Tries to authenticate the user using the .rhosts file. Returns true if /*
authentication succeeds. If ignore_rhosts is non-zero, this will not * Tries to authenticate the user using the .rhosts file. Returns true if
consider .rhosts and .shosts (/etc/hosts.equiv will still be used). */ * authentication succeeds. If ignore_rhosts is non-zero, this will not
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
*/
int auth_rhosts(struct passwd * pw, const char *client_user); int auth_rhosts(struct passwd * pw, const char *client_user);
/* Tries to authenticate the user using the .rhosts file and the host using /*
its host key. Returns true if authentication succeeds. */ * Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, auth_rhosts_rsa(struct passwd * pw, const char *client_user,
BIGNUM * client_host_key_e, BIGNUM * client_host_key_n); BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
/* Tries to authenticate the user using password. Returns true if /*
authentication succeeds. */ * Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int auth_password(struct passwd * pw, const char *password); int auth_password(struct passwd * pw, const char *password);
/* Performs the RSA authentication dialog with the client. This returns /*
0 if the client could not be authenticated, and 1 if authentication was * Performs the RSA authentication dialog with the client. This returns 0 if
successful. This may exit if there is a serious protocol violation. */ * the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_rsa(struct passwd * pw, BIGNUM * client_n); int auth_rsa(struct passwd * pw, BIGNUM * client_n);
/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer /*
over the key. Skips any whitespace at the beginning and at end. */ * Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n); int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
/* Returns the name of the machine at the other end of the socket. The /*
returned string should be freed by the caller. */ * Returns the name of the machine at the other end of the socket. The
* returned string should be freed by the caller.
*/
char *get_remote_hostname(int socket); char *get_remote_hostname(int socket);
/* Return the canonical name of the host in the other side of the current /*
connection (as returned by packet_get_connection). The host name is * Return the canonical name of the host in the other side of the current
cached, so it is efficient to call this several times. */ * connection (as returned by packet_get_connection). The host name is
* cached, so it is efficient to call this several times.
*/
const char *get_canonical_hostname(void); const char *get_canonical_hostname(void);
/* Returns the remote IP address as an ascii string. The value need not be /*
freed by the caller. */ * Returns the remote IP address as an ascii string. The value need not be
* freed by the caller.
*/
const char *get_remote_ipaddr(void); const char *get_remote_ipaddr(void);
/* Returns the port number of the peer of the socket. */ /* Returns the port number of the peer of the socket. */
@ -315,16 +372,20 @@ int get_peer_port(int sock);
/* Returns the port number of the remote host. */ /* Returns the port number of the remote host. */
int get_remote_port(void); int get_remote_port(void);
/* Tries to match the host name (which must be in all lowercase) against the /*
comma-separated sequence of subpatterns (each possibly preceded by ! to * Tries to match the host name (which must be in all lowercase) against the
indicate negation). Returns true if there is a positive match; zero * comma-separated sequence of subpatterns (each possibly preceded by ! to
otherwise. */ * indicate negation). Returns true if there is a positive match; zero
* otherwise.
*/
int match_hostname(const char *host, const char *pattern, unsigned int len); int match_hostname(const char *host, const char *pattern, unsigned int len);
/* Checks whether the given host is already in the list of our known hosts. /*
Returns HOST_OK if the host is known and has the specified key, * Checks whether the given host is already in the list of our known hosts.
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known * Returns HOST_OK if the host is known and has the specified key, HOST_NEW
but used to have a different host key. The host must be in all lowercase. */ * if the host is not known, and HOST_CHANGED if the host is known but used
* to have a different host key. The host must be in all lowercase.
*/
typedef enum { typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED HOST_OK, HOST_NEW, HOST_CHANGED
} HostStatus; } HostStatus;
@ -332,43 +393,55 @@ HostStatus
check_host_in_hostfile(const char *filename, const char *host, check_host_in_hostfile(const char *filename, const char *host,
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn); BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
/* Appends an entry to the host file. Returns false if the entry /*
could not be appended. */ * Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
int int
add_host_to_hostfile(const char *filename, const char *host, add_host_to_hostfile(const char *filename, const char *host,
BIGNUM * e, BIGNUM * n); BIGNUM * e, BIGNUM * n);
/* Performs the RSA authentication challenge-response dialog with the client, /*
and returns true (non-zero) if the client gave the correct answer to * Performs the RSA authentication challenge-response dialog with the client,
our challenge; returns zero if the client gives a wrong answer. */ * and returns true (non-zero) if the client gave the correct answer to our
* challenge; returns zero if the client gives a wrong answer.
*/
int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n); int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n);
/* Reads a passphrase from /dev/tty with echo turned off. Returns the /*
passphrase (allocated with xmalloc). Exits if EOF is encountered. * Reads a passphrase from /dev/tty with echo turned off. Returns the
If from_stdin is true, the passphrase will be read from stdin instead. */ * 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(const char *prompt, int from_stdin); char *read_passphrase(const char *prompt, int from_stdin);
/* Saves the authentication (private) key in a file, encrypting it with /*
passphrase. The identification of the file (lowest 64 bits of n) * Saves the authentication (private) key in a file, encrypting it with
will precede the key to provide identification of the key without * passphrase. The identification of the file (lowest 64 bits of n) will
needing a passphrase. */ * precede the key to provide identification of the key without needing a
* passphrase.
*/
int int
save_private_key(const char *filename, const char *passphrase, save_private_key(const char *filename, const char *passphrase,
RSA * private_key, const char *comment); RSA * private_key, const char *comment);
/* Loads the public part of the key file (public key and comment). /*
Returns 0 if an error occurred; zero if the public key was successfully * Loads the public part of the key file (public key and comment). Returns 0
read. The comment of the key is returned in comment_return if it is * if an error occurred; zero if the public key was successfully read. The
non-NULL; the caller must free the value with xfree. */ * comment of the key is returned in comment_return if it is non-NULL; the
* caller must free the value with xfree.
*/
int int
load_public_key(const char *filename, RSA * pub, load_public_key(const char *filename, RSA * pub,
char **comment_return); char **comment_return);
/* Loads the private key from the file. Returns 0 if an error is encountered /*
(file does not exist or is not readable, or passphrase is bad). * Loads the private key from the file. Returns 0 if an error is encountered
This initializes the private key. The comment of the key is returned * (file does not exist or is not readable, or passphrase is bad). This
in comment_return if it is non-NULL; the caller must free the value * initializes the private key. The comment of the key is returned in
with xfree. */ * comment_return if it is non-NULL; the caller must free the value with
* xfree.
*/
int int
load_private_key(const char *filename, const char *passphrase, load_private_key(const char *filename, const char *passphrase,
RSA * private_key, char **comment_return); RSA * private_key, char **comment_return);
@ -418,9 +491,11 @@ void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/* same as fatal() but w/o logging */ /* same as fatal() but w/o logging */
void fatal_cleanup(void); void fatal_cleanup(void);
/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting. /*
It is permissible to call fatal_remove_cleanup for the function itself * Registers a cleanup function to be called by fatal()/fatal_cleanup()
from the function. */ * before exiting. It is permissible to call fatal_remove_cleanup for the
* function itself from the function.
*/
void fatal_add_cleanup(void (*proc) (void *context), void *context); void fatal_add_cleanup(void (*proc) (void *context), void *context);
/* Removes a cleanup function to be called at fatal(). */ /* Removes a cleanup function to be called at fatal(). */
@ -431,9 +506,11 @@ void fatal_remove_cleanup(void (*proc) (void *context), void *context);
/* Sets specific protocol options. */ /* Sets specific protocol options. */
void channel_set_options(int hostname_in_open); void channel_set_options(int hostname_in_open);
/* Allocate a new channel object and set its type and socket. Remote_name /*
must have been allocated with xmalloc; this will free it when the channel * Allocate a new channel object and set its type and socket. Remote_name
is freed. */ * must have been allocated with xmalloc; this will free it when the channel
* is freed.
*/
int channel_allocate(int type, int sock, char *remote_name); int channel_allocate(int type, int sock, char *remote_name);
/* Free the channel and close its socket. */ /* Free the channel and close its socket. */
@ -442,16 +519,20 @@ void channel_free(int channel);
/* Add any bits relevant to channels in select bitmasks. */ /* Add any bits relevant to channels in select bitmasks. */
void channel_prepare_select(fd_set * readset, fd_set * writeset); void channel_prepare_select(fd_set * readset, fd_set * writeset);
/* After select, perform any appropriate operations for channels which /*
have events pending. */ * After select, perform any appropriate operations for channels which have
* events pending.
*/
void channel_after_select(fd_set * readset, fd_set * writeset); void channel_after_select(fd_set * readset, fd_set * writeset);
/* If there is data to send to the connection, send some of it now. */ /* If there is data to send to the connection, send some of it now. */
void channel_output_poll(void); void channel_output_poll(void);
/* This is called when a packet of type CHANNEL_DATA has just been received. /*
The message type has already been consumed, but channel number and data * This is called when a packet of type CHANNEL_DATA has just been received.
is still there. */ * The message type has already been consumed, but channel number and data is
* still there.
*/
void channel_input_data(int payload_len); void channel_input_data(int payload_len);
/* Returns true if no channel has too much buffered data. */ /* Returns true if no channel has too much buffered data. */
@ -473,8 +554,10 @@ void channel_input_open_failure(void);
any unix domain sockets. */ any unix domain sockets. */
void channel_stop_listening(void); void channel_stop_listening(void);
/* Closes the sockets of all channels. This is used to close extra file /*
descriptors after a fork. */ * Closes the sockets of all channels. This is used to close extra file
* descriptors after a fork.
*/
void channel_close_all(void); void channel_close_all(void);
/* Returns the maximum file descriptor number used by the channels. */ /* Returns the maximum file descriptor number used by the channels. */
@ -483,92 +566,123 @@ int channel_max_fd(void);
/* Returns true if there is still an open channel over the connection. */ /* Returns true if there is still an open channel over the connection. */
int channel_still_open(void); int channel_still_open(void);
/* Returns a string containing a list of all open channels. The list is /*
suitable for displaying to the user. It uses crlf instead of newlines. * Returns a string containing a list of all open channels. The list is
The caller should free the string with xfree. */ * suitable for displaying to the user. It uses crlf instead of newlines.
* The caller should free the string with xfree.
*/
char *channel_open_message(void); char *channel_open_message(void);
/* Initiate forwarding of connections to local port "port" through the secure /*
channel to host:port from remote side. This never returns if there * Initiate forwarding of connections to local port "port" through the secure
was an error. */ * channel to host:port from remote side. This never returns if there was an
* error.
*/
void void
channel_request_local_forwarding(int port, const char *host, channel_request_local_forwarding(int port, const char *host,
int remote_port); int remote_port);
/* Initiate forwarding of connections to port "port" on remote host through /*
the secure channel to host:port from local side. This never returns * Initiate forwarding of connections to port "port" on remote host through
if there was an error. This registers that open requests for that * the secure channel to host:port from local side. This never returns if
port are permitted. */ * there was an error. This registers that open requests for that port are
* permitted.
*/
void void
channel_request_remote_forwarding(int port, const char *host, channel_request_remote_forwarding(int port, const char *host,
int remote_port); int remote_port);
/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually /*
called by the server, because the user could connect to any port anyway, * Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
and the server has no way to know but to trust the client anyway. */ * called by the server, because the user could connect to any port anyway,
* and the server has no way to know but to trust the client anyway.
*/
void channel_permit_all_opens(void); void channel_permit_all_opens(void);
/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates /*
listening for the port, and sends back a success reply (or disconnect * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
message if there was an error). This never returns if there was an * listening for the port, and sends back a success reply (or disconnect
error. */ * message if there was an error). This never returns if there was an error.
*/
void channel_input_port_forward_request(int is_root); void channel_input_port_forward_request(int is_root);
/* This is called after receiving PORT_OPEN message. This attempts to connect /*
to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or * This is called after receiving PORT_OPEN message. This attempts to
CHANNEL_OPEN_FAILURE. */ * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
* or CHANNEL_OPEN_FAILURE.
*/
void channel_input_port_open(int payload_len); void channel_input_port_open(int payload_len);
/* Creates a port for X11 connections, and starts listening for it. /*
Returns the display name, or NULL if an error was encountered. */ * Creates a port for X11 connections, and starts listening for it. Returns
* the display name, or NULL if an error was encountered.
*/
char *x11_create_display(int screen); char *x11_create_display(int screen);
/* Creates an internet domain socket for listening for X11 connections. /*
Returns a suitable value for the DISPLAY variable, or NULL if an error * Creates an internet domain socket for listening for X11 connections.
occurs. */ * Returns a suitable value for the DISPLAY variable, or NULL if an error
* occurs.
*/
char *x11_create_display_inet(int screen); char *x11_create_display_inet(int screen);
/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains /*
the remote channel number. We should do whatever we want, and respond * This is called when SSH_SMSG_X11_OPEN is received. The packet contains
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ * the remote channel number. We should do whatever we want, and respond
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
*/
void x11_input_open(int payload_len); void x11_input_open(int payload_len);
/* Requests forwarding of X11 connections. This should be called on the /*
client only. */ * Requests forwarding of X11 connections. This should be called on the
* client only.
*/
void x11_request_forwarding(void); void x11_request_forwarding(void);
/* Requests forwarding for X11 connections, with authentication spoofing. /*
This should be called in the client only. */ * Requests forwarding for X11 connections, with authentication spoofing.
* This should be called in the client only.
*/
void x11_request_forwarding_with_spoofing(const char *proto, const char *data); void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
/* Sends a message to the server to request authentication fd forwarding. */ /* Sends a message to the server to request authentication fd forwarding. */
void auth_request_forwarding(void); void auth_request_forwarding(void);
/* Returns the name of the forwarded authentication socket. Returns NULL /*
if there is no forwarded authentication socket. The returned value points * Returns the name of the forwarded authentication socket. Returns NULL if
to a static buffer. */ * there is no forwarded authentication socket. The returned value points to
* a static buffer.
*/
char *auth_get_socket_name(void); char *auth_get_socket_name(void);
/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. /*
This starts forwarding authentication requests. */ * This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
* This starts forwarding authentication requests.
*/
void auth_input_request_forwarding(struct passwd * pw); void auth_input_request_forwarding(struct passwd * pw);
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ /* This is called to process an SSH_SMSG_AGENT_OPEN message. */
void auth_input_open_request(void); void auth_input_open_request(void);
/* Returns true if the given string matches the pattern (which may contain /*
? and * as wildcards), and zero if it does not match. */ * Returns true if the given string matches the pattern (which may contain ?
* and * as wildcards), and zero if it does not match.
*/
int match_pattern(const char *s, const char *pattern); int match_pattern(const char *s, const char *pattern);
/* Expands tildes in the file name. Returns data allocated by xmalloc. /*
Warning: this calls getpw*. */ * Expands tildes in the file name. Returns data allocated by xmalloc.
* Warning: this calls getpw*.
*/
char *tilde_expand_filename(const char *filename, uid_t my_uid); char *tilde_expand_filename(const char *filename, uid_t my_uid);
/* Performs the interactive session. This handles data transmission between /*
the client and the program. Note that the notion of stdin, stdout, and * Performs the interactive session. This handles data transmission between
stderr in this function is sort of reversed: this function writes to * the client and the program. Note that the notion of stdin, stdout, and
stdin (of the child program), and reads from stdout and stderr (of the * stderr in this function is sort of reversed: this function writes to stdin
child program). */ * (of the child program), and reads from stdout and stderr (of the child
* program).
*/
void server_loop(int pid, int fdin, int fdout, int fderr); void server_loop(int pid, int fdin, int fdout, int fderr);
/* Client side main loop for the interactive session. */ /* Client side main loop for the interactive session. */
@ -582,9 +696,11 @@ struct envstring {
#ifdef KRB4 #ifdef KRB4
#include <krb.h> #include <krb.h>
/* Performs Kerberos v4 mutual authentication with the client. This returns /*
0 if the client could not be authenticated, and 1 if authentication was * Performs Kerberos v4 mutual authentication with the client. This returns 0
successful. This may exit if there is a serious protocol violation. */ * if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_krb4(const char *server_user, KTEXT auth, char **client); int auth_krb4(const char *server_user, KTEXT auth, char **client);
int krb4_init(uid_t uid); int krb4_init(uid_t uid);
void krb4_cleanup_proc(void *ignore); void krb4_cleanup_proc(void *ignore);

View File

@ -8,7 +8,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: sshconnect.c,v 1.14 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: sshconnect.c,v 1.15 1999/11/25 00:54:59 damien Exp $");
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/bn.h> #include <openssl/bn.h>
@ -142,8 +142,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
{ {
int sock; int sock;
/* If we are running as root and want to connect to a privileged /*
port, bind our own socket to a privileged port. */ * If we are running as root and want to connect to a privileged
* port, bind our own socket to a privileged port.
*/
if (privileged) { if (privileged) {
int p = IPPORT_RESERVED - 1; int p = IPPORT_RESERVED - 1;
@ -227,9 +229,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
!anonymous && geteuid() == 0 && !anonymous && geteuid() == 0 &&
port < IPPORT_RESERVED); port < IPPORT_RESERVED);
/* Connect to the host. We use the user's uid in /*
the hope that it will help with the problems of * Connect to the host. We use the user's uid in the
tcp_wrappers showing the remote uid as root. */ * hope that it will help with the problems of
* tcp_wrappers showing the remote uid as root.
*/
temporarily_use_uid(original_real_uid); temporarily_use_uid(original_real_uid);
if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr)) if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
>= 0) { >= 0) {
@ -270,8 +274,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
!anonymous && geteuid() == 0 && !anonymous && geteuid() == 0 &&
port < IPPORT_RESERVED); port < IPPORT_RESERVED);
/* Connect to the host. We use the user's uid in the hope that /*
it will help with tcp_wrappers showing the remote uid as root. */ * Connect to the host. We use the user's
* uid in the hope that it will help with
* tcp_wrappers showing the remote uid as
* root.
*/
temporarily_use_uid(original_real_uid); temporarily_use_uid(original_real_uid);
if (connect(sock, (struct sockaddr *) hostaddr, if (connect(sock, (struct sockaddr *) hostaddr,
sizeof(*hostaddr)) >= 0) { sizeof(*hostaddr)) >= 0) {
@ -282,8 +290,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
debug("connect: %.100s", strerror(errno)); debug("connect: %.100s", strerror(errno));
restore_uid(); restore_uid();
/* Close the failed socket; there appear to be some problems when /*
reusing a socket for which connect() has already returned an error. */ * Close the failed socket; there appear to
* be some problems when reusing a socket for
* which connect() has already returned an
* error.
*/
shutdown(sock, SHUT_RDWR); shutdown(sock, SHUT_RDWR);
close(sock); close(sock);
} }
@ -300,10 +312,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
debug("Connection established."); debug("Connection established.");
/* Set socket options. We would like the socket to disappear as /*
soon as it has been closed for whatever reason. */ * Set socket options. We would like the socket to disappear as soon
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, * as it has been closed for whatever reason.
sizeof(on)); */ */
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)); setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
linger.l_onoff = 1; linger.l_onoff = 1;
linger.l_linger = 5; linger.l_linger = 5;
@ -493,8 +506,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
/* Wait for server's response. */ /* Wait for server's response. */
type = packet_read(&plen); type = packet_read(&plen);
/* The server responds with failure if it doesn\'t like our key or /*
doesn\'t support RSA authentication. */ * The server responds with failure if it doesn\'t like our key or
* doesn\'t support RSA authentication.
*/
if (type == SSH_SMSG_FAILURE) { if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key."); debug("Server refused our key.");
xfree(comment); xfree(comment);
@ -514,8 +529,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
debug("Received RSA challenge from server."); debug("Received RSA challenge from server.");
private_key = RSA_new(); private_key = RSA_new();
/* Load the private key. Try first with empty passphrase; if it /*
fails, ask for a passphrase. */ * Load the private key. Try first with empty passphrase; if it
* fails, ask for a passphrase.
*/
if (!load_private_key(authfile, "", private_key, NULL)) { if (!load_private_key(authfile, "", private_key, NULL)) {
char buf[300]; char buf[300];
snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
@ -720,9 +737,11 @@ try_kerberos_authentication()
packet_integrity_check(plen, 4 + auth.length, type); packet_integrity_check(plen, 4 + auth.length, type);
/* If his response isn't properly encrypted with the /*
session key, and the decrypted checksum fails to match, * If his response isn't properly encrypted with the session
he's bogus. Bail out. */ * key, and the decrypted checksum fails to match, he's
* bogus. Bail out.
*/
r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
&foreign, &local, &msg_data); &foreign, &local, &msg_data);
if (r != KSUCCESS) { if (r != KSUCCESS) {
@ -894,8 +913,10 @@ ssh_exchange_identification()
} }
buf[sizeof(buf) - 1] = 0; buf[sizeof(buf) - 1] = 0;
/* Check that the versions match. In future this might accept /*
several versions and set appropriate flags to handle them. */ * Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
remote_version) != 3) remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf); fatal("Bad remote protocol version identification: '%.100s'", buf);
@ -916,9 +937,11 @@ ssh_exchange_identification()
} }
} }
#if 0 #if 0
/* Removed for now, to permit compatibility with latter versions. /*
The server will reject our version and disconnect if it doesn't * Removed for now, to permit compatibility with latter versions. The
support it. */ * server will reject our version and disconnect if it doesn't
* support it.
*/
if (remote_major != PROTOCOL_MAJOR) if (remote_major != PROTOCOL_MAJOR)
fatal("Protocol major versions differ: %d vs. %d", fatal("Protocol major versions differ: %d vs. %d",
PROTOCOL_MAJOR, remote_major); PROTOCOL_MAJOR, remote_major);
@ -1086,10 +1109,7 @@ ssh_login(int host_key_valid,
protocol_flags = packet_get_int(); protocol_flags = packet_get_int();
packet_set_protocol_flags(protocol_flags); packet_set_protocol_flags(protocol_flags);
/* Get supported cipher types. */
supported_ciphers = packet_get_int(); supported_ciphers = packet_get_int();
/* Get supported authentication types. */
supported_authentications = packet_get_int(); supported_authentications = packet_get_int();
debug("Received server public key (%d bits) and host key (%d bits).", debug("Received server public key (%d bits) and host key (%d bits).",
@ -1099,11 +1119,12 @@ ssh_login(int host_key_valid,
8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
SSH_SMSG_PUBLIC_KEY); SSH_SMSG_PUBLIC_KEY);
/* Compute the session id. */
compute_session_id(session_id, check_bytes, host_key->n, public_key->n); compute_session_id(session_id, check_bytes, host_key->n, public_key->n);
/* Check if the host key is present in the user\'s list of known /*
hosts or in the systemwide list. */ * Check if the host key is present in the user\'s list of known
* hosts or in the systemwide list.
*/
host_status = check_host_in_hostfile(options.user_hostfile, host, host_status = check_host_in_hostfile(options.user_hostfile, host,
host_key->e, host_key->n, host_key->e, host_key->n,
file_key->e, file_key->n); file_key->e, file_key->n);
@ -1111,18 +1132,22 @@ ssh_login(int host_key_valid,
host_status = check_host_in_hostfile(options.system_hostfile, host, host_status = check_host_in_hostfile(options.system_hostfile, host,
host_key->e, host_key->n, host_key->e, host_key->n,
file_key->e, file_key->n); file_key->e, file_key->n);
/* Force accepting of the host key for localhost and 127.0.0.1. /*
The problem is that if the home directory is NFS-mounted to * Force accepting of the host key for localhost and 127.0.0.1. The
multiple machines, localhost will refer to a different machine * problem is that if the home directory is NFS-mounted to multiple
in each of them, and the user will get bogus HOST_CHANGED * machines, localhost will refer to a different machine in each of
warnings. This essentially disables host authentication for * them, and the user will get bogus HOST_CHANGED warnings. This
localhost; however, this is probably not a real problem. */ * essentially disables host authentication for localhost; however,
* this is probably not a real problem.
*/
if (local) { if (local) {
debug("Forcing accepting of host key for localhost."); debug("Forcing accepting of host key for localhost.");
host_status = HOST_OK; host_status = HOST_OK;
} }
/* Also perform check for the ip address, skip the check if we are /*
localhost or the hostname was an ip address to begin with */ * Also perform check for the ip address, skip the check if we are
* localhost or the hostname was an ip address to begin with
*/
if (options.check_host_ip && !local && strcmp(host, ip)) { if (options.check_host_ip && !local && strcmp(host, ip)) {
RSA *ip_key = RSA_new(); RSA *ip_key = RSA_new();
ip_key->n = BN_new(); ip_key->n = BN_new();
@ -1226,13 +1251,18 @@ ssh_login(int host_key_valid,
error("Add correct host key in %.100s to get rid of this message.", error("Add correct host key in %.100s to get rid of this message.",
options.user_hostfile); options.user_hostfile);
/* If strict host key checking is in use, the user will /*
have to edit the key manually and we can only abort. */ * 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)
fatal("Host key for %.200s has changed and you have requested strict checking.", host); fatal("Host key for %.200s has changed and you have requested strict checking.", host);
/* If strict host key checking has not been requested, allow the connection /*
but without password authentication or agent forwarding. */ * If strict host key checking has not been requested, allow
* the connection but without password authentication or
* agent forwarding.
*/
if (options.password_authentication) { if (options.password_authentication) {
error("Password authentication is disabled to avoid trojan horses."); error("Password authentication is disabled to avoid trojan horses.");
options.password_authentication = 0; options.password_authentication = 0;
@ -1241,11 +1271,13 @@ ssh_login(int host_key_valid,
error("Agent forwarding is disabled to avoid trojan horses."); error("Agent forwarding is disabled to avoid trojan horses.");
options.forward_agent = 0; options.forward_agent = 0;
} }
/* XXX Should permit the user to change to use the new id. /*
This could be done by converting the host key to an * XXX Should permit the user to change to use the new id.
identifying sentence, tell that the host identifies * This could be done by converting the host key to an
itself by that sentence, and ask the user if he/she * identifying sentence, tell that the host identifies itself
whishes to accept the authentication. */ * by that sentence, and ask the user if he/she whishes to
* accept the authentication.
*/
break; break;
} }
@ -1255,9 +1287,11 @@ ssh_login(int host_key_valid,
/* Generate a session key. */ /* Generate a session key. */
arc4random_stir(); arc4random_stir();
/* Generate an encryption key for the session. The key is a 256 /*
bit random number, interpreted as a 32-byte key, with the least * Generate an encryption key for the session. The key is a 256 bit
significant 8 bits being the first byte of the key. */ * random number, interpreted as a 32-byte key, with the least
* significant 8 bits being the first byte of the key.
*/
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
if (i % 4 == 0) if (i % 4 == 0)
rand = arc4random(); rand = arc4random();
@ -1265,9 +1299,11 @@ ssh_login(int host_key_valid,
rand >>= 8; rand >>= 8;
} }
/* According to the protocol spec, the first byte of the session /*
key is the highest byte of the integer. The session key is * According to the protocol spec, the first byte of the session key
xored with the first 16 bytes of the session id. */ * is the highest byte of the integer. The session key is xored with
* the first 16 bytes of the session id.
*/
key = BN_new(); key = BN_new();
BN_set_word(key, 0); BN_set_word(key, 0);
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
@ -1278,8 +1314,10 @@ ssh_login(int host_key_valid,
BN_add_word(key, session_key[i]); BN_add_word(key, session_key[i]);
} }
/* Encrypt the integer using the public key and host key of the /*
server (key with smaller modulus first). */ * Encrypt the integer using the public key and host key of the
* server (key with smaller modulus first).
*/
if (BN_cmp(public_key->n, host_key->n) < 0) { if (BN_cmp(public_key->n, host_key->n) < 0) {
/* Public key has smaller modulus. */ /* Public key has smaller modulus. */
if (BN_num_bits(host_key->n) < if (BN_num_bits(host_key->n) <
@ -1354,8 +1392,10 @@ ssh_login(int host_key_valid,
/* We will no longer need the session key here. Destroy any extra copies. */ /* We will no longer need the session key here. Destroy any extra copies. */
memset(session_key, 0, sizeof(session_key)); memset(session_key, 0, sizeof(session_key));
/* Expect a success message from the server. Note that this /*
message will be received in encrypted form. */ * Expect a success message from the server. Note that this message
* will be received in encrypted form.
*/
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
debug("Received encrypted confirmation."); debug("Received encrypted confirmation.");
@ -1366,9 +1406,11 @@ ssh_login(int host_key_valid,
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
/* The server should respond with success if no authentication is /*
needed (the user has no password). Otherwise the server * The server should respond with success if no authentication is
responds with failure. */ * needed (the user has no password). Otherwise the server responds
* with failure.
*/
type = packet_read(&payload_len); type = packet_read(&payload_len);
/* check whether the connection was accepted without authentication. */ /* check whether the connection was accepted without authentication. */
@ -1410,8 +1452,10 @@ ssh_login(int host_key_valid,
} }
#endif /* KRB4 */ #endif /* KRB4 */
/* Use rhosts authentication if running in privileged socket and /*
we do not wish to remain anonymous. */ * Use rhosts authentication if running in privileged socket and we
* do not wish to remain anonymous.
*/
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
options.rhosts_authentication) { options.rhosts_authentication) {
debug("Trying rhosts authentication."); debug("Trying rhosts authentication.");
@ -1428,8 +1472,10 @@ ssh_login(int host_key_valid,
packet_disconnect("Protocol error: got %d in response to rhosts auth", packet_disconnect("Protocol error: got %d in response to rhosts auth",
type); type);
} }
/* Try .rhosts or /etc/hosts.equiv authentication with RSA host /*
authentication. */ * Try .rhosts or /etc/hosts.equiv authentication with RSA host
* authentication.
*/
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
options.rhosts_rsa_authentication && host_key_valid) { options.rhosts_rsa_authentication && host_key_valid) {
if (try_rhosts_rsa_authentication(local_user, own_host_key)) if (try_rhosts_rsa_authentication(local_user, own_host_key))
@ -1438,10 +1484,11 @@ ssh_login(int host_key_valid,
/* Try RSA authentication if the server supports it. */ /* Try RSA authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_RSA)) && if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
options.rsa_authentication) { options.rsa_authentication) {
/* Try RSA authentication using the authentication agent. /*
The agent is tried first because no passphrase is * Try RSA authentication using the authentication agent. The
needed for it, whereas identity files may require * agent is tried first because no passphrase is needed for
passphrases. */ * it, whereas identity files may require passphrases.
*/
if (try_agent_authentication()) if (try_agent_authentication())
return; return;

499
sshd.c
View File

@ -11,7 +11,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: sshd.c,v 1.31 1999/11/24 23:42:08 damien Exp $"); RCSID("$Id: sshd.c,v 1.32 1999/11/25 00:54:59 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -65,12 +65,16 @@ char *av0;
/* Saved arguments to main(). */ /* Saved arguments to main(). */
char **saved_argv; char **saved_argv;
/* This is set to the socket that the server is listening; this is used in /*
the SIGHUP signal handler. */ * This is set to the socket that the server is listening; this is used in
* the SIGHUP signal handler.
*/
int listen_sock; int listen_sock;
/* the client's version string, passed by sshd2 in compat mode. /*
if != NULL, sshd will skip the version-number exchange */ * the client's version string, passed by sshd2 in compat mode. if != NULL,
* sshd will skip the version-number exchange
*/
char *client_version_string = NULL; char *client_version_string = NULL;
/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ /* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
@ -88,19 +92,23 @@ struct envstring *custom_environment = NULL;
/* Session id for the current session. */ /* Session id for the current session. */
unsigned char session_id[16]; unsigned char session_id[16];
/* Any really sensitive data in the application is contained in this structure. /*
The idea is that this structure could be locked into memory so that the * Any really sensitive data in the application is contained in this
pages do not get written into swap. However, there are some problems. * structure. The idea is that this structure could be locked into memory so
The private key contains BIGNUMs, and we do not (in principle) have * that the pages do not get written into swap. However, there are some
access to the internals of them, and locking just the structure is not * problems. The private key contains BIGNUMs, and we do not (in principle)
very useful. Currently, memory locking is not implemented. */ * have access to the internals of them, and locking just the structure is
* not very useful. Currently, memory locking is not implemented.
*/
struct { struct {
RSA *private_key; /* Private part of server key. */ RSA *private_key; /* Private part of server key. */
RSA *host_key; /* Private part of host key. */ RSA *host_key; /* Private part of host key. */
} sensitive_data; } sensitive_data;
/* Flag indicating whether the current session key has been used. This flag /*
is set whenever the key is used, and cleared when the key is regenerated. */ * Flag indicating whether the current session key has been used. This flag
* is set whenever the key is used, and cleared when the key is regenerated.
*/
int key_used = 0; int key_used = 0;
/* This is set to true when SIGHUP is received. */ /* This is set to true when SIGHUP is received. */
@ -466,7 +474,7 @@ main(int ac, char **av)
fprintf(stderr, "sshd version %s\n", SSH_VERSION); fprintf(stderr, "sshd version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [options]\n", av0); fprintf(stderr, "Usage: %s [options]\n", av0);
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR); fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE);
fprintf(stderr, " -d Debugging mode\n"); fprintf(stderr, " -d Debugging mode\n");
fprintf(stderr, " -i Started from inetd\n"); fprintf(stderr, " -i Started from inetd\n");
fprintf(stderr, " -q Quiet (no logging)\n"); fprintf(stderr, " -q Quiet (no logging)\n");
@ -614,13 +622,11 @@ main(int ac, char **av)
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger, setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,
sizeof(linger)); sizeof(linger));
/* Initialize the socket address. */
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_addr = options.listen_addr; sin.sin_addr = options.listen_addr;
sin.sin_port = htons(options.port); sin.sin_port = htons(options.port);
/* Bind the socket to the desired port. */
if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
error("bind: %.100s", strerror(errno)); error("bind: %.100s", strerror(errno));
shutdown(listen_sock, SHUT_RDWR); shutdown(listen_sock, SHUT_RDWR);
@ -628,12 +634,13 @@ main(int ac, char **av)
fatal("Bind to port %d failed.", options.port); fatal("Bind to port %d failed.", options.port);
} }
if (!debug_flag) { if (!debug_flag) {
/* Record our pid in /etc/sshd_pid to make it /*
easier to kill the correct sshd. We don\'t * Record our pid in /etc/sshd_pid to make it easier
want to do this before the bind above because * to kill the correct sshd. We don\'t want to do
the bind will fail if there already is a * this before the bind above because the bind will
daemon, and this will overwrite any old pid in * fail if there already is a daemon, and this will
the file. */ * overwrite any old pid in the file.
*/
f = fopen(SSH_DAEMON_PID_FILE, "w"); f = fopen(SSH_DAEMON_PID_FILE, "w");
if (f) { if (f) {
fprintf(f, "%u\n", (unsigned int) getpid()); fprintf(f, "%u\n", (unsigned int) getpid());
@ -666,8 +673,10 @@ main(int ac, char **av)
/* Arrange SIGCHLD to be caught. */ /* Arrange SIGCHLD to be caught. */
signal(SIGCHLD, main_sigchld_handler); signal(SIGCHLD, main_sigchld_handler);
/* Stay listening for connections until the system crashes /*
or the daemon is killed with a signal. */ * Stay listening for connections until the system crashes or
* the daemon is killed with a signal.
*/
for (;;) { for (;;) {
if (received_sighup) if (received_sighup)
sighup_restart(); sighup_restart();
@ -682,12 +691,16 @@ main(int ac, char **av)
error("accept: %.100s", strerror(errno)); error("accept: %.100s", strerror(errno));
continue; continue;
} }
/* Got connection. Fork a child to handle it, /*
unless we are in debugging mode. */ * Got connection. Fork a child to handle it, unless
* we are in debugging mode.
*/
if (debug_flag) { if (debug_flag) {
/* In debugging mode. Close the listening /*
socket, and start processing the * In debugging mode. Close the listening
connection without forking. */ * socket, and start processing the
* connection without forking.
*/
debug("Server will not fork when running in debugging mode."); debug("Server will not fork when running in debugging mode.");
close(listen_sock); close(listen_sock);
sock_in = newsock; sock_in = newsock;
@ -695,16 +708,17 @@ main(int ac, char **av)
pid = getpid(); pid = getpid();
break; break;
} else { } else {
/* Normal production daemon. Fork, and /*
have the child process the connection. * Normal production daemon. Fork, and have
The parent continues listening. */ * the child process the connection. The
* parent continues listening.
*/
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
/* Child. Close the listening /*
socket, and start using the * Child. Close the listening socket, and start using the
accepted socket. Reinitialize * accepted socket. Reinitialize logging (since our pid has
logging (since our pid has * changed). We break out of the loop to handle the connection.
changed). We break out of the */
loop to handle the connection. */
close(listen_sock); close(listen_sock);
sock_in = newsock; sock_in = newsock;
sock_out = newsock; sock_out = newsock;
@ -731,9 +745,11 @@ main(int ac, char **av)
/* This is the child processing a new connection. */ /* This is the child processing a new connection. */
/* Disable the key regeneration alarm. We will not regenerate the /*
key since we are no longer in a position to give it to anyone. * Disable the key regeneration alarm. We will not regenerate the
We will not restart on SIGHUP since it no longer makes sense. */ * key since we are no longer in a position to give it to anyone. We
* will not restart on SIGHUP since it no longer makes sense.
*/
alarm(0); alarm(0);
signal(SIGALRM, SIG_DFL); signal(SIGALRM, SIG_DFL);
signal(SIGHUP, SIG_DFL); signal(SIGHUP, SIG_DFL);
@ -741,17 +757,20 @@ main(int ac, char **av)
signal(SIGQUIT, SIG_DFL); signal(SIGQUIT, SIG_DFL);
signal(SIGCHLD, SIG_DFL); signal(SIGCHLD, SIG_DFL);
/* Set socket options for the connection. We want the socket to /*
close as fast as possible without waiting for anything. If the * Set socket options for the connection. We want the socket to
connection is not a socket, these will do nothing. */ * close as fast as possible without waiting for anything. If the
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, * connection is not a socket, these will do nothing.
sizeof(on)); */ */
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
linger.l_onoff = 1; linger.l_onoff = 1;
linger.l_linger = 5; linger.l_linger = 5;
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
/* Register our connection. This turns encryption off because we /*
do not have a key. */ * Register our connection. This turns encryption off because we do
* not have a key.
*/
packet_set_connection(sock_in, sock_out); packet_set_connection(sock_in, sock_out);
remote_port = get_remote_port(); remote_port = get_remote_port();
@ -777,12 +796,14 @@ main(int ac, char **av)
verbose("Connection from %.500s port %d", remote_ip, remote_port); verbose("Connection from %.500s port %d", remote_ip, remote_port);
#endif /* LIBWRAP */ #endif /* LIBWRAP */
/* We don\'t want to listen forever unless the other side /*
successfully authenticates itself. So we set up an alarm which * We don\'t want to listen forever unless the other side
is cleared after successful authentication. A limit of zero * successfully authenticates itself. So we set up an alarm which is
indicates no limit. Note that we don\'t set the alarm in * cleared after successful authentication. A limit of zero
debugging mode; it is just annoying to have the server exit * indicates no limit. Note that we don\'t set the alarm in debugging
just when you are about to discover the bug. */ * mode; it is just annoying to have the server exit just when you
* are about to discover the bug.
*/
signal(SIGALRM, grace_alarm_handler); signal(SIGALRM, grace_alarm_handler);
if (!debug_flag) if (!debug_flag)
alarm(options.login_grace_time); alarm(options.login_grace_time);
@ -815,8 +836,10 @@ main(int ac, char **av)
buf[sizeof(buf) - 1] = 0; buf[sizeof(buf) - 1] = 0;
} }
/* Check that the versions match. In future this might accept /*
several versions and set appropriate flags to handle them. */ * Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
remote_version) != 3) { remote_version) != 3) {
const char *s = "Protocol mismatch.\n"; const char *s = "Protocol mismatch.\n";
@ -848,11 +871,13 @@ main(int ac, char **av)
no_agent_forwarding_flag = 1; no_agent_forwarding_flag = 1;
} }
} }
/* Check that the connection comes from a privileged port. Rhosts- /*
and Rhosts-RSA-Authentication only make sense from priviledged * Check that the connection comes from a privileged port. Rhosts-
programs. Of course, if the intruder has root access on his * and Rhosts-RSA-Authentication only make sense from priviledged
local machine, he can connect from any port. So do not use * programs. Of course, if the intruder has root access on his local
these authentication methods from machines that you do not trust. */ * machine, he can connect from any port. So do not use these
* authentication methods from machines that you do not trust.
*/
if (remote_port >= IPPORT_RESERVED || if (remote_port >= IPPORT_RESERVED ||
remote_port < IPPORT_RESERVED / 2) { remote_port < IPPORT_RESERVED / 2) {
options.rhosts_authentication = 0; options.rhosts_authentication = 0;
@ -914,13 +939,15 @@ do_connection()
int plen, slen; int plen, slen;
u_int32_t rand = 0; u_int32_t rand = 0;
/* Generate check bytes that the client must send back in the user /*
packet in order for it to be accepted; this is used to defy ip * Generate check bytes that the client must send back in the user
spoofing attacks. Note that this only works against somebody * packet in order for it to be accepted; this is used to defy ip
doing IP spoofing from a remote machine; any machine on the * spoofing attacks. Note that this only works against somebody
local network can still see outgoing packets and catch the * doing IP spoofing from a remote machine; any machine on the local
random cookie. This only affects rhosts authentication, and * network can still see outgoing packets and catch the random
this is one of the reasons why it is inherently insecure. */ * cookie. This only affects rhosts authentication, and this is one
* of the reasons why it is inherently insecure.
*/
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (i % 4 == 0) if (i % 4 == 0)
rand = arc4random(); rand = arc4random();
@ -928,9 +955,11 @@ do_connection()
rand >>= 8; rand >>= 8;
} }
/* Send our public key. We include in the packet 64 bits of /*
random data that must be matched in the reply in order to * Send our public key. We include in the packet 64 bits of random
prevent IP spoofing. */ * data that must be matched in the reply in order to prevent IP
* spoofing.
*/
packet_start(SSH_SMSG_PUBLIC_KEY); packet_start(SSH_SMSG_PUBLIC_KEY);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
packet_put_char(check_bytes[i]); packet_put_char(check_bytes[i]);
@ -1002,14 +1031,15 @@ do_connection()
session_key_int = BN_new(); session_key_int = BN_new();
packet_get_bignum(session_key_int, &slen); packet_get_bignum(session_key_int, &slen);
/* Get protocol flags. */
protocol_flags = packet_get_int(); protocol_flags = packet_get_int();
packet_set_protocol_flags(protocol_flags); packet_set_protocol_flags(protocol_flags);
packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY); packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
/* Decrypt it using our private server key and private host key /*
(key with larger modulus first). */ * Decrypt it using our private server key and private host key (key
* with larger modulus first).
*/
if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) { if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
/* Private key has bigger modulus. */ /* Private key has bigger modulus. */
if (BN_num_bits(sensitive_data.private_key->n) < if (BN_num_bits(sensitive_data.private_key->n) <
@ -1040,14 +1070,15 @@ do_connection()
sensitive_data.private_key); sensitive_data.private_key);
} }
/* Compute session id for this session. */
compute_session_id(session_id, check_bytes, compute_session_id(session_id, check_bytes,
sensitive_data.host_key->n, sensitive_data.host_key->n,
sensitive_data.private_key->n); sensitive_data.private_key->n);
/* Extract session key from the decrypted integer. The key is in /*
the least significant 256 bits of the integer; the first byte * Extract session key from the decrypted integer. The key is in the
of the key is in the highest bits. */ * least significant 256 bits of the integer; the first byte of the
* key is in the highest bits.
*/
BN_mask_bits(session_key_int, sizeof(session_key) * 8); BN_mask_bits(session_key_int, sizeof(session_key) * 8);
len = BN_num_bytes(session_key_int); len = BN_num_bytes(session_key_int);
if (len < 0 || len > sizeof(session_key)) if (len < 0 || len > sizeof(session_key))
@ -1125,8 +1156,7 @@ allowed_user(struct passwd * pw)
if (match_pattern(pw->pw_name, options.deny_users[i])) if (match_pattern(pw->pw_name, options.deny_users[i]))
return 0; return 0;
} }
/* Return false if AllowUsers isn't empty and user isn't listed /* Return false if AllowUsers isn't empty and user isn't listed there */
there */
if (options.num_allow_users > 0) { if (options.num_allow_users > 0) {
if (!pw->pw_name) if (!pw->pw_name)
return 0; return 0;
@ -1151,8 +1181,10 @@ allowed_user(struct passwd * pw)
if (match_pattern(grp->gr_name, options.deny_groups[i])) if (match_pattern(grp->gr_name, options.deny_groups[i]))
return 0; return 0;
} }
/* Return false if AllowGroups isn't empty and user's /*
group isn't listed there */ * Return false if AllowGroups isn't empty and user's group
* isn't listed there
*/
if (options.num_allow_groups > 0) { if (options.num_allow_groups > 0) {
if (!grp->gr_name) if (!grp->gr_name)
return 0; return 0;
@ -1216,8 +1248,10 @@ do_authentication(char *user)
} }
#endif #endif
/* If we are not running as root, the user must have the same uid /*
as the server. */ * If we are not running as root, the user must have the same uid as
* the server.
*/
if (getuid() != 0 && pw->pw_uid != getuid()) if (getuid() != 0 && pw->pw_uid != getuid())
packet_disconnect("Cannot change user when server not running as root."); packet_disconnect("Cannot change user when server not running as root.");
@ -1357,10 +1391,12 @@ do_authloop(struct passwd * pw)
verbose("Rhosts authentication disabled."); verbose("Rhosts authentication disabled.");
break; break;
} }
/* Get client user name. Note that we just have /*
to trust the client; this is one reason why * Get client user name. Note that we just have to
rhosts authentication is insecure. (Another is * trust the client; this is one reason why rhosts
IP-spoofing on a local network.) */ * authentication is insecure. (Another is
* IP-spoofing on a local network.)
*/
client_user = packet_get_string(&ulen); client_user = packet_get_string(&ulen);
packet_integrity_check(plen, 4 + ulen, type); packet_integrity_check(plen, 4 + ulen, type);
@ -1379,9 +1415,11 @@ do_authloop(struct passwd * pw)
verbose("Rhosts with RSA authentication disabled."); verbose("Rhosts with RSA authentication disabled.");
break; break;
} }
/* Get client user name. Note that we just have /*
to trust the client; root on the client machine * Get client user name. Note that we just have to
can claim to be any user. */ * trust the client; root on the client machine can
* claim to be any user.
*/
client_user = packet_get_string(&ulen); client_user = packet_get_string(&ulen);
/* Get the client host key. */ /* Get the client host key. */
@ -1425,9 +1463,11 @@ do_authloop(struct passwd * pw)
verbose("Password authentication disabled."); verbose("Password authentication disabled.");
break; break;
} }
/* Read user password. It is in plain text, but /*
was transmitted over the encrypted channel so * Read user password. It is in plain text, but was
it is not visible to an outside observer. */ * transmitted over the encrypted channel so it is
* not visible to an outside observer.
*/
password = packet_get_string(&dlen); password = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type); packet_integrity_check(plen, 4 + dlen, type);
@ -1463,8 +1503,7 @@ do_authloop(struct passwd * pw)
skeyinfo = skey_fake_keyinfo(pw->pw_name); skeyinfo = skey_fake_keyinfo(pw->pw_name);
} }
if (skeyinfo != NULL) { if (skeyinfo != NULL) {
/* we send our s/key- in /* we send our s/key- in tis-challenge messages */
tis-challenge messages */
debug("sending challenge '%s'", skeyinfo); debug("sending challenge '%s'", skeyinfo);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_string(skeyinfo, strlen(skeyinfo)); packet_put_string(skeyinfo, strlen(skeyinfo));
@ -1493,8 +1532,10 @@ do_authloop(struct passwd * pw)
#endif #endif
default: default:
/* Any unknown messages will be ignored (and /*
failure returned) during authentication. */ * Any unknown messages will be ignored (and failure
* returned) during authentication.
*/
log("Unknown message during authentication: type %d", type); log("Unknown message during authentication: type %d", type);
break; break;
} }
@ -1559,11 +1600,12 @@ do_fake_authloop(char *user)
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
/* Keep reading packets, and always respond with a failure. This /*
is to avoid disclosing whether such a user really exists. */ * Keep reading packets, and always respond with a failure. This is
* to avoid disclosing whether such a user really exists.
*/
for (attempt = 1;; attempt++) { for (attempt = 1;; attempt++) {
/* Read a packet. This will not return if the client /* Read a packet. This will not return if the client disconnects. */
disconnects. */
int plen; int plen;
int type = packet_read(&plen); int type = packet_read(&plen);
#ifdef SKEY #ifdef SKEY
@ -1583,8 +1625,10 @@ do_fake_authloop(char *user)
if (attempt > AUTH_FAIL_MAX) if (attempt > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, user); packet_disconnect(AUTH_FAIL_MSG, user);
/* Send failure. This should be indistinguishable from a /*
failed authentication. */ * Send failure. This should be indistinguishable from a
* failed authentication.
*/
packet_start(SSH_SMSG_FAILURE); packet_start(SSH_SMSG_FAILURE);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
@ -1630,19 +1674,25 @@ do_authenticated(struct passwd * pw)
mode_t tty_mode; mode_t tty_mode;
int n_bytes; int n_bytes;
/* Cancel the alarm we set to limit the time taken for /*
authentication. */ * Cancel the alarm we set to limit the time taken for
* authentication.
*/
alarm(0); alarm(0);
/* Inform the channel mechanism that we are the server side and /*
that the client may request to connect to any port at all. * Inform the channel mechanism that we are the server side and that
(The user could do it anyway, and we wouldn\'t know what is * the client may request to connect to any port at all. (The user
permitted except by the client telling us, so we can equally * could do it anyway, and we wouldn\'t know what is permitted except
well trust the client not to request anything bogus.) */ * by the client telling us, so we can equally well trust the client
* not to request anything bogus.)
*/
channel_permit_all_opens(); channel_permit_all_opens();
/* We stay in this loop until the client requests to execute a /*
shell or a command. */ * We stay in this loop until the client requests to execute a shell
* or a command.
*/
while (1) { while (1) {
int plen, dlen; int plen, dlen;
@ -1826,8 +1876,10 @@ do_authenticated(struct passwd * pw)
return; return;
default: default:
/* Any unknown messages in this phase are ignored, /*
and a failure message is returned. */ * Any unknown messages in this phase are ignored,
* and a failure message is returned.
*/
log("Unknown packet type received after authentication: %d", type); log("Unknown packet type received after authentication: %d", type);
goto fail; goto fail;
} }
@ -1852,8 +1904,10 @@ fail:
continue; continue;
do_forced_command: do_forced_command:
/* There is a forced command specified for this login. /*
Execute it. */ * There is a forced command specified for this login.
* Execute it.
*/
debug("Executing forced command: %.900s", forced_command); debug("Executing forced command: %.900s", forced_command);
if (have_pty) if (have_pty)
do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data); do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
@ -1897,14 +1951,18 @@ do_exec_no_pty(const char *command, struct passwd * pw,
/* Child. Reinitialize the log since the pid has changed. */ /* Child. Reinitialize the log since the pid has changed. */
log_init(av0, options.log_level, options.log_facility, log_stderr); log_init(av0, options.log_level, options.log_facility, log_stderr);
/* Create a new session and process group since the 4.4BSD /*
setlogin() affects the entire process group. */ * Create a new session and process group since the 4.4BSD
* setlogin() affects the entire process group.
*/
if (setsid() < 0) if (setsid() < 0)
error("setsid failed: %.100s", strerror(errno)); error("setsid failed: %.100s", strerror(errno));
#ifdef USE_PIPES #ifdef USE_PIPES
/* Redirect stdin. We close the parent side of the socket /*
pair, and make the child side the standard input. */ * Redirect stdin. We close the parent side of the socket
* pair, and make the child side the standard input.
*/
close(pin[1]); close(pin[1]);
if (dup2(pin[0], 0) < 0) if (dup2(pin[0], 0) < 0)
perror("dup2 stdin"); perror("dup2 stdin");
@ -1922,9 +1980,11 @@ do_exec_no_pty(const char *command, struct passwd * pw,
perror("dup2 stderr"); perror("dup2 stderr");
close(perr[1]); close(perr[1]);
#else /* USE_PIPES */ #else /* USE_PIPES */
/* Redirect stdin, stdout, and stderr. Stdin and stdout /*
will use the same socket, as some programs * Redirect stdin, stdout, and stderr. Stdin and stdout will
(particularly rdist) seem to depend on it. */ * use the same socket, as some programs (particularly rdist)
* seem to depend on it.
*/
close(inout[1]); close(inout[1]);
close(err[1]); close(err[1]);
if (dup2(inout[0], 0) < 0) /* stdin */ if (dup2(inout[0], 0) < 0) /* stdin */
@ -1955,8 +2015,10 @@ do_exec_no_pty(const char *command, struct passwd * pw,
close(inout[0]); close(inout[0]);
close(err[0]); close(err[0]);
/* Enter the interactive session. Note: server_loop must be able /*
to handle the case that fdin and fdout are the same. */ * Enter the interactive session. Note: server_loop must be able to
* handle the case that fdin and fdout are the same.
*/
server_loop(pid, inout[1], inout[1], err[1]); server_loop(pid, inout[1], inout[1], err[1]);
/* server_loop has closed inout[1] and err[1]. */ /* server_loop has closed inout[1] and err[1]. */
#endif /* USE_PIPES */ #endif /* USE_PIPES */
@ -2012,8 +2074,10 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
/* Get remote host name. */ /* Get remote host name. */
hostname = get_canonical_hostname(); hostname = get_canonical_hostname();
/* Get the time when the user last logged in. Buf will be set to /*
contain the hostname the last login was from. */ * Get the time when the user last logged in. Buf will be set to
* contain the hostname the last login was from.
*/
if (!options.use_login) { if (!options.use_login) {
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
buf, sizeof(buf)); buf, sizeof(buf));
@ -2049,9 +2113,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
/* Close the extra descriptor for the pseudo tty. */ /* Close the extra descriptor for the pseudo tty. */
close(ttyfd); close(ttyfd);
/* Get IP address of client. This is needed because we /*
want to record where the user logged in from. If the * Get IP address of client. This is needed because we want
connection is not a socket, let the ip address be 0.0.0.0. */ * to record where the user logged in from. If the
* connection is not a socket, let the ip address be 0.0.0.0.
*/
memset(&from, 0, sizeof(from)); memset(&from, 0, sizeof(from));
if (packet_get_connection_in() == packet_get_connection_out()) { if (packet_get_connection_in() == packet_get_connection_out()) {
fromlen = sizeof(from); fromlen = sizeof(from);
@ -2075,12 +2141,14 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
fprintf(stderr, pamconv_msg); fprintf(stderr, pamconv_msg);
#endif #endif
/* If the user has logged in before, display the time of /*
last login. However, don't display anything extra if a * If the user has logged in before, display the time of last
command has been specified (so that ssh can be used to * login. However, don't display anything extra if a command
execute commands on a remote machine without users * has been specified (so that ssh can be used to execute
knowing they are going to another machine). Login(1) * commands on a remote machine without users knowing they
will do this for us as well, so check if login(1) is used */ * are going to another machine). Login(1) will do this for
* us as well, so check if login(1) is used
*/
if (command == NULL && last_login_time != 0 && !quiet_login && if (command == NULL && last_login_time != 0 && !quiet_login &&
!options.use_login) { !options.use_login) {
/* Convert the date to a string. */ /* Convert the date to a string. */
@ -2095,10 +2163,12 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
else else
printf("Last login: %s from %s\r\n", time_string, buf); printf("Last login: %s from %s\r\n", time_string, buf);
} }
/* Print /etc/motd unless a command was specified or /*
printing it was disabled in server options or login(1) * Print /etc/motd unless a command was specified or printing
will be used. Note that some machines appear to print * it was disabled in server options or login(1) will be
it in /etc/profile or similar. */ * used. Note that some machines appear to print it in
* /etc/profile or similar.
*/
if (command == NULL && options.print_motd && !quiet_login && if (command == NULL && options.print_motd && !quiet_login &&
!options.use_login) { !options.use_login) {
/* Print /etc/motd if it exists. */ /* Print /etc/motd if it exists. */
@ -2118,15 +2188,19 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
/* Parent. Close the slave side of the pseudo tty. */ /* Parent. Close the slave side of the pseudo tty. */
close(ttyfd); close(ttyfd);
/* Create another descriptor of the pty master side for use as the /*
standard input. We could use the original descriptor, but this * Create another descriptor of the pty master side for use as the
simplifies code in server_loop. The descriptor is bidirectional. */ * standard input. We could use the original descriptor, but this
* simplifies code in server_loop. The descriptor is bidirectional.
*/
fdout = dup(ptyfd); fdout = dup(ptyfd);
if (fdout < 0) if (fdout < 0)
packet_disconnect("dup failed: %.100s", strerror(errno)); packet_disconnect("dup failed: %.100s", strerror(errno));
/* Add a cleanup function to clear the utmp entry and record logout /*
time in case we call fatal() (e.g., the connection gets closed). */ * Add a cleanup function to clear the utmp entry and record logout
* time in case we call fatal() (e.g., the connection gets closed).
*/
cleanup_context.pid = pid; cleanup_context.pid = pid;
cleanup_context.ttyname = ttyname; cleanup_context.ttyname = ttyname;
fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context); fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
@ -2144,9 +2218,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
/* Release the pseudo-tty. */ /* Release the pseudo-tty. */
pty_release(ttyname); pty_release(ttyname);
/* Close the server side of the socket pairs. We must do this /*
after the pty cleanup, so that another process doesn't get this * Close the server side of the socket pairs. We must do this after
pty while we're still cleaning up. */ * the pty cleanup, so that another process doesn't get this pty
* while we're still cleaning up.
*/
close(ptyfd); close(ptyfd);
close(fdout); close(fdout);
} }
@ -2162,19 +2238,21 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name,
unsigned int i, namelen; unsigned int i, namelen;
char **env; char **env;
/* Find the slot where the value should be stored. If the /*
variable already exists, we reuse the slot; otherwise we append * Find the slot where the value should be stored. If the variable
a new slot at the end of the array, expanding if necessary. */ * already exists, we reuse the slot; otherwise we append a new slot
* at the end of the array, expanding if necessary.
*/
env = *envp; env = *envp;
namelen = strlen(name); namelen = strlen(name);
for (i = 0; env[i]; i++) for (i = 0; env[i]; i++)
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
break; break;
if (env[i]) { if (env[i]) {
/* Name already exists. Reuse the slot. */ /* Reuse the slot. */
xfree(env[i]); xfree(env[i]);
} else { } else {
/* New variable. Expand the array if necessary. */ /* New variable. Expand if necessary. */
if (i >= (*envsizep) - 1) { if (i >= (*envsizep) - 1) {
(*envsizep) += 50; (*envsizep) += 50;
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
@ -2202,40 +2280,27 @@ read_environment_file(char ***env, unsigned int *envsize,
char buf[4096]; char buf[4096];
char *cp, *value; char *cp, *value;
/* Open the environment file. */
f = fopen(filename, "r"); f = fopen(filename, "r");
if (!f) if (!f)
return; return;
/* Process each line. */
while (fgets(buf, sizeof(buf), f)) { while (fgets(buf, sizeof(buf), f)) {
/* Skip leading whitespace. */ for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++); ;
/* Ignore empty and comment lines. */
if (!*cp || *cp == '#' || *cp == '\n') if (!*cp || *cp == '#' || *cp == '\n')
continue; continue;
/* Remove newline. */
if (strchr(cp, '\n')) if (strchr(cp, '\n'))
*strchr(cp, '\n') = '\0'; *strchr(cp, '\n') = '\0';
/* Find the equals sign. Its lack indicates badly
formatted line. */
value = strchr(cp, '='); value = strchr(cp, '=');
if (value == NULL) { if (value == NULL) {
fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
continue; continue;
} }
/* Replace the equals sign by nul, and advance value to /* Replace the equals sign by nul, and advance value to the value string. */
the value string. */
*value = '\0'; *value = '\0';
value++; value++;
/* Set the value in environment. */
child_set_env(env, envsize, cp, value); child_set_env(env, envsize, cp, value);
} }
fclose(f); fclose(f);
} }
@ -2299,8 +2364,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %d.", (int) pw->pw_uid); fatal("Failed to set uids to %d.", (int) pw->pw_uid);
} }
/* Get the shell from the password data. An empty shell field is /*
legal, and means /bin/sh. */ * Get the shell from the password data. An empty shell field is
* legal, and means /bin/sh.
*/
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
#ifdef AFS #ifdef AFS
@ -2315,8 +2382,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
} }
#endif /* AFS */ #endif /* AFS */
/* Initialize the environment. In the first part we allocate /* Initialize the environment. */
space for all environment variables. */
envsize = 100; envsize = 100;
env = xmalloc(envsize * sizeof(char *)); env = xmalloc(envsize * sizeof(char *));
env[0] = NULL; env[0] = NULL;
@ -2335,7 +2401,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
/* Normal systems set SHELL by default. */ /* Normal systems set SHELL by default. */
child_set_env(&env, &envsize, "SHELL", shell); child_set_env(&env, &envsize, "SHELL", shell);
} }
/* Let it inherit timezone if we have one. */
if (getenv("TZ")) if (getenv("TZ"))
child_set_env(&env, &envsize, "TZ", getenv("TZ")); child_set_env(&env, &envsize, "TZ", getenv("TZ"));
@ -2354,20 +2419,14 @@ do_child(const char *command, struct passwd * pw, const char *term,
xfree(ce); xfree(ce);
} }
/* Set SSH_CLIENT. */
snprintf(buf, sizeof buf, "%.50s %d %d", snprintf(buf, sizeof buf, "%.50s %d %d",
get_remote_ipaddr(), get_remote_port(), options.port); get_remote_ipaddr(), get_remote_port(), options.port);
child_set_env(&env, &envsize, "SSH_CLIENT", buf); child_set_env(&env, &envsize, "SSH_CLIENT", buf);
/* Set SSH_TTY if we have a pty. */
if (ttyname) if (ttyname)
child_set_env(&env, &envsize, "SSH_TTY", ttyname); child_set_env(&env, &envsize, "SSH_TTY", ttyname);
/* Set TERM if we have a pty. */
if (term) if (term)
child_set_env(&env, &envsize, "TERM", term); child_set_env(&env, &envsize, "TERM", term);
/* Set DISPLAY if we have one. */
if (display) if (display)
child_set_env(&env, &envsize, "DISPLAY", display); child_set_env(&env, &envsize, "DISPLAY", display);
@ -2400,52 +2459,57 @@ do_child(const char *command, struct passwd * pw, const char *term,
} }
#endif /* HAVE_LIBPAM */ #endif /* HAVE_LIBPAM */
/* Set XAUTHORITY to always be a local file. */
if (xauthfile) if (xauthfile)
child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
/* Set variable for forwarded authentication connection, if we
have one. */
if (auth_get_socket_name() != NULL) if (auth_get_socket_name() != NULL)
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
auth_get_socket_name()); auth_get_socket_name());
/* Read $HOME/.ssh/environment. */ /* read $HOME/.ssh/environment. */
if (!options.use_login) { if (!options.use_login) {
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir); snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
read_environment_file(&env, &envsize, buf); read_environment_file(&env, &envsize, buf);
} }
/* If debugging, dump the environment to stderr. */
if (debug_flag) { if (debug_flag) {
/* dump the environment */
fprintf(stderr, "Environment:\n"); fprintf(stderr, "Environment:\n");
for (i = 0; env[i]; i++) for (i = 0; env[i]; i++)
fprintf(stderr, " %.200s\n", env[i]); fprintf(stderr, " %.200s\n", env[i]);
} }
/* Close the connection descriptors; note that this is the child, /*
and the server will still have the socket open, and it is * Close the connection descriptors; note that this is the child, and
important that we do not shutdown it. Note that the * the server will still have the socket open, and it is important
descriptors cannot be closed before building the environment, * that we do not shutdown it. Note that the descriptors cannot be
as we call get_remote_ipaddr there. */ * closed before building the environment, as we call
* get_remote_ipaddr there.
*/
if (packet_get_connection_in() == packet_get_connection_out()) if (packet_get_connection_in() == packet_get_connection_out())
close(packet_get_connection_in()); close(packet_get_connection_in());
else { else {
close(packet_get_connection_in()); close(packet_get_connection_in());
close(packet_get_connection_out()); close(packet_get_connection_out());
} }
/* Close all descriptors related to channels. They will still /*
remain open in the parent. */ * Close all descriptors related to channels. They will still remain
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
channel_close_all(); channel_close_all();
/* Close any extra file descriptors. Note that there may still be /*
descriptors left by system functions. They will be closed * Close any extra file descriptors. Note that there may still be
later. */ * descriptors left by system functions. They will be closed later.
*/
endpwent(); endpwent();
endhostent(); endhostent();
/* Close any extra open file descriptors so that we don\'t have /*
them hanging around in clients. Note that we want to do this * Close any extra open file descriptors so that we don\'t have them
after initgroups, because at least on Solaris 2.3 it leaves * hanging around in clients. Note that we want to do this after
file descriptors open. */ * initgroups, because at least on Solaris 2.3 it leaves file
* descriptors open.
*/
for (i = 3; i < 64; i++) for (i = 3; i < 64; i++)
close(i); close(i);
@ -2454,12 +2518,16 @@ do_child(const char *command, struct passwd * pw, const char *term,
fprintf(stderr, "Could not chdir to home directory %s: %s\n", fprintf(stderr, "Could not chdir to home directory %s: %s\n",
pw->pw_dir, strerror(errno)); pw->pw_dir, strerror(errno));
/* Must take new environment into use so that .ssh/rc, /etc/sshrc /*
and xauth are run in the proper environment. */ * Must take new environment into use so that .ssh/rc, /etc/sshrc and
* xauth are run in the proper environment.
*/
environ = env; environ = env;
/* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found /*
first in this order). */ * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
* in this order).
*/
if (!options.use_login) { if (!options.use_login) {
if (stat(SSH_USER_RC, &st) >= 0) { if (stat(SSH_USER_RC, &st) >= 0) {
if (debug_flag) if (debug_flag)
@ -2486,8 +2554,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
} }
#ifdef XAUTH_PATH #ifdef XAUTH_PATH
else { else {
/* Add authority data to .Xauthority if /* Add authority data to .Xauthority if appropriate. */
appropriate. */
if (auth_proto != NULL && auth_data != NULL) { if (auth_proto != NULL && auth_data != NULL) {
if (debug_flag) if (debug_flag)
fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
@ -2510,15 +2577,19 @@ do_child(const char *command, struct passwd * pw, const char *term,
else else
cp = shell; cp = shell;
} }
/* If we have no command, execute the shell. In this case, the /*
shell name to be passed in argv[0] is preceded by '-' to * If we have no command, execute the shell. In this case, the shell
indicate that this is a login shell. */ * name to be passed in argv[0] is preceded by '-' to indicate that
* this is a login shell.
*/
if (!command) { if (!command) {
if (!options.use_login) { if (!options.use_login) {
char buf[256]; char buf[256];
/* Check for mail if we have a tty and it was /*
enabled in server options. */ * Check for mail if we have a tty and it was enabled
* in server options.
*/
if (ttyname && options.check_mail) { if (ttyname && options.check_mail) {
char *mailbox; char *mailbox;
struct stat mailstat; struct stat mailstat;
@ -2558,8 +2629,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
exit(1); exit(1);
} }
} }
/* Execute the command using the user's shell. This uses the -c /*
option to execute the command. */ * Execute the command using the user's shell. This uses the -c
* option to execute the command.
*/
argv[0] = (char *) cp; argv[0] = (char *) cp;
argv[1] = "-c"; argv[1] = "-c";
argv[2] = (char *) command; argv[2] = (char *) command;

View File

@ -6,7 +6,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: tildexpand.c,v 1.2 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: tildexpand.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -47,12 +47,12 @@ tilde_expand_filename(const char *filename, uid_t my_uid)
user[userlen] = 0; user[userlen] = 0;
pw = getpwnam(user); pw = getpwnam(user);
} }
/* Check that we found the user. */
if (!pw) if (!pw)
fatal("Unknown user %100s.", user); fatal("Unknown user %100s.", user);
/* If referring to someones home directory, return it now. */ /* If referring to someones home directory, return it now. */
if (!cp) { /* Only home directory specified */ if (!cp) {
/* Only home directory specified */
return xstrdup(pw->pw_dir); return xstrdup(pw->pw_dir);
} }
/* Build a path combining the specified directory and path. */ /* Build a path combining the specified directory and path. */

View File

@ -10,7 +10,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ttymodes.c,v 1.2 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: ttymodes.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
@ -209,7 +209,6 @@ tty_make_modes(int fd)
struct termios tio; struct termios tio;
int baud; int baud;
/* Get the modes. */
if (tcgetattr(fd, &tio) < 0) { if (tcgetattr(fd, &tio) < 0) {
packet_put_char(TTY_OP_END); packet_put_char(TTY_OP_END);
log("tcgetattr: %.100s", strerror(errno)); log("tcgetattr: %.100s", strerror(errno));

View File

@ -12,7 +12,7 @@
* *
*/ */
/* RCSID("$Id: ttymodes.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */ /* RCSID("$Id: ttymodes.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
/* The tty mode description is a stream of bytes. The stream consists of /* The tty mode description is a stream of bytes. The stream consists of
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0). * opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
@ -29,10 +29,10 @@
/* /*
* Some constants and prototypes are defined in packet.h; this file * Some constants and prototypes are defined in packet.h; this file
* is only intended for including from ttymodes.h. * is only intended for including from ttymodes.c.
*/ */
/* termios macro *//* sgtty macro */ /* termios macro */ /* sgtty macro */
/* name, op */ /* name, op */
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1) TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2) TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
@ -92,7 +92,7 @@ TTYMODE(IXON, c_iflag, 38) /* n/a */
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39) TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40) TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
#ifdef IMAXBEL #ifdef IMAXBEL
TTYMODE(IMAXBEL, c_iflag, 41) /* n/a */ TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */
#endif /* IMAXBEL */ #endif /* IMAXBEL */
TTYMODE(ISIG, c_lflag, 50) /* n/a */ TTYMODE(ISIG, c_lflag, 50) /* n/a */
@ -110,7 +110,7 @@ TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */ TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
#endif /* IEXTEN */ #endif /* IEXTEN */
#if defined(ECHOCTL) #if defined(ECHOCTL)
TTYMODE(ECHOCTL, c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60) TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
#endif /* ECHOCTL */ #endif /* ECHOCTL */
#ifdef ECHOKE #ifdef ECHOKE
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */ TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
@ -138,3 +138,4 @@ TTYMODE(CS7, c_cflag, 90) /* n/a */
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91) TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
TTYMODE(PARENB, c_cflag, 92) /* n/a */ TTYMODE(PARENB, c_cflag, 92) /* n/a */
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93) TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)

View File

@ -7,7 +7,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: uidswap.c,v 1.2 1999/11/24 13:26:23 damien Exp $"); RCSID("$Id: uidswap.c,v 1.3 1999/11/25 00:55:00 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "uidswap.h" #include "uidswap.h"
@ -66,10 +66,11 @@ restore_uid()
if (seteuid(saved_euid) < 0) if (seteuid(saved_euid) < 0)
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno)); debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
#else /* SAVED_IDS_WORK_WITH_SETEUID */ #else /* SAVED_IDS_WORK_WITH_SETEUID */
/* We are unable to restore the real uid to its unprivileged /*
value. */ * We are unable to restore the real uid to its unprivileged value.
/* Propagate the real uid (usually more privileged) to effective * Propagate the real uid (usually more privileged) to effective uid
uid as well. */ * as well.
*/
setuid(getuid()); setuid(getuid());
#endif /* SAVED_IDS_WORK_WITH_SETEUID */ #endif /* SAVED_IDS_WORK_WITH_SETEUID */
} }