summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/openssh/auth-chall.c110
-rw-r--r--crypto/openssh/auth-krb4.c318
-rw-r--r--crypto/openssh/auth-krb5.c438
-rw-r--r--crypto/openssh/auth-pam.c4
-rw-r--r--crypto/openssh/auth-passwd.c28
-rw-r--r--crypto/openssh/auth-rh-rsa.c51
-rw-r--r--crypto/openssh/auth-rsa.c107
-rw-r--r--crypto/openssh/auth.c230
-rw-r--r--crypto/openssh/auth.h168
-rw-r--r--crypto/openssh/auth1.c262
-rw-r--r--crypto/openssh/auth2.c478
-rw-r--r--crypto/openssh/authfd.c51
-rw-r--r--crypto/openssh/authfile.c118
-rw-r--r--crypto/openssh/bufaux.c25
-rw-r--r--crypto/openssh/canohost.c48
-rw-r--r--crypto/openssh/channels.c1754
-rw-r--r--crypto/openssh/channels.h342
-rw-r--r--crypto/openssh/cipher.c717
-rw-r--r--crypto/openssh/cipher.h79
-rw-r--r--crypto/openssh/compat.c138
-rw-r--r--crypto/openssh/compat.h55
-rw-r--r--crypto/openssh/hostfile.c17
-rw-r--r--crypto/openssh/includes.h10
-rw-r--r--crypto/openssh/key.c146
-rw-r--r--crypto/openssh/packet.h251
-rw-r--r--crypto/openssh/pathnames.h37
-rw-r--r--crypto/openssh/readconf.c225
-rw-r--r--crypto/openssh/readconf.h77
-rw-r--r--crypto/openssh/rijndael.c2
-rw-r--r--crypto/openssh/rsa.c13
-rw-r--r--crypto/openssh/rsa.h13
-rw-r--r--crypto/openssh/servconf.c1034
-rw-r--r--crypto/openssh/servconf.h68
-rw-r--r--crypto/openssh/serverloop.c440
-rw-r--r--crypto/openssh/session.c1355
-rw-r--r--crypto/openssh/ssh-add.c211
-rw-r--r--crypto/openssh/ssh-agent.c386
-rw-r--r--crypto/openssh/ssh.1420
-rw-r--r--crypto/openssh/ssh.c446
-rw-r--r--crypto/openssh/ssh.h10
-rw-r--r--crypto/openssh/ssh_config24
-rw-r--r--crypto/openssh/sshconnect.c548
-rw-r--r--crypto/openssh/sshconnect.h29
-rw-r--r--crypto/openssh/sshconnect1.c745
-rw-r--r--crypto/openssh/sshconnect2.c239
-rw-r--r--crypto/openssh/sshd.8392
-rw-r--r--crypto/openssh/sshd.c308
-rw-r--r--crypto/openssh/sshd_config117
-rw-r--r--crypto/openssh/sshlogin.c6
-rw-r--r--crypto/openssh/sshpty.c26
-rw-r--r--crypto/openssh/version.h10
51 files changed, 6809 insertions, 6317 deletions
diff --git a/crypto/openssh/auth-chall.c b/crypto/openssh/auth-chall.c
index a87799b..147e998 100644
--- a/crypto/openssh/auth-chall.c
+++ b/crypto/openssh/auth-chall.c
@@ -23,83 +23,61 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
+RCSID("$OpenBSD: auth-chall.c,v 1.8 2001/05/18 14:13:28 markus Exp $");
RCSID("$FreeBSD$");
#include "auth.h"
#include "log.h"
+#include "xmalloc.h"
-#ifdef BSD_AUTH
-char *
-get_challenge(Authctxt *authctxt, char *devs)
-{
- char *challenge;
+/* limited protocol v1 interface to kbd-interactive authentication */
- if (authctxt->as != NULL) {
- debug2("try reuse session");
- challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
- if (challenge != NULL) {
- debug2("reuse bsd auth session");
- return challenge;
- }
- auth_close(authctxt->as);
- authctxt->as = NULL;
- }
- debug2("new bsd auth session");
- if (devs == NULL || strlen(devs) == 0)
- devs = authctxt->style;
- debug3("bsd auth: devs %s", devs ? devs : "<default>");
- authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
- &challenge);
- if (authctxt->as == NULL)
- return NULL;
- debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
- return challenge;
-}
-int
-verify_response(Authctxt *authctxt, char *response)
-{
- int authok;
-
- if (authctxt->as == 0)
- error("verify_response: no bsd auth session");
- authok = auth_userresponse(authctxt->as, response, 0);
- authctxt->as = NULL;
- debug("verify_response: <%s> = <%d>", response, authok);
- return authok != 0;
-}
-#else
-#ifdef SKEY
-#include <opie.h>
+extern KbdintDevice *devices[];
+static KbdintDevice *device;
char *
-get_challenge(Authctxt *authctxt, char *devs)
+get_challenge(Authctxt *authctxt)
{
- static char challenge[1024];
- struct opie opie;
- if (opiechallenge(&opie, authctxt->user, challenge) == -1)
+ char *challenge, *name, *info, **prompts;
+ u_int i, numprompts;
+ u_int *echo_on;
+
+ device = devices[0]; /* we always use the 1st device for protocol 1 */
+ if (device == NULL)
return NULL;
- strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
- return challenge;
-}
-int
-verify_response(Authctxt *authctxt, char *response)
-{
- return (authctxt->valid &&
- opie_haskey(authctxt->pw->pw_name) == 0 &&
- opie_passverify(authctxt->pw->pw_name, response) != -1);
-}
-#else
-/* not available */
-char *
-get_challenge(Authctxt *authctxt, char *devs)
-{
- return NULL;
+ if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
+ return NULL;
+ if (device->query(authctxt->kbdintctxt, &name, &info,
+ &numprompts, &prompts, &echo_on)) {
+ device->free_ctx(authctxt->kbdintctxt);
+ authctxt->kbdintctxt = NULL;
+ return NULL;
+ }
+ if (numprompts < 1)
+ fatal("get_challenge: numprompts < 1");
+ challenge = xstrdup(prompts[0]);
+ for (i = 0; i < numprompts; i++)
+ xfree(prompts[i]);
+ xfree(prompts);
+ xfree(name);
+ xfree(echo_on);
+ xfree(info);
+
+ return (challenge);
}
int
-verify_response(Authctxt *authctxt, char *response)
+verify_response(Authctxt *authctxt, const char *response)
{
- return 0;
+ char *resp[1];
+ int res;
+
+ if (device == NULL)
+ return 0;
+ if (authctxt->kbdintctxt == NULL)
+ return 0;
+ resp[0] = (char *)response;
+ res = device->respond(authctxt->kbdintctxt, 1, resp);
+ device->free_ctx(authctxt->kbdintctxt);
+ authctxt->kbdintctxt = NULL;
+ return res ? 0 : 1;
}
-#endif
-#endif
diff --git a/crypto/openssh/auth-krb4.c b/crypto/openssh/auth-krb4.c
index bf63720..745b9c5 100644
--- a/crypto/openssh/auth-krb4.c
+++ b/crypto/openssh/auth-krb4.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
+RCSID("$OpenBSD: auth-krb4.c,v 1.25 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
@@ -32,6 +32,7 @@ RCSID("$FreeBSD$");
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
+#include "uidswap.h"
#include "auth.h"
#ifdef AFS
@@ -39,48 +40,92 @@ RCSID("$FreeBSD$");
#endif
#ifdef KRB4
-char *ticket = NULL;
-
extern ServerOptions options;
+static int
+krb4_init(void *context)
+{
+ static int cleanup_registered = 0;
+ Authctxt *authctxt = (Authctxt *)context;
+ const char *tkt_root = TKT_ROOT;
+ struct stat st;
+ int fd;
+
+ if (!authctxt->krb4_ticket_file) {
+ /* Set unique ticket string manually since we're still root. */
+ authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
+#ifdef AFS
+ if (lstat("/ticket", &st) != -1)
+ tkt_root = "/ticket/";
+#endif /* AFS */
+ snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d",
+ tkt_root, authctxt->pw->pw_uid, getpid());
+ krb_set_tkt_string(authctxt->krb4_ticket_file);
+ }
+ /* Register ticket cleanup in case of fatal error. */
+ if (!cleanup_registered) {
+ fatal_add_cleanup(krb4_cleanup_proc, authctxt);
+ cleanup_registered = 1;
+ }
+ /* Try to create our ticket file. */
+ if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
+ close(fd);
+ return (1);
+ }
+ /* Ticket file exists - make sure user owns it (just passed ticket). */
+ if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
+ if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
+ st.st_uid == authctxt->pw->pw_uid)
+ return (1);
+ }
+ /* Failure - cancel cleanup function, leaving ticket for inspection. */
+ log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
+
+ fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
+ cleanup_registered = 0;
+
+ xfree(authctxt->krb4_ticket_file);
+ authctxt->krb4_ticket_file = NULL;
+
+ return (0);
+}
+
/*
* try krb4 authentication,
* return 1 on success, 0 on failure, -1 if krb4 is not available
*/
-
int
-auth_krb4_password(struct passwd * pw, const char *password)
+auth_krb4_password(Authctxt *authctxt, const char *password)
{
AUTH_DAT adata;
KTEXT_ST tkt;
struct hostent *hp;
- u_long faddr;
- char localhost[MAXHOSTNAMELEN];
- char phost[INST_SZ];
- char realm[REALM_SZ];
+ struct passwd *pw;
+ char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
+ u_int32_t faddr;
int r;
+ if ((pw = authctxt->pw) == NULL)
+ return (0);
+
/*
* 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) {
-
/* Set up our ticket file. */
- if (!krb4_init(pw->pw_uid)) {
+ if (!krb4_init(authctxt)) {
log("Couldn't initialize Kerberos ticket file for %s!",
pw->pw_name);
- goto kerberos_auth_failure;
+ goto failure;
}
/* Try to get TGT using our password. */
- r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
- realm, "krbtgt", realm,
- DEFAULT_TKT_LIFE, (char *) password);
+ r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
+ "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
if (r != INTK_OK) {
- packet_send_debug("Kerberos V4 password "
- "authentication for %s failed: %s",
- pw->pw_name, krb_err_txt[r]);
- goto kerberos_auth_failure;
+ debug("Kerberos v4 password authentication for %s "
+ "failed: %s", pw->pw_name, krb_err_txt[r]);
+ goto failure;
}
/* Successful authentication. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
@@ -90,17 +135,17 @@ auth_krb4_password(struct passwd * pw, const char *password)
* "rcmd" ticket to ensure that we are not talking
* to a bogus Kerberos server.
*/
- (void) gethostname(localhost, sizeof(localhost));
- (void) strlcpy(phost, (char *) krb_get_phost(localhost),
- INST_SZ);
+ gethostname(localhost, sizeof(localhost));
+ strlcpy(phost, (char *)krb_get_phost(localhost),
+ sizeof(phost));
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
if (r == KSUCCESS) {
- if (!(hp = gethostbyname(localhost))) {
+ if ((hp = gethostbyname(localhost)) == NULL) {
log("Couldn't get local host address!");
- goto kerberos_auth_failure;
+ goto failure;
}
- memmove((void *) &faddr, (void *) hp->h_addr,
+ memmove((void *)&faddr, (void *)hp->h_addr,
sizeof(faddr));
/* Verify our "rcmd" ticket. */
@@ -111,116 +156,71 @@ auth_krb4_password(struct passwd * pw, const char *password)
* Probably didn't have a srvtab on
* localhost. Disallow login.
*/
- log("Kerberos V4 TGT for %s unverifiable, "
+ log("Kerberos v4 TGT for %s unverifiable, "
"no srvtab installed? krb_rd_req: %s",
pw->pw_name, krb_err_txt[r]);
- goto kerberos_auth_failure;
+ goto failure;
} else if (r != KSUCCESS) {
- log("Kerberos V4 %s ticket unverifiable: %s",
+ log("Kerberos v4 %s ticket unverifiable: %s",
KRB4_SERVICE_NAME, krb_err_txt[r]);
- goto kerberos_auth_failure;
+ goto failure;
}
} else if (r == KDC_PR_UNKNOWN) {
/*
* Disallow login if no rcmd service exists, and
* 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,
- krb_err_txt[r], KRB4_SERVICE_NAME, phost);
- goto kerberos_auth_failure;
+ krb_err_txt[r], KRB4_SERVICE_NAME, phost);
+ goto failure;
} else {
/*
* TGT is bad, forget it. Possibly spoofed!
*/
- packet_send_debug("WARNING: Kerberos V4 TGT "
- "possibly spoofed for %s: %s",
- pw->pw_name, krb_err_txt[r]);
- goto kerberos_auth_failure;
+ debug("WARNING: Kerberos v4 TGT possibly spoofed "
+ "for %s: %s", pw->pw_name, krb_err_txt[r]);
+ goto failure;
}
-
/* Authentication succeeded. */
- return 1;
+ return (1);
+ } else
+ /* Logging in as root or no local Kerberos realm. */
+ debug("Unable to authenticate to Kerberos.");
-kerberos_auth_failure:
- krb4_cleanup_proc(NULL);
+ failure:
+ krb4_cleanup_proc(authctxt);
+
+ if (!options.kerberos_or_local_passwd)
+ return (0);
- if (!options.krb4_or_local_passwd)
- return 0;
- } else {
- /* Logging in as root or no local Kerberos realm. */
- packet_send_debug("Unable to authenticate to Kerberos.");
- }
/* Fall back to ordinary passwd authentication. */
- return -1;
+ return (-1);
}
void
-krb4_cleanup_proc(void *ignore)
+krb4_cleanup_proc(void *context)
{
+ Authctxt *authctxt = (Authctxt *)context;
debug("krb4_cleanup_proc called");
- if (ticket) {
+ if (authctxt->krb4_ticket_file) {
(void) dest_tkt();
- xfree(ticket);
- ticket = NULL;
- }
-}
-
-int
-krb4_init(uid_t uid)
-{
- static int cleanup_registered = 0;
- const char *tkt_root = TKT_ROOT;
- struct stat st;
- int fd;
-
- if (!ticket) {
- /* Set unique ticket string manually since we're still root. */
- ticket = xmalloc(MAXPATHLEN);
-#ifdef AFS
- if (lstat("/ticket", &st) != -1)
- tkt_root = "/ticket/";
-#endif /* AFS */
- snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
- (void) krb_set_tkt_string(ticket);
- }
- /* Register ticket cleanup in case of fatal error. */
- if (!cleanup_registered) {
- fatal_add_cleanup(krb4_cleanup_proc, NULL);
- cleanup_registered = 1;
- }
- /* Try to create our ticket file. */
- if ((fd = mkstemp(ticket)) != -1) {
- close(fd);
- return 1;
+ xfree(authctxt->krb4_ticket_file);
+ authctxt->krb4_ticket_file = NULL;
}
- /* Ticket file exists - make sure user owns it (just passed ticket). */
- if (lstat(ticket, &st) != -1) {
- if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
- st.st_uid == uid)
- return 1;
- }
- /* Failure - cancel cleanup function, leaving bad ticket for inspection. */
- log("WARNING: bad ticket file %s", ticket);
- fatal_remove_cleanup(krb4_cleanup_proc, NULL);
- cleanup_registered = 0;
- xfree(ticket);
- ticket = NULL;
-
- return 0;
}
int
-auth_krb4(const char *server_user, KTEXT auth, char **client)
+auth_krb4(Authctxt *authctxt, KTEXT auth, char **client)
{
AUTH_DAT adat = {0};
KTEXT_ST reply;
+ Key_schedule schedule;
+ struct sockaddr_in local, foreign;
char instance[INST_SZ];
- int r, s;
socklen_t slen;
u_int cksum;
- Key_schedule schedule;
- struct sockaddr_in local, foreign;
+ int r, s;
s = packet_get_connection_in();
@@ -238,9 +238,10 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
instance[1] = 0;
/* Get the encrypted request, challenge, and session key. */
- if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
- packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
- return 0;
+ if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
+ 0, &adat, ""))) {
+ debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
+ return (0);
}
des_key_sched((des_cblock *) adat.session, schedule);
@@ -249,12 +250,11 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
*adat.pinst ? "." : "", adat.pinst, adat.prealm);
/* Check ~/.klogin authorization now. */
- if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
- packet_send_debug("Kerberos V4 .klogin authorization failed!");
- log("Kerberos V4 .klogin authorization failed for %s to account %s",
- *client, server_user);
+ if (kuserok(&adat, authctxt->user) != KSUCCESS) {
+ log("Kerberos v4 .klogin authorization failed for %s to "
+ "account %s", *client, authctxt->user);
xfree(*client);
- return 0;
+ return (0);
}
/* Increment the checksum, and return it encrypted with the
session key. */
@@ -265,7 +265,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
empty message, admitting our failure. */
if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
schedule, &adat.session, &local, &foreign)) < 0) {
- packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
+ debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
reply.dat[0] = 0;
reply.length = 0;
} else
@@ -278,89 +278,79 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
packet_put_string((char *) reply.dat, reply.length);
packet_send();
packet_write_wait();
- return 1;
+ return (1);
}
#endif /* KRB4 */
#ifdef AFS
int
-auth_krb4_tgt(struct passwd *pw, const char *string)
+auth_krb4_tgt(Authctxt *authctxt, const char *string)
{
CREDENTIALS creds;
+ struct passwd *pw;
+
+ if ((pw = authctxt->pw) == NULL)
+ goto failure;
+
+ temporarily_use_uid(pw);
- if (pw == NULL)
- goto auth_kerberos_tgt_failure;
if (!radix_to_creds(string, &creds)) {
- log("Protocol error decoding Kerberos V4 tgt");
- packet_send_debug("Protocol error decoding Kerberos V4 tgt");
- goto auth_kerberos_tgt_failure;
+ log("Protocol error decoding Kerberos v4 TGT");
+ goto failure;
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "krbtgt", sizeof creds.service);
if (strcmp(creds.service, "krbtgt")) {
- log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
- creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
- pw->pw_name);
- packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
+ log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
creds.realm, pw->pw_name);
- goto auth_kerberos_tgt_failure;
+ goto failure;
}
- if (!krb4_init(pw->pw_uid))
- goto auth_kerberos_tgt_failure;
+ if (!krb4_init(authctxt))
+ goto failure;
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
- goto auth_kerberos_tgt_failure;
+ goto failure;
if (save_credentials(creds.service, creds.instance, creds.realm,
- creds.session, creds.lifetime, creds.kvno,
- &creds.ticket_st, creds.issue_date) != KSUCCESS) {
- packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
- goto auth_kerberos_tgt_failure;
+ creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
+ creds.issue_date) != KSUCCESS) {
+ debug("Kerberos v4 TGT refused: couldn't save credentials");
+ goto failure;
}
/* Successful authentication, passed all checks. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
- packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
- creds.service, creds.instance, creds.realm, creds.pname,
- creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
+ debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
+ creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
memset(&creds, 0, sizeof(creds));
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
- return 1;
-auth_kerberos_tgt_failure:
- krb4_cleanup_proc(NULL);
+ restore_uid();
+
+ return (1);
+
+ failure:
+ krb4_cleanup_proc(authctxt);
memset(&creds, 0, sizeof(creds));
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- return 0;
+ restore_uid();
+
+ return (0);
}
int
-auth_afs_token(struct passwd *pw, const char *token_string)
+auth_afs_token(Authctxt *authctxt, const char *token_string)
{
CREDENTIALS creds;
+ struct passwd *pw;
uid_t uid;
- if (pw == NULL) {
- /* XXX fake protocol error */
- packet_send_debug("Protocol error decoding AFS token");
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- return 0;
- }
+ if ((pw = authctxt->pw) == NULL)
+ return (0);
+
if (!radix_to_creds(token_string, &creds)) {
log("Protocol error decoding AFS token");
- packet_send_debug("Protocol error decoding AFS token");
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- return 0;
+ return (0);
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "afs", sizeof creds.service);
@@ -371,22 +361,14 @@ auth_afs_token(struct passwd *pw, const char *token_string)
uid = pw->pw_uid;
if (kafs_settoken(creds.realm, uid, &creds)) {
- log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
- pw->pw_name);
- packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
- creds.realm, pw->pw_name);
+ log("AFS token (%s@%s) rejected for %s",
+ creds.pname, creds.realm, pw->pw_name);
memset(&creds, 0, sizeof(creds));
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- return 0;
+ return (0);
}
- packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
- creds.realm, creds.pname, creds.realm);
+ debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
memset(&creds, 0, sizeof(creds));
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
- return 1;
+
+ return (1);
}
#endif /* AFS */
diff --git a/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c
index efe9376..ff23c98 100644
--- a/crypto/openssh/auth-krb5.c
+++ b/crypto/openssh/auth-krb5.c
@@ -1,250 +1,272 @@
/*
* Kerberos v5 authentication and ticket-passing routines.
- *
- * $FreeBSD$
*/
#include "includes.h"
+RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $");
+RCSID("$FreeBSD$");
+
#include "ssh.h"
#include "ssh1.h"
#include "packet.h"
#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "auth.h"
#ifdef KRB5
+#include <krb5.h>
-krb5_context ssh_context = NULL;
-krb5_auth_context auth_context;
-krb5_ccache mem_ccache = NULL; /* Credential cache for acquired ticket */
+extern ServerOptions options;
-/* Try krb5 authentication. server_user is passed for logging purposes only,
- in auth is received ticket, in client is returned principal from the
- ticket */
-int
-auth_krb5(const char* server_user, krb5_data *auth, krb5_principal *client)
+static int
+krb5_init(void *context)
{
+ Authctxt *authctxt = (Authctxt *)context;
krb5_error_code problem;
- krb5_principal server = NULL;
- krb5_principal tkt_client = NULL;
+ static int cleanup_registered = 0;
+
+ if (authctxt->krb5_ctx == NULL) {
+ problem = krb5_init_context(&authctxt->krb5_ctx);
+ if (problem)
+ return (problem);
+ krb5_init_ets(authctxt->krb5_ctx);
+ }
+ if (!cleanup_registered) {
+ fatal_add_cleanup(krb5_cleanup_proc, authctxt);
+ cleanup_registered = 1;
+ }
+ return (0);
+}
+
+/*
+ * Try krb5 authentication. server_user is passed for logging purposes
+ * only, in auth is received ticket, in client is returned principal
+ * from the ticket
+ */
+int
+auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client)
+{
+ krb5_error_code problem;
+ krb5_principal server;
krb5_data reply;
- krb5_ticket *ticket = NULL;
- int fd;
- int ret;
-
+ krb5_ticket *ticket;
+ int fd, ret;
+
+ ret = 0;
+ server = NULL;
+ ticket = NULL;
reply.length = 0;
-
- problem = krb5_init();
- if (problem)
- return 0;
-
- problem = krb5_auth_con_init(ssh_context, &auth_context);
- if (problem) {
- log("Kerberos v5 authentication failed: %.100s",
- krb5_get_err_text(ssh_context, problem));
- return 0;
- }
-
- fd = packet_get_connection_in();
- problem = krb5_auth_con_setaddrs_from_fd(ssh_context, auth_context, &fd);
- if (problem) {
- ret = 0;
- goto err;
- }
-
- problem = krb5_sname_to_principal(ssh_context, NULL, NULL ,
+ problem = krb5_init(authctxt);
+ if (problem)
+ goto err;
+
+ problem = krb5_auth_con_init(authctxt->krb5_ctx,
+ &authctxt->krb5_auth_ctx);
+ if (problem)
+ goto err;
+
+ fd = packet_get_connection_in();
+ problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
+ authctxt->krb5_auth_ctx, &fd);
+ if (problem)
+ goto err;
+
+ problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL ,
KRB5_NT_SRV_HST, &server);
- if (problem) {
- ret = 0;
- goto err;
- }
-
- problem = krb5_rd_req(ssh_context, &auth_context, auth, server, NULL,
- NULL, &ticket);
- if (problem) {
- ret = 0;
- goto err;
- }
-
- problem = krb5_copy_principal(ssh_context, ticket->client, &tkt_client);
- if (problem) {
- ret = 0;
- goto err;
- }
-
+ if (problem)
+ goto err;
+
+ problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
+ auth, server, NULL, NULL, &ticket);
+ if (problem)
+ goto err;
+
+ problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
+ &authctxt->krb5_user);
+ if (problem)
+ goto err;
+
/* if client wants mutual auth */
- problem = krb5_mk_rep(ssh_context, auth_context, &reply);
- if (problem) {
- ret = 0;
- goto err;
- }
-
- *client = tkt_client;
-
+ problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
+ &reply);
+ if (problem)
+ goto err;
+
+ /* Check .k5login authorization now. */
+ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
+ authctxt->pw->pw_name))
+ goto err;
+
+ if (client)
+ krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
+ client);
+
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
packet_put_string((char *) reply.data, reply.length);
packet_send();
packet_write_wait();
+
ret = 1;
-
-err:
+ err:
if (server)
- krb5_free_principal(ssh_context, server);
+ krb5_free_principal(authctxt->krb5_ctx, server);
if (ticket)
- krb5_free_ticket(ssh_context, ticket);
+ krb5_free_ticket(authctxt->krb5_ctx, ticket);
if (reply.length)
- xfree(reply.data);
- return ret;
+ xfree(reply.data);
+
+ if (problem) {
+ if (authctxt->krb5_ctx != NULL)
+ debug("Kerberos v5 authentication failed: %s",
+ krb5_get_err_text(authctxt->krb5_ctx, problem));
+ else
+ debug("Kerberos v5 authentication failed: %d",
+ problem);
+ }
+
+ return (ret);
}
int
-auth_krb5_tgt(char *server_user, krb5_data *tgt, krb5_principal tkt_client)
+auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
{
- krb5_error_code problem;
- krb5_ccache ccache = NULL;
-
- if (ssh_context == NULL) {
- goto fail;
- }
-
- problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
- if (problem) {
- goto fail;
- }
-
- problem = krb5_cc_initialize(ssh_context, ccache, tkt_client);
- if (problem) {
- goto fail;
- }
-
- problem = krb5_rd_cred2(ssh_context, auth_context, ccache, tgt);
- if (problem) {
- goto fail;
- }
-
- mem_ccache = ccache;
- ccache = NULL;
-
- /*
- problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
- if (problem) {
- mem_ccache = NULL;
- goto fail;
- }
-
-
- problem = krb5_cc_destroy(ssh_context, ccache);
- if (problem)
- goto fail;
- */
-
-#if 0
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-#endif
- return 1;
-
-fail:
- if (ccache)
- krb5_cc_destroy(ssh_context, ccache);
-#if 0
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
-#endif
- return 0;
+ krb5_error_code problem;
+ krb5_ccache ccache = NULL;
+ char *pname;
+
+ if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
+ return (0);
+
+ temporarily_use_uid(authctxt->pw);
+
+ problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
+ if (problem)
+ goto fail;
+
+ problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
+ authctxt->krb5_user);
+ if (problem)
+ goto fail;
+
+ problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
+ ccache, tgt);
+ if (problem)
+ goto fail;
+
+ authctxt->krb5_fwd_ccache = ccache;
+ ccache = NULL;
+
+ authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+
+ problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
+ &pname);
+ if (problem)
+ goto fail;
+
+ debug("Kerberos v5 TGT accepted (%s)", pname);
+
+ restore_uid();
+
+ return (1);
+
+ fail:
+ if (problem)
+ debug("Kerberos v5 TGT passing failed: %s",
+ krb5_get_err_text(authctxt->krb5_ctx, problem));
+ if (ccache)
+ krb5_cc_destroy(authctxt->krb5_ctx, ccache);
+
+ restore_uid();
+
+ return (0);
}
int
-auth_krb5_password(struct passwd *pw, const char *password)
+auth_krb5_password(Authctxt *authctxt, const char *password)
{
- krb5_error_code problem;
- krb5_ccache ccache = NULL;
- krb5_principal client = NULL;
- int ret;
-
- problem = krb5_init();
- if (problem)
- return 0;
-
- problem = krb5_parse_name(ssh_context, pw->pw_name, &client);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- problem = krb5_cc_initialize(ssh_context, ccache, client);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- problem = krb5_verify_user(ssh_context, client, ccache, password, 1, NULL);
- if (problem) {
- ret = 0;
- goto out;
- }
-
-/*
- problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
- if (problem) {
- ret = 0;
- mem_ccache = NULL;
- goto out;
- }
- */
- mem_ccache = ccache;
- ccache = NULL;
-
- ret = 1;
-out:
- if (client != NULL)
- krb5_free_principal(ssh_context, client);
- if (ccache != NULL)
- krb5_cc_destroy(ssh_context, ccache);
- return ret;
+ krb5_error_code problem;
+
+ if (authctxt->pw == NULL)
+ return (0);
+
+ temporarily_use_uid(authctxt->pw);
+
+ problem = krb5_init(authctxt);
+ if (problem)
+ goto out;
+
+ problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
+ &authctxt->krb5_user);
+ if (problem)
+ goto out;
+
+ problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
+ &authctxt->krb5_fwd_ccache);
+ if (problem)
+ goto out;
+
+ problem = krb5_cc_initialize(authctxt->krb5_ctx,
+ authctxt->krb5_fwd_ccache, authctxt->krb5_user);
+ if (problem)
+ goto out;
+
+ restore_uid();
+ problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
+ authctxt->krb5_fwd_ccache, password, 1, NULL);
+ temporarily_use_uid(authctxt->pw);
+
+ if (problem)
+ goto out;
+
+ authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+
+ out:
+ restore_uid();
+
+ if (problem) {
+ if (authctxt->krb5_ctx != NULL)
+ debug("Kerberos password authentication failed: %s",
+ krb5_get_err_text(authctxt->krb5_ctx, problem));
+ else
+ debug("Kerberos password authentication failed: %d",
+ problem);
+
+ krb5_cleanup_proc(authctxt);
+
+ if (options.kerberos_or_local_passwd)
+ return (-1);
+ else
+ return (0);
+ }
+ return (1);
}
void
-krb5_cleanup_proc(void *ignore)
+krb5_cleanup_proc(void *context)
{
- extern krb5_principal tkt_client;
-
- debug("krb5_cleanup_proc() called");
- if (mem_ccache)
- krb5_cc_destroy(ssh_context, mem_ccache);
- if (tkt_client)
- krb5_free_principal(ssh_context, tkt_client);
- if (auth_context)
- krb5_auth_con_free(ssh_context, auth_context);
- if (ssh_context)
- krb5_free_context(ssh_context);
-}
-
-int
-krb5_init(void)
-{
- krb5_error_code problem;
- static cleanup_registered = 0;
-
- if (ssh_context == NULL) {
- problem = krb5_init_context(&ssh_context);
- if (problem)
- return problem;
- krb5_init_ets(ssh_context);
- }
-
- if (!cleanup_registered) {
- fatal_add_cleanup(krb5_cleanup_proc, NULL);
- cleanup_registered = 1;
- }
- return 0;
+ Authctxt *authctxt = (Authctxt *)context;
+
+ debug("krb5_cleanup_proc called");
+ if (authctxt->krb5_fwd_ccache) {
+ krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+ authctxt->krb5_fwd_ccache = NULL;
+ }
+ if (authctxt->krb5_user) {
+ krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
+ authctxt->krb5_user = NULL;
+ }
+ if (authctxt->krb5_auth_ctx) {
+ krb5_auth_con_free(authctxt->krb5_ctx,
+ authctxt->krb5_auth_ctx);
+ authctxt->krb5_auth_ctx = NULL;
+ }
+ if (authctxt->krb5_ctx) {
+ krb5_free_context(authctxt->krb5_ctx);
+ authctxt->krb5_ctx = NULL;
+ }
}
-
+
#endif /* KRB5 */
diff --git a/crypto/openssh/auth-pam.c b/crypto/openssh/auth-pam.c
index 16d5ac7..03a464d 100644
--- a/crypto/openssh/auth-pam.c
+++ b/crypto/openssh/auth-pam.c
@@ -223,9 +223,9 @@ int do_pam_account(char *username, char *remote_user)
do_pam_set_conv(&conv);
debug("PAM setting rhost to \"%.200s\"",
- get_canonical_hostname(options.reverse_mapping_check));
+ get_canonical_hostname(options.verify_reverse_mapping));
pam_retval = pam_set_item(pamh, PAM_RHOST,
- get_canonical_hostname(options.reverse_mapping_check));
+ get_canonical_hostname(options.verify_reverse_mapping));
if (pam_retval != PAM_SUCCESS) {
fatal("PAM set rhost failed[%d]: %.200s",
pam_retval, PAM_STRERROR(pamh, pam_retval));
diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c
index 1ca7fa9..ab7447f 100644
--- a/crypto/openssh/auth-passwd.c
+++ b/crypto/openssh/auth-passwd.c
@@ -36,11 +36,10 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $");
+RCSID("$OpenBSD: auth-passwd.c,v 1.24 2002/03/04 12:43:06 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
-#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
@@ -65,30 +64,29 @@ auth_password(Authctxt *authctxt, const char *password)
return 0;
if (*password == '\0' && options.permit_empty_passwd == 0)
return 0;
-#ifdef BSD_AUTH
- if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
- (char *)password) == 0)
- return 0;
- else
- return 1;
-#endif
#ifdef KRB5
if (options.kerberos_authentication == 1) {
- if (auth_krb5_password(pw, password))
- return 1;
+ int ret = auth_krb5_password(authctxt, password);
+ if (ret == 1 || ret == 0)
+ return ret;
/* Fall back to ordinary passwd authentication. */
}
-
-#endif /* KRB5 */
+#endif
#ifdef KRB4
if (options.kerberos_authentication == 1) {
- int ret = auth_krb4_password(pw, password);
+ int ret = auth_krb4_password(authctxt, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
-
+#ifdef BSD_AUTH
+ if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
+ (char *)password) == 0)
+ return 0;
+ else
+ return 1;
+#endif
/* Check for users with no password. */
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
return 1;
diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c
index 596a7bb..e985219 100644
--- a/crypto/openssh/auth-rh-rsa.c
+++ b/crypto/openssh/auth-rh-rsa.c
@@ -13,11 +13,10 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
+RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
-#include "xmalloc.h"
#include "uidswap.h"
#include "log.h"
#include "servconf.h"
@@ -25,7 +24,6 @@ RCSID("$FreeBSD$");
#include "hostfile.h"
#include "pathnames.h"
#include "auth.h"
-#include "tildexpand.h"
#include "canohost.h"
/*
@@ -34,16 +32,15 @@ RCSID("$FreeBSD$");
*/
int
-auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
+auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key)
{
extern ServerOptions options;
const char *canonical_hostname;
HostStatus host_status;
- Key *client_key, *found;
debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
- if (pw == NULL || client_host_key == NULL)
+ if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL)
return 0;
/* Check if we would accept it using rhosts authentication. */
@@ -51,45 +48,13 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
return 0;
canonical_hostname = get_canonical_hostname(
- options.reverse_mapping_check);
+ options.verify_reverse_mapping);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
- /* wrap the RSA key into a 'generic' key */
- client_key = key_new(KEY_RSA1);
- BN_copy(client_key->rsa->e, client_host_key->e);
- BN_copy(client_key->rsa->n, client_host_key->n);
- found = key_new(KEY_RSA1);
-
- /* Check if we know the host and its host key. */
- host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
- client_key, found, NULL);
-
- /* Check user host file unless ignored. */
- if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
- struct stat st;
- char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
- /*
- * Check file permissions of _PATH_SSH_USER_HOSTFILE, auth_rsa()
- * did already check pw->pw_dir, but there is a race XXX
- */
- if (options.strict_modes &&
- (stat(user_hostfile, &st) == 0) &&
- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
- log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
- pw->pw_name, user_hostfile);
- } else {
- /* XXX race between stat and the following open() */
- temporarily_use_uid(pw);
- host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
- client_key, found, NULL);
- restore_uid();
- }
- xfree(user_hostfile);
- }
- key_free(client_key);
- key_free(found);
+ host_status = check_key_in_hostfiles(pw, client_host_key,
+ canonical_hostname, _PATH_SSH_SYSTEM_HOSTFILE,
+ options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
if (host_status != HOST_OK) {
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
@@ -99,7 +64,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
/* A matching host key was found and is known. */
/* Perform the challenge-response dialog with the client for the host key. */
- if (!auth_rsa_challenge_dialog(client_host_key)) {
+ if (!auth_rsa_challenge_dialog(client_host_key->rsa)) {
log("Client on %.800s failed to respond correctly to host authentication.",
canonical_hostname);
return 0;
diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c
index a7e0625..77ea57b 100644
--- a/crypto/openssh/auth-rsa.c
+++ b/crypto/openssh/auth-rsa.c
@@ -14,7 +14,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
+RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/rsa.h>
@@ -32,6 +32,7 @@ RCSID("$FreeBSD$");
#include "log.h"
#include "servconf.h"
#include "auth.h"
+#include "hostfile.h"
/* import */
extern ServerOptions options;
@@ -66,14 +67,17 @@ auth_rsa_challenge_dialog(RSA *pk)
u_char buf[32], mdbuf[16], response[16];
MD5_CTX md;
u_int i;
- int plen, len;
+ int len;
- encrypted_challenge = BN_new();
- challenge = BN_new();
+ if ((encrypted_challenge = BN_new()) == NULL)
+ fatal("auth_rsa_challenge_dialog: BN_new() failed");
+ if ((challenge = BN_new()) == NULL)
+ fatal("auth_rsa_challenge_dialog: BN_new() failed");
/* Generate a random challenge. */
BN_rand(challenge, 256, 0, 0);
- ctx = BN_CTX_new();
+ if ((ctx = BN_CTX_new()) == NULL)
+ fatal("auth_rsa_challenge_dialog: BN_CTX_new() failed");
BN_mod(challenge, challenge, pk->n, ctx);
BN_CTX_free(ctx);
@@ -88,10 +92,10 @@ auth_rsa_challenge_dialog(RSA *pk)
packet_write_wait();
/* Wait for a response. */
- packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
- packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
+ packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
response[i] = packet_get_char();
+ packet_check_eom();
/* The response is MD5 of decrypted challenge plus session id. */
len = BN_num_bytes(challenge);
@@ -123,13 +127,14 @@ auth_rsa_challenge_dialog(RSA *pk)
int
auth_rsa(struct passwd *pw, BIGNUM *client_n)
{
- char line[8192], file[MAXPATHLEN];
+ char line[8192], *file;
int authenticated;
u_int bits;
FILE *f;
u_long linenum = 0;
struct stat st;
- RSA *pk;
+ Key *key;
+ char *fp;
/* no user given */
if (pw == NULL)
@@ -139,13 +144,14 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
temporarily_use_uid(pw);
/* The authorized keys. */
- snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
- _PATH_SSH_USER_PERMITTED_KEYS);
+ file = authorized_keys_file(pw);
+ debug("trying public RSA key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
/* Restore the privileged uid. */
restore_uid();
+ xfree(file);
return 0;
}
/* Open the file containing the authorized keys. */
@@ -155,50 +161,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
packet_send_debug("Could not open %.900s for reading.", file);
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
+ xfree(file);
return 0;
}
- if (options.strict_modes) {
- int fail = 0;
- char buf[1024];
- /* Check open file in order to avoid open/stat races */
- if (fstat(fileno(f), &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
- "bad ownership or modes for '%s'.", pw->pw_name, file);
- fail = 1;
- } else {
- /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
- int i;
- static const char *check[] = {
- "", _PATH_SSH_USER_DIR, NULL
- };
- for (i = 0; check[i]; i++) {
- snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
- if (stat(line, &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
- "bad ownership or modes for '%s'.", pw->pw_name, line);
- fail = 1;
- break;
- }
- }
- }
- if (fail) {
- fclose(f);
- log("%s", buf);
- packet_send_debug("%s", buf);
- restore_uid();
- return 0;
- }
+ if (options.strict_modes &&
+ secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+ xfree(file);
+ fclose(f);
+ log("Authentication refused: %s", line);
+ packet_send_debug("Authentication refused: %s", line);
+ restore_uid();
+ return 0;
}
/* Flag indicating whether authentication has succeeded. */
authenticated = 0;
- pk = RSA_new();
- pk->e = BN_new();
- pk->n = BN_new();
+ key = key_new(KEY_RSA1);
/*
* Go though the accepted keys, looking for the current key. If
@@ -236,24 +214,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
options = NULL;
/* Parse the key from the line. */
- if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
- debug("%.100s, line %lu: bad key syntax",
- file, linenum);
- packet_send_debug("%.100s, line %lu: bad key syntax",
+ if (hostfile_read_key(&cp, &bits, key) == 0) {
+ debug("%.100s, line %lu: non ssh1 key syntax",
file, linenum);
continue;
}
/* cp now points to the comment part. */
/* Check if the we have found the desired key (identified by its modulus). */
- if (BN_cmp(pk->n, client_n) != 0)
+ if (BN_cmp(key->rsa->n, client_n) != 0)
continue;
/* check the real bits */
- if (bits != BN_num_bits(pk->n))
- log("Warning: %s, line %ld: keysize mismatch: "
+ if (bits != BN_num_bits(key->rsa->n))
+ log("Warning: %s, line %lu: keysize mismatch: "
"actual %d vs. announced %d.",
- file, linenum, BN_num_bits(pk->n), bits);
+ file, linenum, BN_num_bits(key->rsa->n), bits);
/* We have found the desired key. */
/*
@@ -264,11 +240,15 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
continue;
/* Perform the challenge-response dialog for this key. */
- if (!auth_rsa_challenge_dialog(pk)) {
+ if (!auth_rsa_challenge_dialog(key->rsa)) {
/* Wrong response. */
verbose("Wrong response to RSA authentication challenge.");
packet_send_debug("Wrong response to RSA authentication challenge.");
- continue;
+ /*
+ * Break out of the loop. Otherwise we might send
+ * another challenge and break the protocol.
+ */
+ break;
}
/*
* Correct response. The client has been successfully
@@ -279,6 +259,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
* otherwise continue searching.
*/
authenticated = 1;
+
+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+ verbose("Found matching %s key: %s",
+ key_type(key), fp);
+ xfree(fp);
+
break;
}
@@ -286,9 +272,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
/* Close the file. */
+ xfree(file);
fclose(f);
- RSA_free(pk);
+ key_free(key);
if (authenticated)
packet_send_debug("RSA authentication accepted.");
diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c
index df945e0..79332a8 100644
--- a/crypto/openssh/auth.c
+++ b/crypto/openssh/auth.c
@@ -23,9 +23,11 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
+RCSID("$OpenBSD: auth.c,v 1.35 2002/03/01 13:12:10 markus Exp $");
RCSID("$FreeBSD$");
+#include <libgen.h>
+
#include "xmalloc.h"
#include "match.h"
#include "groupaccess.h"
@@ -34,6 +36,10 @@ RCSID("$FreeBSD$");
#include "auth.h"
#include "auth-options.h"
#include "canohost.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "uidswap.h"
+#include "tildexpand.h"
/* import */
extern ServerOptions options;
@@ -51,6 +57,7 @@ int
allowed_user(struct passwd * pw)
{
struct stat st;
+ const char *hostname = NULL, *ipaddr = NULL;
char *shell;
int i;
@@ -65,36 +72,60 @@ allowed_user(struct passwd * pw)
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
/* deny if shell does not exists or is not executable */
- if (stat(shell, &st) != 0)
+ if (stat(shell, &st) != 0) {
+ log("User %.100s not allowed because shell %.100s does not exist",
+ pw->pw_name, shell);
return 0;
- if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
+ }
+ if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) {
+ log("User %.100s not allowed because shell %.100s is not executable",
+ pw->pw_name, shell);
return 0;
+ }
+
+ if (options.num_deny_users > 0 || options.num_allow_users > 0) {
+ hostname = get_canonical_hostname(options.verify_reverse_mapping);
+ ipaddr = get_remote_ipaddr();
+ }
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
for (i = 0; i < options.num_deny_users; i++)
- if (match_pattern(pw->pw_name, options.deny_users[i]))
+ if (match_user(pw->pw_name, hostname, ipaddr,
+ options.deny_users[i])) {
+ log("User %.100s not allowed because listed in DenyUsers",
+ pw->pw_name);
return 0;
+ }
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
for (i = 0; i < options.num_allow_users; i++)
- if (match_pattern(pw->pw_name, options.allow_users[i]))
+ if (match_user(pw->pw_name, hostname, ipaddr,
+ options.allow_users[i]))
break;
/* i < options.num_allow_users iff we break for loop */
- if (i >= options.num_allow_users)
+ if (i >= options.num_allow_users) {
+ log("User %.100s not allowed because not listed in AllowUsers",
+ pw->pw_name);
return 0;
+ }
}
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
/* Get the user's group access list (primary and supplementary) */
- if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+ if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
+ log("User %.100s not allowed because not in any group",
+ pw->pw_name);
return 0;
+ }
/* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0)
if (ga_match(options.deny_groups,
options.num_deny_groups)) {
ga_free();
+ log("User %.100s not allowed because a group is listed in DenyGroups",
+ pw->pw_name);
return 0;
}
/*
@@ -105,6 +136,8 @@ allowed_user(struct passwd * pw)
if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
+ log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
+ pw->pw_name);
return 0;
}
ga_free();
@@ -143,7 +176,7 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
- authctxt->valid && authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user,
+ authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
info);
@@ -173,3 +206,184 @@ auth_root_allowed(char *method)
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}
+
+
+/*
+ * Given a template and a passwd structure, build a filename
+ * by substituting % tokenised options. Currently, %% becomes '%',
+ * %h becomes the home directory and %u the username.
+ *
+ * This returns a buffer allocated by xmalloc.
+ */
+char *
+expand_filename(const char *filename, struct passwd *pw)
+{
+ Buffer buffer;
+ char *file;
+ const char *cp;
+
+ /*
+ * Build the filename string in the buffer by making the appropriate
+ * substitutions to the given file name.
+ */
+ buffer_init(&buffer);
+ for (cp = filename; *cp; cp++) {
+ if (cp[0] == '%' && cp[1] == '%') {
+ buffer_append(&buffer, "%", 1);
+ cp++;
+ continue;
+ }
+ if (cp[0] == '%' && cp[1] == 'h') {
+ buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
+ cp++;
+ continue;
+ }
+ if (cp[0] == '%' && cp[1] == 'u') {
+ buffer_append(&buffer, pw->pw_name,
+ strlen(pw->pw_name));
+ cp++;
+ continue;
+ }
+ buffer_append(&buffer, cp, 1);
+ }
+ buffer_append(&buffer, "\0", 1);
+
+ /*
+ * Ensure that filename starts anchored. If not, be backward
+ * compatible and prepend the '%h/'
+ */
+ file = xmalloc(MAXPATHLEN);
+ cp = buffer_ptr(&buffer);
+ if (*cp != '/')
+ snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
+ else
+ strlcpy(file, cp, MAXPATHLEN);
+
+ buffer_free(&buffer);
+ return file;
+}
+
+char *
+authorized_keys_file(struct passwd *pw)
+{
+ return expand_filename(options.authorized_keys_file, pw);
+}
+
+char *
+authorized_keys_file2(struct passwd *pw)
+{
+ return expand_filename(options.authorized_keys_file2, pw);
+}
+
+/* return ok if key exists in sysfile or userfile */
+HostStatus
+check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
+ const char *sysfile, const char *userfile)
+{
+ Key *found;
+ char *user_hostfile;
+ struct stat st;
+ HostStatus host_status;
+
+ /* Check if we know the host and its host key. */
+ found = key_new(key->type);
+ host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
+
+ if (host_status != HOST_OK && userfile != NULL) {
+ user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
+ if (options.strict_modes &&
+ (stat(user_hostfile, &st) == 0) &&
+ ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+ (st.st_mode & 022) != 0)) {
+ log("Authentication refused for %.100s: "
+ "bad owner or modes for %.200s",
+ pw->pw_name, user_hostfile);
+ } else {
+ temporarily_use_uid(pw);
+ host_status = check_host_in_hostfile(user_hostfile,
+ host, key, found, NULL);
+ restore_uid();
+ }
+ xfree(user_hostfile);
+ }
+ key_free(found);
+
+ debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
+ "ok" : "not found", host);
+ return host_status;
+}
+
+
+/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must either be owned by either the owner of
+ * of the file or root and no directories must be group or world writable.
+ *
+ * XXX Should any specific check be done for sym links ?
+ *
+ * Takes an open file descriptor, the file name, a uid and and
+ * error buffer plus max size as arguments.
+ *
+ * Returns 0 on success and -1 on failure
+ */
+int
+secure_filename(FILE *f, const char *file, struct passwd *pw,
+ char *err, size_t errlen)
+{
+ uid_t uid = pw->pw_uid;
+ char buf[MAXPATHLEN], homedir[MAXPATHLEN];
+ char *cp;
+ struct stat st;
+
+ if (realpath(file, buf) == NULL) {
+ snprintf(err, errlen, "realpath %s failed: %s", file,
+ strerror(errno));
+ return -1;
+ }
+ if (realpath(pw->pw_dir, homedir) == NULL) {
+ snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir,
+ strerror(errno));
+ return -1;
+ }
+
+ /* check the open file to avoid races */
+ if (fstat(fileno(f), &st) < 0 ||
+ (st.st_uid != 0 && st.st_uid != uid) ||
+ (st.st_mode & 022) != 0) {
+ snprintf(err, errlen, "bad ownership or modes for file %s",
+ buf);
+ return -1;
+ }
+
+ /* for each component of the canonical path, walking upwards */
+ for (;;) {
+ if ((cp = dirname(buf)) == NULL) {
+ snprintf(err, errlen, "dirname() failed");
+ return -1;
+ }
+ strlcpy(buf, cp, sizeof(buf));
+
+ debug3("secure_filename: checking '%s'", buf);
+ if (stat(buf, &st) < 0 ||
+ (st.st_uid != 0 && st.st_uid != uid) ||
+ (st.st_mode & 022) != 0) {
+ snprintf(err, errlen,
+ "bad ownership or modes for directory %s", buf);
+ return -1;
+ }
+
+ /* If are passed the homedir then we can stop */
+ if (strcmp(homedir, buf) == 0) {
+ debug3("secure_filename: terminating check at '%s'",
+ buf);
+ break;
+ }
+ /*
+ * dirname should always complete with a "/" path,
+ * but we can be paranoid and check for "." too
+ */
+ if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
+ break;
+ }
+ return 0;
+}
diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h
index 3385c9b..a6265f3 100644
--- a/crypto/openssh/auth.h
+++ b/crypto/openssh/auth.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: auth.h,v 1.29 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -21,12 +24,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
- * $FreeBSD$
*/
+
#ifndef AUTH_H
#define AUTH_H
+#include "key.h"
+#include "hostfile.h"
#include <openssl/rsa.h>
#ifdef HAVE_LOGIN_CAP
@@ -35,119 +39,115 @@
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
+#ifdef KRB5
+#include <krb5.h>
+#endif
typedef struct Authctxt Authctxt;
+typedef struct KbdintDevice KbdintDevice;
+
struct Authctxt {
- int success;
- int postponed;
- int valid;
- int attempt;
- int failures;
- char *user;
- char *service;
- struct passwd *pw;
- char *style;
+ int success;
+ int postponed;
+ int valid;
+ int attempt;
+ int failures;
+ char *user;
+ char *service;
+ struct passwd *pw;
+ char *style;
+ void *kbdintctxt;
#ifdef BSD_AUTH
- auth_session_t *as;
+ auth_session_t *as;
+#endif
+#ifdef KRB4
+ char *krb4_ticket_file;
+#endif
+#ifdef KRB5
+ krb5_context krb5_ctx;
+ krb5_auth_context krb5_auth_ctx;
+ krb5_ccache krb5_fwd_ccache;
+ krb5_principal krb5_user;
+ char *krb5_ticket_file;
#endif
};
/*
- * Tries to authenticate the user using the .rhosts file. Returns true if
- * authentication succeeds. If ignore_rhosts is non-zero, this will not
- * consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
+ * Keyboard interactive device:
+ * init_ctx returns: non NULL upon success
+ * query returns: 0 - success, otherwise failure
+ * respond returns: 0 - success, 1 - need further interaction,
+ * otherwise - failure
*/
-int auth_rhosts(struct passwd * pw, const char *client_user);
-
-/* extended interface similar to auth_rhosts() */
-int
-auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
- const char *ipaddr);
+struct KbdintDevice
+{
+ const char *name;
+ void* (*init_ctx)(Authctxt*);
+ int (*query)(void *ctx, char **name, char **infotxt,
+ u_int *numprompts, char ***prompts, u_int **echo_on);
+ int (*respond)(void *ctx, u_int numresp, char **responses);
+ void (*free_ctx)(void *ctx);
+};
-/*
- * Tries to authenticate the user using the .rhosts file and the host using
- * its host key. Returns true if authentication succeeds.
- */
+int auth_rhosts(struct passwd *, const char *);
int
-auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
-
-/*
- * Tries to authenticate the user using password. Returns true if
- * authentication succeeds.
- */
-int auth_password(Authctxt *authctxt, 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
- * successful. This may exit if there is a serious protocol violation.
- */
-int auth_rsa(struct passwd * pw, BIGNUM * client_n);
+auth_rhosts2(struct passwd *, const char *, const char *, const char *);
-/*
- * 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, u_int *bitsp, 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 our
- * challenge; returns zero if the client gives a wrong answer.
- */
-int auth_rsa_challenge_dialog(RSA *pk);
+int auth_rhosts_rsa(struct passwd *, const char *, Key *);
+int auth_password(Authctxt *, const char *);
+int auth_rsa(struct passwd *, BIGNUM *);
+int auth_rsa_challenge_dialog(RSA *);
#ifdef KRB4
#include <krb.h>
-#endif /* KRB4 */
-#ifdef KRB5
-#include <krb5.h>
-int auth_krb5(); /* XXX Doplnit prototypy */
-int auth_krb5_tgt();
-int krb5_init();
-void krb5_cleanup_proc(void *ignore);
-int auth_krb5_password(struct passwd *pw, const char *password);
-#endif /* KRB5 */
-
-#ifdef KRB4
-#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
- * successful. This may exit if there is a serious protocol violation.
- */
-int auth_krb4(const char *server_user, KTEXT auth, char **client);
-int krb4_init(uid_t uid);
-void krb4_cleanup_proc(void *ignore);
-int auth_krb4_password(struct passwd * pw, const char *password);
+int auth_krb4(Authctxt *, KTEXT, char **);
+int auth_krb4_password(Authctxt *, const char *);
+void krb4_cleanup_proc(void *);
#ifdef AFS
#include <kafs.h>
+int auth_krb4_tgt(Authctxt *, const char *);
+int auth_afs_token(Authctxt *, const char *);
+#endif /* AFS */
-/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
-int auth_kerberos_tgt(struct passwd * pw, const char *string);
-int auth_afs_token(struct passwd * pw, const char *token_string);
-#endif /* AFS */
+#endif /* KRB4 */
-#endif /* KRB4 */
+#ifdef KRB5
+int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client);
+int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
+int auth_krb5_password(Authctxt *authctxt, const char *password);
+void krb5_cleanup_proc(void *authctxt);
+#endif /* KRB5 */
void do_authentication(void);
void do_authentication2(void);
Authctxt *authctxt_new(void);
-void auth_log(Authctxt *authctxt, int authenticated, char *method, char *info);
-void userauth_finish(Authctxt *authctxt, int authenticated, char *method);
-int auth_root_allowed(char *method);
+void auth_log(Authctxt *, int, char *, char *);
+void userauth_finish(Authctxt *, int, char *);
+int auth_root_allowed(char *);
-int auth2_challenge(Authctxt *authctxt, char *devs);
+int auth2_challenge(Authctxt *, char *);
+void auth2_challenge_stop(Authctxt *);
-int allowed_user(struct passwd * pw);
+int allowed_user(struct passwd *);
-char *get_challenge(Authctxt *authctxt, char *devs);
-int verify_response(Authctxt *authctxt, char *response);
+char *get_challenge(Authctxt *);
+int verify_response(Authctxt *, const char *);
struct passwd * auth_get_user(void);
+char *expand_filename(const char *, struct passwd *);
+char *authorized_keys_file(struct passwd *);
+char *authorized_keys_file2(struct passwd *);
+
+int
+secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
+
+HostStatus
+check_key_in_hostfiles(struct passwd *, Key *, const char *,
+ const char *, const char *);
+
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c
index 3df36e2..7311a23 100644
--- a/crypto/openssh/auth1.c
+++ b/crypto/openssh/auth1.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
+RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h"
@@ -23,26 +23,23 @@ RCSID("$FreeBSD$");
#include "servconf.h"
#include "compat.h"
#include "auth.h"
-#include "auth-pam.h"
+#include "channels.h"
#include "session.h"
#include "canohost.h"
#include "misc.h"
+#include "uidswap.h"
+
#include <login_cap.h>
+#include "auth-pam.h"
#include <security/pam_appl.h>
-#ifdef KRB5
-extern krb5_context ssh_context;
-krb5_principal tkt_client = NULL; /* Principal from the received ticket.
-Also is used as an indication of succesful krb5 authentization. */
-#endif
-
/* import */
extern ServerOptions options;
/*
* convert ssh auth msg type into description
*/
-char *
+static char *
get_authname(int type)
{
static char buf[1024];
@@ -71,17 +68,16 @@ get_authname(int type)
* read packets, try to authenticate the user and
* return only if authentication is successful
*/
-void
+static void
do_authloop(Authctxt *authctxt)
{
int authenticated = 0;
u_int bits;
- RSA *client_host_key;
+ Key *client_host_key;
BIGNUM *n;
char *client_user, *password;
char info[1024];
u_int dlen;
- int plen, nlen, elen;
u_int ulen;
int type = 0;
struct passwd *pw = authctxt->pw;
@@ -95,41 +91,23 @@ do_authloop(Authctxt *authctxt)
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip;
- from_host = get_canonical_hostname(options.reverse_mapping_check);
+ from_host = get_canonical_hostname(options.verify_reverse_mapping);
from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
-#if 0
-#ifdef KRB5
- {
- krb5_error_code ret;
-
- ret = krb5_init_context(&ssh_context);
- if (ret)
- verbose("Error while initializing Kerberos V5.");
- krb5_init_ets(ssh_context);
-
- }
-#endif /* KRB5 */
-#endif
debug("Attempting authentication for %s%.100s.",
- authctxt->valid ? "" : "illegal user ", authctxt->user);
+ authctxt->valid ? "" : "illegal user ", authctxt->user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#if defined(KRB4) || defined(KRB5)
- (!options.kerberos_authentication
-#if defined(KRB4)
- || options.krb4_or_local_passwd
-#endif
- ) &&
+ (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
#ifdef USE_PAM
- auth_pam_password(authctxt, "")
+ auth_pam_password(authctxt, "")) {
#else
- auth_password(authctxt, "")
+ auth_password(authctxt, "")) {
#endif
- ) {
auth_log(authctxt, 1, "without authentication", "");
return;
}
@@ -148,101 +126,67 @@ do_authloop(Authctxt *authctxt)
info[0] = '\0';
/* Get a packet from the client. */
- type = packet_read(&plen);
+ type = packet_read();
/* Process the packet. */
switch (type) {
-#ifdef AFS
-#ifndef KRB5
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- if (!options.krb4_tgt_passing) {
- /* packet_get_all(); */
- verbose("Kerberos v4 tgt passing disabled.");
- break;
- } else {
- /* Accept Kerberos v4 tgt. */
- char *tgt = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_krb4_tgt(pw, tgt))
- verbose("Kerberos v4 tgt REFUSED for %.100ss", authctxt->user);
- xfree(tgt);
- }
- continue;
-#endif /* !KRB5 */
- case SSH_CMSG_HAVE_AFS_TOKEN:
- if (!options.afs_token_passing || !k_hasafs()) {
- verbose("AFS token passing disabled.");
- break;
- } else {
- /* Accept AFS token. */
- char *token_string = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_afs_token(pw, token_string))
- verbose("AFS token REFUSED for %.100s", authctxt->user);
- xfree(token_string);
- }
- continue;
-#endif /* AFS */
+
#if defined(KRB4) || defined(KRB5)
case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) {
verbose("Kerberos authentication disabled.");
- break;
} else {
- /* Try Kerberos authentication. */
- u_int len;
- char *tkt_user = NULL;
- char *kdata = packet_get_string(&len);
- packet_integrity_check(plen, 4 + len, type);
-
- if (!authctxt->valid) {
- /* Do nothing. */
- } else if (kdata[0] == 4) { /* 4 == KRB_PROT_VERSION */
-#ifdef KRB4
- KTEXT_ST auth;
-
- auth.length = len;
- if (auth.length < MAX_KTXT_LEN)
- memcpy(auth.dat, kdata, auth.length);
- authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
+ char *kdata = packet_get_string(&dlen);
+ packet_check_eom();
- if (authenticated) {
- snprintf(info, sizeof info,
- " tktuser %.100s", tkt_user);
- xfree(tkt_user);
+ if (kdata[0] == 4) { /* KRB_PROT_VERSION */
+#ifdef KRB4
+ KTEXT_ST tkt;
+
+ tkt.length = dlen;
+ if (tkt.length < MAX_KTXT_LEN)
+ memcpy(tkt.dat, kdata, tkt.length);
+
+ if (auth_krb4(authctxt, &tkt, &client_user)) {
+ authenticated = 1;
+ snprintf(info, sizeof(info),
+ " tktuser %.100s",
+ client_user);
+ xfree(client_user);
}
-#else
- verbose("Kerberos v4 authentication disabled.");
#endif /* KRB4 */
} else {
-#ifndef KRB5
- verbose("Kerberos v5 authentication disabled.");
-#else
- krb5_data k5data;
- k5data.length = len;
- k5data.data = kdata;
- #if 0
- if (krb5_init_context(&ssh_context)) {
- verbose("Error while initializing Kerberos V5.");
- break;
- }
- krb5_init_ets(ssh_context);
- #endif
- /* pw->name is passed just for logging purposes */
- if (auth_krb5(pw->pw_name, &k5data, &tkt_client)) {
- /* authorize client against .k5login */
- if (krb5_kuserok(ssh_context,
- tkt_client,
- pw->pw_name))
- authenticated = 1;
+#ifdef KRB5
+ krb5_data tkt;
+ tkt.length = dlen;
+ tkt.data = kdata;
+
+ if (auth_krb5(authctxt, &tkt, &client_user)) {
+ authenticated = 1;
+ snprintf(info, sizeof(info),
+ " tktuser %.100s",
+ client_user);
+ xfree(client_user);
}
#endif /* KRB5 */
- }
+ }
xfree(kdata);
- }
- break;
+ }
+ break;
#endif /* KRB4 || KRB5 */
+#if defined(AFS) || defined(KRB5)
+ /* XXX - punt on backward compatibility here. */
+ case SSH_CMSG_HAVE_KERBEROS_TGT:
+ packet_send_debug("Kerberos TGT passing disabled before authentication.");
+ break;
+#ifdef AFS
+ case SSH_CMSG_HAVE_AFS_TOKEN:
+ packet_send_debug("AFS token passing disabled before authentication.");
+ break;
+#endif /* AFS */
+#endif /* AFS || KRB5 */
+
case SSH_CMSG_AUTH_RHOSTS:
if (!options.rhosts_authentication) {
verbose("Rhosts authentication disabled.");
@@ -255,7 +199,7 @@ do_authloop(Authctxt *authctxt)
* IP-spoofing on a local network.)
*/
client_user = packet_get_string(&ulen);
- packet_integrity_check(plen, 4 + ulen, type);
+ packet_check_eom();
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
authenticated = auth_rhosts(pw, client_user);
@@ -276,24 +220,20 @@ do_authloop(Authctxt *authctxt)
client_user = packet_get_string(&ulen);
/* Get the client host key. */
- client_host_key = RSA_new();
- if (client_host_key == NULL)
- fatal("RSA_new failed");
- client_host_key->e = BN_new();
- client_host_key->n = BN_new();
- if (client_host_key->e == NULL || client_host_key->n == NULL)
- fatal("BN_new failed");
+ client_host_key = key_new(KEY_RSA1);
bits = packet_get_int();
- packet_get_bignum(client_host_key->e, &elen);
- packet_get_bignum(client_host_key->n, &nlen);
+ packet_get_bignum(client_host_key->rsa->e);
+ packet_get_bignum(client_host_key->rsa->n);
- if (bits != BN_num_bits(client_host_key->n))
+ if (bits != BN_num_bits(client_host_key->rsa->n))
verbose("Warning: keysize mismatch for client_host_key: "
- "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
- packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+ "actual %d, announced %d",
+ BN_num_bits(client_host_key->rsa->n), bits);
+ packet_check_eom();
- authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
- RSA_free(client_host_key);
+ authenticated = auth_rhosts_rsa(pw, client_user,
+ client_host_key);
+ key_free(client_host_key);
snprintf(info, sizeof info, " ruser %.100s", client_user);
break;
@@ -304,9 +244,10 @@ do_authloop(Authctxt *authctxt)
break;
}
/* RSA authentication requested. */
- n = BN_new();
- packet_get_bignum(n, &nlen);
- packet_integrity_check(plen, nlen, type);
+ if ((n = BN_new()) == NULL)
+ fatal("do_authloop: BN_new failed");
+ packet_get_bignum(n);
+ packet_check_eom();
authenticated = auth_rsa(pw, n);
BN_clear_free(n);
break;
@@ -322,7 +263,7 @@ do_authloop(Authctxt *authctxt)
* not visible to an outside observer.
*/
password = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
+ packet_check_eom();
#ifdef USE_PAM
/* Do PAM auth with password */
@@ -356,12 +297,9 @@ do_authloop(Authctxt *authctxt)
continue;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
- if (pam_cookie == NULL)
- break;
- {
+ if (pam_cookie != NULL) {
char *response = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
pam_cookie->resp[0]->resp = strdup(response);
xfree(response);
authenticated = ipam_complete_auth(pam_cookie);
@@ -372,12 +310,13 @@ do_authloop(Authctxt *authctxt)
#elif defined(SKEY)
case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS");
- if (options.challenge_reponse_authentication == 1) {
- char *challenge = get_challenge(authctxt, authctxt->style);
+ if (options.challenge_response_authentication == 1) {
+ char *challenge = get_challenge(authctxt);
if (challenge != NULL) {
debug("sending challenge '%s'", challenge);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_cstring(challenge);
+ xfree(challenge);
packet_send();
packet_write_wait();
continue;
@@ -386,10 +325,10 @@ do_authloop(Authctxt *authctxt)
break;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
- if (options.challenge_reponse_authentication == 1) {
+ if (options.challenge_response_authentication == 1) {
char *response = packet_get_string(&dlen);
debug("got response '%s'", response);
- packet_integrity_check(plen, 4 + dlen, type);
+ packet_check_eom();
authenticated = verify_response(authctxt, response);
memset(response, 'r', dlen);
xfree(response);
@@ -401,32 +340,6 @@ do_authloop(Authctxt *authctxt)
log("TIS authentication unsupported.");
break;
#endif
-#ifdef KRB5
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- /* Passing krb5 ticket */
- if (!options.krb5_tgt_passing
- /*|| !options.krb5_authentication */) {
- verbose("Kerberos v5 tgt passing disabled.");
- break;
- }
-
- if (tkt_client == NULL) {
- /* passing tgt without krb5 authentication */
- }
-
- {
- krb5_data tgt;
- u_int tgtlen;
- tgt.data = packet_get_string(&tgtlen);
- tgt.length = tgtlen;
-
- if (!auth_krb5_tgt(pw->pw_name, &tgt, tkt_client))
- verbose ("Kerberos V5 TGT refused for %.100s", pw->pw_name);
- xfree(tgt.data);
-
- break;
- }
-#endif /* KRB5 */
default:
/*
@@ -481,7 +394,7 @@ do_authloop(Authctxt *authctxt)
if (pw != NULL && pw->pw_uid == 0)
log("ROOT LOGIN as '%.100s' from %.100s",
pw->pw_name,
- get_canonical_hostname(options.reverse_mapping_check));
+ get_canonical_hostname(options.verify_reverse_mapping));
/* Log before sending the reply */
auth_log(authctxt, authenticated, get_authname(type), info);
@@ -513,23 +426,26 @@ do_authloop(Authctxt *authctxt)
* been exchanged and encryption is enabled.
*/
void
-do_authentication()
+do_authentication(void)
{
Authctxt *authctxt;
struct passwd *pw;
- int plen;
u_int ulen;
- char *user, *style = NULL;
+ char *p, *user, *style = NULL;
/* Get the name of the user that we wish to log in as. */
- packet_read_expect(&plen, SSH_CMSG_USER);
+ packet_read_expect(SSH_CMSG_USER);
/* Get the user name. */
user = packet_get_string(&ulen);
- packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+ packet_check_eom();
if ((style = strchr(user, ':')) != NULL)
- *style++ = 0;
+ *style++ = '\0';
+
+ /* XXX - SSH.com Kerberos v5 braindeath. */
+ if ((p = strchr(user, '@')) != NULL)
+ *p = '\0';
authctxt = authctxt_new();
authctxt->user = user;
diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c
index 702695a..1592da2 100644
--- a/crypto/openssh/auth2.c
+++ b/crypto/openssh/auth2.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@@ -51,7 +51,7 @@ RCSID("$FreeBSD$");
#include "misc.h"
#include "hostfile.h"
#include "canohost.h"
-#include "tildexpand.h"
+#include "match.h"
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
@@ -74,26 +74,22 @@ struct Authmethod {
/* protocol */
-void input_service_request(int type, int plen, void *ctxt);
-void input_userauth_request(int type, int plen, void *ctxt);
-void protocol_error(int type, int plen, void *ctxt);
+static void input_service_request(int, u_int32_t, void *);
+static void input_userauth_request(int, u_int32_t, void *);
/* helper */
-Authmethod *authmethod_lookup(const char *name);
-char *authmethods_get(void);
-int user_key_allowed(struct passwd *pw, Key *key);
-int
-hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
- Key *key);
+static Authmethod *authmethod_lookup(const char *);
+static char *authmethods_get(void);
+static int user_key_allowed(struct passwd *, Key *);
+static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
/* auth */
-void userauth_banner(void);
-void userauth_reply(Authctxt *authctxt, int authenticated);
-int userauth_none(Authctxt *authctxt);
-int userauth_passwd(Authctxt *authctxt);
-int userauth_pubkey(Authctxt *authctxt);
-int userauth_hostbased(Authctxt *authctxt);
-int userauth_kbdint(Authctxt *authctxt);
+static void userauth_banner(void);
+static int userauth_none(Authctxt *);
+static int userauth_passwd(Authctxt *);
+static int userauth_pubkey(Authctxt *);
+static int userauth_hostbased(Authctxt *);
+static int userauth_kbdint(Authctxt *);
Authmethod authmethods[] = {
{"none",
@@ -119,44 +115,30 @@ Authmethod authmethods[] = {
*/
void
-do_authentication2()
+do_authentication2(void)
{
Authctxt *authctxt = authctxt_new();
x_authctxt = authctxt; /*XXX*/
-#if defined(KRB4) || defined(KRB5)
- /* turn off kerberos, not supported by SSH2 */
- options.kerberos_authentication = 0;
-#endif
- /* challenge-reponse is implemented via keyboard interactive */
- if (options.challenge_reponse_authentication)
+ /* challenge-response is implemented via keyboard interactive */
+ if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
- dispatch_init(&protocol_error);
+ dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated(authctxt);
}
-void
-protocol_error(int type, int plen, void *ctxt)
-{
- log("auth: protocol error: type %d plen %d", type, plen);
- packet_start(SSH2_MSG_UNIMPLEMENTED);
- packet_put_int(0);
- packet_send();
- packet_write_wait();
-}
-
-void
-input_service_request(int type, int plen, void *ctxt)
+static void
+input_service_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
u_int len;
int accept = 0;
char *service = packet_get_string(&len);
- packet_done();
+ packet_check_eom();
if (authctxt == NULL)
fatal("input_service_request: no authctxt");
@@ -182,8 +164,8 @@ input_service_request(int type, int plen, void *ctxt)
xfree(service);
}
-void
-input_userauth_request(int type, int plen, void *ctxt)
+static void
+input_userauth_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
Authmethod *m = NULL;
@@ -195,7 +177,7 @@ input_userauth_request(int type, int plen, void *ctxt)
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip;
- from_host = get_canonical_hostname(options.reverse_mapping_check);
+ from_host = get_canonical_hostname(options.verify_reverse_mapping);
from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
@@ -229,14 +211,12 @@ input_userauth_request(int type, int plen, void *ctxt)
setproctitle("%s", pw ? user : "unknown");
authctxt->user = xstrdup(user);
authctxt->service = xstrdup(service);
- authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
- } else if (authctxt->valid) {
- if (strcmp(user, authctxt->user) != 0 ||
- strcmp(service, authctxt->service) != 0) {
- log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
- user, service, authctxt->user, authctxt->service);
- authctxt->valid = 0;
- }
+ authctxt->style = style ? xstrdup(style) : NULL;
+ } else if (strcmp(user, authctxt->user) != 0 ||
+ strcmp(service, authctxt->service) != 0) {
+ packet_disconnect("Change of username or service not allowed: "
+ "(%s,%s) -> (%s,%s)",
+ authctxt->user, authctxt->service, user, service);
}
#ifdef HAVE_LOGIN_CAP
@@ -267,14 +247,8 @@ input_userauth_request(int type, int plen, void *ctxt)
}
#endif /* LOGIN_ACCESS */
/* reset state */
- dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
+ auth2_challenge_stop(authctxt);
authctxt->postponed = 0;
-#ifdef BSD_AUTH
- if (authctxt->as) {
- auth_close(authctxt->as);
- authctxt->as = NULL;
- }
-#endif
/* try to authenticate user */
m = authmethod_lookup(method);
@@ -296,6 +270,8 @@ input_userauth_request(int type, int plen, void *ctxt)
void
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
{
+ char *methods;
+
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
@@ -308,11 +284,32 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
/* Log before sending the reply */
auth_log(authctxt, authenticated, method, " ssh2");
- if (!authctxt->postponed)
- userauth_reply(authctxt, authenticated);
+ if (authctxt->postponed)
+ return;
+
+ /* XXX todo: check if multiple auth methods are needed */
+ if (authenticated == 1) {
+ /* turn off userauth */
+ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
+ packet_start(SSH2_MSG_USERAUTH_SUCCESS);
+ packet_send();
+ packet_write_wait();
+ /* now we can break out */
+ authctxt->success = 1;
+ } else {
+ if (authctxt->failures++ > AUTH_FAIL_MAX)
+ packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+ methods = authmethods_get();
+ packet_start(SSH2_MSG_USERAUTH_FAILURE);
+ packet_put_cstring(methods);
+ packet_put_char(0); /* XXX partial success, unused */
+ packet_send();
+ packet_write_wait();
+ xfree(methods);
+ }
}
-void
+static void
userauth_banner(void)
{
struct stat st;
@@ -343,41 +340,14 @@ done:
return;
}
-void
-userauth_reply(Authctxt *authctxt, int authenticated)
-{
- char *methods;
-
- /* XXX todo: check if multiple auth methods are needed */
- if (authenticated == 1) {
- /* turn off userauth */
- dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
- packet_start(SSH2_MSG_USERAUTH_SUCCESS);
- packet_send();
- packet_write_wait();
- /* now we can break out */
- authctxt->success = 1;
- } else {
- if (authctxt->failures++ > AUTH_FAIL_MAX)
- packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
- methods = authmethods_get();
- packet_start(SSH2_MSG_USERAUTH_FAILURE);
- packet_put_cstring(methods);
- packet_put_char(0); /* XXX partial success, unused */
- packet_send();
- packet_write_wait();
- xfree(methods);
- }
-}
-
-int
+static int
userauth_none(Authctxt *authctxt)
{
/* disable method "none", only allowed one time */
Authmethod *m = authmethod_lookup("none");
if (m != NULL)
m->enabled = NULL;
- packet_done();
+ packet_check_eom();
userauth_banner();
#ifdef USE_PAM
return authctxt->valid ? auth_pam_password(authctxt, "") : 0;
@@ -386,7 +356,7 @@ userauth_none(Authctxt *authctxt)
#endif /* USE_PAM */
}
-int
+static int
userauth_passwd(Authctxt *authctxt)
{
char *password;
@@ -397,7 +367,7 @@ userauth_passwd(Authctxt *authctxt)
if (change)
log("password change not supported");
password = packet_get_string(&len);
- packet_done();
+ packet_check_eom();
if (authctxt->valid &&
#ifdef USE_PAM
auth_password(authctxt, password) == 1)
@@ -410,33 +380,33 @@ userauth_passwd(Authctxt *authctxt)
return authenticated;
}
-int
+static int
userauth_kbdint(Authctxt *authctxt)
{
int authenticated = 0;
- char *lang = NULL;
- char *devs = NULL;
+ char *lang, *devs;
lang = packet_get_string(NULL);
devs = packet_get_string(NULL);
- packet_done();
+ packet_check_eom();
- debug("keyboard-interactive language %s devs %s", lang, devs);
+ debug("keyboard-interactive devs %s", devs);
- if (options.challenge_reponse_authentication)
+ if (options.challenge_response_authentication)
authenticated = auth2_challenge(authctxt, devs);
- xfree(lang);
xfree(devs);
+ xfree(lang);
return authenticated;
}
-int
+static int
userauth_pubkey(Authctxt *authctxt)
{
Buffer b;
- Key *key;
- char *pkalg, *pkblob, *sig;
+ Key *key = NULL;
+ char *pkalg;
+ u_char *pkblob, *sig;
u_int alen, blen, slen;
int have_sig, pktype;
int authenticated = 0;
@@ -462,83 +432,92 @@ userauth_pubkey(Authctxt *authctxt)
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
- log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
- xfree(pkalg);
- xfree(pkblob);
- return 0;
+ log("userauth_pubkey: unsupported public key algorithm: %s",
+ pkalg);
+ goto done;
}
key = key_from_blob(pkblob, blen);
- if (key != NULL) {
- if (have_sig) {
- sig = packet_get_string(&slen);
- packet_done();
- buffer_init(&b);
- if (datafellows & SSH_OLD_SESSIONID) {
- buffer_append(&b, session_id2, session_id2_len);
- } else {
- buffer_put_string(&b, session_id2, session_id2_len);
- }
- /* reconstruct packet */
- buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&b, authctxt->user);
- buffer_put_cstring(&b,
- datafellows & SSH_BUG_PKSERVICE ?
- "ssh-userauth" :
- authctxt->service);
- if (datafellows & SSH_BUG_PKAUTH) {
- buffer_put_char(&b, have_sig);
- } else {
- buffer_put_cstring(&b, "publickey");
- buffer_put_char(&b, have_sig);
- buffer_put_cstring(&b, pkalg);
- }
- buffer_put_string(&b, pkblob, blen);
+ if (key == NULL) {
+ error("userauth_pubkey: cannot decode key: %s", pkalg);
+ goto done;
+ }
+ if (key->type != pktype) {
+ error("userauth_pubkey: type mismatch for decoded key "
+ "(received %d, expected %d)", key->type, pktype);
+ goto done;
+ }
+ if (have_sig) {
+ sig = packet_get_string(&slen);
+ packet_check_eom();
+ buffer_init(&b);
+ if (datafellows & SSH_OLD_SESSIONID) {
+ buffer_append(&b, session_id2, session_id2_len);
+ } else {
+ buffer_put_string(&b, session_id2, session_id2_len);
+ }
+ /* reconstruct packet */
+ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+ buffer_put_cstring(&b, authctxt->user);
+ buffer_put_cstring(&b,
+ datafellows & SSH_BUG_PKSERVICE ?
+ "ssh-userauth" :
+ authctxt->service);
+ if (datafellows & SSH_BUG_PKAUTH) {
+ buffer_put_char(&b, have_sig);
+ } else {
+ buffer_put_cstring(&b, "publickey");
+ buffer_put_char(&b, have_sig);
+ buffer_put_cstring(&b, pkalg);
+ }
+ buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_PK
- buffer_dump(&b);
+ buffer_dump(&b);
#endif
- /* test for correct signature */
- if (user_key_allowed(authctxt->pw, key) &&
- key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
- authenticated = 1;
- buffer_clear(&b);
- xfree(sig);
- } else {
- debug("test whether pkalg/pkblob are acceptable");
- packet_done();
-
- /* XXX fake reply and always send PK_OK ? */
- /*
- * XXX this allows testing whether a user is allowed
- * to login: if you happen to have a valid pubkey this
- * message is sent. the message is NEVER sent at all
- * if a user is not allowed to login. is this an
- * issue? -markus
- */
- if (user_key_allowed(authctxt->pw, key)) {
- packet_start(SSH2_MSG_USERAUTH_PK_OK);
- packet_put_string(pkalg, alen);
- packet_put_string(pkblob, blen);
- packet_send();
- packet_write_wait();
- authctxt->postponed = 1;
- }
+ /* test for correct signature */
+ if (user_key_allowed(authctxt->pw, key) &&
+ key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+ authenticated = 1;
+ buffer_clear(&b);
+ xfree(sig);
+ } else {
+ debug("test whether pkalg/pkblob are acceptable");
+ packet_check_eom();
+
+ /* XXX fake reply and always send PK_OK ? */
+ /*
+ * XXX this allows testing whether a user is allowed
+ * to login: if you happen to have a valid pubkey this
+ * message is sent. the message is NEVER sent at all
+ * if a user is not allowed to login. is this an
+ * issue? -markus
+ */
+ if (user_key_allowed(authctxt->pw, key)) {
+ packet_start(SSH2_MSG_USERAUTH_PK_OK);
+ packet_put_string(pkalg, alen);
+ packet_put_string(pkblob, blen);
+ packet_send();
+ packet_write_wait();
+ authctxt->postponed = 1;
}
- if (authenticated != 1)
- auth_clear_options();
- key_free(key);
}
+ if (authenticated != 1)
+ auth_clear_options();
+done:
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
+ if (key != NULL)
+ key_free(key);
xfree(pkalg);
xfree(pkblob);
return authenticated;
}
-int
+static int
userauth_hostbased(Authctxt *authctxt)
{
Buffer b;
- Key *key;
- char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
+ Key *key = NULL;
+ char *pkalg, *cuser, *chost, *service;
+ u_char *pkblob, *sig;
u_int alen, blen, slen;
int pktype;
int authenticated = 0;
@@ -571,7 +550,12 @@ userauth_hostbased(Authctxt *authctxt)
}
key = key_from_blob(pkblob, blen);
if (key == NULL) {
- debug("userauth_hostbased: cannot decode key: %s", pkalg);
+ error("userauth_hostbased: cannot decode key: %s", pkalg);
+ goto done;
+ }
+ if (key->type != pktype) {
+ error("userauth_hostbased: type mismatch for decoded key "
+ "(received %d, expected %d)", key->type, pktype);
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
@@ -596,10 +580,10 @@ userauth_hostbased(Authctxt *authctxt)
authenticated = 1;
buffer_clear(&b);
- key_free(key);
-
done:
debug2("userauth_hostbased: authenticated %d", authenticated);
+ if (key != NULL)
+ key_free(key);
xfree(pkalg);
xfree(pkblob);
xfree(cuser);
@@ -618,39 +602,30 @@ auth_get_user(void)
#define DELIM ","
-char *
+static char *
authmethods_get(void)
{
Authmethod *method = NULL;
- u_int size = 0;
+ Buffer b;
char *list;
+ buffer_init(&b);
for (method = authmethods; method->name != NULL; method++) {
if (strcmp(method->name, "none") == 0)
continue;
if (method->enabled != NULL && *(method->enabled) != 0) {
- if (size != 0)
- size += strlen(DELIM);
- size += strlen(method->name);
- }
- }
- size++; /* trailing '\0' */
- list = xmalloc(size);
- list[0] = '\0';
-
- for (method = authmethods; method->name != NULL; method++) {
- if (strcmp(method->name, "none") == 0)
- continue;
- if (method->enabled != NULL && *(method->enabled) != 0) {
- if (list[0] != '\0')
- strlcat(list, DELIM, size);
- strlcat(list, method->name, size);
+ if (buffer_len(&b) > 0)
+ buffer_append(&b, ",", 1);
+ buffer_append(&b, method->name, strlen(method->name));
}
}
+ buffer_append(&b, "\0", 1);
+ list = xstrdup(buffer_ptr(&b));
+ buffer_free(&b);
return list;
}
-Authmethod *
+static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
@@ -665,15 +640,16 @@ authmethod_lookup(const char *name)
}
/* return 1 if user allows given key */
-int
-user_key_allowed(struct passwd *pw, Key *key)
+static int
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
{
- char line[8192], file[MAXPATHLEN];
+ char line[8192];
int found_key = 0;
FILE *f;
u_long linenum = 0;
struct stat st;
Key *found;
+ char *fp;
if (pw == NULL)
return 0;
@@ -681,9 +657,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Temporarily use the user's uid. */
temporarily_use_uid(pw);
- /* The authorized keys. */
- snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
- _PATH_SSH_USER_PERMITTED_KEYS2);
+ debug("trying public key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
@@ -698,46 +672,14 @@ user_key_allowed(struct passwd *pw, Key *key)
restore_uid();
return 0;
}
- if (options.strict_modes) {
- int fail = 0;
- char buf[1024];
- /* Check open file in order to avoid open/stat races */
- if (fstat(fileno(f), &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(buf, sizeof buf,
- "%s authentication refused for %.100s: "
- "bad ownership or modes for '%s'.",
- key_type(key), pw->pw_name, file);
- fail = 1;
- } else {
- /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
- int i;
- static const char *check[] = {
- "", _PATH_SSH_USER_DIR, NULL
- };
- for (i = 0; check[i]; i++) {
- snprintf(line, sizeof line, "%.500s/%.100s",
- pw->pw_dir, check[i]);
- if (stat(line, &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(buf, sizeof buf,
- "%s authentication refused for %.100s: "
- "bad ownership or modes for '%s'.",
- key_type(key), pw->pw_name, line);
- fail = 1;
- break;
- }
- }
- }
- if (fail) {
- fclose(f);
- log("%s", buf);
- restore_uid();
- return 0;
- }
+ if (options.strict_modes &&
+ secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+ fclose(f);
+ log("Authentication refused: %s", line);
+ restore_uid();
+ return 0;
}
+
found_key = 0;
found = key_new(key->type);
@@ -750,7 +692,7 @@ user_key_allowed(struct passwd *pw, Key *key)
if (!*cp || *cp == '\n' || *cp == '#')
continue;
- if (key_read(found, &cp) == -1) {
+ if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
@@ -764,7 +706,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
- if (key_read(found, &cp) == -1) {
+ if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
@@ -773,8 +715,12 @@ user_key_allowed(struct passwd *pw, Key *key)
if (key_equal(found, key) &&
auth_parse_options(pw, options, file, linenum) == 1) {
found_key = 1;
- debug("matching key found: file %s, line %ld",
+ debug("matching key found: file %s, line %lu",
file, linenum);
+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+ verbose("Found matching %s key: %s",
+ key_type(found), fp);
+ xfree(fp);
break;
}
}
@@ -786,18 +732,36 @@ user_key_allowed(struct passwd *pw, Key *key)
return found_key;
}
+/* check whether given key is in .ssh/authorized_keys* */
+static int
+user_key_allowed(struct passwd *pw, Key *key)
+{
+ int success;
+ char *file;
+
+ file = authorized_keys_file(pw);
+ success = user_key_allowed2(pw, key, file);
+ xfree(file);
+ if (success)
+ return success;
+
+ /* try suffix "2" for backward compat, too */
+ file = authorized_keys_file2(pw);
+ success = user_key_allowed2(pw, key, file);
+ xfree(file);
+ return success;
+}
+
/* return 1 if given hostkey is allowed */
-int
+static int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key)
{
- Key *found;
const char *resolvedname, *ipaddr, *lookup;
- struct stat st;
- char *user_hostfile;
- int host_status, len;
+ HostStatus host_status;
+ int len;
- resolvedname = get_canonical_hostname(options.reverse_mapping_check);
+ resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
@@ -822,32 +786,16 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
}
debug2("userauth_hostbased: access allowed by auth_rhosts2");
- /* XXX this is copied from auth-rh-rsa.c and should be shared */
- found = key_new(key->type);
- host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE2, lookup,
- key, found, NULL);
-
- if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
- user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE2,
- pw->pw_uid);
- if (options.strict_modes &&
- (stat(user_hostfile, &st) == 0) &&
- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
- log("Hostbased authentication refused for %.100s: "
- "bad owner or modes for %.200s",
- pw->pw_name, user_hostfile);
- } else {
- temporarily_use_uid(pw);
- host_status = check_host_in_hostfile(user_hostfile,
- lookup, key, found, NULL);
- restore_uid();
- }
- xfree(user_hostfile);
- }
- key_free(found);
+ host_status = check_key_in_hostfiles(pw, key, lookup,
+ _PATH_SSH_SYSTEM_HOSTFILE,
+ options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
+
+ /* backward compat if no key has been found. */
+ if (host_status == HOST_NEW)
+ host_status = check_key_in_hostfiles(pw, key, lookup,
+ _PATH_SSH_SYSTEM_HOSTFILE2,
+ options.ignore_user_known_hosts ? NULL :
+ _PATH_SSH_USER_HOSTFILE2);
- debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
- "ok" : "not found", lookup);
return (host_status == HOST_OK);
}
diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c
index 953c852..35a6a3f 100644
--- a/crypto/openssh/authfd.c
+++ b/crypto/openssh/authfd.c
@@ -35,7 +35,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: authfd.c,v 1.39 2001/04/05 10:42:48 markus Exp $");
+RCSID("$OpenBSD: authfd.c,v 1.48 2002/02/24 19:14:59 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@@ -59,7 +59,8 @@ int decode_reply(int type);
/* macro to check for "agent failure" message */
#define agent_failed(x) \
- ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE))
+ ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
+ (x == SSH2_AGENT_FAILURE))
/* Returns the number of the authentication fd, or -1 if there is none. */
@@ -67,7 +68,7 @@ int
ssh_get_authentication_socket(void)
{
const char *authsocket;
- int sock, len;
+ int sock;
struct sockaddr_un sunaddr;
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
@@ -76,8 +77,6 @@ ssh_get_authentication_socket(void)
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
- len = SUN_LEN(&sunaddr)+1;
- sunaddr.sun_len = len;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
@@ -88,14 +87,14 @@ ssh_get_authentication_socket(void)
close(sock);
return -1;
}
- if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
+ if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
close(sock);
return -1;
}
return sock;
}
-int
+static int
ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
{
int l, len;
@@ -219,7 +218,7 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version)
int type, code1 = 0, code2 = 0;
Buffer request;
- switch(version){
+ switch (version) {
case 1:
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
@@ -288,7 +287,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
* Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data.
*/
- switch(version){
+ switch (version) {
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities);
@@ -346,7 +345,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
buffer_put_bignum(&buffer, key->rsa->e);
buffer_put_bignum(&buffer, key->rsa->n);
buffer_put_bignum(&buffer, challenge);
- buffer_append(&buffer, (char *) session_id, 16);
+ buffer_append(&buffer, session_id, 16);
buffer_put_int(&buffer, response_type);
if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
@@ -376,8 +375,8 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
- u_char **sigp, int *lenp,
- u_char *data, int datalen)
+ u_char **sigp, u_int *lenp,
+ u_char *data, u_int datalen)
{
extern int datafellows;
Buffer msg;
@@ -418,7 +417,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */
-void
+static void
ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{
buffer_clear(b);
@@ -431,16 +430,16 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
buffer_put_bignum(b, key->iqmp); /* ssh key->u */
buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
- buffer_put_string(b, comment, strlen(comment));
+ buffer_put_cstring(b, comment);
}
-void
+static void
ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
buffer_put_cstring(b, key_ssh_name(key));
- switch(key->type){
+ switch (key->type) {
case KEY_RSA:
buffer_put_bignum2(b, key->rsa->n);
buffer_put_bignum2(b, key->rsa->e);
@@ -533,6 +532,25 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
return decode_reply(type);
}
+int
+ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id)
+{
+ Buffer msg;
+ int type;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
+ SSH_AGENTC_REMOVE_SMARTCARD_KEY);
+ buffer_put_cstring(&msg, reader_id);
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
+ return 0;
+ }
+ type = buffer_get_char(&msg);
+ buffer_free(&msg);
+ return decode_reply(type);
+}
+
/*
* Removes all identities from the agent. This call is not meant to be used
* by normal applications.
@@ -565,6 +583,7 @@ decode_reply(int type)
switch (type) {
case SSH_AGENT_FAILURE:
case SSH_COM_AGENT2_FAILURE:
+ case SSH2_AGENT_FAILURE:
log("SSH_AGENT_FAILURE");
return 0;
case SSH_AGENT_SUCCESS:
diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c
index 4d47501..80b2fc5 100644
--- a/crypto/openssh/authfile.c
+++ b/crypto/openssh/authfile.c
@@ -36,7 +36,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
+RCSID("$OpenBSD: authfile.c,v 1.48 2002/02/28 15:46:33 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/err.h>
@@ -51,6 +51,7 @@ RCSID("$FreeBSD$");
#include "ssh.h"
#include "log.h"
#include "authfile.h"
+#include "rsa.h"
/* Version identification string for SSH v1 identity files. */
static const char authfile_id_string[] =
@@ -63,13 +64,13 @@ static const char authfile_id_string[] =
* passphrase.
*/
-int
+static int
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
const char *comment)
{
Buffer buffer, encrypted;
- char buf[100], *cp;
- int fd, i;
+ u_char buf[100], *cp;
+ int fd, i, cipher_num;
CipherContext ciphercontext;
Cipher *cipher;
u_int32_t rand;
@@ -78,11 +79,9 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
*/
- if (strcmp(passphrase, "") == 0)
- cipher = cipher_by_number(SSH_CIPHER_NONE);
- else
- cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
- if (cipher == NULL)
+ cipher_num = (strcmp(passphrase, "") == 0) ?
+ SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
+ if ((cipher = cipher_by_number(cipher_num)) == NULL)
fatal("save_private_key_rsa: bad cipher");
/* This buffer is used to built the secret part of the private key. */
@@ -119,21 +118,23 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
buffer_put_char(&encrypted, 0);
/* Store cipher type. */
- buffer_put_char(&encrypted, cipher->number);
+ buffer_put_char(&encrypted, cipher_num);
buffer_put_int(&encrypted, 0); /* For future extension */
/* Store public key. This will be in plain text. */
buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
buffer_put_bignum(&encrypted, key->rsa->n);
buffer_put_bignum(&encrypted, key->rsa->e);
- buffer_put_string(&encrypted, comment, strlen(comment));
+ buffer_put_cstring(&encrypted, comment);
/* Allocate space for the private part of the key in the buffer. */
- buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
+ cp = buffer_append_space(&encrypted, buffer_len(&buffer));
- cipher_set_key_string(&ciphercontext, cipher, passphrase);
- cipher_encrypt(&ciphercontext, (u_char *) cp,
- (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
+ cipher_set_key_string(&ciphercontext, cipher, passphrase,
+ CIPHER_ENCRYPT);
+ cipher_crypt(&ciphercontext, cp,
+ buffer_ptr(&buffer), buffer_len(&buffer));
+ cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
/* Destroy temporary data. */
@@ -148,7 +149,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) {
error("write to key file %s failed: %s", filename,
- strerror(errno));
+ strerror(errno));
buffer_free(&encrypted);
close(fd);
unlink(filename);
@@ -160,7 +161,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
}
/* save SSH v2 key in OpenSSL PEM format */
-int
+static int
key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
const char *comment)
{
@@ -168,8 +169,8 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
int fd;
int success = 0;
int len = strlen(_passphrase);
- char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
- EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
+ u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
+ const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
if (len > 0 && len <= 4) {
error("passphrase too short: have %d bytes, need > 4", len);
@@ -227,7 +228,7 @@ key_save_private(Key *key, const char *filename, const char *passphrase,
* otherwise.
*/
-Key *
+static Key *
key_load_public_rsa1(int fd, const char *filename, char **commentp)
{
Buffer buffer;
@@ -240,7 +241,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
- buffer_append_space(&buffer, &cp, len);
+ cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@@ -251,7 +252,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
- debug3("No RSA1 key file %.200s.", filename);
+ debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@@ -261,7 +262,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
- debug3("No RSA1 key file %.200s.", filename);
+ debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@@ -307,25 +308,23 @@ key_load_public_type(int type, const char *filename, char **commentp)
* Assumes we are called under uid of the owner of the file.
*/
-Key *
+static Key *
key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
char **commentp)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
- char *cp;
+ u_char *cp;
CipherContext ciphercontext;
Cipher *cipher;
- BN_CTX *ctx;
- BIGNUM *aux;
Key *prv = NULL;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
- buffer_append_space(&buffer, &cp, len);
+ cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@@ -337,7 +336,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
- debug3("No RSA1 key file %.200s.", filename);
+ debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@@ -348,7 +347,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
- debug3("No RSA1 key file %.200s.", filename);
+ debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@@ -379,12 +378,14 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
}
/* Initialize space for decrypted data. */
buffer_init(&decrypted);
- buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
+ cp = buffer_append_space(&decrypted, buffer_len(&buffer));
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
- cipher_set_key_string(&ciphercontext, cipher, passphrase);
- cipher_decrypt(&ciphercontext, (u_char *) cp,
- (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
+ cipher_set_key_string(&ciphercontext, cipher, passphrase,
+ CIPHER_DECRYPT);
+ cipher_crypt(&ciphercontext, cp,
+ buffer_ptr(&buffer), buffer_len(&buffer));
+ cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&buffer);
@@ -407,17 +408,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
/* calculate p-1 and q-1 */
- ctx = BN_CTX_new();
- aux = BN_new();
-
- BN_sub(aux, prv->rsa->q, BN_value_one());
- BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
-
- BN_sub(aux, prv->rsa->p, BN_value_one());
- BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
-
- BN_clear_free(aux);
- BN_CTX_free(ctx);
+ rsa_generate_additional_parameters(prv->rsa);
buffer_free(&decrypted);
close(fd);
@@ -431,7 +422,7 @@ fail:
return NULL;
}
-Key *
+static Key *
key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{
@@ -451,7 +442,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
debug("PEM_read_PrivateKey failed");
(void)ERR_get_error();
} else if (pk->type == EVP_PKEY_RSA &&
- (type == KEY_UNSPEC||type==KEY_RSA)) {
+ (type == KEY_UNSPEC||type==KEY_RSA)) {
prv = key_new(KEY_UNSPEC);
prv->rsa = EVP_PKEY_get1_RSA(pk);
prv->type = KEY_RSA;
@@ -460,7 +451,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
RSA_print_fp(stderr, prv->rsa, 8);
#endif
} else if (pk->type == EVP_PKEY_DSA &&
- (type == KEY_UNSPEC||type==KEY_DSA)) {
+ (type == KEY_UNSPEC||type==KEY_DSA)) {
prv = key_new(KEY_UNSPEC);
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
@@ -482,20 +473,23 @@ key_load_private_pem(int fd, int type, const char *passphrase,
return prv;
}
-int
+static int
key_perm_ok(int fd, const char *filename)
{
struct stat st;
- /* check owner and modes */
- if (fstat(fd, &st) < 0 ||
- (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
- (st.st_mode & 077) != 0) {
- close(fd);
+ if (fstat(fd, &st) < 0)
+ return 0;
+ /*
+ * if a key owned by the user is accessed, then we check the
+ * permissions of the file. if the key owned by a different user,
+ * then we don't care.
+ */
+ if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
- error("Bad ownership or mode(0%3.3o) for '%s'.",
+ error("Permissions 0%3.3o for '%s' are too open.",
st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
@@ -541,7 +535,7 @@ Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp)
{
- Key *pub;
+ Key *pub, *prv;
int fd;
fd = open(filename, O_RDONLY);
@@ -556,16 +550,20 @@ key_load_private(const char *filename, const char *passphrase,
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
if (pub == NULL) {
/* closes fd */
- return key_load_private_pem(fd, KEY_UNSPEC, passphrase, commentp);
+ prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
+ /* use the filename as a comment for PEM */
+ if (commentp && prv)
+ *commentp = xstrdup(filename);
} else {
/* it's a SSH v1 key if the public key part is readable */
key_free(pub);
/* closes fd */
- return key_load_private_rsa1(fd, filename, passphrase, NULL);
+ prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
}
+ return prv;
}
-int
+static int
key_try_load_public(Key *k, const char *filename, char **commentp)
{
FILE *f;
@@ -577,7 +575,7 @@ key_try_load_public(Key *k, const char *filename, char **commentp)
while (fgets(line, sizeof(line), f)) {
line[sizeof(line)-1] = '\0';
cp = line;
- switch(*cp){
+ switch (*cp) {
case '#':
case '\n':
case '\0':
diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c
index cf8a170..b7f99090 100644
--- a/crypto/openssh/bufaux.c
+++ b/crypto/openssh/bufaux.c
@@ -37,7 +37,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
+RCSID("$OpenBSD: bufaux.c,v 1.22 2002/01/18 18:14:17 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h>
@@ -63,7 +63,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf);
if (oi != bin_size)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
- oi, bin_size);
+ oi, bin_size);
/* Store the number of bits in the buffer in two bytes, msb first. */
PUT_16BIT(msg, bits);
@@ -78,7 +78,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
/*
* Retrieves an BIGNUM from the buffer.
*/
-int
+void
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{
int bits, bytes;
@@ -91,11 +91,9 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
bytes = (bits + 7) / 8;
if (buffer_len(buffer) < bytes)
fatal("buffer_get_bignum: input buffer too small");
- bin = (u_char *) buffer_ptr(buffer);
+ bin = buffer_ptr(buffer);
BN_bin2bn(bin, bytes, value);
buffer_consume(buffer, bytes);
-
- return 2 + bytes;
}
/*
@@ -113,16 +111,16 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf+1);
if (oi != bytes-1)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
- oi, bytes);
+ oi, bytes);
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
u_char *uc = buf;
log("negativ!");
- for(i = bytes-1, carry = 1; i>=0; i--) {
+ for (i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
- if(carry)
+ if (carry)
carry = !++uc[i];
}
}
@@ -131,15 +129,14 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
xfree(buf);
}
-int
+void
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
/**XXX should be two's-complement */
int len;
- u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
+ u_char *bin = buffer_get_string(buffer, (u_int *)&len);
BN_bin2bn(bin, len, value);
xfree(bin);
- return len;
}
/*
@@ -188,11 +185,11 @@ buffer_put_int64(Buffer *buffer, u_int64_t value)
* will be stored there. A null character will be automatically appended
* to the returned string, and is not counted in length.
*/
-char *
+void *
buffer_get_string(Buffer *buffer, u_int *length_ptr)
{
u_int len;
- char *value;
+ u_char *value;
/* Get the length. */
len = buffer_get_int(buffer);
if (len > 256 * 1024)
diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c
index b535444..2892aaa 100644
--- a/crypto/openssh/canohost.c
+++ b/crypto/openssh/canohost.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: canohost.c,v 1.26 2001/04/18 14:15:00 markus Exp $");
+RCSID("$OpenBSD: canohost.c,v 1.31 2002/02/27 21:23:13 stevesk Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
@@ -20,15 +20,15 @@ RCSID("$FreeBSD$");
#include "log.h"
#include "canohost.h"
-void check_ip_options(int socket, char *ipaddr);
+static void check_ip_options(int, char *);
/*
* Return the canonical name of the host at the other end of the socket. The
* caller should free the returned string with xfree.
*/
-char *
-get_remote_hostname(int socket, int reverse_mapping_check)
+static char *
+get_remote_hostname(int socket, int verify_reverse_mapping)
{
struct sockaddr_storage from;
int i;
@@ -47,13 +47,13 @@ get_remote_hostname(int socket, int reverse_mapping_check)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
- NULL, 0, NI_NUMERICHOST) != 0)
+ NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
- NULL, 0, NI_NAMEREQD) != 0) {
+ NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
log("Could not reverse map address %.100s.", ntop);
return xstrdup(ntop);
@@ -69,7 +69,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
if (isupper(name[i]))
name[i] = tolower(name[i]);
- if (!reverse_mapping_check)
+ if (!verify_reverse_mapping)
return xstrdup(name);
/*
* Map it back to an IP address and check that the given
@@ -119,7 +119,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
* exit here if we detect any IP options.
*/
/* IPv4 only */
-void
+static void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200];
@@ -133,7 +133,7 @@ check_ip_options(int socket, char *ipaddr)
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
- if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
+ if (getsockopt(socket, ipproto, IP_OPTIONS, options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
@@ -153,14 +153,14 @@ check_ip_options(int socket, char *ipaddr)
*/
const char *
-get_canonical_hostname(int reverse_mapping_check)
+get_canonical_hostname(int verify_reverse_mapping)
{
static char *canonical_host_name = NULL;
- static int reverse_mapping_checked = 0;
+ static int verify_reverse_mapping_done = 0;
/* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) {
- if (reverse_mapping_checked != reverse_mapping_check)
+ if (verify_reverse_mapping_done != verify_reverse_mapping)
xfree(canonical_host_name);
else
return canonical_host_name;
@@ -169,11 +169,11 @@ get_canonical_hostname(int reverse_mapping_check)
/* Get the real hostname if socket; otherwise return UNKNOWN. */
if (packet_connection_is_on_socket())
canonical_host_name = get_remote_hostname(
- packet_get_connection_in(), reverse_mapping_check);
+ packet_get_connection_in(), verify_reverse_mapping);
else
canonical_host_name = xstrdup("UNKNOWN");
- reverse_mapping_checked = reverse_mapping_check;
+ verify_reverse_mapping_done = verify_reverse_mapping;
return canonical_host_name;
}
@@ -181,7 +181,7 @@ get_canonical_hostname(int reverse_mapping_check)
* Returns the remote IP-address of socket as a string. The returned
* string must be freed.
*/
-char *
+static char *
get_socket_address(int socket, int remote, int flags)
{
struct sockaddr_storage addr;
@@ -209,7 +209,7 @@ get_socket_address(int socket, int remote, int flags)
}
/* Get the address in ascii. */
if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
- NULL, 0, flags) != 0) {
+ NULL, 0, flags) != 0) {
error("get_socket_ipaddr: getnameinfo %d failed", flags);
return NULL;
}
@@ -240,7 +240,7 @@ get_local_name(int socket)
*/
const char *
-get_remote_ipaddr()
+get_remote_ipaddr(void)
{
static char *canonical_host_ip = NULL;
@@ -260,11 +260,11 @@ get_remote_ipaddr()
}
const char *
-get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
+get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping)
{
static const char *remote = "";
if (utmp_len > 0)
- remote = get_canonical_hostname(reverse_mapping_check);
+ remote = get_canonical_hostname(verify_reverse_mapping);
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
@@ -272,7 +272,7 @@ get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
/* Returns the local/remote port for the socket. */
-int
+static int
get_sock_port(int sock, int local)
{
struct sockaddr_storage from;
@@ -295,14 +295,14 @@ get_sock_port(int sock, int local)
}
/* Return port number. */
if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
- strport, sizeof(strport), NI_NUMERICSERV) != 0)
+ strport, sizeof(strport), NI_NUMERICSERV) != 0)
fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
return atoi(strport);
}
/* Returns remote/local port number for the current connection. */
-int
+static int
get_port(int local)
{
/*
@@ -323,13 +323,13 @@ get_peer_port(int sock)
}
int
-get_remote_port()
+get_remote_port(void)
{
return get_port(0);
}
int
-get_local_port()
+get_local_port(void)
{
return get_port(1);
}
diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c
index 2d27260..9fea660 100644
--- a/crypto/openssh/channels.c
+++ b/crypto/openssh/channels.c
@@ -12,9 +12,8 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
- *
* SSH2 support added by Markus Friedl.
- * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Dug Song. All rights reserved.
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
*
@@ -40,71 +39,47 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.109 2001/04/17 12:55:03 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.171 2002/03/04 19:37:58 markus Exp $");
RCSID("$FreeBSD$");
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-
#include "ssh.h"
#include "ssh1.h"
#include "ssh2.h"
#include "packet.h"
#include "xmalloc.h"
-#include "buffer.h"
-#include "bufaux.h"
#include "uidswap.h"
#include "log.h"
#include "misc.h"
#include "channels.h"
-#include "nchan.h"
#include "compat.h"
#include "canohost.h"
#include "key.h"
#include "authfd.h"
+#include "pathnames.h"
-/* Maximum number of fake X11 displays to try. */
-#define MAX_DISPLAYS 1000
-/* Max len of agent socket */
-#define MAX_SOCKET_NAME 100
+/* -- channel core */
/*
* 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 type
- * SSH_CHANNEL_FREE.
+ * initialized (at least the type field); unused slots set to NULL
*/
static int channels_alloc = 0;
/*
* Maximum file descriptor value used in any of the channels. This is
- * updated in channel_allocate.
+ * updated in channel_new.
*/
static int channel_max_fd = 0;
-/* Name and directory of socket for authentication agent forwarding. */
-static char *channel_forwarded_auth_socket_name = NULL;
-static char *channel_forwarded_auth_socket_dir = NULL;
-
-/* Saved X11 authentication protocol name. */
-char *x11_saved_proto = NULL;
-
-/* Saved X11 authentication data. This is the real data. */
-char *x11_saved_data = NULL;
-u_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.
- */
-char *x11_fake_data = NULL;
-u_int x11_fake_data_len;
+/* -- tcp forwarding */
/*
* Data structure for storing which hosts are permitted for forward requests.
@@ -120,6 +95,7 @@ typedef struct {
/* List of all permitted host/port pairs to connect. */
static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
+
/* Number of permitted host/port pairs in the array. */
static int num_permitted_opens = 0;
/*
@@ -129,34 +105,54 @@ static int num_permitted_opens = 0;
*/
static int all_opens_permitted = 0;
-/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
-static int have_hostname_in_open = 0;
-/* AF_UNSPEC or AF_INET or AF_INET6 */
-int IPv4or6 = AF_UNSPEC;
+/* -- X11 forwarding */
-void port_open_helper(Channel *c, char *rtype);
+/* Maximum number of fake X11 displays to try. */
+#define MAX_DISPLAYS 1000
-/* Sets specific protocol options. */
+/* Saved X11 authentication protocol name. */
+static char *x11_saved_proto = NULL;
-void
-channel_set_options(int hostname_in_open)
-{
- have_hostname_in_open = hostname_in_open;
-}
+/* Saved X11 authentication data. This is the real data. */
+static char *x11_saved_data = NULL;
+static u_int x11_saved_data_len = 0;
-/* lookup channel by id */
+/*
+ * Fake X11 authentication data. This is what the server will be sending us;
+ * we should replace any occurrences of this by the real data.
+ */
+static char *x11_fake_data = NULL;
+static u_int x11_fake_data_len;
+
+
+/* -- agent forwarding */
+
+#define NUM_SOCKS 10
+
+/* Name and directory of socket for authentication agent forwarding. */
+static char *auth_sock_name = NULL;
+static char *auth_sock_dir = NULL;
+
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+int IPv4or6 = AF_UNSPEC;
+
+/* helper */
+static void port_open_helper(Channel *c, char *rtype);
+
+/* -- channel core */
Channel *
channel_lookup(int id)
{
Channel *c;
+
if (id < 0 || id >= channels_alloc) {
log("channel_lookup: %d: bad id", id);
return NULL;
}
- c = &channels[id];
- if (c->type == SSH_CHANNEL_FREE) {
+ c = channels[id];
+ if (c == NULL) {
log("channel_lookup: %d: bad id: channel free", id);
return NULL;
}
@@ -168,7 +164,7 @@ channel_lookup(int id)
* when the channel consumer/producer is ready, e.g. shell exec'd
*/
-void
+static void
channel_register_fds(Channel *c, int rfd, int wfd, int efd,
int extusage, int nonblock)
{
@@ -213,7 +209,7 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
* remote_name to be freed.
*/
-int
+Channel *
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
int window, int maxpack, int extusage, char *remote_name, int nonblock)
{
@@ -222,20 +218,15 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
/* Do initial allocation if this is the first call. */
if (channels_alloc == 0) {
- chan_init();
channels_alloc = 10;
- channels = xmalloc(channels_alloc * sizeof(Channel));
+ channels = xmalloc(channels_alloc * sizeof(Channel *));
for (i = 0; i < channels_alloc; i++)
- channels[i].type = SSH_CHANNEL_FREE;
- /*
- * Kludge: arrange a call to channel_stop_listening if we
- * terminate with fatal().
- */
- fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
+ channels[i] = NULL;
+ fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL);
}
/* Try to find a free slot where to put the new channel. */
for (found = -1, i = 0; i < channels_alloc; i++)
- if (channels[i].type == SSH_CHANNEL_FREE) {
+ if (channels[i] == NULL) {
/* Found a free slot. */
found = i;
break;
@@ -245,16 +236,19 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
found = channels_alloc;
channels_alloc += 10;
debug2("channel: expanding %d", channels_alloc);
- channels = xrealloc(channels, channels_alloc * sizeof(Channel));
+ channels = xrealloc(channels, channels_alloc * sizeof(Channel *));
for (i = found; i < channels_alloc; i++)
- channels[i].type = SSH_CHANNEL_FREE;
+ channels[i] = NULL;
}
- /* Initialize and return new channel number. */
- c = &channels[found];
+ /* Initialize and return new channel. */
+ c = channels[found] = xmalloc(sizeof(Channel));
+ memset(c, 0, sizeof(Channel));
buffer_init(&c->input);
buffer_init(&c->output);
buffer_init(&c->extended);
- chan_init_iostates(c);
+ c->ostate = CHAN_OUTPUT_OPEN;
+ c->istate = CHAN_INPUT_OPEN;
+ c->flags = 0;
channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
c->self = found;
c->type = type;
@@ -267,73 +261,402 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
c->remote_name = remote_name;
c->remote_window = 0;
c->remote_maxpacket = 0;
- c->cb_fn = NULL;
- c->cb_arg = NULL;
- c->cb_event = 0;
- c->dettach_user = NULL;
+ c->force_drain = 0;
+ c->single_connection = 0;
+ c->detach_user = NULL;
+ c->confirm = NULL;
c->input_filter = NULL;
debug("channel %d: new [%s]", found, remote_name);
- return found;
+ return c;
}
-/* old interface XXX */
-int
-channel_allocate(int type, int sock, char *remote_name)
+
+static int
+channel_find_maxfd(void)
{
- return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1);
+ int i, max = 0;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL) {
+ max = MAX(max, c->rfd);
+ max = MAX(max, c->wfd);
+ max = MAX(max, c->efd);
+ }
+ }
+ return max;
}
+int
+channel_close_fd(int *fdp)
+{
+ int ret = 0, fd = *fdp;
+
+ if (fd != -1) {
+ ret = close(fd);
+ *fdp = -1;
+ if (fd == channel_max_fd)
+ channel_max_fd = channel_find_maxfd();
+ }
+ return ret;
+}
/* Close all channel fd/socket. */
-void
+static void
channel_close_fds(Channel *c)
{
- if (c->sock != -1) {
- close(c->sock);
- c->sock = -1;
- }
- if (c->rfd != -1) {
- close(c->rfd);
- c->rfd = -1;
- }
- if (c->wfd != -1) {
- close(c->wfd);
- c->wfd = -1;
- }
- if (c->efd != -1) {
- close(c->efd);
- c->efd = -1;
- }
+ debug3("channel_close_fds: channel %d: r %d w %d e %d",
+ c->self, c->rfd, c->wfd, c->efd);
+
+ channel_close_fd(&c->sock);
+ channel_close_fd(&c->rfd);
+ channel_close_fd(&c->wfd);
+ channel_close_fd(&c->efd);
}
/* Free the channel and close its fd/socket. */
void
-channel_free(int id)
+channel_free(Channel *c)
{
- Channel *c = channel_lookup(id);
- char *s = channel_open_message();
+ char *s;
+ int i, n;
- if (c == NULL)
- packet_disconnect("channel free: bad local channel %d", id);
- debug("channel_free: channel %d: status: %s", id, s);
+ for (n = 0, i = 0; i < channels_alloc; i++)
+ if (channels[i])
+ n++;
+ debug("channel_free: channel %d: %s, nchannels %d", c->self,
+ c->remote_name ? c->remote_name : "???", n);
+
+ s = channel_open_message();
+ debug3("channel_free: status: %s", s);
xfree(s);
- if (c->dettach_user != NULL) {
- debug("channel_free: channel %d: dettaching channel user", id);
- c->dettach_user(c->self, NULL);
- }
if (c->sock != -1)
shutdown(c->sock, SHUT_RDWR);
channel_close_fds(c);
buffer_free(&c->input);
buffer_free(&c->output);
buffer_free(&c->extended);
- c->type = SSH_CHANNEL_FREE;
if (c->remote_name) {
xfree(c->remote_name);
c->remote_name = NULL;
}
+ channels[c->self] = NULL;
+ xfree(c);
+}
+
+void
+channel_free_all(void)
+{
+ int i;
+
+ for (i = 0; i < channels_alloc; i++)
+ if (channels[i] != NULL)
+ channel_free(channels[i]);
+}
+
+/*
+ * Closes the sockets/fds of all channels. This is used to close extra file
+ * descriptors after a fork.
+ */
+
+void
+channel_close_all(void)
+{
+ int i;
+
+ for (i = 0; i < channels_alloc; i++)
+ if (channels[i] != NULL)
+ channel_close_fds(channels[i]);
+}
+
+/*
+ * Stop listening to channels.
+ */
+
+void
+channel_stop_listening(void)
+{
+ int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL) {
+ switch (c->type) {
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_X11_LISTENER:
+ channel_close_fd(&c->sock);
+ channel_free(c);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Returns true if no channel has too much buffered data, and false if one or
+ * more channel is overfull.
+ */
+
+int
+channel_not_very_much_buffered_data(void)
+{
+ u_int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
+#if 0
+ if (!compat20 &&
+ buffer_len(&c->input) > packet_get_maxsize()) {
+ debug("channel %d: big input buffer %d",
+ c->self, buffer_len(&c->input));
+ return 0;
+ }
+#endif
+ if (buffer_len(&c->output) > packet_get_maxsize()) {
+ debug("channel %d: big output buffer %d > %d",
+ c->self, buffer_len(&c->output),
+ packet_get_maxsize());
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/* Returns true if any channel is still open. */
+
+int
+channel_still_open(void)
+{
+ int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c == NULL)
+ continue;
+ switch (c->type) {
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_CLOSED:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_CONNECTING:
+ case SSH_CHANNEL_ZOMBIE:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ if (!compat20)
+ fatal("cannot happen: SSH_CHANNEL_LARVAL");
+ continue;
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return 1;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return 1;
+ default:
+ fatal("channel_still_open: bad channel type %d", c->type);
+ /* NOTREACHED */
+ }
+ }
+ return 0;
+}
+
+/* Returns the id of an open channel suitable for keepaliving */
+
+int
+channel_find_open(void)
+{
+ int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c == NULL)
+ continue;
+ switch (c->type) {
+ case SSH_CHANNEL_CLOSED:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_CONNECTING:
+ case SSH_CHANNEL_ZOMBIE:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return i;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return i;
+ default:
+ fatal("channel_find_open: bad channel type %d", c->type);
+ /* NOTREACHED */
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * Returns a message describing the currently open forwarded connections,
+ * suitable for sending to the client. The message contains crlf pairs for
+ * newlines.
+ */
+
+char *
+channel_open_message(void)
+{
+ Buffer buffer;
+ Channel *c;
+ char buf[1024], *cp;
+ int i;
+
+ buffer_init(&buffer);
+ snprintf(buf, sizeof buf, "The following connections are open:\r\n");
+ buffer_append(&buffer, buf, strlen(buf));
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c == NULL)
+ continue;
+ switch (c->type) {
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_CLOSED:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_ZOMBIE:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_CONNECTING:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
+ c->self, c->remote_name,
+ c->type, c->remote_id,
+ c->istate, buffer_len(&c->input),
+ c->ostate, buffer_len(&c->output),
+ c->rfd, c->wfd);
+ buffer_append(&buffer, buf, strlen(buf));
+ continue;
+ default:
+ fatal("channel_open_message: bad channel type %d", c->type);
+ /* NOTREACHED */
+ }
+ }
+ buffer_append(&buffer, "\0", 1);
+ cp = xstrdup(buffer_ptr(&buffer));
+ buffer_free(&buffer);
+ return cp;
+}
+
+void
+channel_send_open(int id)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_send_open: %d: bad id", id);
+ return;
+ }
+ debug("send channel open %d", id);
+ packet_start(SSH2_MSG_CHANNEL_OPEN);
+ packet_put_cstring(c->ctype);
+ packet_put_int(c->self);
+ packet_put_int(c->local_window);
+ packet_put_int(c->local_maxpacket);
+ packet_send();
+}
+
+void
+channel_request_start(int local_id, char *service, int wantconfirm)
+{
+ Channel *c = channel_lookup(local_id);
+ if (c == NULL) {
+ log("channel_request_start: %d: unknown channel id", local_id);
+ return;
+ }
+ debug("channel request %d: %s", local_id, service) ;
+ packet_start(SSH2_MSG_CHANNEL_REQUEST);
+ packet_put_int(c->remote_id);
+ packet_put_cstring(service);
+ packet_put_char(wantconfirm);
+}
+void
+channel_register_confirm(int id, channel_callback_fn *fn)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_register_comfirm: %d: bad id", id);
+ return;
+ }
+ c->confirm = fn;
+}
+void
+channel_register_cleanup(int id, channel_callback_fn *fn)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_register_cleanup: %d: bad id", id);
+ return;
+ }
+ c->detach_user = fn;
+}
+void
+channel_cancel_cleanup(int id)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_cancel_cleanup: %d: bad id", id);
+ return;
+ }
+ c->detach_user = NULL;
+}
+void
+channel_register_filter(int id, channel_filter_fn *fn)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_register_filter: %d: bad id", id);
+ return;
+ }
+ c->input_filter = fn;
+}
+
+void
+channel_set_fds(int id, int rfd, int wfd, int efd,
+ int extusage, int nonblock, u_int window_max)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
+ fatal("channel_activate for non-larval channel %d.", id);
+ channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
+ c->type = SSH_CHANNEL_OPEN;
+ c->local_window = c->local_window_max = window_max;
+ packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->local_window);
+ packet_send();
}
/*
@@ -348,20 +671,20 @@ typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);
chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
-void
+static void
channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
FD_SET(c->sock, readset);
}
-void
+static void
channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset)
{
debug3("channel %d: waiting for connection", c->self);
FD_SET(c->sock, writeset);
}
-void
+static void
channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
{
if (buffer_len(&c->input) < packet_get_maxsize())
@@ -370,29 +693,14 @@ channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
FD_SET(c->sock, writeset);
}
-void
-channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
+static void
+channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset)
{
- /* test whether sockets are 'alive' for read/write */
- if (c->istate == CHAN_INPUT_OPEN)
- if (buffer_len(&c->input) < packet_get_maxsize())
- FD_SET(c->sock, readset);
- if (c->ostate == CHAN_OUTPUT_OPEN ||
- c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- if (buffer_len(&c->output) > 0) {
- FD_SET(c->sock, writeset);
- } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- chan_obuf_empty(c);
- }
- }
-}
+ u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
-void
-channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
-{
if (c->istate == CHAN_INPUT_OPEN &&
- c->remote_window > 0 &&
- buffer_len(&c->input) < c->remote_window)
+ limit > 0 &&
+ buffer_len(&c->input) < limit)
FD_SET(c->rfd, readset);
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
@@ -403,7 +711,7 @@ channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
}
}
/** XXX check close conditions, too */
- if (c->efd != -1) {
+ if (compat20 && c->efd != -1) {
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
buffer_len(&c->extended) > 0)
FD_SET(c->efd, writeset);
@@ -413,7 +721,7 @@ channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
}
}
-void
+static void
channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
{
if (buffer_len(&c->input) == 0) {
@@ -425,11 +733,11 @@ channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
}
}
-void
+static void
channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
{
if (buffer_len(&c->output) == 0)
- channel_free(c->self);
+ chan_mark_dead(c);
else
FD_SET(c->sock, writeset);
}
@@ -441,19 +749,20 @@ channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
* data in that packet is then substituted by the real data if it matches the
* fake data, and the channel is put into normal mode.
* XXX All this happens at the client side.
+ * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
*/
-int
-x11_open_helper(Channel *c)
+static int
+x11_open_helper(Buffer *b)
{
u_char *ucp;
u_int proto_len, data_len;
/* Check if the fixed size part of the packet is in buffer. */
- if (buffer_len(&c->output) < 12)
+ if (buffer_len(b) < 12)
return 0;
/* Parse the lengths of variable-length fields. */
- ucp = (u_char *) buffer_ptr(&c->output);
+ ucp = buffer_ptr(b);
if (ucp[0] == 0x42) { /* Byte order MSB first. */
proto_len = 256 * ucp[6] + ucp[7];
data_len = 256 * ucp[8] + ucp[9];
@@ -462,12 +771,12 @@ x11_open_helper(Channel *c)
data_len = ucp[8] + 256 * ucp[9];
} else {
debug("Initial X11 packet contains bad byte order byte: 0x%x",
- ucp[0]);
+ ucp[0]);
return -1;
}
/* Check if the whole packet is in buffer. */
- if (buffer_len(&c->output) <
+ if (buffer_len(b) <
12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
return 0;
@@ -500,10 +809,10 @@ x11_open_helper(Channel *c)
return 1;
}
-void
+static void
channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
{
- int ret = x11_open_helper(c);
+ int ret = x11_open_helper(&c->output);
if (ret == 1) {
/* Start normal processing for the channel. */
c->type = SSH_CHANNEL_OPEN;
@@ -516,7 +825,7 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
log("X11 connection rejected because of wrong authentication.");
buffer_clear(&c->input);
buffer_clear(&c->output);
- close(c->sock);
+ channel_close_fd(&c->sock);
c->sock = -1;
c->type = SSH_CHANNEL_CLOSED;
packet_start(SSH_MSG_CHANNEL_CLOSE);
@@ -525,31 +834,39 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
}
}
-void
+static void
channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
{
- int ret = x11_open_helper(c);
+ int ret = x11_open_helper(&c->output);
+
+ /* c->force_drain = 1; */
+
if (ret == 1) {
c->type = SSH_CHANNEL_OPEN;
- if (compat20)
- channel_pre_open_20(c, readset, writeset);
- else
- channel_pre_open_15(c, readset, writeset);
+ channel_pre_open(c, readset, writeset);
} else if (ret == -1) {
+ log("X11 connection rejected because of wrong authentication.");
debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
- chan_read_failed(c); /** force close? */
- chan_write_failed(c);
+ chan_read_failed(c);
+ buffer_clear(&c->input);
+ chan_ibuf_empty(c);
+ buffer_clear(&c->output);
+ /* for proto v1, the peer will send an IEOF */
+ if (compat20)
+ chan_write_failed(c);
+ else
+ c->type = SSH_CHANNEL_OPEN;
debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
}
}
/* try to decode a socks4 header */
-int
+static int
channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
{
u_char *p, *host;
int len, have, i, found;
- char username[256];
+ char username[256];
struct {
u_int8_t version;
u_int8_t command;
@@ -596,7 +913,7 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
host = inet_ntoa(s4_req.dest_addr);
strlcpy(c->path, host, sizeof(c->path));
c->host_port = ntohs(s4_req.dest_port);
-
+
debug("channel %d: dynamic request: socks4 host %s port %u command %u",
c->self, host, c->host_port, s4_req.command);
@@ -614,14 +931,14 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
}
/* dynamic port forwarding */
-void
+static void
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
{
u_char *p;
int have, ret;
have = buffer_len(&c->input);
-
+ c->delayed = 0;
debug2("channel %d: pre_dynamic: have %d", c->self, have);
/* buffer_dump(&c->input); */
/* check if the fixed size part of the packet is in buffer. */
@@ -641,7 +958,7 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
break;
}
if (ret < 0) {
- channel_free(c->self);
+ chan_mark_dead(c);
} else if (ret == 0) {
debug2("channel %d: pre_dynamic: need more", c->self);
/* need more */
@@ -654,11 +971,12 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
}
/* This is our fake X11 server socket. */
-void
+static void
channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
+ Channel *nc;
struct sockaddr addr;
- int newsock, newch;
+ int newsock;
socklen_t addrlen;
char buf[16384], *remote_ipaddr;
int remote_port;
@@ -667,25 +985,31 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
debug("X11 connection requested.");
addrlen = sizeof(addr);
newsock = accept(c->sock, &addr, &addrlen);
+ if (c->single_connection) {
+ debug("single_connection: closing X11 listener.");
+ channel_close_fd(&c->sock);
+ chan_mark_dead(c);
+ }
if (newsock < 0) {
error("accept: %.100s", strerror(errno));
return;
}
+ set_nodelay(newsock);
remote_ipaddr = get_peer_ipaddr(newsock);
remote_port = get_peer_port(newsock);
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
remote_ipaddr, remote_port);
- newch = channel_new("x11",
+ nc = channel_new("accepted x11 socket",
SSH_CHANNEL_OPENING, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket,
0, xstrdup(buf), 1);
if (compat20) {
packet_start(SSH2_MSG_CHANNEL_OPEN);
packet_put_cstring("x11");
- packet_put_int(newch);
- packet_put_int(c->local_window_max);
- packet_put_int(c->local_maxpacket);
+ packet_put_int(nc->self);
+ packet_put_int(nc->local_window_max);
+ packet_put_int(nc->local_maxpacket);
/* originator ipaddr and port */
packet_put_cstring(remote_ipaddr);
if (datafellows & SSH_BUG_X11FWD) {
@@ -696,16 +1020,17 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
packet_send();
} else {
packet_start(SSH_SMSG_X11_OPEN);
- packet_put_int(newch);
- if (have_hostname_in_open)
- packet_put_string(buf, strlen(buf));
+ packet_put_int(nc->self);
+ if (packet_get_protocol_flags() &
+ SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
+ packet_put_cstring(buf);
packet_send();
}
xfree(remote_ipaddr);
}
}
-void
+static void
port_open_helper(Channel *c, char *rtype)
{
int direct;
@@ -748,7 +1073,8 @@ port_open_helper(Channel *c, char *rtype)
packet_put_int(c->self);
packet_put_cstring(c->path);
packet_put_int(c->host_port);
- if (have_hostname_in_open)
+ if (packet_get_protocol_flags() &
+ SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
packet_put_cstring(c->remote_name);
packet_send();
}
@@ -758,12 +1084,12 @@ port_open_helper(Channel *c, char *rtype)
/*
* This socket is listening for connections to a forwarded TCP/IP port.
*/
-void
+static void
channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
Channel *nc;
struct sockaddr addr;
- int newsock, newch, nextstate;
+ int newsock, nextstate;
socklen_t addrlen;
char *rtype;
@@ -772,10 +1098,18 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
"to %.100s port %d requested.",
c->listening_port, c->path, c->host_port);
- rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
- "forwarded-tcpip" : "direct-tcpip";
- nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC :
- SSH_CHANNEL_OPENING;
+ if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "forwarded-tcpip";
+ } else {
+ if (c->host_port == 0) {
+ nextstate = SSH_CHANNEL_DYNAMIC;
+ rtype = "dynamic-tcpip";
+ } else {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "direct-tcpip";
+ }
+ }
addrlen = sizeof(addr);
newsock = accept(c->sock, &addr, &addrlen);
@@ -783,22 +1117,25 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
error("accept: %.100s", strerror(errno));
return;
}
- newch = channel_new(rtype,
+ set_nodelay(newsock);
+ nc = channel_new(rtype,
nextstate, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket,
0, xstrdup(rtype), 1);
-
- nc = channel_lookup(newch);
- if (nc == NULL) {
- error("xxx: no new channel:");
- return;
- }
nc->listening_port = c->listening_port;
nc->host_port = c->host_port;
strlcpy(nc->path, c->path, sizeof(nc->path));
- if (nextstate != SSH_CHANNEL_DYNAMIC)
+ if (nextstate == SSH_CHANNEL_DYNAMIC) {
+ /*
+ * do not call the channel_post handler until
+ * this flag has been reset by a pre-handler.
+ * otherwise the FD_ISSET calls might overflow
+ */
+ nc->delayed = 1;
+ } else {
port_open_helper(nc, rtype);
+ }
}
}
@@ -806,11 +1143,13 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
* This is the authentication agent socket listening for connections from
* clients.
*/
-void
+static void
channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
+ Channel *nc;
+ char *name;
+ int newsock;
struct sockaddr addr;
- int newsock, newch;
socklen_t addrlen;
if (FD_ISSET(c->sock, readset)) {
@@ -820,47 +1159,72 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
error("accept from auth socket: %.100s", strerror(errno));
return;
}
- newch = channel_new("accepted auth socket",
+ name = xstrdup("accepted auth socket");
+ nc = channel_new("accepted auth socket",
SSH_CHANNEL_OPENING, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket,
- 0, xstrdup("accepted auth socket"), 1);
+ 0, name, 1);
if (compat20) {
packet_start(SSH2_MSG_CHANNEL_OPEN);
packet_put_cstring("auth-agent@openssh.com");
- packet_put_int(newch);
+ packet_put_int(nc->self);
packet_put_int(c->local_window_max);
packet_put_int(c->local_maxpacket);
} else {
packet_start(SSH_SMSG_AGENT_OPEN);
- packet_put_int(newch);
+ packet_put_int(nc->self);
}
packet_send();
}
}
-void
+static void
channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset)
{
+ int err = 0;
+ socklen_t sz = sizeof(err);
+
if (FD_ISSET(c->sock, writeset)) {
- int err = 0;
- int sz = sizeof(err);
- c->type = SSH_CHANNEL_OPEN;
- if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) {
- debug("getsockopt SO_ERROR failed");
+ if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
+ err = errno;
+ error("getsockopt SO_ERROR failed");
+ }
+ if (err == 0) {
+ debug("channel %d: connected", c->self);
+ c->type = SSH_CHANNEL_OPEN;
+ if (compat20) {
+ packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->self);
+ packet_put_int(c->local_window);
+ packet_put_int(c->local_maxpacket);
+ } else {
+ packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->self);
+ }
} else {
- if (err == 0) {
- debug("channel %d: connected)", c->self);
+ debug("channel %d: not connected: %s",
+ c->self, strerror(err));
+ if (compat20) {
+ packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(c->remote_id);
+ packet_put_int(SSH2_OPEN_CONNECT_FAILED);
+ if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+ packet_put_cstring(strerror(err));
+ packet_put_cstring("");
+ }
} else {
- debug("channel %d: not connected: %s",
- c->self, strerror(err));
- chan_read_failed(c);
- chan_write_failed(c);
+ packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(c->remote_id);
}
+ chan_mark_dead(c);
}
+ packet_send();
}
}
-int
+static int
channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
{
char buf[16*1024];
@@ -876,18 +1240,18 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
c->self, c->rfd, len);
if (c->type != SSH_CHANNEL_OPEN) {
debug("channel %d: not open", c->self);
- channel_free(c->self);
+ chan_mark_dead(c);
return -1;
} else if (compat13) {
- buffer_consume(&c->output, buffer_len(&c->output));
+ buffer_clear(&c->output);
c->type = SSH_CHANNEL_INPUT_DRAINING;
- debug("channel %d: status set to input draining.", c->self);
+ debug("channel %d: input draining.", c->self);
} else {
chan_read_failed(c);
}
return -1;
}
- if(c->input_filter != NULL) {
+ if (c->input_filter != NULL) {
if (c->input_filter(c, buf, len) == -1) {
debug("channel %d: filter stops", c->self);
chan_read_failed(c);
@@ -898,35 +1262,38 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
}
return 1;
}
-int
+static int
channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
{
struct termios tio;
+ u_char *data;
+ u_int dlen;
int len;
/* Send buffered output data to the socket. */
if (c->wfd != -1 &&
FD_ISSET(c->wfd, writeset) &&
buffer_len(&c->output) > 0) {
- len = write(c->wfd, buffer_ptr(&c->output),
- buffer_len(&c->output));
+ data = buffer_ptr(&c->output);
+ dlen = buffer_len(&c->output);
+ len = write(c->wfd, data, dlen);
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 1;
if (len <= 0) {
if (c->type != SSH_CHANNEL_OPEN) {
debug("channel %d: not open", c->self);
- channel_free(c->self);
+ chan_mark_dead(c);
return -1;
} else if (compat13) {
- buffer_consume(&c->output, buffer_len(&c->output));
- debug("channel %d: status set to input draining.", c->self);
+ buffer_clear(&c->output);
+ debug("channel %d: input draining.", c->self);
c->type = SSH_CHANNEL_INPUT_DRAINING;
} else {
chan_write_failed(c);
}
return -1;
}
- if (compat20 && c->isatty) {
+ if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {
if (tcgetattr(c->wfd, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
@@ -946,7 +1313,7 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
}
return 1;
}
-int
+static int
channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
{
char buf[16*1024];
@@ -966,8 +1333,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
if (len <= 0) {
debug2("channel %d: closing write-efd %d",
c->self, c->efd);
- close(c->efd);
- c->efd = -1;
+ channel_close_fd(&c->efd);
} else {
buffer_consume(&c->extended, len);
c->local_consumed += len;
@@ -976,14 +1342,13 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
FD_ISSET(c->efd, readset)) {
len = read(c->efd, buf, sizeof(buf));
debug2("channel %d: read %d from efd %d",
- c->self, len, c->efd);
+ c->self, len, c->efd);
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 1;
if (len <= 0) {
debug2("channel %d: closing read-efd %d",
c->self, c->efd);
- close(c->efd);
- c->efd = -1;
+ channel_close_fd(&c->efd);
} else {
buffer_append(&c->extended, buf, len);
}
@@ -991,7 +1356,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
}
return 1;
}
-int
+static int
channel_check_window(Channel *c)
{
if (c->type == SSH_CHANNEL_OPEN &&
@@ -1011,24 +1376,20 @@ channel_check_window(Channel *c)
return 1;
}
-void
-channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
-{
- channel_handle_rfd(c, readset, writeset);
- channel_handle_wfd(c, readset, writeset);
-}
-
-void
-channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset)
+static void
+channel_post_open(Channel *c, fd_set * readset, fd_set * writeset)
{
+ if (c->delayed)
+ return;
channel_handle_rfd(c, readset, writeset);
channel_handle_wfd(c, readset, writeset);
+ if (!compat20)
+ return;
channel_handle_efd(c, readset, writeset);
-
channel_check_window(c);
}
-void
+static void
channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
{
int len;
@@ -1037,16 +1398,16 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
len = write(c->sock, buffer_ptr(&c->output),
buffer_len(&c->output));
if (len <= 0)
- buffer_consume(&c->output, buffer_len(&c->output));
+ buffer_clear(&c->output);
else
buffer_consume(&c->output, len);
}
}
-void
+static void
channel_handler_init_20(void)
{
- channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20;
+ channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
@@ -1055,16 +1416,16 @@ channel_handler_init_20(void)
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
- channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2;
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
}
-void
+static void
channel_handler_init_13(void)
{
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13;
@@ -1077,19 +1438,19 @@ channel_handler_init_13(void)
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
- channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1;
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
}
-void
+static void
channel_handler_init_15(void)
{
- channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15;
+ channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
@@ -1100,16 +1461,16 @@ channel_handler_init_15(void)
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
- channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1;
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
}
-void
+static void
channel_handler_init(void)
{
int i;
- for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
+ for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
channel_pre[i] = NULL;
channel_post[i] = NULL;
}
@@ -1121,7 +1482,29 @@ channel_handler_init(void)
channel_handler_init_15();
}
-void
+/* gc dead channels */
+static void
+channel_garbage_collect(Channel *c)
+{
+ if (c == NULL)
+ return;
+ if (c->detach_user != NULL) {
+ if (!chan_is_dead(c, 0))
+ return;
+ debug("channel %d: gc: notify user", c->self);
+ c->detach_user(c->self, NULL);
+ /* if we still have a callback */
+ if (c->detach_user != NULL)
+ return;
+ debug("channel %d: gc: user detached", c->self);
+ }
+ if (!chan_is_dead(c, 1))
+ return;
+ debug("channel %d: garbage collecting", c->self);
+ channel_free(c);
+}
+
+static void
channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
{
static int did_init = 0;
@@ -1133,36 +1516,22 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
did_init = 1;
}
for (i = 0; i < channels_alloc; i++) {
- c = &channels[i];
- if (c->type == SSH_CHANNEL_FREE)
+ c = channels[i];
+ if (c == NULL)
continue;
- if (ftab[c->type] == NULL)
- continue;
- (*ftab[c->type])(c, readset, writeset);
- if (chan_is_dead(c)) {
- /*
- * we have to remove the fd's from the select mask
- * before the channels are free'd and the fd's are
- * closed
- */
- if (c->wfd != -1)
- FD_CLR(c->wfd, writeset);
- if (c->rfd != -1)
- FD_CLR(c->rfd, readset);
- if (c->efd != -1) {
- if (c->extended_usage == CHAN_EXTENDED_READ)
- FD_CLR(c->efd, readset);
- if (c->extended_usage == CHAN_EXTENDED_WRITE)
- FD_CLR(c->efd, writeset);
- }
- channel_free(c->self);
- }
+ if (ftab[c->type] != NULL)
+ (*ftab[c->type])(c, readset, writeset);
+ channel_garbage_collect(c);
}
}
+/*
+ * Allocate/update select bitmasks and add any bits relevant to channels in
+ * select bitmasks.
+ */
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- int rekeying)
+ int *nallocp, int rekeying)
{
int n;
u_int sz;
@@ -1170,15 +1539,13 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
n = MAX(*maxfdp, channel_max_fd);
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
- if (*readsetp == NULL || n > *maxfdp) {
- if (*readsetp)
- xfree(*readsetp);
- if (*writesetp)
- xfree(*writesetp);
- *readsetp = xmalloc(sz);
- *writesetp = xmalloc(sz);
- *maxfdp = n;
+ /* perhaps check sz < nalloc/2 and shrink? */
+ if (*readsetp == NULL || sz > *nallocp) {
+ *readsetp = xrealloc(*readsetp, sz);
+ *writesetp = xrealloc(*writesetp, sz);
+ *nallocp = sz;
}
+ *maxfdp = n;
memset(*readsetp, 0, sz);
memset(*writesetp, 0, sz);
@@ -1186,24 +1553,34 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
channel_handler(channel_pre, *readsetp, *writesetp);
}
+/*
+ * After select, perform any appropriate operations for channels which have
+ * events pending.
+ */
void
channel_after_select(fd_set * readset, fd_set * writeset)
{
channel_handler(channel_post, readset, writeset);
}
+
/* If there is data to send to the connection, enqueue some of it now. */
void
-channel_output_poll()
+channel_output_poll(void)
{
int len, i;
Channel *c;
for (i = 0; i < channels_alloc; i++) {
- c = &channels[i];
+ c = channels[i];
+ if (c == NULL)
+ continue;
- /* We are only interested in channels that can have buffered incoming data. */
+ /*
+ * We are only interested in channels that can have buffered
+ * incoming data.
+ */
if (compat13) {
if (c->type != SSH_CHANNEL_OPEN &&
c->type != SSH_CHANNEL_INPUT_DRAINING)
@@ -1215,7 +1592,7 @@ channel_output_poll()
if (compat20 &&
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
/* XXX is this true? */
- debug2("channel %d: no data after CLOSE", c->self);
+ debug3("channel %d: will not send data after close", c->self);
continue;
}
@@ -1223,7 +1600,10 @@ channel_output_poll()
if ((c->istate == CHAN_INPUT_OPEN ||
c->istate == CHAN_INPUT_WAIT_DRAIN) &&
(len = buffer_len(&c->input)) > 0) {
- /* Send some data for the other side over the secure connection. */
+ /*
+ * Send some data for the other side over the secure
+ * connection.
+ */
if (compat20) {
if (len > c->remote_window)
len = c->remote_window;
@@ -1281,14 +1661,11 @@ channel_output_poll()
}
}
-/*
- * 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 is
- * still there.
- */
+
+/* -- protocol input */
void
-channel_input_data(int type, int plen, void *ctxt)
+channel_input_data(int type, u_int32_t seq, void *ctxt)
{
int id;
char *data;
@@ -1312,9 +1689,8 @@ channel_input_data(int type, int plen, void *ctxt)
/* Get the data. */
data = packet_get_string(&data_len);
- packet_done();
- if (compat20){
+ if (compat20) {
if (data_len > c->local_maxpacket) {
log("channel %d: rcvd big packet %d, maxpack %d",
c->self, data_len, c->local_maxpacket);
@@ -1326,14 +1702,14 @@ channel_input_data(int type, int plen, void *ctxt)
return;
}
c->local_window -= data_len;
- }else{
- packet_integrity_check(plen, 4 + 4 + data_len, type);
}
+ packet_check_eom();
buffer_append(&c->output, data, data_len);
xfree(data);
}
+
void
-channel_input_extended_data(int type, int plen, void *ctxt)
+channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
{
int id;
int tcode;
@@ -1359,7 +1735,7 @@ channel_input_extended_data(int type, int plen, void *ctxt)
return;
}
data = packet_get_string(&data_len);
- packet_done();
+ packet_check_eom();
if (data_len > c->local_window) {
log("channel %d: rcvd too much extended_data %d, win %d",
c->self, data_len, c->local_window);
@@ -1372,60 +1748,37 @@ channel_input_extended_data(int type, int plen, void *ctxt)
xfree(data);
}
-
-/*
- * Returns true if no channel has too much buffered data, and false if one or
- * more channel is overfull.
- */
-
-int
-channel_not_very_much_buffered_data()
-{
- u_int i;
- Channel *c;
-
- for (i = 0; i < channels_alloc; i++) {
- c = &channels[i];
- if (c->type == SSH_CHANNEL_OPEN) {
- if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
- debug("channel %d: big input buffer %d",
- c->self, buffer_len(&c->input));
- return 0;
- }
- if (buffer_len(&c->output) > packet_get_maxsize()) {
- debug("channel %d: big output buffer %d",
- c->self, buffer_len(&c->output));
- return 0;
- }
- }
- }
- return 1;
-}
-
void
-channel_input_ieof(int type, int plen, void *ctxt)
+channel_input_ieof(int type, u_int32_t seq, void *ctxt)
{
int id;
Channel *c;
- packet_integrity_check(plen, 4, type);
-
id = packet_get_int();
+ packet_check_eom();
c = channel_lookup(id);
if (c == NULL)
packet_disconnect("Received ieof for nonexistent channel %d.", id);
chan_rcvd_ieof(c);
+
+ /* XXX force input close */
+ if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
+ debug("channel %d: FORCE input drain", c->self);
+ c->istate = CHAN_INPUT_WAIT_DRAIN;
+ if (buffer_len(&c->input) == 0)
+ chan_ibuf_empty(c);
+ }
+
}
void
-channel_input_close(int type, int plen, void *ctxt)
+channel_input_close(int type, u_int32_t seq, void *ctxt)
{
int id;
Channel *c;
- packet_integrity_check(plen, 4, type);
-
id = packet_get_int();
+ packet_check_eom();
c = channel_lookup(id);
if (c == NULL)
packet_disconnect("Received close for nonexistent channel %d.", id);
@@ -1450,48 +1803,46 @@ channel_input_close(int type, int plen, void *ctxt)
* Not a closed channel - mark it as draining, which will
* cause it to be freed later.
*/
- buffer_consume(&c->input, buffer_len(&c->input));
+ buffer_clear(&c->input);
c->type = SSH_CHANNEL_OUTPUT_DRAINING;
}
}
/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
void
-channel_input_oclose(int type, int plen, void *ctxt)
+channel_input_oclose(int type, u_int32_t seq, void *ctxt)
{
int id = packet_get_int();
Channel *c = channel_lookup(id);
- packet_integrity_check(plen, 4, type);
+
+ packet_check_eom();
if (c == NULL)
packet_disconnect("Received oclose for nonexistent channel %d.", id);
chan_rcvd_oclose(c);
}
void
-channel_input_close_confirmation(int type, int plen, void *ctxt)
+channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
{
int id = packet_get_int();
Channel *c = channel_lookup(id);
- packet_done();
+ packet_check_eom();
if (c == NULL)
packet_disconnect("Received close confirmation for "
"out-of-range channel %d.", id);
if (c->type != SSH_CHANNEL_CLOSED)
packet_disconnect("Received close confirmation for "
"non-closed channel %d (type %d).", id, c->type);
- channel_free(c->self);
+ channel_free(c);
}
void
-channel_input_open_confirmation(int type, int plen, void *ctxt)
+channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
{
int id, remote_id;
Channel *c;
- if (!compat20)
- packet_integrity_check(plen, 4 + 4, type);
-
id = packet_get_int();
c = channel_lookup(id);
@@ -1506,27 +1857,40 @@ channel_input_open_confirmation(int type, int plen, void *ctxt)
if (compat20) {
c->remote_window = packet_get_int();
c->remote_maxpacket = packet_get_int();
- packet_done();
- if (c->cb_fn != NULL && c->cb_event == type) {
+ if (c->confirm) {
debug2("callback start");
- c->cb_fn(c->self, c->cb_arg);
+ c->confirm(c->self, NULL);
debug2("callback done");
}
debug("channel %d: open confirm rwindow %d rmax %d", c->self,
c->remote_window, c->remote_maxpacket);
}
+ packet_check_eom();
+}
+
+static char *
+reason2txt(int reason)
+{
+ switch (reason) {
+ case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
+ return "administratively prohibited";
+ case SSH2_OPEN_CONNECT_FAILED:
+ return "connect failed";
+ case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
+ return "unknown channel type";
+ case SSH2_OPEN_RESOURCE_SHORTAGE:
+ return "resource shortage";
+ }
+ return "unknown reason";
}
void
-channel_input_open_failure(int type, int plen, void *ctxt)
+channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
{
int id, reason;
char *msg = NULL, *lang = NULL;
Channel *c;
- if (!compat20)
- packet_integrity_check(plen, 4, type);
-
id = packet_get_int();
c = channel_lookup(id);
@@ -1535,49 +1899,24 @@ channel_input_open_failure(int type, int plen, void *ctxt)
"non-opening channel %d.", id);
if (compat20) {
reason = packet_get_int();
- if (packet_remaining() > 0) {
+ if (!(datafellows & SSH_BUG_OPENFAILURE)) {
msg = packet_get_string(NULL);
lang = packet_get_string(NULL);
}
- packet_done();
- log("channel_open_failure: %d: reason %d %s", id,
- reason, msg ? msg : "<no additional info>");
+ log("channel %d: open failed: %s%s%s", id,
+ reason2txt(reason), msg ? ": ": "", msg ? msg : "");
if (msg != NULL)
xfree(msg);
if (lang != NULL)
xfree(lang);
}
+ packet_check_eom();
/* Free the channel. This will also close the socket. */
- channel_free(id);
-}
-
-void
-channel_input_channel_request(int type, int plen, void *ctxt)
-{
- int id;
- Channel *c;
-
- id = packet_get_int();
- c = channel_lookup(id);
-
- if (c == NULL ||
- (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
- packet_disconnect("Received request for "
- "non-open channel %d.", id);
- if (c->cb_fn != NULL && c->cb_event == type) {
- debug2("callback start");
- c->cb_fn(c->self, c->cb_arg);
- debug2("callback done");
- } else {
- char *service = packet_get_string(NULL);
- debug("channel %d: rcvd request for %s", c->self, service);
- debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
- xfree(service);
- }
+ channel_free(c);
}
void
-channel_input_window_adjust(int type, int plen, void *ctxt)
+channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
{
Channel *c;
int id, adjust;
@@ -1595,224 +1934,77 @@ channel_input_window_adjust(int type, int plen, void *ctxt)
return;
}
adjust = packet_get_int();
- packet_done();
+ packet_check_eom();
debug2("channel %d: rcvd adjust %d", id, adjust);
c->remote_window += adjust;
}
-/*
- * Stops listening for channels, and removes any unix domain sockets that we
- * might have.
- */
-
-void
-channel_stop_listening()
-{
- int i;
- for (i = 0; i < channels_alloc; i++) {
- switch (channels[i].type) {
- case SSH_CHANNEL_AUTH_SOCKET:
- close(channels[i].sock);
- /* auth_sock_cleanup_proc deletes the socket */
- channel_free(i);
- break;
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_RPORT_LISTENER:
- case SSH_CHANNEL_X11_LISTENER:
- close(channels[i].sock);
- channel_free(i);
- break;
- default:
- break;
- }
- }
-}
-
-/*
- * Closes the sockets/fds of all channels. This is used to close extra file
- * descriptors after a fork.
- */
-
void
-channel_close_all()
-{
- int i;
- for (i = 0; i < channels_alloc; i++)
- if (channels[i].type != SSH_CHANNEL_FREE)
- channel_close_fds(&channels[i]);
-}
-
-/* Returns true if any channel is still open. */
-
-int
-channel_still_open()
+channel_input_port_open(int type, u_int32_t seq, void *ctxt)
{
- u_int i;
- for (i = 0; i < channels_alloc; i++)
- switch (channels[i].type) {
- case SSH_CHANNEL_FREE:
- case SSH_CHANNEL_X11_LISTENER:
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_RPORT_LISTENER:
- case SSH_CHANNEL_CLOSED:
- case SSH_CHANNEL_AUTH_SOCKET:
- case SSH_CHANNEL_DYNAMIC:
- case SSH_CHANNEL_CONNECTING: /* XXX ??? */
- continue;
- case SSH_CHANNEL_LARVAL:
- if (!compat20)
- fatal("cannot happen: SSH_CHANNEL_LARVAL");
- continue;
- case SSH_CHANNEL_OPENING:
- case SSH_CHANNEL_OPEN:
- case SSH_CHANNEL_X11_OPEN:
- return 1;
- case SSH_CHANNEL_INPUT_DRAINING:
- case SSH_CHANNEL_OUTPUT_DRAINING:
- if (!compat13)
- fatal("cannot happen: OUT_DRAIN");
- return 1;
- default:
- fatal("channel_still_open: bad channel type %d", channels[i].type);
- /* NOTREACHED */
- }
- return 0;
-}
+ Channel *c = NULL;
+ u_short host_port;
+ char *host, *originator_string;
+ int remote_id, sock = -1;
-/* Returns the id of an open channel suitable for keepaliving */
+ remote_id = packet_get_int();
+ host = packet_get_string(NULL);
+ host_port = packet_get_int();
-int
-channel_find_open()
-{
- u_int i;
- for (i = 0; i < channels_alloc; i++)
- switch (channels[i].type) {
- case SSH_CHANNEL_CLOSED:
- case SSH_CHANNEL_DYNAMIC:
- case SSH_CHANNEL_FREE:
- case SSH_CHANNEL_X11_LISTENER:
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_RPORT_LISTENER:
- case SSH_CHANNEL_OPENING:
- continue;
- case SSH_CHANNEL_LARVAL:
- case SSH_CHANNEL_AUTH_SOCKET:
- case SSH_CHANNEL_CONNECTING: /* XXX ??? */
- case SSH_CHANNEL_OPEN:
- case SSH_CHANNEL_X11_OPEN:
- return i;
- case SSH_CHANNEL_INPUT_DRAINING:
- case SSH_CHANNEL_OUTPUT_DRAINING:
- if (!compat13)
- fatal("cannot happen: OUT_DRAIN");
- return i;
- default:
- fatal("channel_find_open: bad channel type %d", channels[i].type);
- /* NOTREACHED */
- }
- return -1;
+ if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
+ originator_string = packet_get_string(NULL);
+ } else {
+ originator_string = xstrdup("unknown (remote did not supply name)");
+ }
+ packet_check_eom();
+ sock = channel_connect_to(host, host_port);
+ if (sock != -1) {
+ c = channel_new("connected socket",
+ SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
+ originator_string, 1);
+ c->remote_id = remote_id;
+ }
+ if (c == NULL) {
+ packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(remote_id);
+ packet_send();
+ }
+ xfree(host);
}
-/*
- * Returns a message describing the currently open forwarded connections,
- * suitable for sending to the client. The message contains crlf pairs for
- * newlines.
- */
-
-char *
-channel_open_message()
-{
- Buffer buffer;
- int i;
- char buf[512], *cp;
-
- buffer_init(&buffer);
- snprintf(buf, sizeof buf, "The following connections are open:\r\n");
- buffer_append(&buffer, buf, strlen(buf));
- for (i = 0; i < channels_alloc; i++) {
- Channel *c = &channels[i];
- switch (c->type) {
- case SSH_CHANNEL_FREE:
- case SSH_CHANNEL_X11_LISTENER:
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_RPORT_LISTENER:
- case SSH_CHANNEL_CLOSED:
- case SSH_CHANNEL_AUTH_SOCKET:
- continue;
- case SSH_CHANNEL_LARVAL:
- case SSH_CHANNEL_OPENING:
- case SSH_CHANNEL_CONNECTING:
- case SSH_CHANNEL_DYNAMIC:
- case SSH_CHANNEL_OPEN:
- case SSH_CHANNEL_X11_OPEN:
- case SSH_CHANNEL_INPUT_DRAINING:
- case SSH_CHANNEL_OUTPUT_DRAINING:
- snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
- c->self, c->remote_name,
- c->type, c->remote_id,
- c->istate, buffer_len(&c->input),
- c->ostate, buffer_len(&c->output),
- c->rfd, c->wfd);
- buffer_append(&buffer, buf, strlen(buf));
- continue;
- default:
- fatal("channel_open_message: bad channel type %d", c->type);
- /* NOTREACHED */
- }
- }
- buffer_append(&buffer, "\0", 1);
- cp = xstrdup(buffer_ptr(&buffer));
- buffer_free(&buffer);
- return cp;
-}
+/* -- tcp forwarding */
-/*
- * Initiate forwarding of connections to local port "port" through the secure
- * channel to host:port from remote side.
- */
-int
-channel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
- u_short port_to_connect, int gateway_ports)
+void
+channel_set_af(int af)
{
- return channel_request_forwarding(
- NULL, listen_port,
- host_to_connect, port_to_connect,
- gateway_ports, /*remote_fwd*/ 0);
+ IPv4or6 = af;
}
-/*
- * If 'remote_fwd' is true we have a '-R style' listener for protocol 2
- * (SSH_CHANNEL_RPORT_LISTENER).
- */
-int
-channel_request_forwarding(
- const char *listen_address, u_short listen_port,
- const char *host_to_connect, u_short port_to_connect,
- int gateway_ports, int remote_fwd)
+static int
+channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port,
+ const char *host_to_connect, u_short port_to_connect, int gateway_ports)
{
- int success, ch, sock, on = 1, ctype;
+ Channel *c;
+ int success, sock, on = 1;
struct addrinfo hints, *ai, *aitop;
- char ntop[NI_MAXHOST], strport[NI_MAXSERV];
const char *host;
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV];
struct linger linger;
success = 0;
+ host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
+ listen_addr : host_to_connect;
- if (remote_fwd) {
- host = listen_address;
- ctype = SSH_CHANNEL_RPORT_LISTENER;
- } else {
- host = host_to_connect;
- ctype =SSH_CHANNEL_PORT_LISTENER;
+ if (host == NULL) {
+ error("No forward host name.");
+ return success;
}
-
- if (strlen(host) > sizeof(channels[0].path) - 1) {
+ if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
error("Forward host name too long.");
return success;
}
- /* XXX listen_address is currently ignored */
/*
* getaddrinfo returns a loopback address if the hostname is
* set to NULL and hints.ai_flags is not AI_PASSIVE
@@ -1830,7 +2022,7 @@ channel_request_forwarding(
continue;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- error("channel_request_forwarding: getnameinfo failed");
+ error("channel_setup_fwd_listener: getnameinfo failed");
continue;
}
/* Create a port to listen for the host. */
@@ -1844,10 +2036,10 @@ channel_request_forwarding(
* 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));
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
linger.l_onoff = 1;
linger.l_linger = 5;
- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
debug("Local forwarding listening on %s port %s.", ntop, strport);
/* Bind the socket to the address. */
@@ -1864,21 +2056,39 @@ channel_request_forwarding(
continue;
}
/* Allocate a channel number for the socket. */
- ch = channel_new("port listener", ctype, sock, sock, -1,
+ c = channel_new("port listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, xstrdup("port listener"), 1);
- strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
- channels[ch].host_port = port_to_connect;
- channels[ch].listening_port = listen_port;
+ strlcpy(c->path, host, sizeof(c->path));
+ c->host_port = port_to_connect;
+ c->listening_port = listen_port;
success = 1;
}
if (success == 0)
- error("channel_request_forwarding: cannot listen to port: %d",
+ error("channel_setup_fwd_listener: cannot listen to port: %d",
listen_port);
freeaddrinfo(aitop);
return success;
}
+/* protocol local port fwd, used by ssh (and sshd in v1) */
+int
+channel_setup_local_fwd_listener(u_short listen_port,
+ const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+{
+ return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
+ NULL, listen_port, host_to_connect, port_to_connect, gateway_ports);
+}
+
+/* protocol v2 remote port fwd, used by sshd */
+int
+channel_setup_remote_fwd_listener(const char *listen_address,
+ u_short listen_port, int gateway_ports)
+{
+ return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
+ listen_address, listen_port, NULL, 0, gateway_ports);
+}
+
/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side.
@@ -1888,7 +2098,7 @@ void
channel_request_remote_forwarding(u_short listen_port,
const char *host_to_connect, u_short port_to_connect)
{
- int payload_len, type, success = 0;
+ int type, success = 0;
/* Record locally that connection to this host/port is permitted. */
if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
@@ -1915,7 +2125,7 @@ channel_request_remote_forwarding(u_short listen_port,
packet_write_wait();
/* Wait for response from the remote side. */
- type = packet_read(&payload_len);
+ type = packet_read();
switch (type) {
case SSH_SMSG_SUCCESS:
success = 1;
@@ -1962,7 +2172,7 @@ channel_input_port_forward_request(int is_root, int gateway_ports)
packet_disconnect("Requested forwarding of port %d but user is not root.",
port);
/* Initiate forwarding */
- channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
+ channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports);
/* Free the argument string. */
xfree(hostname);
@@ -1974,7 +2184,7 @@ channel_input_port_forward_request(int is_root, int gateway_ports)
* anyway, and the server has no way to know but to trust the client anyway.
*/
void
-channel_permit_all_opens()
+channel_permit_all_opens(void)
{
if (num_permitted_opens == 0)
all_opens_permitted = 1;
@@ -2007,7 +2217,7 @@ channel_clear_permitted_opens(void)
/* return socket to remote host, port */
-int
+static int
connect_to(const char *host, u_short port)
{
struct addrinfo hints, *ai, *aitop;
@@ -2055,11 +2265,12 @@ connect_to(const char *host, u_short port)
return -1;
}
/* success */
+ set_nodelay(sock);
return sock;
}
int
-channel_connect_by_listen_adress(u_short listen_port)
+channel_connect_by_listen_address(u_short listen_port)
{
int i;
@@ -2095,79 +2306,36 @@ channel_connect_to(const char *host, u_short port)
return connect_to(host, port);
}
-/*
- * This is called after receiving PORT_OPEN message. This attempts to
- * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
- * or CHANNEL_OPEN_FAILURE.
- */
-
-void
-channel_input_port_open(int type, int plen, void *ctxt)
-{
- u_short host_port;
- char *host, *originator_string;
- int remote_channel, sock = -1, newch;
-
- remote_channel = packet_get_int();
- host = packet_get_string(NULL);
- host_port = packet_get_int();
-
- if (have_hostname_in_open) {
- originator_string = packet_get_string(NULL);
- } else {
- originator_string = xstrdup("unknown (remote did not supply name)");
- }
- packet_done();
- sock = channel_connect_to(host, host_port);
- if (sock != -1) {
- newch = channel_allocate(SSH_CHANNEL_CONNECTING,
- sock, originator_string);
- channels[newch].remote_id = remote_channel;
-
- /*XXX delay answer? */
- packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(remote_channel);
- packet_put_int(newch);
- packet_send();
- } else {
- packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(remote_channel);
- packet_send();
- }
- xfree(host);
-}
+/* -- X11 forwarding */
/*
* Creates an internet domain socket for listening for X11 connections.
- * Returns a suitable value for the DISPLAY variable, or NULL if an error
- * occurs.
+ * Returns a suitable display number for the DISPLAY variable, or -1 if
+ * an error occurs.
*/
-
-#define NUM_SOCKS 10
-
-char *
-x11_create_display_inet(int screen_number, int x11_display_offset)
+int
+x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
+ int single_connection)
{
+ Channel *nc = NULL;
int display_number, sock;
u_short port;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
- char display[512];
- char hostname[MAXHOSTNAMELEN];
for (display_number = x11_display_offset;
- display_number < MAX_DISPLAYS;
- display_number++) {
+ display_number < MAX_DISPLAYS;
+ display_number++) {
port = 6000 + display_number;
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
- hints.ai_flags = AI_PASSIVE; /* XXX loopback only ? */
+ hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
error("getaddrinfo: %.100s", gai_strerror(gaierr));
- return NULL;
+ return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@@ -2175,14 +2343,12 @@ x11_create_display_inet(int screen_number, int x11_display_offset)
sock = socket(ai->ai_family, SOCK_STREAM, 0);
if (sock < 0) {
error("socket: %.100s", strerror(errno));
- return NULL;
+ return -1;
}
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
debug("bind port %d: %.100s", port, strerror(errno));
- shutdown(sock, SHUT_RDWR);
close(sock);
for (n = 0; n < num_socks; n++) {
- shutdown(socks[n], SHUT_RDWR);
close(socks[n]);
}
num_socks = 0;
@@ -2198,67 +2364,47 @@ x11_create_display_inet(int screen_number, int x11_display_offset)
}
if (display_number >= MAX_DISPLAYS) {
error("Failed to allocate internet-domain X11 display socket.");
- return NULL;
+ return -1;
}
/* Start listening for connections on the socket. */
for (n = 0; n < num_socks; n++) {
sock = socks[n];
if (listen(sock, 5) < 0) {
error("listen: %.100s", strerror(errno));
- shutdown(sock, SHUT_RDWR);
close(sock);
- return NULL;
+ return -1;
}
}
- /* Set up a suitable value for the DISPLAY variable. */
- if (gethostname(hostname, sizeof(hostname)) < 0)
- fatal("gethostname: %.100s", strerror(errno));
- snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
- display_number, screen_number);
-
/* Allocate a channel for each socket. */
for (n = 0; n < num_socks; n++) {
sock = socks[n];
- (void) channel_new("x11 listener",
+ nc = channel_new("x11 listener",
SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, xstrdup("X11 inet listener"), 1);
+ nc->single_connection = single_connection;
}
- /* Return a suitable value for the DISPLAY environment variable. */
- return xstrdup(display);
+ /* Return the display number for the DISPLAY environment variable. */
+ return display_number;
}
-#ifndef X_UNIX_PATH
-#define X_UNIX_PATH "/tmp/.X11-unix/X"
-#endif
-
-static
-int
+static int
connect_local_xsocket(u_int dnr)
{
- static const char *const x_sockets[] = {
- X_UNIX_PATH "%u",
- "/var/X/.X11-unix/X" "%u",
- "/usr/spool/sockets/X11/" "%u",
- NULL
- };
int sock;
struct sockaddr_un addr;
- const char *const * path;
- for (path = x_sockets; *path; ++path) {
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- error("socket: %.100s", strerror(errno));
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);
- if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
- return sock;
- close(sock);
- }
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ error("socket: %.100s", strerror(errno));
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr);
+ if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
+ return sock;
+ close(sock);
error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
return -1;
}
@@ -2293,7 +2439,7 @@ x11_connect_display(void)
/* Connect to the unix domain socket. */
if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
- display);
+ display);
return -1;
}
/* Create a socket. */
@@ -2308,8 +2454,7 @@ x11_connect_display(void)
* 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));
- buf[sizeof(buf) - 1] = 0;
+ strlcpy(buf, display, sizeof(buf));
cp = strchr(buf, ':');
if (!cp) {
error("Could not find ':' in DISPLAY: %.100s", display);
@@ -2319,7 +2464,7 @@ x11_connect_display(void)
/* buf now contains the host name. But first we parse the display number. */
if (sscanf(cp + 1, "%d", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
- display);
+ display);
return -1;
}
@@ -2355,6 +2500,7 @@ x11_connect_display(void)
strerror(errno));
return -1;
}
+ set_nodelay(sock);
return sock;
}
@@ -2365,56 +2511,52 @@ x11_connect_display(void)
*/
void
-x11_input_open(int type, int plen, void *ctxt)
+x11_input_open(int type, u_int32_t seq, void *ctxt)
{
- int remote_channel, sock = 0, newch;
+ Channel *c = NULL;
+ int remote_id, sock = 0;
char *remote_host;
- u_int remote_len;
- /* Get remote channel number. */
- remote_channel = packet_get_int();
+ debug("Received X11 open request.");
+
+ remote_id = packet_get_int();
- /* Get remote originator name. */
- if (have_hostname_in_open) {
- remote_host = packet_get_string(&remote_len);
- remote_len += 4;
+ if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
+ remote_host = packet_get_string(NULL);
} else {
remote_host = xstrdup("unknown (remote did not supply name)");
- remote_len = 0;
}
-
- debug("Received X11 open request.");
- packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN);
+ packet_check_eom();
/* Obtain a connection to the real X display. */
sock = x11_connect_display();
- if (sock == -1) {
+ if (sock != -1) {
+ /* Allocate a channel for this connection. */
+ c = channel_new("connected x11 socket",
+ SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
+ remote_host, 1);
+ c->remote_id = remote_id;
+ c->force_drain = 1;
+ }
+ if (c == NULL) {
/* Send refusal to the remote host. */
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(remote_channel);
- packet_send();
+ packet_put_int(remote_id);
} else {
- /* Allocate a channel for this connection. */
- newch = channel_allocate(
- (x11_saved_proto == NULL) ?
- SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN,
- sock, remote_host);
- channels[newch].remote_id = remote_channel;
-
/* Send a confirmation to the remote host. */
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(remote_channel);
- packet_put_int(newch);
- packet_send();
+ packet_put_int(remote_id);
+ packet_put_int(c->self);
}
+ packet_send();
}
/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
void
-deny_input_open(int type, int plen, void *ctxt)
+deny_input_open(int type, u_int32_t seq, void *ctxt)
{
int rchan = packet_get_int();
- switch(type){
+ switch (type) {
case SSH_SMSG_AGENT_OPEN:
error("Warning: ssh server tried agent forwarding.");
break;
@@ -2422,7 +2564,7 @@ deny_input_open(int type, int plen, void *ctxt)
error("Warning: ssh server tried X11 forwarding.");
break;
default:
- error("deny_input_open: type %d plen %d", type, plen);
+ error("deny_input_open: type %d", type);
break;
}
error("Warning: this is probably a break in attempt by a malicious server.");
@@ -2434,8 +2576,8 @@ deny_input_open(int type, int plen, void *ctxt)
/*
* Requests forwarding of X11 connections, generates fake authentication
* data, and enables authentication spoofing.
+ * This should be called in the client only.
*/
-
void
x11_request_forwarding_with_spoofing(int client_session_id,
const char *proto, const char *data)
@@ -2500,10 +2642,13 @@ x11_request_forwarding_with_spoofing(int client_session_id,
xfree(new_data);
}
+
+/* -- agent forwarding */
+
/* Sends a message to the server to request authentication fd forwarding. */
void
-auth_request_forwarding()
+auth_request_forwarding(void)
{
packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
packet_send();
@@ -2517,9 +2662,9 @@ auth_request_forwarding()
*/
char *
-auth_get_socket_name()
+auth_get_socket_name(void)
{
- return channel_forwarded_auth_socket_name;
+ return auth_sock_name;
}
/* removes the agent forwarding socket */
@@ -2529,11 +2674,11 @@ auth_sock_cleanup_proc(void *_pw)
{
struct passwd *pw = _pw;
- if (channel_forwarded_auth_socket_name) {
+ if (auth_sock_name) {
temporarily_use_uid(pw);
- unlink(channel_forwarded_auth_socket_name);
- rmdir(channel_forwarded_auth_socket_dir);
- channel_forwarded_auth_socket_name = NULL;
+ unlink(auth_sock_name);
+ rmdir(auth_sock_dir);
+ auth_sock_name = NULL;
restore_uid();
}
}
@@ -2546,33 +2691,36 @@ auth_sock_cleanup_proc(void *_pw)
int
auth_input_request_forwarding(struct passwd * pw)
{
- int sock, newch;
+ Channel *nc;
+ int sock;
struct sockaddr_un sunaddr;
- if (auth_get_socket_name() != NULL)
- fatal("Protocol error: authentication forwarding requested twice.");
+ if (auth_get_socket_name() != NULL) {
+ error("authentication forwarding requested twice.");
+ return 0;
+ }
/* Temporarily drop privileged uid for mkdir/bind. */
temporarily_use_uid(pw);
/* Allocate a buffer for the socket name, and format the name. */
- channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);
- channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME);
- strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);
+ auth_sock_name = xmalloc(MAXPATHLEN);
+ auth_sock_dir = xmalloc(MAXPATHLEN);
+ strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
/* Create private directory for socket */
- if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) {
- packet_send_debug("Agent forwarding disabled: mkdtemp() failed: %.100s",
- strerror(errno));
+ if (mkdtemp(auth_sock_dir) == NULL) {
+ packet_send_debug("Agent forwarding disabled: "
+ "mkdtemp() failed: %.100s", strerror(errno));
restore_uid();
- xfree(channel_forwarded_auth_socket_name);
- xfree(channel_forwarded_auth_socket_dir);
- channel_forwarded_auth_socket_name = NULL;
- channel_forwarded_auth_socket_dir = NULL;
+ xfree(auth_sock_name);
+ xfree(auth_sock_dir);
+ auth_sock_name = NULL;
+ auth_sock_dir = NULL;
return 0;
}
- snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d",
- channel_forwarded_auth_socket_dir, (int) getpid());
+ snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d",
+ auth_sock_dir, (int) getpid());
/* delete agent socket on fatal() */
fatal_add_cleanup(auth_sock_cleanup_proc, pw);
@@ -2585,8 +2733,7 @@ auth_input_request_forwarding(struct passwd * pw)
/* Bind it to the name. */
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
- strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name,
- sizeof(sunaddr.sun_path));
+ strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
packet_disconnect("bind: %.100s", strerror(errno));
@@ -2599,28 +2746,26 @@ auth_input_request_forwarding(struct passwd * pw)
packet_disconnect("listen: %.100s", strerror(errno));
/* Allocate a channel for the authentication agent socket. */
- newch = channel_new("auth socket",
+ nc = channel_new("auth socket",
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, xstrdup("auth socket"), 1);
-
- strlcpy(channels[newch].path, channel_forwarded_auth_socket_name,
- sizeof(channels[newch].path));
+ strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
return 1;
}
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
void
-auth_input_open_request(int type, int plen, void *ctxt)
+auth_input_open_request(int type, u_int32_t seq, void *ctxt)
{
- int remch, sock, newch;
- char *dummyname;
-
- packet_integrity_check(plen, 4, type);
+ Channel *c = NULL;
+ int remote_id, sock;
+ char *name;
/* Read the remote channel number from the message. */
- remch = packet_get_int();
+ remote_id = packet_get_int();
+ packet_check_eom();
/*
* Get a connection to the local authentication agent (this may again
@@ -2634,129 +2779,22 @@ auth_input_open_request(int type, int plen, void *ctxt)
* because authentication forwarding is only enabled if we have an
* agent.
*/
- if (sock < 0) {
- packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(remch);
- packet_send();
- return;
+ if (sock >= 0) {
+ name = xstrdup("authentication agent connection");
+ c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
+ -1, 0, 0, 0, name, 1);
+ c->remote_id = remote_id;
+ c->force_drain = 1;
}
- 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
- * channel cannot yet be freed at that point.
- */
- dummyname = xstrdup("authentication agent connection");
-
- newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
- channels[newch].remote_id = remch;
-
- /* Send a confirmation to the remote host. */
- packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(remch);
- packet_put_int(newch);
- packet_send();
-}
-
-void
-channel_start_open(int id)
-{
- Channel *c = channel_lookup(id);
if (c == NULL) {
- log("channel_open: %d: bad id", id);
- return;
- }
- debug("send channel open %d", id);
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring(c->ctype);
- packet_put_int(c->self);
- packet_put_int(c->local_window);
- packet_put_int(c->local_maxpacket);
-}
-void
-channel_open(int id)
-{
- /* XXX REMOVE ME */
- channel_start_open(id);
- packet_send();
-}
-void
-channel_request(int id, char *service, int wantconfirm)
-{
- channel_request_start(id, service, wantconfirm);
- packet_send();
- debug("channel request %d: %s", id, service) ;
-}
-void
-channel_request_start(int id, char *service, int wantconfirm)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL) {
- log("channel_request: %d: bad id", id);
- return;
- }
- packet_start(SSH2_MSG_CHANNEL_REQUEST);
- packet_put_int(c->remote_id);
- packet_put_cstring(service);
- packet_put_char(wantconfirm);
-}
-void
-channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL) {
- log("channel_register_callback: %d: bad id", id);
- return;
- }
- c->cb_event = mtype;
- c->cb_fn = fn;
- c->cb_arg = arg;
-}
-void
-channel_register_cleanup(int id, channel_callback_fn *fn)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL) {
- log("channel_register_cleanup: %d: bad id", id);
- return;
- }
- c->dettach_user = fn;
-}
-void
-channel_cancel_cleanup(int id)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL) {
- log("channel_cancel_cleanup: %d: bad id", id);
- return;
- }
- c->dettach_user = NULL;
-}
-void
-channel_register_filter(int id, channel_filter_fn *fn)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL) {
- log("channel_register_filter: %d: bad id", id);
- return;
+ packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(remote_id);
+ } else {
+ /* Send a confirmation to the remote host. */
+ debug("Forwarding authentication connection.");
+ packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(remote_id);
+ packet_put_int(c->self);
}
- c->input_filter = fn;
-}
-
-void
-channel_set_fds(int id, int rfd, int wfd, int efd,
- int extusage, int nonblock)
-{
- Channel *c = channel_lookup(id);
- if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
- fatal("channel_activate for non-larval channel %d.", id);
- channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
- c->type = SSH_CHANNEL_OPEN;
- /* XXX window size? */
- c->local_window = c->local_window_max = c->local_maxpacket * 2;
- packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
- packet_put_int(c->remote_id);
- packet_put_int(c->local_window);
packet_send();
}
diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h
index 16ddde5..9425739 100644
--- a/crypto/openssh/channels.h
+++ b/crypto/openssh/channels.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: channels.h,v 1.65 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -10,7 +13,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,16 +35,13 @@
* (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("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
-/* RCSID("$FreeBSD$"); */
-#ifndef CHANNELS_H
-#define CHANNELS_H
+#ifndef CHANNEL_H
+#define CHANNEL_H
#include "buffer.h"
/* Definitions for channel types. */
-#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
@@ -55,38 +55,38 @@
#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
#define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13
-#define SSH_CHANNEL_MAX_TYPE 14
+#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */
+#define SSH_CHANNEL_MAX_TYPE 15
+
+#define SSH_CHANNEL_PATH_LEN 256
-/*
- * Data structure for channel data. This is iniailized in channel_allocate
- * and cleared in channel_free.
- */
struct Channel;
typedef struct Channel Channel;
-typedef void channel_callback_fn(int id, void *arg);
-typedef int channel_filter_fn(struct Channel *c, char *buf, int len);
+typedef void channel_callback_fn(int, void *);
+typedef int channel_filter_fn(struct Channel *, char *, int);
struct Channel {
int type; /* channel type/state */
int self; /* my own channel identifier */
int remote_id; /* channel identifier for remote peer */
- /* peer can be reached over encrypted connection, via packet-sent */
- int istate; /* input from channel (state of receive half) */
- int ostate; /* output to channel (state of transmit half) */
+ u_int istate; /* input from channel (state of receive half) */
+ u_int ostate; /* output to channel (state of transmit half) */
int flags; /* close sent/rcvd */
int rfd; /* read fd */
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
int isatty; /* rfd is a tty */
+ int force_drain; /* force close on iEOF */
+ int delayed; /* fdset hack */
Buffer input; /* data read from socket, to be sent over
* encrypted connection */
Buffer output; /* data received over encrypted connection for
* send on socket */
Buffer extended;
- char path[200]; /* path for unix domain sockets, or host name
- * for forwards */
+ char path[SSH_CHANNEL_PATH_LEN];
+ /* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */
@@ -98,14 +98,13 @@ struct Channel {
int local_consumed;
int local_maxpacket;
int extended_usage;
+ int single_connection;
char *ctype; /* type */
/* callback */
- channel_callback_fn *cb_fn;
- void *cb_arg;
- int cb_event;
- channel_callback_fn *dettach_user;
+ channel_callback_fn *confirm;
+ channel_callback_fn *detach_user;
/* filter */
channel_filter_fn *input_filter;
@@ -116,199 +115,110 @@ struct Channel {
#define CHAN_EXTENDED_WRITE 2
/* default window/packet sizes for tcp/x11-fwd-channel */
-#define CHAN_SES_WINDOW_DEFAULT (32*1024)
-#define CHAN_SES_PACKET_DEFAULT (CHAN_SES_WINDOW_DEFAULT/2)
-#define CHAN_TCP_WINDOW_DEFAULT (32*1024)
-#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2)
-#define CHAN_X11_WINDOW_DEFAULT (4*1024)
-#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2)
-
-
-void channel_open(int id);
-void channel_request(int id, char *service, int wantconfirm);
-void channel_request_start(int id, char *service, int wantconfirm);
-void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
-void channel_register_cleanup(int id, channel_callback_fn *fn);
-void channel_register_filter(int id, channel_filter_fn *fn);
-void channel_cancel_cleanup(int id);
-Channel *channel_lookup(int id);
-
-int
-channel_new(char *ctype, int type, int rfd, int wfd, int efd,
- int window, int maxpack, int extended_usage, char *remote_name,
- int nonblock);
-void
-channel_set_fds(int id, int rfd, int wfd, int efd,
- int extusage, int nonblock);
-
-void deny_input_open(int type, int plen, void *ctxt);
-
-void channel_input_channel_request(int type, int plen, void *ctxt);
-void channel_input_close(int type, int plen, void *ctxt);
-void channel_input_close_confirmation(int type, int plen, void *ctxt);
-void channel_input_data(int type, int plen, void *ctxt);
-void channel_input_extended_data(int type, int plen, void *ctxt);
-void channel_input_ieof(int type, int plen, void *ctxt);
-void channel_input_oclose(int type, int plen, void *ctxt);
-void channel_input_open_confirmation(int type, int plen, void *ctxt);
-void channel_input_open_failure(int type, int plen, void *ctxt);
-void channel_input_port_open(int type, int plen, void *ctxt);
-void channel_input_window_adjust(int type, int plen, void *ctxt);
-
-/* Sets specific protocol options. */
-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
- * is freed.
- */
-int channel_allocate(int type, int sock, char *remote_name);
-
-/* Free the channel and close its socket. */
-void channel_free(int channel);
-
-/*
- * Allocate/update select bitmasks and add any bits relevant to channels in
- * select bitmasks.
- */
-void
-channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- int rekeying);
-
-/*
- * After select, perform any appropriate operations for channels which have
- * events pending.
- */
-void channel_after_select(fd_set * readset, fd_set * writeset);
-
-/* If there is data to send to the connection, send some of it now. */
-void channel_output_poll(void);
-
-/* Returns true if no channel has too much buffered data. */
-int channel_not_very_much_buffered_data(void);
-
-/* This closes any sockets that are listening for connections; this removes
- any unix domain sockets. */
-void channel_stop_listening(void);
-
-/*
- * Closes the sockets of all channels. This is used to close extra file
- * descriptors after a fork.
- */
-void channel_close_all(void);
-
-/* Returns true if there is still an open channel over the connection. */
-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.
- * The caller should free the string with xfree.
- */
-char *channel_open_message(void);
-
-/*
- * Initiate forwarding of connections to local port "port" through the secure
- * channel to host:port from remote side.
- */
-int
-channel_request_local_forwarding(u_short listen_port,
- const char *host_to_connect, u_short port_to_connect, int gateway_ports);
-int
-channel_request_forwarding(const char *listen_address, u_short listen_port,
- const char *host_to_connect, u_short port_to_connect, int gateway_ports,
- int remote_fwd);
-
-/*
- * Initiate forwarding of connections to port "port" on remote host through
- * the secure channel to host:port from local side. This never returns if
- * there was an error. This registers that open requests for that port are
- * permitted.
- */
-void
-channel_request_remote_forwarding(u_short port, const char *host,
- u_short remote_port);
-
-/*
- * Permits opening to any host/port if permitted_opens[] is empty. This is
- * usually 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);
-
-/* Add host/port to list of allowed targets for port forwarding */
-void channel_add_permitted_opens(char *host, int port);
-
-/* Flush list */
-void channel_clear_permitted_opens(void);
-
-/*
- * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
- * listening for the port, and sends back a success reply (or disconnect
- * message if there was an error). This never returns if there was an error.
- */
-void channel_input_port_forward_request(int is_root, int gateway_ports);
-
-/*
- * 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);
-
-/*
- * Creates an internet domain socket for listening for X11 connections.
- * Returns a suitable value for the DISPLAY variable, or NULL if an error
- * occurs.
- */
-char *x11_create_display_inet(int screen, int x11_display_offset);
-
-/*
- * 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
- * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
- */
-void x11_input_open(int type, int plen, void *ctxt);
-
-/*
- * Requests forwarding of X11 connections. This should be called on the
- * client only.
- */
-void x11_request_forwarding(void);
-
-/*
- * Requests forwarding for X11 connections, with authentication spoofing.
- * This should be called in the client only.
- */
-void
-x11_request_forwarding_with_spoofing(int client_session_id,
- const char *proto, const char *data);
-
-/* Sends a message to the server to request authentication fd forwarding. */
-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 to
- * a static buffer.
- */
-char *auth_get_socket_name(void);
-
-/*
- * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
- * This starts forwarding authentication requests.
- */
-int auth_input_request_forwarding(struct passwd * pw);
-
-/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
-void auth_input_open_request(int type, int plen, void *ctxt);
-
-/* XXX */
-void auth_sock_cleanup_proc(void *pw);
-int channel_connect_to(const char *host, u_short host_port);
-int channel_connect_by_listen_adress(u_short listen_port);
-int x11_connect_display(void);
-
-int channel_find_open(void);
+#define CHAN_SES_PACKET_DEFAULT (32*1024)
+#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT)
+#define CHAN_TCP_PACKET_DEFAULT (32*1024)
+#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT)
+#define CHAN_X11_PACKET_DEFAULT (16*1024)
+#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT)
+
+/* possible input states */
+#define CHAN_INPUT_OPEN 0
+#define CHAN_INPUT_WAIT_DRAIN 1
+#define CHAN_INPUT_WAIT_OCLOSE 2
+#define CHAN_INPUT_CLOSED 3
+
+/* possible output states */
+#define CHAN_OUTPUT_OPEN 0
+#define CHAN_OUTPUT_WAIT_DRAIN 1
+#define CHAN_OUTPUT_WAIT_IEOF 2
+#define CHAN_OUTPUT_CLOSED 3
+
+#define CHAN_CLOSE_SENT 0x01
+#define CHAN_CLOSE_RCVD 0x02
+
+/* channel management */
+
+Channel *channel_lookup(int);
+Channel *channel_new(char *, int, int, int, int, int, int, int, char *, int);
+void channel_set_fds(int, int, int, int, int, int, u_int);
+void channel_free(Channel *);
+void channel_free_all(void);
+void channel_stop_listening(void);
+
+void channel_send_open(int);
+void channel_request_start(int, char *, int);
+void channel_register_cleanup(int, channel_callback_fn *);
+void channel_register_confirm(int, channel_callback_fn *);
+void channel_register_filter(int, channel_filter_fn *);
+void channel_cancel_cleanup(int);
+int channel_close_fd(int *);
+
+/* protocol handler */
+
+void channel_input_close(int, u_int32_t, void *);
+void channel_input_close_confirmation(int, u_int32_t, void *);
+void channel_input_data(int, u_int32_t, void *);
+void channel_input_extended_data(int, u_int32_t, void *);
+void channel_input_ieof(int, u_int32_t, void *);
+void channel_input_oclose(int, u_int32_t, void *);
+void channel_input_open_confirmation(int, u_int32_t, void *);
+void channel_input_open_failure(int, u_int32_t, void *);
+void channel_input_port_open(int, u_int32_t, void *);
+void channel_input_window_adjust(int, u_int32_t, void *);
+
+/* file descriptor handling (read/write) */
+
+void channel_prepare_select(fd_set **, fd_set **, int *, int*, int);
+void channel_after_select(fd_set *, fd_set *);
+void channel_output_poll(void);
+
+int channel_not_very_much_buffered_data(void);
+void channel_close_all(void);
+int channel_still_open(void);
+char *channel_open_message(void);
+int channel_find_open(void);
+
+/* tcp forwarding */
+void channel_set_af(int af);
+void channel_permit_all_opens(void);
+void channel_add_permitted_opens(char *, int);
+void channel_clear_permitted_opens(void);
+void channel_input_port_forward_request(int, int);
+int channel_connect_to(const char *, u_short);
+int channel_connect_by_listen_address(u_short);
+void channel_request_remote_forwarding(u_short, const char *, u_short);
+int channel_setup_local_fwd_listener(u_short, const char *, u_short, int);
+int channel_setup_remote_fwd_listener(const char *, u_short, int);
+
+/* x11 forwarding */
+
+int x11_connect_display(void);
+int x11_create_display_inet(int, int, int);
+void x11_input_open(int, u_int32_t, void *);
+void x11_request_forwarding_with_spoofing(int, const char *, const char *);
+void deny_input_open(int, u_int32_t, void *);
+
+/* agent forwarding */
+
+void auth_request_forwarding(void);
+char *auth_get_socket_name(void);
+int auth_input_request_forwarding(struct passwd *);
+void auth_input_open_request(int, u_int32_t, void *);
+
+/* channel close */
+
+int chan_is_dead(Channel *, int);
+void chan_mark_dead(Channel *);
+
+/* channel events */
+
+void chan_rcvd_oclose(Channel *);
+void chan_read_failed(Channel *);
+void chan_ibuf_empty(Channel *);
+
+void chan_rcvd_ieof(Channel *);
+void chan_write_failed(Channel *);
+void chan_obuf_empty(Channel *);
#endif
diff --git a/crypto/openssh/cipher.c b/crypto/openssh/cipher.c
index 07036d4..806c5c1 100644
--- a/crypto/openssh/cipher.c
+++ b/crypto/openssh/cipher.c
@@ -11,7 +11,7 @@
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
- * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,7 +35,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: cipher.c,v 1.43 2001/02/04 15:32:23 stevesk Exp $");
+RCSID("$OpenBSD: cipher.c,v 1.52 2002/02/18 13:05:32 markus Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h"
@@ -43,389 +43,53 @@ RCSID("$FreeBSD$");
#include "cipher.h"
#include <openssl/md5.h>
+#include "rijndael.h"
+
+static EVP_CIPHER *evp_ssh1_3des(void);
+static EVP_CIPHER *evp_ssh1_bf(void);
+static EVP_CIPHER *evp_rijndael(void);
+
+struct Cipher {
+ char *name;
+ int number; /* for ssh1 only */
+ u_int block_size;
+ u_int key_len;
+ EVP_CIPHER *(*evptype)(void);
+} ciphers[] = {
+ { "none", SSH_CIPHER_NONE, 8, 0, EVP_enc_null },
+ { "des", SSH_CIPHER_DES, 8, 8, EVP_des_cbc },
+ { "3des", SSH_CIPHER_3DES, 8, 16, evp_ssh1_3des },
+ { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, evp_ssh1_bf },
+
+ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, EVP_des_ede3_cbc },
+ { "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc },
+ { "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_cast5_cbc },
+ { "arcfour", SSH_CIPHER_SSH2, 8, 16, EVP_rc4 },
+ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, evp_rijndael },
+ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, evp_rijndael },
+ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, evp_rijndael },
+
+ { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL }
+};
+/*--*/
-/* no encryption */
-void
-none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
-}
-void
-none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
-}
-void
-none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- memcpy(dest, src, len);
-}
-
-/* DES */
-void
-des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- static int dowarn = 1;
- if (dowarn) {
- error("Warning: use of DES is strongly discouraged "
- "due to cryptographic weaknesses");
- dowarn = 0;
- }
- des_set_key((void *)key, cc->u.des.key);
-}
-void
-des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
- memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));
-}
-void
-des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
- DES_ENCRYPT);
-}
-void
-des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
- DES_DECRYPT);
-}
-
-/* 3DES */
-void
-des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- des_set_key((void *) key, cc->u.des3.key1);
- des_set_key((void *) (key+8), cc->u.des3.key2);
- des_set_key((void *) (key+16), cc->u.des3.key3);
-}
-void
-des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
- memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));
- memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));
- if (iv == NULL)
- return;
- memcpy(cc->u.des3.iv3, (char *)iv, 8);
-}
-void
-des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- des_ede3_cbc_encrypt(src, dest, len,
- cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
- &cc->u.des3.iv3, DES_ENCRYPT);
-}
-void
-des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- des_ede3_cbc_encrypt(src, dest, len,
- cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
- &cc->u.des3.iv3, DES_DECRYPT);
-}
-
-/*
- * This is used by SSH1:
- *
- * What kind of triple DES are these 2 routines?
- *
- * Why is there a redundant initialization vector?
- *
- * If only iv3 was used, then, this would till effect have been
- * outer-cbc. However, there is also a private iv1 == iv2 which
- * perhaps makes differential analysis easier. On the other hand, the
- * private iv1 probably makes the CRC-32 attack ineffective. This is a
- * result of that there is no longer any known iv1 to use when
- * choosing the X block.
- */
-void
-des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- des_set_key((void *) key, cc->u.des3.key1);
- des_set_key((void *) (key+8), cc->u.des3.key2);
- if (keylen <= 16)
- des_set_key((void *) key, cc->u.des3.key3);
- else
- des_set_key((void *) (key+16), cc->u.des3.key3);
-}
-void
-des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- des_cblock iv1;
- des_cblock *iv2 = &cc->u.des3.iv2;
- des_cblock *iv3 = &cc->u.des3.iv3;
-
- memcpy(&iv1, iv2, 8);
-
- des_ncbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
- des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
- des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
-}
-void
-des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- des_cblock iv1;
- des_cblock *iv2 = &cc->u.des3.iv2;
- des_cblock *iv3 = &cc->u.des3.iv3;
-
- memcpy(&iv1, iv2, 8);
-
- des_ncbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
- des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
- des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
-}
-
-/* Blowfish */
-void
-blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
-}
-void
-blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
- if (iv == NULL)
- memset(cc->u.bf.iv, 0, 8);
- else
- memcpy(cc->u.bf.iv, (char *)iv, 8);
-}
-void
-blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
- BF_ENCRYPT);
-}
-void
-blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
- BF_DECRYPT);
-}
-
-/*
- * SSH1 uses a variation on Blowfish, all bytes must be swapped before
- * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
- */
-static void
-swap_bytes(const u_char *src, u_char *dst, int n)
-{
- char c[4];
-
- /* Process 4 bytes every lap. */
- for (n = n / 4; n > 0; n--) {
- c[3] = *src++;
- c[2] = *src++;
- c[1] = *src++;
- c[0] = *src++;
-
- *dst++ = c[0];
- *dst++ = c[1];
- *dst++ = c[2];
- *dst++ = c[3];
- }
-}
-
-void
-blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- swap_bytes(src, dest, len);
- BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
- BF_ENCRYPT);
- swap_bytes(dest, dest, len);
-}
-void
-blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
-{
- swap_bytes(src, dest, len);
- BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
- BF_DECRYPT);
- swap_bytes(dest, dest, len);
-}
-
-/* alleged rc4 */
-void
-arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);
-}
-void
-arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- RC4(&cc->u.rc4, len, (u_char *)src, dest);
-}
-
-/* CAST */
-void
-cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);
-}
-void
-cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
- if (iv == NULL)
- fatal("no IV for %s.", cc->cipher->name);
- memcpy(cc->u.cast.iv, (char *)iv, 8);
-}
-void
-cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
- CAST_ENCRYPT);
-}
-void
-cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
-{
- CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
- CAST_DECRYPT);
-}
-
-/* RIJNDAEL */
-
-#define RIJNDAEL_BLOCKSIZE 16
-void
-rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
-{
- rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1);
- rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0);
-}
-void
-rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
-{
- if (iv == NULL)
- fatal("no IV for %s.", cc->cipher->name);
- memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
-}
-void
-rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
+u_int
+cipher_blocksize(Cipher *c)
{
- rijndael_ctx *ctx = &cc->u.rijndael.enc;
- u4byte *iv = cc->u.rijndael.iv;
- u4byte in[4];
- u4byte *cprev, *cnow, *plain;
- int i, blocks = len / RIJNDAEL_BLOCKSIZE;
- if (len == 0)
- return;
- if (len % RIJNDAEL_BLOCKSIZE)
- fatal("rijndael_cbc_encrypt: bad len %d", len);
- cnow = (u4byte*) dest;
- plain = (u4byte*) src;
- cprev = iv;
- for(i = 0; i < blocks; i++, plain+=4, cnow+=4) {
- in[0] = plain[0] ^ cprev[0];
- in[1] = plain[1] ^ cprev[1];
- in[2] = plain[2] ^ cprev[2];
- in[3] = plain[3] ^ cprev[3];
- rijndael_encrypt(ctx, in, cnow);
- cprev = cnow;
- }
- memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);
+ return (c->block_size);
}
-
-void
-rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
- u_int len)
+u_int
+cipher_keylen(Cipher *c)
{
- rijndael_ctx *ctx = &cc->u.rijndael.dec;
- u4byte *iv = cc->u.rijndael.iv;
- u4byte ivsaved[4];
- u4byte *cnow = (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE);
- u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE);
- u4byte *ivp;
- int i, blocks = len / RIJNDAEL_BLOCKSIZE;
- if (len == 0)
- return;
- if (len % RIJNDAEL_BLOCKSIZE)
- fatal("rijndael_cbc_decrypt: bad len %d", len);
- memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);
- for(i = blocks; i > 0; i--, cnow-=4, plain-=4) {
- rijndael_decrypt(ctx, cnow, plain);
- ivp = (i == 1) ? iv : cnow-4;
- plain[0] ^= ivp[0];
- plain[1] ^= ivp[1];
- plain[2] ^= ivp[2];
- plain[3] ^= ivp[3];
- }
- memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);
+ return (c->key_len);
}
-Cipher ciphers[] = {
- { "none",
- SSH_CIPHER_NONE, 8, 0,
- none_setkey, none_setiv,
- none_crypt, none_crypt },
- { "des",
- SSH_CIPHER_DES, 8, 8,
- des_ssh1_setkey, des_ssh1_setiv,
- des_ssh1_encrypt, des_ssh1_decrypt },
- { "3des",
- SSH_CIPHER_3DES, 8, 16,
- des3_ssh1_setkey, des3_setiv,
- des3_ssh1_encrypt, des3_ssh1_decrypt },
- { "blowfish",
- SSH_CIPHER_BLOWFISH, 8, 16,
- blowfish_setkey, blowfish_setiv,
- blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },
-
- { "3des-cbc",
- SSH_CIPHER_SSH2, 8, 24,
- des3_setkey, des3_setiv,
- des3_cbc_encrypt, des3_cbc_decrypt },
- { "blowfish-cbc",
- SSH_CIPHER_SSH2, 8, 16,
- blowfish_setkey, blowfish_setiv,
- blowfish_cbc_encrypt, blowfish_cbc_decrypt },
- { "cast128-cbc",
- SSH_CIPHER_SSH2, 8, 16,
- cast_setkey, cast_setiv,
- cast_cbc_encrypt, cast_cbc_decrypt },
- { "arcfour",
- SSH_CIPHER_SSH2, 8, 16,
- arcfour_setkey, none_setiv,
- arcfour_crypt, arcfour_crypt },
- { "aes128-cbc",
- SSH_CIPHER_SSH2, 16, 16,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "aes192-cbc",
- SSH_CIPHER_SSH2, 16, 24,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "aes256-cbc",
- SSH_CIPHER_SSH2, 16, 32,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "rijndael128-cbc",
- SSH_CIPHER_SSH2, 16, 16,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "rijndael192-cbc",
- SSH_CIPHER_SSH2, 16, 24,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "rijndael256-cbc",
- SSH_CIPHER_SSH2, 16, 32,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { "rijndael-cbc@lysator.liu.se",
- SSH_CIPHER_SSH2, 16, 32,
- rijndael_setkey, rijndael_setiv,
- rijndael_cbc_encrypt, rijndael_cbc_decrypt },
- { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
-};
-
-/*--*/
-
u_int
cipher_mask_ssh1(int client)
{
u_int mask = 0;
- mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
+ mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH;
if (client) {
mask |= 1 << SSH_CIPHER_DES;
@@ -465,7 +129,7 @@ ciphers_valid(const char *names)
return 0;
ciphers = cp = xstrdup(names);
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
- (p = strsep(&cp, CIPHER_SEP))) {
+ (p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
debug("bad cipher %s [%s]", p, names);
@@ -504,8 +168,24 @@ cipher_name(int id)
void
cipher_init(CipherContext *cc, Cipher *cipher,
- const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
+ const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
+ int encrypt)
{
+ static int dowarn = 1;
+ const EVP_CIPHER *type;
+ int klen;
+
+ if (cipher->number == SSH_CIPHER_DES) {
+ if (dowarn) {
+ error("Warning: use of DES is strongly discouraged "
+ "due to cryptographic weaknesses");
+ dowarn = 0;
+ }
+ if (keylen > 8)
+ keylen = 8;
+ }
+ cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
+
if (keylen < cipher->key_len)
fatal("cipher_init: key length %d is insufficient for %s.",
keylen, cipher->name);
@@ -513,24 +193,40 @@ cipher_init(CipherContext *cc, Cipher *cipher,
fatal("cipher_init: iv length %d is insufficient for %s.",
ivlen, cipher->name);
cc->cipher = cipher;
- cipher->setkey(cc, key, keylen);
- cipher->setiv(cc, iv, ivlen);
+
+ type = (*cipher->evptype)();
+
+ EVP_CIPHER_CTX_init(&cc->evp);
+ if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
+ (encrypt == CIPHER_ENCRYPT)) == 0)
+ fatal("cipher_init: EVP_CipherInit failed for %s",
+ cipher->name);
+ klen = EVP_CIPHER_CTX_key_length(&cc->evp);
+ if (klen > 0 && keylen != klen) {
+ debug("cipher_init: set keylen (%d -> %d)", klen, keylen);
+ if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
+ fatal("cipher_init: set keylen failed (%d -> %d)",
+ klen, keylen);
+ }
+ if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
+ fatal("cipher_init: EVP_CipherInit: set key failed for %s",
+ cipher->name);
}
void
-cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
if (len % cc->cipher->block_size)
fatal("cipher_encrypt: bad plaintext length %d", len);
- cc->cipher->encrypt(cc, dest, src, len);
+ if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0)
+ fatal("evp_crypt: EVP_Cipher failed");
}
void
-cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+cipher_cleanup(CipherContext *cc)
{
- if (len % cc->cipher->block_size)
- fatal("cipher_decrypt: bad ciphertext length %d", len);
- cc->cipher->decrypt(cc, dest, src, len);
+ if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
+ error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
}
/*
@@ -540,7 +236,7 @@ cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
void
cipher_set_key_string(CipherContext *cc, Cipher *cipher,
- const char *passphrase)
+ const char *passphrase, int encrypt)
{
MD5_CTX md;
u_char digest[16];
@@ -549,8 +245,257 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
MD5_Final(digest, &md);
- cipher_init(cc, cipher, digest, 16, NULL, 0);
+ cipher_init(cc, cipher, digest, 16, NULL, 0, encrypt);
memset(digest, 0, sizeof(digest));
memset(&md, 0, sizeof(md));
}
+
+/* Implementations for other non-EVP ciphers */
+
+/*
+ * This is used by SSH1:
+ *
+ * What kind of triple DES are these 2 routines?
+ *
+ * Why is there a redundant initialization vector?
+ *
+ * If only iv3 was used, then, this would till effect have been
+ * outer-cbc. However, there is also a private iv1 == iv2 which
+ * perhaps makes differential analysis easier. On the other hand, the
+ * private iv1 probably makes the CRC-32 attack ineffective. This is a
+ * result of that there is no longer any known iv1 to use when
+ * choosing the X block.
+ */
+struct ssh1_3des_ctx
+{
+ EVP_CIPHER_CTX k1, k2, k3;
+};
+static int
+ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+ int enc)
+{
+ struct ssh1_3des_ctx *c;
+ u_char *k1, *k2, *k3;
+
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+ c = xmalloc(sizeof(*c));
+ EVP_CIPHER_CTX_set_app_data(ctx, c);
+ }
+ if (key == NULL)
+ return (1);
+ if (enc == -1)
+ enc = ctx->encrypt;
+ k1 = k2 = k3 = (u_char *) key;
+ k2 += 8;
+ if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
+ if (enc)
+ k3 += 16;
+ else
+ k1 += 16;
+ }
+ EVP_CIPHER_CTX_init(&c->k1);
+ EVP_CIPHER_CTX_init(&c->k2);
+ EVP_CIPHER_CTX_init(&c->k3);
+ if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
+ EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
+ EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
+ memset(c, 0, sizeof(*c));
+ xfree(c);
+ EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+ return (0);
+ }
+ return (1);
+}
+static int
+ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
+{
+ struct ssh1_3des_ctx *c;
+
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+ error("ssh1_3des_cbc: no context");
+ return (0);
+ }
+ if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
+ EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
+ EVP_Cipher(&c->k3, dest, dest, len) == 0)
+ return (0);
+ return (1);
+}
+static int
+ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ struct ssh1_3des_ctx *c;
+
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+ memset(c, 0, sizeof(*c));
+ xfree(c);
+ EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+ }
+ return (1);
+}
+static EVP_CIPHER *
+evp_ssh1_3des(void)
+{
+ static EVP_CIPHER ssh1_3des;
+
+ memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
+ ssh1_3des.nid = NID_undef;
+ ssh1_3des.block_size = 8;
+ ssh1_3des.iv_len = 0;
+ ssh1_3des.key_len = 16;
+ ssh1_3des.init = ssh1_3des_init;
+ ssh1_3des.cleanup = ssh1_3des_cleanup;
+ ssh1_3des.do_cipher = ssh1_3des_cbc;
+ ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
+ return (&ssh1_3des);
+}
+
+/*
+ * SSH1 uses a variation on Blowfish, all bytes must be swapped before
+ * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
+ */
+static void
+swap_bytes(const u_char *src, u_char *dst, int n)
+{
+ u_char c[4];
+
+ /* Process 4 bytes every lap. */
+ for (n = n / 4; n > 0; n--) {
+ c[3] = *src++;
+ c[2] = *src++;
+ c[1] = *src++;
+ c[0] = *src++;
+
+ *dst++ = c[0];
+ *dst++ = c[1];
+ *dst++ = c[2];
+ *dst++ = c[3];
+ }
+}
+static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *, const u_char *, u_int) = NULL;
+static int
+bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int len)
+{
+ int ret;
+
+ swap_bytes(in, out, len);
+ ret = (*orig_bf)(ctx, out, out, len);
+ swap_bytes(out, out, len);
+ return (ret);
+}
+static EVP_CIPHER *
+evp_ssh1_bf(void)
+{
+ static EVP_CIPHER ssh1_bf;
+
+ memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
+ orig_bf = ssh1_bf.do_cipher;
+ ssh1_bf.nid = NID_undef;
+ ssh1_bf.do_cipher = bf_ssh1_cipher;
+ ssh1_bf.key_len = 32;
+ return (&ssh1_bf);
+}
+
+/* RIJNDAEL */
+#define RIJNDAEL_BLOCKSIZE 16
+struct ssh_rijndael_ctx
+{
+ rijndael_ctx r_ctx;
+ u_char r_iv[RIJNDAEL_BLOCKSIZE];
+};
+
+static int
+ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+ int enc)
+{
+ struct ssh_rijndael_ctx *c;
+
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+ c = xmalloc(sizeof(*c));
+ EVP_CIPHER_CTX_set_app_data(ctx, c);
+ }
+ if (key != NULL) {
+ if (enc == -1)
+ enc = ctx->encrypt;
+ rijndael_set_key(&c->r_ctx, (u_char *)key,
+ 8*EVP_CIPHER_CTX_key_length(ctx), enc);
+ }
+ if (iv != NULL)
+ memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE);
+ return (1);
+}
+static int
+ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
+ u_int len)
+{
+ struct ssh_rijndael_ctx *c;
+ u_char buf[RIJNDAEL_BLOCKSIZE];
+ u_char *cprev, *cnow, *plain, *ivp;
+ int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
+
+ if (len == 0)
+ return (1);
+ if (len % RIJNDAEL_BLOCKSIZE)
+ fatal("ssh_rijndael_cbc: bad len %d", len);
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+ error("ssh_rijndael_cbc: no context");
+ return (0);
+ }
+ if (ctx->encrypt) {
+ cnow = dest;
+ plain = (u_char *)src;
+ cprev = c->r_iv;
+ for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
+ cnow+=RIJNDAEL_BLOCKSIZE) {
+ for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+ buf[j] = plain[j] ^ cprev[j];
+ rijndael_encrypt(&c->r_ctx, buf, cnow);
+ cprev = cnow;
+ }
+ memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE);
+ } else {
+ cnow = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
+ plain = dest+len-RIJNDAEL_BLOCKSIZE;
+
+ memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE);
+ for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
+ plain-=RIJNDAEL_BLOCKSIZE) {
+ rijndael_decrypt(&c->r_ctx, cnow, plain);
+ ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE;
+ for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+ plain[j] ^= ivp[j];
+ }
+ memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE);
+ }
+ return (1);
+}
+static int
+ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ struct ssh_rijndael_ctx *c;
+
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+ memset(c, 0, sizeof(*c));
+ xfree(c);
+ EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+ }
+ return (1);
+}
+static EVP_CIPHER *
+evp_rijndael(void)
+{
+ static EVP_CIPHER rijndal_cbc;
+
+ memset(&rijndal_cbc, 0, sizeof(EVP_CIPHER));
+ rijndal_cbc.nid = NID_undef;
+ rijndal_cbc.block_size = RIJNDAEL_BLOCKSIZE;
+ rijndal_cbc.iv_len = RIJNDAEL_BLOCKSIZE;
+ rijndal_cbc.key_len = 16;
+ rijndal_cbc.init = ssh_rijndael_init;
+ rijndal_cbc.cleanup = ssh_rijndael_cleanup;
+ rijndal_cbc.do_cipher = ssh_rijndael_cbc;
+ rijndal_cbc.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
+ EVP_CIPH_ALWAYS_CALL_INIT;
+ return (&rijndal_cbc);
+}
diff --git a/crypto/openssh/cipher.h b/crypto/openssh/cipher.h
index 870d1da..8aa5982 100644
--- a/crypto/openssh/cipher.h
+++ b/crypto/openssh/cipher.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: cipher.h,v 1.32 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -32,17 +35,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef CIPHER_H
#define CIPHER_H
-#include <openssl/des.h>
-#include <openssl/blowfish.h>
-#include <openssl/rc4.h>
-#include <openssl/cast.h>
-#include "rijndael.h"
+#include <openssl/evp.h>
/*
* Cipher types for SSH-1. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
@@ -60,59 +56,30 @@
#define SSH_CIPHER_RESERVED 7
#define SSH_CIPHER_MAX 31
+#define CIPHER_ENCRYPT 1
+#define CIPHER_DECRYPT 0
+
typedef struct Cipher Cipher;
typedef struct CipherContext CipherContext;
+struct Cipher;
struct CipherContext {
- union {
- struct {
- des_key_schedule key;
- des_cblock iv;
- } des;
- struct {
- des_key_schedule key1;
- des_key_schedule key2;
- des_cblock iv2;
- des_key_schedule key3;
- des_cblock iv3;
- } des3;
- struct {
- struct bf_key_st key;
- u_char iv[8];
- } bf;
- struct {
- CAST_KEY key;
- u_char iv[8];
- } cast;
- struct {
- u4byte iv[4];
- rijndael_ctx enc;
- rijndael_ctx dec;
- } rijndael;
- RC4_KEY rc4;
- } u;
+ int plaintext;
+ EVP_CIPHER_CTX evp;
Cipher *cipher;
};
-struct Cipher {
- char *name;
- int number; /* for ssh1 only */
- u_int block_size;
- u_int key_len;
- void (*setkey)(CipherContext *, const u_char *, u_int);
- void (*setiv)(CipherContext *, const u_char *, u_int);
- void (*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
- void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
-};
-
-u_int cipher_mask_ssh1(int client);
-Cipher *cipher_by_name(const char *name);
-Cipher *cipher_by_number(int id);
-int cipher_number(const char *name);
-char *cipher_name(int id);
-int ciphers_valid(const char *names);
-void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int);
-void cipher_encrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
-void cipher_decrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
-void cipher_set_key_string(CipherContext *context, Cipher *cipher, const char *passphrase);
+u_int cipher_mask_ssh1(int);
+Cipher *cipher_by_name(const char *);
+Cipher *cipher_by_number(int);
+int cipher_number(const char *);
+char *cipher_name(int);
+int ciphers_valid(const char *);
+void cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
+ const u_char *, u_int, int);
+void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
+void cipher_cleanup(CipherContext *);
+void cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+u_int cipher_blocksize(Cipher *);
+u_int cipher_keylen(Cipher *);
#endif /* CIPHER_H */
diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c
index 0fc3518..57694327 100644
--- a/crypto/openssh/compat.c
+++ b/crypto/openssh/compat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,15 +23,15 @@
*/
#include "includes.h"
+RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $");
RCSID("$FreeBSD$");
-RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $");
-
-#include <regex.h>
+#include "buffer.h"
#include "packet.h"
#include "xmalloc.h"
#include "compat.h"
#include "log.h"
+#include "match.h"
int compat13 = 0;
int compat20 = 0;
@@ -53,76 +53,97 @@ enable_compat13(void)
void
compat_datafellows(const char *version)
{
- int i, ret;
- char ebuf[1024];
- regex_t reg;
+ int i;
static struct {
char *pat;
int bugs;
} check[] = {
- { "^OpenSSH[-_]2\\.[012]",
- SSH_OLD_SESSIONID|SSH_BUG_BANNER|
+ { "OpenSSH-2.0*,"
+ "OpenSSH-2.1*,"
+ "OpenSSH_2.1*,"
+ "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
- { "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
+ { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
- { "^OpenSSH_2\\.3\\.", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
+ { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY},
- { "^OpenSSH_2\\.5\\.[01]p1",
+ { "OpenSSH_2.5.0p1*,"
+ "OpenSSH_2.5.1p1*",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY },
- { "^OpenSSH_2\\.5\\.[012]",
- SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
- { "^OpenSSH_2\\.5\\.3",
- SSH_BUG_NOREKEY },
- { "^OpenSSH", 0 },
- { "MindTerm", 0 },
- { "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+ { "OpenSSH_2.5.0*,"
+ "OpenSSH_2.5.1*,"
+ "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
+ { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY },
+ { "Sun_SSH_1.0*", SSH_BUG_NOREKEY },
+ { "OpenSSH*", 0 },
+ { "*MindTerm*", 0 },
+ { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
- { "^2\\.1 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+ { "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
- { "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+ { "2.0.13*,"
+ "2.0.14*,"
+ "2.0.15*,"
+ "2.0.16*,"
+ "2.0.17*,"
+ "2.0.18*,"
+ "2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
- SSH_BUG_HBSERVICE },
- { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+ SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE|
+ SSH_BUG_DUMMYCHAN },
+ { "2.0.11*,"
+ "2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
+ SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
+ SSH_BUG_DUMMYCHAN },
+ { "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+ SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+ SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
+ SSH_BUG_PKAUTH|SSH_BUG_PKOK|
+ SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
+ SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN },
+ { "2.2.0*,"
+ "2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5 },
- { "^2\\.[23]\\.0", SSH_BUG_HMAC|SSH_BUG_RSASIGMD5 },
- { "^2\\.3\\.", SSH_BUG_RSASIGMD5 },
- { "^2\\.[2-9]\\.", 0 },
- { "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
- { "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
- { "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
- { "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
- { "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
- { "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */
- { "^SSH Compatible Server", /* Netscreen */
- SSH_BUG_PASSWORDPAD },
- { "^OSU_0", SSH_BUG_PASSWORDPAD },
- { "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD },
- { "^OSU_1\\.5alpha[1-3]",
+ { "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5 },
+ { "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */
+ { "2.*", SSH_BUG_DEBUG },
+ { "3.0.*", SSH_BUG_DEBUG },
+ { "3.0 SecureCRT*", SSH_OLD_SESSIONID },
+ { "1.7 SecureFX*", SSH_OLD_SESSIONID },
+ { "1.2.18*,"
+ "1.2.19*,"
+ "1.2.20*,"
+ "1.2.21*,"
+ "1.2.22*", SSH_BUG_IGNOREMSG },
+ { "1.3.2*", SSH_BUG_IGNOREMSG }, /* f-secure */
+ { "*SSH Compatible Server*", /* Netscreen */
SSH_BUG_PASSWORDPAD },
- { "^SSH_Version_Mapper",
+ { "*OSU_0*,"
+ "OSU_1.0*,"
+ "OSU_1.1*,"
+ "OSU_1.2*,"
+ "OSU_1.3*,"
+ "OSU_1.4*,"
+ "OSU_1.5alpha1*,"
+ "OSU_1.5alpha2*,"
+ "OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD },
+ { "*SSH_Version_Mapper*",
SSH_BUG_SCANNER },
{ NULL, 0 }
};
+
/* process table, return first match */
for (i = 0; check[i].pat; i++) {
- ret = regcomp(&reg, check[i].pat, REG_EXTENDED|REG_NOSUB);
- if (ret != 0) {
- regerror(ret, &reg, ebuf, sizeof(ebuf));
- ebuf[sizeof(ebuf)-1] = '\0';
- error("regerror: %s", ebuf);
- continue;
- }
- ret = regexec(&reg, version, 0, NULL, 0);
- regfree(&reg);
- if (ret == 0) {
+ if (match_pattern_list(version, check[i].pat,
+ strlen(check[i].pat), 0) == 1) {
debug("match: %s pat %s", version, check[i].pat);
datafellows = check[i].bugs;
return;
@@ -142,7 +163,7 @@ proto_spec(const char *spec)
return ret;
q = s = xstrdup(spec);
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
- switch(atoi(p)) {
+ switch (atoi(p)) {
case 1:
if (ret == SSH_PROTO_UNKNOWN)
ret |= SSH_PROTO_1_PREFERRED;
@@ -163,24 +184,25 @@ proto_spec(const char *spec)
char *
compat_cipher_proposal(char *cipher_prop)
{
+ Buffer b;
char *orig_prop, *fix_ciphers;
char *cp, *tmp;
- size_t len;
if (!(datafellows & SSH_BUG_BIGENDIANAES))
return(cipher_prop);
- len = strlen(cipher_prop) + 1;
- fix_ciphers = xmalloc(len);
- *fix_ciphers = '\0';
+ buffer_init(&b);
tmp = orig_prop = xstrdup(cipher_prop);
- while((cp = strsep(&tmp, ",")) != NULL) {
- if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) {
- if (*fix_ciphers)
- strlcat(fix_ciphers, ",", len);
- strlcat(fix_ciphers, cp, len);
+ while ((cp = strsep(&tmp, ",")) != NULL) {
+ if (strncmp(cp, "aes", 3) != 0) {
+ if (buffer_len(&b) > 0)
+ buffer_append(&b, ",", 1);
+ buffer_append(&b, cp, strlen(cp));
}
}
+ buffer_append(&b, "\0", 1);
+ fix_ciphers = xstrdup(buffer_ptr(&b));
+ buffer_free(&b);
xfree(orig_prop);
debug2("Original cipher proposal: %s", cipher_prop);
debug2("Compat cipher proposal: %s", fix_ciphers);
diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h
index a13234c..82acc5b 100644
--- a/crypto/openssh/compat.h
+++ b/crypto/openssh/compat.h
@@ -1,5 +1,8 @@
+/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
- * Copyright (c) 1999 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -21,8 +24,6 @@
* (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("$FreeBSD$"); */
-/* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */
#ifndef COMPAT_H
#define COMPAT_H
@@ -32,29 +33,33 @@
#define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04
-#define SSH_BUG_SIGBLOB 0x0001
-#define SSH_BUG_PKSERVICE 0x0002
-#define SSH_BUG_HMAC 0x0004
-#define SSH_BUG_X11FWD 0x0008
-#define SSH_OLD_SESSIONID 0x0010
-#define SSH_BUG_PKAUTH 0x0020
-#define SSH_BUG_DEBUG 0x0040
-#define SSH_BUG_BANNER 0x0080
-#define SSH_BUG_IGNOREMSG 0x0100
-#define SSH_BUG_PKOK 0x0200
-#define SSH_BUG_PASSWORDPAD 0x0400
-#define SSH_BUG_SCANNER 0x0800
-#define SSH_BUG_BIGENDIANAES 0x1000
-#define SSH_BUG_RSASIGMD5 0x2000
-#define SSH_OLD_DHGEX 0x4000
-#define SSH_BUG_NOREKEY 0x8000
-#define SSH_BUG_HBSERVICE 0x10000
+#define SSH_BUG_SIGBLOB 0x00000001
+#define SSH_BUG_PKSERVICE 0x00000002
+#define SSH_BUG_HMAC 0x00000004
+#define SSH_BUG_X11FWD 0x00000008
+#define SSH_OLD_SESSIONID 0x00000010
+#define SSH_BUG_PKAUTH 0x00000020
+#define SSH_BUG_DEBUG 0x00000040
+#define SSH_BUG_BANNER 0x00000080
+#define SSH_BUG_IGNOREMSG 0x00000100
+#define SSH_BUG_PKOK 0x00000200
+#define SSH_BUG_PASSWORDPAD 0x00000400
+#define SSH_BUG_SCANNER 0x00000800
+#define SSH_BUG_BIGENDIANAES 0x00001000
+#define SSH_BUG_RSASIGMD5 0x00002000
+#define SSH_OLD_DHGEX 0x00004000
+#define SSH_BUG_NOREKEY 0x00008000
+#define SSH_BUG_HBSERVICE 0x00010000
+#define SSH_BUG_OPENFAILURE 0x00020000
+#define SSH_BUG_DERIVEKEY 0x00040000
+#define SSH_BUG_DUMMYCHAN 0x00100000
+
+void enable_compat13(void);
+void enable_compat20(void);
+void compat_datafellows(const char *);
+int proto_spec(const char *);
+char *compat_cipher_proposal(char *);
-void enable_compat13(void);
-void enable_compat20(void);
-void compat_datafellows(const char *s);
-int proto_spec(const char *spec);
-char *compat_cipher_proposal(char *cipher_prop);
extern int compat13;
extern int compat20;
extern int datafellows;
diff --git a/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c
index fa70d7e..5b2ee4b 100644
--- a/crypto/openssh/hostfile.c
+++ b/crypto/openssh/hostfile.c
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
- * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $");
+RCSID("$OpenBSD: hostfile.c,v 1.29 2001/12/18 10:04:21 jakob Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
@@ -72,18 +72,7 @@ hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
return 1;
}
-int
-auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
-{
- Key *k = key_new(KEY_RSA1);
- int ret = hostfile_read_key(cpp, bitsp, k);
- BN_copy(e, k->rsa->e);
- BN_copy(n, k->rsa->n);
- key_free(k);
- return ret;
-}
-
-int
+static int
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
{
if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
diff --git a/crypto/openssh/includes.h b/crypto/openssh/includes.h
index 8cf76f4..3cef95d 100644
--- a/crypto/openssh/includes.h
+++ b/crypto/openssh/includes.h
@@ -1,4 +1,5 @@
-/* $OpenBSD: includes.h,v 1.14 2001/01/29 01:58:16 niklas Exp $ */
+/* $OpenBSD: includes.h,v 1.17 2002/01/26 16:44:22 stevesk Exp $ */
+/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -11,8 +12,6 @@
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
- *
- * $FreeBSD$
*/
#ifndef INCLUDES_H
@@ -57,11 +56,6 @@
#include "version.h"
-/* Define this to be the path of the xauth program. */
-#ifndef XAUTH_PATH
-#define XAUTH_PATH "/usr/X11R6/bin/xauth"
-#endif
-
/*
* Define this to use pipes instead of socketpairs for communicating with the
* client program. Socketpairs do not seem to work on all systems.
diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c
index e3279c8..05780ab 100644
--- a/crypto/openssh/key.c
+++ b/crypto/openssh/key.c
@@ -9,7 +9,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,7 +32,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
-RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
+RCSID("$OpenBSD: key.c,v 1.41 2002/02/28 15:46:33 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@@ -55,22 +55,31 @@ key_new(int type)
DSA *dsa;
k = xmalloc(sizeof(*k));
k->type = type;
+ k->flags = 0;
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
- rsa = RSA_new();
- rsa->n = BN_new();
- rsa->e = BN_new();
+ if ((rsa = RSA_new()) == NULL)
+ fatal("key_new: RSA_new failed");
+ if ((rsa->n = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
+ if ((rsa->e = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
k->rsa = rsa;
break;
case KEY_DSA:
- dsa = DSA_new();
- dsa->p = BN_new();
- dsa->q = BN_new();
- dsa->g = BN_new();
- dsa->pub_key = BN_new();
+ if ((dsa = DSA_new()) == NULL)
+ fatal("key_new: DSA_new failed");
+ if ((dsa->p = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
+ if ((dsa->q = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
+ if ((dsa->g = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
+ if ((dsa->pub_key = BN_new()) == NULL)
+ fatal("key_new: BN_new failed");
k->dsa = dsa;
break;
case KEY_UNSPEC:
@@ -88,15 +97,22 @@ key_new_private(int type)
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
- k->rsa->d = BN_new();
- k->rsa->iqmp = BN_new();
- k->rsa->q = BN_new();
- k->rsa->p = BN_new();
- k->rsa->dmq1 = BN_new();
- k->rsa->dmp1 = BN_new();
+ if ((k->rsa->d = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ if ((k->rsa->iqmp = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ if ((k->rsa->q = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ if ((k->rsa->p = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ if ((k->rsa->dmq1 = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ if ((k->rsa->dmp1 = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
break;
case KEY_DSA:
- k->dsa->priv_key = BN_new();
+ if ((k->dsa->priv_key = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
break;
case KEY_UNSPEC:
break;
@@ -154,14 +170,14 @@ key_equal(Key *a, Key *b)
return 0;
}
-u_char*
-key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
+static u_char*
+key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
{
- EVP_MD *md = NULL;
+ const EVP_MD *md = NULL;
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
- int len = 0;
+ u_int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
@@ -201,8 +217,7 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
retval = xmalloc(EVP_MAX_MD_SIZE);
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, blob, len);
- EVP_DigestFinal(&ctx, retval, NULL);
- *dgst_raw_length = md->md_size;
+ EVP_DigestFinal(&ctx, retval, dgst_raw_length);
memset(blob, 0, len);
xfree(blob);
} else {
@@ -211,15 +226,15 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
return retval;
}
-char*
-key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
+static char*
+key_fingerprint_hex(u_char* dgst_raw, u_int dgst_raw_len)
{
char *retval;
int i;
retval = xmalloc(dgst_raw_len * 3 + 1);
retval[0] = '\0';
- for(i = 0; i < dgst_raw_len; i++) {
+ for (i = 0; i < dgst_raw_len; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
strlcat(retval, hex, dgst_raw_len * 3);
@@ -228,8 +243,8 @@ key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
return retval;
}
-char*
-key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
+static char*
+key_fingerprint_bubblebabble(u_char* dgst_raw, u_int dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
@@ -280,12 +295,12 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
{
char *retval = NULL;
u_char *dgst_raw;
- size_t dgst_raw_len;
-
+ u_int dgst_raw_len;
+
dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
if (!dgst_raw)
fatal("key_fingerprint: null from key_fingerprint_raw()");
- switch(dgst_rep) {
+ switch (dgst_rep) {
case SSH_FP_HEX:
retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
break;
@@ -309,7 +324,7 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
* last processed (and maybe modified) character. Note that this may modify
* the buffer containing the number.
*/
-int
+static int
read_bignum(char **cpp, BIGNUM * value)
{
char *cp = *cpp;
@@ -345,7 +360,7 @@ read_bignum(char **cpp, BIGNUM * value)
*cpp = cp;
return 1;
}
-int
+static int
write_bignum(FILE *f, BIGNUM *num)
{
char *buf = BN_bn2dec(num);
@@ -354,11 +369,11 @@ write_bignum(FILE *f, BIGNUM *num)
return 0;
}
fprintf(f, " %s", buf);
- xfree(buf);
+ OPENSSL_free(buf);
return 1;
}
-/* returns 1 ok, -1 error, 0 type mismatch */
+/* returns 1 ok, -1 error */
int
key_read(Key *ret, char **cpp)
{
@@ -371,7 +386,7 @@ key_read(Key *ret, char **cpp)
cp = *cpp;
- switch(ret->type) {
+ switch (ret->type) {
case KEY_RSA1:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
@@ -413,21 +428,22 @@ key_read(Key *ret, char **cpp)
} else if (ret->type != type) {
/* is a key, but different type */
debug3("key_read: type mismatch");
- return 0;
+ return -1;
}
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("key_read: uudecode %s failed", cp);
+ xfree(blob);
return -1;
}
k = key_from_blob(blob, n);
+ xfree(blob);
if (k == NULL) {
error("key_read: key_from_blob %s failed", cp);
return -1;
}
- xfree(blob);
if (k->type != type) {
error("key_read: type mismatch: encoding error");
key_free(k);
@@ -454,9 +470,9 @@ key_read(Key *ret, char **cpp)
#endif
}
/*XXXX*/
+ key_free(k);
if (success != 1)
break;
- key_free(k);
/* advance cp: skip whitespace and data */
while (*cp == ' ' || *cp == '\t')
cp++;
@@ -473,8 +489,9 @@ key_read(Key *ret, char **cpp)
int
key_write(Key *key, FILE *f)
{
- int success = 0;
- u_int bits = 0;
+ int n, success = 0;
+ u_int len, bits = 0;
+ u_char *blob, *uu;
if (key->type == KEY_RSA1 && key->rsa != NULL) {
/* size of modulus 'n' */
@@ -488,8 +505,6 @@ key_write(Key *key, FILE *f)
}
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
- int len, n;
- u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
@@ -532,7 +547,8 @@ key_ssh_name(Key *k)
return "ssh-unknown";
}
u_int
-key_size(Key *k){
+key_size(Key *k)
+{
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -545,7 +561,7 @@ key_size(Key *k){
return 0;
}
-RSA *
+static RSA *
rsa_generate_private_key(u_int bits)
{
RSA *private;
@@ -555,7 +571,7 @@ rsa_generate_private_key(u_int bits)
return private;
}
-DSA*
+static DSA*
dsa_generate_private_key(u_int bits)
{
DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
@@ -615,15 +631,15 @@ key_from_private(Key *k)
int
key_type_from_name(char *name)
{
- if (strcmp(name, "rsa1") == 0){
+ if (strcmp(name, "rsa1") == 0) {
return KEY_RSA1;
- } else if (strcmp(name, "rsa") == 0){
+ } else if (strcmp(name, "rsa") == 0) {
return KEY_RSA;
- } else if (strcmp(name, "dsa") == 0){
+ } else if (strcmp(name, "dsa") == 0) {
return KEY_DSA;
- } else if (strcmp(name, "ssh-rsa") == 0){
+ } else if (strcmp(name, "ssh-rsa") == 0) {
return KEY_RSA;
- } else if (strcmp(name, "ssh-dss") == 0){
+ } else if (strcmp(name, "ssh-dss") == 0) {
return KEY_DSA;
}
debug2("key_type_from_name: unknown key type '%s'", name);
@@ -639,7 +655,7 @@ key_names_valid2(const char *names)
return 0;
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
- (p = strsep(&cp, ","))) {
+ (p = strsep(&cp, ","))) {
switch (key_type_from_name(p)) {
case KEY_RSA1:
case KEY_UNSPEC:
@@ -653,7 +669,7 @@ key_names_valid2(const char *names)
}
Key *
-key_from_blob(char *blob, int blen)
+key_from_blob(u_char *blob, int blen)
{
Buffer b;
char *ktype;
@@ -668,7 +684,7 @@ key_from_blob(char *blob, int blen)
ktype = buffer_get_string(&b, NULL);
type = key_type_from_name(ktype);
- switch(type){
+ switch (type) {
case KEY_RSA:
key = key_new(type);
buffer_get_bignum2(&b, key->rsa->e);
@@ -714,7 +730,7 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
return 0;
}
buffer_init(&b);
- switch(key->type){
+ switch (key->type) {
case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p);
@@ -728,8 +744,9 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
buffer_put_bignum2(&b, key->rsa->n);
break;
default:
- error("key_to_blob: illegal key type %d", key->type);
- break;
+ error("key_to_blob: unsupported key type %d", key->type);
+ buffer_free(&b);
+ return 0;
}
len = buffer_len(&b);
buf = xmalloc(len);
@@ -746,10 +763,10 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
int
key_sign(
Key *key,
- u_char **sigp, int *lenp,
- u_char *data, int datalen)
+ u_char **sigp, u_int *lenp,
+ u_char *data, u_int datalen)
{
- switch(key->type){
+ switch (key->type) {
case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen);
break;
@@ -766,10 +783,13 @@ key_sign(
int
key_verify(
Key *key,
- u_char *signature, int signaturelen,
- u_char *data, int datalen)
+ u_char *signature, u_int signaturelen,
+ u_char *data, u_int datalen)
{
- switch(key->type){
+ if (signaturelen == 0)
+ return -1;
+
+ switch (key->type) {
case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen);
break;
diff --git a/crypto/openssh/packet.h b/crypto/openssh/packet.h
index 09dd995..deaf81c 100644
--- a/crypto/openssh/packet.h
+++ b/crypto/openssh/packet.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: packet.h,v 1.33 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -11,191 +14,69 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef PACKET_H
#define PACKET_H
#include <openssl/bn.h>
-/*
- * Sets the socket used for communication. Disables encryption until
- * packet_set_encryption_key is called. It is permissible that fd_in and
- * 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);
-
-/* Puts the connection file descriptors into non-blocking mode. */
-void packet_set_nonblocking(void);
-
-/* Returns the file descriptor used for input. */
-int packet_get_connection_in(void);
-
-/* Returns the file descriptor used for output. */
-int packet_get_connection_out(void);
-
-/*
- * Closes the connection (both descriptors) and clears and frees internal
- * data structures.
- */
-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 are
- * encrypted independently of each other. Cipher types are defined in ssh.h.
- */
-void
-packet_set_encryption_key(const u_char *key, u_int keylen,
- int cipher_type);
-
-/*
- * Sets remote side protocol flags for the current connection. This can be
- * called at any time.
- */
-void packet_set_protocol_flags(u_int flags);
-
-/* Returns the remote protocol flags set earlier by the above function. */
-u_int packet_get_protocol_flags(void);
-
-/* Enables compression in both directions starting from the next packet. */
-void packet_start_compression(int level);
-
-/*
- * Informs that the current session is interactive. Sets IP flags for
- * optimal performance in interactive use.
- */
-void packet_set_interactive(int interactive);
-
-/* Returns true if the current connection is interactive. */
-int packet_is_interactive(void);
-
-/* Starts constructing a packet to send. */
-void packet_start(int type);
-
-/* Appends a character to the packet data. */
-void packet_put_char(int ch);
-
-/* Appends an integer to the packet data. */
-void packet_put_int(u_int value);
-
-/* Appends an arbitrary precision integer to packet data. */
-void packet_put_bignum(BIGNUM * value);
-void packet_put_bignum2(BIGNUM * value);
-
-/* Appends a string to packet data. */
-void packet_put_string(const char *buf, u_int len);
-void packet_put_cstring(const char *str);
-void packet_put_raw(const char *buf, u_int len);
-
-/*
- * Finalizes and sends the packet. If the encryption key has been set,
- * encrypts the packet before sending.
- */
-void packet_send(void);
-
-/* Waits until a packet has been received, and returns its type. */
-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.
- */
-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
- * SSH_MSG_NONE. This does not wait for data from the connection.
- * SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
- * messages are skipped by this function and are never returned to higher
- * levels.
- */
-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.
- */
-void packet_process_incoming(const char *buf, u_int len);
-
-/* Returns a character (0-255) from the packet data. */
-u_int packet_get_char(void);
-
-/* Returns an integer from the packet data. */
-u_int packet_get_int(void);
-
-/*
- * 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_bignum2(BIGNUM * value, int *length_ptr);
-char *packet_get_raw(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
- * 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(u_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.
- * 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,...) __attribute__((format(printf, 1, 2)));
-
-/*
- * Sends a diagnostic message to the other side. This message can be sent at
- * any time (but not while constructing another message). The message is
- * printed immediately, but only if the client is being executed in verbose
- * mode. These messages are primarily intended to ease debugging
- * authentication problems. The total length of the message must not exceed
- * 1024 bytes. This will automatically call packet_write_wait. If the
- * remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
- * this will do nothing.
- */
-void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
-
-/* Checks if there is any buffered output, and tries to write some of the output. */
-void packet_write_poll(void);
-
-/* Waits until all pending output data has been written. */
-void packet_write_wait(void);
+void packet_set_connection(int, int);
+void packet_set_nonblocking(void);
+int packet_get_connection_in(void);
+int packet_get_connection_out(void);
+void packet_close(void);
+void packet_set_encryption_key(const u_char *, u_int, int);
+void packet_set_protocol_flags(u_int);
+u_int packet_get_protocol_flags(void);
+void packet_start_compression(int);
+void packet_set_interactive(int);
+int packet_is_interactive(void);
+
+void packet_start(u_char);
+void packet_put_char(int ch);
+void packet_put_int(u_int value);
+void packet_put_bignum(BIGNUM * value);
+void packet_put_bignum2(BIGNUM * value);
+void packet_put_string(const void *buf, u_int len);
+void packet_put_cstring(const char *str);
+void packet_put_raw(const void *buf, u_int len);
+void packet_send(void);
+
+int packet_read(void);
+void packet_read_expect(int type);
+int packet_read_poll(void);
+void packet_process_incoming(const char *buf, u_int len);
+int packet_read_seqnr(u_int32_t *seqnr_p);
+int packet_read_poll_seqnr(u_int32_t *seqnr_p);
+
+u_int packet_get_char(void);
+u_int packet_get_int(void);
+void packet_get_bignum(BIGNUM * value);
+void packet_get_bignum2(BIGNUM * value);
+void *packet_get_raw(int *length_ptr);
+void *packet_get_string(u_int *length_ptr);
+void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+
+void packet_write_poll(void);
+void packet_write_wait(void);
+int packet_have_data_to_write(void);
+int packet_not_very_much_data_to_write(void);
+
+int packet_connection_is_on_socket(void);
+int packet_connection_is_ipv4(void);
+int packet_remaining(void);
+void packet_send_ignore(int);
+void packet_add_padding(u_char);
+
+void tty_make_modes(int, struct termios *);
+void tty_parse_modes(int, int *);
-/* Returns true if there is buffered data to write to the connection. */
-int packet_have_data_to_write(void);
-
-/* Returns true if there is not too much data to write to the connection. */
-int packet_not_very_much_data_to_write(void);
-
-/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */
extern int max_packet_size;
-int packet_set_maxsize(int s);
-#define packet_get_maxsize() max_packet_size
-
-/* Stores tty modes from the fd or tiop into current packet. */
-void tty_make_modes(int fd, struct termios *tiop);
-
-/* Parses tty modes for the fd from the current packet. */
-void tty_parse_modes(int fd, int *n_bytes_ptr);
+int packet_set_maxsize(int);
+#define packet_get_maxsize() max_packet_size
-#define packet_integrity_check(payload_len, expected_len, type) \
-do { \
- int _p = (payload_len), _e = (expected_len); \
- if (_p != _e) { \
- log("Packet integrity error (%d != %d) at %s:%d", \
- _p, _e, __FILE__, __LINE__); \
- packet_disconnect("Packet integrity error. (%d)", (type)); \
- } \
-} while (0)
-
-#define packet_done() \
+/* don't allow remaining bytes after the end of the message */
+#define packet_check_eom() \
do { \
int _len = packet_remaining(); \
if (_len > 0) { \
@@ -205,20 +86,4 @@ do { \
} \
} while (0)
-/* remote host is connected via a socket/ipv4 */
-int packet_connection_is_on_socket(void);
-int packet_connection_is_ipv4(void);
-
-/* enable SSH2 packet format */
-void packet_set_ssh2_format(void);
-
-/* returns remaining payload bytes */
-int packet_remaining(void);
-
-/* append an ignore message */
-void packet_send_ignore(int nbytes);
-
-/* add an ignore message and make sure size (current+ignore) = n*sumlen */
-void packet_inject_ignore(int sumlen);
-
#endif /* PACKET_H */
diff --git a/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h
index 0b0f2d3..8dde2a3 100644
--- a/crypto/openssh/pathnames.h
+++ b/crypto/openssh/pathnames.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
+/* $OpenBSD: pathnames.h,v 1.11 2002/02/09 17:37:34 deraadt Exp $ */
/* $FreeBSD$ */
/*
@@ -13,26 +13,30 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-#define ETCDIR "/etc/ssh"
+#define ETCDIR "/etc"
+#define SSHDIR ETCDIR "/ssh"
#define _PATH_SSH_PIDDIR "/var/run"
/*
* System-wide file containing host keys of known hosts. This file should be
* world-readable.
*/
-#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
-#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
+#define _PATH_SSH_SYSTEM_HOSTFILE SSHDIR "/ssh_known_hosts"
+/* backward compat for protocol 2 */
+#define _PATH_SSH_SYSTEM_HOSTFILE2 SSHDIR "/ssh_known_hosts2"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
* should be world-readable.
*/
-#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
-#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
-#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
-#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
-#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
-#define _PATH_DH_PRIMES ETCDIR "/primes"
+#define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config"
+#define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config"
+#define _PATH_HOST_KEY_FILE SSHDIR "/ssh_host_key"
+#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key"
+#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
+#define _PATH_DH_MODULI SSHDIR "/moduli"
+/* Backwards compatibility */
+#define _PATH_DH_PRIMES SSHDIR "/primes"
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
@@ -54,6 +58,7 @@
* contain anything particularly secret.
*/
#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
+/* backward compat for protocol 2 */
#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
@@ -81,6 +86,8 @@
* running as root.)
*/
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
+
+/* backward compat for protocol v2 */
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
@@ -90,13 +97,13 @@
* use. xauth will be run if neither of these exists.
*/
#define _PATH_SSH_USER_RC ".ssh/rc"
-#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
+#define _PATH_SSH_SYSTEM_RC SSHDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
-#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
+#define _PATH_SSH_HOSTS_EQUIV SSHDIR "/shosts.equiv"
#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv"
/*
@@ -104,6 +111,12 @@
*/
#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
+/* xauth for X11 forwarding */
+#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
+
+/* UNIX domain socket for X11 server; displaynum will replace %u */
+#define _PATH_UNIX_X "/tmp/.X11-unix/X%u"
+
/* for scp */
#define _PATH_CP "cp"
diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c
index 47b4b48..5e755ad 100644
--- a/crypto/openssh/readconf.c
+++ b/crypto/openssh/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.76 2001/04/17 10:53:25 markus Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.95 2002/02/04 12:15:25 markus Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
@@ -99,12 +99,12 @@ typedef enum {
oChallengeResponseAuthentication, oXAuthLocation,
#if defined(KRB4) || defined(KRB5)
oKerberosAuthentication,
-#endif /* KRB4 */
-#ifdef KRB5
- oKrb5TgtPassing,
-#endif /* KRB5 */
+#endif
+#if defined(AFS) || defined(KRB5)
+ oKerberosTgtPassing,
+#endif
#ifdef AFS
- oKrb4TgtPassing, oAFSTokenPassing,
+ oAFSTokenPassing,
#endif
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
@@ -115,7 +115,8 @@ typedef enum {
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
- oHostKeyAlgorithms
+ oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
+ oClearAllForwardings, oNoHostAuthenticationForLocalhost
} OpCodes;
/* Textual representations of the tokens. */
@@ -143,12 +144,11 @@ static struct {
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
#if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", oKerberosAuthentication },
-#endif /* KRB4 || KRB5 */
-#ifdef KRB5
- { "kerberos5tgtpassing", oKrb5TgtPassing },
-#endif /* KRB5 */
+#endif
+#if defined(AFS) || defined(KRB5)
+ { "kerberostgtpassing", oKerberosTgtPassing },
+#endif
#ifdef AFS
- { "kerberos4tgtpassing", oKrb4TgtPassing },
{ "afstokenpassing", oAFSTokenPassing },
#endif
{ "fallbacktorsh", oFallBackToRsh },
@@ -169,9 +169,9 @@ static struct {
{ "host", oHost },
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
- { "userknownhostsfile", oUserKnownHostsFile },
+ { "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
- { "userknownhostsfile2", oUserKnownHostsFile2 },
+ { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
@@ -184,7 +184,11 @@ static struct {
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
- { NULL, 0 }
+ { "bindaddress", oBindAddress },
+ { "smartcarddevice", oSmartcardDevice },
+ { "clearallforwardings", oClearAllForwardings },
+ { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+ { NULL, oBadOption }
};
/*
@@ -220,13 +224,26 @@ add_remote_forward(Options *options, u_short port, const char *host,
Forward *fwd;
if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many remote forwards (max %d).",
- SSH_MAX_FORWARDS_PER_DIRECTION);
+ SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->remote_forwards[options->num_remote_forwards++];
fwd->port = port;
fwd->host = xstrdup(host);
fwd->host_port = host_port;
}
+static void
+clear_forwardings(Options *options)
+{
+ int i;
+
+ for (i = 0; i < options->num_local_forwards; i++)
+ xfree(options->local_forwards[i].host);
+ options->num_local_forwards = 0;
+ for (i = 0; i < options->num_remote_forwards; i++)
+ xfree(options->remote_forwards[i].host);
+ options->num_remote_forwards = 0;
+}
+
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@@ -258,6 +275,7 @@ process_config_line(Options *options, const char *host,
char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
int opcode, *intptr, value;
u_short fwd_port, fwd_host_port;
+ char sfwd_host_port[6];
s = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
@@ -336,32 +354,24 @@ parse_flag:
intptr = &options->hostbased_authentication;
goto parse_flag;
+ case oChallengeResponseAuthentication:
+ intptr = &options->challenge_response_authentication;
+ goto parse_flag;
#if defined(KRB4) || defined(KRB5)
case oKerberosAuthentication:
intptr = &options->kerberos_authentication;
goto parse_flag;
-#endif /* KRB4 || KRB5 */
-
- case oChallengeResponseAuthentication:
- intptr = &options->challenge_reponse_authentication;
- goto parse_flag;
-
-#ifdef KRB5
- case oKrb5TgtPassing:
- intptr = &options->krb5_tgt_passing;
+#endif
+#if defined(AFS) || defined(KRB5)
+ case oKerberosTgtPassing:
+ intptr = &options->kerberos_tgt_passing;
goto parse_flag;
-#endif /* KRB5 */
-
+#endif
#ifdef AFS
- case oKrb4TgtPassing:
- intptr = &options->krb4_tgt_passing;
- goto parse_flag;
-
case oAFSTokenPassing:
intptr = &options->afs_token_passing;
goto parse_flag;
#endif
-
case oFallBackToRsh:
intptr = &options->fallback_to_rsh;
goto parse_flag;
@@ -383,7 +393,7 @@ parse_flag:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no/ask argument.",
- filename, linenum);
+ filename, linenum);
value = 0; /* To avoid compiler warning... */
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1;
@@ -405,6 +415,10 @@ parse_flag:
intptr = &options->keepalives;
goto parse_flag;
+ case oNoHostAuthenticationForLocalhost:
+ intptr = &options->no_host_authentication_for_localhost;
+ goto parse_flag;
+
case oNumberOfPasswordPrompts:
intptr = &options->number_of_password_prompts;
goto parse_int;
@@ -421,7 +435,7 @@ parse_flag:
intptr = &options->num_identity_files;
if (*intptr >= SSH_MAX_IDENTITY_FILES)
fatal("%.200s line %d: Too many identity files specified (max %d).",
- filename, linenum, SSH_MAX_IDENTITY_FILES);
+ filename, linenum, SSH_MAX_IDENTITY_FILES);
charptr = &options->identity_files[*intptr];
*charptr = xstrdup(arg);
*intptr = *intptr + 1;
@@ -470,6 +484,14 @@ parse_string:
charptr = &options->preferred_authentications;
goto parse_string;
+ case oBindAddress:
+ charptr = &options->bind_address;
+ goto parse_string;
+
+ case oSmartcardDevice:
+ charptr = &options->smartcard_device;
+ goto parse_string;
+
case oProxyCommand:
charptr = &options->proxy_command;
string = xstrdup("");
@@ -513,7 +535,7 @@ parse_int:
value = cipher_number(arg);
if (value == -1)
fatal("%.200s line %d: Bad cipher '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -524,7 +546,7 @@ parse_int:
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!ciphers_valid(arg))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
@@ -535,7 +557,7 @@ parse_int:
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
@@ -546,7 +568,7 @@ parse_int:
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!key_names_valid2(arg))
fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->hostkeyalgorithms == NULL)
options->hostkeyalgorithms = xstrdup(arg);
break;
@@ -559,7 +581,7 @@ parse_int:
value = proto_spec(arg);
if (value == SSH_PROTO_UNKNOWN)
fatal("%.200s line %d: Bad protocol spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
*intptr = value;
break;
@@ -568,49 +590,41 @@ parse_int:
intptr = (int *) &options->log_level;
arg = strdelim(&s);
value = log_level_number(arg);
- if (value == (LogLevel) - 1)
+ if (value == SYSLOG_LEVEL_NOT_SET)
fatal("%.200s line %d: unsupported log level '%s'",
- filename, linenum, arg ? arg : "<NONE>");
- if (*activep && (LogLevel) * intptr == -1)
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
*intptr = (LogLevel) value;
break;
- case oRemoteForward:
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- fwd_port = a2port(arg);
- if (fwd_port == 0)
- fatal("%.200s line %d: Badly formatted port number.",
- filename, linenum);
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing second argument.",
- filename, linenum);
- if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
- fatal("%.200s line %d: Badly formatted host:port.",
- filename, linenum);
- if (*activep)
- add_remote_forward(options, fwd_port, buf, fwd_host_port);
- break;
-
case oLocalForward:
+ case oRemoteForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- fwd_port = a2port(arg);
- if (fwd_port == 0)
- fatal("%.200s line %d: Badly formatted port number.",
- filename, linenum);
+ fatal("%.200s line %d: Missing port argument.",
+ filename, linenum);
+ if ((fwd_port = a2port(arg)) == 0)
+ fatal("%.200s line %d: Bad listen port.",
+ filename, linenum);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
- filename, linenum);
- if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
- fatal("%.200s line %d: Badly formatted host:port.",
- filename, linenum);
- if (*activep)
- add_local_forward(options, fwd_port, buf, fwd_host_port);
+ filename, linenum);
+ if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
+ sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
+ fatal("%.200s line %d: Bad forwarding specification.",
+ filename, linenum);
+ if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
+ fatal("%.200s line %d: Bad forwarding port.",
+ filename, linenum);
+ if (*activep) {
+ if (opcode == oLocalForward)
+ add_local_forward(options, fwd_port, buf,
+ fwd_host_port);
+ else if (opcode == oRemoteForward)
+ add_remote_forward(options, fwd_port, buf,
+ fwd_host_port);
+ }
break;
case oDynamicForward:
@@ -622,9 +636,14 @@ parse_int:
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
- add_local_forward(options, fwd_port, "socks4", 0);
+ if (*activep)
+ add_local_forward(options, fwd_port, "socks4", 0);
break;
+ case oClearAllForwardings:
+ intptr = &options->clear_forwardings;
+ goto parse_flag;
+
case oHost:
*activep = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@@ -647,10 +666,10 @@ parse_int:
else if (strlen(arg) == 1)
value = (u_char) arg[0];
else if (strcmp(arg, "none") == 0)
- value = -2;
+ value = SSH_ESCAPECHAR_NONE;
else {
fatal("%.200s line %d: Bad escape character.",
- filename, linenum);
+ filename, linenum);
/* NOTREACHED */
value = 0; /* Avoid compiler warning. */
}
@@ -665,7 +684,7 @@ parse_int:
/* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
- filename, linenum, arg);
+ filename, linenum, arg);
}
return 0;
}
@@ -674,10 +693,10 @@ parse_int:
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
- * there is an error. If the file does not exist, this returns immediately.
+ * there is an error. If the file does not exist, this returns 0.
*/
-void
+int
read_config_file(const char *filename, const char *host, Options *options)
{
FILE *f;
@@ -688,7 +707,7 @@ read_config_file(const char *filename, const char *host, Options *options)
/* Open the file. */
f = fopen(filename, "r");
if (!f)
- return;
+ return 0;
debug("Reading configuration data %.200s", filename);
@@ -707,7 +726,8 @@ read_config_file(const char *filename, const char *host, Options *options)
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
- filename, bad_options);
+ filename, bad_options);
+ return 1;
}
/*
@@ -729,15 +749,14 @@ initialize_options(Options * options)
options->rhosts_authentication = -1;
options->rsa_authentication = -1;
options->pubkey_authentication = -1;
- options->challenge_reponse_authentication = -1;
+ options->challenge_response_authentication = -1;
#if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1;
#endif
-#ifdef KRB5
- options->krb5_tgt_passing = -1;
-#endif /* KRB5 */
+#if defined(AFS) || defined(KRB5)
+ options->kerberos_tgt_passing = -1;
+#endif
#ifdef AFS
- options->krb4_tgt_passing = -1;
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
@@ -773,8 +792,12 @@ initialize_options(Options * options)
options->user_hostfile2 = NULL;
options->num_local_forwards = 0;
options->num_remote_forwards = 0;
- options->log_level = (LogLevel) - 1;
+ options->clear_forwardings = -1;
+ options->log_level = SYSLOG_LEVEL_NOT_SET;
options->preferred_authentications = NULL;
+ options->bind_address = NULL;
+ options->smartcard_device = NULL;
+ options->no_host_authentication_for_localhost = - 1;
}
/*
@@ -791,10 +814,8 @@ fill_default_options(Options * options)
options->forward_agent = 0;
if (options->forward_x11 == -1)
options->forward_x11 = 0;
-#ifdef XAUTH_PATH
if (options->xauth_location == NULL)
- options->xauth_location = XAUTH_PATH;
-#endif /* XAUTH_PATH */
+ options->xauth_location = _PATH_XAUTH;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->use_privileged_port == -1)
@@ -805,22 +826,20 @@ fill_default_options(Options * options)
options->rsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
- if (options->challenge_reponse_authentication == -1)
- options->challenge_reponse_authentication = 0;
+ if (options->challenge_response_authentication == -1)
+ options->challenge_response_authentication = 1;
#if defined(KRB4) || defined(KRB5)
if (options->kerberos_authentication == -1)
options->kerberos_authentication = 1;
-#endif /* KRB4 || KRB5 */
-#ifdef KRB5
- if (options->krb5_tgt_passing == -1)
- options->krb5_tgt_passing = 1;
-#endif /* KRB5 */
+#endif
+#if defined(AFS) || defined(KRB5)
+ if (options->kerberos_tgt_passing == -1)
+ options->kerberos_tgt_passing = 1;
+#endif
#ifdef AFS
- if (options->krb4_tgt_passing == -1)
- options->krb4_tgt_passing = 1;
if (options->afs_token_passing == -1)
options->afs_token_passing = 1;
-#endif /* AFS */
+#endif
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
@@ -848,7 +867,7 @@ fill_default_options(Options * options)
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->connection_attempts == -1)
- options->connection_attempts = 4;
+ options->connection_attempts = 1;
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
/* Selected in ssh_login(). */
@@ -891,8 +910,12 @@ fill_default_options(Options * options)
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL)
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
- if (options->log_level == (LogLevel) - 1)
+ if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
+ if (options->clear_forwardings == 1)
+ clear_forwardings(options);
+ if (options->no_host_authentication_for_localhost == - 1)
+ options->no_host_authentication_for_localhost = 0;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h
index f429f76..c310137 100644
--- a/crypto/openssh/readconf.h
+++ b/crypto/openssh/readconf.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: readconf.h,v 1.42 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -11,9 +14,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef READCONF_H
#define READCONF_H
@@ -40,19 +40,15 @@ typedef struct {
int rsa_authentication; /* Try RSA authentication. */
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int hostbased_authentication; /* ssh2's rhosts_rsa */
- int challenge_reponse_authentication;
+ int challenge_response_authentication;
/* Try S/Key or TIS, authentication. */
#if defined(KRB4) || defined(KRB5)
- int kerberos_authentication; /* Try Kerberos
- * authentication. */
+ int kerberos_authentication; /* Try Kerberos authentication. */
+#endif
+#if defined(AFS) || defined(KRB5)
+ int kerberos_tgt_passing; /* Try Kerberos TGT passing. */
#endif
-
-#ifdef KRB5
- int krb5_tgt_passing;
-#endif /* KRB5 */
-
#ifdef AFS
- int krb4_tgt_passing; /* Try Kerberos v4 tgt passing. */
int afs_token_passing; /* Try AFS token passing. */
#endif
int password_authentication; /* Try password
@@ -86,11 +82,13 @@ typedef struct {
char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */
- char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
+ char *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2;
char *user_hostfile2;
char *preferred_authentications;
+ char *bind_address; /* local socket address for connection to sshd */
+ char *smartcard_device; /* Smartcard reader device */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
@@ -103,56 +101,19 @@ typedef struct {
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+ int clear_forwardings;
+ int no_host_authentication_for_localhost;
} 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. Options
- * 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);
-
-/*
- * 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 initialize_options(Options *);
+void fill_default_options(Options *);
+int read_config_file(const char *, const char *, Options *);
-/*
- * Processes a single option line as used in the configuration files. This
- * only sets those values that have not already been set. Returns 0 for legal
- * options
- */
int
-process_config_line(Options * options, const char *host,
- char *line, const char *filename, int linenum,
- int *activep);
-
-/*
- * Reads the config file and modifies the options accordingly. Options
- * 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
-read_config_file(const char *filename, const char *host,
- Options * options);
+process_config_line(Options *, const char *, char *, const char *, int, int *);
-/*
- * Adds a local TCP/IP port forward to options. Never returns if there is an
- * error.
- */
-void
-add_local_forward(Options * options, u_short port, const char *host,
- u_short host_port);
-
-/*
- * Adds a remote TCP/IP port forward to options. Never returns if there is
- * an error.
- */
-void
-add_remote_forward(Options * options, u_short port, const char *host,
- u_short host_port);
+void add_local_forward(Options *, u_short, const char *, u_short);
+void add_remote_forward(Options *, u_short, const char *, u_short);
#endif /* READCONF_H */
diff --git a/crypto/openssh/rijndael.c b/crypto/openssh/rijndael.c
index a5d6804..fa05e4c 100644
--- a/crypto/openssh/rijndael.c
+++ b/crypto/openssh/rijndael.c
@@ -1,4 +1,5 @@
/* $OpenBSD: rijndael.c,v 1.13 2001/12/19 07:18:56 deraadt Exp $ */
+/* $FreeBSD$ */
/**
* rijndael-alg-fst.c
@@ -25,6 +26,7 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
diff --git a/crypto/openssh/rsa.c b/crypto/openssh/rsa.c
index 357272b..ae936f0 100644
--- a/crypto/openssh/rsa.c
+++ b/crypto/openssh/rsa.c
@@ -60,7 +60,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: rsa.c,v 1.22 2001/03/26 23:23:23 markus Exp $");
+RCSID("$OpenBSD: rsa.c,v 1.24 2001/12/27 18:22:16 markus Exp $");
RCSID("$FreeBSD$");
#include "rsa.h"
@@ -121,14 +121,17 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
return len;
}
+/* calculate p-1 and q-1 */
void
-generate_additional_parameters(RSA *rsa)
+rsa_generate_additional_parameters(RSA *rsa)
{
BIGNUM *aux;
BN_CTX *ctx;
- /* Generate additional parameters */
- aux = BN_new();
- ctx = BN_CTX_new();
+
+ if ((aux = BN_new()) == NULL)
+ fatal("rsa_generate_additional_parameters: BN_new failed");
+ if ((ctx = BN_CTX_new()) == NULL)
+ fatal("rsa_generate_additional_parameters: BN_CTX_new failed");
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
diff --git a/crypto/openssh/rsa.h b/crypto/openssh/rsa.h
index f5e0c96..5ea6e28 100644
--- a/crypto/openssh/rsa.h
+++ b/crypto/openssh/rsa.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: rsa.h,v 1.15 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -11,18 +14,14 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef RSA_H
#define RSA_H
#include <openssl/bn.h>
#include <openssl/rsa.h>
-void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
-int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
-
-void generate_additional_parameters __P((RSA *rsa));
+void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
+int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
+void rsa_generate_additional_parameters(RSA *);
#endif /* RSA_H */
diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c
index 17bdbc5..ac806c6 100644
--- a/crypto/openssh/servconf.c
+++ b/crypto/openssh/servconf.c
@@ -10,10 +10,10 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.78 2001/04/15 21:28:35 stevesk Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.101 2002/02/04 12:15:25 markus Exp $");
RCSID("$FreeBSD$");
-#ifdef KRB4
+#if defined(KRB4) || defined(KRB5)
#include <krb.h>
#endif
#ifdef AFS
@@ -32,8 +32,8 @@ RCSID("$FreeBSD$");
#include "kex.h"
#include "mac.h"
-void add_listen_addr(ServerOptions *options, char *addr, u_short port);
-void add_one_listen_addr(ServerOptions *options, char *addr, u_short port);
+static void add_listen_addr(ServerOptions *, char *, u_short);
+static void add_one_listen_addr(ServerOptions *, char *, u_short);
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
@@ -57,14 +57,14 @@ initialize_server_options(ServerOptions *options)
options->ignore_user_known_hosts = -1;
options->print_motd = -1;
options->print_lastlog = -1;
- options->check_mail = -1;
options->x11_forwarding = -1;
options->x11_display_offset = -1;
+ options->x11_use_localhost = -1;
options->xauth_location = NULL;
options->strict_modes = -1;
options->keepalives = -1;
- options->log_facility = (SyslogFacility) - 1;
- options->log_level = (LogLevel) - 1;
+ options->log_facility = SYSLOG_FACILITY_NOT_SET;
+ options->log_level = SYSLOG_LEVEL_NOT_SET;
options->rhosts_authentication = -1;
options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
@@ -73,21 +73,18 @@ initialize_server_options(ServerOptions *options)
options->pubkey_authentication = -1;
#if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1;
+ options->kerberos_or_local_passwd = -1;
+ options->kerberos_ticket_cleanup = -1;
#endif
-#ifdef KRB4
- options->krb4_or_local_passwd = -1;
- options->krb4_ticket_cleanup = -1;
+#if defined(AFS) || defined(KRB5)
+ options->kerberos_tgt_passing = -1;
#endif
-#ifdef KRB5
- options->krb5_tgt_passing = -1;
-#endif /* KRB5 */
#ifdef AFS
- options->krb4_tgt_passing = -1;
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
- options->challenge_reponse_authentication = -1;
+ options->challenge_response_authentication = -1;
options->permit_empty_passwd = -1;
options->use_login = -1;
options->allow_tcp_forwarding = -1;
@@ -99,16 +96,17 @@ initialize_server_options(ServerOptions *options)
options->macs = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->gateway_ports = -1;
- options->connections_per_period = 0;
options->connections_period = 0;
options->num_subsystems = 0;
options->max_startups_begin = -1;
options->max_startups_rate = -1;
options->max_startups = -1;
options->banner = NULL;
- options->reverse_mapping_check = -1;
+ options->verify_reverse_mapping = -1;
options->client_alive_interval = -1;
options->client_alive_count_max = -1;
+ options->authorized_keys_file = NULL;
+ options->authorized_keys_file2 = NULL;
}
void
@@ -119,9 +117,14 @@ fill_default_server_options(ServerOptions *options)
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
if (options->protocol & SSH_PROTO_1)
- options->host_key_files[options->num_host_key_files++] = _PATH_HOST_KEY_FILE;
- if (options->protocol & SSH_PROTO_2)
- options->host_key_files[options->num_host_key_files++] = _PATH_HOST_DSA_KEY_FILE;
+ options->host_key_files[options->num_host_key_files++] =
+ _PATH_HOST_KEY_FILE;
+ if (options->protocol & SSH_PROTO_2) {
+ options->host_key_files[options->num_host_key_files++] =
+ _PATH_HOST_RSA_KEY_FILE;
+ options->host_key_files[options->num_host_key_files++] =
+ _PATH_HOST_DSA_KEY_FILE;
+ }
}
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
@@ -151,17 +154,17 @@ fill_default_server_options(ServerOptions *options)
options->x11_forwarding = 1;
if (options->x11_display_offset == -1)
options->x11_display_offset = 10;
-#ifdef XAUTH_PATH
+ if (options->x11_use_localhost == -1)
+ options->x11_use_localhost = 1;
if (options->xauth_location == NULL)
- options->xauth_location = XAUTH_PATH;
-#endif /* XAUTH_PATH */
+ options->xauth_location = _PATH_XAUTH;
if (options->strict_modes == -1)
options->strict_modes = 1;
if (options->keepalives == -1)
options->keepalives = 1;
- if (options->log_facility == (SyslogFacility) (-1))
+ if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
options->log_facility = SYSLOG_FACILITY_AUTH;
- if (options->log_level == (LogLevel) (-1))
+ if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
if (options->rhosts_authentication == -1)
options->rhosts_authentication = 0;
@@ -175,39 +178,28 @@ fill_default_server_options(ServerOptions *options)
options->rsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
-#if defined(KRB4) && defined(KRB5)
- if (options->kerberos_authentication == -1)
- options->kerberos_authentication =
- (access(KEYFILE, R_OK) == 0) || (access(krb5_defkeyname, R_OK) == 0);
-#elif defined(KRB4)
+#if defined(KRB4) || defined(KRB5)
if (options->kerberos_authentication == -1)
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
-#elif defined(KRB5)
- if (options->kerberos_authentication == -1)
- options->kerberos_authentication = (access(krb5_defkeyname, R_OK) == 0);
+ if (options->kerberos_or_local_passwd == -1)
+ options->kerberos_or_local_passwd = 1;
+ if (options->kerberos_ticket_cleanup == -1)
+ options->kerberos_ticket_cleanup = 1;
+#endif
+#if defined(AFS) || defined(KRB5)
+ if (options->kerberos_tgt_passing == -1)
+ options->kerberos_tgt_passing = 0;
#endif
-#ifdef KRB4
- if (options->krb4_or_local_passwd == -1)
- options->krb4_or_local_passwd = 1;
- if (options->krb4_ticket_cleanup == -1)
- options->krb4_ticket_cleanup = 1;
-#endif /* KRB4 */
-#ifdef KRB5
- if (options->krb5_tgt_passing == -1)
- options->krb5_tgt_passing = 1;
-#endif /* KRB5 */
#ifdef AFS
- if (options->krb4_tgt_passing == -1)
- options->krb4_tgt_passing = 0;
if (options->afs_token_passing == -1)
options->afs_token_passing = k_hasafs();
-#endif /* AFS */
+#endif
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0;
- if (options->challenge_reponse_authentication == -1)
- options->challenge_reponse_authentication = 1;
+ if (options->challenge_response_authentication == -1)
+ options->challenge_response_authentication = 1;
if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0;
if (options->use_login == -1)
@@ -222,12 +214,21 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_rate = 100; /* 100% */
if (options->max_startups_begin == -1)
options->max_startups_begin = options->max_startups;
- if (options->reverse_mapping_check == -1)
- options->reverse_mapping_check = 0;
+ if (options->verify_reverse_mapping == -1)
+ options->verify_reverse_mapping = 0;
if (options->client_alive_interval == -1)
- options->client_alive_interval = 0;
+ options->client_alive_interval = 0;
if (options->client_alive_count_max == -1)
options->client_alive_count_max = 3;
+ if (options->authorized_keys_file2 == NULL) {
+ /* authorized_keys_file2 falls back to authorized_keys_file */
+ if (options->authorized_keys_file != NULL)
+ options->authorized_keys_file2 = options->authorized_keys_file;
+ else
+ options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
+ }
+ if (options->authorized_keys_file == NULL)
+ options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
}
/* Keyword tokens. */
@@ -237,29 +238,28 @@ typedef enum {
sPermitRootLogin, sLogFacility, sLogLevel,
sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
#if defined(KRB4) || defined(KRB5)
- sKerberosAuthentication,
+ sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
#endif
-#ifdef KRB4
- sKrb4OrLocalPasswd, sKrb4TicketCleanup,
+#if defined(AFS) || defined(KRB5)
+ sKerberosTgtPassing,
#endif
-#ifdef KRB5
- sKrb5TgtPassing,
-#endif /* KRB5 */
#ifdef AFS
- sKrb4TgtPassing, sAFSTokenPassing,
+ sAFSTokenPassing,
#endif
sChallengeResponseAuthentication,
sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
- sX11Forwarding, sX11DisplayOffset,
- sStrictModes, sEmptyPasswd, sKeepAlives, sCheckMail,
+ sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
+ sStrictModes, sEmptyPasswd, sKeepAlives,
sUseLogin, sAllowTcpForwarding,
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
- sBanner, sReverseMappingCheck, sHostbasedAuthentication,
- sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- sClientAliveCountMax, sVersionAddendum, sConnectionsPerPeriod
+ sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
+ sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+ sCheckMail, sVersionAddendum,
+ sDeprecated
} ServerOpCodes;
/* Textual representation of the tokens. */
@@ -281,28 +281,24 @@ static struct {
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
{ "hostbasedauthentication", sHostbasedAuthentication },
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
+ { "rsaauthentication", sRSAAuthentication },
{ "pubkeyauthentication", sPubkeyAuthentication },
{ "dsaauthentication", sPubkeyAuthentication }, /* alias */
- { "rsaauthentication", sRSAAuthentication },
#if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", sKerberosAuthentication },
+ { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
+ { "kerberosticketcleanup", sKerberosTicketCleanup },
#endif
-#ifdef KRB4
- { "kerberos4orlocalpasswd", sKrb4OrLocalPasswd },
- { "kerberos4ticketcleanup", sKrb4TicketCleanup },
+#if defined(AFS) || defined(KRB5)
+ { "kerberostgtpassing", sKerberosTgtPassing },
#endif
-#ifdef KRB5
- { "kerberos5tgtpassing", sKrb5TgtPassing },
-#endif /* KRB5 */
#ifdef AFS
- { "kerberos4tgtpassing", sKrb4TgtPassing },
{ "afstokenpassing", sAFSTokenPassing },
#endif
{ "passwordauthentication", sPasswordAuthentication },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
{ "challengeresponseauthentication", sChallengeResponseAuthentication },
{ "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
- { "checkmail", sCheckMail },
{ "listenaddress", sListenAddress },
{ "printmotd", sPrintMotd },
{ "printlastlog", sPrintLastLog },
@@ -310,6 +306,7 @@ static struct {
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
{ "x11forwarding", sX11Forwarding },
{ "x11displayoffset", sX11DisplayOffset },
+ { "x11uselocalhost", sX11UseLocalhost },
{ "xauthlocation", sXAuthLocation },
{ "strictmodes", sStrictModes },
{ "permitemptypasswords", sEmptyPasswd },
@@ -324,15 +321,18 @@ static struct {
{ "macs", sMacs },
{ "protocol", sProtocol },
{ "gatewayports", sGatewayPorts },
- { "connectionsperperiod", sConnectionsPerPeriod },
{ "subsystem", sSubsystem },
{ "maxstartups", sMaxStartups },
- { "versionaddendum", sVersionAddendum },
{ "banner", sBanner },
- { "reversemappingcheck", sReverseMappingCheck },
+ { "verifyreversemapping", sVerifyReverseMapping },
+ { "reversemappingcheck", sVerifyReverseMapping },
{ "clientaliveinterval", sClientAliveInterval },
{ "clientalivecountmax", sClientAliveCountMax },
- { NULL, 0 }
+ { "authorizedkeysfile", sAuthorizedKeysFile },
+ { "authorizedkeysfile2", sAuthorizedKeysFile2 },
+ { "checkmail", sCheckMail },
+ { "versionaddendum", sVersionAddendum },
+ { NULL, sBadOption }
};
/*
@@ -354,7 +354,7 @@ parse_token(const char *cp, const char *filename,
return sBadOption;
}
-void
+static void
add_listen_addr(ServerOptions *options, char *addr, u_short port)
{
int i;
@@ -368,7 +368,7 @@ add_listen_addr(ServerOptions *options, char *addr, u_short port)
add_one_listen_addr(options, addr, port);
}
-void
+static void
add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
{
struct addrinfo hints, *ai, *aitop;
@@ -390,479 +390,509 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
options->listen_addrs = aitop;
}
-/* Reads the server configuration file. */
-
-void
-read_server_config(ServerOptions *options, const char *filename)
+int
+process_server_config_line(ServerOptions *options, char *line,
+ const char *filename, int linenum)
{
- FILE *f;
- char line[1024];
char *cp, **charptr, *arg, *p;
- int linenum, *intptr, value;
- int bad_options = 0;
+ int *intptr, value;
ServerOpCodes opcode;
- int i;
+ int i, n;
- f = fopen(filename, "r");
- if (!f) {
- perror(filename);
- exit(1);
- }
- linenum = 0;
- while (fgets(line, sizeof(line), f)) {
- linenum++;
- cp = line;
+ cp = line;
+ arg = strdelim(&cp);
+ /* Ignore leading whitespace */
+ if (*arg == '\0')
arg = strdelim(&cp);
- /* Ignore leading whitespace */
- if (*arg == '\0')
- arg = strdelim(&cp);
- if (!arg || !*arg || *arg == '#')
- continue;
- intptr = NULL;
- charptr = NULL;
- opcode = parse_token(arg, filename, linenum);
- switch (opcode) {
- case sBadOption:
- bad_options++;
- continue;
- case sPort:
- /* ignore ports from configfile if cmdline specifies ports */
- if (options->ports_from_cmdline)
- continue;
- if (options->listen_addrs != NULL)
- fatal("%s line %d: ports must be specified before "
- "ListenAdress.\n", filename, linenum);
- if (options->num_ports >= MAX_PORTS)
- fatal("%s line %d: too many ports.",
- filename, linenum);
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing port number.",
- filename, linenum);
- options->ports[options->num_ports++] = a2port(arg);
- if (options->ports[options->num_ports-1] == 0)
- fatal("%s line %d: Badly formatted port number.",
- filename, linenum);
- break;
-
- case sServerKeyBits:
- intptr = &options->server_key_bits;
+ if (!arg || !*arg || *arg == '#')
+ return 0;
+ intptr = NULL;
+ charptr = NULL;
+ opcode = parse_token(arg, filename, linenum);
+ switch (opcode) {
+ case sBadOption:
+ return -1;
+ case sPort:
+ /* ignore ports from configfile if cmdline specifies ports */
+ if (options->ports_from_cmdline)
+ return 0;
+ if (options->listen_addrs != NULL)
+ fatal("%s line %d: ports must be specified before "
+ "ListenAddress.", filename, linenum);
+ if (options->num_ports >= MAX_PORTS)
+ fatal("%s line %d: too many ports.",
+ filename, linenum);
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing port number.",
+ filename, linenum);
+ options->ports[options->num_ports++] = a2port(arg);
+ if (options->ports[options->num_ports-1] == 0)
+ fatal("%s line %d: Badly formatted port number.",
+ filename, linenum);
+ break;
+
+ case sServerKeyBits:
+ intptr = &options->server_key_bits;
parse_int:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing integer value.",
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing integer value.",
+ filename, linenum);
+ value = atoi(arg);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
+
+ case sLoginGraceTime:
+ intptr = &options->login_grace_time;
+parse_time:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing time value.",
+ filename, linenum);
+ if ((value = convtime(arg)) == -1)
+ fatal("%s line %d: invalid time value.",
+ filename, linenum);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
+
+ case sKeyRegenerationTime:
+ intptr = &options->key_regeneration_time;
+ goto parse_time;
+
+ case sListenAddress:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
+ fatal("%s line %d: missing inet addr.",
+ filename, linenum);
+ if (*arg == '[') {
+ if ((p = strchr(arg, ']')) == NULL)
+ fatal("%s line %d: bad ipv6 inet addr usage.",
filename, linenum);
- value = atoi(arg);
- if (value == 0) {
- fprintf(stderr, "%s line %d: invalid integer value.\n",
- filename, linenum);
- exit(1);
- }
- if (*intptr == -1)
- *intptr = value;
+ arg++;
+ memmove(p, p+1, strlen(p+1)+1);
+ } else if (((p = strchr(arg, ':')) == NULL) ||
+ (strchr(p+1, ':') != NULL)) {
+ add_listen_addr(options, arg, 0);
break;
+ }
+ if (*p == ':') {
+ u_short port;
- case sLoginGraceTime:
- intptr = &options->login_grace_time;
- goto parse_int;
-
- case sKeyRegenerationTime:
- intptr = &options->key_regeneration_time;
- goto parse_int;
-
- case sListenAddress:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
- fatal("%s line %d: missing inet addr.",
+ p++;
+ if (*p == '\0')
+ fatal("%s line %d: bad inet addr:port usage.",
filename, linenum);
- if (*arg == '[') {
- if ((p = strchr(arg, ']')) == NULL)
- fatal("%s line %d: bad ipv6 inet addr usage.",
+ else {
+ *(p-1) = '\0';
+ if ((port = a2port(p)) == 0)
+ fatal("%s line %d: bad port number.",
filename, linenum);
- arg++;
- memmove(p, p+1, strlen(p+1)+1);
- } else if (((p = strchr(arg, ':')) == NULL) ||
- (strchr(p+1, ':') != NULL)) {
- add_listen_addr(options, arg, 0);
- break;
+ add_listen_addr(options, arg, port);
}
- if (*p == ':') {
- u_short port;
-
- p++;
- if (*p == '\0')
- fatal("%s line %d: bad inet addr:port usage.",
- filename, linenum);
- else {
- *(p-1) = '\0';
- if ((port = a2port(p)) == 0)
- fatal("%s line %d: bad port number.",
- filename, linenum);
- add_listen_addr(options, arg, port);
- }
- } else if (*p == '\0')
- add_listen_addr(options, arg, 0);
- else
- fatal("%s line %d: bad inet addr usage.",
- filename, linenum);
- break;
-
- case sHostKeyFile:
- intptr = &options->num_host_key_files;
- if (*intptr >= MAX_HOSTKEYS)
- fatal("%s line %d: too many host keys specified (max %d).",
- filename, linenum, MAX_HOSTKEYS);
- charptr = &options->host_key_files[*intptr];
+ } else if (*p == '\0')
+ add_listen_addr(options, arg, 0);
+ else
+ fatal("%s line %d: bad inet addr usage.",
+ filename, linenum);
+ break;
+
+ case sHostKeyFile:
+ intptr = &options->num_host_key_files;
+ if (*intptr >= MAX_HOSTKEYS)
+ fatal("%s line %d: too many host keys specified (max %d).",
+ filename, linenum, MAX_HOSTKEYS);
+ charptr = &options->host_key_files[*intptr];
parse_filename:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing file name.",
- filename, linenum);
- if (*charptr == NULL) {
- *charptr = tilde_expand_filename(arg, getuid());
- /* increase optional counter */
- if (intptr != NULL)
- *intptr = *intptr + 1;
- }
- break;
-
- case sPidFile:
- charptr = &options->pid_file;
- goto parse_filename;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing file name.",
+ filename, linenum);
+ if (*charptr == NULL) {
+ *charptr = tilde_expand_filename(arg, getuid());
+ /* increase optional counter */
+ if (intptr != NULL)
+ *intptr = *intptr + 1;
+ }
+ break;
- case sPermitRootLogin:
- intptr = &options->permit_root_login;
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing yes/"
- "without-password/forced-commands-only/no "
- "argument.", filename, linenum);
- value = 0; /* silence compiler */
- if (strcmp(arg, "without-password") == 0)
- value = PERMIT_NO_PASSWD;
- else if (strcmp(arg, "forced-commands-only") == 0)
- value = PERMIT_FORCED_ONLY;
- else if (strcmp(arg, "yes") == 0)
- value = PERMIT_YES;
- else if (strcmp(arg, "no") == 0)
- value = PERMIT_NO;
- else
- fatal("%s line %d: Bad yes/"
- "without-password/forced-commands-only/no "
- "argument: %s", filename, linenum, arg);
- if (*intptr == -1)
- *intptr = value;
- break;
+ case sPidFile:
+ charptr = &options->pid_file;
+ goto parse_filename;
- case sIgnoreRhosts:
- intptr = &options->ignore_rhosts;
+ case sPermitRootLogin:
+ intptr = &options->permit_root_login;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing yes/"
+ "without-password/forced-commands-only/no "
+ "argument.", filename, linenum);
+ value = 0; /* silence compiler */
+ if (strcmp(arg, "without-password") == 0)
+ value = PERMIT_NO_PASSWD;
+ else if (strcmp(arg, "forced-commands-only") == 0)
+ value = PERMIT_FORCED_ONLY;
+ else if (strcmp(arg, "yes") == 0)
+ value = PERMIT_YES;
+ else if (strcmp(arg, "no") == 0)
+ value = PERMIT_NO;
+ else
+ fatal("%s line %d: Bad yes/"
+ "without-password/forced-commands-only/no "
+ "argument: %s", filename, linenum, arg);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
+
+ case sIgnoreRhosts:
+ intptr = &options->ignore_rhosts;
parse_flag:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing yes/no argument.",
- filename, linenum);
- value = 0; /* silence compiler */
- if (strcmp(arg, "yes") == 0)
- value = 1;
- else if (strcmp(arg, "no") == 0)
- value = 0;
- else
- fatal("%s line %d: Bad yes/no argument: %s",
- filename, linenum, arg);
- if (*intptr == -1)
- *intptr = value;
- break;
-
- case sIgnoreUserKnownHosts:
- intptr = &options->ignore_user_known_hosts;
- goto parse_flag;
-
- case sRhostsAuthentication:
- intptr = &options->rhosts_authentication;
- goto parse_flag;
-
- case sRhostsRSAAuthentication:
- intptr = &options->rhosts_rsa_authentication;
- goto parse_flag;
-
- case sHostbasedAuthentication:
- intptr = &options->hostbased_authentication;
- goto parse_flag;
-
- case sHostbasedUsesNameFromPacketOnly:
- intptr = &options->hostbased_uses_name_from_packet_only;
- goto parse_flag;
-
- case sRSAAuthentication:
- intptr = &options->rsa_authentication;
- goto parse_flag;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing yes/no argument.",
+ filename, linenum);
+ value = 0; /* silence compiler */
+ if (strcmp(arg, "yes") == 0)
+ value = 1;
+ else if (strcmp(arg, "no") == 0)
+ value = 0;
+ else
+ fatal("%s line %d: Bad yes/no argument: %s",
+ filename, linenum, arg);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
+
+ case sIgnoreUserKnownHosts:
+ intptr = &options->ignore_user_known_hosts;
+ goto parse_flag;
+
+ case sRhostsAuthentication:
+ intptr = &options->rhosts_authentication;
+ goto parse_flag;
+
+ case sRhostsRSAAuthentication:
+ intptr = &options->rhosts_rsa_authentication;
+ goto parse_flag;
+
+ case sHostbasedAuthentication:
+ intptr = &options->hostbased_authentication;
+ goto parse_flag;
+
+ case sHostbasedUsesNameFromPacketOnly:
+ intptr = &options->hostbased_uses_name_from_packet_only;
+ goto parse_flag;
+
+ case sRSAAuthentication:
+ intptr = &options->rsa_authentication;
+ goto parse_flag;
+
+ case sPubkeyAuthentication:
+ intptr = &options->pubkey_authentication;
+ goto parse_flag;
+#if defined(KRB4) || defined(KRB5)
+ case sKerberosAuthentication:
+ intptr = &options->kerberos_authentication;
+ goto parse_flag;
- case sPubkeyAuthentication:
- intptr = &options->pubkey_authentication;
- goto parse_flag;
+ case sKerberosOrLocalPasswd:
+ intptr = &options->kerberos_or_local_passwd;
+ goto parse_flag;
-#if defined(KRB4) || defined(KRB5)
- case sKerberosAuthentication:
- intptr = &options->kerberos_authentication;
- goto parse_flag;
+ case sKerberosTicketCleanup:
+ intptr = &options->kerberos_ticket_cleanup;
+ goto parse_flag;
#endif
-
-#ifdef KRB4
- case sKrb4OrLocalPasswd:
- intptr = &options->krb4_or_local_passwd;
- goto parse_flag;
-
- case sKrb4TicketCleanup:
- intptr = &options->krb4_ticket_cleanup;
- goto parse_flag;
+#if defined(AFS) || defined(KRB5)
+ case sKerberosTgtPassing:
+ intptr = &options->kerberos_tgt_passing;
+ goto parse_flag;
#endif
-
-#ifdef KRB5
- case sKrb5TgtPassing:
- intptr = &options->krb5_tgt_passing;
- goto parse_flag;
-#endif /* KRB5 */
-
#ifdef AFS
- case sKrb4TgtPassing:
- intptr = &options->krb4_tgt_passing;
- goto parse_flag;
-
- case sAFSTokenPassing:
- intptr = &options->afs_token_passing;
- goto parse_flag;
+ case sAFSTokenPassing:
+ intptr = &options->afs_token_passing;
+ goto parse_flag;
#endif
- case sPasswordAuthentication:
- intptr = &options->password_authentication;
- goto parse_flag;
-
- case sKbdInteractiveAuthentication:
- intptr = &options->kbd_interactive_authentication;
- goto parse_flag;
-
- case sCheckMail:
- intptr = &options->check_mail;
- goto parse_flag;
+ case sPasswordAuthentication:
+ intptr = &options->password_authentication;
+ goto parse_flag;
- case sChallengeResponseAuthentication:
- intptr = &options->challenge_reponse_authentication;
- goto parse_flag;
+ case sKbdInteractiveAuthentication:
+ intptr = &options->kbd_interactive_authentication;
+ goto parse_flag;
- case sPrintMotd:
- intptr = &options->print_motd;
- goto parse_flag;
+ case sChallengeResponseAuthentication:
+ intptr = &options->challenge_response_authentication;
+ goto parse_flag;
- case sPrintLastLog:
- intptr = &options->print_lastlog;
- goto parse_flag;
+ case sPrintMotd:
+ intptr = &options->print_motd;
+ goto parse_flag;
- case sX11Forwarding:
- intptr = &options->x11_forwarding;
- goto parse_flag;
+ case sPrintLastLog:
+ intptr = &options->print_lastlog;
+ goto parse_flag;
- case sX11DisplayOffset:
- intptr = &options->x11_display_offset;
- goto parse_int;
+ case sX11Forwarding:
+ intptr = &options->x11_forwarding;
+ goto parse_flag;
- case sXAuthLocation:
- charptr = &options->xauth_location;
- goto parse_filename;
+ case sX11DisplayOffset:
+ intptr = &options->x11_display_offset;
+ goto parse_int;
- case sStrictModes:
- intptr = &options->strict_modes;
- goto parse_flag;
+ case sX11UseLocalhost:
+ intptr = &options->x11_use_localhost;
+ goto parse_flag;
- case sKeepAlives:
- intptr = &options->keepalives;
- goto parse_flag;
+ case sXAuthLocation:
+ charptr = &options->xauth_location;
+ goto parse_filename;
- case sEmptyPasswd:
- intptr = &options->permit_empty_passwd;
- goto parse_flag;
+ case sStrictModes:
+ intptr = &options->strict_modes;
+ goto parse_flag;
- case sUseLogin:
- intptr = &options->use_login;
- goto parse_flag;
+ case sKeepAlives:
+ intptr = &options->keepalives;
+ goto parse_flag;
- case sGatewayPorts:
- intptr = &options->gateway_ports;
- goto parse_flag;
+ case sEmptyPasswd:
+ intptr = &options->permit_empty_passwd;
+ goto parse_flag;
- case sReverseMappingCheck:
- intptr = &options->reverse_mapping_check;
- goto parse_flag;
+ case sUseLogin:
+ intptr = &options->use_login;
+ goto parse_flag;
- case sLogFacility:
- intptr = (int *) &options->log_facility;
- arg = strdelim(&cp);
- value = log_facility_number(arg);
- if (value == (SyslogFacility) - 1)
- fatal("%.200s line %d: unsupported log facility '%s'",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == -1)
- *intptr = (SyslogFacility) value;
- break;
-
- case sLogLevel:
- intptr = (int *) &options->log_level;
- arg = strdelim(&cp);
- value = log_level_number(arg);
- if (value == (LogLevel) - 1)
- fatal("%.200s line %d: unsupported log level '%s'",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == -1)
- *intptr = (LogLevel) value;
- break;
+ case sGatewayPorts:
+ intptr = &options->gateway_ports;
+ goto parse_flag;
- case sAllowTcpForwarding:
- intptr = &options->allow_tcp_forwarding;
- goto parse_flag;
+ case sVerifyReverseMapping:
+ intptr = &options->verify_reverse_mapping;
+ goto parse_flag;
- case sAllowUsers:
- while ((arg = strdelim(&cp)) && *arg != '\0') {
- if (options->num_allow_users >= MAX_ALLOW_USERS)
- fatal("%.200s line %d: too many allow users.",
- filename, linenum);
- options->allow_users[options->num_allow_users++] = xstrdup(arg);
- }
- break;
-
- case sDenyUsers:
- while ((arg = strdelim(&cp)) && *arg != '\0') {
- if (options->num_deny_users >= MAX_DENY_USERS)
- fatal(".200%s line %d: too many deny users.",
- filename, linenum);
- options->deny_users[options->num_deny_users++] = xstrdup(arg);
- }
- break;
-
- case sAllowGroups:
- while ((arg = strdelim(&cp)) && *arg != '\0') {
- if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
- fatal("%.200s line %d: too many allow groups.",
- filename, linenum);
- options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
- }
- break;
+ case sLogFacility:
+ intptr = (int *) &options->log_facility;
+ arg = strdelim(&cp);
+ value = log_facility_number(arg);
+ if (value == SYSLOG_FACILITY_NOT_SET)
+ fatal("%.200s line %d: unsupported log facility '%s'",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*intptr == -1)
+ *intptr = (SyslogFacility) value;
+ break;
+
+ case sLogLevel:
+ intptr = (int *) &options->log_level;
+ arg = strdelim(&cp);
+ value = log_level_number(arg);
+ if (value == SYSLOG_LEVEL_NOT_SET)
+ fatal("%.200s line %d: unsupported log level '%s'",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*intptr == -1)
+ *intptr = (LogLevel) value;
+ break;
+
+ case sAllowTcpForwarding:
+ intptr = &options->allow_tcp_forwarding;
+ goto parse_flag;
+
+ case sAllowUsers:
+ while ((arg = strdelim(&cp)) && *arg != '\0') {
+ if (options->num_allow_users >= MAX_ALLOW_USERS)
+ fatal("%s line %d: too many allow users.",
+ filename, linenum);
+ options->allow_users[options->num_allow_users++] = xstrdup(arg);
+ }
+ break;
- case sDenyGroups:
- while ((arg = strdelim(&cp)) && *arg != '\0') {
- if (options->num_deny_groups >= MAX_DENY_GROUPS)
- fatal("%.200s line %d: too many deny groups.",
- filename, linenum);
- options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
- }
- break;
+ case sDenyUsers:
+ while ((arg = strdelim(&cp)) && *arg != '\0') {
+ if (options->num_deny_users >= MAX_DENY_USERS)
+ fatal( "%s line %d: too many deny users.",
+ filename, linenum);
+ options->deny_users[options->num_deny_users++] = xstrdup(arg);
+ }
+ break;
- case sCiphers:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- if (!ciphers_valid(arg))
- fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (options->ciphers == NULL)
- options->ciphers = xstrdup(arg);
- break;
+ case sAllowGroups:
+ while ((arg = strdelim(&cp)) && *arg != '\0') {
+ if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
+ fatal("%s line %d: too many allow groups.",
+ filename, linenum);
+ options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
+ }
+ break;
- case sMacs:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- if (!mac_valid(arg))
- fatal("%s line %d: Bad SSH2 mac spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (options->macs == NULL)
- options->macs = xstrdup(arg);
- break;
+ case sDenyGroups:
+ while ((arg = strdelim(&cp)) && *arg != '\0') {
+ if (options->num_deny_groups >= MAX_DENY_GROUPS)
+ fatal("%s line %d: too many deny groups.",
+ filename, linenum);
+ options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
+ }
+ break;
- case sProtocol:
- intptr = &options->protocol;
+ case sCiphers:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing argument.", filename, linenum);
+ if (!ciphers_valid(arg))
+ fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (options->ciphers == NULL)
+ options->ciphers = xstrdup(arg);
+ break;
+
+ case sMacs:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing argument.", filename, linenum);
+ if (!mac_valid(arg))
+ fatal("%s line %d: Bad SSH2 mac spec '%s'.",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (options->macs == NULL)
+ options->macs = xstrdup(arg);
+ break;
+
+ case sProtocol:
+ intptr = &options->protocol;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing argument.", filename, linenum);
+ value = proto_spec(arg);
+ if (value == SSH_PROTO_UNKNOWN)
+ fatal("%s line %d: Bad protocol spec '%s'.",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*intptr == SSH_PROTO_UNKNOWN)
+ *intptr = value;
+ break;
+
+ case sSubsystem:
+ if (options->num_subsystems >= MAX_SUBSYSTEMS) {
+ fatal("%s line %d: too many subsystems defined.",
+ filename, linenum);
+ }
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing subsystem name.",
+ filename, linenum);
+ for (i = 0; i < options->num_subsystems; i++)
+ if (strcmp(arg, options->subsystem_name[i]) == 0)
+ fatal("%s line %d: Subsystem '%s' already defined.",
+ filename, linenum, arg);
+ options->subsystem_name[options->num_subsystems] = xstrdup(arg);
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing subsystem command.",
+ filename, linenum);
+ options->subsystem_command[options->num_subsystems] = xstrdup(arg);
+ options->num_subsystems++;
+ break;
+
+ case sMaxStartups:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: Missing MaxStartups spec.",
+ filename, linenum);
+ if ((n = sscanf(arg, "%d:%d:%d",
+ &options->max_startups_begin,
+ &options->max_startups_rate,
+ &options->max_startups)) == 3) {
+ if (options->max_startups_begin >
+ options->max_startups ||
+ options->max_startups_rate > 100 ||
+ options->max_startups_rate < 1)
+ fatal("%s line %d: Illegal MaxStartups spec.",
+ filename, linenum);
+ } else if (n != 1)
+ fatal("%s line %d: Illegal MaxStartups spec.",
+ filename, linenum);
+ else
+ options->max_startups = options->max_startups_begin;
+ break;
+
+ case sBanner:
+ charptr = &options->banner;
+ goto parse_filename;
+ /*
+ * These options can contain %X options expanded at
+ * connect time, so that you can specify paths like:
+ *
+ * AuthorizedKeysFile /etc/ssh_keys/%u
+ */
+ case sAuthorizedKeysFile:
+ case sAuthorizedKeysFile2:
+ charptr = (opcode == sAuthorizedKeysFile ) ?
+ &options->authorized_keys_file :
+ &options->authorized_keys_file2;
+ goto parse_filename;
+
+ case sClientAliveInterval:
+ intptr = &options->client_alive_interval;
+ goto parse_time;
+
+ case sClientAliveCountMax:
+ intptr = &options->client_alive_count_max;
+ goto parse_int;
+
+ case sDeprecated:
+ log("%s line %d: Deprecated option %s",
+ filename, linenum, arg);
+ while (arg)
+ arg = strdelim(&cp);
+ break;
+
+ case sCheckMail:
+ intptr = &options->check_mail;
+ goto parse_flag;
+
+ case sVersionAddendum:
+ ssh_version_set_addendum(strtok(cp, "\n"));
+ do {
arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- value = proto_spec(arg);
- if (value == SSH_PROTO_UNKNOWN)
- fatal("%s line %d: Bad protocol spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == SSH_PROTO_UNKNOWN)
- *intptr = value;
- break;
+ } while (arg != NULL && *arg != '\0');
+ break;
- case sConnectionsPerPeriod:
- (void)strdelim(&cp);
- error("ConnectionsPerPeriod has been deprecated!");
- break;
+ default:
+ fatal("%s line %d: Missing handler for opcode %s (%d)",
+ filename, linenum, arg, opcode);
+ }
+ if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
+ fatal("%s line %d: garbage at end of line; \"%.200s\".",
+ filename, linenum, arg);
+ return 0;
+}
- case sSubsystem:
- if(options->num_subsystems >= MAX_SUBSYSTEMS) {
- fatal("%s line %d: too many subsystems defined.",
- filename, linenum);
- }
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing subsystem name.",
- filename, linenum);
- for (i = 0; i < options->num_subsystems; i++)
- if(strcmp(arg, options->subsystem_name[i]) == 0)
- fatal("%s line %d: Subsystem '%s' already defined.",
- filename, linenum, arg);
- options->subsystem_name[options->num_subsystems] = xstrdup(arg);
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing subsystem command.",
- filename, linenum);
- options->subsystem_command[options->num_subsystems] = xstrdup(arg);
- options->num_subsystems++;
- break;
+/* Reads the server configuration file. */
- case sMaxStartups:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing MaxStartups spec.",
- filename, linenum);
- if (sscanf(arg, "%d:%d:%d",
- &options->max_startups_begin,
- &options->max_startups_rate,
- &options->max_startups) == 3) {
- if (options->max_startups_begin >
- options->max_startups ||
- options->max_startups_rate > 100 ||
- options->max_startups_rate < 1)
- fatal("%s line %d: Illegal MaxStartups spec.",
- filename, linenum);
- break;
- }
- intptr = &options->max_startups;
- goto parse_int;
-
- case sVersionAddendum:
- ssh_version_set_addendum(strtok(cp, "\n"));
- do
- arg = strdelim(&cp);
- while (arg != NULL && *arg != '\0');
- break;
+void
+read_server_config(ServerOptions *options, const char *filename)
+{
+ FILE *f;
+ char line[1024];
+ int linenum;
+ int bad_options = 0;
- case sBanner:
- charptr = &options->banner;
- goto parse_filename;
- case sClientAliveInterval:
- intptr = &options->client_alive_interval;
- goto parse_int;
- case sClientAliveCountMax:
- intptr = &options->client_alive_count_max;
- goto parse_int;
- default:
- fatal("%.200s line %d: Missing handler for opcode %s (%d)",
- filename, linenum, arg, opcode);
- }
- if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
- fatal("%s line %d: garbage at end of line; \"%.200s\".",
- filename, linenum, arg);
+ f = fopen(filename, "r");
+ if (!f) {
+ perror(filename);
+ exit(1);
+ }
+ linenum = 0;
+ while (fgets(line, sizeof(line), f)) {
+ /* Update line number counter. */
+ linenum++;
+ if (process_server_config_line(options, line, filename, linenum) != 0)
+ bad_options++;
}
fclose(f);
if (bad_options > 0)
- fatal("%.200s: terminating, %d bad configuration options",
+ fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
}
diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h
index 2d84ee4..d5bf6be 100644
--- a/crypto/openssh/servconf.h
+++ b/crypto/openssh/servconf.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -11,9 +14,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef SERVCONF_H
#define SERVCONF_H
@@ -53,10 +53,11 @@ typedef struct {
* for RhostsRsaAuth */
int print_motd; /* If true, print /etc/motd. */
int print_lastlog; /* If true, print lastlog */
- int check_mail; /* If true, check for new mail. */
+ int check_mail; /* If true, check for new mail */
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start
* searching at */
+ int x11_use_localhost; /* If true, use localhost for fake X11 server. */
char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */
@@ -73,32 +74,29 @@ typedef struct {
int hostbased_authentication; /* If true, permit ssh2 hostbased auth */
int hostbased_uses_name_from_packet_only; /* experimental */
int rsa_authentication; /* If true, permit RSA authentication. */
-#if defined(KRB4) || defined(KRB5)
- int kerberos_authentication; /* If true, permit Kerberos auth. */
-#endif /* KRB4 || KRB5 */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
-#ifdef KRB4
- int krb4_or_local_passwd; /* If true, permit kerberos v4
+#if defined(KRB4) || defined(KRB5)
+ int kerberos_authentication; /* If true, permit Kerberos
+ * authentication. */
+ int kerberos_or_local_passwd; /* If true, permit kerberos
* and any other password
* authentication mechanism,
* such as SecurID or
* /etc/passwd */
- int krb4_ticket_cleanup; /* If true, destroy ticket
+ int kerberos_ticket_cleanup; /* If true, destroy ticket
* file on logout. */
#endif
-#ifdef KRB5
- int krb5_tgt_passing;
-
-#endif /* KRB5 */
-#ifdef AFS
- int krb4_tgt_passing; /* If true, permit Kerberos v4 tgt
+#if defined(AFS) || defined(KRB5)
+ int kerberos_tgt_passing; /* If true, permit Kerberos TGT
* passing. */
+#endif
+#ifdef AFS
int afs_token_passing; /* If true, permit AFS token passing. */
#endif
int password_authentication; /* If true, permit password
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
- int challenge_reponse_authentication;
+ int challenge_response_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int use_login; /* If true, login(1) is used */
@@ -111,11 +109,6 @@ typedef struct {
char *allow_groups[MAX_ALLOW_GROUPS];
u_int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS];
- unsigned int connections_per_period; /*
- * If not 0, number of sshd
- * connections accepted per
- * connections_period.
- */
unsigned int connections_period;
u_int num_subsystems;
@@ -126,31 +119,26 @@ typedef struct {
int max_startups_rate;
int max_startups;
char *banner; /* SSH-2 banner message */
- int reverse_mapping_check; /* cross-check ip and dns */
+ int verify_reverse_mapping; /* cross-check ip and dns */
int client_alive_interval; /*
- * poke the client this often to
- * see if it's still there
+ * poke the client this often to
+ * see if it's still there
*/
int client_alive_count_max; /*
- *If the client is unresponsive
- * for this many intervals, above
- * diconnect the session
+ * If the client is unresponsive
+ * for this many intervals above,
+ * disconnect the session
*/
+ char *authorized_keys_file; /* File containing public keys */
+ char *authorized_keys_file2;
+
} ServerOptions;
-/*
- * Initializes the server options to special values that indicate that they
- * have not yet been set.
- */
-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.
- */
-void read_server_config(ServerOptions * options, const char *filename);
+void initialize_server_options(ServerOptions *);
+void read_server_config(ServerOptions *, const char *);
+void fill_default_server_options(ServerOptions *);
+int process_server_config_line(ServerOptions *, char *, const char *, int);
-/* Sets values for those values that have not yet been set. */
-void fill_default_server_options(ServerOptions * options);
#endif /* SERVCONF_H */
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
index 02d034e..c5731d4 100644
--- a/crypto/openssh/serverloop.c
+++ b/crypto/openssh/serverloop.c
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,8 @@
*/
#include "includes.h"
+RCSID("$OpenBSD: serverloop.c,v 1.98 2002/02/06 14:55:16 markus Exp $");
RCSID("$FreeBSD$");
-RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h"
#include "packet.h"
@@ -60,6 +60,7 @@ extern ServerOptions options;
/* XXX */
extern Kex *xxx_kex;
+static Authctxt *xxx_authctxt;
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
@@ -80,46 +81,71 @@ static int connection_in; /* Connection to client (input). */
static int connection_out; /* Connection to client (output). */
static int connection_closed = 0; /* Connection to client closed. */
static u_int buffer_high; /* "Soft" max buffer size. */
+static int client_alive_timeouts = 0;
/*
* 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 pid_t child_pid; /* Pid of the child. */
-static volatile int child_terminated; /* The child has terminated. */
-static volatile int child_wait_status; /* Status from wait(). */
+static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */
-void server_init_dispatch(void);
+/* prototypes */
+static void server_init_dispatch(void);
-int client_alive_timeouts = 0;
-
-void
-sigchld_handler(int sig)
+/*
+ * we write to this pipe if a SIGCHLD is caught in order to avoid
+ * the race between select() and child_terminated
+ */
+static int notify_pipe[2];
+static void
+notify_setup(void)
{
- int save_errno = errno;
- pid_t wait_pid;
-
- debug("Received SIGCHLD.");
- wait_pid = wait((int *) &child_wait_status);
- if (wait_pid != -1) {
- if (wait_pid != child_pid)
- error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
- wait_pid, child_pid);
- if (WIFEXITED(child_wait_status) ||
- WIFSIGNALED(child_wait_status))
- child_terminated = 1;
+ if (pipe(notify_pipe) < 0) {
+ error("pipe(notify_pipe) failed %s", strerror(errno));
+ } else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) ||
+ (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) {
+ error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
+ close(notify_pipe[0]);
+ close(notify_pipe[1]);
+ } else {
+ set_nonblock(notify_pipe[0]);
+ set_nonblock(notify_pipe[1]);
+ return;
}
- signal(SIGCHLD, sigchld_handler);
- errno = save_errno;
+ notify_pipe[0] = -1; /* read end */
+ notify_pipe[1] = -1; /* write end */
}
-void
-sigchld_handler2(int sig)
+static void
+notify_parent(void)
+{
+ if (notify_pipe[1] != -1)
+ write(notify_pipe[1], "", 1);
+}
+static void
+notify_prepare(fd_set *readset)
+{
+ if (notify_pipe[0] != -1)
+ FD_SET(notify_pipe[0], readset);
+}
+static void
+notify_done(fd_set *readset)
+{
+ char c;
+
+ if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
+ while (read(notify_pipe[0], &c, 1) != -1)
+ debug2("notify_done: reading");
+}
+
+static void
+sigchld_handler(int sig)
{
int save_errno = errno;
debug("Received SIGCHLD.");
child_terminated = 1;
- signal(SIGCHLD, sigchld_handler2);
+ signal(SIGCHLD, sigchld_handler);
+ notify_parent();
errno = save_errno;
}
@@ -127,7 +153,7 @@ sigchld_handler2(int sig)
* Make packets from buffered stderr data, and buffer it for sending
* to the client.
*/
-void
+static void
make_packets_from_stderr_data(void)
{
int len;
@@ -156,7 +182,7 @@ make_packets_from_stderr_data(void)
* Make packets from buffered stdout data, and buffer it for sending to the
* client.
*/
-void
+static void
make_packets_from_stdout_data(void)
{
int len;
@@ -181,44 +207,69 @@ make_packets_from_stdout_data(void)
}
}
+static void
+client_alive_check(void)
+{
+ static int had_channel = 0;
+ int id;
+
+ id = channel_find_open();
+ if (id == -1) {
+ if (!had_channel)
+ return;
+ packet_disconnect("No open channels after timeout!");
+ }
+ had_channel = 1;
+
+ /* timeout, check to see how many we have had */
+ if (++client_alive_timeouts > options.client_alive_count_max)
+ packet_disconnect("Timeout, your session not responding.");
+
+ /*
+ * send a bogus channel request with "wantreply",
+ * we should get back a failure
+ */
+ channel_request_start(id, "keepalive@openssh.com", 1);
+ packet_send();
+}
+
/*
* Sleep in select() until we can do something. This will initialize the
* select masks. Upon return, the masks will indicate which descriptors
* have data or can accept data. Optionally, a maximum time can be specified
* for the duration of the wait (0 = infinite).
*/
-void
+static void
wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- u_int max_time_milliseconds)
+ int *nallocp, u_int max_time_milliseconds)
{
struct timeval tv, *tvp;
int ret;
int client_alive_scheduled = 0;
/*
- * if using client_alive, set the max timeout accordingly,
+ * if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
* alive by setting the client_alive_scheduled flag.
*
* this could be randomized somewhat to make traffic
- * analysis more difficult, but we're not doing it yet.
+ * analysis more difficult, but we're not doing it yet.
*/
- if (max_time_milliseconds == 0 && options.client_alive_interval) {
- client_alive_scheduled = 1;
+ if (compat20 &&
+ max_time_milliseconds == 0 && options.client_alive_interval) {
+ client_alive_scheduled = 1;
max_time_milliseconds = options.client_alive_interval * 1000;
- } else
- client_alive_scheduled = 0;
-
- /* When select fails we restart from here. */
-retry_select:
+ }
/* Allocate and update select() masks for channel descriptors. */
- channel_prepare_select(readsetp, writesetp, maxfdp, 0);
+ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
if (compat20) {
+#if 0
/* wrong: bad condition XXX */
if (channel_not_very_much_buffered_data())
- FD_SET(connection_in, *readsetp);
+#endif
+ FD_SET(connection_in, *readsetp);
} else {
/*
* Read packets from the client unless we have too much
@@ -244,6 +295,7 @@ retry_select:
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
FD_SET(fdin, *writesetp);
}
+ notify_prepare(*readsetp);
/*
* If we have buffered packet data going to the client, mark that
@@ -268,48 +320,28 @@ retry_select:
tvp = &tv;
}
if (tvp!=NULL)
- debug3("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
+ debug3("tvp!=NULL kid %d mili %d", (int) child_terminated,
+ max_time_milliseconds);
/* Wait for something to happen, or the timeout to expire. */
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret == -1) {
+ memset(*readsetp, 0, *nallocp);
+ memset(*writesetp, 0, *nallocp);
if (errno != EINTR)
error("select: %.100s", strerror(errno));
- else
- goto retry_select;
- }
- if (ret == 0 && client_alive_scheduled) {
- /* timeout, check to see how many we have had */
- client_alive_timeouts++;
+ } else if (ret == 0 && client_alive_scheduled)
+ client_alive_check();
- if (client_alive_timeouts > options.client_alive_count_max ) {
- packet_disconnect(
- "Timeout, your session not responding.");
- } else {
- /*
- * send a bogus channel request with "wantreply"
- * we should get back a failure
- */
- int id;
-
- id = channel_find_open();
- if (id != -1) {
- channel_request_start(id,
- "keepalive@openssh.com", 1);
- packet_send();
- } else
- packet_disconnect(
- "No open channels after timeout!");
- }
- }
+ notify_done(*readsetp);
}
/*
* Processes input from the client and the program. Input data is stored
* in buffers and processed later.
*/
-void
+static void
process_input(fd_set * readset)
{
int len;
@@ -365,31 +397,31 @@ process_input(fd_set * readset)
/*
* Sends data from internal buffers to client program stdin.
*/
-void
+static void
process_output(fd_set * writeset)
{
struct termios tio;
+ u_char *data;
+ u_int dlen;
int len;
/* Write buffered data to program stdin. */
if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
- len = write(fdin, buffer_ptr(&stdin_buffer),
- buffer_len(&stdin_buffer));
+ data = buffer_ptr(&stdin_buffer);
+ dlen = buffer_len(&stdin_buffer);
+ len = write(fdin, data, dlen);
if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
/* do nothing */
} else if (len <= 0) {
-#ifdef USE_PIPES
- close(fdin);
-#else
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
-#endif
fdin = -1;
} else {
/* Successful write. */
- if (fdin_is_tty && tcgetattr(fdin, &tio) == 0 &&
+ if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&
+ tcgetattr(fdin, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
* Simulate echo to reduce the impact of
@@ -413,7 +445,7 @@ process_output(fd_set * writeset)
* Wait until all buffered output has been sent to the client.
* This is used when the program terminates.
*/
-void
+static void
drain_output(void)
{
/* Send any buffered stdout data to the client. */
@@ -438,7 +470,7 @@ drain_output(void)
packet_write_wait();
}
-void
+static void
process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
@@ -455,7 +487,7 @@ void
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
{
fd_set *readset = NULL, *writeset = NULL;
- int max_fd;
+ int max_fd = 0, nalloc = 0;
int wait_status; /* Status returned by wait(). */
pid_t wait_pid; /* pid returned by wait(). */
int waiting_termination = 0; /* Have displayed waiting close message. */
@@ -467,7 +499,6 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
debug("Entering interactive session.");
/* Initialize the SIGCHLD kludge. */
- child_pid = pid;
child_terminated = 0;
signal(SIGCHLD, sigchld_handler);
@@ -489,6 +520,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
+ notify_setup();
+
previous_stdout_buffer_bytes = 0;
/* Set approximate I/O buffer size. */
@@ -497,12 +530,14 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
else
buffer_high = 64 * 1024;
+#if 0
/* Initialize max_fd to the maximum of the known file descriptors. */
- max_fd = MAX(fdin, fdout);
+ max_fd = MAX(connection_in, connection_out);
+ max_fd = MAX(max_fd, fdin);
+ max_fd = MAX(max_fd, fdout);
if (fderr != -1)
max_fd = MAX(max_fd, fderr);
- max_fd = MAX(max_fd, connection_in);
- max_fd = MAX(max_fd, connection_out);
+#endif
/* Initialize Initialize buffers. */
buffer_init(&stdin_buffer);
@@ -531,14 +566,10 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
* input data, cause a real eof by closing fdin.
*/
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
-#ifdef USE_PIPES
- close(fdin);
-#else
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
-#endif
fdin = -1;
}
/* Make packets from buffered stderr data to send to the client. */
@@ -588,9 +619,15 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
xfree(cp);
}
}
+ max_fd = MAX(connection_in, connection_out);
+ max_fd = MAX(max_fd, fdin);
+ max_fd = MAX(max_fd, fdout);
+ max_fd = MAX(max_fd, fderr);
+ max_fd = MAX(max_fd, notify_pipe[0]);
+
/* Sleep in select() until we can do something. */
wait_until_can_do_something(&readset, &writeset, &max_fd,
- max_time_milliseconds);
+ &nalloc, max_time_milliseconds);
/* Process any channel events. */
channel_after_select(readset, writeset);
@@ -612,7 +649,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
drain_output();
debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
- stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
+ stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
/* Free and clear the buffers. */
buffer_free(&stdin_buffer);
@@ -632,31 +669,18 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
close(fdin);
fdin = -1;
- /* Stop listening for channels; this removes unix domain sockets. */
- channel_stop_listening();
-
- /* Wait for the child to exit. Get its exit status. */
- wait_pid = wait(&wait_status);
- if (wait_pid == -1) {
- /*
- * It is possible that the wait was handled by SIGCHLD
- * handler. This may result in either: this call
- * returning with EINTR, or: this call returning ECHILD.
- */
- if (child_terminated)
- wait_status = child_wait_status;
- else
- packet_disconnect("wait: %.100s", strerror(errno));
- } else {
- /* Check if it matches the process we forked. */
- if (wait_pid != pid)
- error("Strange, wait returned pid %d, expected %d",
- wait_pid, pid);
- }
+ channel_free_all();
/* We no longer want our SIGCHLD handler to be called. */
signal(SIGCHLD, SIG_DFL);
+ wait_pid = waitpid(-1, &wait_status, 0);
+ if (wait_pid == -1)
+ packet_disconnect("wait: %.100s", strerror(errno));
+ else if (wait_pid != pid)
+ error("Strange, wait returned pid %d, expected %d",
+ wait_pid, pid);
+
/* Check if it exited normally. */
if (WIFEXITED(wait_status)) {
/* Yes, normal exit. Get exit status and send it to the client. */
@@ -674,8 +698,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
* the exit status.
*/
do {
- int plen;
- type = packet_read(&plen);
+ type = packet_read();
}
while (type != SSH_CMSG_EXIT_CONFIRMATION);
@@ -692,21 +715,44 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* NOTREACHED */
}
+static void
+collect_children(void)
+{
+ pid_t pid;
+ sigset_t oset, nset;
+ int status;
+
+ /* block SIGCHLD while we check for dead children */
+ sigemptyset(&nset);
+ sigaddset(&nset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &nset, &oset);
+ if (child_terminated) {
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ session_close_by_pid(pid, status);
+ child_terminated = 0;
+ }
+ sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
void
-server_loop2(void)
+server_loop2(Authctxt *authctxt)
{
fd_set *readset = NULL, *writeset = NULL;
- int rekeying = 0, max_fd, status;
- pid_t pid;
+ int rekeying = 0, max_fd, nalloc = 0;
debug("Entering interactive session for SSH2.");
- signal(SIGCHLD, sigchld_handler2);
+ signal(SIGCHLD, sigchld_handler);
child_terminated = 0;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
+ notify_setup();
+
max_fd = MAX(connection_in, connection_out);
+ max_fd = MAX(max_fd, notify_pipe[0]);
+
+ xxx_authctxt = authctxt;
server_init_dispatch();
@@ -718,12 +764,9 @@ server_loop2(void)
if (!rekeying && packet_not_very_much_data_to_write())
channel_output_poll();
wait_until_can_do_something(&readset, &writeset, &max_fd,
- rekeying);
- if (child_terminated) {
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
- session_close_by_pid(pid, status);
- child_terminated = 0;
- }
+ &nalloc, 0);
+
+ collect_children();
if (!rekeying)
channel_after_select(readset, writeset);
process_input(readset);
@@ -731,32 +774,35 @@ server_loop2(void)
break;
process_output(writeset);
}
+ collect_children();
+
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
- signal(SIGCHLD, SIG_DFL);
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
- session_close_by_pid(pid, status);
- channel_stop_listening();
+ /* free all channels, no more reads and writes */
+ channel_free_all();
+
+ /* free remaining sessions, e.g. remove wtmp entries */
+ session_destroy_all();
}
-void
-server_input_channel_failure(int type, int plen, void *ctxt)
+static void
+server_input_channel_failure(int type, u_int32_t seq, void *ctxt)
{
debug("Got CHANNEL_FAILURE for keepalive");
- /*
- * reset timeout, since we got a sane answer from the client.
+ /*
+ * reset timeout, since we got a sane answer from the client.
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
- client_alive_timeouts = 0;
+ client_alive_timeouts = 0;
}
-void
-server_input_stdin_data(int type, int plen, void *ctxt)
+static void
+server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
{
char *data;
u_int data_len;
@@ -766,14 +812,14 @@ server_input_stdin_data(int type, int plen, void *ctxt)
if (fdin == -1)
return;
data = packet_get_string(&data_len);
- packet_integrity_check(plen, (4 + data_len), type);
+ packet_check_eom();
buffer_append(&stdin_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
}
-void
-server_input_eof(int type, int plen, void *ctxt)
+static void
+server_input_eof(int type, u_int32_t seq, void *ctxt)
{
/*
* Eof from the client. The stdin descriptor to the
@@ -781,12 +827,12 @@ server_input_eof(int type, int plen, void *ctxt)
* drained.
*/
debug("EOF received for stdin.");
- packet_integrity_check(plen, 0, type);
+ packet_check_eom();
stdin_eof = 1;
}
-void
-server_input_window_size(int type, int plen, void *ctxt)
+static void
+server_input_window_size(int type, u_int32_t seq, void *ctxt)
{
int row = packet_get_int();
int col = packet_get_int();
@@ -794,15 +840,16 @@ server_input_window_size(int type, int plen, void *ctxt)
int ypixel = packet_get_int();
debug("Window change received.");
- packet_integrity_check(plen, 4 * 4, type);
+ packet_check_eom();
if (fdin != -1)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
}
-Channel *
+static Channel *
server_request_direct_tcpip(char *ctype)
{
- int sock, newch;
+ Channel *c;
+ int sock;
char *target, *originator;
int target_port, originator_port;
@@ -810,7 +857,7 @@ server_request_direct_tcpip(char *ctype)
target_port = packet_get_int();
originator = packet_get_string(NULL);
originator_port = packet_get_int();
- packet_done();
+ packet_check_eom();
debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
originator, originator_port, target, target_port);
@@ -821,42 +868,39 @@ server_request_direct_tcpip(char *ctype)
xfree(originator);
if (sock < 0)
return NULL;
- newch = channel_new(ctype, SSH_CHANNEL_CONNECTING,
+ c = channel_new(ctype, SSH_CHANNEL_CONNECTING,
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
- return (newch >= 0) ? channel_lookup(newch) : NULL;
+ return c;
}
-Channel *
+static Channel *
server_request_session(char *ctype)
{
- int newch;
+ Channel *c;
debug("input_session_request");
- packet_done();
+ packet_check_eom();
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
- newch = channel_new(ctype, SSH_CHANNEL_LARVAL,
- -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
+ c = channel_new(ctype, SSH_CHANNEL_LARVAL,
+ -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
- if (session_open(newch) == 1) {
- channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST,
- session_input_channel_req, (void *)0);
- channel_register_cleanup(newch, session_close_by_channel);
- return channel_lookup(newch);
- } else {
- debug("session open failed, free channel %d", newch);
- channel_free(newch);
+ if (session_open(xxx_authctxt, c->self) != 1) {
+ debug("session open failed, free channel %d", c->self);
+ channel_free(c);
+ return NULL;
}
- return NULL;
+ channel_register_cleanup(c->self, session_close_by_channel);
+ return c;
}
-void
-server_input_channel_open(int type, int plen, void *ctxt)
+static void
+server_input_channel_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
char *ctype;
@@ -883,27 +927,30 @@ server_input_channel_open(int type, int plen, void *ctxt)
c->remote_id = rchan;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
-
- packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(c->remote_id);
- packet_put_int(c->self);
- packet_put_int(c->local_window);
- packet_put_int(c->local_maxpacket);
- packet_send();
+ if (c->type != SSH_CHANNEL_CONNECTING) {
+ packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->self);
+ packet_put_int(c->local_window);
+ packet_put_int(c->local_maxpacket);
+ packet_send();
+ }
} else {
debug("server_input_channel_open: failure %s", ctype);
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan);
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
- packet_put_cstring("bla bla");
- packet_put_cstring("");
+ if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+ packet_put_cstring("open failed");
+ packet_put_cstring("");
+ }
packet_send();
}
xfree(ctype);
}
-void
-server_input_global_request(int type, int plen, void *ctxt)
+static void
+server_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
@@ -935,11 +982,8 @@ server_input_global_request(int type, int plen, void *ctxt)
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
- success = channel_request_forwarding(
- listen_address, listen_port,
- /*unspec host_to_connect*/ "<unspec host>",
- /*unspec port_to_connect*/ 0,
- options.gateway_ports, /*remote*/ 1);
+ success = channel_setup_remote_fwd_listener(
+ listen_address, listen_port, options.gateway_ports);
}
xfree(listen_address);
}
@@ -951,8 +995,35 @@ server_input_global_request(int type, int plen, void *ctxt)
}
xfree(rtype);
}
+static void
+server_input_channel_req(int type, u_int32_t seq, void *ctxt)
+{
+ Channel *c;
+ int id, reply, success = 0;
+ char *rtype;
-void
+ id = packet_get_int();
+ rtype = packet_get_string(NULL);
+ reply = packet_get_char();
+
+ debug("server_input_channel_req: channel %d request %s reply %d",
+ id, rtype, reply);
+
+ if ((c = channel_lookup(id)) == NULL)
+ packet_disconnect("server_input_channel_req: "
+ "unknown channel %d", id);
+ if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
+ success = session_input_channel_req(c, rtype);
+ if (reply) {
+ packet_start(success ?
+ SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ }
+ xfree(rtype);
+}
+
+static void
server_init_dispatch_20(void)
{
debug("server_init_dispatch_20");
@@ -964,7 +1035,7 @@ server_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
- dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
+ dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
/* client_alive */
@@ -972,7 +1043,7 @@ server_init_dispatch_20(void)
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
-void
+static void
server_init_dispatch_13(void)
{
debug("server_init_dispatch_13");
@@ -987,7 +1058,7 @@ server_init_dispatch_13(void)
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
}
-void
+static void
server_init_dispatch_15(void)
{
server_init_dispatch_13();
@@ -995,7 +1066,7 @@ server_init_dispatch_15(void)
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
}
-void
+static void
server_init_dispatch(void)
{
if (compat20)
@@ -1005,4 +1076,3 @@ server_init_dispatch(void)
else
server_init_dispatch_15();
}
-
diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c
index 9a4e93f..7cf71bb 100644
--- a/crypto/openssh/session.c
+++ b/crypto/openssh/session.c
@@ -9,7 +9,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,7 +33,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.80 2001/06/04 21:59:43 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.128 2002/02/16 00:51:44 markus Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
@@ -47,7 +47,6 @@ RCSID("$FreeBSD$");
#include "uidswap.h"
#include "compat.h"
#include "channels.h"
-#include "nchan.h"
#include "bufaux.h"
#include "auth.h"
#include "auth-options.h"
@@ -67,10 +66,6 @@ RCSID("$FreeBSD$");
#include <login_cap.h>
#endif
-#ifdef KRB5
-extern krb5_context ssh_context;
-#endif
-
/* types */
#define TTYSZ 64
@@ -78,7 +73,8 @@ typedef struct Session Session;
struct Session {
int used;
int self;
- struct passwd *pw;
+ struct passwd *pw;
+ Authctxt *authctxt;
pid_t pid;
/* tty */
char *term;
@@ -86,8 +82,10 @@ struct Session {
int row, col, xpixel, ypixel;
char tty[TTYSZ];
/* X11 */
+ int display_number;
char *display;
int screen;
+ char *auth_display;
char *auth_proto;
char *auth_data;
int single_connection;
@@ -99,19 +97,23 @@ struct Session {
/* func */
Session *session_new(void);
-void session_set_fds(Session *s, int fdin, int fdout, int fderr);
-void session_pty_cleanup(Session *s);
-void session_proctitle(Session *s);
-void do_exec_pty(Session *s, const char *command);
-void do_exec_no_pty(Session *s, const char *command);
-void do_login(Session *s, const char *command);
-void do_child(Session *s, const char *command);
+void session_set_fds(Session *, int, int, int);
+static void session_pty_cleanup(void *);
+void session_proctitle(Session *);
+int session_setup_x11fwd(Session *);
+void do_exec_pty(Session *, const char *);
+void do_exec_no_pty(Session *, const char *);
+void do_exec(Session *, const char *);
+void do_login(Session *, const char *);
+void do_child(Session *, const char *);
void do_motd(void);
-int check_quietlogin(Session *s, const char *command);
-void xauthfile_cleanup_proc(void *pw);
+int check_quietlogin(Session *, const char *);
+
+static void do_authenticated1(Authctxt *);
+static void do_authenticated2(Authctxt *);
-void do_authenticated1(Authctxt *authctxt);
-void do_authenticated2(Authctxt *authctxt);
+static void session_close(Session *);
+static int session_pty_req(Session *);
/* import */
extern ServerOptions options;
@@ -122,11 +124,8 @@ extern u_int utmp_len;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
-/* Local Xauthority file. */
-static char *xauthfile;
-
/* original command from peer. */
-char *original_command = NULL;
+const char *original_command = NULL;
/* data */
#define MAX_SESSIONS 10
@@ -169,56 +168,17 @@ do_authenticated(Authctxt *authctxt)
else
do_authenticated1(authctxt);
- /* remote user's local Xauthority file and agent socket */
- if (xauthfile)
- xauthfile_cleanup_proc(authctxt->pw);
+ /* remove agent socket */
if (auth_get_socket_name())
auth_sock_cleanup_proc(authctxt->pw);
-}
-
-/*
- * Remove local Xauthority file.
- */
-void
-xauthfile_cleanup_proc(void *_pw)
-{
- struct passwd *pw = _pw;
- char *p;
-
- debug("xauthfile_cleanup_proc called");
- if (xauthfile != NULL) {
- temporarily_use_uid(pw);
- unlink(xauthfile);
- p = strrchr(xauthfile, '/');
- if (p != NULL) {
- *p = '\0';
- rmdir(xauthfile);
- }
- xfree(xauthfile);
- xauthfile = NULL;
- restore_uid();
- }
-}
-
-/*
- * Function to perform cleanup if we get aborted abnormally (e.g., due to a
- * dropped connection).
- */
-void
-pty_cleanup_proc(void *session)
-{
- Session *s=session;
- if (s == NULL)
- fatal("pty_cleanup_proc: no session");
- debug("pty_cleanup_proc: %s", s->tty);
-
- if (s->pid != 0) {
- /* Record that the user has logged out. */
- record_logout(s->pid, s->tty);
- }
-
- /* Release the pseudo-tty. */
- pty_release(s->tty);
+#ifdef KRB4
+ if (options.kerberos_ticket_cleanup)
+ krb4_cleanup_proc(authctxt);
+#endif
+#ifdef KRB5
+ if (options.kerberos_ticket_cleanup)
+ krb5_cleanup_proc(authctxt);
+#endif
}
/*
@@ -227,17 +187,18 @@ pty_cleanup_proc(void *session)
* terminals are allocated, X11, TCP/IP, and authentication agent forwardings
* are requested, etc.
*/
-void
+static void
do_authenticated1(Authctxt *authctxt)
{
Session *s;
char *command;
- int success, type, fd, n_bytes, plen, screen_flag, have_pty = 0;
+ int success, type, screen_flag;
int compression_level = 0, enable_compression_after_reply = 0;
u_int proto_len, data_len, dlen;
struct stat st;
s = session_new();
+ s->authctxt = authctxt;
s->pw = authctxt->pw;
/*
@@ -248,16 +209,16 @@ do_authenticated1(Authctxt *authctxt)
success = 0;
/* Get a packet from the client. */
- type = packet_read(&plen);
+ type = packet_read();
/* Process the packet. */
switch (type) {
case SSH_CMSG_REQUEST_COMPRESSION:
- packet_integrity_check(plen, 4, type);
compression_level = packet_get_int();
+ packet_check_eom();
if (compression_level < 1 || compression_level > 9) {
packet_send_debug("Received illegal compression level %d.",
- compression_level);
+ compression_level);
break;
}
/* Enable compression after we have responded with SUCCESS. */
@@ -266,71 +227,10 @@ do_authenticated1(Authctxt *authctxt)
break;
case SSH_CMSG_REQUEST_PTY:
- if (no_pty_flag) {
- debug("Allocating a pty not permitted for this authentication.");
- break;
- }
- if (have_pty)
- packet_disconnect("Protocol error: you already have a pty.");
-
- debug("Allocating pty.");
-
- /* Allocate a pty and open it. */
- if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
- sizeof(s->tty))) {
- error("Failed to allocate pty.");
- break;
- }
- fatal_add_cleanup(pty_cleanup_proc, (void *)s);
- pty_setowner(s->pw, s->tty);
-
- /* Get TERM from the packet. Note that the value may be of arbitrary length. */
- s->term = packet_get_string(&dlen);
- packet_integrity_check(dlen, strlen(s->term), type);
- /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
- /* Remaining bytes */
- n_bytes = plen - (4 + dlen + 4 * 4);
-
- if (strcmp(s->term, "") == 0) {
- xfree(s->term);
- s->term = NULL;
- }
- /* Get window size from the packet. */
- s->row = packet_get_int();
- s->col = packet_get_int();
- s->xpixel = packet_get_int();
- s->ypixel = packet_get_int();
- pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
-
- /* Get tty modes from the packet. */
- tty_parse_modes(s->ttyfd, &n_bytes);
- packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
-
- session_proctitle(s);
-
- /* Indicate that we now have a pty. */
- success = 1;
- have_pty = 1;
+ success = session_pty_req(s);
break;
case SSH_CMSG_X11_REQUEST_FORWARDING:
- if (!options.x11_forwarding) {
- packet_send_debug("X11 forwarding disabled in server configuration file.");
- break;
- }
- if (!options.xauth_location ||
- (stat(options.xauth_location, &st) == -1)) {
- packet_send_debug("No xauth program; cannot forward with spoofing.");
- break;
- }
- if (no_x11_forwarding_flag) {
- packet_send_debug("X11 forwarding not permitted for this authentication.");
- break;
- }
- debug("Received request for X11 forwarding with auth spoofing.");
- if (s->display != NULL)
- packet_disconnect("Protocol error: X11 display already set.");
-
s->auth_proto = packet_get_string(&proto_len);
s->auth_data = packet_get_string(&data_len);
@@ -342,39 +242,18 @@ do_authenticated1(Authctxt *authctxt)
if (!screen_flag)
debug2("Buggy client: "
"X11 screen flag missing");
- packet_integrity_check(plen,
- 4 + proto_len + 4 + data_len + 4, type);
s->screen = packet_get_int();
} else {
- packet_integrity_check(plen,
- 4 + proto_len + 4 + data_len, type);
s->screen = 0;
}
- s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
-
- if (s->display == NULL)
- break;
-
- /* Setup to always have a local .Xauthority. */
- xauthfile = xmalloc(MAXPATHLEN);
- strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
- temporarily_use_uid(s->pw);
- if (mkdtemp(xauthfile) == NULL) {
- restore_uid();
- error("private X11 dir: mkdtemp %s failed: %s",
- xauthfile, strerror(errno));
- xfree(xauthfile);
- xauthfile = NULL;
- /* XXXX remove listening channels */
- break;
+ packet_check_eom();
+ success = session_setup_x11fwd(s);
+ if (!success) {
+ xfree(s->auth_proto);
+ xfree(s->auth_data);
+ s->auth_proto = NULL;
+ s->auth_data = NULL;
}
- strlcat(xauthfile, "/cookies", MAXPATHLEN);
- fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (fd >= 0)
- close(fd);
- restore_uid();
- fatal_add_cleanup(xauthfile_cleanup_proc, s->pw);
- success = 1;
break;
case SSH_CMSG_AGENT_REQUEST_FORWARDING:
@@ -405,28 +284,70 @@ do_authenticated1(Authctxt *authctxt)
success = 1;
break;
+#if defined(AFS) || defined(KRB5)
+ case SSH_CMSG_HAVE_KERBEROS_TGT:
+ if (!options.kerberos_tgt_passing) {
+ verbose("Kerberos TGT passing disabled.");
+ } else {
+ char *kdata = packet_get_string(&dlen);
+ packet_check_eom();
+
+ /* XXX - 0x41, see creds_to_radix version */
+ if (kdata[0] != 0x41) {
+#ifdef KRB5
+ krb5_data tgt;
+ tgt.data = kdata;
+ tgt.length = dlen;
+
+ if (auth_krb5_tgt(s->authctxt, &tgt))
+ success = 1;
+ else
+ verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);
+#endif /* KRB5 */
+ } else {
+#ifdef AFS
+ if (auth_krb4_tgt(s->authctxt, kdata))
+ success = 1;
+ else
+ verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);
+#endif /* AFS */
+ }
+ xfree(kdata);
+ }
+ break;
+#endif /* AFS || KRB5 */
+
+#ifdef AFS
+ case SSH_CMSG_HAVE_AFS_TOKEN:
+ if (!options.afs_token_passing || !k_hasafs()) {
+ verbose("AFS token passing disabled.");
+ } else {
+ /* Accept AFS token. */
+ char *token = packet_get_string(&dlen);
+ packet_check_eom();
+
+ if (auth_afs_token(s->authctxt, token))
+ success = 1;
+ else
+ verbose("AFS token refused for %.100s",
+ s->authctxt->user);
+ xfree(token);
+ }
+ break;
+#endif /* AFS */
+
case SSH_CMSG_EXEC_SHELL:
case SSH_CMSG_EXEC_CMD:
if (type == SSH_CMSG_EXEC_CMD) {
command = packet_get_string(&dlen);
debug("Exec command '%.500s'", command);
- packet_integrity_check(plen, 4 + dlen, type);
+ do_exec(s, command);
+ xfree(command);
} else {
- command = NULL;
- packet_integrity_check(plen, 0, type);
- }
- if (forced_command != NULL) {
- original_command = command;
- command = forced_command;
- debug("Forced command '%.500s'", forced_command);
+ do_exec(s, NULL);
}
- if (have_pty)
- do_exec_pty(s, command);
- else
- do_exec_no_pty(s, command);
-
- if (command != NULL)
- xfree(command);
+ packet_check_eom();
+ session_close(s);
return;
default:
@@ -594,26 +515,22 @@ do_exec_pty(Session *s, const char *command)
/* Fork the child. */
if ((pid = fork()) == 0) {
+
/* Child. Reinitialize the log because the pid has changed. */
log_init(__progname, options.log_level, options.log_facility, log_stderr);
-
/* Close the master side of the pseudo tty. */
close(ptyfd);
/* Make the pseudo tty our controlling tty. */
pty_make_controlling_tty(&ttyfd, s->tty);
- /* Redirect stdin from the pseudo tty. */
- if (dup2(ttyfd, fileno(stdin)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stdout to the pseudo tty. */
- if (dup2(ttyfd, fileno(stdout)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stderr to the pseudo tty. */
- if (dup2(ttyfd, fileno(stderr)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
+ /* Redirect stdin/stdout/stderr from the pseudo tty. */
+ if (dup2(ttyfd, 0) < 0)
+ error("dup2 stdin: %s", strerror(errno));
+ if (dup2(ttyfd, 1) < 0)
+ error("dup2 stdout: %s", strerror(errno));
+ if (dup2(ttyfd, 2) < 0)
+ error("dup2 stderr: %s", strerror(errno));
/* Close the extra descriptor for the pseudo tty. */
close(ttyfd);
@@ -655,10 +572,31 @@ do_exec_pty(Session *s, const char *command)
} else {
server_loop(pid, ptyfd, fdout, -1);
/* server_loop _has_ closed ptyfd and fdout. */
- session_pty_cleanup(s);
}
}
+/*
+ * This is called to fork and execute a command. If another command is
+ * to be forced, execute that instead.
+ */
+void
+do_exec(Session *s, const char *command)
+{
+ if (forced_command) {
+ original_command = command;
+ command = forced_command;
+ debug("Forced command '%.900s'", command);
+ }
+
+ if (s->ttyfd != -1)
+ do_exec_pty(s, command);
+ else
+ do_exec_no_pty(s, command);
+
+ original_command = NULL;
+}
+
+
/* administrative, login(1)-like work */
void
do_login(Session *s, const char *command)
@@ -689,7 +627,7 @@ do_login(Session *s, const char *command)
if (packet_connection_is_on_socket()) {
fromlen = sizeof(from);
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & from, &fromlen) < 0) {
+ (struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
fatal_cleanup();
}
@@ -704,7 +642,7 @@ do_login(Session *s, const char *command)
/* Record that there was a login on that tty from the remote host. */
record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
- get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
+ get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping),
(struct sockaddr *)&from);
#ifdef USE_PAM
@@ -717,12 +655,10 @@ do_login(Session *s, const char *command)
do_pam_chauthtok();
}
#endif
-
#ifdef USE_PAM
if (!check_quietlogin(s, command) && !pam_password_change_required())
print_pam_messages();
#endif /* USE_PAM */
-
#ifdef __FreeBSD__
if (pw->pw_change || pw->pw_expire)
(void)gettimeofday(&tv, NULL);
@@ -761,7 +697,7 @@ do_login(Session *s, const char *command)
log(
"LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s",
pw->pw_name, get_remote_name_or_ip(utmp_len,
- options.reverse_mapping_check), s->tty);
+ options.verify_reverse_mapping), s->tty);
exit(254);
} else if (pw->pw_expire - tv.tv_sec < warntime &&
!check_quietlogin(s, command))
@@ -771,14 +707,13 @@ do_login(Session *s, const char *command)
}
#endif /* !USE_PAM */
#endif /* __FreeBSD__ */
-
#ifdef HAVE_LOGIN_CAP
if (!auth_ttyok(lc, s->tty)) {
(void)printf("Permission denied.\n");
log(
"LOGIN %.200s REFUSED (TTY) FROM %.200s ON TTY %.200s",
pw->pw_name, get_remote_name_or_ip(utmp_len,
- options.reverse_mapping_check), s->tty);
+ options.verify_reverse_mapping), s->tty);
exit(254);
}
#endif /* HAVE_LOGIN_CAP */
@@ -791,11 +726,11 @@ do_login(Session *s, const char *command)
* are going to another machine). Login(1) will do this for
* us as well, so check if login(1) is used
*/
+
if (command == NULL && options.print_lastlog &&
last_login_time != 0 && !check_quietlogin(s, command) &&
!options.use_login) {
time_string = ctime(&last_login_time);
- /* Remove the trailing newline. */
if (strchr(time_string, '\n'))
*strchr(time_string, '\n') = 0;
if (strcmp(hostname, "") == 0)
@@ -843,9 +778,9 @@ do_motd(void)
#ifdef HAVE_LOGIN_CAP
f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
"/etc/motd"), "r");
-#else /* !HAVE_LOGIN_CAP */
+#else
f = fopen("/etc/motd", "r");
-#endif /* HAVE_LOGIN_CAP */
+#endif
if (f) {
while (fgets(buf, sizeof(buf), f))
fputs(buf, stdout);
@@ -854,6 +789,7 @@ do_motd(void)
}
}
+
/*
* Check for quiet login, either .hushlogin or command given.
*/
@@ -861,7 +797,7 @@ int
check_quietlogin(Session *s, const char *command)
{
char buf[256];
- struct passwd * pw = s->pw;
+ struct passwd *pw = s->pw;
struct stat st;
/* Return 1 if .hushlogin exists or a command given. */
@@ -882,9 +818,9 @@ check_quietlogin(Session *s, const char *command)
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden.
*/
-void
+static void
child_set_env(char ***envp, u_int *envsizep, const char *name,
- const char *value)
+ const char *value)
{
u_int i, namelen;
char **env;
@@ -923,9 +859,9 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
* Otherwise, it must consist of empty lines, comments (line starts with '#')
* and assignments of the form name=value. No other forms are allowed.
*/
-void
+static void
read_environment_file(char ***env, u_int *envsize,
- const char *filename)
+ const char *filename)
{
FILE *f;
char buf[4096];
@@ -962,7 +898,8 @@ read_environment_file(char ***env, u_int *envsize,
/*
* Sets any environment variables which have been specified by PAM
*/
-void do_pam_environment(char ***env, int *envsize)
+static void
+do_pam_environment(char ***env, int *envsize)
{
char *equals, var_name[512], var_val[512];
char **pam_env;
@@ -988,148 +925,18 @@ void do_pam_environment(char ***env, int *envsize)
}
#endif /* USE_PAM */
-
-/*
- * Performs common processing for the child, such as setting up the
- * environment, closing extra file descriptors, setting the user and group
- * ids, and executing the command or shell.
- */
-void
-do_child(Session *s, const char *command)
+static char **
+do_setup_env(Session *s, const char *shell)
{
- const char *shell, *hostname = NULL, *cp = NULL;
- struct passwd * pw = s->pw;
char buf[256];
- char cmd[1024];
- FILE *f = NULL;
- u_int envsize, i;
- char **env = NULL;
- extern char **environ;
- struct stat st;
- char *argv[10];
- int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;
-
- /* remove hostkey from the child's memory */
- destroy_sensitive_data();
-
- /* login(1) is only called if we execute the login shell */
- if (options.use_login && command != NULL)
- options.use_login = 0;
-
-#ifndef USE_PAM
- if (!options.use_login) {
-#ifdef HAVE_LOGIN_CAP
- if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
- f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
- _PATH_NOLOGIN), "r");
-#else
- if (pw->pw_uid)
- f = fopen(_PATH_NOLOGIN, "r");
-#endif
- if (f) {
- /* /etc/nologin exists. Print its contents and exit. */
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- exit(254);
- }
- }
-#endif /* !USE_PAM */
- /* Set login name, uid, gid, and groups. */
- /* Login(1) does this as well, and it needs uid 0 for the "-h"
- switch, so we let login(1) to this for us. */
- if (!options.use_login) {
-#ifdef HAVE_LOGIN_CAP
- char **tmpenv;
-
- /* Initialize temp environment */
- envsize = 64;
- env = xmalloc(envsize * sizeof(char *));
- env[0] = NULL;
-
- child_set_env(&env, &envsize, "PATH",
- (pw->pw_uid == 0) ?
- _PATH_STDPATH : _PATH_DEFPATH);
-
- snprintf(buf, sizeof buf, "%.200s/%.50s",
- _PATH_MAILDIR, pw->pw_name);
- child_set_env(&env, &envsize, "MAIL", buf);
-
- if (getenv("TZ"))
- child_set_env(&env, &envsize, "TZ", getenv("TZ"));
-
- /* Save parent environment */
- tmpenv = environ;
- environ = env;
-
- if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETALL) < 0)
- fatal("setusercontext failed: %s", strerror(errno));
-
- /* Restore parent environment */
- env = environ;
- environ = tmpenv;
-
- for (envsize = 0; env[envsize] != NULL; ++envsize)
- ;
- envsize = (envsize < 100) ? 100 : envsize + 16;
- env = xrealloc(env, envsize * sizeof(char *));
-
-#endif /* !HAVE_LOGIN_CAP */
- if (getuid() == 0 || geteuid() == 0) {
-#ifdef HAVE_LOGIN_CAP
- if (setusercontext(lc, pw, pw->pw_uid,
- (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
- perror("unable to set user context");
- exit(1);
- }
-#else
- if (setlogin(pw->pw_name) < 0)
- error("setlogin failed: %s", strerror(errno));
- if (setgid(pw->pw_gid) < 0) {
- perror("setgid");
- exit(1);
- }
- /* Initialize the group list. */
- if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
- perror("initgroups");
- exit(1);
- }
- endgrent();
-
- /* Permanently switch to the desired uid. */
- permanently_set_uid(pw);
-#endif /* HAVE_LOGIN_CAP */
- }
- if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
- fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
- }
- /*
- * 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;
-#ifdef HAVE_LOGIN_CAP
- shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
-#endif
-
-#ifdef AFS
- /* Try to get AFS tokens for the local cell. */
- if (k_hasafs()) {
- char cell[64];
-
- if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
- krb_afslog(cell, 0);
-
- krb_afslog(0, 0);
- }
-#endif /* AFS */
+ u_int i, envsize;
+ char **env;
+ struct passwd *pw = s->pw;
/* Initialize the environment. */
- if (env == NULL) {
- envsize = 100;
- env = xmalloc(envsize * sizeof(char *));
- env[0] = NULL;
- }
+ envsize = 100;
+ env = xmalloc(envsize * sizeof(char *));
+ env[0] = NULL;
if (!options.use_login) {
/* Set basic environment. */
@@ -1155,23 +962,24 @@ do_child(Session *s, const char *command)
/* Set custom environment options from RSA authentication. */
if (!options.use_login) {
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- char *s = ce->s;
- int i;
- for (i = 0; s[i] != '=' && s[i]; i++);
- if (s[i] == '=') {
- s[i] = 0;
- child_set_env(&env, &envsize, s, s + i + 1);
+ while (custom_environment) {
+ struct envstring *ce = custom_environment;
+ char *s = ce->s;
+
+ for (i = 0; s[i] != '=' && s[i]; i++)
+ ;
+ if (s[i] == '=') {
+ s[i] = 0;
+ child_set_env(&env, &envsize, s, s + i + 1);
+ }
+ custom_environment = ce->next;
+ xfree(ce->s);
+ xfree(ce);
}
- custom_environment = ce->next;
- xfree(ce->s);
- xfree(ce);
- }
}
snprintf(buf, sizeof buf, "%.50s %d %d",
- get_remote_ipaddr(), get_remote_port(), get_local_port());
+ get_remote_ipaddr(), get_remote_port(), get_local_port());
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
if (s->ttyfd != -1)
@@ -1183,51 +991,25 @@ do_child(Session *s, const char *command)
if (original_command)
child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
original_command);
-
#ifdef KRB4
- {
- extern char *ticket;
-
- if (ticket)
- child_set_env(&env, &envsize, "KRBTKFILE", ticket);
- }
-#endif /* KRB4 */
+ if (s->authctxt->krb4_ticket_file)
+ child_set_env(&env, &envsize, "KRBTKFILE",
+ s->authctxt->krb4_ticket_file);
+#endif
#ifdef KRB5
-{
- extern krb5_ccache mem_ccache;
-
- if (mem_ccache) {
- krb5_error_code problem;
- krb5_ccache ccache;
-#ifdef AFS
- if (k_hasafs())
- krb5_afslog(ssh_context, mem_ccache, NULL, NULL);
-#endif /* AFS */
-
- problem = krb5_cc_default(ssh_context, &ccache);
- if (problem) {}
- else {
- problem = krb5_cc_copy_cache(ssh_context, mem_ccache, ccache);
- if (problem) {}
- }
-
- krb5_cc_close(ssh_context, ccache);
- }
-
- krb5_cleanup_proc(NULL);
- }
-#endif /* KRB5 */
+ if (s->authctxt->krb5_ticket_file)
+ child_set_env(&env, &envsize, "KRB5CCNAME",
+ s->authctxt->krb5_ticket_file);
+#endif
#ifdef USE_PAM
/* Pull in any environment variables that may have been set by PAM. */
do_pam_environment(&env, &envsize);
#endif /* USE_PAM */
- if (xauthfile)
- child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
if (auth_get_socket_name() != NULL)
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
- auth_get_socket_name());
+ auth_get_socket_name());
/* read $HOME/.ssh/environment. */
if (!options.use_login) {
@@ -1241,10 +1023,178 @@ do_child(Session *s, const char *command)
for (i = 0; env[i]; i++)
fprintf(stderr, " %.200s\n", env[i]);
}
+ return env;
+}
+
+/*
+ * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
+ * first in this order).
+ */
+static void
+do_rc_files(Session *s, const char *shell)
+{
+ FILE *f = NULL;
+ char cmd[1024];
+ int do_xauth;
+ struct stat st;
+
+ do_xauth =
+ s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
+
+ /* ignore _PATH_SSH_USER_RC for subsystems */
+ if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
+ snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
+ shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
+ if (debug_flag)
+ fprintf(stderr, "Running %s\n", cmd);
+ f = popen(cmd, "w");
+ if (f) {
+ if (do_xauth)
+ fprintf(f, "%s %s\n", s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n",
+ _PATH_SSH_USER_RC);
+ } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
+ if (debug_flag)
+ fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
+ _PATH_SSH_SYSTEM_RC);
+ f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
+ if (f) {
+ if (do_xauth)
+ fprintf(f, "%s %s\n", s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n",
+ _PATH_SSH_SYSTEM_RC);
+ } else if (do_xauth && options.xauth_location != NULL) {
+ /* Add authority data to .Xauthority if appropriate. */
+ if (debug_flag) {
+ fprintf(stderr,
+ "Running %.100s add "
+ "%.100s %.100s %.100s\n",
+ options.xauth_location, s->auth_display,
+ s->auth_proto, s->auth_data);
+ }
+ snprintf(cmd, sizeof cmd, "%s -q -",
+ options.xauth_location);
+ f = popen(cmd, "w");
+ if (f) {
+ fprintf(f, "add %s %s %s\n",
+ s->auth_display, s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else {
+ fprintf(stderr, "Could not run %s\n",
+ cmd);
+ }
+ }
+}
+
+static void
+do_nologin(struct passwd *pw)
+{
+ FILE *f = NULL;
+ char buf[1024];
+
+#ifdef HAVE_LOGIN_CAP
+ if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+ f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
+ _PATH_NOLOGIN), "r");
+#else
+ if (pw->pw_uid)
+ f = fopen(_PATH_NOLOGIN, "r");
+#endif
+ if (f) {
+ /* /etc/nologin exists. Print its contents and exit. */
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ exit(254);
+ }
+}
+
+/* Set login name, uid, gid, and groups. */
+static void
+do_setusercontext(struct passwd *pw)
+{
+ if (getuid() == 0 || geteuid() == 0) {
+#ifdef HAVE_LOGIN_CAP
+ if (setusercontext(lc, pw, pw->pw_uid,
+ (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
+ perror("unable to set user context");
+ exit(1);
+ }
+#else
+ if (setlogin(pw->pw_name) < 0)
+ error("setlogin failed: %s", strerror(errno));
+ if (setgid(pw->pw_gid) < 0) {
+ perror("setgid");
+ exit(1);
+ }
+ /* Initialize the group list. */
+ if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+ perror("initgroups");
+ exit(1);
+ }
+ endgrent();
+
+ /* Permanently switch to the desired uid. */
+ permanently_set_uid(pw);
+#endif
+ }
+ if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+ fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+}
+
+/*
+ * Performs common processing for the child, such as setting up the
+ * environment, closing extra file descriptors, setting the user and group
+ * ids, and executing the command or shell.
+ */
+void
+do_child(Session *s, const char *command)
+{
+ extern char **environ;
+ char **env;
+ char *argv[10];
+ const char *shell, *shell0, *hostname = NULL;
+ struct passwd *pw = s->pw;
+ u_int i;
+
+ /* remove hostkey from the child's memory */
+ destroy_sensitive_data();
+
+ /* login(1) is only called if we execute the login shell */
+ if (options.use_login && command != NULL)
+ options.use_login = 0;
+
+ /*
+ * Login(1) does this as well, and it needs uid 0 for the "-h"
+ * switch, so we let login(1) to this for us.
+ */
+ if (!options.use_login) {
+ do_nologin(pw);
+ do_setusercontext(pw);
+ }
+
+ /*
+ * 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;
+#ifdef HAVE_LOGIN_CAP
+ shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
+#endif
+
+ env = do_setup_env(s, shell);
+
/* we have to stash the hostname before we close our socket. */
if (options.use_login)
hostname = get_remote_name_or_ip(utmp_len,
- options.reverse_mapping_check);
+ options.verify_reverse_mapping);
/*
* Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important
@@ -1272,45 +1222,6 @@ do_child(Session *s, const char *command)
endpwent();
/*
- * Restore any signal handlers set by sshd previously that should
- * be restored to their initial state.
- */
- signal(SIGPIPE, SIG_DFL);
-
- /* Change current directory to the user\'s home directory. */
- if (
-#ifdef __FreeBSD__
- !*pw->pw_dir ||
-#endif /* __FreeBSD__ */
- chdir(pw->pw_dir) < 0
- ) {
-#ifdef HAVE_LOGIN_CAP
- if (login_getcapbool(lc, "requirehome", 0)) {
- (void)printf("Home directory not available\n");
- log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s",
- pw->pw_name, ttyname);
- exit(254);
- }
-#endif /* HAVE_LOGIN_CAP */
-#ifdef __FreeBSD__
- if (chdir("/") < 0) {
- (void)printf("Cannot find root directory\n");
- log("LOGIN %.200s REFUSED (ROOTDIR) ON TTY %.200s",
- pw->pw_name, ttyname);
- exit(254);
- }
- if (!check_quietlogin(s, command) || *pw->pw_dir)
- (void)printf(
- "No home directory.\nLogging in with home = \"/\".\n");
-
-#else /* !__FreeBSD__ */
-
- fprintf(stderr, "Could not chdir to home directory %s: %s\n",
- pw->pw_dir, strerror(errno));
-#endif /* __FreeBSD__ */
- }
-
- /*
* Close any extra open file descriptors so that we don\'t have them
* hanging around in clients. Note that we want to do this after
* initgroups, because at least on Solaris 2.3 it leaves file
@@ -1320,153 +1231,89 @@ do_child(Session *s, const char *command)
close(i);
/*
- * 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/ssh/sshrc and xauth are run in the proper environment.
*/
environ = env;
- /*
- * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
- * in this order).
- */
- if (!options.use_login) {
- /* ignore _PATH_SSH_USER_RC for subsystems */
- if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
- snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
- shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
- if (debug_flag)
- fprintf(stderr, "Running %s\n", cmd);
- f = popen(cmd, "w");
- if (f) {
- if (do_xauth)
- fprintf(f, "%s %s\n", s->auth_proto,
- s->auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n",
- _PATH_SSH_USER_RC);
- } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
- if (debug_flag)
- fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
- _PATH_SSH_SYSTEM_RC);
- f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
- if (f) {
- if (do_xauth)
- fprintf(f, "%s %s\n", s->auth_proto,
- s->auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n",
- _PATH_SSH_SYSTEM_RC);
- } else if (do_xauth && options.xauth_location != NULL) {
- /* Add authority data to .Xauthority if appropriate. */
- char *screen = strchr(s->display, ':');
-
- if (debug_flag) {
- fprintf(stderr,
- "Running %.100s add "
- "%.100s %.100s %.100s\n",
- options.xauth_location, s->display,
- s->auth_proto, s->auth_data);
- if (screen != NULL)
- fprintf(stderr,
- "Adding %.*s/unix%s %s %s\n",
- (int)(screen - s->display),
- s->display, screen,
- s->auth_proto, s->auth_data);
- }
- snprintf(cmd, sizeof cmd, "%s -q -",
- options.xauth_location);
- f = popen(cmd, "w");
- if (f) {
- fprintf(f, "add %s %s %s\n", s->display,
- s->auth_proto, s->auth_data);
- if (screen != NULL)
- fprintf(f, "add %.*s/unix%s %s %s\n",
- (int)(screen - s->display),
- s->display, screen,
- s->auth_proto,
- s->auth_data);
- pclose(f);
- } else {
- fprintf(stderr, "Could not run %s\n",
- cmd);
- }
- }
- /* Get the last component of the shell name. */
- cp = strrchr(shell, '/');
- if (cp)
- cp++;
- else
- cp = shell;
+#ifdef AFS
+ /* Try to get AFS tokens for the local cell. */
+ if (k_hasafs()) {
+ char cell[64];
+
+ if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+ krb_afslog(cell, 0);
+
+ krb_afslog(0, 0);
+ }
+#endif /* AFS */
+
+ /* Change current directory to the user\'s home directory. */
+ if (chdir(pw->pw_dir) < 0) {
+ fprintf(stderr, "Could not chdir to home directory %s: %s\n",
+ pw->pw_dir, strerror(errno));
+#ifdef HAVE_LOGIN_CAP
+ if (login_getcapbool(lc, "requirehome", 0))
+ exit(1);
+#endif
}
+ if (!options.use_login)
+ do_rc_files(s, shell);
+
/* restore SIGPIPE for child */
signal(SIGPIPE, SIG_DFL);
+ if (options.use_login) {
+ /* Launch login(1). */
+
+ execl("/usr/bin/login", "login", "-h", hostname,
+ "-p", "-f", "--", pw->pw_name, (char *)NULL);
+
+ /* Login couldn't be executed, die. */
+
+ perror("login");
+ exit(1);
+ }
+
+ /* Get the last component of the shell name. */
+ if ((shell0 = strrchr(shell, '/')) != NULL)
+ shell0++;
+ else
+ shell0 = 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 indicate that
* this is a login shell.
*/
if (!command) {
- if (!options.use_login) {
- char buf[256];
-
- /*
- * Check for mail if we have a tty and it was enabled
- * in server options.
- */
- if (s->ttyfd != -1 && options.check_mail) {
- char *mailbox;
- struct stat mailstat;
-
- mailbox = getenv("MAIL");
- if (mailbox != NULL) {
- if (stat(mailbox, &mailstat) != 0 ||
- mailstat.st_size == 0)
-#ifdef __FreeBSD__
- ;
-#else /* !__FreeBSD__ */
- printf("No mail.\n");
-#endif /* __FreeBSD__ */
- else if (mailstat.st_mtime < mailstat.st_atime)
- printf("You have mail.\n");
- else
- printf("You have new mail.\n");
- }
- }
- /* Start the shell. Set initial character to '-'. */
- buf[0] = '-';
- strncpy(buf + 1, cp, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = 0;
+ char argv0[256];
- /* Execute the shell. */
- argv[0] = buf;
- argv[1] = NULL;
- execve(shell, argv, env);
+ /* Start the shell. Set initial character to '-'. */
+ argv0[0] = '-';
- /* Executing the shell failed. */
+ if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
+ >= sizeof(argv0) - 1) {
+ errno = EINVAL;
perror(shell);
exit(1);
+ }
- } else {
- /* Launch login(1). */
-
- execl("/usr/bin/login", "login", "-h", hostname,
- "-p", "-f", "--", pw->pw_name, NULL);
-
- /* Login couldn't be executed, die. */
+ /* Execute the shell. */
+ argv[0] = argv0;
+ argv[1] = NULL;
+ execve(shell, argv, env);
- perror("login");
- exit(1);
- }
+ /* Executing the shell failed. */
+ perror(shell);
+ exit(1);
}
/*
* Execute the command using the user's shell. This uses the -c
* option to execute the command.
*/
- argv[0] = (char *) cp;
+ argv[0] = (char *) shell0;
argv[1] = "-c";
argv[2] = (char *) command;
argv[3] = NULL;
@@ -1482,13 +1329,12 @@ session_new(void)
static int did_init = 0;
if (!did_init) {
debug("session_new: init");
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
sessions[i].used = 0;
- sessions[i].self = i;
}
did_init = 1;
}
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
if (! s->used) {
memset(s, 0, sizeof(*s));
@@ -1496,6 +1342,7 @@ session_new(void)
s->ptyfd = -1;
s->ttyfd = -1;
s->used = 1;
+ s->self = i;
debug("session_new: session %d", i);
return s;
}
@@ -1503,11 +1350,11 @@ session_new(void)
return NULL;
}
-void
+static void
session_dump(void)
{
int i;
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
debug("dump: used %d session %d %p channel %d pid %d",
s->used,
@@ -1519,7 +1366,7 @@ session_dump(void)
}
int
-session_open(int chanid)
+session_open(Authctxt *authctxt, int chanid)
{
Session *s = session_new();
debug("session_open: channel %d", chanid);
@@ -1527,7 +1374,8 @@ session_open(int chanid)
error("no more sessions");
return 0;
}
- s->pw = auth_get_user();
+ s->authctxt = authctxt;
+ s->pw = authctxt->pw;
if (s->pw == NULL)
fatal("no user for session %d", s->self);
debug("session_open: session %d: link with channel %d", s->self, chanid);
@@ -1535,11 +1383,11 @@ session_open(int chanid)
return 1;
}
-Session *
+static Session *
session_by_channel(int id)
{
int i;
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
if (s->used && s->chanid == id) {
debug("session_by_channel: session %d channel %d", i, id);
@@ -1551,12 +1399,12 @@ session_by_channel(int id)
return NULL;
}
-Session *
+static Session *
session_by_pid(pid_t pid)
{
int i;
debug("session_by_pid: pid %d", pid);
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
if (s->used && s->pid == pid)
return s;
@@ -1566,31 +1414,42 @@ session_by_pid(pid_t pid)
return NULL;
}
-int
+static int
session_window_change_req(Session *s)
{
s->col = packet_get_int();
s->row = packet_get_int();
s->xpixel = packet_get_int();
s->ypixel = packet_get_int();
- packet_done();
+ packet_check_eom();
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
return 1;
}
-int
+static int
session_pty_req(Session *s)
{
u_int len;
int n_bytes;
- if (no_pty_flag)
+ if (no_pty_flag) {
+ debug("Allocating a pty not permitted for this authentication.");
return 0;
- if (s->ttyfd != -1)
+ }
+ if (s->ttyfd != -1) {
+ packet_disconnect("Protocol error: you already have a pty.");
return 0;
+ }
+
s->term = packet_get_string(&len);
- s->col = packet_get_int();
- s->row = packet_get_int();
+
+ if (compat20) {
+ s->col = packet_get_int();
+ s->row = packet_get_int();
+ } else {
+ s->row = packet_get_int();
+ s->col = packet_get_int();
+ }
s->xpixel = packet_get_int();
s->ypixel = packet_get_int();
@@ -1598,9 +1457,12 @@ session_pty_req(Session *s)
xfree(s->term);
s->term = NULL;
}
+
/* Allocate a pty and open it. */
+ debug("Allocating pty.");
if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
- xfree(s->term);
+ if (s->term)
+ xfree(s->term);
s->term = NULL;
s->ptyfd = -1;
s->ttyfd = -1;
@@ -1608,151 +1470,108 @@ session_pty_req(Session *s)
return 0;
}
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
+
+ /* for SSH1 the tty modes length is not given */
+ if (!compat20)
+ n_bytes = packet_remaining();
+ tty_parse_modes(s->ttyfd, &n_bytes);
+
/*
* Add a cleanup function to clear the utmp entry and record logout
* time in case we call fatal() (e.g., the connection gets closed).
*/
- fatal_add_cleanup(pty_cleanup_proc, (void *)s);
+ fatal_add_cleanup(session_pty_cleanup, (void *)s);
pty_setowner(s->pw, s->tty);
- /* Get window size from the packet. */
- pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
- /* Get tty modes from the packet. */
- tty_parse_modes(s->ttyfd, &n_bytes);
- packet_done();
+ /* Set window size from the packet. */
+ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+ packet_check_eom();
session_proctitle(s);
-
return 1;
}
-int
+static int
session_subsystem_req(Session *s)
{
+ struct stat st;
u_int len;
int success = 0;
- char *subsys = packet_get_string(&len);
+ char *cmd, *subsys = packet_get_string(&len);
int i;
- packet_done();
- log("subsystem request for %s", subsys);
+ packet_check_eom();
+ log("subsystem request for %.100s", subsys);
for (i = 0; i < options.num_subsystems; i++) {
- if(strcmp(subsys, options.subsystem_name[i]) == 0) {
- debug("subsystem: exec() %s", options.subsystem_command[i]);
+ if (strcmp(subsys, options.subsystem_name[i]) == 0) {
+ cmd = options.subsystem_command[i];
+ if (stat(cmd, &st) < 0) {
+ error("subsystem: cannot stat %s: %s", cmd,
+ strerror(errno));
+ break;
+ }
+ debug("subsystem: exec() %s", cmd);
s->is_subsystem = 1;
- do_exec_no_pty(s, options.subsystem_command[i]);
+ do_exec(s, cmd);
success = 1;
+ break;
}
}
if (!success)
- log("subsystem request for %s failed, subsystem not found", subsys);
+ log("subsystem request for %.100s failed, subsystem not found",
+ subsys);
xfree(subsys);
return success;
}
-int
+static int
session_x11_req(Session *s)
{
- int fd;
- struct stat st;
- if (no_x11_forwarding_flag) {
- debug("X11 forwarding disabled in user configuration file.");
- return 0;
- }
- if (!options.x11_forwarding) {
- debug("X11 forwarding disabled in server configuration file.");
- return 0;
- }
- if (!options.xauth_location ||
- (stat(options.xauth_location, &st) == -1)) {
- packet_send_debug("No xauth program; cannot forward with spoofing.");
- return 0;
- }
- if (xauthfile != NULL) {
- debug("X11 fwd already started.");
- return 0;
- }
-
- debug("Received request for X11 forwarding with auth spoofing.");
- if (s->display != NULL)
- packet_disconnect("Protocol error: X11 display already set.");
+ int success;
s->single_connection = packet_get_char();
s->auth_proto = packet_get_string(NULL);
s->auth_data = packet_get_string(NULL);
s->screen = packet_get_int();
- packet_done();
+ packet_check_eom();
- s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
- if (s->display == NULL) {
- xfree(s->auth_proto);
- xfree(s->auth_data);
- return 0;
- }
- xauthfile = xmalloc(MAXPATHLEN);
- strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
- temporarily_use_uid(s->pw);
- if (mkdtemp(xauthfile) == NULL) {
- restore_uid();
- error("private X11 dir: mkdtemp %s failed: %s",
- xauthfile, strerror(errno));
- xfree(xauthfile);
- xauthfile = NULL;
+ success = session_setup_x11fwd(s);
+ if (!success) {
xfree(s->auth_proto);
xfree(s->auth_data);
- /* XXXX remove listening channels */
- return 0;
+ s->auth_proto = NULL;
+ s->auth_data = NULL;
}
- strlcat(xauthfile, "/cookies", MAXPATHLEN);
- fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (fd >= 0)
- close(fd);
- restore_uid();
- fatal_add_cleanup(xauthfile_cleanup_proc, s->pw);
- return 1;
+ return success;
}
-int
+static int
session_shell_req(Session *s)
{
- /* if forced_command == NULL, the shell is execed */
- char *shell = forced_command;
- packet_done();
- if (s->ttyfd == -1)
- do_exec_no_pty(s, shell);
- else
- do_exec_pty(s, shell);
+ packet_check_eom();
+ do_exec(s, NULL);
return 1;
}
-int
+static int
session_exec_req(Session *s)
{
u_int len;
char *command = packet_get_string(&len);
- packet_done();
- if (forced_command) {
- original_command = command;
- command = forced_command;
- debug("Forced command '%.500s'", forced_command);
- }
- if (s->ttyfd == -1)
- do_exec_no_pty(s, command);
- else
- do_exec_pty(s, command);
- if (forced_command == NULL)
- xfree(command);
+ packet_check_eom();
+ do_exec(s, command);
+ xfree(command);
return 1;
}
-int
+static int
session_auth_agent_req(Session *s)
{
static int called = 0;
- packet_done();
+ packet_check_eom();
if (no_agent_forwarding_flag) {
debug("session_auth_agent_req: no_agent_forwarding_flag");
return 0;
@@ -1765,28 +1584,18 @@ session_auth_agent_req(Session *s)
}
}
-void
-session_input_channel_req(int id, void *arg)
+int
+session_input_channel_req(Channel *c, const char *rtype)
{
- u_int len;
- int reply;
int success = 0;
- char *rtype;
Session *s;
- Channel *c;
-
- rtype = packet_get_string(&len);
- reply = packet_get_char();
- s = session_by_channel(id);
- if (s == NULL)
- fatal("session_input_channel_req: channel %d: no session", id);
- c = channel_lookup(id);
- if (c == NULL)
- fatal("session_input_channel_req: channel %d: bad channel", id);
-
- debug("session_input_channel_req: session %d channel %d request %s reply %d",
- s->self, id, rtype, reply);
+ if ((s = session_by_channel(c->self)) == NULL) {
+ log("session_input_channel_req: no session %d req %.100s",
+ c->self, rtype);
+ return 0;
+ }
+ debug("session_input_channel_req: session %d req %s", s->self, rtype);
/*
* a session is in LARVAL state until a shell, a command
@@ -1810,14 +1619,7 @@ session_input_channel_req(int id, void *arg)
if (strcmp(rtype, "window-change") == 0) {
success = session_window_change_req(s);
}
-
- if (reply) {
- packet_start(success ?
- SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
- packet_put_int(c->remote_id);
- packet_send();
- }
- xfree(rtype);
+ return success;
}
void
@@ -1834,22 +1636,31 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
channel_set_fds(s->chanid,
fdout, fdin, fderr,
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
- 1);
+ 1,
+ CHAN_SES_WINDOW_DEFAULT);
}
-void
-session_pty_cleanup(Session *s)
+/*
+ * Function to perform pty cleanup. Also called if we get aborted abnormally
+ * (e.g., due to a dropped connection).
+ */
+static void
+session_pty_cleanup(void *session)
{
- if (s == NULL || s->ttyfd == -1)
+ Session *s = session;
+
+ if (s == NULL) {
+ error("session_pty_cleanup: no session");
+ return;
+ }
+ if (s->ttyfd == -1)
return;
debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
- /* Cancel the cleanup function. */
- fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
-
/* Record that the user has logged out. */
- record_logout(s->pid, s->tty);
+ if (s->pid != 0)
+ record_logout(s->pid, s->tty);
/* Release the pseudo-tty. */
pty_release(s->tty);
@@ -1861,29 +1672,28 @@ session_pty_cleanup(Session *s)
*/
if (close(s->ptymaster) < 0)
error("close(s->ptymaster): %s", strerror(errno));
+
+ /* unlink pty from session */
+ s->ttyfd = -1;
}
-void
+static void
session_exit_message(Session *s, int status)
{
Channel *c;
- if (s == NULL)
- fatal("session_close: no session");
- c = channel_lookup(s->chanid);
- if (c == NULL)
- fatal("session_close: session %d: no channel %d",
+
+ if ((c = channel_lookup(s->chanid)) == NULL)
+ fatal("session_exit_message: session %d: no channel %d",
s->self, s->chanid);
debug("session_exit_message: session %d channel %d pid %d",
s->self, s->chanid, s->pid);
if (WIFEXITED(status)) {
- channel_request_start(s->chanid,
- "exit-status", 0);
+ channel_request_start(s->chanid, "exit-status", 0);
packet_put_int(WEXITSTATUS(status));
packet_send();
} else if (WIFSIGNALED(status)) {
- channel_request_start(s->chanid,
- "exit-signal", 0);
+ channel_request_start(s->chanid, "exit-signal", 0);
packet_put_int(WTERMSIG(status));
packet_put_char(WCOREDUMP(status));
packet_put_cstring("");
@@ -1908,26 +1718,25 @@ session_exit_message(Session *s, int status)
s->chanid = -1;
}
-void
-session_free(Session *s)
+static void
+session_close(Session *s)
{
- debug("session_free: session %d pid %d", s->self, s->pid);
+ debug("session_close: session %d pid %d", s->self, s->pid);
+ if (s->ttyfd != -1) {
+ fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+ session_pty_cleanup(s);
+ }
if (s->term)
xfree(s->term);
if (s->display)
xfree(s->display);
+ if (s->auth_display)
+ xfree(s->auth_display);
if (s->auth_data)
xfree(s->auth_data);
if (s->auth_proto)
xfree(s->auth_proto);
s->used = 0;
-}
-
-void
-session_close(Session *s)
-{
- session_pty_cleanup(s);
- session_free(s);
session_proctitle(s);
}
@@ -1936,7 +1745,7 @@ session_close_by_pid(pid_t pid, int status)
{
Session *s = session_by_pid(pid);
if (s == NULL) {
- debug("session_close_by_pid: no session for pid %d", s->pid);
+ debug("session_close_by_pid: no session for pid %d", pid);
return;
}
if (s->chanid != -1)
@@ -1953,34 +1762,46 @@ session_close_by_channel(int id, void *arg)
{
Session *s = session_by_channel(id);
if (s == NULL) {
- debug("session_close_by_channel: no session for channel %d", id);
+ debug("session_close_by_channel: no session for id %d", id);
return;
}
- /* disconnect channel */
+ debug("session_close_by_channel: channel %d child %d", id, s->pid);
+ if (s->pid != 0) {
+ debug("session_close_by_channel: channel %d: has child", id);
+ /*
+ * delay detach of session, but release pty, since
+ * the fd's to the child are already closed
+ */
+ if (s->ttyfd != -1) {
+ fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+ session_pty_cleanup(s);
+ }
+ return;
+ }
+ /* detach by removing callback */
channel_cancel_cleanup(s->chanid);
s->chanid = -1;
+ session_close(s);
+}
- debug("session_close_by_channel: channel %d kill %d", id, s->pid);
- if (s->pid == 0) {
- /* close session immediately */
- session_close(s);
- } else {
- /* notify child, delay session cleanup */
- if (s->pid <= 1)
- fatal("session_close_by_channel: Unsafe s->pid = %d", s->pid);
- if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
- error("session_close_by_channel: kill %d: %s",
- s->pid, strerror(errno));
+void
+session_destroy_all(void)
+{
+ int i;
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (s->used)
+ session_close(s);
}
}
-char *
+static char *
session_tty_list(void)
{
static char buf[1024];
int i;
buf[0] = '\0';
- for(i = 0; i < MAX_SESSIONS; i++) {
+ for (i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
if (s->used && s->ttyfd != -1) {
if (buf[0] != '\0')
@@ -2002,9 +1823,69 @@ session_proctitle(Session *s)
setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
}
-void
-do_authenticated2(Authctxt *authctxt)
+int
+session_setup_x11fwd(Session *s)
{
+ struct stat st;
+ char display[512], auth_display[512];
+ char hostname[MAXHOSTNAMELEN];
- server_loop2();
+ if (no_x11_forwarding_flag) {
+ packet_send_debug("X11 forwarding disabled in user configuration file.");
+ return 0;
+ }
+ if (!options.x11_forwarding) {
+ debug("X11 forwarding disabled in server configuration file.");
+ return 0;
+ }
+ if (!options.xauth_location ||
+ (stat(options.xauth_location, &st) == -1)) {
+ packet_send_debug("No xauth program; cannot forward with spoofing.");
+ return 0;
+ }
+ if (options.use_login) {
+ packet_send_debug("X11 forwarding disabled; "
+ "not compatible with UseLogin=yes.");
+ return 0;
+ }
+ if (s->display != NULL) {
+ debug("X11 display already set.");
+ return 0;
+ }
+ s->display_number = x11_create_display_inet(options.x11_display_offset,
+ options.x11_use_localhost, s->single_connection);
+ if (s->display_number == -1) {
+ debug("x11_create_display_inet failed.");
+ return 0;
+ }
+
+ /* Set up a suitable value for the DISPLAY variable. */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ fatal("gethostname: %.100s", strerror(errno));
+ /*
+ * auth_display must be used as the displayname when the
+ * authorization entry is added with xauth(1). This will be
+ * different than the DISPLAY string for localhost displays.
+ */
+ if (options.x11_use_localhost) {
+ snprintf(display, sizeof display, "localhost:%d.%d",
+ s->display_number, s->screen);
+ snprintf(auth_display, sizeof auth_display, "unix:%d.%d",
+ s->display_number, s->screen);
+ s->display = xstrdup(display);
+ s->auth_display = xstrdup(auth_display);
+ } else {
+ snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
+ s->display_number, s->screen);
+ s->display = xstrdup(display);
+ s->auth_display = xstrdup(display);
+ }
+
+ return 1;
+}
+
+static void
+do_authenticated2(Authctxt *authctxt)
+{
+ server_loop2(authctxt);
}
diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c
index 82a67a8..526a187 100644
--- a/crypto/openssh/ssh-add.c
+++ b/crypto/openssh/ssh-add.c
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 implementation,
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,8 @@
*/
#include "includes.h"
+RCSID("$OpenBSD: ssh-add.c,v 1.50 2002/01/29 14:27:57 markus Exp $");
RCSID("$FreeBSD$");
-RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $");
#include <openssl/evp.h>
@@ -50,9 +50,21 @@ RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $");
#include "pathnames.h"
#include "readpass.h"
+/* argv0 */
+extern char *__progname;
+
+/* Default files to add */
+static char *default_files[] = {
+ _PATH_SSH_CLIENT_ID_RSA,
+ _PATH_SSH_CLIENT_ID_DSA,
+ _PATH_SSH_CLIENT_IDENTITY,
+ NULL
+};
+
+
/* we keep a cache of one passphrases */
static char *pass = NULL;
-void
+static void
clear_pass(void)
{
if (pass) {
@@ -62,53 +74,61 @@ clear_pass(void)
}
}
-void
+static int
delete_file(AuthenticationConnection *ac, const char *filename)
{
Key *public;
char *comment = NULL;
+ int ret = -1;
public = key_load_public(filename, &comment);
if (public == NULL) {
printf("Bad key file %s\n", filename);
- return;
+ return -1;
}
- if (ssh_remove_identity(ac, public))
+ if (ssh_remove_identity(ac, public)) {
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
- else
+ ret = 0;
+ } else
fprintf(stderr, "Could not remove identity: %s\n", filename);
+
key_free(public);
xfree(comment);
+
+ return ret;
}
/* Send a request to remove all identities. */
-void
+static int
delete_all(AuthenticationConnection *ac)
{
- int success = 1;
+ int ret = -1;
- if (!ssh_remove_all_identities(ac, 1))
- success = 0;
+ if (ssh_remove_all_identities(ac, 1))
+ ret = 0;
/* ignore error-code for ssh2 */
ssh_remove_all_identities(ac, 2);
- if (success)
+ if (ret == 0)
fprintf(stderr, "All identities removed.\n");
else
fprintf(stderr, "Failed to remove all identities.\n");
+
+ return ret;
}
-void
+static int
add_file(AuthenticationConnection *ac, const char *filename)
{
struct stat st;
Key *private;
char *comment = NULL;
char msg[1024];
+ int ret = -1;
if (stat(filename, &st) < 0) {
perror(filename);
- exit(1);
+ return -1;
}
/* At first, try empty passphrase */
private = key_load_private(filename, "", &comment);
@@ -120,15 +140,14 @@ add_file(AuthenticationConnection *ac, const char *filename)
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
- printf("Need passphrase for %.200s\n", filename);
snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ",
comment);
for (;;) {
- pass = read_passphrase(msg, 1);
+ pass = read_passphrase(msg, RP_ALLOW_STDIN);
if (strcmp(pass, "") == 0) {
clear_pass();
xfree(comment);
- return;
+ return -1;
}
private = key_load_private(filename, pass, &comment);
if (private != NULL)
@@ -137,15 +156,33 @@ add_file(AuthenticationConnection *ac, const char *filename)
strlcpy(msg, "Bad passphrase, try again: ", sizeof msg);
}
}
- if (ssh_add_identity(ac, private, comment))
+ if (ssh_add_identity(ac, private, comment)) {
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
- else
+ ret = 0;
+ } else
fprintf(stderr, "Could not add identity: %s\n", filename);
+
xfree(comment);
key_free(private);
+
+ return ret;
+}
+
+static int
+update_card(AuthenticationConnection *ac, int add, const char *id)
+{
+ if (ssh_update_card(ac, add, id)) {
+ fprintf(stderr, "Card %s: %s\n",
+ add ? "added" : "removed", id);
+ return 0;
+ } else {
+ fprintf(stderr, "Could not %s card: %s\n",
+ add ? "add" : "remove", id);
+ return -1;
+ }
}
-void
+static int
list_identities(AuthenticationConnection *ac, int do_fp)
{
Key *key;
@@ -155,8 +192,8 @@ list_identities(AuthenticationConnection *ac, int do_fp)
for (version = 1; version <= 2; version++) {
for (key = ssh_get_first_identity(ac, &comment, version);
- key != NULL;
- key = ssh_get_next_identity(ac, &comment, version)) {
+ key != NULL;
+ key = ssh_get_next_identity(ac, &comment, version)) {
had_identities = 1;
if (do_fp) {
fp = key_fingerprint(key, SSH_FP_MD5,
@@ -173,19 +210,49 @@ list_identities(AuthenticationConnection *ac, int do_fp)
xfree(comment);
}
}
- if (!had_identities)
+ if (!had_identities) {
printf("The agent has no identities.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+do_file(AuthenticationConnection *ac, int deleting, char *file)
+{
+ if (deleting) {
+ if (delete_file(ac, file) == -1)
+ return -1;
+ } else {
+ if (add_file(ac, file) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s [options]\n", __progname);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -l List fingerprints of all identities.\n");
+ fprintf(stderr, " -L List public key parameters of all identities.\n");
+ fprintf(stderr, " -d Delete identity.\n");
+ fprintf(stderr, " -D Delete all identities.\n");
+#ifdef SMARTCARD
+ fprintf(stderr, " -s reader Add key in smartcard reader.\n");
+ fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
+#endif
}
int
main(int argc, char **argv)
{
+ extern char *optarg;
+ extern int optind;
AuthenticationConnection *ac = NULL;
- struct passwd *pw;
- char buf[1024];
- int no_files = 1;
- int i;
- int deleting = 0;
+ char *sc_reader_id = NULL;
+ int i, ch, deleting = 0, ret = 0;
SSLeay_add_all_algorithms();
@@ -193,46 +260,70 @@ main(int argc, char **argv)
ac = ssh_get_authentication_connection();
if (ac == NULL) {
fprintf(stderr, "Could not open a connection to your authentication agent.\n");
- exit(1);
+ exit(2);
}
- for (i = 1; i < argc; i++) {
- if ((strcmp(argv[i], "-l") == 0) ||
- (strcmp(argv[i], "-L") == 0)) {
- list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
- /* Don't default-add/delete if -l. */
- no_files = 0;
- continue;
- }
- if (strcmp(argv[i], "-d") == 0) {
+ while ((ch = getopt(argc, argv, "lLdDe:s:")) != -1) {
+ switch (ch) {
+ case 'l':
+ case 'L':
+ if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
+ ret = 1;
+ goto done;
+ break;
+ case 'd':
deleting = 1;
- continue;
- }
- if (strcmp(argv[i], "-D") == 0) {
- delete_all(ac);
- no_files = 0;
- continue;
+ break;
+ case 'D':
+ if (delete_all(ac) == -1)
+ ret = 1;
+ goto done;
+ break;
+ case 's':
+ sc_reader_id = optarg;
+ break;
+ case 'e':
+ deleting = 1;
+ sc_reader_id = optarg;
+ break;
+ default:
+ usage();
+ ret = 1;
+ goto done;
}
- no_files = 0;
- if (deleting)
- delete_file(ac, argv[i]);
- else
- add_file(ac, argv[i]);
}
- if (no_files) {
- pw = getpwuid(getuid());
- if (!pw) {
+ argc -= optind;
+ argv += optind;
+ if (sc_reader_id != NULL) {
+ if (update_card(ac, !deleting, sc_reader_id) == -1)
+ ret = 1;
+ goto done;
+ }
+ if (argc == 0) {
+ char buf[MAXPATHLEN];
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) == NULL) {
fprintf(stderr, "No user found with uid %u\n",
(u_int)getuid());
- ssh_close_authentication_connection(ac);
- exit(1);
+ ret = 1;
+ goto done;
+ }
+
+ for(i = 0; default_files[i]; i++) {
+ snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
+ default_files[i]);
+ if (do_file(ac, deleting, buf) == -1)
+ ret = 1;
+ }
+ } else {
+ for(i = 0; i < argc; i++) {
+ if (do_file(ac, deleting, argv[i]) == -1)
+ ret = 1;
}
- snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
- if (deleting)
- delete_file(ac, buf);
- else
- add_file(ac, buf);
}
clear_pass();
+
+done:
ssh_close_authentication_connection(ac);
- exit(0);
+ return ret;
}
diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c
index ae0f044..07df747 100644
--- a/crypto/openssh/ssh-agent.c
+++ b/crypto/openssh/ssh-agent.c
@@ -1,5 +1,3 @@
-/* $OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $ */
-
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -12,8 +10,7 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
- * SSH2 implementation,
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,7 +34,8 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $");
+#include <sys/queue.h>
+RCSID("$OpenBSD: ssh-agent.c,v 1.82 2002/03/04 17:27:39 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@@ -48,21 +46,26 @@ RCSID("$FreeBSD$");
#include "buffer.h"
#include "bufaux.h"
#include "xmalloc.h"
-#include "packet.h"
#include "getput.h"
-#include "mpaux.h"
#include "key.h"
#include "authfd.h"
-#include "cipher.h"
-#include "kex.h"
#include "compat.h"
#include "log.h"
+#ifdef SMARTCARD
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
+typedef enum {
+ AUTH_UNUSED,
+ AUTH_SOCKET,
+ AUTH_CONNECTION
+} sock_type;
+
typedef struct {
int fd;
- enum {
- AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
- } type;
+ sock_type type;
Buffer input;
Buffer output;
} SocketEntry;
@@ -70,14 +73,15 @@ typedef struct {
u_int sockets_alloc = 0;
SocketEntry *sockets = NULL;
-typedef struct {
+typedef struct identity {
+ TAILQ_ENTRY(identity) next;
Key *key;
char *comment;
} Identity;
typedef struct {
int nentries;
- Identity *identities;
+ TAILQ_HEAD(idqueue, identity) idlist;
} Idtab;
/* private key table, one per protocol version */
@@ -94,20 +98,18 @@ char socket_dir[1024];
extern char *__progname;
-int prepare_select(fd_set **, fd_set **, int *);
-
-void
+static void
idtab_init(void)
{
int i;
- for (i = 0; i <=2; i++){
- idtable[i].identities = NULL;
+ for (i = 0; i <=2; i++) {
+ TAILQ_INIT(&idtable[i].idlist);
idtable[i].nentries = 0;
}
}
/* return private key table for requested protocol version */
-Idtab *
+static Idtab *
idtab_lookup(int version)
{
if (version < 1 || version > 2)
@@ -116,35 +118,40 @@ idtab_lookup(int version)
}
/* return matching private key for given public key */
-Key *
-lookup_private_key(Key *key, int *idx, int version)
+static Identity *
+lookup_identity(Key *key, int version)
{
- int i;
+ Identity *id;
+
Idtab *tab = idtab_lookup(version);
- for (i = 0; i < tab->nentries; i++) {
- if (key_equal(key, tab->identities[i].key)) {
- if (idx != NULL)
- *idx = i;
- return tab->identities[i].key;
- }
+ TAILQ_FOREACH(id, &tab->idlist, next) {
+ if (key_equal(key, id->key))
+ return (id);
}
- return NULL;
+ return (NULL);
+}
+
+static void
+free_identity(Identity *id)
+{
+ key_free(id->key);
+ xfree(id->comment);
+ xfree(id);
}
/* send list of supported public keys to 'client' */
-void
+static void
process_request_identities(SocketEntry *e, int version)
{
Idtab *tab = idtab_lookup(version);
Buffer msg;
- int i;
+ Identity *id;
buffer_init(&msg);
buffer_put_char(&msg, (version == 1) ?
SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
buffer_put_int(&msg, tab->nentries);
- for (i = 0; i < tab->nentries; i++) {
- Identity *id = &tab->identities[i];
+ TAILQ_FOREACH(id, &tab->idlist, next) {
if (id->key->type == KEY_RSA1) {
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
buffer_put_bignum(&msg, id->key->rsa->e);
@@ -164,10 +171,11 @@ process_request_identities(SocketEntry *e, int version)
}
/* ssh1 only */
-void
+static void
process_authentication_challenge1(SocketEntry *e)
{
- Key *key, *private;
+ Identity *id;
+ Key *key;
BIGNUM *challenge;
int i, len;
Buffer msg;
@@ -177,7 +185,8 @@ process_authentication_challenge1(SocketEntry *e)
buffer_init(&msg);
key = key_new(KEY_RSA1);
- challenge = BN_new();
+ if ((challenge = BN_new()) == NULL)
+ fatal("process_authentication_challenge1: BN_new failed");
buffer_get_int(&e->input); /* ignored */
buffer_get_bignum(&e->input, key->rsa->e);
@@ -187,13 +196,14 @@ process_authentication_challenge1(SocketEntry *e)
/* Only protocol 1.1 is supported */
if (buffer_len(&e->input) == 0)
goto failure;
- buffer_get(&e->input, (char *) session_id, 16);
+ buffer_get(&e->input, session_id, 16);
response_type = buffer_get_int(&e->input);
if (response_type != 1)
goto failure;
- private = lookup_private_key(key, NULL, 1);
- if (private != NULL) {
+ id = lookup_identity(key, 1);
+ if (id != NULL) {
+ Key *private = id->key;
/* Decrypt the challenge using the private key. */
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
goto failure;
@@ -230,11 +240,11 @@ send:
}
/* ssh2 only */
-void
+static void
process_sign_request2(SocketEntry *e)
{
extern int datafellows;
- Key *key, *private;
+ Key *key;
u_char *blob, *data, *signature = NULL;
u_int blen, dlen, slen = 0;
int flags;
@@ -252,9 +262,9 @@ process_sign_request2(SocketEntry *e)
key = key_from_blob(blob, blen);
if (key != NULL) {
- private = lookup_private_key(key, NULL, 2);
- if (private != NULL)
- ok = key_sign(private, &signature, &slen, data, dlen);
+ Identity *id = lookup_identity(key, 2);
+ if (id != NULL)
+ ok = key_sign(id->key, &signature, &slen, data, dlen);
}
key_free(key);
buffer_init(&msg);
@@ -275,16 +285,16 @@ process_sign_request2(SocketEntry *e)
}
/* shared */
-void
+static void
process_remove_identity(SocketEntry *e, int version)
{
- Key *key = NULL, *private;
+ Key *key = NULL;
u_char *blob;
u_int blen;
u_int bits;
int success = 0;
- switch(version){
+ switch (version) {
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&e->input);
@@ -302,9 +312,8 @@ process_remove_identity(SocketEntry *e, int version)
break;
}
if (key != NULL) {
- int idx;
- private = lookup_private_key(key, &idx, version);
- if (private != NULL) {
+ Identity *id = lookup_identity(key, version);
+ if (id != NULL) {
/*
* We have this key. Free the old key. Since we
* don\'t want to leave empty slots in the middle of
@@ -313,19 +322,12 @@ process_remove_identity(SocketEntry *e, int version)
* of the array.
*/
Idtab *tab = idtab_lookup(version);
- key_free(tab->identities[idx].key);
- xfree(tab->identities[idx].comment);
if (tab->nentries < 1)
fatal("process_remove_identity: "
"internal error: tab->nentries %d",
tab->nentries);
- if (idx != tab->nentries - 1) {
- int i;
- for (i = idx; i < tab->nentries - 1; i++)
- tab->identities[i] = tab->identities[i+1];
- }
- tab->identities[tab->nentries - 1].key = NULL;
- tab->identities[tab->nentries - 1].comment = NULL;
+ TAILQ_REMOVE(&tab->idlist, id, next);
+ free_identity(id);
tab->nentries--;
success = 1;
}
@@ -336,16 +338,17 @@ process_remove_identity(SocketEntry *e, int version)
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
-void
+static void
process_remove_all_identities(SocketEntry *e, int version)
{
- u_int i;
Idtab *tab = idtab_lookup(version);
+ Identity *id;
/* Loop over all identities and clear the keys. */
- for (i = 0; i < tab->nentries; i++) {
- key_free(tab->identities[i].key);
- xfree(tab->identities[i].comment);
+ for (id = TAILQ_FIRST(&tab->idlist); id;
+ id = TAILQ_FIRST(&tab->idlist)) {
+ TAILQ_REMOVE(&tab->idlist, id, next);
+ free_identity(id);
}
/* Mark that there are no identities. */
@@ -357,7 +360,7 @@ process_remove_all_identities(SocketEntry *e, int version)
return;
}
-void
+static void
process_add_identity(SocketEntry *e, int version)
{
Key *k = NULL;
@@ -380,13 +383,13 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum(&e->input, k->rsa->p); /* q */
/* Generate additional parameters */
- generate_additional_parameters(k->rsa);
+ rsa_generate_additional_parameters(k->rsa);
break;
case 2:
type_name = buffer_get_string(&e->input, NULL);
type = key_type_from_name(type_name);
xfree(type_name);
- switch(type) {
+ switch (type) {
case KEY_DSA:
k = key_new_private(type);
buffer_get_bignum2(&e->input, k->dsa->p);
@@ -405,7 +408,7 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum2(&e->input, k->rsa->q);
/* Generate additional parameters */
- generate_additional_parameters(k->rsa);
+ rsa_generate_additional_parameters(k->rsa);
break;
default:
buffer_clear(&e->input);
@@ -419,14 +422,11 @@ process_add_identity(SocketEntry *e, int version)
goto send;
}
success = 1;
- if (lookup_private_key(k, NULL, version) == NULL) {
- if (tab->nentries == 0)
- tab->identities = xmalloc(sizeof(Identity));
- else
- tab->identities = xrealloc(tab->identities,
- (tab->nentries + 1) * sizeof(Identity));
- tab->identities[tab->nentries].key = k;
- tab->identities[tab->nentries].comment = comment;
+ if (lookup_identity(k, version) == NULL) {
+ Identity *id = xmalloc(sizeof(Identity));
+ id->key = k;
+ id->comment = comment;
+ TAILQ_INSERT_TAIL(&tab->idlist, id, next);
/* Increment the number of identities. */
tab->nentries++;
} else {
@@ -439,9 +439,104 @@ send:
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
+
+#ifdef SMARTCARD
+static void
+process_add_smartcard_key (SocketEntry *e)
+{
+ Idtab *tab;
+ Key *n = NULL, *k = NULL;
+ char *sc_reader_id = NULL;
+ int success = 0;
+
+ sc_reader_id = buffer_get_string(&e->input, NULL);
+ k = sc_get_key(sc_reader_id);
+ xfree(sc_reader_id);
+
+ if (k == NULL) {
+ error("sc_get_pubkey failed");
+ goto send;
+ }
+ success = 1;
+
+ tab = idtab_lookup(1);
+ k->type = KEY_RSA1;
+ if (lookup_identity(k, 1) == NULL) {
+ Identity *id = xmalloc(sizeof(Identity));
+ n = key_new(KEY_RSA1);
+ BN_copy(n->rsa->n, k->rsa->n);
+ BN_copy(n->rsa->e, k->rsa->e);
+ RSA_set_method(n->rsa, sc_get_engine());
+ id->key = n;
+ id->comment = xstrdup("rsa1 smartcard");
+ TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+ tab->nentries++;
+ }
+ k->type = KEY_RSA;
+ tab = idtab_lookup(2);
+ if (lookup_identity(k, 2) == NULL) {
+ Identity *id = xmalloc(sizeof(Identity));
+ n = key_new(KEY_RSA);
+ BN_copy(n->rsa->n, k->rsa->n);
+ BN_copy(n->rsa->e, k->rsa->e);
+ RSA_set_method(n->rsa, sc_get_engine());
+ id->key = n;
+ id->comment = xstrdup("rsa smartcard");
+ TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+ tab->nentries++;
+ }
+ key_free(k);
+send:
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_smartcard_key(SocketEntry *e)
+{
+ Key *k = NULL;
+ int success = 0;
+ char *sc_reader_id = NULL;
+
+ sc_reader_id = buffer_get_string(&e->input, NULL);
+ k = sc_get_key(sc_reader_id);
+ xfree(sc_reader_id);
+
+ if (k == NULL) {
+ error("sc_get_pubkey failed");
+ } else {
+ Identity *id;
+ k->type = KEY_RSA1;
+ id = lookup_identity(k, 1);
+ if (id != NULL) {
+ Idtab *tab = idtab_lookup(1);
+ TAILQ_REMOVE(&tab->idlist, id, next);
+ free_identity(id);
+ tab->nentries--;
+ success = 1;
+ }
+ k->type = KEY_RSA;
+ id = lookup_identity(k, 2);
+ if (id != NULL) {
+ Idtab *tab = idtab_lookup(2);
+ TAILQ_REMOVE(&tab->idlist, id, next);
+ free_identity(id);
+ tab->nentries--;
+ success = 1;
+ }
+ key_free(k);
+ }
+
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* SMARTCARD */
+
/* dispatch incoming messages */
-void
+static void
process_message(SocketEntry *e)
{
u_int msg_len;
@@ -449,7 +544,7 @@ process_message(SocketEntry *e)
u_char *cp;
if (buffer_len(&e->input) < 5)
return; /* Incomplete message. */
- cp = (u_char *) buffer_ptr(&e->input);
+ cp = buffer_ptr(&e->input);
msg_len = GET_32BIT(cp);
if (msg_len > 256 * 1024) {
shutdown(e->fd, SHUT_RDWR);
@@ -462,6 +557,7 @@ process_message(SocketEntry *e)
buffer_consume(&e->input, 4);
type = buffer_get_char(&e->input);
+ debug("type %d", type);
switch (type) {
/* ssh1 */
case SSH_AGENTC_RSA_CHALLENGE:
@@ -495,6 +591,14 @@ process_message(SocketEntry *e)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e, 2);
break;
+#ifdef SMARTCARD
+ case SSH_AGENTC_ADD_SMARTCARD_KEY:
+ process_add_smartcard_key(e);
+ break;
+ case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
+ process_remove_smartcard_key(e);
+ break;
+#endif /* SMARTCARD */
default:
/* Unknown message. Respond with failure. */
error("Unknown message %d", type);
@@ -505,8 +609,8 @@ process_message(SocketEntry *e)
}
}
-void
-new_socket(int type, int fd)
+static void
+new_socket(sock_type type, int fd)
{
u_int i, old_alloc;
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
@@ -537,8 +641,8 @@ new_socket(int type, int fd)
buffer_init(&sockets[old_alloc].output);
}
-int
-prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
+static int
+prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
{
u_int i, sz;
int n = 0;
@@ -558,15 +662,18 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
}
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
- if (*fdrp == NULL || n > *fdl) {
+ if (*fdrp == NULL || sz > *nallocp) {
if (*fdrp)
xfree(*fdrp);
if (*fdwp)
xfree(*fdwp);
*fdrp = xmalloc(sz);
*fdwp = xmalloc(sz);
- *fdl = n;
+ *nallocp = sz;
}
+ if (n < *fdl)
+ debug("XXX shrink: %d < %d", n, *fdl);
+ *fdl = n;
memset(*fdrp, 0, sz);
memset(*fdwp, 0, sz);
@@ -585,7 +692,7 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
return (1);
}
-void
+static void
after_select(fd_set *readset, fd_set *writeset)
{
u_int i;
@@ -604,7 +711,8 @@ after_select(fd_set *readset, fd_set *writeset)
sock = accept(sockets[i].fd,
(struct sockaddr *) &sunaddr, &slen);
if (sock < 0) {
- perror("accept from AUTH_SOCKET");
+ error("accept from AUTH_SOCKET: %s",
+ strerror(errno));
break;
}
new_socket(AUTH_CONNECTION, sock);
@@ -657,22 +765,8 @@ after_select(fd_set *readset, fd_set *writeset)
}
}
-void
-check_parent_exists(int sig)
-{
- int save_errno = errno;
-
- if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
- /* printf("Parent has died - Authentication agent exiting.\n"); */
- exit(1);
- }
- signal(SIGALRM, check_parent_exists);
- alarm(10);
- errno = save_errno;
-}
-
-void
-cleanup_socket(void)
+static void
+cleanup_socket(void *p)
{
if (socket_name[0])
unlink(socket_name);
@@ -680,33 +774,51 @@ cleanup_socket(void)
rmdir(socket_dir);
}
-void
+static void
cleanup_exit(int i)
{
- cleanup_socket();
+ cleanup_socket(NULL);
exit(i);
}
-void
+static void
cleanup_handler(int sig)
{
- cleanup_socket();
+ cleanup_socket(NULL);
_exit(2);
}
-void
+static void
+check_parent_exists(int sig)
+{
+ int save_errno = errno;
+
+ if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
+ /* printf("Parent has died - Authentication agent exiting.\n"); */
+ cleanup_handler(sig); /* safe */
+ }
+ signal(SIGALRM, check_parent_exists);
+ alarm(10);
+ errno = save_errno;
+}
+
+static void
usage(void)
{
- fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
- fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
+ fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
__progname);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -c Generate C-shell commands on stdout.\n");
+ fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n");
+ fprintf(stderr, " -k Kill the current agent.\n");
+ fprintf(stderr, " -d Debug mode.\n");
exit(1);
}
int
main(int ac, char **av)
{
- int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
+ int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
struct sockaddr_un sunaddr;
struct rlimit rlim;
pid_t pid;
@@ -716,7 +828,7 @@ main(int ac, char **av)
SSLeay_add_all_algorithms();
- while ((ch = getopt(ac, av, "cks")) != -1) {
+ while ((ch = getopt(ac, av, "cdks")) != -1) {
switch (ch) {
case 'c':
if (s_flag)
@@ -731,6 +843,11 @@ main(int ac, char **av)
usage();
s_flag++;
break;
+ case 'd':
+ if (d_flag)
+ usage();
+ d_flag++;
+ break;
default:
usage();
}
@@ -738,10 +855,10 @@ main(int ac, char **av)
ac -= optind;
av += optind;
- if (ac > 0 && (c_flag || k_flag || s_flag))
+ if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
usage();
- if (ac == 0 && !c_flag && !k_flag && !s_flag) {
+ if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) {
shell = getenv("SHELL");
if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
c_flag = 1;
@@ -806,10 +923,18 @@ main(int ac, char **av)
* Fork, and have the parent execute the command, if any, or present
* the socket data. The child continues as the authentication agent.
*/
+ if (d_flag) {
+ log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
+ format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+ printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+ SSH_AUTHSOCKET_ENV_NAME);
+ printf("echo Agent pid %d;\n", parent_pid);
+ goto skip;
+ }
pid = fork();
if (pid == -1) {
perror("fork");
- exit(1);
+ cleanup_exit(1);
}
if (pid != 0) { /* Parent - execute the given command. */
close(sock);
@@ -832,6 +957,15 @@ main(int ac, char **av)
perror(av[0]);
exit(1);
}
+ /* child */
+ log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
+
+ if (setsid() == -1) {
+ error("setsid: %s", strerror(errno));
+ cleanup_exit(1);
+ }
+
+ (void)chdir("/");
close(0);
close(1);
close(2);
@@ -839,33 +973,31 @@ main(int ac, char **av)
/* deny core dumps, since memory contains unencrypted private keys */
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
- perror("setrlimit rlimit_core failed");
- cleanup_exit(1);
- }
- if (setsid() == -1) {
- perror("setsid");
- cleanup_exit(1);
- }
- if (atexit(cleanup_socket) < 0) {
- perror("atexit");
+ error("setrlimit RLIMIT_CORE: %s", strerror(errno));
cleanup_exit(1);
}
+
+skip:
+ fatal_add_cleanup(cleanup_socket, NULL);
new_socket(AUTH_SOCKET, sock);
if (ac > 0) {
signal(SIGALRM, check_parent_exists);
alarm(10);
}
idtab_init();
- signal(SIGINT, SIG_IGN);
+ if (!d_flag)
+ signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_handler);
signal(SIGTERM, cleanup_handler);
+ nalloc = 0;
+
while (1) {
- prepare_select(&readsetp, &writesetp, &max_fd);
+ prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
if (errno == EINTR)
continue;
- exit(1);
+ fatal("select: %s", strerror(errno));
}
after_select(readsetp, writesetp);
}
diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1
index f2b74ea..0b8a0cd 100644
--- a/crypto/openssh/ssh.1
+++ b/crypto/openssh/ssh.1
@@ -34,10 +34,9 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh.1,v 1.107 2001/04/22 23:58:36 markus Exp $
+.\" $OpenBSD: ssh.1,v 1.148 2002/02/18 17:55:20 markus Exp $
.\" $FreeBSD$
-.\"
-.Dd September 25, 1999
+.Dd March 18, 2002
.Dt SSH 1
.Os
.Sh NAME
@@ -46,11 +45,12 @@
.Sh SYNOPSIS
.Nm ssh
.Op Fl l Ar login_name
-.Op Ar hostname | user@hostname
+.Ar hostname | user@hostname
.Op Ar command
.Pp
.Nm ssh
.Op Fl afgknqstvxACNPTX1246
+.Op Fl b Ar bind_address
.Op Fl c Ar cipher_spec
.Op Fl e Ar escape_char
.Op Fl i Ar identity_file
@@ -58,6 +58,7 @@
.Op Fl m Ar mac_spec
.Op Fl o Ar option
.Op Fl p Ar port
+.Op Fl F Ar configfile
.Oo Fl L Xo
.Sm off
.Ar port :
@@ -74,7 +75,8 @@
.Sm on
.Xc
.Oc
-.Op Ar hostname | user@hostname
+.Op Fl D Ar port
+.Ar hostname | user@hostname
.Op Ar command
.Sh DESCRIPTION
.Nm
@@ -206,16 +208,14 @@ the password cannot be seen by someone listening on the network.
.Pp
.Ss SSH protocol version 2
.Pp
-When a user connects using the protocol version 2
-different authentication methods are available.
+When a user connects using protocol version 2
+similar authentication methods are available.
Using the default values for
.Cm PreferredAuthentications ,
-the client will try to authenticate first using the public key method;
-if this method fails password authentication is attempted,
-and finally if this method fails keyboard-interactive authentication
-is attempted.
-If this method fails password authentication is
-tried.
+the client will try to authenticate first using the hostbased method;
+if this method fails public key authentication is attempted,
+and finally if this method fails keyboard-interactive and
+password authentication are tried.
.Pp
The public key method is similar to RSA authentication described
in the previous section and allows the RSA or DSA algorithm to be used:
@@ -225,7 +225,7 @@ or
.Pa $HOME/.ssh/id_rsa ,
to sign the session identifier and sends the result to the server.
The server checks whether the matching public key is listed in
-.Pa $HOME/.ssh/authorized_keys2
+.Pa $HOME/.ssh/authorized_keys
and grants access if both the key is found and the signature is correct.
The session identifier is derived from a shared Diffie-Hellman value
and is only known to the client and the server.
@@ -270,16 +270,16 @@ of
.Ss Escape Characters
.Pp
When a pseudo terminal has been requested, ssh supports a number of functions
-through the use of an escape character.
+through the use of an escape character.
.Pp
A single tilde character can be sent as
.Ic ~~
-(or by following the tilde by a character other than those described above).
+or by following the tilde by a character other than those described below.
The escape character must always follow a newline to be interpreted as
special.
The escape character can be changed in configuration files using the
.Cm EscapeChar
-configuration directive or on the command line by the
+configuration directive or on the command line by the
.Fl e
option.
.Pp
@@ -295,7 +295,7 @@ Background ssh
List forwarded connections
.It Cm ~&
Background ssh at logout when waiting for forwarded connection / X11 sessions
-to terminate (protocol version 1 only)
+to terminate
.It Cm ~?
Display a list of escape characters
.It Cm ~R
@@ -305,18 +305,27 @@ and if the peer supports it)
.Pp
.Ss X11 and TCP forwarding
.Pp
-If the user is using X11 (the
+If the
+.Cm ForwardX11
+variable is set to
+.Dq yes
+(or, see the description of the
+.Fl X
+and
+.Fl x
+options described later)
+and the user is using X11 (the
.Ev DISPLAY
-environment variable is set), the connection to the X11 display can
-be forwarded to the remote side in such a way that any X11
+environment variable is set), the connection to the X11 display is
+automatically forwarded to the remote side in such a way that any X11
programs started from the shell (or command) will go through the
encrypted channel, and the connection to the real X server will be made
from the local machine.
The user should not manually set
.Ev DISPLAY .
-Forwarding of X11 connections weakens the security of ssh and is
-disabled by default. X11 forwarding can be enabled on the command line
-or in configuration files.
+Forwarding of X11 connections can be
+configured on the command line or in configuration files.
+Take note that X11 forwarding can represent a security hazard.
.Pp
The
.Ev DISPLAY
@@ -342,10 +351,10 @@ sent to the server machine (and no cookies are sent in the plain).
.Pp
If the user is using an authentication agent, the connection to the agent
is automatically forwarded to the remote side unless disabled on
-command line or in a configuration file.
+the command line or in a configuration file.
.Pp
Forwarding of arbitrary TCP/IP connections over the secure channel can
-be specified either on command line or in a configuration file.
+be specified either on the command line or in a configuration file.
One possible application of TCP/IP forwarding is a secure connection to an
electronic purse; another is going through firewalls.
.Pp
@@ -354,17 +363,12 @@ electronic purse; another is going through firewalls.
.Nm
automatically maintains and checks a database containing
identifications for all hosts it has ever been used with.
-RSA host keys are stored in
+Host keys are stored in
.Pa $HOME/.ssh/known_hosts
-and
-host keys used in the protocol version 2 are stored in
-.Pa $HOME/.ssh/known_hosts2
in the user's home directory.
-Additionally, the files
+Additionally, the file
.Pa /etc/ssh/ssh_known_hosts
-and
-.Pa /etc/ssh/ssh_known_hosts2
-are automatically checked for known hosts.
+is automatically checked for known hosts.
Any new hosts are automatically added to the user's file.
If a host's identification
ever changes,
@@ -386,20 +390,27 @@ Disables forwarding of the authentication agent connection.
.It Fl A
Enables forwarding of the authentication agent connection.
This can also be specified on a per-host basis in a configuration file.
-.It Fl c Ar blowfish|3des
+.It Fl b Ar bind_address
+Specify the interface to transmit from on machines with multiple
+interfaces or aliased addresses.
+.It Fl c Ar blowfish|3des|des
Selects the cipher to use for encrypting the session.
.Ar 3des
is used by default.
It is believed to be secure.
.Ar 3des
(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
-It is presumably more secure than the
-.Ar des
-cipher which is no longer fully supported in
-.Nm ssh .
.Ar blowfish
is a fast block cipher, it appears very secure and is much faster than
.Ar 3des .
+.Ar des
+is only supported in the
+.Nm
+client for interoperability with legacy protocol 1 implementations
+that do not support the
+.Ar 3des
+cipher. Its use is strongly discouraged due to cryptographic
+weaknesses.
.It Fl c Ar cipher_spec
Additionally, for protocol version 2 a comma-separated list of ciphers can
be specified in order of preference.
@@ -434,17 +445,27 @@ something like
.It Fl g
Allows remote hosts to connect to local forwarded ports.
.It Fl i Ar identity_file
-Selects the file from which the identity (private key) for
+Selects a file from which the identity (private key) for
RSA or DSA authentication is read.
-Default is
+The default is
.Pa $HOME/.ssh/identity
-in the user's home directory.
+for protocol version 1, and
+.Pa $HOME/.ssh/id_rsa
+and
+.Pa $HOME/.ssh/id_dsa
+for protocol version 2.
Identity files may also be specified on
a per-host basis in the configuration file.
It is possible to have multiple
.Fl i
options (and multiple identities specified in
configuration files).
+.It Fl I Ar smartcard_device
+Specifies which smartcard device to use. The argument is
+the device
+.Nm
+should use to communicate with a smartcard used for storing the user's
+private RSA key.
.It Fl k
Disables forwarding of Kerberos tickets and AFS tokens.
This may also be specified on a per-host basis in the configuration file.
@@ -480,20 +501,19 @@ needs to ask for a password or passphrase; see also the
option.)
.It Fl N
Do not execute a remote command.
-This is useful if you just want to forward ports
+This is useful for just forwarding ports
(protocol version 2 only).
.It Fl o Ar option
-Can be used to give options in the format used in the config file.
+Can be used to give options in the format used in the configuration file.
This is useful for specifying options for which there is no separate
command-line flag.
-The option has the same format as a line in the configuration file.
.It Fl p Ar port
Port to connect to on the remote host.
This can be specified on a
per-host basis in the configuration file.
.It Fl P
Use a non-privileged port for outgoing connections.
-This can be used if your firewall does
+This can be used if a firewall does
not permit connections from privileged ports.
Note that this option turns off
.Cm RhostsAuthentication
@@ -503,10 +523,9 @@ for older servers.
.It Fl q
Quiet mode.
Causes all warning and diagnostic messages to be suppressed.
-Only fatal errors are displayed.
.It Fl s
-May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
-of SSH as a secure transport for other application (eg. sftp). The
+May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
+of SSH as a secure transport for other applications (eg. sftp). The
subsystem is specified as the remote command.
.It Fl t
Force pseudo-tty allocation.
@@ -550,8 +569,16 @@ Compression is desirable on modem lines and other
slow connections, but will only slow down things on fast networks.
The default value can be set on a host-by-host basis in the
configuration files; see the
-.Cm Compress
+.Cm Compression
option below.
+.It Fl F Ar configfile
+Specifies an alternative per-user configuration file.
+If a configuration file is given on the command line,
+the system-wide configuration file
+.Pq Pa /etc/ssh/ssh_config
+will be ignored.
+The default for the per-user configuration file is
+.Pa $HOME/.ssh/config .
.It Fl L Ar port:host:hostport
Specifies that the given port on the local (client) host is to be
forwarded to the given host and port on the remote side.
@@ -585,6 +612,20 @@ Privileged ports can be forwarded only when
logging in as root on the remote machine.
IPv6 addresses can be specified with an alternative syntax:
.Ar port/host/hostport
+.It Fl D Ar port
+Specifies a local
+.Dq dynamic
+application-level port forwarding.
+This works by allocating a socket to listen to
+.Ar port
+on the local side, and whenever a connection is made to this port, the
+connection is forwarded over the secure channel, and the application
+protocol is then used to determine where to connect to from the
+remote machine. Currently the SOCKS4 protocol is supported, and
+.Nm
+will act as a SOCKS4 server.
+Only root can forward privileged ports.
+Dynamic port forwardings can also be specified in the configuration file.
.It Fl 1
Forces
.Nm
@@ -604,7 +645,8 @@ to use IPv6 addresses only.
.El
.Sh CONFIGURATION FILES
.Nm
-obtains configuration data from the following sources (in this order):
+obtains configuration data from the following sources in
+the following order:
command line options, user's configuration file
.Pq Pa $HOME/.ssh/config ,
and system-wide configuration file
@@ -629,9 +671,21 @@ are comments.
.Pp
Otherwise a line is of the format
.Dq keyword arguments .
+Configuration options may be separated by whitespace or
+optional whitespace and exactly one
+.Ql = ;
+the latter format is useful to avoid the need to quote whitespace
+when specifying configuration options using the
+.Nm ssh ,
+.Nm scp
+and
+.Nm sftp
+.Fl o
+option.
+.Pp
The possible
-keywords and their meanings are as follows (note that the
-configuration files are case-sensitive):
+keywords and their meanings are as follows (note that
+keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm Host
Restricts the following declarations (up to the next
@@ -662,14 +716,21 @@ This option applies to protocol version 1 only.
If set to
.Dq yes ,
passphrase/password querying will be disabled.
-This option is useful in scripts and other batch jobs where you have no
-user to supply the password.
+This option is useful in scripts and other batch jobs where no user
+is present to supply the password.
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq no .
+.It Cm BindAddress
+Specify the interface to transmit from on machines with multiple
+interfaces or aliased addresses.
+Note that this option does not work if
+.Cm UsePrivilegedPort
+is set to
+.Dq yes .
.It Cm CheckHostIP
If this flag is set to
.Dq yes ,
@@ -686,10 +747,19 @@ The default is
Specifies the cipher to use for encrypting the session
in protocol version 1.
Currently,
-.Dq blowfish
+.Dq blowfish ,
+.Dq 3des ,
and
-.Dq 3des
+.Dq des
are supported.
+.Ar des
+is only supported in the
+.Nm
+client for interoperability with legacy protocol 1 implementations
+that do not support the
+.Ar 3des
+cipher. Its use is strongly discouraged due to cryptographic
+weaknesses.
The default is
.Dq 3des .
.It Cm Ciphers
@@ -702,6 +772,22 @@ The default is
``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
aes192-cbc,aes256-cbc''
.Ed
+.It Cm ClearAllForwardings
+Specifies that all local, remote and dynamic port forwardings
+specified in the configuration files or on the command line be
+cleared. This option is primarily useful when used from the
+.Nm
+command line to clear port forwardings set in
+configuration files, and is automatically set by
+.Xr scp 1
+and
+.Xr sftp 1 .
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
.It Cm Compression
Specifies whether to use compression.
The argument must be
@@ -722,7 +808,18 @@ Specifies the number of tries (one per second) to make before falling
back to rsh or exiting.
The argument must be an integer.
This may be useful in scripts if the connection sometimes fails.
-The default is 4.
+The default is 1.
+.It Cm DynamicForward
+Specifies that a TCP/IP port on the local machine be forwarded
+over the secure channel, and the application
+protocol is then used to determine where to connect to from the
+remote machine. The argument must be a port number.
+Currently the SOCKS4 protocol is supported, and
+.Nm
+will act as a SOCKS4 server.
+Multiple forwardings may be specified, and
+additional forwardings can be given on the command line. Only
+the superuser can forward privileged ports.
.It Cm EscapeChar
Sets the escape character (default:
.Ql ~ ) .
@@ -773,6 +870,15 @@ The default is
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to local
forwarded ports.
+By default,
+.Nm
+binds local port forwardings to the loopback addresss. This
+prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that
+.Nm
+should bind local port forwardings to the wildcard address,
+thus allowing remote hosts to connect to forwarded ports.
The argument must be
.Dq yes
or
@@ -780,13 +886,9 @@ or
The default is
.Dq no .
.It Cm GlobalKnownHostsFile
-Specifies a file to use for the protocol version 1 global
+Specifies a file to use for the global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts .
-.It Cm GlobalKnownHostsFile2
-Specifies a file to use for the protocol version 2 global
-host key database instead of
-.Pa /etc/ssh/ssh_known_hosts2 .
.It Cm HostbasedAuthentication
Specifies whether to try rhosts based authentication with public key
authentication.
@@ -795,21 +897,21 @@ The argument must be
or
.Dq no .
The default is
-.Dq yes .
+.Dq no .
This option applies to protocol version 2 only and
is similar to
.Cm RhostsRSAAuthentication .
.It Cm HostKeyAlgorithms
-Specfies the protocol version 2 host key algorithms
+Specifies the protocol version 2 host key algorithms
that the client wants to use in order of preference.
The default for this option is:
-.Dq ssh-rsa,ssh-dss
+.Dq ssh-rsa,ssh-dss .
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
in the host key database files.
This option is useful for tunneling ssh connections
-or if you have multiple servers running on a single host.
+or for multiple servers running on a single host.
.It Cm HostName
Specifies the real host name to log into.
This can be used to specify nicknames or abbreviations for hosts.
@@ -818,10 +920,14 @@ Numeric IP addresses are also permitted (both on the command line and in
.Cm HostName
specifications).
.It Cm IdentityFile
-Specifies the file from which the user's RSA or DSA authentication identity
-is read (default
+Specifies a file from which the user's RSA or DSA authentication identity
+is read. The default is
.Pa $HOME/.ssh/identity
-in the user's home directory).
+for protocol version 1, and
+.Pa $HOME/.ssh/id_rsa
+and
+.Pa $HOME/.ssh/id_dsa
+for protocol version 2.
Additionally, any identities represented by the authentication agent
will be used for authentication.
The file name may use the tilde
@@ -830,7 +936,7 @@ It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
.It Cm KeepAlive
-Specifies whether the system should send keepalive messages to the
+Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
@@ -845,8 +951,7 @@ if the network goes down or the remote host dies.
This is important in scripts, and many users want it too.
.Pp
To disable keepalives, the value should be set to
-.Dq no
-in both the server and the client configuration files.
+.Dq no .
.It Cm KerberosAuthentication
Specifies whether Kerberos authentication will be used.
The argument to this keyword must be
@@ -862,9 +967,11 @@ or
.Dq no .
.It Cm LocalForward
Specifies that a TCP/IP port on the local machine be forwarded over
-the secure channel to given host:port from the remote machine.
+the secure channel to the specified host and port from the remote machine.
The first argument must be a port number, and the second must be
-host:port.
+.Ar host:port .
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Only the superuser can forward privileged ports.
@@ -872,20 +979,27 @@ Only the superuser can forward privileged ports.
Gives the verbosity level that is used when logging messages from
.Nm ssh .
The possible values are:
-QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
-The default is INFO.
+QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3.
+The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2
+and DEBUG3 each specify higher levels of verbose output.
.It Cm MACs
-Specifies the MAC (message authentication code) algorithms
+Specifies the MAC (message authentication code) algorithms
in order of preference.
The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
-.Pp
-.Bd -literal
- ``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
- hmac-sha1-96,hmac-md5-96''
-.Ed
+.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
+.It Cm NoHostAuthenticationForLocalhost
+This option can be used if the home directory is shared across machines.
+In this case localhost will refer to a different machine on each of
+the machines and the user will get many warnings about changed host keys.
+However, this option disables host authentication for localhost.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is to check the host key for localhost.
.It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
@@ -902,13 +1016,13 @@ The default is
Specifies the port number to connect on the remote host.
Default is 22.
.It Cm PreferredAuthentications
-Specifies the order in which the client should try protocol 2
-authentication methods. This allows a client to prefer one method (e.g.
+Specifies the order in which the client should try protocol 2
+authentication methods. This allows a client to prefer one method (e.g.
.Cm keyboard-interactive )
over another method (e.g.
.Cm password )
The default for this option is:
-.Dq publickey, password, keyboard-interactive
+.Dq hostbased,publickey,keyboard-interactive,password .
.It Cm Protocol
Specifies the protocol versions
.Nm
@@ -960,9 +1074,11 @@ The default is
This option applies to protocol version 2 only.
.It Cm RemoteForward
Specifies that a TCP/IP port on the remote machine be forwarded over
-the secure channel to given host:port from the local machine.
+the secure channel to the specified host and port from the local machine.
The first argument must be a port number, and the second must be
-host:port.
+.Ar host:port .
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Only the superuser can forward privileged ports.
@@ -975,8 +1091,8 @@ Disabling rhosts authentication may reduce
authentication time on slow connections when rhosts authentication is
not used.
Most servers do not permit RhostsAuthentication because it
-is not secure (see
-.Cm RhostsRSAAuthentication ).
+is not secure (see
+.Cm RhostsRSAAuthentication ) .
The argument to this keyword must be
.Dq yes
or
@@ -1008,31 +1124,31 @@ The default is
Note that this option applies to protocol version 1 only.
.It Cm ChallengeResponseAuthentication
Specifies whether to use challenge response authentication.
-Currently there is only support for
-.Xr skey 1
-authentication.
The argument to this keyword must be
.Dq yes
or
.Dq no .
The default is
-.Dq no .
+.Dq yes .
+.It Cm SmartcardDevice
+Specifies which smartcard device to use. The argument to this keyword is
+the device
+.Nm
+should use to communicate with a smartcard used for storing the user's
+private RSA key. By default, no device is specified and smartcard support
+is not activated.
.It Cm StrictHostKeyChecking
If this flag is set to
.Dq yes ,
.Nm
will never automatically add host keys to the
.Pa $HOME/.ssh/known_hosts
-and
-.Pa $HOME/.ssh/known_hosts2
-files, and refuses to connect to hosts whose host key has changed.
-This provides maximum protection against trojan horse attacks.
-However, it can be somewhat annoying if you don't have good
+file, and refuses to connect to hosts whose host key has changed.
+This provides maximum protection against trojan horse attacks,
+however, can be annoying when the
.Pa /etc/ssh/ssh_known_hosts
-and
-.Pa /etc/ssh/ssh_known_hosts2
-files installed and frequently
-connect to new hosts.
+file is poorly maintained, or connections to new hosts are
+frequently made.
This option forces the user to manually
add all new hosts.
If this flag is set to
@@ -1064,26 +1180,22 @@ or
.Dq no .
The default is
.Dq no .
-Note that you need to set this option to
+Note that this option must be set to
.Dq yes
-if you want to use
+if
.Cm RhostsAuthentication
and
.Cm RhostsRSAAuthentication
-with older servers.
+authentications are needed with older servers.
.It Cm User
Specifies the user to log in as.
-This can be useful if you have a different user name on different machines.
+This can be useful when a different user name is used on different machines.
This saves the trouble of
having to remember to give the user name on the command line.
.It Cm UserKnownHostsFile
-Specifies a file to use for the protocol version 1 user
+Specifies a file to use for the user
host key database instead of
.Pa $HOME/.ssh/known_hosts .
-.It Cm UserKnownHostsFile2
-Specifies a file to use for the protocol version 2 user
-host key database instead of
-.Pa $HOME/.ssh/known_hosts2 .
.It Cm UseRsh
Specifies that rlogin/rsh should be used for this host.
It is possible that the host does not at all support the
@@ -1136,14 +1248,37 @@ Synonym for
.Ev USER ;
set for compatibility with systems that use this variable.
.It Ev MAIL
-Set to point the user's mailbox.
+Set to the path of the user's mailbox.
.It Ev PATH
Set to the default
.Ev PATH ,
as specified when compiling
.Nm ssh .
+.It Ev SSH_ASKPASS
+If
+.Nm
+needs a passphrase, it will read the passphrase from the current
+terminal if it was run from a terminal.
+If
+.Nm
+does not have a terminal associated with it but
+.Ev DISPLAY
+and
+.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
+.Nm
+from a
+.Pa .Xsession
+or related script.
+(Note that on some machines it
+may be necessary to redirect the input from
+.Pa /dev/null
+to make this work.)
.It Ev SSH_AUTH_SOCK
-indicates the path of a unix-domain socket used to communicate with the
+Identifies the path of a unix-domain socket used to communicate with the
agent.
.It Ev SSH_CLIENT
Identifies the client end of the connection.
@@ -1176,13 +1311,10 @@ and adds lines of the format
to the environment.
.Sh FILES
.Bl -tag -width Ds
-.It Pa $HOME/.ssh/known_hosts, $HOME/.ssh/known_hosts2
-Records host keys for all hosts the user has logged into (that are not
+.It Pa $HOME/.ssh/known_hosts
+Records host keys for all hosts the user has logged into that are not
in
-.Pa /etc/ssh/ssh_known_hosts
-for protocol version 1 or
-.Pa /etc/ssh/ssh_known_hosts2
-for protocol version 2).
+.Pa /etc/ssh/ssh_known_hosts .
See
.Xr sshd 8 .
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa
@@ -1205,15 +1337,15 @@ The contents of the
file should be added to
.Pa $HOME/.ssh/authorized_keys
on all machines
-where you wish to log in using protocol version 1 RSA authentication.
+where the user wishes to log in using protocol version 1 RSA authentication.
The contents of the
.Pa $HOME/.ssh/id_dsa.pub
and
.Pa $HOME/.ssh/id_rsa.pub
file should be added to
-.Pa $HOME/.ssh/authorized_keys2
+.Pa $HOME/.ssh/authorized_keys
on all machines
-where you wish to log in using protocol version 2 DSA/RSA authentication.
+where the user wishes to log in using protocol version 2 DSA/RSA authentication.
These files are not
sensitive and can (but need not) be readable by anyone.
These files are
@@ -1229,34 +1361,23 @@ This file does not usually contain any sensitive information,
but the recommended permissions are read/write for the user, and not
accessible by others.
.It Pa $HOME/.ssh/authorized_keys
-Lists the RSA keys that can be used for logging in as this user.
+Lists the public keys (RSA/DSA) that can be used for logging in as this user.
The format of this file is described in the
.Xr sshd 8
manual page.
In the simplest form the format is the same as the .pub
-identity files (that is, each line contains the number of bits in
-modulus, public exponent, modulus, and comment fields, separated by
-spaces).
-This file is not highly sensitive, but the recommended
-permissions are read/write for the user, and not accessible by others.
-.It Pa $HOME/.ssh/authorized_keys2
-Lists the public keys (RSA/DSA) that can be used for logging in as this user.
+identity files.
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
-.It Pa /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2
+.It Pa /etc/ssh/ssh_known_hosts
Systemwide list of known host keys.
-.Pa /etc/ssh/ssh_known_hosts
-contains RSA and
-.Pa /etc/ssh/ssh_known_hosts2
-contains RSA or DSA keys for protocol version 2.
-These files should be prepared by the
+This file should be prepared by the
system administrator to contain the public host keys of all machines in the
organization.
This file should be world-readable.
This file contains
public keys, one per line, in the following format (fields separated
-by spaces): system name, number of bits in modulus, public exponent,
-modulus, and optional comment field.
+by spaces): system name, public key and optional comment field.
When different names are used
for the same machine, all such names should be listed, separated by
commas.
@@ -1277,6 +1398,15 @@ This file provides defaults for those
values that are not specified in the user's configuration file, and
for those users who do not have a configuration file.
This file must be world-readable.
+.It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key
+These three files contain the private parts of the host keys
+and are used for
+.Cm RhostsRSAAuthentication
+and
+.Cm HostbasedAuthentication .
+Since they are readable only by root
+.Nm
+must be setuid root if these authentication methods are desired.
.It Pa $HOME/.rhosts
This file is used in
.Pa \&.rhosts
@@ -1302,9 +1432,9 @@ Note that by default
.Xr sshd 8
will be installed so that it requires successful RSA host
authentication before permitting \s+2.\s0rhosts authentication.
-If your server machine does not have the client's host key in
+If the server machine does not have the client's host key in
.Pa /etc/ssh/ssh_known_hosts ,
-you can store it in
+it can be stored in
.Pa $HOME/.ssh/known_hosts .
The easiest way to do this is to
connect back to the client from the server machine using ssh; this
@@ -1361,6 +1491,10 @@ Contains additional definitions for environment variables, see section
.Sx ENVIRONMENT
above.
.El
+.Sh DIAGNOSTICS
+.Nm
+exits with the exit status of the remote command or with 255
+if an error occurred.
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
@@ -1387,7 +1521,7 @@ protocol versions 1.5 and 2.0.
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
-.%N draft-ietf-secsh-architecture-07.txt
-.%D January 2001
+.%N draft-ietf-secsh-architecture-09.txt
+.%D July 2001
.%O work in progress material
.Re
diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c
index 0ed1ec1..e991920 100644
--- a/crypto/openssh/ssh.c
+++ b/crypto/openssh/ssh.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.116 2001/04/17 12:55:04 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.164 2002/02/14 23:28:00 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@@ -70,6 +70,11 @@ RCSID("$FreeBSD$");
#include "mac.h"
#include "sshtty.h"
+#ifdef SMARTCARD
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
extern char *__progname;
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
@@ -106,6 +111,9 @@ int fork_after_authentication_flag = 0;
*/
Options options;
+/* optional user configfile */
+char *config = NULL;
+
/*
* 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 in a
@@ -116,14 +124,6 @@ char *host;
/* socket address the host resolves to */
struct sockaddr_storage 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
- * 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;
-
/* Private host keys. */
struct {
Key **keys;
@@ -141,22 +141,27 @@ int subsystem_flag = 0;
/* Prints a help message to the user. This function never returns. */
-void
+static void
usage(void)
{
fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -l user Log in using this user name.\n");
fprintf(stderr, " -n Redirect input from " _PATH_DEVNULL ".\n");
+ fprintf(stderr, " -F config Config file (default: ~/%s).\n",
+ _PATH_SSH_USER_CONFFILE);
fprintf(stderr, " -A Enable authentication agent forwarding.\n");
- fprintf(stderr, " -a Disable authentication agent forwarding.\n");
+ fprintf(stderr, " -a Disable authentication agent forwarding (default).\n");
#ifdef AFS
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
#endif /* AFS */
fprintf(stderr, " -X Enable X11 connection forwarding.\n");
- fprintf(stderr, " -x Disable X11 connection forwarding.\n");
+ fprintf(stderr, " -x Disable X11 connection forwarding (default).\n");
fprintf(stderr, " -i file Identity for public key authentication "
"(default: ~/.ssh/identity)\n");
+#ifdef SMARTCARD
+ fprintf(stderr, " -I reader Set smartcard reader.\n");
+#endif
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
fprintf(stderr, " -T Do not allocate a tty.\n");
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
@@ -167,14 +172,14 @@ usage(void)
fprintf(stderr, " -f Fork into background after authentication.\n");
fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
- fprintf(stderr, " -c cipher Select encryption algorithm: "
- "``3des'', ``blowfish''\n");
+ fprintf(stderr, " -c cipher Select encryption algorithm\n");
fprintf(stderr, " -m macs Specify MAC algorithms for protocol version 2.\n");
fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
+ fprintf(stderr, " -D port Enable dynamic application-level port forwarding.\n");
fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
@@ -184,6 +189,7 @@ usage(void)
fprintf(stderr, " -6 Use IPv6 only.\n");
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
fprintf(stderr, " -s Invoke command (mandatory) as SSH2 subsystem.\n");
+ fprintf(stderr, " -b addr Local IP address.\n");
exit(1);
}
@@ -191,7 +197,7 @@ usage(void)
* Connects to the given host using rsh (or prints an error message and exits
* if rsh is not available). This function never returns.
*/
-void
+static void
rsh_connect(char *host, char *user, Buffer * command)
{
char *args[10];
@@ -228,9 +234,9 @@ rsh_connect(char *host, char *user, Buffer * command)
exit(1);
}
-int ssh_session(void);
-int ssh_session2(void);
-void load_public_identity_files(void);
+static int ssh_session(void);
+static int ssh_session2(void);
+static void load_public_identity_files(void);
/*
* Main program for the ssh client.
@@ -238,13 +244,16 @@ void load_public_identity_files(void);
int
main(int ac, char **av)
{
- int i, opt, optind, exit_status, ok;
+ int i, opt, exit_status, cerr;
u_short fwd_port, fwd_host_port;
- char *optarg, *cp, buf[256];
+ char sfwd_port[6], sfwd_host_port[6];
+ char *p, *cp, buf[256];
struct stat st;
struct passwd *pw;
int dummy;
uid_t original_effective_uid;
+ extern int optind, optreset;
+ extern char *optarg;
/*
* Save the original real uid. It will be needed later (uid-swapping
@@ -292,35 +301,9 @@ main(int ac, char **av)
/* Parse command-line arguments. */
host = NULL;
- for (optind = 1; optind < ac; optind++) {
- if (av[optind][0] != '-') {
- if (host)
- break;
- if ((cp = strchr(av[optind], '@'))) {
- if(cp == av[optind])
- usage();
- options.user = av[optind];
- *cp = '\0';
- host = ++cp;
- } else
- host = av[optind];
- continue;
- }
- opt = av[optind][1];
- if (!opt)
- usage();
- if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
- optarg = av[optind] + 2;
- if (strcmp(optarg, "") == 0) {
- if (optind >= ac - 1)
- usage();
- optarg = av[++optind];
- }
- } else {
- if (av[optind][2])
- usage();
- optarg = NULL;
- }
+again:
+ while ((opt = getopt(ac, av,
+ "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
@@ -361,23 +344,29 @@ main(int ac, char **av)
break;
#ifdef AFS
case 'k':
- options.krb4_tgt_passing = 0;
-#ifdef KRB5
- options.krb5_tgt_passing = 0;
-#endif
+ options.kerberos_tgt_passing = 0;
options.afs_token_passing = 0;
break;
#endif
case 'i':
if (stat(optarg, &st) < 0) {
- fprintf(stderr, "Warning: Identity file %s does not exist.\n",
- optarg);
+ fprintf(stderr, "Warning: Identity file %s "
+ "does not exist.\n", optarg);
break;
}
- if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
- fatal("Too many identity files specified (max %d)",
- SSH_MAX_IDENTITY_FILES);
- options.identity_files[options.num_identity_files++] = xstrdup(optarg);
+ if (options.num_identity_files >=
+ SSH_MAX_IDENTITY_FILES)
+ fatal("Too many identity files specified "
+ "(max %d)", SSH_MAX_IDENTITY_FILES);
+ options.identity_files[options.num_identity_files++] =
+ xstrdup(optarg);
+ break;
+ case 'I':
+#ifdef SMARTCARD
+ options.smartcard_device = xstrdup(optarg);
+#else
+ fprintf(stderr, "no support for smartcards.\n");
+#endif
break;
case 't':
if (tty_flag)
@@ -391,9 +380,8 @@ main(int ac, char **av)
} else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
options.log_level++;
break;
- } else {
+ } else
fatal("Too high debugging level.");
- }
/* fallthrough */
case 'V':
fprintf(stderr,
@@ -410,14 +398,16 @@ main(int ac, char **av)
break;
case 'e':
if (optarg[0] == '^' && optarg[2] == 0 &&
- (u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128)
+ (u_char) optarg[1] >= 64 &&
+ (u_char) optarg[1] < 128)
options.escape_char = (u_char) optarg[1] & 31;
else if (strlen(optarg) == 1)
options.escape_char = (u_char) optarg[0];
else if (strcmp(optarg, "none") == 0)
- options.escape_char = -2;
+ options.escape_char = SSH_ESCAPECHAR_NONE;
else {
- fprintf(stderr, "Bad escape character '%s'.\n", optarg);
+ fprintf(stderr, "Bad escape character '%s'.\n",
+ optarg);
exit(1);
}
break;
@@ -430,23 +420,25 @@ main(int ac, char **av)
/* SSH1 only */
options.cipher = cipher_number(optarg);
if (options.cipher == -1) {
- fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
+ fprintf(stderr,
+ "Unknown cipher type '%s'\n",
+ optarg);
exit(1);
}
- if (options.cipher == SSH_CIPHER_3DES) {
+ if (options.cipher == SSH_CIPHER_3DES)
options.ciphers = "3des-cbc";
- } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
+ else if (options.cipher == SSH_CIPHER_BLOWFISH)
options.ciphers = "blowfish-cbc";
- } else {
+ else
options.ciphers = (char *)-1;
- }
}
break;
case 'm':
if (mac_valid(optarg))
options.macs = xstrdup(optarg);
else {
- fprintf(stderr, "Unknown mac type '%s'\n", optarg);
+ fprintf(stderr, "Unknown mac type '%s'\n",
+ optarg);
exit(1);
}
break;
@@ -460,33 +452,38 @@ main(int ac, char **av)
case 'l':
options.user = optarg;
break;
+
+ case 'L':
case 'R':
- if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
- &fwd_host_port) != 3 &&
- sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
- &fwd_host_port) != 3) {
- fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
+ if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]",
+ sfwd_port, buf, sfwd_host_port) != 3 &&
+ sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]",
+ sfwd_port, buf, sfwd_host_port) != 3) {
+ fprintf(stderr,
+ "Bad forwarding specification '%s'\n",
+ optarg);
usage();
/* NOTREACHED */
}
- add_remote_forward(&options, fwd_port, buf, fwd_host_port);
- break;
- case 'L':
- if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
- &fwd_host_port) != 3 &&
- sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
- &fwd_host_port) != 3) {
- fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
- usage();
- /* NOTREACHED */
+ if ((fwd_port = a2port(sfwd_port)) == 0 ||
+ (fwd_host_port = a2port(sfwd_host_port)) == 0) {
+ fprintf(stderr,
+ "Bad forwarding port(s) '%s'\n", optarg);
+ exit(1);
}
- add_local_forward(&options, fwd_port, buf, fwd_host_port);
+ if (opt == 'L')
+ add_local_forward(&options, fwd_port, buf,
+ fwd_host_port);
+ else if (opt == 'R')
+ add_remote_forward(&options, fwd_port, buf,
+ fwd_host_port);
break;
case 'D':
fwd_port = a2port(optarg);
if (fwd_port == 0) {
- fprintf(stderr, "Bad dynamic port '%s'\n", optarg);
+ fprintf(stderr, "Bad dynamic port '%s'\n",
+ optarg);
exit(1);
}
add_local_forward(&options, fwd_port, "socks4", 0);
@@ -504,24 +501,53 @@ main(int ac, char **av)
break;
case 'o':
dummy = 1;
- if (process_config_line(&options, host ? host : "", optarg,
- "command-line", 0, &dummy) != 0)
+ if (process_config_line(&options, host ? host : "",
+ optarg, "command-line", 0, &dummy) != 0)
exit(1);
break;
case 's':
subsystem_flag = 1;
break;
+ case 'b':
+ options.bind_address = optarg;
+ break;
+ case 'F':
+ config = optarg;
+ break;
default:
usage();
}
}
+ ac -= optind;
+ av += optind;
+
+ if (ac > 0 && !host && **av != '-') {
+ if (strchr(*av, '@')) {
+ p = xstrdup(*av);
+ cp = strchr(p, '@');
+ if (cp == NULL || cp == p)
+ usage();
+ options.user = p;
+ *cp = '\0';
+ host = ++cp;
+ } else
+ host = *av;
+ ac--, av++;
+ if (ac > 0) {
+ optind = 0;
+ optreset = 1;
+ goto again;
+ }
+ }
+
/* Check that we got a host name. */
if (!host)
usage();
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
+ channel_set_af(IPv4or6);
/* Initialize the command to execute on remote host. */
buffer_init(&command);
@@ -531,18 +557,18 @@ main(int ac, char **av)
* is no limit on the length of the command, except by the maximum
* packet size. Also sets the tty flag if there is no command.
*/
- if (optind == ac) {
+ if (!ac) {
/* No command specified - execute shell on a tty. */
tty_flag = 1;
if (subsystem_flag) {
- fprintf(stderr, "You must specify a subsystem to invoke.\n");
+ fprintf(stderr,
+ "You must specify a subsystem to invoke.\n");
usage();
}
} else {
- /* A command has been specified. Store it into the
- buffer. */
- for (i = optind; i < ac; i++) {
- if (i > optind)
+ /* A command has been specified. Store it into the buffer. */
+ for (i = 0; i < ac; i++) {
+ if (i)
buffer_append(&command, " ", 1);
buffer_append(&command, av[i], strlen(av[i]));
}
@@ -573,12 +599,22 @@ main(int ac, char **av)
log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
SYSLOG_FACILITY_USER, 1);
- /* Read per-user configuration file. */
- snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_CONFFILE);
- read_config_file(buf, host, &options);
-
- /* Read systemwide configuration file. */
- read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
+ /*
+ * Read per-user configuration file. Ignore the system wide config
+ * file if the user specifies a config file on the command line.
+ */
+ if (config != NULL) {
+ if (!read_config_file(config, host, &options))
+ fatal("Can't open user config file %.100s: "
+ "%.100s", config, strerror(errno));
+ } else {
+ snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
+ _PATH_SSH_USER_CONFFILE);
+ (void)read_config_file(buf, host, &options);
+
+ /* Read systemwide configuration file after use config. */
+ (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
+ }
/* Fill configuration defaults. */
fill_default_options(&options);
@@ -637,7 +673,7 @@ main(int ac, char **av)
/* Open a connection to the remote host. */
- ok = ssh_connect(host, &hostaddr, options.port,
+ cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6,
options.connection_attempts,
original_effective_uid != 0 || !options.use_privileged_port,
pw, options.proxy_command);
@@ -650,7 +686,7 @@ main(int ac, char **av)
*/
sensitive_data.nkeys = 0;
sensitive_data.keys = NULL;
- if (ok && (options.rhosts_rsa_authentication ||
+ if (!cerr && (options.rhosts_rsa_authentication ||
options.hostbased_authentication)) {
sensitive_data.nkeys = 3;
sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key));
@@ -682,26 +718,25 @@ main(int ac, char **av)
* 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, _PATH_SSH_USER_DIR);
+ snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
if (stat(buf, &st) < 0)
if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf);
/* Check if the connection failed, and try "rsh" if appropriate. */
- if (!ok) {
+ if (cerr) {
+ if (!options.fallback_to_rsh)
+ exit(1);
if (options.port != 0)
- log("Secure connection to %.100s on port %hu refused%.100s.",
- host, options.port,
- options.fallback_to_rsh ? "; reverting to insecure method" : "");
+ log("Secure connection to %.100s on port %hu refused; "
+ "reverting to insecure method",
+ host, options.port);
else
- log("Secure connection to %.100s refused%.100s.", host,
- options.fallback_to_rsh ? "; reverting to insecure method" : "");
+ log("Secure connection to %.100s refused; "
+ "reverting to insecure method.", host);
- if (options.fallback_to_rsh) {
- rsh_connect(host, options.user, &command);
- fatal("rsh_connect returned");
- }
- exit(1);
+ rsh_connect(host, options.user, &command);
+ fatal("rsh_connect returned");
}
/* load options.identity_files */
load_public_identity_files();
@@ -717,6 +752,8 @@ main(int ac, char **av)
options.user_hostfile2 =
tilde_expand_filename(options.user_hostfile2, original_real_uid);
+ signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
+
/* Log into the remote system. This never returns if the login fails. */
ssh_login(sensitive_data.keys, sensitive_data.nkeys,
host, (struct sockaddr *)&hostaddr, pw);
@@ -733,26 +770,53 @@ main(int ac, char **av)
}
xfree(sensitive_data.keys);
}
+ for (i = 0; i < options.num_identity_files; i++) {
+ if (options.identity_files[i]) {
+ xfree(options.identity_files[i]);
+ options.identity_files[i] = NULL;
+ }
+ if (options.identity_keys[i]) {
+ key_free(options.identity_keys[i]);
+ options.identity_keys[i] = NULL;
+ }
+ }
exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close();
return exit_status;
}
-void
-x11_get_proto(char *proto, int proto_len, char *data, int data_len)
+static void
+x11_get_proto(char **_proto, char **_data)
{
char line[512];
+ static char proto[512], data[512];
FILE *f;
int got_data = 0, i;
+ char *display;
- if (options.xauth_location) {
+ *_proto = proto;
+ *_data = data;
+ proto[0] = data[0] = '\0';
+ if (options.xauth_location && (display = getenv("DISPLAY"))) {
/* Try to get Xauthority information for the display. */
- snprintf(line, sizeof line, "%.100s list %.200s 2>" _PATH_DEVNULL,
- options.xauth_location, getenv("DISPLAY"));
+ if (strncmp(display, "localhost:", 10) == 0)
+ /*
+ * Handle FamilyLocal case where $DISPLAY does
+ * not match an authorization entry. For this we
+ * just try "xauth list unix:displaynum.screennum".
+ * XXX: "localhost" match to determine FamilyLocal
+ * is not perfect.
+ */
+ snprintf(line, sizeof line, "%.100s list unix:%s 2>"
+ _PATH_DEVNULL, options.xauth_location, display+10);
+ else
+ snprintf(line, sizeof line, "%.100s list %.200s 2>"
+ _PATH_DEVNULL, options.xauth_location, display);
+ debug2("x11_get_proto %s", line);
f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) &&
- sscanf(line, "%*s %s %s", proto, data) == 2)
+ sscanf(line, "%*s %511s %511s", proto, data) == 2)
got_data = 1;
if (f)
pclose(f);
@@ -768,17 +832,17 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
if (!got_data) {
u_int32_t rand = 0;
- strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len);
+ strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
for (i = 0; i < 16; i++) {
if (i % 4 == 0)
rand = arc4random();
- snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff);
+ snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
rand >>= 8;
}
}
}
-void
+static void
ssh_init_forwarding(void)
{
int success = 0;
@@ -790,7 +854,7 @@ ssh_init_forwarding(void)
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port);
- success += channel_request_local_forwarding(
+ success += channel_setup_local_fwd_listener(
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
@@ -812,7 +876,7 @@ ssh_init_forwarding(void)
}
}
-void
+static void
check_agent_present(void)
{
if (options.forward_agent) {
@@ -825,11 +889,10 @@ check_agent_present(void)
}
}
-int
+static int
ssh_session(void)
{
int type;
- int plen;
int interactive = 0;
int have_tty = 0;
struct winsize ws;
@@ -847,7 +910,7 @@ ssh_session(void)
packet_put_int(options.compression_level);
packet_send();
packet_write_wait();
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS)
packet_start_compression(options.compression_level);
else if (type == SSH_SMSG_FAILURE)
@@ -867,7 +930,7 @@ ssh_session(void)
cp = getenv("TERM");
if (!cp)
cp = "";
- packet_put_string(cp, strlen(cp));
+ packet_put_cstring(cp);
/* Store window size in the packet. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
@@ -885,7 +948,7 @@ ssh_session(void)
packet_write_wait();
/* Read response from the server. */
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
have_tty = 1;
@@ -896,15 +959,15 @@ ssh_session(void)
}
/* Request X11 forwarding if enabled and DISPLAY is set. */
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
- char proto[512], data[512];
+ char *proto, *data;
/* Get reasonable local authentication information. */
- x11_get_proto(proto, sizeof proto, data, sizeof data);
+ x11_get_proto(&proto, &data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(0, proto, data);
/* Read response from the server. */
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
} else if (type == SSH_SMSG_FAILURE) {
@@ -924,8 +987,8 @@ ssh_session(void)
auth_request_forwarding();
/* Read response from the server. */
- type = packet_read(&plen);
- packet_integrity_check(plen, 0, type);
+ type = packet_read();
+ packet_check_eom();
if (type != SSH_SMSG_SUCCESS)
log("Warning: Remote host denied authentication agent forwarding.");
}
@@ -946,7 +1009,7 @@ ssh_session(void)
int len = buffer_len(&command);
if (len > 900)
len = 900;
- debug("Sending command: %.*s", len, buffer_ptr(&command));
+ debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
packet_start(SSH_CMSG_EXEC_CMD);
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send();
@@ -959,11 +1022,12 @@ ssh_session(void)
}
/* Enter the interactive session. */
- return client_loop(have_tty, tty_flag ? options.escape_char : -1, 0);
+ return client_loop(have_tty, tty_flag ?
+ options.escape_char : SSH_ESCAPECHAR_NONE, 0);
}
-void
-client_subsystem_reply(int type, int plen, void *ctxt)
+static void
+client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
{
int id, len;
@@ -971,20 +1035,21 @@ client_subsystem_reply(int type, int plen, void *ctxt)
len = buffer_len(&command);
if (len > 900)
len = 900;
- packet_done();
+ packet_check_eom();
if (type == SSH2_MSG_CHANNEL_FAILURE)
fatal("Request for subsystem '%.*s' failed on channel %d",
- len, buffer_ptr(&command), id);
+ len, (u_char *)buffer_ptr(&command), id);
}
-void
-ssh_session2_callback(int id, void *arg)
+/* request pty/x11/agent/tcpfwd/shell for channel */
+static void
+ssh_session2_setup(int id, void *arg)
{
int len;
int interactive = 0;
struct termios tio;
- debug("client_init id %d arg %ld", id, (long)arg);
+ debug("ssh_session2_setup: id %d", id);
if (tty_flag) {
struct winsize ws;
@@ -1010,9 +1075,9 @@ ssh_session2_callback(int id, void *arg)
}
if (options.forward_x11 &&
getenv("DISPLAY") != NULL) {
- char proto[512], data[512];
+ char *proto, *data;
/* Get reasonable local authentication information. */
- x11_get_proto(proto, sizeof proto, data, sizeof data);
+ x11_get_proto(&proto, &data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(id, proto, data);
@@ -1032,32 +1097,32 @@ ssh_session2_callback(int id, void *arg)
if (len > 900)
len = 900;
if (subsystem_flag) {
- debug("Sending subsystem: %.*s", len, buffer_ptr(&command));
+ debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
channel_request_start(id, "subsystem", /*want reply*/ 1);
/* register callback for reply */
/* XXX we asume that client_loop has already been called */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
} else {
- debug("Sending command: %.*s", len, buffer_ptr(&command));
+ debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
channel_request_start(id, "exec", 0);
}
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send();
} else {
- channel_request(id, "shell", 0);
+ channel_request_start(id, "shell", 0);
+ packet_send();
}
- /* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
- /* register different callback, etc. XXX */
packet_set_interactive(interactive);
}
-int
-ssh_session2_command(void)
+/* open new channel for a session */
+static int
+ssh_session2_open(void)
{
- int id, window, packetmax;
- int in, out, err;
+ Channel *c;
+ int window, packetmax, in, out, err;
if (stdin_null_flag) {
in = open(_PATH_DEVNULL, O_RDONLY);
@@ -1080,50 +1145,85 @@ ssh_session2_command(void)
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
- if (!tty_flag) {
- window *= 2;
- packetmax *=2;
+ if (tty_flag) {
+ window >>= 1;
+ packetmax >>= 1;
}
- id = channel_new(
+ c = channel_new(
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
xstrdup("client-session"), /*nonblock*/0);
-debug("channel_new: %d", id);
+ debug3("ssh_session2_open: channel_new: %d", c->self);
- channel_open(id);
- channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
- ssh_session2_callback, (void *)0);
+ channel_send_open(c->self);
+ if (!no_shell_flag)
+ channel_register_confirm(c->self, ssh_session2_setup);
- return id;
+ return c->self;
}
-int
+static int
ssh_session2(void)
{
- int id;
+ int id = -1;
/* XXX should be pre-session */
ssh_init_forwarding();
- id = no_shell_flag ? -1 : ssh_session2_command();
+ if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
+ id = ssh_session2_open();
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
- return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id);
+ return client_loop(tty_flag, tty_flag ?
+ options.escape_char : SSH_ESCAPECHAR_NONE, id);
}
-void
+static void
load_public_identity_files(void)
{
char *filename;
Key *public;
- int i;
-
- for (i = 0; i < options.num_identity_files; i++) {
+ int i = 0;
+
+#ifdef SMARTCARD
+ if (options.smartcard_device != NULL &&
+ options.num_identity_files + 1 < SSH_MAX_IDENTITY_FILES &&
+ (public = sc_get_key(options.smartcard_device)) != NULL ) {
+ Key *new;
+
+ if (options.num_identity_files + 2 > SSH_MAX_IDENTITY_FILES)
+ options.num_identity_files = SSH_MAX_IDENTITY_FILES - 2;
+ memmove(&options.identity_files[2], &options.identity_files[0],
+ sizeof(char *) * options.num_identity_files);
+ options.num_identity_files += 2;
+ i = 2;
+
+ /* XXX ssh1 vs ssh2 */
+ new = key_new(KEY_RSA);
+ new->flags = KEY_FLAG_EXT;
+ BN_copy(new->rsa->n, public->rsa->n);
+ BN_copy(new->rsa->e, public->rsa->e);
+ RSA_set_method(new->rsa, sc_get_engine());
+ options.identity_keys[0] = new;
+ options.identity_files[0] = xstrdup("smartcard rsa key");;
+
+ new = key_new(KEY_RSA1);
+ new->flags = KEY_FLAG_EXT;
+ BN_copy(new->rsa->n, public->rsa->n);
+ BN_copy(new->rsa->e, public->rsa->e);
+ RSA_set_method(new->rsa, sc_get_engine());
+ options.identity_keys[1] = new;
+ options.identity_files[1] = xstrdup("smartcard rsa1 key");
+
+ key_free(public);
+ }
+#endif /* SMARTCARD */
+ for (; i < options.num_identity_files; i++) {
filename = tilde_expand_filename(options.identity_files[i],
original_real_uid);
public = key_load_public(filename, NULL);
diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h
index 7485fb8..6848e1e 100644
--- a/crypto/openssh/ssh.h
+++ b/crypto/openssh/ssh.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: ssh.h,v 1.64 2002/03/04 17:27:39 stevesk Exp $ */
+/* $FreeBSD$ */
+
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -10,9 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: ssh.h,v 1.62 2001/01/23 10:45:10 markus Exp $"); */
-/* RCSID("$FreeBSD$"); */
-
#ifndef SSH_H
#define SSH_H
@@ -83,8 +83,8 @@
/* Name of Kerberos service for SSH to use. */
#define KRB4_SERVICE_NAME "rcmd"
-/* Kerberos IV tickets can't be forwarded. This is an AFS hack! */
-#define SSH_CMSG_HAVE_KRB4_TGT SSH_CMSG_HAVE_KERBEROS_TGT /* credentials (s) */
+/* Used to identify ``EscapeChar none'' */
+#define SSH_ESCAPECHAR_NONE -2
#ifdef USE_PAM
#include "auth-pam.h"
diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config
index a02ad7d..d289d4c 100644
--- a/crypto/openssh/ssh_config
+++ b/crypto/openssh/ssh_config
@@ -1,13 +1,10 @@
-# This is ssh client systemwide configuration file. This file provides
-# defaults for users, and the values can be changed in per-user configuration
-# files or on the command line.
-#
-# $OpenBSD: ssh_config,v 1.10 2001/04/03 21:19:38 todd Exp $
-# $FreeBSD$
+# $OpenBSD: ssh_config,v 1.12 2002/01/16 17:55:33 stevesk Exp $
+# $FreeBSD$
-# This is ssh client systemwide configuration file. See ssh(1) for more
-# information. This file provides defaults for users, and the values can
-# be changed in per-user configuration files or on the command line.
+# This is the ssh client system-wide configuration file. See ssh(1)
+# for more information. This file provides defaults for users, and
+# the values can be changed in per-user configuration files or on the
+# command line.
# Configuration data is parsed as follows:
# 1. command line options
@@ -22,7 +19,7 @@
# Host *
# ForwardAgent no
# ForwardX11 no
-# RhostsAuthentication no
+# RhostsAuthentication yes
# RhostsRSAAuthentication yes
# RSAAuthentication yes
# PasswordAuthentication yes
@@ -30,11 +27,12 @@
# UseRsh no
# BatchMode no
# CheckHostIP yes
-# StrictHostKeyChecking yes
+# StrictHostKeyChecking ask
# IdentityFile ~/.ssh/identity
-# IdentityFile ~/.ssh/id_dsa
# IdentityFile ~/.ssh/id_rsa
+# IdentityFile ~/.ssh/id_dsa
# Port 22
# Protocol 2,1
-# Cipher blowfish
+# Cipher 3des
+# Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc
# EscapeChar ~
diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c
index 679660f..1a6f8e4 100644
--- a/crypto/openssh/sshconnect.c
+++ b/crypto/openssh/sshconnect.c
@@ -13,7 +13,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.119 2002/01/21 15:13:51 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h>
@@ -32,9 +32,7 @@ RCSID("$FreeBSD$");
#include "readconf.h"
#include "atomicio.h"
#include "misc.h"
-#include "auth.h"
-#include "ssh1.h"
-#include "canohost.h"
+#include "readpass.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
@@ -42,13 +40,31 @@ char *server_version_string = NULL;
extern Options options;
extern char *__progname;
-/* AF_UNSPEC or AF_INET or AF_INET6 */
-extern int IPv4or6;
+static const char *
+sockaddr_ntop(struct sockaddr *sa)
+{
+ void *addr;
+ static char addrbuf[INET6_ADDRSTRLEN];
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ addr = &((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+ default:
+ /* This case should be protected against elsewhere */
+ abort(); /* XXX abort is bad -- do something else */
+ }
+ inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
+ return addrbuf;
+}
/*
* Connect to the given ssh server using a proxy command.
*/
-int
+static int
ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
const char *proxy_command)
{
@@ -91,7 +107,7 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
/* Create pipes for communicating with the proxy. */
if (pipe(pin) < 0 || pipe(pout) < 0)
fatal("Could not create pipes to communicate with the proxy: %.100s",
- strerror(errno));
+ strerror(errno));
debug("Executing proxy command: %.500s", command_string);
@@ -142,16 +158,18 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
/* Set the connection file descriptors. */
packet_set_connection(pout[0], pin[1]);
- return 1;
+ /* Indicate OK return */
+ return 0;
}
/*
* Creates a (possibly privileged) socket for use as the ssh connection.
*/
-int
+static int
ssh_create_socket(struct passwd *pw, int privileged, int family)
{
- int sock;
+ int sock, gaierr;
+ struct addrinfo hints, *res;
/*
* If we are running as root and want to connect to a privileged
@@ -164,17 +182,40 @@ ssh_create_socket(struct passwd *pw, int privileged, int family)
error("rresvport: af=%d %.100s", family, strerror(errno));
else
debug("Allocated local port %d.", p);
- } else {
- /*
- * Just create an ordinary socket on arbitrary port. We use
- * the user's uid to create the socket.
- */
- temporarily_use_uid(pw);
- sock = socket(family, SOCK_STREAM, 0);
- if (sock < 0)
- error("socket: %.100s", strerror(errno));
- restore_uid();
+ return sock;
}
+ /*
+ * Just create an ordinary socket on arbitrary port. We use
+ * the user's uid to create the socket.
+ */
+ temporarily_use_uid(pw);
+ sock = socket(family, SOCK_STREAM, 0);
+ if (sock < 0)
+ error("socket: %.100s", strerror(errno));
+ restore_uid();
+
+ /* Bind the socket to an alternative local IP address */
+ if (options.bind_address == NULL)
+ return sock;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
+ if (gaierr) {
+ error("getaddrinfo: %s: %s", options.bind_address,
+ gai_strerror(gaierr));
+ close(sock);
+ return -1;
+ }
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ error("bind: %s: %s", options.bind_address, strerror(errno));
+ close(sock);
+ freeaddrinfo(res);
+ return -1;
+ }
+ freeaddrinfo(res);
return sock;
}
@@ -188,12 +229,17 @@ ssh_create_socket(struct passwd *pw, int privileged, int family)
* second). If proxy_command is non-NULL, it specifies the command (with %h
* and %p substituted for host and port, respectively) to use to contact
* the daemon.
+ * Return values:
+ * 0 for OK
+ * ECONNREFUSED if we got a "Connection Refused" by the peer on any address
+ * ECONNABORTED if we failed without a "Connection refused"
+ * Suitable error messages for the connection failure will already have been
+ * printed.
*/
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
- u_short port, int connection_attempts,
- int anonymous, struct passwd *pw,
- const char *proxy_command)
+ u_short port, int family, int connection_attempts,
+ int anonymous, struct passwd *pw, const char *proxy_command)
{
int gaierr;
int on = 1;
@@ -202,9 +248,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
struct addrinfo hints, *ai, *aitop;
struct linger linger;
struct servent *sp;
+ /*
+ * Did we get only other errors than "Connection refused" (which
+ * should block fallback to rsh and similar), or did we get at least
+ * one "Connection refused"?
+ */
+ int full_failure = 1;
debug("ssh_connect: getuid %u geteuid %u anon %d",
- (u_int) getuid(), (u_int) geteuid(), anonymous);
+ (u_int) getuid(), (u_int) geteuid(), anonymous);
/* Get default port if port has not been set. */
if (port == 0) {
@@ -221,7 +273,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* No proxy command. */
memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
+ hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
@@ -232,8 +284,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* Try to connect several times. On some machines, the first time
* will sometimes fail. In general socket code appears to behave
* quite magically on many machines.
- */
- for (attempt = 0; attempt < connection_attempts; attempt++) {
+ */
+ for (attempt = 0; ;) {
if (attempt > 0)
debug("Trying again...");
@@ -256,6 +308,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
!anonymous && geteuid() == 0,
ai->ai_family);
if (sock < 0)
+ /* Any error is already output */
continue;
/* Connect to the host. We use the user's uid in the
@@ -269,7 +322,11 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
restore_uid();
break;
} else {
- debug("connect: %.100s", strerror(errno));
+ if (errno == ECONNREFUSED)
+ full_failure = 0;
+ log("ssh: connect to address %s port %s: %s",
+ sockaddr_ntop(ai->ai_addr), strport,
+ strerror(errno));
restore_uid();
/*
* Close the failed socket; there appear to
@@ -277,13 +334,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* which connect() has already returned an
* error.
*/
- shutdown(sock, SHUT_RDWR);
close(sock);
}
}
if (ai)
break; /* Successful connection. */
+ attempt++;
+ if (attempt >= connection_attempts)
+ break;
/* Sleep a moment before retrying. */
sleep(1);
}
@@ -292,7 +351,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Return failure if we didn't get a successful connection. */
if (attempt >= connection_attempts)
- return 0;
+ return full_failure ? ECONNABORTED : ECONNREFUSED;
debug("Connection established.");
@@ -314,14 +373,14 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Set the connection. */
packet_set_connection(sock, sock);
- return 1;
+ return 0;
}
/*
* Waits for the server identification string, and sends our own
* identification string.
*/
-void
+static void
ssh_exchange_identification(void)
{
char buf[256], remote_version[256]; /* must be same size! */
@@ -363,12 +422,12 @@ ssh_exchange_identification(void)
&remote_major, &remote_minor, remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf);
debug("Remote protocol version %d.%d, remote software version %.100s",
- remote_major, remote_minor, remote_version);
+ remote_major, remote_minor, remote_version);
compat_datafellows(remote_version);
mismatch = 0;
- switch(remote_major) {
+ switch (remote_major) {
case 1:
if (remote_minor == 99 &&
(options.protocol & SSH_PROTO_2) &&
@@ -406,8 +465,6 @@ ssh_exchange_identification(void)
fatal("Protocol major versions differ: %d vs. %d",
(options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
remote_major);
- if (compat20)
- packet_set_ssh2_format();
/* Send our own protocol version identification. */
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
@@ -422,61 +479,38 @@ ssh_exchange_identification(void)
}
/* defaults to 'no' */
-int
-read_yes_or_no(const char *prompt, int defval)
+static int
+confirm(const char *prompt)
{
- char buf[1024];
- FILE *f;
- int retval = -1;
+ const char *msg, *again = "Please type 'yes' or 'no': ";
+ char *p;
+ int ret = -1;
if (options.batch_mode)
return 0;
-
- if (isatty(STDIN_FILENO))
- f = stdin;
- else
- f = fopen(_PATH_TTY, "rw");
-
- if (f == NULL)
- return 0;
-
- fflush(stdout);
-
- while (1) {
- fprintf(stderr, "%s", prompt);
- if (fgets(buf, sizeof(buf), f) == NULL) {
- /* Print a newline (the prompt probably didn\'t have one). */
- fprintf(stderr, "\n");
- strlcpy(buf, "no", sizeof buf);
- }
- /* Remove newline from response. */
- if (strchr(buf, '\n'))
- *strchr(buf, '\n') = 0;
-
- if (buf[0] == 0)
- retval = defval;
- if (strcmp(buf, "yes") == 0)
- retval = 1;
- else if (strcmp(buf, "no") == 0)
- retval = 0;
- else
- fprintf(stderr, "Please type 'yes' or 'no'.\n");
-
- if (retval != -1) {
- if (f != stdin)
- fclose(f);
- return retval;
- }
+ for (msg = prompt;;msg = again) {
+ p = read_passphrase(msg, RP_ECHO);
+ if (p == NULL ||
+ (p[0] == '\0') || (p[0] == '\n') ||
+ strncasecmp(p, "no", 2) == 0)
+ ret = 0;
+ if (strncasecmp(p, "yes", 3) == 0)
+ ret = 1;
+ if (p)
+ xfree(p);
+ if (ret != -1)
+ return ret;
}
}
/*
- * check whether the supplied host key is valid, return only if ok.
+ * check whether the supplied host key is valid, return -1 if the key
+ * is not valid. the user_hostfile will not be updated if 'readonly' is true.
*/
-void
+static int
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
- const char *user_hostfile, const char *system_hostfile)
+ int readonly, const char *user_hostfile, const char *system_hostfile)
{
Key *file_key;
char *type = key_type(host_key);
@@ -486,7 +520,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
HostStatus ip_status;
int local = 0, host_ip_differ = 0;
char ntop[NI_MAXHOST];
- int host_line, ip_line;
+ char msg[1024];
+ int len, host_line, ip_line;
const char *host_file = NULL, *ip_file = NULL;
/*
@@ -500,19 +535,22 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
/** hostaddr == 0! */
switch (hostaddr->sa_family) {
case AF_INET:
- local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
+ local = (ntohl(((struct sockaddr_in *)hostaddr)->
+ sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
break;
case AF_INET6:
- local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
+ local = IN6_IS_ADDR_LOOPBACK(
+ &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
break;
default:
local = 0;
break;
}
- if (local && options.host_key_alias == NULL) {
+ if (options.no_host_authentication_for_localhost == 1 && local &&
+ options.host_key_alias == NULL) {
debug("Forcing accepting of host key for "
"loopback/localhost.");
- return;
+ return 0;
}
/*
@@ -556,10 +594,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* hosts or in the systemwide list.
*/
host_file = user_hostfile;
- host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
+ host_status = check_host_in_hostfile(host_file, host, host_key,
+ file_key, &host_line);
if (host_status == HOST_NEW) {
host_file = system_hostfile;
- host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
+ host_status = check_host_in_hostfile(host_file, host, host_key,
+ file_key, &host_line);
}
/*
* Also perform check for the ip address, skip the check if we are
@@ -569,10 +609,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
Key *ip_key = key_new(host_key->type);
ip_file = user_hostfile;
- ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
+ ip_status = check_host_in_hostfile(ip_file, ip, host_key,
+ ip_key, &ip_line);
if (ip_status == HOST_NEW) {
ip_file = system_hostfile;
- ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
+ ip_status = check_host_in_hostfile(ip_file, ip,
+ host_key, ip_key, &ip_line);
}
if (host_status == HOST_CHANGED &&
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
@@ -591,32 +633,46 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
host, type);
debug("Found key in %s:%d", host_file, host_line);
if (options.check_host_ip && ip_status == HOST_NEW) {
- if (!add_host_to_hostfile(user_hostfile, ip, host_key))
- log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).",
- type, ip, user_hostfile);
- else
- log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.",
+ if (readonly)
+ log("%s host key for IP address "
+ "'%.128s' not in list of known hosts.",
type, ip);
+ else if (!add_host_to_hostfile(user_hostfile, ip,
+ host_key))
+ log("Failed to add the %s host key for IP "
+ "address '%.128s' to the list of known "
+ "hosts (%.30s).", type, ip, user_hostfile);
+ else
+ log("Warning: Permanently added the %s host "
+ "key for IP address '%.128s' to the list "
+ "of known hosts.", type, ip);
}
break;
case HOST_NEW:
+ if (readonly)
+ goto fail;
/* The host is new. */
if (options.strict_host_key_checking == 1) {
- /* User has requested strict host key checking. We will not add the host key
- automatically. The only alternative left is to abort. */
- fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host);
+ /*
+ * User has requested strict host key checking. We
+ * will not add the host key automatically. The only
+ * alternative left is to abort.
+ */
+ error("No %s host key is known for %.200s and you "
+ "have requested strict checking.", type, host);
+ goto fail;
} else if (options.strict_host_key_checking == 2) {
/* The default */
- char prompt[1024];
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
- snprintf(prompt, sizeof(prompt),
- "The authenticity of host '%.200s (%s)' can't be established.\n"
+ snprintf(msg, sizeof(msg),
+ "The authenticity of host '%.200s (%s)' can't be "
+ "established.\n"
"%s key fingerprint is %s.\n"
- "Are you sure you want to continue connecting (yes/no)? ",
- host, ip, type, fp);
+ "Are you sure you want to continue connecting "
+ "(yes/no)? ", host, ip, type, fp);
xfree(fp);
- if (!read_yes_or_no(prompt, -1))
- fatal("Aborted by user!");
+ if (!confirm(msg))
+ goto fail;
}
if (options.check_host_ip && ip_status == HOST_NEW) {
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
@@ -624,13 +680,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
} else
hostp = host;
- /* If not in strict mode, add the key automatically to the local known_hosts file. */
+ /*
+ * If not in strict mode, add the key automatically to the
+ * local known_hosts file.
+ */
if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
- log("Failed to add the host to the list of known hosts (%.500s).",
- user_hostfile);
+ log("Failed to add the host to the list of known "
+ "hosts (%.500s).", user_hostfile);
else
- log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.",
- hostp, type);
+ log("Warning: Permanently added '%.200s' (%s) to the "
+ "list of known hosts.", hostp, type);
break;
case HOST_CHANGED:
if (options.check_host_ip && host_ip_differ) {
@@ -672,8 +731,11 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* 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)
- fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host);
+ if (options.strict_host_key_checking) {
+ error("%s host key for %.200s has changed and you have "
+ "requested strict checking.", type, host);
+ goto fail;
+ }
/*
* If strict host key checking has not been requested, allow
@@ -681,20 +743,26 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* agent forwarding.
*/
if (options.password_authentication) {
- error("Password authentication is disabled to avoid trojan horses.");
+ error("Password authentication is disabled to avoid "
+ "man-in-the-middle attacks.");
options.password_authentication = 0;
}
if (options.forward_agent) {
- error("Agent forwarding is disabled to avoid trojan horses.");
+ error("Agent forwarding is disabled to avoid "
+ "man-in-the-middle attacks.");
options.forward_agent = 0;
}
if (options.forward_x11) {
- error("X11 forwarding is disabled to avoid trojan horses.");
+ error("X11 forwarding is disabled to avoid "
+ "man-in-the-middle attacks.");
options.forward_x11 = 0;
}
- if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) {
- error("Port forwarding is disabled to avoid trojan horses.");
- options.num_local_forwards = options.num_remote_forwards = 0;
+ if (options.num_local_forwards > 0 ||
+ options.num_remote_forwards > 0) {
+ error("Port forwarding is disabled to avoid "
+ "man-in-the-middle attacks.");
+ options.num_local_forwards =
+ options.num_remote_forwards = 0;
}
/*
* XXX Should permit the user to change to use the new id.
@@ -708,222 +776,54 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
if (options.check_host_ip && host_status != HOST_CHANGED &&
ip_status == HOST_CHANGED) {
- log("Warning: the %s host key for '%.200s' "
- "differs from the key for the IP address '%.128s'",
- type, host, ip);
- if (host_status == HOST_OK)
- log("Matching host key in %s:%d", host_file, host_line);
- log("Offending key for IP in %s:%d", ip_file, ip_line);
+ snprintf(msg, sizeof(msg),
+ "Warning: the %s host key for '%.200s' "
+ "differs from the key for the IP address '%.128s'"
+ "\nOffending key for IP in %s:%d",
+ type, host, ip, ip_file, ip_line);
+ if (host_status == HOST_OK) {
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len,
+ "\nMatching host key in %s:%d",
+ host_file, host_line);
+ }
if (options.strict_host_key_checking == 1) {
- fatal("Exiting, you have requested strict checking.");
+ log(msg);
+ error("Exiting, you have requested strict checking.");
+ goto fail;
} else if (options.strict_host_key_checking == 2) {
- if (!read_yes_or_no("Are you sure you want " \
- "to continue connecting (yes/no)? ", -1))
- fatal("Aborted by user!");
+ strlcat(msg, "\nAre you sure you want "
+ "to continue connecting (yes/no)? ", sizeof(msg));
+ if (!confirm(msg))
+ goto fail;
+ } else {
+ log(msg);
}
}
xfree(ip);
-}
+ return 0;
-#ifdef KRB5
-int
-try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context)
-{
- krb5_error_code problem;
- const char *tkfile;
- struct stat buf;
- krb5_ccache ccache = NULL;
- const char *remotehost;
- krb5_data ap;
- int type, payload_len;
- krb5_ap_rep_enc_part *reply = NULL;
- int ret;
-
- memset(&ap, 0, sizeof(ap));
-
- problem = krb5_init_context(context);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- tkfile = krb5_cc_default_name(*context);
- if (strncmp(tkfile, "FILE:", 5) == 0)
- tkfile += 5;
-
- if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
- debug("Kerberos V5: could not get default ccache (permission denied).");
- ret = 0;
- goto out;
- }
-
- problem = krb5_cc_default(*context, &ccache);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- remotehost = get_canonical_hostname(1);
-
- problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED,
- "host", remotehost, NULL, ccache, &ap);
- if (problem) {
- ret = 0;
- goto out;
- }
-
- packet_start(SSH_CMSG_AUTH_KERBEROS);
- packet_put_string((char *) ap.data, ap.length);
- packet_send();
- packet_write_wait();
-
- xfree(ap.data);
- ap.length = 0;
-
- type = packet_read(&payload_len);
- switch (type) {
- case SSH_SMSG_FAILURE:
- /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
- debug("Kerberos V5 authentication failed.");
- ret = 0;
- break;
-
- case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
- /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
- debug("Kerberos V5 authentication accepted.");
-
- /* Get server's response. */
- ap.data = packet_get_string((unsigned int *) &ap.length);
-
- packet_integrity_check(payload_len, 4 + ap.length, type);
- /* XXX je to dobre? */
-
- problem = krb5_rd_rep(*context, *auth_context, &ap, &reply);
- if (problem) {
- ret = 0;
- goto out;
- }
- ret = 1;
- break;
-
- default:
- packet_disconnect("Protocol error on Kerberos V5 response: %d", type);
- ret = 0;
- break;
-
- }
-
-out:
- if (ccache != NULL)
- krb5_cc_close(*context, ccache);
- if (reply != NULL)
- krb5_free_ap_rep_enc_part(*context, reply);
- if (ap.length > 0)
- krb5_data_free(&ap);
-
- return ret;
-
+fail:
+ xfree(ip);
+ return -1;
}
-void
-send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
+int
+verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
- int fd;
- int type, payload_len;
- krb5_error_code problem;
- krb5_data outbuf;
- krb5_ccache ccache = NULL;
- krb5_creds creds;
- krb5_kdc_flags flags;
- const char *remotehost = get_canonical_hostname(1);
-
- memset(&creds, 0, sizeof(creds));
- memset(&outbuf, 0, sizeof(outbuf));
-
- fd = packet_get_connection_in();
- problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd);
- if (problem) {
- goto out;
- }
-
-#if 0
- tkfile = krb5_cc_default_name(context);
- if (strncmp(tkfile, "FILE:", 5) == 0)
- tkfile += 5;
-
- if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
- debug("Kerberos V5: could not get default ccache (permission denied).");
- goto out;
- }
-#endif
-
- problem = krb5_cc_default(context, &ccache);
- if (problem) {
- goto out;
- }
-
- problem = krb5_cc_get_principal(context, ccache, &creds.client);
- if (problem) {
- goto out;
- }
-
- problem = krb5_build_principal(context, &creds.server,
- strlen(creds.client->realm),
- creds.client->realm,
- "krbtgt",
- creds.client->realm,
- NULL);
- if (problem) {
- goto out;
- }
-
- creds.times.endtime = 0;
-
- flags.i = 0;
- flags.b.forwarded = 1;
- flags.b.forwardable = krb5_config_get_bool(context, NULL,
- "libdefaults", "forwardable", NULL);
-
- problem = krb5_get_forwarded_creds (context,
- auth_context,
- ccache,
- flags.i,
- remotehost,
- &creds,
- &outbuf);
- if (problem) {
- goto out;
- }
-
- packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
- packet_put_string((char *)outbuf.data, outbuf.length);
- packet_send();
- packet_write_wait();
-
- type = packet_read(&payload_len);
- switch (type) {
- case SSH_SMSG_SUCCESS:
- break;
- case SSH_SMSG_FAILURE:
- break;
- default:
- break;
- }
-
-out:
- if (creds.client)
- krb5_free_principal(context, creds.client);
- if (creds.server)
- krb5_free_principal(context, creds.server);
- if (ccache)
- krb5_cc_close(context, ccache);
- if (outbuf.data)
- xfree(outbuf.data);
-
- return;
+ struct stat st;
+
+ /* return ok if the key can be found in an old keyfile */
+ if (stat(options.system_hostfile2, &st) == 0 ||
+ stat(options.user_hostfile2, &st) == 0) {
+ if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
+ options.user_hostfile2, options.system_hostfile2) == 0)
+ return 0;
+ }
+ return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
+ options.user_hostfile, options.system_hostfile);
}
-#endif /* KRB5 */
/*
* Starts a dialog with the server, and authenticates the current user on the
@@ -972,7 +872,7 @@ ssh_put_password(char *password)
char *padded;
if (datafellows & SSH_BUG_PASSWORDPAD) {
- packet_put_string(password, strlen(password));
+ packet_put_cstring(password);
return;
}
size = roundup(strlen(password) + 1, 32);
diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h
index 575827d..5c1d326 100644
--- a/crypto/openssh/sshconnect.h
+++ b/crypto/openssh/sshconnect.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.h,v 1.9 2001/04/12 19:15:25 markus Exp $ */
+/* $OpenBSD: sshconnect.h,v 1.13 2001/10/08 19:05:05 markus Exp $ */
/* $FreeBSD$ */
/*
@@ -28,29 +28,20 @@
#define SSHCONNECT_H
int
-ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
- u_short port, int connection_attempts,
- int anonymous, struct passwd *pw,
- const char *proxy_command);
+ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
+ int, struct passwd *, const char *);
void
-ssh_login(Key **keys, int nkeys, const char *orighost,
- struct sockaddr *hostaddr, struct passwd *pw);
+ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *);
-void
-check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
- const char *user_hostfile, const char *system_hostfile);
+int verify_host_key(char *, struct sockaddr *, Key *);
-void ssh_kex(char *host, struct sockaddr *hostaddr);
-void ssh_kex2(char *host, struct sockaddr *hostaddr);
+void ssh_kex(char *, struct sockaddr *);
+void ssh_kex2(char *, struct sockaddr *);
-void
-ssh_userauth1(const char *local_user, const char *server_user, char *host,
- Key **keys, int nkeys);
-void
-ssh_userauth2(const char *local_user, const char *server_user, char *host,
- Key **keys, int nkeys);
+void ssh_userauth1(const char *, const char *, char *, Key **, int);
+void ssh_userauth2(const char *, const char *, char *, Key **, int);
-void ssh_put_password(char *password);
+void ssh_put_password(char *);
#endif
diff --git a/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c
index 60d16b1..f021bec 100644
--- a/crypto/openssh/sshconnect1.c
+++ b/crypto/openssh/sshconnect1.c
@@ -13,15 +13,18 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect1.c,v 1.31 2001/04/17 08:14:01 markus Exp $");
+RCSID("$OpenBSD: sshconnect1.c,v 1.48 2002/02/11 16:15:46 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h>
-#include <openssl/evp.h>
+#include <openssl/md5.h>
#ifdef KRB4
#include <krb.h>
#endif
+#ifdef KRB5
+#include <krb5.h>
+#endif
#ifdef AFS
#include <kafs.h>
#include "radix.h"
@@ -57,7 +60,7 @@ extern char *__progname;
* Checks if the user has an authentication agent, and if so, tries to
* authenticate using the agent.
*/
-int
+static int
try_agent_authentication(void)
{
int type;
@@ -65,7 +68,6 @@ try_agent_authentication(void)
AuthenticationConnection *auth;
u_char response[16];
u_int i;
- int plen, clen;
Key *key;
BIGNUM *challenge;
@@ -74,12 +76,12 @@ try_agent_authentication(void)
if (!auth)
return 0;
- challenge = BN_new();
-
+ if ((challenge = BN_new()) == NULL)
+ fatal("try_agent_authentication: BN_new failed");
/* Loop through identities served by the agent. */
for (key = ssh_get_first_identity(auth, &comment, 1);
- key != NULL;
- key = ssh_get_next_identity(auth, &comment, 1)) {
+ key != NULL;
+ key = ssh_get_next_identity(auth, &comment, 1)) {
/* Try this identity. */
debug("Trying RSA authentication via agent with '%.100s'", comment);
@@ -92,7 +94,7 @@ try_agent_authentication(void)
packet_write_wait();
/* Wait for server's response. */
- type = packet_read(&plen);
+ type = packet_read();
/* The server sends failure if it doesn\'t like our key or
does not support RSA authentication. */
@@ -106,9 +108,8 @@ try_agent_authentication(void)
packet_disconnect("Protocol error during RSA authentication: %d",
type);
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
+ packet_get_bignum(challenge);
+ packet_check_eom();
debug("Received RSA challenge from server.");
@@ -133,7 +134,7 @@ try_agent_authentication(void)
packet_write_wait();
/* Wait for response from the server. */
- type = packet_read(&plen);
+ type = packet_read();
/* The server returns success if it accepted the authentication. */
if (type == SSH_SMSG_SUCCESS) {
@@ -157,7 +158,7 @@ try_agent_authentication(void)
* Computes the proper response to a RSA challenge, and sends the response to
* the server.
*/
-void
+static void
respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
{
u_char buf[32], response[16];
@@ -202,23 +203,18 @@ respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
* Checks if the user has authentication file, and if so, tries to authenticate
* the user using it.
*/
-int
-try_rsa_authentication(const char *authfile)
+static int
+try_rsa_authentication(int idx)
{
BIGNUM *challenge;
- Key *public;
- Key *private;
- char *passphrase, *comment;
- int type, i;
- int plen, clen;
+ Key *public, *private;
+ char buf[300], *passphrase, *comment, *authfile;
+ int i, type, quit;
+
+ public = options.identity_keys[idx];
+ authfile = options.identity_files[idx];
+ comment = xstrdup(authfile);
- /* Try to load identification for the authentication key. */
- /* XXKEYLOAD */
- public = key_load_public_type(KEY_RSA1, authfile, &comment);
- if (public == NULL) {
- /* Could not load it. Fail. */
- return 0;
- }
debug("Trying RSA authentication with key '%.100s'", comment);
/* Tell the server that we are willing to authenticate using this key. */
@@ -227,11 +223,8 @@ try_rsa_authentication(const char *authfile)
packet_send();
packet_write_wait();
- /* We no longer need the public key. */
- key_free(public);
-
/* Wait for server's response. */
- type = packet_read(&plen);
+ type = packet_read();
/*
* The server responds with failure if it doesn\'t like our key or
@@ -247,68 +240,74 @@ try_rsa_authentication(const char *authfile)
packet_disconnect("Protocol error during RSA authentication: %d", type);
/* Get the challenge from the packet. */
- challenge = BN_new();
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
+ if ((challenge = BN_new()) == NULL)
+ fatal("try_rsa_authentication: BN_new failed");
+ packet_get_bignum(challenge);
+ packet_check_eom();
debug("Received RSA challenge from server.");
/*
- * Load the private key. Try first with empty passphrase; if it
+ * If the key is not stored in external hardware, we have to
+ * load the private key. Try first with empty passphrase; if it
* fails, ask for a passphrase.
*/
- private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
- if (private == NULL) {
- char buf[300];
- snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
- comment);
- if (!options.batch_mode)
+ if (public->flags && KEY_FLAG_EXT)
+ private = public;
+ else
+ private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
+ if (private == NULL && !options.batch_mode) {
+ snprintf(buf, sizeof(buf),
+ "Enter passphrase for RSA key '%.100s': ", comment);
+ for (i = 0; i < options.number_of_password_prompts; i++) {
passphrase = read_passphrase(buf, 0);
- else {
- debug("Will not query passphrase for %.100s in batch mode.",
- comment);
- passphrase = xstrdup("");
- }
-
- /* Load the authentication file using the pasphrase. */
- private = key_load_private_type(KEY_RSA1, authfile, passphrase, NULL);
- if (private == NULL) {
+ if (strcmp(passphrase, "") != 0) {
+ private = key_load_private_type(KEY_RSA1,
+ authfile, passphrase, NULL);
+ quit = 0;
+ } else {
+ debug2("no passphrase given, try next key");
+ quit = 1;
+ }
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
- error("Bad passphrase.");
-
- /* Send a dummy response packet to avoid protocol error. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(0);
- packet_send();
- packet_write_wait();
-
- /* Expect the server to reject it... */
- packet_read_expect(&plen, SSH_SMSG_FAILURE);
- xfree(comment);
- BN_clear_free(challenge);
- return 0;
+ if (private != NULL || quit)
+ break;
+ debug2("bad passphrase given, try again...");
}
- /* Destroy the passphrase. */
- memset(passphrase, 0, strlen(passphrase));
- xfree(passphrase);
}
/* We no longer need the comment. */
xfree(comment);
+ if (private == NULL) {
+ if (!options.batch_mode)
+ error("Bad passphrase.");
+
+ /* Send a dummy response packet to avoid protocol error. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(0);
+ packet_send();
+ packet_write_wait();
+
+ /* Expect the server to reject it... */
+ packet_read_expect(SSH_SMSG_FAILURE);
+ BN_clear_free(challenge);
+ return 0;
+ }
+
/* Compute and send a response to the challenge. */
respond_to_rsa_challenge(challenge, private->rsa);
- /* Destroy the private key. */
- key_free(private);
+ /* Destroy the private key unless it in external hardware. */
+ if (!(private->flags & KEY_FLAG_EXT))
+ key_free(private);
/* We no longer need the challenge. */
BN_clear_free(challenge);
/* Wait for response from the server. */
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
debug("RSA authentication accepted by server.");
return 1;
@@ -323,18 +322,17 @@ try_rsa_authentication(const char *authfile)
* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
* authentication and RSA host authentication.
*/
-int
+static int
try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
{
int type;
BIGNUM *challenge;
- int plen, clen;
debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
/* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
- packet_put_string(local_user, strlen(local_user));
+ packet_put_cstring(local_user);
packet_put_int(BN_num_bits(host_key->rsa->n));
packet_put_bignum(host_key->rsa->e);
packet_put_bignum(host_key->rsa->n);
@@ -342,7 +340,7 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
packet_write_wait();
/* Wait for server's response. */
- type = packet_read(&plen);
+ type = packet_read();
/* The server responds with failure if it doesn't admit our
.rhosts authentication or doesn't know our host key. */
@@ -355,10 +353,10 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
packet_disconnect("Protocol error during RSA authentication: %d", type);
/* Get the challenge from the packet. */
- challenge = BN_new();
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
+ if ((challenge = BN_new()) == NULL)
+ fatal("try_rhosts_rsa_authentication: BN_new failed");
+ packet_get_bignum(challenge);
+ packet_check_eom();
debug("Received RSA challenge for host key from server.");
@@ -369,7 +367,7 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
BN_clear_free(challenge);
/* Wait for response from the server. */
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
return 1;
@@ -381,7 +379,7 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
}
#ifdef KRB4
-int
+static int
try_krb4_authentication(void)
{
KTEXT_ST auth; /* Kerberos data */
@@ -389,7 +387,7 @@ try_krb4_authentication(void)
char inst[INST_SZ];
char *realm;
CREDENTIALS cred;
- int r, type, plen;
+ int r, type;
socklen_t slen;
Key_schedule schedule;
u_long checksum, cksum;
@@ -401,19 +399,20 @@ try_krb4_authentication(void)
if (stat(tkt_string(), &st) < 0)
return 0;
- strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ);
+ strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)),
+ INST_SZ);
- realm = (char *) krb_realmofhost(get_canonical_hostname(1));
+ realm = (char *)krb_realmofhost(get_canonical_hostname(1));
if (!realm) {
- debug("Kerberos V4: no realm for %s", get_canonical_hostname(1));
+ debug("Kerberos v4: no realm for %s", get_canonical_hostname(1));
return 0;
}
/* This can really be anything. */
- checksum = (u_long) getpid();
+ checksum = (u_long)getpid();
r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
if (r != KSUCCESS) {
- debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
+ debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]);
return 0;
}
/* Get session key to decrypt the server's reply with. */
@@ -436,35 +435,35 @@ try_krb4_authentication(void)
slen = sizeof(local);
memset(&local, 0, sizeof(local));
if (getsockname(packet_get_connection_in(),
- (struct sockaddr *) & local, &slen) < 0)
+ (struct sockaddr *)&local, &slen) < 0)
debug("getsockname failed: %s", strerror(errno));
slen = sizeof(foreign);
memset(&foreign, 0, sizeof(foreign));
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & foreign, &slen) < 0) {
+ (struct sockaddr *)&foreign, &slen) < 0) {
debug("getpeername failed: %s", strerror(errno));
fatal_cleanup();
}
/* Get server reply. */
- type = packet_read(&plen);
+ type = packet_read();
switch (type) {
case SSH_SMSG_FAILURE:
/* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
- debug("Kerberos V4 authentication failed.");
+ debug("Kerberos v4 authentication failed.");
return 0;
break;
case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
/* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
- debug("Kerberos V4 authentication accepted.");
+ debug("Kerberos v4 authentication accepted.");
/* Get server's response. */
reply = packet_get_string((u_int *) &auth.length);
memcpy(auth.dat, reply, auth.length);
xfree(reply);
- packet_integrity_check(plen, 4 + auth.length, type);
+ packet_check_eom();
/*
* If his response isn't properly encrypted with the session
@@ -472,84 +471,275 @@ try_krb4_authentication(void)
* bogus. Bail out.
*/
r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
- &foreign, &local, &msg_data);
+ &foreign, &local, &msg_data);
if (r != KSUCCESS) {
- debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
- packet_disconnect("Kerberos V4 challenge failed!");
+ debug("Kerberos v4 krb_rd_priv failed: %s",
+ krb_err_txt[r]);
+ packet_disconnect("Kerberos v4 challenge failed!");
}
/* Fetch the (incremented) checksum that we supplied in the request. */
- (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
+ memcpy((char *)&cksum, (char *)msg_data.app_data,
+ sizeof(cksum));
cksum = ntohl(cksum);
/* If it matches, we're golden. */
if (cksum == checksum + 1) {
- debug("Kerberos V4 challenge successful.");
+ debug("Kerberos v4 challenge successful.");
return 1;
} else
- packet_disconnect("Kerberos V4 challenge failed!");
+ packet_disconnect("Kerberos v4 challenge failed!");
break;
default:
- packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
+ packet_disconnect("Protocol error on Kerberos v4 response: %d", type);
}
return 0;
}
#endif /* KRB4 */
+#ifdef KRB5
+static int
+try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context)
+{
+ krb5_error_code problem;
+ const char *tkfile;
+ struct stat buf;
+ krb5_ccache ccache = NULL;
+ const char *remotehost;
+ krb5_data ap;
+ int type;
+ krb5_ap_rep_enc_part *reply = NULL;
+ int ret;
+
+ memset(&ap, 0, sizeof(ap));
+
+ problem = krb5_init_context(context);
+ if (problem) {
+ debug("Kerberos v5: krb5_init_context failed");
+ ret = 0;
+ goto out;
+ }
+
+ tkfile = krb5_cc_default_name(*context);
+ if (strncmp(tkfile, "FILE:", 5) == 0)
+ tkfile += 5;
+
+ if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
+ debug("Kerberos v5: could not get default ccache (permission denied).");
+ ret = 0;
+ goto out;
+ }
+
+ problem = krb5_cc_default(*context, &ccache);
+ if (problem) {
+ debug("Kerberos v5: krb5_cc_default failed: %s",
+ krb5_get_err_text(*context, problem));
+ ret = 0;
+ goto out;
+ }
+
+ remotehost = get_canonical_hostname(1);
+
+ problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED,
+ "host", remotehost, NULL, ccache, &ap);
+ if (problem) {
+ debug("Kerberos v5: krb5_mk_req failed: %s",
+ krb5_get_err_text(*context, problem));
+ ret = 0;
+ goto out;
+ }
+
+ packet_start(SSH_CMSG_AUTH_KERBEROS);
+ packet_put_string((char *) ap.data, ap.length);
+ packet_send();
+ packet_write_wait();
+
+ xfree(ap.data);
+ ap.length = 0;
+
+ type = packet_read();
+ switch (type) {
+ case SSH_SMSG_FAILURE:
+ /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
+ debug("Kerberos v5 authentication failed.");
+ ret = 0;
+ break;
+
+ case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
+ /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
+ debug("Kerberos v5 authentication accepted.");
+
+ /* Get server's response. */
+ ap.data = packet_get_string((unsigned int *) &ap.length);
+ packet_check_eom();
+ /* XXX je to dobre? */
+
+ problem = krb5_rd_rep(*context, *auth_context, &ap, &reply);
+ if (problem) {
+ ret = 0;
+ }
+ ret = 1;
+ break;
+
+ default:
+ packet_disconnect("Protocol error on Kerberos v5 response: %d",
+ type);
+ ret = 0;
+ break;
+
+ }
+
+ out:
+ if (ccache != NULL)
+ krb5_cc_close(*context, ccache);
+ if (reply != NULL)
+ krb5_free_ap_rep_enc_part(*context, reply);
+ if (ap.length > 0)
+ krb5_data_free(&ap);
+
+ return (ret);
+}
+
+static void
+send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
+{
+ int fd, type;
+ krb5_error_code problem;
+ krb5_data outbuf;
+ krb5_ccache ccache = NULL;
+ krb5_creds creds;
+ krb5_kdc_flags flags;
+ const char *remotehost;
+
+ memset(&creds, 0, sizeof(creds));
+ memset(&outbuf, 0, sizeof(outbuf));
+
+ fd = packet_get_connection_in();
+
+ problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd);
+ if (problem)
+ goto out;
+
+ problem = krb5_cc_default(context, &ccache);
+ if (problem)
+ goto out;
+
+ problem = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (problem)
+ goto out;
+
+ problem = krb5_build_principal(context, &creds.server,
+ strlen(creds.client->realm), creds.client->realm,
+ "krbtgt", creds.client->realm, NULL);
+ if (problem)
+ goto out;
+
+ creds.times.endtime = 0;
+
+ flags.i = 0;
+ flags.b.forwarded = 1;
+ flags.b.forwardable = krb5_config_get_bool(context, NULL,
+ "libdefaults", "forwardable", NULL);
+
+ remotehost = get_canonical_hostname(1);
+
+ problem = krb5_get_forwarded_creds(context, auth_context,
+ ccache, flags.i, remotehost, &creds, &outbuf);
+ if (problem)
+ goto out;
+
+ packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+ packet_put_string((char *)outbuf.data, outbuf.length);
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read();
+
+ if (type == SSH_SMSG_SUCCESS) {
+ char *pname;
+
+ krb5_unparse_name(context, creds.client, &pname);
+ debug("Kerberos v5 TGT forwarded (%s).", pname);
+ xfree(pname);
+ } else
+ debug("Kerberos v5 TGT forwarding failed.");
+
+ return;
+
+ out:
+ if (problem)
+ debug("Kerberos v5 TGT forwarding failed: %s",
+ krb5_get_err_text(context, problem));
+ if (creds.client)
+ krb5_free_principal(context, creds.client);
+ if (creds.server)
+ krb5_free_principal(context, creds.server);
+ if (ccache)
+ krb5_cc_close(context, ccache);
+ if (outbuf.data)
+ xfree(outbuf.data);
+}
+#endif /* KRB5 */
+
#ifdef AFS
-int
+static void
send_krb4_tgt(void)
{
CREDENTIALS *creds;
- char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
- int r, type, plen;
- char buffer[8192];
struct stat st;
+ char buffer[4096], pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+ int problem, type;
/* Don't do anything if we don't have any tickets. */
if (stat(tkt_string(), &st) < 0)
- return 0;
+ return;
creds = xmalloc(sizeof(*creds));
- if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
- debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
- return 0;
- }
- if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
- debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
- return 0;
- }
+ problem = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm);
+ if (problem)
+ goto out;
+
+ problem = krb_get_cred("krbtgt", prealm, prealm, creds);
+ if (problem)
+ goto out;
+
if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
- debug("Kerberos V4 ticket expired: %s", TKT_FILE);
- return 0;
+ problem = RD_AP_EXP;
+ goto out;
}
- creds_to_radix(creds, (u_char *)buffer, sizeof buffer);
- xfree(creds);
+ creds_to_radix(creds, (u_char *)buffer, sizeof(buffer));
- packet_start(SSH_CMSG_HAVE_KRB4_TGT);
- packet_put_string(buffer, strlen(buffer));
+ packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+ packet_put_cstring(buffer);
packet_send();
packet_write_wait();
- type = packet_read(&plen);
+ type = packet_read();
- if (type == SSH_SMSG_FAILURE)
- debug("Kerberos TGT for realm %s rejected.", prealm);
- else if (type != SSH_SMSG_SUCCESS)
- packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
+ if (type == SSH_SMSG_SUCCESS)
+ debug("Kerberos v4 TGT forwarded (%s%s%s@%s).",
+ creds->pname, creds->pinst[0] ? "." : "",
+ creds->pinst, creds->realm);
+ else
+ debug("Kerberos v4 TGT rejected.");
+
+ xfree(creds);
+ return;
- return 1;
+ out:
+ debug("Kerberos v4 TGT passing failed: %s", krb_err_txt[problem]);
+ xfree(creds);
}
-void
+static void
send_afs_tokens(void)
{
CREDENTIALS creds;
struct ViceIoctl parms;
struct ClearToken ct;
- int i, type, len, plen;
+ int i, type, len;
char buf[2048], *p, *server_cell;
char buffer[8192];
@@ -582,27 +772,29 @@ send_afs_tokens(void)
server_cell = p;
/* Flesh out our credentials. */
- strlcpy(creds.service, "afs", sizeof creds.service);
+ strlcpy(creds.service, "afs", sizeof(creds.service));
creds.instance[0] = '\0';
strlcpy(creds.realm, server_cell, REALM_SZ);
memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
creds.issue_date = ct.BeginTimestamp;
- creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
+ creds.lifetime = krb_time_to_life(creds.issue_date,
+ ct.EndTimestamp);
creds.kvno = ct.AuthHandle;
snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
creds.pinst[0] = '\0';
/* Encode token, ship it off. */
- if (creds_to_radix(&creds, (u_char *) buffer, sizeof buffer) <= 0)
+ if (creds_to_radix(&creds, (u_char *)buffer,
+ sizeof(buffer)) <= 0)
break;
packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
- packet_put_string(buffer, strlen(buffer));
+ packet_put_cstring(buffer);
packet_send();
packet_write_wait();
/* Roger, Roger. Clearance, Clarence. What's your vector,
Victor? */
- type = packet_read(&plen);
+ type = packet_read();
if (type == SSH_SMSG_FAILURE)
debug("AFS token for cell %s rejected.", server_cell);
@@ -617,38 +809,37 @@ send_afs_tokens(void)
* Tries to authenticate with any string-based challenge/response system.
* Note that the client code is not tied to s/key or TIS.
*/
-int
-try_challenge_reponse_authentication(void)
+static int
+try_challenge_response_authentication(void)
{
int type, i;
- int payload_len;
u_int clen;
char prompt[1024];
char *challenge, *response;
- debug("Doing challenge reponse authentication.");
-
- /* request a challenge */
- packet_start(SSH_CMSG_AUTH_TIS);
- packet_send();
- packet_write_wait();
+ debug("Doing challenge response authentication.");
- type = packet_read(&payload_len);
- if (type != SSH_SMSG_FAILURE &&
- type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
- packet_disconnect("Protocol error: got %d in response "
- "to skey-auth", type);
- }
- if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
- debug("No challenge for skey authentication.");
- return 0;
- }
- challenge = packet_get_string(&clen);
- packet_integrity_check(payload_len, (4 + clen), type);
- snprintf(prompt, sizeof prompt, "%s%s", challenge,
- strchr(challenge, '\n') ? "" : "\nResponse: ");
- xfree(challenge);
for (i = 0; i < options.number_of_password_prompts; i++) {
+ /* request a challenge */
+ packet_start(SSH_CMSG_AUTH_TIS);
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read();
+ if (type != SSH_SMSG_FAILURE &&
+ type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+ packet_disconnect("Protocol error: got %d in response "
+ "to SSH_CMSG_AUTH_TIS", type);
+ }
+ if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+ debug("No challenge.");
+ return 0;
+ }
+ challenge = packet_get_string(&clen);
+ packet_check_eom();
+ snprintf(prompt, sizeof prompt, "%s%s", challenge,
+ strchr(challenge, '\n') ? "" : "\nResponse: ");
+ xfree(challenge);
if (i != 0)
error("Permission denied, please try again.");
if (options.cipher == SSH_CIPHER_NONE)
@@ -665,7 +856,7 @@ try_challenge_reponse_authentication(void)
xfree(response);
packet_send();
packet_write_wait();
- type = packet_read(&payload_len);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS)
return 1;
if (type != SSH_SMSG_FAILURE)
@@ -679,10 +870,10 @@ try_challenge_reponse_authentication(void)
/*
* Tries to authenticate with plain passwd authentication.
*/
-int
+static int
try_password_authentication(char *prompt)
{
- int type, i, payload_len;
+ int type, i;
char *password;
debug("Doing password authentication.");
@@ -699,7 +890,7 @@ try_password_authentication(char *prompt)
packet_send();
packet_write_wait();
- type = packet_read(&payload_len);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS)
return 1;
if (type != SSH_SMSG_FAILURE)
@@ -717,54 +908,43 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
{
int i;
BIGNUM *key;
- RSA *host_key;
- RSA *public_key;
- Key k;
+ Key *host_key, *server_key;
int bits, rbits;
int ssh_cipher_default = SSH_CIPHER_3DES;
u_char session_key[SSH_SESSION_KEY_LENGTH];
u_char cookie[8];
u_int supported_ciphers;
u_int server_flags, client_flags;
- int payload_len, clen, sum_len = 0;
u_int32_t rand = 0;
debug("Waiting for server public key.");
/* Wait for a public key packet from the server. */
- packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
+ packet_read_expect(SSH_SMSG_PUBLIC_KEY);
/* Get cookie from the packet. */
for (i = 0; i < 8; i++)
cookie[i] = packet_get_char();
/* Get the public key. */
- public_key = RSA_new();
- bits = packet_get_int();/* bits */
- public_key->e = BN_new();
- packet_get_bignum(public_key->e, &clen);
- sum_len += clen;
- public_key->n = BN_new();
- packet_get_bignum(public_key->n, &clen);
- sum_len += clen;
-
- rbits = BN_num_bits(public_key->n);
+ server_key = key_new(KEY_RSA1);
+ bits = packet_get_int();
+ packet_get_bignum(server_key->rsa->e);
+ packet_get_bignum(server_key->rsa->n);
+
+ rbits = BN_num_bits(server_key->rsa->n);
if (bits != rbits) {
log("Warning: Server lies about size of server public key: "
"actual size is %d bits vs. announced %d.", rbits, bits);
log("Warning: This may be due to an old implementation of ssh.");
}
/* Get the host key. */
- host_key = RSA_new();
- bits = packet_get_int();/* bits */
- host_key->e = BN_new();
- packet_get_bignum(host_key->e, &clen);
- sum_len += clen;
- host_key->n = BN_new();
- packet_get_bignum(host_key->n, &clen);
- sum_len += clen;
-
- rbits = BN_num_bits(host_key->n);
+ host_key = key_new(KEY_RSA1);
+ bits = packet_get_int();
+ packet_get_bignum(host_key->rsa->e);
+ packet_get_bignum(host_key->rsa->n);
+
+ rbits = BN_num_bits(host_key->rsa->n);
if (bits != rbits) {
log("Warning: Server lies about size of server host key: "
"actual size is %d bits vs. announced %d.", rbits, bits);
@@ -777,21 +957,17 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
supported_ciphers = packet_get_int();
supported_authentications = packet_get_int();
+ packet_check_eom();
debug("Received server public key (%d bits) and host key (%d bits).",
- BN_num_bits(public_key->n), BN_num_bits(host_key->n));
+ BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n));
- packet_integrity_check(payload_len,
- 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
- SSH_SMSG_PUBLIC_KEY);
- k.type = KEY_RSA1;
- k.rsa = host_key;
- check_host_key(host, hostaddr, &k,
- options.user_hostfile, options.system_hostfile);
+ if (verify_host_key(host, hostaddr, host_key) == -1)
+ fatal("Host key verification failed.");
client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
- compute_session_id(session_id, cookie, host_key->n, public_key->n);
+ compute_session_id(session_id, cookie, host_key->rsa->n, server_key->rsa->n);
/* Generate a session key. */
arc4random_stir();
@@ -813,7 +989,8 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
* is the highest byte of the integer. The session key is xored with
* the first 16 bytes of the session id.
*/
- key = BN_new();
+ if ((key = BN_new()) == NULL)
+ fatal("respond_to_rsa_challenge: BN_new failed");
BN_set_word(key, 0);
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
BN_lshift(key, key, 8);
@@ -827,35 +1004,35 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
* 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(server_key->rsa->n, host_key->rsa->n) < 0) {
/* Public key has smaller modulus. */
- if (BN_num_bits(host_key->n) <
- BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
- "SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(host_key->n),
- BN_num_bits(public_key->n),
- SSH_KEY_BITS_RESERVED);
+ if (BN_num_bits(host_key->rsa->n) <
+ BN_num_bits(server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("respond_to_rsa_challenge: host_key %d < server_key %d + "
+ "SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(host_key->rsa->n),
+ BN_num_bits(server_key->rsa->n),
+ SSH_KEY_BITS_RESERVED);
}
- rsa_public_encrypt(key, key, public_key);
- rsa_public_encrypt(key, key, host_key);
+ rsa_public_encrypt(key, key, server_key->rsa);
+ rsa_public_encrypt(key, key, host_key->rsa);
} else {
/* Host key has smaller modulus (or they are equal). */
- if (BN_num_bits(public_key->n) <
- BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
- "SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(public_key->n),
- BN_num_bits(host_key->n),
- SSH_KEY_BITS_RESERVED);
+ if (BN_num_bits(server_key->rsa->n) <
+ BN_num_bits(host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("respond_to_rsa_challenge: server_key %d < host_key %d + "
+ "SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(server_key->rsa->n),
+ BN_num_bits(host_key->rsa->n),
+ SSH_KEY_BITS_RESERVED);
}
- rsa_public_encrypt(key, key, host_key);
- rsa_public_encrypt(key, key, public_key);
+ rsa_public_encrypt(key, key, host_key->rsa);
+ rsa_public_encrypt(key, key, server_key->rsa);
}
/* Destroy the public keys since we no longer need them. */
- RSA_free(public_key);
- RSA_free(host_key);
+ key_free(server_key);
+ key_free(host_key);
if (options.cipher == SSH_CIPHER_NOT_SET) {
if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
@@ -869,7 +1046,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
/* Check that the selected cipher is supported. */
if (!(supported_ciphers & (1 << options.cipher)))
fatal("Selected cipher type %.100s not supported by server.",
- cipher_name(options.cipher));
+ cipher_name(options.cipher));
debug("Encryption type: %.100s", cipher_name(options.cipher));
@@ -904,7 +1081,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
* 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(SSH_SMSG_SUCCESS);
debug("Received encrypted confirmation.");
}
@@ -916,15 +1093,18 @@ void
ssh_userauth1(const char *local_user, const char *server_user, char *host,
Key **keys, int nkeys)
{
+#ifdef KRB5
+ krb5_context context = NULL;
+ krb5_auth_context auth_context = NULL;
+#endif
int i, type;
- int payload_len;
if (supported_authentications == 0)
fatal("ssh_userauth1: server supports no auth methods");
/* Send the name of the user to log in as on the server. */
packet_start(SSH_CMSG_USER);
- packet_put_string(server_user, strlen(server_user));
+ packet_put_cstring(server_user);
packet_send();
packet_write_wait();
@@ -933,77 +1113,44 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host,
* needed (the user has no password). Otherwise the server responds
* with failure.
*/
- type = packet_read(&payload_len);
+ type = packet_read();
/* check whether the connection was accepted without authentication. */
if (type == SSH_SMSG_SUCCESS)
- return;
+ goto success;
if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
- type);
+ packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type);
#ifdef KRB5
if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
- options.kerberos_authentication){
- krb5_context ssh_context = NULL;
- krb5_auth_context auth_context = NULL;
-
- debug("Trying Kerberos V5 authentication.");
-
- if (try_krb5_authentication(&ssh_context, &auth_context)) {
- type = packet_read(&payload_len);
- if (type == SSH_SMSG_SUCCESS) {
- if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
- options.krb5_tgt_passing) {
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
- send_krb5_tgt(ssh_context, auth_context);
-
- }
- krb5_auth_con_free(ssh_context, auth_context);
- krb5_free_context(ssh_context);
- return;
- }
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to Kerberos5 auth", type);
+ options.kerberos_authentication) {
+ debug("Trying Kerberos v5 authentication.");
+ if (try_krb5_authentication(&context, &auth_context)) {
+ type = packet_read();
+ if (type == SSH_SMSG_SUCCESS)
+ goto success;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response to Kerberos v5 auth", type);
+ }
}
- }
#endif /* KRB5 */
-#ifdef AFS
- /* Try Kerberos tgt passing if the server supports it. */
- if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
- options.krb4_tgt_passing) {
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
- (void) send_krb4_tgt();
- }
- /* Try AFS token passing if the server supports it. */
- if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
- options.afs_token_passing && k_hasafs()) {
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
- send_afs_tokens();
- }
-#endif /* AFS */
-
#ifdef KRB4
if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
options.kerberos_authentication) {
- debug("Trying Kerberos authentication.");
+ debug("Trying Kerberos v4 authentication.");
+
if (try_krb4_authentication()) {
- /* The server should respond with success or failure. */
- type = packet_read(&payload_len);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS)
- return;
+ goto success;
if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
+ packet_disconnect("Protocol error: got %d in response to Kerberos v4 auth", type);
}
}
#endif /* KRB4 */
-
/*
* Use rhosts authentication if running in privileged socket and we
* do not wish to remain anonymous.
@@ -1012,14 +1159,14 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host,
options.rhosts_authentication) {
debug("Trying rhosts authentication.");
packet_start(SSH_CMSG_AUTH_RHOSTS);
- packet_put_string(local_user, strlen(local_user));
+ packet_put_cstring(local_user);
packet_send();
packet_write_wait();
/* The server should respond with success or failure. */
- type = packet_read(&payload_len);
+ type = packet_read();
if (type == SSH_SMSG_SUCCESS)
- return;
+ goto success;
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error: got %d in response to rhosts auth",
type);
@@ -1033,7 +1180,7 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host,
for (i = 0; i < nkeys; i++) {
if (keys[i] != NULL && keys[i]->type == KEY_RSA1 &&
try_rhosts_rsa_authentication(local_user, keys[i]))
- return;
+ goto success;
}
}
/* Try RSA authentication if the server supports it. */
@@ -1045,20 +1192,20 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host,
* it, whereas identity files may require passphrases.
*/
if (try_agent_authentication())
- return;
+ goto success;
/* Try RSA authentication for each identity. */
for (i = 0; i < options.num_identity_files; i++)
if (options.identity_keys[i] != NULL &&
options.identity_keys[i]->type == KEY_RSA1 &&
- try_rsa_authentication(options.identity_files[i]))
- return;
+ try_rsa_authentication(i))
+ goto success;
}
/* Try challenge response authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
- options.challenge_reponse_authentication && !options.batch_mode) {
- if (try_challenge_reponse_authentication())
- return;
+ options.challenge_response_authentication && !options.batch_mode) {
+ if (try_challenge_response_authentication())
+ goto success;
}
/* Try password authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
@@ -1068,9 +1215,43 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host,
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
server_user, host);
if (try_password_authentication(prompt))
- return;
+ goto success;
}
/* All authentication methods have failed. Exit with an error message. */
fatal("Permission denied.");
/* NOTREACHED */
+
+ success:
+#ifdef KRB5
+ /* Try Kerberos v5 TGT passing. */
+ if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+ options.kerberos_tgt_passing && context && auth_context) {
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+ send_krb5_tgt(context, auth_context);
+ }
+ if (auth_context)
+ krb5_auth_con_free(context, auth_context);
+ if (context)
+ krb5_free_context(context);
+#endif
+
+#ifdef AFS
+ /* Try Kerberos v4 TGT passing if the server supports it. */
+ if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+ options.kerberos_tgt_passing) {
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+ send_krb4_tgt();
+ }
+ /* Try AFS token passing if the server supports it. */
+ if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+ options.afs_token_passing && k_hasafs()) {
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+ send_afs_tokens();
+ }
+#endif /* AFS */
+
+ return; /* need statement after label */
}
diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c
index 4f76bd0..89faec6 100644
--- a/crypto/openssh/sshconnect2.c
+++ b/crypto/openssh/sshconnect2.c
@@ -23,30 +23,21 @@
*/
#include "includes.h"
+RCSID("$OpenBSD: sshconnect2.c,v 1.97 2002/02/25 16:33:27 markus Exp $");
RCSID("$FreeBSD$");
-RCSID("$OpenBSD: sshconnect2.c,v 1.72 2001/04/18 23:43:26 markus Exp $");
-
-#include <openssl/bn.h>
-#include <openssl/md5.h>
-#include <openssl/dh.h>
-#include <openssl/hmac.h>
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
-#include "rsa.h"
#include "buffer.h"
#include "packet.h"
-#include "uidswap.h"
#include "compat.h"
#include "bufaux.h"
#include "cipher.h"
#include "kex.h"
#include "myproposal.h"
-#include "key.h"
#include "sshconnect.h"
#include "authfile.h"
-#include "cli.h"
#include "dh.h"
#include "authfd.h"
#include "log.h"
@@ -73,11 +64,11 @@ struct sockaddr *xxx_hostaddr;
Kex *xxx_kex = NULL;
-int
-check_host_key_callback(Key *hostkey)
+static int
+verify_host_key_callback(Key *hostkey)
{
- check_host_key(xxx_host, xxx_hostaddr, hostkey,
- options.user_hostfile2, options.system_hostfile2);
+ if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
+ fatal("Host key verification failed.");
return 0;
}
@@ -113,14 +104,14 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
}
if (options.hostkeyalgorithms != NULL)
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
options.hostkeyalgorithms;
/* start key exchange */
kex = kex_setup(myproposal);
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
- kex->check_host_key=&check_host_key_callback;
+ kex->verify_host_key=&verify_host_key_callback;
xxx_kex = kex;
@@ -148,7 +139,7 @@ typedef struct Authmethod Authmethod;
typedef int sign_cb_fn(
Authctxt *authctxt, Key *key,
- u_char **sigp, int *lenp, u_char *data, int datalen);
+ u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
struct Authctxt {
const char *server_user;
@@ -166,6 +157,8 @@ struct Authctxt {
/* hostbased */
Key **keys;
int nkeys;
+ /* kbd-interactive */
+ int info_req_seen;
};
struct Authmethod {
char *name; /* string to compare against server's list */
@@ -174,47 +167,45 @@ struct Authmethod {
int *batch_flag; /* flag in option struct that disables method */
};
-void input_userauth_success(int type, int plen, void *ctxt);
-void input_userauth_failure(int type, int plen, void *ctxt);
-void input_userauth_banner(int type, int plen, void *ctxt);
-void input_userauth_error(int type, int plen, void *ctxt);
-void input_userauth_info_req(int type, int plen, void *ctxt);
-void input_userauth_pk_ok(int type, int plen, void *ctxt);
+void input_userauth_success(int, u_int32_t, void *);
+void input_userauth_failure(int, u_int32_t, void *);
+void input_userauth_banner(int, u_int32_t, void *);
+void input_userauth_error(int, u_int32_t, void *);
+void input_userauth_info_req(int, u_int32_t, void *);
+void input_userauth_pk_ok(int, u_int32_t, void *);
-int userauth_none(Authctxt *authctxt);
-int userauth_pubkey(Authctxt *authctxt);
-int userauth_passwd(Authctxt *authctxt);
-int userauth_kbdint(Authctxt *authctxt);
-int userauth_hostbased(Authctxt *authctxt);
+int userauth_none(Authctxt *);
+int userauth_pubkey(Authctxt *);
+int userauth_passwd(Authctxt *);
+int userauth_kbdint(Authctxt *);
+int userauth_hostbased(Authctxt *);
-void userauth(Authctxt *authctxt, char *authlist);
+void userauth(Authctxt *, char *);
-int
-sign_and_send_pubkey(Authctxt *authctxt, Key *k,
- sign_cb_fn *sign_callback);
-void clear_auth_state(Authctxt *authctxt);
+static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
+static void clear_auth_state(Authctxt *);
-Authmethod *authmethod_get(char *authlist);
-Authmethod *authmethod_lookup(const char *name);
-char *authmethods_get(void);
+static Authmethod *authmethod_get(char *authlist);
+static Authmethod *authmethod_lookup(const char *name);
+static char *authmethods_get(void);
Authmethod authmethods[] = {
+ {"hostbased",
+ userauth_hostbased,
+ &options.hostbased_authentication,
+ NULL},
{"publickey",
userauth_pubkey,
&options.pubkey_authentication,
NULL},
- {"password",
- userauth_passwd,
- &options.password_authentication,
- &options.batch_mode},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication,
&options.batch_mode},
- {"hostbased",
- userauth_hostbased,
- &options.hostbased_authentication,
- NULL},
+ {"password",
+ userauth_passwd,
+ &options.password_authentication,
+ &options.batch_mode},
{"none",
userauth_none,
NULL,
@@ -228,9 +219,8 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
{
Authctxt authctxt;
int type;
- int plen;
- if (options.challenge_reponse_authentication)
+ if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
debug("send SSH2_MSG_SERVICE_REQUEST");
@@ -238,24 +228,25 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
packet_put_cstring("ssh-userauth");
packet_send();
packet_write_wait();
- type = packet_read(&plen);
+ type = packet_read();
if (type != SSH2_MSG_SERVICE_ACCEPT) {
fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
}
if (packet_remaining() > 0) {
- char *reply = packet_get_string(&plen);
+ char *reply = packet_get_string(NULL);
debug("service_accept: %s", reply);
xfree(reply);
} else {
debug("buggy server: service_accept w/o service");
}
- packet_done();
+ packet_check_eom();
debug("got SSH2_MSG_SERVICE_ACCEPT");
if (options.preferred_authentications == NULL)
options.preferred_authentications = authmethods_get();
/* setup authentication context */
+ memset(&authctxt, 0, sizeof(authctxt));
authctxt.agent = ssh_get_authentication_connection();
authctxt.server_user = server_user;
authctxt.local_user = local_user;
@@ -266,6 +257,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
authctxt.authlist = NULL;
authctxt.keys = keys;
authctxt.nkeys = nkeys;
+ authctxt.info_req_seen = 0;
if (authctxt.method == NULL)
fatal("ssh_userauth2: internal error: cannot send userauth none request");
@@ -308,13 +300,13 @@ userauth(Authctxt *authctxt, char *authlist)
}
}
void
-input_userauth_error(int type, int plen, void *ctxt)
+input_userauth_error(int type, u_int32_t seq, void *ctxt)
{
fatal("input_userauth_error: bad message during authentication: "
"type %d", type);
}
void
-input_userauth_banner(int type, int plen, void *ctxt)
+input_userauth_banner(int type, u_int32_t seq, void *ctxt)
{
char *msg, *lang;
debug3("input_userauth_banner");
@@ -325,7 +317,7 @@ input_userauth_banner(int type, int plen, void *ctxt)
xfree(lang);
}
void
-input_userauth_success(int type, int plen, void *ctxt)
+input_userauth_success(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
if (authctxt == NULL)
@@ -336,7 +328,7 @@ input_userauth_success(int type, int plen, void *ctxt)
authctxt->success = 1; /* break out */
}
void
-input_userauth_failure(int type, int plen, void *ctxt)
+input_userauth_failure(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
char *authlist = NULL;
@@ -347,7 +339,7 @@ input_userauth_failure(int type, int plen, void *ctxt)
authlist = packet_get_string(NULL);
partial = packet_get_char();
- packet_done();
+ packet_check_eom();
if (partial != 0)
log("Authenticated with partial success.");
@@ -357,13 +349,15 @@ input_userauth_failure(int type, int plen, void *ctxt)
userauth(authctxt, authlist);
}
void
-input_userauth_pk_ok(int type, int plen, void *ctxt)
+input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
Key *key = NULL;
Buffer b;
- int alen, blen, sent = 0;
- char *pkalg, *pkblob, *fp;
+ int pktype, sent = 0;
+ u_int alen, blen;
+ char *pkalg, *fp;
+ u_char *pkblob;
if (authctxt == NULL)
fatal("input_userauth_pk_ok: no authentication context");
@@ -379,7 +373,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
}
- packet_done();
+ packet_check_eom();
debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
@@ -390,7 +384,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
debug("no last key or no sign cb");
break;
}
- if (key_type_from_name(pkalg) == KEY_UNSPEC) {
+ if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
debug("unknown pkalg %s", pkalg);
break;
}
@@ -398,6 +392,12 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
debug("no key from blob. pkalg %s", pkalg);
break;
}
+ if (key->type != pktype) {
+ error("input_userauth_pk_ok: type mismatch "
+ "for decoded key (received %d, expected %d)",
+ key->type, pktype);
+ break;
+ }
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
debug2("input_userauth_pk_ok: fp %s", fp);
xfree(fp);
@@ -407,7 +407,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
}
sent = sign_and_send_pubkey(authctxt, key,
authctxt->last_key_sign);
- } while(0);
+ } while (0);
if (key != NULL)
key_free(key);
@@ -446,7 +446,7 @@ userauth_passwd(Authctxt *authctxt)
if (attempt++ >= options.number_of_password_prompts)
return 0;
- if(attempt != 1)
+ if (attempt != 1)
error("Permission denied, please try again.");
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
@@ -460,12 +460,12 @@ userauth_passwd(Authctxt *authctxt)
ssh_put_password(password);
memset(password, 0, strlen(password));
xfree(password);
- packet_inject_ignore(64);
+ packet_add_padding(64);
packet_send();
return 1;
}
-void
+static void
clear_auth_state(Authctxt *authctxt)
{
/* XXX clear authentication state */
@@ -478,12 +478,12 @@ clear_auth_state(Authctxt *authctxt)
authctxt->last_key_sign = NULL;
}
-int
+static int
sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
{
Buffer b;
u_char *blob, *signature;
- int bloblen, slen;
+ u_int bloblen, slen;
int skip = 0;
int ret = -1;
int have_sig = 1;
@@ -563,12 +563,12 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
return 1;
}
-int
+static int
send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
int hint)
{
u_char *blob;
- int bloblen, have_sig = 0;
+ u_int bloblen, have_sig = 0;
debug3("send_pubkey_test");
@@ -596,7 +596,7 @@ send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
return 1;
}
-Key *
+static Key *
load_identity_file(char *filename)
{
Key *private;
@@ -613,7 +613,7 @@ load_identity_file(char *filename)
if (options.batch_mode)
return NULL;
snprintf(prompt, sizeof prompt,
- "Enter passphrase for key '%.100s': ", filename);
+ "Enter passphrase for key '%.100s': ", filename);
for (i = 0; i < options.number_of_password_prompts; i++) {
passphrase = read_passphrase(prompt, 0);
if (strcmp(passphrase, "") != 0) {
@@ -634,9 +634,9 @@ load_identity_file(char *filename)
return private;
}
-int
-identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
- u_char *data, int datalen)
+static int
+identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
+ u_char *data, u_int datalen)
{
Key *private;
int idx, ret;
@@ -644,6 +644,11 @@ identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
idx = authctxt->last_key_hint;
if (idx < 0)
return -1;
+
+ /* private key is stored in external hardware */
+ if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
+ return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
+
private = load_identity_file(options.identity_files[idx]);
if (private == NULL)
return -1;
@@ -652,19 +657,21 @@ identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
return ret;
}
-int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
- u_char *data, int datalen)
+static int
+agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
+ u_char *data, u_int datalen)
{
return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
}
-int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
- u_char *data, int datalen)
+static int
+key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
+ u_char *data, u_int datalen)
{
return key_sign(key, sigp, lenp, data, datalen);
}
-int
+static int
userauth_pubkey_agent(Authctxt *authctxt)
{
static int called = 0;
@@ -703,7 +710,7 @@ userauth_pubkey(Authctxt *authctxt)
if (authctxt->agent != NULL) {
do {
sent = userauth_pubkey_agent(authctxt);
- } while(!sent && authctxt->agent->howmany > 0);
+ } while (!sent && authctxt->agent->howmany > 0);
}
while (!sent && idx < options.num_identity_files) {
key = options.identity_keys[idx];
@@ -736,6 +743,12 @@ userauth_kbdint(Authctxt *authctxt)
if (attempt++ >= options.number_of_password_prompts)
return 0;
+ /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
+ if (attempt > 1 && !authctxt->info_req_seen) {
+ debug3("userauth_kbdint: disable: no info_req_seen");
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
+ return 0;
+ }
debug2("userauth_kbdint");
packet_start(SSH2_MSG_USERAUTH_REQUEST);
@@ -755,7 +768,7 @@ userauth_kbdint(Authctxt *authctxt)
* parse INFO_REQUEST, prompt user and send INFO_RESPONSE
*/
void
-input_userauth_info_req(int type, int plen, void *ctxt)
+input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
char *name, *inst, *lang, *prompt, *response;
@@ -767,13 +780,15 @@ input_userauth_info_req(int type, int plen, void *ctxt)
if (authctxt == NULL)
fatal("input_userauth_info_req: no authentication context");
+ authctxt->info_req_seen = 1;
+
name = packet_get_string(NULL);
inst = packet_get_string(NULL);
lang = packet_get_string(NULL);
if (strlen(name) > 0)
- cli_mesg(name);
+ log("%s", name);
if (strlen(inst) > 0)
- cli_mesg(inst);
+ log("%s", inst);
xfree(name);
xfree(inst);
xfree(lang);
@@ -788,20 +803,21 @@ input_userauth_info_req(int type, int plen, void *ctxt)
packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
packet_put_int(num_prompts);
+ debug2("input_userauth_info_req: num_prompts %d", num_prompts);
for (i = 0; i < num_prompts; i++) {
prompt = packet_get_string(NULL);
echo = packet_get_char();
- response = cli_prompt(prompt, echo);
+ response = read_passphrase(prompt, echo ? RP_ECHO : 0);
ssh_put_password(response);
memset(response, 0, strlen(response));
xfree(response);
xfree(prompt);
}
- packet_done(); /* done with parsing incoming message. */
+ packet_check_eom(); /* done with parsing incoming message. */
- packet_inject_ignore(64);
+ packet_add_padding(64);
packet_send();
}
@@ -820,16 +836,6 @@ userauth_hostbased(Authctxt *authctxt)
u_int blen, slen;
int ok, i, len, found = 0;
- p = get_local_name(packet_get_connection_in());
- if (p == NULL) {
- error("userauth_hostbased: cannot get local ipaddr/name");
- return 0;
- }
- len = strlen(p) + 2;
- chost = xmalloc(len);
- strlcpy(chost, p, len);
- strlcat(chost, ".", len);
- debug2("userauth_hostbased: chost %s", chost);
/* check for a useful key */
for (i = 0; i < authctxt->nkeys; i++) {
private = authctxt->keys[i];
@@ -841,14 +847,26 @@ userauth_hostbased(Authctxt *authctxt)
}
}
if (!found) {
- xfree(chost);
+ debug("userauth_hostbased: no more client hostkeys");
return 0;
}
if (key_to_blob(private, &blob, &blen) == 0) {
key_free(private);
- xfree(chost);
return 0;
}
+ /* figure out a name for the client host */
+ p = get_local_name(packet_get_connection_in());
+ if (p == NULL) {
+ error("userauth_hostbased: cannot get local ipaddr/name");
+ key_free(private);
+ return 0;
+ }
+ len = strlen(p) + 2;
+ chost = xmalloc(len);
+ strlcpy(chost, p, len);
+ strlcat(chost, ".", len);
+ debug2("userauth_hostbased: chost %s", chost);
+
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
authctxt->service;
pkalg = xstrdup(key_ssh_name(private));
@@ -866,7 +884,6 @@ userauth_hostbased(Authctxt *authctxt)
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
- debug2("xxx: chost %s", chost);
ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
key_free(private);
buffer_free(&b);
@@ -900,7 +917,7 @@ userauth_hostbased(Authctxt *authctxt)
* given auth method name, if configurable options permit this method fill
* in auth_ident field and return true, otherwise return false.
*/
-int
+static int
authmethod_is_enabled(Authmethod *method)
{
if (method == NULL)
@@ -914,7 +931,7 @@ authmethod_is_enabled(Authmethod *method)
return 1;
}
-Authmethod *
+static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
@@ -935,12 +952,12 @@ static char *preferred = NULL;
* next method we should try. If the server initially sends a nil list,
* use a built-in default list.
*/
-Authmethod *
+static Authmethod *
authmethod_get(char *authlist)
{
char *name = NULL;
- int next;
+ u_int next;
/* Use a suitable default if we're passed a nil list. */
if (authlist == NULL || strlen(authlist) == 0)
@@ -975,21 +992,23 @@ authmethod_get(char *authlist)
}
}
-
-#define DELIM ","
-char *
+static char *
authmethods_get(void)
{
Authmethod *method = NULL;
- char buf[1024];
+ Buffer b;
+ char *list;
- buf[0] = '\0';
+ buffer_init(&b);
for (method = authmethods; method->name != NULL; method++) {
if (authmethod_is_enabled(method)) {
- if (buf[0] != '\0')
- strlcat(buf, DELIM, sizeof buf);
- strlcat(buf, method->name, sizeof buf);
+ if (buffer_len(&b) > 0)
+ buffer_append(&b, ",", 1);
+ buffer_append(&b, method->name, strlen(method->name));
}
}
- return xstrdup(buf);
+ buffer_append(&b, "\0", 1);
+ list = xstrdup(buffer_ptr(&b));
+ buffer_free(&b);
+ return list;
}
diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8
index 0292473..0e85466 100644
--- a/crypto/openssh/sshd.8
+++ b/crypto/openssh/sshd.8
@@ -34,10 +34,9 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: sshd.8,v 1.120 2001/04/22 23:58:36 markus Exp $
+.\" $OpenBSD: sshd.8,v 1.170 2002/02/28 20:46:10 stevesk Exp $
.\" $FreeBSD$
-.\"
-.Dd September 25, 1999
+.Dd March 18, 2002
.Dt SSHD 8
.Os
.Sh NAME
@@ -45,15 +44,15 @@
.Nd OpenSSH SSH daemon
.Sh SYNOPSIS
.Nm sshd
-.Op Fl deiqD46
+.Op Fl deiqtD46
.Op Fl b Ar bits
.Op Fl f Ar config_file
.Op Fl g Ar login_grace_time
.Op Fl h Ar host_key_file
.Op Fl k Ar key_gen_time
+.Op Fl o Ar option
.Op Fl p Ar port
.Op Fl u Ar len
-.Op Fl V Ar client_protocol_id
.Sh DESCRIPTION
.Nm
(SSH Daemon) is the daemon program for
@@ -66,7 +65,7 @@ install and use as possible.
.Pp
.Nm
is the daemon that listens for connections from clients.
-It is normally started at boot from
+It is normally started at boot from
.Pa /etc/rc.network .
It forks a new
daemon for each incoming connection.
@@ -120,9 +119,8 @@ configuration file if desired.
System security is not improved unless
.Xr rshd 8 ,
.Xr rlogind 8 ,
-.Xr rexecd 8 ,
and
-.Xr rexd 8
+.Xr rexecd 8
are disabled (thus completely disabling
.Xr rlogin 1
and
@@ -132,7 +130,7 @@ into the machine).
.Ss SSH protocol version 2
.Pp
Version 2 works similarly:
-Each host has a host-specific DSA key used to identify the host.
+Each host has a host-specific key (RSA or DSA) used to identify the host.
However, when the daemon starts, it does not generate a server key.
Forward security is provided through a Diffie-Hellman key agreement.
This key agreement results in a shared session key.
@@ -178,7 +176,7 @@ configuration file.
.Nm
rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP ,
-by executing itself with the name it was started as, ie.
+by executing itself with the name it was started as, i.e.,
.Pa /usr/sbin/sshd .
.Pp
The options are as follows:
@@ -186,7 +184,6 @@ The options are as follows:
.It Fl b Ar bits
Specifies the number of bits in the ephemeral protocol version 1
server key (default 768).
-.Pp
.It Fl d
Debug mode.
The server sends verbose debug output to the system
@@ -212,12 +209,18 @@ If the client fails to authenticate the user within
this many seconds, the server disconnects and exits.
A value of zero indicates no limit.
.It Fl h Ar host_key_file
-Specifies the file from which the host key is read (default
-.Pa /etc/ssh/ssh_host_key ) .
+Specifies a file from which a host key is read.
This option must be given if
.Nm
is not run as root (as the normal
-host file is normally not readable by anyone but root).
+host key files are normally not readable by anyone but root).
+The default is
+.Pa /etc/ssh/ssh_host_key
+for protocol version 1, and
+.Pa /etc/ssh/ssh_host_rsa_key
+and
+.Pa /etc/ssh/ssh_host_dsa_key
+for protocol version 2.
It is possible to have multiple host key files for
the different protocol versions and host key algorithms.
.It Fl i
@@ -242,14 +245,27 @@ it becomes impossible to recover the key for decrypting intercepted
communications even if the machine is cracked into or physically
seized.
A value of zero indicates that the key will never be regenerated.
+.It Fl o Ar option
+Can be used to give options in the format used in the configuration file.
+This is useful for specifying options for which there is no separate
+command-line flag.
.It Fl p Ar port
Specifies the port on which the server listens for connections
(default 22).
+Multiple port options are permitted.
+Ports specified in the configuration file are ignored when a
+command-line port is specified.
.It Fl q
Quiet mode.
Nothing is sent to the system log.
Normally the beginning,
authentication, and termination of each connection is logged.
+.It Fl t
+Test mode.
+Only check the validity of the configuration file and sanity of the keys.
+This is useful for updating
+.Nm
+reliably as configuration options may change.
.It Fl u Ar len
This option is used to specify the size of the field
in the
@@ -266,6 +282,23 @@ indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
+.Fl u0
+is also be used to prevent
+.Nm
+from making DNS requests unless the authentication
+mechanism or configuration requires it.
+Authentication mechanisms that may require DNS include
+.Cm RhostsAuthentication ,
+.Cm RhostsRSAAuthentication ,
+.Cm HostbasedAuthentication
+and using a
+.Cm from="pattern-list"
+option in a key file.
+Configuration options that require DNS include using a
+USER@HOST pattern in
+.Cm AllowUsers
+or
+.Cm DenyUsers .
.It Fl D
When this option is specified
.Nm
@@ -288,19 +321,21 @@ reads configuration data from
(or the file specified with
.Fl f
on the command line).
-The file contains keyword-value pairs, one per line.
+The file contains keyword-argument pairs, one per line.
Lines starting with
.Ql #
and empty lines are interpreted as comments.
.Pp
-The following keywords are possible.
+The possible
+keywords and their meanings are as follows (note that
+keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm AFSTokenPassing
Specifies whether an AFS token may be forwarded to the server.
Default is
.Dq yes .
.It Cm AllowGroups
-This keyword can be followed by a list of group names, separated
+This keyword can be followed by a list of group name patterns, separated
by spaces.
If specified, login is allowed only for users whose primary
group or supplementary group list matches one of the patterns.
@@ -309,8 +344,8 @@ and
.Ql ?
can be used as
wildcards in the patterns.
-Only group names are valid; a numerical group ID isn't recognized.
-By default login is allowed regardless of the group list.
+Only group names are valid; a numerical group ID is not recognized.
+By default, login is allowed for all groups.
.Pp
.It Cm AllowTcpForwarding
Specifies whether TCP forwarding is permitted.
@@ -321,7 +356,7 @@ users are also denied shell access, as they can always install their
own forwarders.
.Pp
.It Cm AllowUsers
-This keyword can be followed by a list of user names, separated
+This keyword can be followed by a list of user name patterns, separated
by spaces.
If specified, login is allowed only for users names that
match one of the patterns.
@@ -330,9 +365,26 @@ and
.Ql ?
can be used as
wildcards in the patterns.
-Only user names are valid; a numerical user ID isn't recognized.
-By default login is allowed regardless of the user name.
+Only user names are valid; a numerical user ID is not recognized.
+By default, login is allowed for all users.
+If the pattern takes the form USER@HOST then USER and HOST
+are separately checked, restricting logins to particular
+users from particular hosts.
.Pp
+.It Cm AuthorizedKeysFile
+Specifies the file that contains the public keys that can be used
+for user authentication.
+.Cm AuthorizedKeysFile
+may contain tokens of the form %T which are substituted during connection
+set-up. The following tokens are defined: %% is replaced by a literal '%',
+%h is replaced by the home directory of the user being authenticated and
+%u is replaced by the username of that user.
+After expansion,
+.Cm AuthorizedKeysFile
+is taken to be an absolute path or one relative to the user's home
+directory.
+The default is
+.Dq .ssh/authorized_keys .
.It Cm Banner
In some jurisdictions, sending a warning message before authentication
may be relevant for getting legal protection.
@@ -341,28 +393,33 @@ authentication is allowed.
This option is only available for protocol version 2.
.Pp
.It Cm ChallengeResponseAuthentication
-Specifies whether
-challenge response
-authentication is allowed.
-Currently there is only support for
-.Xr skey 1
-authentication.
+Specifies whether challenge response authentication is allowed.
+All authentication styles from
+.Xr login.conf 5
+are supported.
The default is
.Dq yes .
+Note that OPIE authentication is enabled only if
+.Cm PasswordAuthentication
+is allowed, too.
.It Cm Ciphers
Specifies the ciphers allowed for protocol version 2.
Multiple ciphers must be comma-separated.
The default is
-.Dq aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour.
+.Pp
+.Bd -literal
+ ``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
+ aes192-cbc,aes256-cbc''
+.Ed
.It Cm CheckMail
Specifies whether
.Nm
-should check for new mail for interactive logins.
+should notify the user of new mail for interactive logins.
The default is
.Dq yes .
.It Cm ClientAliveInterval
Sets a timeout interval in seconds after which if no data has been received
-from the client,
+from the client,
.Nm
will send a message through the encrypted
channel to request a response from the client.
@@ -374,49 +431,62 @@ Sets the number of client alive messages (see above) which may be
sent without
.Nm
receiving any messages back from the client. If this threshold is
-reached while client alive messages are being sent,
+reached while client alive messages are being sent,
.Nm
will disconnect the client, terminating the session. It is important
-to note that the use of client alive messages is very different from
-.Cm Keepalive
+to note that the use of client alive messages is very different from
+.Cm KeepAlive
(below). The client alive messages are sent through the
encrypted channel and therefore will not be spoofable. The TCP keepalive
option enabled by
-.Cm Keepalive
-is spoofable. You want to use the client
-alive mechanism when you are basing something important on
-clients having an active connection to the server.
+.Cm KeepAlive
+is spoofable. The client alive mechanism is valuable when the client or
+server depend on knowing when a connection has become inactive.
.Pp
-The default value is 3. If you set
+The default value is 3. If
.Cm ClientAliveInterval
-(above) to 15, and leave this value at the default, unresponsive ssh clients
-will be disconnected after approximately 45 seconds.
+(above) is set to 15, and
+.Cm ClientAliveCountMax
+is left at the default, unresponsive ssh clients
+will be disconnected after approximately 45 seconds.
.It Cm DenyGroups
-This keyword can be followed by a number of group names, separated
+This keyword can be followed by a list of group name patterns, separated
by spaces.
-Users whose primary group or supplementary group list matches
-one of the patterns aren't allowed to log in.
+Login is disallowed for users whose primary group or supplementary
+group list matches one of the patterns.
.Ql \&*
and
.Ql ?
can be used as
wildcards in the patterns.
-Only group names are valid; a numerical group ID isn't recognized.
-By default login is allowed regardless of the group list.
+Only group names are valid; a numerical group ID is not recognized.
+By default, login is allowed for all groups.
.Pp
.It Cm DenyUsers
-This keyword can be followed by a number of user names, separated
+This keyword can be followed by a list of user name patterns, separated
by spaces.
Login is disallowed for user names that match one of the patterns.
.Ql \&*
and
.Ql ?
can be used as wildcards in the patterns.
-Only user names are valid; a numerical user ID isn't recognized.
-By default login is allowed regardless of the user name.
+Only user names are valid; a numerical user ID is not recognized.
+By default, login is allowed for all users.
+If the pattern takes the form USER@HOST then USER and HOST
+are separately checked, restricting logins to particular
+users from particular hosts.
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to ports
forwarded for the client.
+By default,
+.Nm
+binds remote port forwardings to the loopback addresss. This
+prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that
+.Nm
+should bind remote port forwardings to the wildcard address,
+thus allowing remote hosts to connect to forwarded ports.
The argument must be
.Dq yes
or
@@ -433,9 +503,15 @@ and applies to protocol version 2 only.
The default is
.Dq no .
.It Cm HostKey
-Specifies the file containing the private host keys (default
-.Pa /etc/ssh/ssh_host_key )
-used by SSH protocol versions 1 and 2.
+Specifies a file containing a private host key
+used by SSH.
+The default is
+.Pa /etc/ssh/ssh_host_key
+for protocol version 1, and
+.Pa /etc/ssh/ssh_host_rsa_key
+and
+.Pa /etc/ssh/ssh_host_dsa_key
+for protocol version 2.
Note that
.Nm
will refuse to use a file if it is group/world-accessible.
@@ -475,7 +551,7 @@ or
The default is
.Dq no .
.It Cm KeepAlive
-Specifies whether the system should send keepalive messages to the
+Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
@@ -490,12 +566,11 @@ users and consuming server resources.
The default is
.Dq yes
(to send keepalives), and the server will notice
-if the network goes down or the client host reboots.
+if the network goes down or the client host crashes.
This avoids infinitely hanging sessions.
.Pp
To disable keepalives, the value should be set to
-.Dq no
-in both the server and the client configuration files.
+.Dq no .
.It Cm KerberosAuthentication
Specifies whether Kerberos authentication is allowed.
This can be in the form of a Kerberos ticket, or if
@@ -578,9 +653,10 @@ The default is 120 (seconds).
Gives the verbosity level that is used when logging messages from
.Nm sshd .
The possible values are:
-QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
-The default is INFO.
-Logging with level DEBUG violates the privacy of users
+QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3.
+The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2
+and DEBUG3 each specify higher levels of debugging output.
+Logging with a DEBUG level violates the privacy of users
and is not recommended.
.It Cm MACs
Specifies the available MAC (message authentication code) algorithms.
@@ -588,11 +664,7 @@ The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
-.Pp
-.Bd -literal
- ``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
- hmac-sha1-96,hmac-md5-96''
-.Ed
+.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
.It Cm MaxStartups
Specifies the maximum number of concurrent unauthenticated connections to the
.Nm
@@ -703,14 +775,6 @@ Specifies whether public key authentication is allowed.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
-.It Cm ReverseMappingCheck
-Specifies whether
-.Nm
-should try to verify the remote host name and check that
-the resolved host name for the remote IP address maps back to the
-very same IP address.
-The default is
-.Dq no .
.It Cm RhostsAuthentication
Specifies whether authentication using rhosts or
.Pa /etc/hosts.equiv
@@ -742,14 +806,8 @@ This option applies to protocol version 1 only.
Defines the number of bits in the ephemeral protocol version 1 server key.
The minimum value is 512, and the default is 768.
.It Cm SkeyAuthentication
-Specifies whether
-.Xr skey 1
-authentication is allowed.
-The default is
-.Dq yes .
-Note that OPIE authentication is enabled only if
-.Cm PasswordAuthentication
-is allowed, too.
+Backward-compatibility alias for
+.Cm ChallengeResponseAuthentication .
.It Cm StrictModes
Specifies whether
.Nm
@@ -780,9 +838,24 @@ The default is AUTH.
Specifies whether
.Xr login 1
is used for interactive login sessions.
+The default is
+.Dq no .
Note that
.Xr login 1
is never used for remote command execution.
+Note also, that if this is enabled,
+.Cm X11Forwarding
+will be disabled because
+.Xr login 1
+does not know how to handle
+.Xr xauth 1
+cookies.
+.It Cm VerifyReverseMapping
+Specifies whether
+.Nm
+should try to verify the remote host name and check that
+the resolved host name for the remote IP address maps back to the
+very same IP address.
The default is
.Dq no .
.It Cm X11DisplayOffset
@@ -799,6 +872,34 @@ The default is
.Dq no .
Note that disabling X11 forwarding does not improve security in any
way, as users can always install their own forwarders.
+X11 forwarding is automatically disabled if
+.Cm UseLogin
+is enabled.
+.It Cm X11UseLocalhost
+Specifies whether
+.Nm
+should bind the X11 forwarding server to the loopback address or to
+the wildcard address. By default,
+.Nm
+binds the forwarding server to the loopback address and sets the
+hostname part of the
+.Ev DISPLAY
+environment variable to
+.Dq localhost .
+This prevents remote hosts from connecting to the fake display.
+However, some older X11 clients may not function with this
+configuration.
+.Cm X11UseLocalhost
+may be set to
+.Dq no
+to specify that the forwarding server should be bound to the wildcard
+address.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
.It Cm XAuthLocation
Specifies the location of the
.Xr xauth 1
@@ -806,6 +907,48 @@ program.
The default is
.Pa /usr/X11R6/bin/xauth .
.El
+.Ss Time Formats
+.Pp
+.Nm
+command-line arguments and configuration file options that specify time
+may be expressed using a sequence of the form:
+.Sm off
+.Ar time Oo Ar qualifier Oc ,
+.Sm on
+where
+.Ar time
+is a positive integer value and
+.Ar qualifier
+is one of the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Cm <none>
+seconds
+.It Cm s | Cm S
+seconds
+.It Cm m | Cm M
+minutes
+.It Cm h | Cm H
+hours
+.It Cm d | Cm D
+days
+.It Cm w | Cm W
+weeks
+.El
+.Pp
+Each member of the sequence is added together to calculate
+the total time value.
+.Pp
+Time format examples:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It 600
+600 seconds (10 minutes)
+.It 10m
+10 minutes
+.It 1h30m
+1 hour 30 minutes (90 minutes)
+.El
.Sh LOGIN PROCESS
When a user successfully logs in,
.Nm
@@ -854,15 +997,13 @@ authentication protocol and cookie (if applicable) in standard input.
Runs user's shell or command.
.El
.Sh AUTHORIZED_KEYS FILE FORMAT
-The
.Pa $HOME/.ssh/authorized_keys
-file lists the RSA keys that are
+is the default file that lists the public keys that are
permitted for RSA authentication in protocol version 1
-Similarly, the
-.Pa $HOME/.ssh/authorized_keys2
-file lists the DSA and RSA keys that are
-permitted for public key authentication (PubkeyAuthentication)
+and for public key authentication (PubkeyAuthentication)
in protocol version 2.
+.Cm AuthorizedKeysFile
+may be used to specify an alternative file.
.Pp
Each line of the file contains one
key (empty lines and lines starting with a
@@ -897,7 +1038,8 @@ file and edit it.
The options (if present) consist of comma-separated option
specifications.
No spaces are permitted, except within double quotes.
-The following option specifications are supported:
+The following option specifications are supported (note
+that option keywords are case-insensitive):
.Bl -tag -width Ds
.It Cm from="pattern-list"
Specifies that in addition to RSA authentication, the canonical name
@@ -923,10 +1065,10 @@ just the key).
Specifies that the command is executed whenever this key is used for
authentication.
The command supplied by the user (if any) is ignored.
-The command is run on a pty if the connection requests a pty;
+The command is run on a pty if the client requests a pty;
otherwise it is run without a tty.
-Note that if you want a 8-bit clean channel,
-you must not request a pty or should specify
+If a 8-bit clean channel is required,
+one must not request a pty or should specify
.Cm no-pty .
A quote may be included in the command by quoting it with a backslash.
This option might be useful
@@ -934,12 +1076,16 @@ to restrict certain RSA keys to perform just a specific operation.
An example might be a key that permits remote backups but nothing else.
Note that the client may specify TCP/IP and/or X11
forwarding unless they are explicitly prohibited.
+Note that this option applies to shell, command or subsystem execution.
.It Cm environment="NAME=value"
Specifies that the string is to be added to the environment when
logging in using this key.
Environment variables set this way
override other default environment values.
Multiple options of this type are permitted.
+This option is automatically disabled if
+.Cm UseLogin
+is enabled.
.It Cm no-port-forwarding
Forbids TCP/IP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
@@ -955,13 +1101,16 @@ authentication.
.It Cm no-pty
Prevents tty allocation (a request to allocate a pty will fail).
.It Cm permitopen="host:port"
-Limit local
+Limit local
.Li ``ssh -L''
port forwarding such that it may only connect to the specified host and
-port. Multiple
+port.
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
+Multiple
.Cm permitopen
-options may be applied separated by commas. No pattern matching is
-performed on the specified hostnames, they must be literal domains or
+options may be applied separated by commas. No pattern matching is
+performed on the specified hostnames, they must be literal domains or
addresses.
.El
.Ss Examples
@@ -974,11 +1123,9 @@ command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hu
permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23.\|.\|.\|2323
.Sh SSH_KNOWN_HOSTS FILE FORMAT
The
-.Pa /etc/ssh/ssh_known_hosts ,
-.Pa /etc/ssh/ssh_known_hosts2 ,
-.Pa $HOME/.ssh/known_hosts ,
+.Pa /etc/ssh/ssh_known_hosts
and
-.Pa $HOME/.ssh/known_hosts2
+.Pa $HOME/.ssh/known_hosts
files contain host public keys for all known hosts.
The global file should
be prepared by the administrator (optional), and the per-user file is
@@ -1054,7 +1201,7 @@ really used for anything; they are provided for the convenience of
the user so their contents can be copied to known hosts files.
These files are created using
.Xr ssh-keygen 1 .
-.It Pa /etc/primes
+.It Pa /etc/moduli
Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
.It Pa /var/run/sshd.pid
Contains the process ID of the
@@ -1064,17 +1211,6 @@ concurrently for different ports, this contains the pid of the one
started last).
The content of this file is not sensitive; it can be world-readable.
.It Pa $HOME/.ssh/authorized_keys
-Lists the RSA keys that can be used to log into the user's account.
-This file must be readable by root (which may on some machines imply
-it being world-readable if the user's home directory resides on an NFS
-volume).
-It is recommended that it not be accessible by others.
-The format of this file is described above.
-Users will place the contents of their
-.Pa identity.pub
-files into this file, as described in
-.Xr ssh-keygen 1 .
-.It Pa $HOME/.ssh/authorized_keys2
Lists the public keys (RSA or DSA) that can be used to log into the user's account.
This file must be readable by root (which may on some machines imply
it being world-readable if the user's home directory resides on an NFS
@@ -1082,6 +1218,7 @@ volume).
It is recommended that it not be accessible by others.
The format of this file is described above.
Users will place the contents of their
+.Pa identity.pub ,
.Pa id_dsa.pub
and/or
.Pa id_rsa.pub
@@ -1089,7 +1226,8 @@ files into this file, as described in
.Xr ssh-keygen 1 .
.It Pa "/etc/ssh/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
These files are consulted when using rhosts with RSA host
-authentication to check the public key of the host.
+authentication or protocol version 2 hostbased authentication
+to check the public key of the host.
The key must be listed in one of these files to be accepted.
The client uses the same files
to verify that it is connecting to the correct remote host.
@@ -1098,17 +1236,6 @@ These files should be writable only by root/the owner.
should be world-readable, and
.Pa $HOME/.ssh/known_hosts
can but need not be world-readable.
-.It Pa "/etc/ssh_known_hosts2" and "$HOME/.ssh/known_hosts2"
-These files are consulted when using protocol version 2 hostbased
-authentication to check the public key of the host.
-The key must be listed in one of these files to be accepted.
-The client uses the same files
-to verify that it is connecting to the correct remote host.
-These files should be writable only by root/the owner.
-.Pa /etc/ssh_known_hosts2
-should be world-readable, and
-.Pa $HOME/.ssh/known_hosts2
-can but need not be world-readable.
.It Pa /etc/nologin
If this file exists,
.Nm
@@ -1117,10 +1244,9 @@ The contents of the file
are displayed to anyone trying to log in, and non-root connections are
refused.
The file should be world-readable.
-.It Pa /etc/hosts.allow
-If compiled with
-.Sy LIBWRAP
-support, tcp-wrappers access controls may be defined here as described in
+.It Pa /etc/hosts.allow, /etc/hosts.deny
+Access controls that should be enforced by tcp-wrappers are defined here.
+Further details are described in
.Xr hosts_access 5 .
.It Pa $HOME/.rhosts
This file contains host-username pairs, separated by a space, one per
@@ -1243,13 +1369,13 @@ protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
-.Xr sftp-server 8 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
-.Xr rlogin 1 ,
-.Xr rsh 1
+.Xr login.conf 5 ,
+.Xr moduli 5 ,
+.Xr sftp-server 8
.Rs
.%A T. Ylonen
.%A T. Kivinen
@@ -1257,8 +1383,8 @@ protocol versions 1.5 and 2.0.
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
-.%N draft-ietf-secsh-architecture-07.txt
-.%D January 2001
+.%N draft-ietf-secsh-architecture-09.txt
+.%D July 2001
.%O work in progress material
.Re
.Rs
@@ -1266,7 +1392,7 @@ protocol versions 1.5 and 2.0.
.%A N. Provos
.%A W. A. Simpson
.%T "Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol"
-.%N draft-ietf-secsh-dh-group-exchange-00.txt
-.%D January 2001
+.%N draft-ietf-secsh-dh-group-exchange-01.txt
+.%D April 2001
.%O work in progress material
.Re
diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c
index 103d458..a48fa8c 100644
--- a/crypto/openssh/sshd.c
+++ b/crypto/openssh/sshd.c
@@ -40,12 +40,12 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.195 2001/04/15 16:58:03 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.228 2002/02/27 21:23:13 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/dh.h>
#include <openssl/bn.h>
-#include <openssl/hmac.h>
+#include <openssl/md5.h>
#include "ssh.h"
#include "ssh1.h"
@@ -75,6 +75,7 @@ RCSID("$FreeBSD$");
#include "auth.h"
#include "misc.h"
#include "dispatch.h"
+#include "channels.h"
#ifdef LIBWRAP
#include <tcpd.h>
@@ -87,10 +88,6 @@ int deny_severity = LOG_WARNING;
#define O_NOCTTY 0
#endif
-#ifdef KRB5
-#include <krb5.h>
-#endif /* KRB5 */
-
extern char *__progname;
/* Server configuration options. */
@@ -113,6 +110,9 @@ extern int IPv4or6;
*/
int debug_flag = 0;
+/* Flag indicating that the daemon should only test the configuration and keys. */
+int test_flag = 0;
+
/* Flag indicating that the daemon is being started from inetd. */
int inetd_flag = 0;
@@ -164,10 +164,11 @@ struct {
* Flag indicating whether the RSA server key needs to be regenerated.
* Is set in the SIGALRM handler and cleared when the key is regenerated.
*/
-int key_do_regen = 0;
+static volatile sig_atomic_t key_do_regen = 0;
-/* This is set to true when SIGHUP is received. */
-int received_sighup = 0;
+/* This is set to true when a signal is received. */
+static volatile sig_atomic_t received_sighup = 0;
+static volatile sig_atomic_t received_sigterm = 0;
/* session identifier, used by RSA-auth */
u_char session_id[16];
@@ -179,17 +180,20 @@ int session_id2_len = 0;
/* record remote hostname or ip */
u_int utmp_len = MAXHOSTNAMELEN;
+/* options.max_startup sized array of fd ints */
+int *startup_pipes = NULL;
+int startup_pipe; /* in child */
+
/* Prototypes for various functions defined later in this file. */
-void do_ssh1_kex(void);
-void do_ssh2_kex(void);
+void destroy_sensitive_data(void);
-void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *);
-void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *);
+static void do_ssh1_kex(void);
+static void do_ssh2_kex(void);
/*
* Close all listening sockets
*/
-void
+static void
close_listen_socks(void)
{
int i;
@@ -198,27 +202,41 @@ close_listen_socks(void)
num_listen_socks = -1;
}
+static void
+close_startup_pipes(void)
+{
+ int i;
+ if (startup_pipes)
+ for (i = 0; i < options.max_startups; i++)
+ if (startup_pipes[i] != -1)
+ close(startup_pipes[i]);
+}
+
/*
* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
* the effect is to reread the configuration file (and to regenerate
* the server key).
*/
-void
+static void
sighup_handler(int sig)
{
+ int save_errno = errno;
+
received_sighup = 1;
signal(SIGHUP, sighup_handler);
+ errno = save_errno;
}
/*
* Called from the main program after receiving SIGHUP.
* Restarts the server.
*/
-void
+static void
sighup_restart(void)
{
log("Received SIGHUP; restarting.");
close_listen_socks();
+ close_startup_pipes();
execv(saved_argv[0], saved_argv);
log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno));
exit(1);
@@ -226,23 +244,18 @@ sighup_restart(void)
/*
* Generic signal handler for terminating signals in the master daemon.
- * These close the listen socket; not closing it seems to cause "Address
- * already in use" problems on some machines, which is inconvenient.
*/
-void
+static void
sigterm_handler(int sig)
{
- log("Received signal %d; terminating.", sig);
- close_listen_socks();
- unlink(options.pid_file);
- exit(255);
+ received_sigterm = sig;
}
/*
* SIGCHLD handler. This is called whenever a child dies. This will then
- * reap any zombies left by exited c.
+ * reap any zombies left by exited children.
*/
-void
+static void
main_sigchld_handler(int sig)
{
int save_errno = errno;
@@ -258,9 +271,11 @@ main_sigchld_handler(int sig)
/*
* Signal handler for the alarm after the login grace period has expired.
*/
-void
+static void
grace_alarm_handler(int sig)
{
+ /* XXX no idea how fix this signal handler */
+
/* Close the connection. */
packet_close();
@@ -275,7 +290,7 @@ grace_alarm_handler(int sig)
* Thus there should be no concurrency control/asynchronous execution
* problems.
*/
-void
+static void
generate_ephemeral_server_key(void)
{
u_int32_t rand = 0;
@@ -298,7 +313,7 @@ generate_ephemeral_server_key(void)
arc4random_stir();
}
-void
+static void
key_regeneration_alarm(int sig)
{
int save_errno = errno;
@@ -307,7 +322,7 @@ key_regeneration_alarm(int sig)
key_do_regen = 1;
}
-void
+static void
sshd_exchange_identification(int sock_in, int sock_out)
{
int i, mismatch;
@@ -335,7 +350,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
/* Send our protocol version identification. */
if (atomicio(write, sock_out, server_version_string, strlen(server_version_string))
!= strlen(server_version_string)) {
- log("Could not write ident string to %s.", get_remote_ipaddr());
+ log("Could not write ident string to %s", get_remote_ipaddr());
fatal_cleanup();
}
@@ -343,7 +358,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
- log("Did not receive identification string from %s.",
+ log("Did not receive identification string from %s",
get_remote_ipaddr());
fatal_cleanup();
}
@@ -379,7 +394,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
fatal_cleanup();
}
debug("Client protocol version %d.%d; client software version %.100s",
- remote_major, remote_minor, remote_version);
+ remote_major, remote_minor, remote_version);
compat_datafellows(remote_version);
@@ -390,7 +405,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
}
mismatch = 0;
- switch(remote_major) {
+ switch (remote_major) {
case 1:
if (remote_minor == 99) {
if (options.protocol & SSH_PROTO_2)
@@ -434,8 +449,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
server_version_string, client_version_string);
fatal_cleanup();
}
- if (compat20)
- packet_set_ssh2_format();
}
@@ -449,7 +462,7 @@ destroy_sensitive_data(void)
key_free(sensitive_data.server_key);
sensitive_data.server_key = NULL;
}
- for(i = 0; i < options.num_host_key_files; i++) {
+ for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
key_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = NULL;
@@ -459,36 +472,40 @@ destroy_sensitive_data(void)
memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
}
-char *
+static char *
list_hostkey_types(void)
{
- static char buf[1024];
+ Buffer b;
+ char *p;
int i;
- buf[0] = '\0';
- for(i = 0; i < options.num_host_key_files; i++) {
+
+ buffer_init(&b);
+ for (i = 0; i < options.num_host_key_files; i++) {
Key *key = sensitive_data.host_keys[i];
if (key == NULL)
continue;
- switch(key->type) {
+ switch (key->type) {
case KEY_RSA:
case KEY_DSA:
- strlcat(buf, key_ssh_name(key), sizeof buf);
- strlcat(buf, ",", sizeof buf);
+ if (buffer_len(&b) > 0)
+ buffer_append(&b, ",", 1);
+ p = key_ssh_name(key);
+ buffer_append(&b, p, strlen(p));
break;
}
}
- i = strlen(buf);
- if (i > 0 && buf[i-1] == ',')
- buf[i-1] = '\0';
- debug("list_hostkey_types: %s", buf);
- return buf;
+ buffer_append(&b, "\0", 1);
+ p = xstrdup(buffer_ptr(&b));
+ buffer_free(&b);
+ debug("list_hostkey_types: %s", p);
+ return p;
}
-Key *
+static Key *
get_hostkey_by_type(int type)
{
int i;
- for(i = 0; i < options.num_host_key_files; i++) {
+ for (i = 0; i < options.num_host_key_files; i++) {
Key *key = sensitive_data.host_keys[i];
if (key != NULL && key->type == type)
return key;
@@ -502,7 +519,7 @@ get_hostkey_by_type(int type)
* of (max_startups_rate/100). the probability increases linearly until
* all connections are dropped for startups > max_startups
*/
-int
+static int
drop_connection(int startups)
{
double p, r;
@@ -525,8 +542,30 @@ drop_connection(int startups)
return (r < p) ? 1 : 0;
}
-int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */
-int startup_pipe; /* in child */
+static void
+usage(void)
+{
+ fprintf(stderr, "sshd version %s\n", SSH_VERSION);
+ fprintf(stderr, "Usage: %s [options]\n", __progname);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
+ fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n");
+ fprintf(stderr, " -i Started from inetd\n");
+ fprintf(stderr, " -D Do not fork into daemon mode\n");
+ fprintf(stderr, " -t Only test configuration file and keys\n");
+ fprintf(stderr, " -q Quiet (no logging)\n");
+ fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
+ fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
+ fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n");
+ fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
+ fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
+ _PATH_HOST_KEY_FILE);
+ fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
+ fprintf(stderr, " -4 Use IPv4 only\n");
+ fprintf(stderr, " -6 Use IPv6 only\n");
+ fprintf(stderr, " -o option Process the option as if it was read from a configuration file.\n");
+ exit(1);
+}
/*
* Main program for the daemon.
@@ -560,7 +599,7 @@ main(int ac, char **av)
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDeiqQ46")) != -1) {
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) {
switch (opt) {
case '4':
IPv4or6 = AF_INET;
@@ -613,10 +652,16 @@ main(int ac, char **av)
}
break;
case 'g':
- options.login_grace_time = atoi(optarg);
+ if ((options.login_grace_time = convtime(optarg)) == -1) {
+ fprintf(stderr, "Invalid login grace time.\n");
+ exit(1);
+ }
break;
case 'k':
- options.key_regeneration_time = atoi(optarg);
+ if ((options.key_regeneration_time = convtime(optarg)) == -1) {
+ fprintf(stderr, "Invalid key regeneration interval.\n");
+ exit(1);
+ }
break;
case 'h':
if (options.num_host_key_files >= MAX_HOSTKEYS) {
@@ -630,40 +675,35 @@ main(int ac, char **av)
/* only makes sense with inetd_flag, i.e. no listen() */
inetd_flag = 1;
break;
+ case 't':
+ test_flag = 1;
+ break;
case 'u':
utmp_len = atoi(optarg);
break;
+ case 'o':
+ if (process_server_config_line(&options, optarg,
+ "command-line", 0) != 0)
+ exit(1);
+ break;
case '?':
default:
- fprintf(stderr, "sshd version %s\n", SSH_VERSION);
- fprintf(stderr, "Usage: %s [options]\n", __progname);
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
- fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n");
- fprintf(stderr, " -i Started from inetd\n");
- fprintf(stderr, " -D Do not fork into daemon mode\n");
- fprintf(stderr, " -q Quiet (no logging)\n");
- fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
- fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
- fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n");
- fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
- fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
- _PATH_HOST_KEY_FILE);
- fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
- fprintf(stderr, " -4 Use IPv4 only\n");
- fprintf(stderr, " -6 Use IPv6 only\n");
- exit(1);
+ usage();
+ break;
}
}
SSLeay_add_all_algorithms();
+ channel_set_af(IPv4or6);
/*
* Force logging to stderr until we have loaded the private host
* key (unless started from inetd)
*/
log_init(__progname,
- options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
- options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
+ options.log_level == SYSLOG_LEVEL_NOT_SET ?
+ SYSLOG_LEVEL_INFO : options.log_level,
+ options.log_facility == SYSLOG_FACILITY_NOT_SET ?
+ SYSLOG_FACILITY_AUTH : options.log_facility,
!inetd_flag);
/* Read server configuration options from the configuration file. */
@@ -682,14 +722,14 @@ main(int ac, char **av)
/* load private host keys */
sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*));
- for(i = 0; i < options.num_host_key_files; i++)
+ for (i = 0; i < options.num_host_key_files; i++)
sensitive_data.host_keys[i] = NULL;
sensitive_data.server_key = NULL;
sensitive_data.ssh1_host_key = NULL;
sensitive_data.have_ssh1_key = 0;
sensitive_data.have_ssh2_key = 0;
- for(i = 0; i < options.num_host_key_files; i++) {
+ for (i = 0; i < options.num_host_key_files; i++) {
key = key_load_private(options.host_key_files[i], "", NULL);
sensitive_data.host_keys[i] = key;
if (key == NULL) {
@@ -698,7 +738,7 @@ main(int ac, char **av)
sensitive_data.host_keys[i] = NULL;
continue;
}
- switch(key->type){
+ switch (key->type) {
case KEY_RSA1:
sensitive_data.ssh1_host_key = key;
sensitive_data.have_ssh1_key = 1;
@@ -747,6 +787,10 @@ main(int ac, char **av)
}
}
+ /* Configuration looks good, so exit if in test mode. */
+ if (test_flag)
+ exit(0);
+
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && !inetd_flag)
log_stderr = 1;
@@ -782,7 +826,7 @@ main(int ac, char **av)
/* Chdir to the root directory so that the current disk can be
unmounted if desired. */
chdir("/");
-
+
/* ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
@@ -834,11 +878,11 @@ main(int ac, char **av)
* close.
*/
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
- (void *) &on, sizeof(on));
+ &on, sizeof(on));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,
- (void *) &linger, sizeof(linger));
+ &linger, sizeof(linger));
debug("Bind to port %s on %s.", strport, ntop);
@@ -863,6 +907,22 @@ main(int ac, char **av)
if (!num_listen_socks)
fatal("Cannot bind any address.");
+ if (options.protocol & SSH_PROTO_1)
+ generate_ephemeral_server_key();
+
+ /*
+ * Arrange to restart on SIGHUP. The handler needs
+ * listen_sock.
+ */
+ signal(SIGHUP, sighup_handler);
+
+ signal(SIGTERM, sigterm_handler);
+ signal(SIGQUIT, sigterm_handler);
+
+ /* Arrange SIGCHLD to be caught. */
+ signal(SIGCHLD, main_sigchld_handler);
+
+ /* Write out the pid file after the sigterm handler is setup */
if (!debug_flag) {
/*
* Record our pid in /var/run/sshd.pid to make it
@@ -877,17 +937,6 @@ main(int ac, char **av)
fclose(f);
}
}
- if (options.protocol & SSH_PROTO_1)
- generate_ephemeral_server_key();
-
- /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
- signal(SIGHUP, sighup_handler);
-
- signal(SIGTERM, sigterm_handler);
- signal(SIGQUIT, sigterm_handler);
-
- /* Arrange SIGCHLD to be caught. */
- signal(SIGCHLD, main_sigchld_handler);
/* setup fd set for listen */
fdset = NULL;
@@ -923,6 +972,13 @@ main(int ac, char **av)
ret = select(maxfd+1, fdset, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR)
error("select: %.100s", strerror(errno));
+ if (received_sigterm) {
+ log("Received signal %d; terminating.",
+ (int) received_sigterm);
+ close_listen_socks();
+ unlink(options.pid_file);
+ exit(255);
+ }
if (key_used && key_do_regen) {
generate_ephemeral_server_key();
key_used = 0;
@@ -957,6 +1013,7 @@ main(int ac, char **av)
}
if (fcntl(newsock, F_SETFL, 0) < 0) {
error("newsock del O_NONBLOCK: %s", strerror(errno));
+ close(newsock);
continue;
}
if (drop_connection(startups) == 1) {
@@ -1010,9 +1067,7 @@ main(int ac, char **av)
* the connection.
*/
startup_pipe = startup_p[1];
- for (j = 0; j < options.max_startups; j++)
- if (startup_pipes[j] != -1)
- close(startup_pipes[j]);
+ close_startup_pipes();
close_listen_socks();
sock_in = newsock;
sock_out = newsock;
@@ -1072,11 +1127,11 @@ main(int ac, char **av)
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
linger.l_onoff = 1;
linger.l_linger = 5;
- setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
+ setsockopt(sock_in, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
/* Set keepalives if requested. */
if (options.keepalives &&
- setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
+ setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
@@ -1089,22 +1144,23 @@ main(int ac, char **av)
remote_port = get_remote_port();
remote_ip = get_remote_ipaddr();
- /* Check whether logins are denied from this host. */
#ifdef LIBWRAP
+ /* Check whether logins are denied from this host. */
{
struct request_info req;
- request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, NULL);
+ request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
fromhost(&req);
if (!hosts_access(&req)) {
+ debug("Connection refused by tcp wrapper");
refuse(&req);
- close(sock_in);
- close(sock_out);
+ /* NOTREACHED */
+ fatal("libwrap refuse returns");
}
- verbose("Connection from %.500s port %d", eval_client(&req), remote_port);
}
#endif /* LIBWRAP */
+
/* Log the connection. */
verbose("Connection from %.500s port %d", remote_ip, remote_port);
@@ -1128,10 +1184,11 @@ main(int ac, char **av)
* 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 ||
- remote_port < IPPORT_RESERVED / 2) {
+ if (options.rhosts_authentication &&
+ (remote_port >= IPPORT_RESERVED ||
+ remote_port < IPPORT_RESERVED / 2)) {
debug("Rhosts Authentication disabled, "
- "originating port not trusted.");
+ "originating port %d not trusted.", remote_port);
options.rhosts_authentication = 0;
}
#if defined(KRB4) && !defined(KRB5)
@@ -1140,7 +1197,7 @@ main(int ac, char **av)
debug("Kerberos Authentication disabled, only available for IPv4.");
options.kerberos_authentication = 0;
}
-#endif /* KRB4 */
+#endif /* KRB4 && !KRB5 */
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
@@ -1160,13 +1217,6 @@ main(int ac, char **av)
do_ssh1_kex();
do_authentication();
}
-
-#ifdef KRB4
- /* Cleanup user's ticket cache file. */
- if (options.krb4_ticket_cleanup)
- (void) dest_tkt();
-#endif /* KRB4 */
-
/* The connection has been terminated. */
verbose("Closing connection to %.100s", remote_ip);
@@ -1181,11 +1231,10 @@ main(int ac, char **av)
/*
* SSH1 key exchange
*/
-void
+static void
do_ssh1_kex(void)
{
int i, len;
- int plen, slen;
int rsafail = 0;
BIGNUM *session_key_int;
u_char session_key[SSH_SESSION_KEY_LENGTH];
@@ -1246,18 +1295,15 @@ do_ssh1_kex(void)
if (options.kerberos_authentication)
auth_mask |= 1 << SSH_AUTH_KERBEROS;
#endif
-#ifdef KRB5
- if (options.krb5_tgt_passing)
- auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
-#endif /* KRB5 */
-
-#ifdef AFS
- if (options.krb4_tgt_passing)
+#if defined(AFS) || defined(KRB5)
+ if (options.kerberos_tgt_passing)
auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
+#endif
+#ifdef AFS
if (options.afs_token_passing)
auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
#endif
- if (options.challenge_reponse_authentication == 1)
+ if (options.challenge_response_authentication == 1)
auth_mask |= 1 << SSH_AUTH_TIS;
if (options.password_authentication)
auth_mask |= 1 << SSH_AUTH_PASSWORD;
@@ -1272,7 +1318,7 @@ do_ssh1_kex(void)
BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
/* Read clients reply (cipher type and session key). */
- packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
+ packet_read_expect(SSH_CMSG_SESSION_KEY);
/* Get cipher type and check whether we accept this. */
cipher_type = packet_get_char();
@@ -1289,13 +1335,13 @@ do_ssh1_kex(void)
debug("Encryption type: %.200s", cipher_name(cipher_type));
/* Get the encrypted integer. */
- session_key_int = BN_new();
- packet_get_bignum(session_key_int, &slen);
+ if ((session_key_int = BN_new()) == NULL)
+ fatal("do_ssh1_kex: BN_new failed");
+ packet_get_bignum(session_key_int);
protocol_flags = packet_get_int();
packet_set_protocol_flags(protocol_flags);
-
- packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
+ packet_check_eom();
/*
* Decrypt it using our private server key and private host key (key
@@ -1365,7 +1411,7 @@ do_ssh1_kex(void)
}
if (rsafail) {
int bytes = BN_num_bytes(session_key_int);
- char *buf = xmalloc(bytes);
+ u_char *buf = xmalloc(bytes);
MD5_CTX md;
log("do_connection: generating a fake encryption key");
@@ -1407,7 +1453,7 @@ do_ssh1_kex(void)
/*
* SSH2 key exchange: diffie-hellman-group1-sha1
*/
-void
+static void
do_ssh2_kex(void)
{
Kex *kex;
diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config
index 854311f..ac3c9f9 100644
--- a/crypto/openssh/sshd_config
+++ b/crypto/openssh/sshd_config
@@ -1,70 +1,93 @@
-# $OpenBSD: sshd_config,v 1.38 2001/04/15 21:41:29 deraadt Exp $
-# $FreeBSD$
+# $OpenBSD: src/usr.bin/ssh/sshd_config,v 1.48 2002/02/19 02:50:59 deraadt Exp $
+# $FreeBSD$
# This is the sshd server system-wide configuration file. See sshd(8)
# for more information.
-Port 22
+# The strategy used for options in the default sshd_config shipped with
+# OpenSSH is to specify options with their default value where
+# possible, but leave them commented. Uncommented options change a
+# default value.
+
+# Note that some of FreeBSD's defaults differ from OpenBSD's, and
+# FreeBSD has a few additional options.
+
+#VersionAddendum FreeBSD localisations 20020318
+
+#Port 22
#Protocol 2,1
#ListenAddress 0.0.0.0
#ListenAddress ::
-HostKey /etc/ssh/ssh_host_key
-HostKey /etc/ssh/ssh_host_dsa_key
-ServerKeyBits 768
-LoginGraceTime 120
-KeyRegenerationInterval 3600
-PermitRootLogin no
-# ConnectionsPerPeriod has been deprecated completely
-
-# After 10 unauthenticated connections, refuse 30% of the new ones, and
-# refuse any more than 60 total.
-MaxStartups 10:30:60
-# Don't read ~/.rhosts and ~/.shosts files
-IgnoreRhosts yes
-# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
-#IgnoreUserKnownHosts yes
-StrictModes yes
-X11Forwarding yes
-X11DisplayOffset 10
-PrintMotd yes
-#PrintLastLog no
-KeepAlive yes
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 3600
+#ServerKeyBits 768
# Logging
-SyslogFacility AUTH
-LogLevel INFO
#obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+#LogLevel INFO
-RhostsAuthentication no
-#
-# For this to work you will also need host keys in /etc/ssh_known_hosts
-RhostsRSAAuthentication no
+# Authentication:
+
+#LoginGraceTime 120
+#PermitRootLogin no
+#StrictModes yes
+
+#RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile .ssh/authorized_keys
+
+# rhosts authentication should not be used
+#RhostsAuthentication no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
# similar for protocol version 2
-HostbasedAuthentication no
-#
-RSAAuthentication yes
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
# To disable tunneled clear text passwords, change to no here!
-PasswordAuthentication yes
-PermitEmptyPasswords no
+#PasswordAuthentication yes
+#PermitEmptyPasswords no
-# Uncomment to disable s/key passwords
-#ChallengeResponseAuthentication no
+# Change to no to disable s/key passwords
+#ChallengeResponseAuthentication yes
-# To change Kerberos options
-#KerberosAuthentication no
+# Kerberos options
+# KerberosAuthentication automatically enabled if keyfile exists
+#KerberosAuthentication yes
#KerberosOrLocalPasswd yes
-#AFSTokenPassing no
-#KerberosTicketCleanup no
+#KerberosTicketCleanup yes
+
+# AFSTokenPassing automatically enabled if k_hasafs() is true
+#AFSTokenPassing yes
-# Kerberos TGT Passing does only work with the AFS kaserver
-#KerberosTgtPassing yes
+# Kerberos TGT Passing only works with the AFS kaserver
+#KerberosTgtPassing no
-CheckMail yes
+#X11Forwarding yes
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#KeepAlive yes
#UseLogin no
+#CheckMail yes
-#MaxStartups 10:30:60
-#Banner /etc/issue.net
-#ReverseMappingCheck yes
+#MaxStartups 10
+# no default banner path
+#Banner /some/path
+#VerifyReverseMapping no
+# override default of no subsystems
Subsystem sftp /usr/libexec/sftp-server
diff --git a/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c
index b8536c0..7b987e9 100644
--- a/crypto/openssh/sshlogin.c
+++ b/crypto/openssh/sshlogin.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $");
+RCSID("$OpenBSD: sshlogin.c,v 1.3 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include <libutil.h>
@@ -87,7 +87,7 @@ get_last_login_time(uid_t uid, const char *logname,
void
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
- const char *host, struct sockaddr * addr)
+ const char *host, struct sockaddr * addr)
{
int fd;
struct lastlog ll;
@@ -99,7 +99,7 @@ record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
u.ut_time = time(NULL);
strncpy(u.ut_name, user, sizeof(u.ut_name));
- realhostname_sa(u.ut_host, sizeof(u.ut_host), addr, addr->sa_len);
+ strncpy(u.ut_host, host, sizeof(u.ut_host));
login(&u);
lastlog = _PATH_LASTLOG;
diff --git a/crypto/openssh/sshpty.c b/crypto/openssh/sshpty.c
index 1544ac6..53fb075 100644
--- a/crypto/openssh/sshpty.c
+++ b/crypto/openssh/sshpty.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $");
+RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include <libutil.h>
@@ -132,7 +132,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
*ttyfd = open(name, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("Could not open pty slave side %.100s: %.100s",
- name, strerror(errno));
+ name, strerror(errno));
close(*ptyfd);
return 0;
}
@@ -225,7 +225,7 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
fd = open(_PATH_TTY, O_WRONLY);
if (fd < 0)
error("open /dev/tty failed - could not set controlling tty: %.100s",
- strerror(errno));
+ strerror(errno));
else {
close(fd);
}
@@ -235,7 +235,7 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
void
pty_change_window_size(int ptyfd, int row, int col,
- int xpixel, int ypixel)
+ int xpixel, int ypixel)
{
struct winsize w;
w.ws_row = row;
@@ -265,7 +265,8 @@ pty_setowner(struct passwd *pw, const char *ttyname)
/*
* Change owner and mode of the tty as required.
- * Warn but continue if filesystem is read-only and the uids match.
+ * Warn but continue if filesystem is read-only and the uids match/
+ * tty is owned by root.
*/
if (stat(ttyname, &st))
fatal("stat(%.100s) failed: %.100s", ttyname,
@@ -273,14 +274,15 @@ pty_setowner(struct passwd *pw, const char *ttyname)
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
if (chown(ttyname, pw->pw_uid, gid) < 0) {
- if (errno == EROFS && st.st_uid == pw->pw_uid)
+ if (errno == EROFS &&
+ (st.st_uid == pw->pw_uid || st.st_uid == 0))
error("chown(%.100s, %d, %d) failed: %.100s",
- ttyname, pw->pw_uid, gid,
- strerror(errno));
+ ttyname, pw->pw_uid, gid,
+ strerror(errno));
else
fatal("chown(%.100s, %d, %d) failed: %.100s",
- ttyname, pw->pw_uid, gid,
- strerror(errno));
+ ttyname, pw->pw_uid, gid,
+ strerror(errno));
}
}
@@ -289,10 +291,10 @@ pty_setowner(struct passwd *pw, const char *ttyname)
if (errno == EROFS &&
(st.st_mode & (S_IRGRP | S_IROTH)) == 0)
error("chmod(%.100s, 0%o) failed: %.100s",
- ttyname, mode, strerror(errno));
+ ttyname, mode, strerror(errno));
else
fatal("chmod(%.100s, 0%o) failed: %.100s",
- ttyname, mode, strerror(errno));
+ ttyname, mode, strerror(errno));
}
}
}
diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h
index 0b69783..7549aa5 100644
--- a/crypto/openssh/version.h
+++ b/crypto/openssh/version.h
@@ -1,11 +1,11 @@
+/* $OpenBSD: version.h,v 1.28 2002/03/06 00:25:55 markus Exp $ */
/* $FreeBSD$ */
-/* $OpenBSD: version.h,v 1.23 2001/04/24 16:43:16 markus Exp $ */
-#ifndef SSH_VERSION
+#ifndef SSH_VERSION
-#define SSH_VERSION (ssh_version_get())
-#define SSH_VERSION_BASE "OpenSSH_2.9"
-#define SSH_VERSION_ADDENDUM "FreeBSD localisations 20020307"
+#define SSH_VERSION (ssh_version_get())
+#define SSH_VERSION_BASE "OpenSSH_3.1"
+#define SSH_VERSION_ADDENDUM "FreeBSD localisations 20020318"
const char *ssh_version_get(void);
void ssh_version_set_addendum(const char *add);
OpenPOWER on IntegriCloud