Resolve conflicts and update for OpenSSH 2.2.0

Reviewed by:	gshapiro, peter, green
This commit is contained in:
kris 2000-09-10 09:35:38 +00:00
parent d345e9b7aa
commit 71b51dc832
37 changed files with 2392 additions and 1657 deletions

View File

@ -1,8 +1,25 @@
/* /*
* Dug Song <dugsong@UMICH.EDU> * Copyright (c) 1999 Dug Song. All rights reserved.
* Kerberos v4 authentication and ticket-passing routines. *
* * Redistribution and use in source and binary forms, with or without
* $FreeBSD$ * modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
@ -11,6 +28,9 @@
#include "ssh.h" #include "ssh.h"
#include "servconf.h" #include "servconf.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.18 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#ifdef KRB4 #ifdef KRB4
char *ticket = NULL; char *ticket = NULL;
@ -82,11 +102,12 @@ auth_krb4_password(struct passwd * pw, const char *password)
if (r == RD_AP_UNDEC) { if (r == RD_AP_UNDEC) {
/* /*
* Probably didn't have a srvtab on * Probably didn't have a srvtab on
* localhost. Allow login. * localhost. Disallow login.
*/ */
log("Kerberos V4 TGT for %s unverifiable, " log("Kerberos V4 TGT for %s unverifiable, "
"no srvtab installed? krb_rd_req: %s", "no srvtab installed? krb_rd_req: %s",
pw->pw_name, krb_err_txt[r]); pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
} else if (r != KSUCCESS) { } 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]); KRB4_SERVICE_NAME, krb_err_txt[r]);
@ -94,12 +115,13 @@ auth_krb4_password(struct passwd * pw, const char *password)
} }
} else if (r == KDC_PR_UNKNOWN) { } else if (r == KDC_PR_UNKNOWN) {
/* /*
* Allow login if no rcmd service exists, but * Disallow login if no rcmd service exists, and
* log the error. * log the error.
*/ */
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s " log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
"not registered, or srvtab is wrong?", pw->pw_name, "not registered, or srvtab is wrong?", pw->pw_name,
krb_err_txt[r], KRB4_SERVICE_NAME, phost); krb_err_txt[r], KRB4_SERVICE_NAME, phost);
goto kerberos_auth_failure;
} else { } else {
/* /*
* TGT is bad, forget it. Possibly spoofed! * TGT is bad, forget it. Possibly spoofed!
@ -152,7 +174,7 @@ krb4_init(uid_t uid)
if (lstat("/ticket", &st) != -1) if (lstat("/ticket", &st) != -1)
tkt_root = "/ticket/"; tkt_root = "/ticket/";
#endif /* AFS */ #endif /* AFS */
snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid()); snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
(void) krb_set_tkt_string(ticket); (void) krb_set_tkt_string(ticket);
} }
/* Register ticket cleanup in case of fatal error. */ /* Register ticket cleanup in case of fatal error. */

View File

@ -2,15 +2,65 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Sat Mar 18 05:11:38 1995 ylo
* Password authentication. This file contains the functions to check whether * Password authentication. This file contains the functions to check whether
* the password is valid for the user. * the password is valid for the user.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
*
* Copyright (c) 1999 Dug Song. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-passwd.c,v 1.15 2000/04/14 10:30:29 markus Exp $"); RCSID("$OpenBSD: auth-passwd.c,v 1.17 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"
@ -21,7 +71,7 @@ RCSID("$Id: auth-passwd.c,v 1.15 2000/04/14 10:30:29 markus Exp $");
* Tries to authenticate the user using password. Returns true if * Tries to authenticate the user using password. Returns true if
* authentication succeeds. * authentication succeeds.
*/ */
int int
auth_password(struct passwd * pw, const char *password) auth_password(struct passwd * pw, const char *password)
{ {
extern ServerOptions options; extern ServerOptions options;

View File

@ -1,22 +1,20 @@
/* /*
*
* auth-rh-rsa.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sun May 7 03:08:06 1995 ylo
*
* Rhosts or /etc/hosts.equiv authentication combined with RSA host * Rhosts or /etc/hosts.equiv authentication combined with RSA host
* authentication. * authentication.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rh-rsa.c,v 1.13 2000/04/14 10:30:29 markus Exp $"); RCSID("$OpenBSD: auth-rh-rsa.c,v 1.16 2000/09/07 21:13:36 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "ssh.h" #include "ssh.h"

View File

@ -1,23 +1,21 @@
/* /*
*
* auth-rsa.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Mon Mar 27 01:46:52 1995 ylo
*
* RSA-based authentication. This code determines whether to admit a login * RSA-based authentication. This code determines whether to admit a login
* based on RSA authentication. This file also contains functions to check * based on RSA authentication. This file also contains functions to check
* validity of the host key. * validity of the host key.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rsa.c,v 1.23 2000/04/29 18:11:51 markus Exp $"); RCSID("$OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp $");
RCSID("$FreeBSD$");
#include "rsa.h" #include "rsa.h"
#include "packet.h" #include "packet.h"
@ -27,18 +25,11 @@ RCSID("$Id: auth-rsa.c,v 1.23 2000/04/29 18:11:51 markus Exp $");
#include "uidswap.h" #include "uidswap.h"
#include "match.h" #include "match.h"
#include "servconf.h" #include "servconf.h"
#include "auth-options.h"
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/md5.h> #include <openssl/md5.h>
/* Flags that may be set in authorized_keys options. */
extern int no_port_forwarding_flag;
extern int no_agent_forwarding_flag;
extern int no_x11_forwarding_flag;
extern int no_pty_flag;
extern char *forced_command;
extern struct envstring *custom_environment;
/* /*
* Session identifier that is used to bind key exchange and authentication * Session identifier that is used to bind key exchange and authentication
* responses to a particular session. * responses to a particular session.
@ -187,8 +178,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
} }
if (fail) { if (fail) {
fclose(f); fclose(f);
log(buf); log("%s",buf);
packet_send_debug(buf); packet_send_debug("%s",buf);
restore_uid(); restore_uid();
return 0; return 0;
} }
@ -269,188 +260,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
* authenticated. Note that we have not yet processed the * authenticated. Note that we have not yet processed the
* options; this will be reset if the options cause the * options; this will be reset if the options cause the
* authentication to be rejected. * authentication to be rejected.
*/
authenticated = 1;
/* RSA part of authentication was accepted. Now process the options. */
if (options) {
while (*options && *options != ' ' && *options != '\t') {
cp = "no-port-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
no_port_forwarding_flag = 1;
options += strlen(cp);
goto next_option;
}
cp = "no-agent-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
packet_send_debug("Agent forwarding disabled.");
no_agent_forwarding_flag = 1;
options += strlen(cp);
goto next_option;
}
cp = "no-X11-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
packet_send_debug("X11 forwarding disabled.");
no_x11_forwarding_flag = 1;
options += strlen(cp);
goto next_option;
}
cp = "no-pty";
if (strncmp(options, cp, strlen(cp)) == 0) {
packet_send_debug("Pty allocation disabled.");
no_pty_flag = 1;
options += strlen(cp);
goto next_option;
}
cp = "command=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
options += strlen(cp);
forced_command = xmalloc(strlen(options) + 1);
i = 0;
while (*options) {
if (*options == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
forced_command[i++] = '"';
continue;
}
forced_command[i++] = *options++;
}
if (!*options) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
}
forced_command[i] = 0;
packet_send_debug("Forced command: %.900s", forced_command);
options++;
goto next_option;
}
cp = "environment=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
char *s;
struct envstring *new_envstring;
options += strlen(cp);
s = xmalloc(strlen(options) + 1);
i = 0;
while (*options) {
if (*options == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
s[i++] = '"';
continue;
}
s[i++] = *options++;
}
if (!*options) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
}
s[i] = 0;
packet_send_debug("Adding to environment: %.900s", s);
debug("Adding to environment: %.900s", s);
options++;
new_envstring = xmalloc(sizeof(struct envstring));
new_envstring->s = s;
new_envstring->next = custom_environment;
custom_environment = new_envstring;
goto next_option;
}
cp = "from=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
char *patterns = xmalloc(strlen(options) + 1);
int i;
options += strlen(cp);
i = 0;
while (*options) {
if (*options == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *options++;
}
if (!*options) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
}
patterns[i] = 0;
options++;
if (!match_hostname(get_canonical_hostname(), patterns,
strlen(patterns)) &&
!match_hostname(get_remote_ipaddr(), patterns,
strlen(patterns))) {
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
pw->pw_name, get_canonical_hostname(),
get_remote_ipaddr());
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
get_canonical_hostname());
xfree(patterns);
/* key invalid for this host, reset flags */
authenticated = 0;
no_agent_forwarding_flag = 0;
no_port_forwarding_flag = 0;
no_pty_flag = 0;
no_x11_forwarding_flag = 0;
while (custom_environment) {
struct envstring *ce = custom_environment;
custom_environment = ce->next;
xfree(ce->s);
xfree(ce);
}
if (forced_command) {
xfree(forced_command);
forced_command = NULL;
}
break;
}
xfree(patterns);
/* Host name matches. */
goto next_option;
}
bad_option:
log("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
authenticated = 0;
break;
next_option:
/*
* Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (!*options)
fatal("Bugs in auth-rsa.c option processing.");
if (*options == ' ' || *options == '\t')
break; /* End of options. */
if (*options != ',')
goto bad_option;
options++;
/* Process the next option. */
continue;
}
}
/*
* Break out of the loop if authentication was successful; * Break out of the loop if authentication was successful;
* otherwise continue searching. * otherwise continue searching.
*/ */
authenticated = auth_parse_options(pw, options, linenum);
if (authenticated) if (authenticated)
break; break;
} }

View File

@ -1,7 +1,30 @@
/* $FreeBSD$ */ /*
* 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $"); RCSID("$OpenBSD: auth-skey.c,v 1.8 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include "ssh.h" #include "ssh.h"
@ -112,7 +135,7 @@ skey_fake_keyinfo(char *username)
mib[0] = CTL_KERN; mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME; mib[1] = KERN_BOOTTIME;
size = sizeof(boottime); size = sizeof(boottime);
bzero(&boottime, sizeof(boottime)); bzero(&boottime, size);
if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
boottime.tv_sec != 0) { boottime.tv_sec != 0) {
secret = (char *)&boottime; secret = (char *)&boottime;

View File

@ -1,13 +1,40 @@
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* $FreeBSD$ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.7 2000/05/17 21:37:24 deraadt Exp $"); RCSID("$OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -26,12 +53,9 @@ RCSID("$OpenBSD: auth.c,v 1.7 2000/05/17 21:37:24 deraadt Exp $");
#include "ssh2.h" #include "ssh2.h"
#include "auth.h" #include "auth.h"
#include "session.h" #include "session.h"
#include "dispatch.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
extern char *forced_command;
/* /*
* Check if the user is allowed to log in via ssh. If user is listed in * Check if the user is allowed to log in via ssh. If user is listed in
@ -115,16 +139,6 @@ allowed_user(struct passwd * pw)
return 0; return 0;
} }
} }
#ifndef __FreeBSD__ /* FreeBSD handle it later */
/* Fail if the account's expiration time has passed. */
if (pw->pw_expire != 0) {
struct timeval tv;
(void)gettimeofday(&tv, NULL);
if (tv.tv_sec >= pw->pw_expire)
return 0;
}
#endif /* !__FreeBSD__ */
/* We found no reason not to let this user try to log on... */ /* We found no reason not to let this user try to log on... */
return 1; return 1;
} }

View File

@ -2,11 +2,16 @@
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.2 2000/04/29 18:11:52 markus Exp $"); RCSID("$OpenBSD: auth1.c,v 1.4 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -148,15 +153,15 @@ do_authloop(struct passwd * pw)
unsigned int ulen; unsigned int ulen;
int type = 0; int type = 0;
void (*authlog) (const char *fmt,...) = verbose; void (*authlog) (const char *fmt,...) = verbose;
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_cap_t *lc; login_cap_t *lc;
#endif /* LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
#if defined(LOGIN_CAP) || defined(LOGIN_ACCESS) #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip; const char *from_host, *from_ip;
from_host = get_canonical_hostname(); from_host = get_canonical_hostname();
from_ip = get_remote_ipaddr(); from_ip = get_remote_ipaddr();
#endif /* LOGIN_CAP || LOGIN_ACCESS */ #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
#ifdef HAVE_LIBPAM #ifdef HAVE_LIBPAM
int pam_retval; int pam_retval;
#endif /* HAVE_LIBPAM */ #endif /* HAVE_LIBPAM */
@ -452,7 +457,7 @@ do_authloop(struct passwd * pw)
} }
} }
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
lc = login_getpwclass(pw); lc = login_getpwclass(pw);
if (lc == NULL) if (lc == NULL)
lc = login_getclassbyname(NULL, pw); lc = login_getclassbyname(NULL, pw);
@ -467,7 +472,7 @@ do_authloop(struct passwd * pw)
packet_disconnect("Logins not available right now."); packet_disconnect("Logins not available right now.");
} }
login_close(lc); login_close(lc);
#endif /* LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
#ifdef LOGIN_ACCESS #ifdef LOGIN_ACCESS
if (!login_access(pw->pw_name, from_host)) { if (!login_access(pw->pw_name, from_host)) {
log("Denied connection for %.200s from %.200s [%.200s].", log("Denied connection for %.200s from %.200s [%.200s].",
@ -548,6 +553,7 @@ do_authentication()
pwcopy.pw_passwd = xstrdup(pw->pw_passwd); pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
pwcopy.pw_uid = pw->pw_uid; pwcopy.pw_uid = pw->pw_uid;
pwcopy.pw_gid = pw->pw_gid; pwcopy.pw_gid = pw->pw_gid;
pwcopy.pw_class = xstrdup(pw->pw_class);
pwcopy.pw_dir = xstrdup(pw->pw_dir); pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell); pwcopy.pw_shell = xstrdup(pw->pw_shell);
pwcopy.pw_class = xstrdup(pw->pw_class); pwcopy.pw_class = xstrdup(pw->pw_class);

View File

@ -9,11 +9,6 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -25,11 +20,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $"); RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include <openssl/dsa.h> #include <openssl/dsa.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
@ -56,6 +51,7 @@ RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $");
#include "dsa.h" #include "dsa.h"
#include "uidswap.h" #include "uidswap.h"
#include "auth-options.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
@ -71,7 +67,7 @@ void protocol_error(int type, int plen);
/* auth */ /* auth */
int ssh2_auth_none(struct passwd *pw); int ssh2_auth_none(struct passwd *pw);
int ssh2_auth_password(struct passwd *pw); int ssh2_auth_password(struct passwd *pw);
int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen); int ssh2_auth_pubkey(struct passwd *pw, char *service);
/* helper */ /* helper */
struct passwd* auth_set_user(char *u, char *s); struct passwd* auth_set_user(char *u, char *s);
@ -152,17 +148,14 @@ input_userauth_request(int type, int plen)
{ {
static void (*authlog) (const char *fmt,...) = verbose; static void (*authlog) (const char *fmt,...) = verbose;
static int attempt = 0; static int attempt = 0;
unsigned int len, rlen; unsigned int len;
int authenticated = 0; int authenticated = 0;
char *raw, *user, *service, *method, *authmsg = NULL; char *user, *service, *method, *authmsg = NULL;
struct passwd *pw; struct passwd *pw;
if (++attempt == AUTH_FAIL_MAX) if (++attempt == AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests"); packet_disconnect("too many failed userauth_requests");
raw = packet_get_raw(&rlen);
if (plen != rlen)
fatal("plen != rlen");
user = packet_get_string(&len); user = packet_get_string(&len);
service = packet_get_string(&len); service = packet_get_string(&len);
method = packet_get_string(&len); method = packet_get_string(&len);
@ -176,7 +169,7 @@ input_userauth_request(int type, int plen)
} else if (strcmp(method, "password") == 0) { } else if (strcmp(method, "password") == 0) {
authenticated = ssh2_auth_password(pw); authenticated = ssh2_auth_password(pw);
} else if (strcmp(method, "publickey") == 0) { } else if (strcmp(method, "publickey") == 0) {
authenticated = ssh2_auth_pubkey(pw, raw, rlen); authenticated = ssh2_auth_pubkey(pw, service);
} }
} }
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
@ -254,7 +247,7 @@ ssh2_auth_password(struct passwd *pw)
return authenticated; return authenticated;
} }
int int
ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) ssh2_auth_pubkey(struct passwd *pw, char *service)
{ {
Buffer b; Buffer b;
Key *key; Key *key;
@ -267,10 +260,6 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
debug("pubkey auth disabled"); debug("pubkey auth disabled");
return 0; return 0;
} }
if (datafellows & SSH_BUG_PUBKEYAUTH) {
log("bug compatibility with ssh-2.0.13 pubkey not implemented");
return 0;
}
have_sig = packet_get_char(); have_sig = packet_get_char();
pkalg = packet_get_string(&alen); pkalg = packet_get_string(&alen);
if (strcmp(pkalg, KEX_DSS) != 0) { if (strcmp(pkalg, KEX_DSS) != 0) {
@ -285,11 +274,22 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
sig = packet_get_string(&slen); sig = packet_get_string(&slen);
packet_done(); packet_done();
buffer_init(&b); buffer_init(&b);
buffer_append(&b, session_id2, session_id2_len); if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
buffer_put_string(&b, session_id2, session_id2_len);
} else {
buffer_append(&b, session_id2, session_id2_len);
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
if (slen + 4 > rlen) buffer_put_cstring(&b, pw->pw_name);
fatal("bad rlen/slen"); buffer_put_cstring(&b,
buffer_append(&b, raw, rlen - slen - 4); datafellows & SSH_BUG_PUBKEYAUTH ?
"ssh-userauth" :
service);
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_DSS #ifdef DEBUG_DSS
buffer_dump(&b); buffer_dump(&b);
#endif #endif
@ -357,6 +357,7 @@ auth_set_user(char *u, char *s)
copy->pw_passwd = xstrdup(pw->pw_passwd); copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_uid = pw->pw_uid; copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid; copy->pw_gid = pw->pw_gid;
copy->pw_class = xstrdup(pw->pw_class);
copy->pw_dir = xstrdup(pw->pw_dir); copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell); copy->pw_shell = xstrdup(pw->pw_shell);
copy->pw_class = xstrdup(pw->pw_class); copy->pw_class = xstrdup(pw->pw_class);
@ -438,8 +439,8 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
} }
} }
if (fail) { if (fail) {
log(buf);
fclose(f); fclose(f);
log("%s",buf);
restore_uid(); restore_uid();
return 0; return 0;
} }
@ -448,17 +449,36 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
found = key_new(KEY_DSA); found = key_new(KEY_DSA);
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
char *cp; char *cp, *options = NULL;
linenum++; linenum++;
/* Skip leading whitespace, empty and comment lines. */ /* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++) for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
; ;
if (!*cp || *cp == '\n' || *cp == '#') if (!*cp || *cp == '\n' || *cp == '#')
continue; continue;
bits = key_read(found, &cp); bits = key_read(found, &cp);
if (bits == 0) if (bits == 0) {
continue; /* no key? check if there are options for this key */
if (key_equal(found, key)) { int quoted = 0;
options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
bits = key_read(found, &cp);
if (bits == 0) {
/* still no key? advance to next line*/
continue;
}
}
if (key_equal(found, key) &&
auth_parse_options(pw, options, linenum) == 1) {
found_key = 1; found_key = 1;
debug("matching key found: file %s, line %ld", debug("matching key found: file %s, line %ld",
file, linenum); file, linenum);

View File

@ -1,31 +1,60 @@
/* /*
*
* authfd.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Wed Mar 29 01:30:28 1995 ylo
*
* Functions for connecting the local authentication agent. * Functions for connecting the local authentication agent.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
* SSH2 implementation,
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: authfd.c,v 1.19 2000/04/29 18:11:52 markus Exp $"); RCSID("$OpenBSD: authfd.c,v 1.27 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
#include "authfd.h"
#include "buffer.h" #include "buffer.h"
#include "bufaux.h" #include "bufaux.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "getput.h" #include "getput.h"
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "key.h"
#include "authfd.h"
#include "kex.h"
#include "dsa.h"
/* helper */
int decode_reply(int type);
/* Returns the number of the authentication fd, or -1 if there is none. */ /* Returns the number of the authentication fd, or -1 if there is none. */
@ -60,6 +89,59 @@ ssh_get_authentication_socket()
return sock; return sock;
} }
int
ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
{
int l, len;
char buf[1024];
/* Get the length of the message, and format it in the buffer. */
len = buffer_len(request);
PUT_32BIT(buf, len);
/* Send the length and then the packet to the agent. */
if (atomicio(write, auth->fd, buf, 4) != 4 ||
atomicio(write, auth->fd, buffer_ptr(request),
buffer_len(request)) != buffer_len(request)) {
error("Error writing to authentication socket.");
return 0;
}
/*
* Wait for response from the agent. First read the length of the
* response packet.
*/
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l <= 0) {
error("Error reading response length from authentication socket.");
return 0;
}
len -= l;
}
/* Extract the length, and check it for sanity. */
len = GET_32BIT(buf);
if (len > 256 * 1024)
fatal("Authentication response too long: %d", len);
/* Read the rest of the response in to the buffer. */
buffer_clear(reply);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l <= 0) {
error("Error reading response from authentication socket.");
return 0;
}
buffer_append(reply, (char *) buf, l);
len -= l;
}
return 1;
}
/* /*
* Closes the agent socket if it should be closed (depends on how it was * Closes the agent socket if it should be closed (depends on how it was
* obtained). The argument must have been returned by * obtained). The argument must have been returned by
@ -98,7 +180,6 @@ ssh_get_authentication_connection()
auth = xmalloc(sizeof(*auth)); auth = xmalloc(sizeof(*auth));
auth->fd = sock; auth->fd = sock;
buffer_init(&auth->packet);
buffer_init(&auth->identities); buffer_init(&auth->identities);
auth->howmany = 0; auth->howmany = 0;
@ -111,121 +192,108 @@ ssh_get_authentication_connection()
*/ */
void void
ssh_close_authentication_connection(AuthenticationConnection *ac) ssh_close_authentication_connection(AuthenticationConnection *auth)
{ {
buffer_free(&ac->packet); buffer_free(&auth->identities);
buffer_free(&ac->identities); close(auth->fd);
close(ac->fd); xfree(auth);
xfree(ac);
} }
/* /*
* Returns the first authentication identity held by the agent. * Returns the first authentication identity held by the agent.
* Returns true if an identity is available, 0 otherwise.
* The caller must initialize the integers before the call, and free the
* comment after a successful call (before calling ssh_get_next_identity).
*/ */
int Key *
ssh_get_first_identity(AuthenticationConnection *auth, ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
BIGNUM *e, BIGNUM *n, char **comment)
{ {
unsigned char msg[8192]; int type, code1 = 0, code2 = 0;
int len, l; Buffer request;
switch(version){
case 1:
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
break;
case 2:
code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
code2 = SSH2_AGENT_IDENTITIES_ANSWER;
break;
default:
return NULL;
}
/* /*
* Send a message to the agent requesting for a list of the * Send a message to the agent requesting for a list of the
* identities it can represent. * identities it can represent.
*/ */
msg[0] = 0; buffer_init(&request);
msg[1] = 0; buffer_put_char(&request, code1);
msg[2] = 0;
msg[3] = 1;
msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
if (atomicio(write, auth->fd, msg, 5) != 5) {
error("write auth->fd: %.100s", strerror(errno));
return 0;
}
/* Read the length of the response. XXX implement timeouts here. */
len = 4;
while (len > 0) {
l = read(auth->fd, msg + 4 - len, len);
if (l <= 0) {
error("read auth->fd: %.100s", strerror(errno));
return 0;
}
len -= l;
}
/*
* Extract the length, and check it for sanity. (We cannot trust
* authentication agents).
*/
len = GET_32BIT(msg);
if (len < 1 || len > 256 * 1024)
fatal("Authentication reply message too long: %d\n", len);
/* Read the packet itself. */
buffer_clear(&auth->identities); buffer_clear(&auth->identities);
while (len > 0) { if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
l = len; buffer_free(&request);
if (l > sizeof(msg)) return NULL;
l = sizeof(msg);
l = read(auth->fd, msg, l);
if (l <= 0)
fatal("Incomplete authentication reply.");
buffer_append(&auth->identities, (char *) msg, l);
len -= l;
} }
buffer_free(&request);
/* Get message type, and verify that we got a proper answer. */ /* Get message type, and verify that we got a proper answer. */
buffer_get(&auth->identities, (char *) msg, 1); type = buffer_get_char(&auth->identities);
if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER) if (type == SSH_AGENT_FAILURE) {
fatal("Bad authentication reply message type: %d", msg[0]); return NULL;
} else if (type != code2) {
fatal("Bad authentication reply message type: %d", type);
}
/* Get the number of entries in the response and check it for sanity. */ /* Get the number of entries in the response and check it for sanity. */
auth->howmany = buffer_get_int(&auth->identities); auth->howmany = buffer_get_int(&auth->identities);
if (auth->howmany > 1024) if (auth->howmany > 1024)
fatal("Too many identities in authentication reply: %d\n", auth->howmany); fatal("Too many identities in authentication reply: %d\n",
auth->howmany);
/* Return the first entry (if any). */ /* Return the first entry (if any). */
return ssh_get_next_identity(auth, e, n, comment); return ssh_get_next_identity(auth, comment, version);
} }
/* Key *
* Returns the next authentication identity for the agent. Other functions ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
* can be called between this and ssh_get_first_identity or two calls of this
* function. This returns 0 if there are no more identities. The caller
* must free comment after a successful return.
*/
int
ssh_get_next_identity(AuthenticationConnection *auth,
BIGNUM *e, BIGNUM *n, char **comment)
{ {
unsigned int bits; unsigned int bits;
unsigned char *blob;
unsigned int blen;
Key *key = NULL;
/* Return failure if no more entries. */ /* Return failure if no more entries. */
if (auth->howmany <= 0) if (auth->howmany <= 0)
return 0; return NULL;
/* /*
* Get the next entry from the packet. These will abort with a fatal * Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data. * error if the packet is too short or contains corrupt data.
*/ */
bits = buffer_get_int(&auth->identities); switch(version){
buffer_get_bignum(&auth->identities, e); case 1:
buffer_get_bignum(&auth->identities, n); key = key_new(KEY_RSA);
*comment = buffer_get_string(&auth->identities, NULL); bits = buffer_get_int(&auth->identities);
buffer_get_bignum(&auth->identities, key->rsa->e);
if (bits != BN_num_bits(n)) buffer_get_bignum(&auth->identities, key->rsa->n);
log("Warning: identity keysize mismatch: actual %d, announced %u", *comment = buffer_get_string(&auth->identities, NULL);
BN_num_bits(n), bits); if (bits != BN_num_bits(key->rsa->n))
log("Warning: identity keysize mismatch: actual %d, announced %u",
BN_num_bits(key->rsa->n), bits);
break;
case 2:
blob = buffer_get_string(&auth->identities, &blen);
*comment = buffer_get_string(&auth->identities, NULL);
key = dsa_key_from_blob(blob, blen);
xfree(blob);
break;
default:
return NULL;
break;
}
/* Decrement the number of remaining entries. */ /* Decrement the number of remaining entries. */
auth->howmany--; auth->howmany--;
return key;
return 1;
} }
/* /*
@ -238,101 +306,124 @@ ssh_get_next_identity(AuthenticationConnection *auth,
int int
ssh_decrypt_challenge(AuthenticationConnection *auth, ssh_decrypt_challenge(AuthenticationConnection *auth,
BIGNUM* e, BIGNUM *n, BIGNUM *challenge, Key* key, BIGNUM *challenge,
unsigned char session_id[16], unsigned char session_id[16],
unsigned int response_type, unsigned int response_type,
unsigned char response[16]) unsigned char response[16])
{ {
Buffer buffer; Buffer buffer;
unsigned char buf[8192]; int success = 0;
int len, l, i; int i;
int type;
/* Response type 0 is no longer supported. */ if (key->type != KEY_RSA)
if (response_type == 0) return 0;
fatal("Compatibility with ssh protocol version 1.0 no longer supported."); if (response_type == 0) {
log("Compatibility with ssh protocol version 1.0 no longer supported.");
/* Format a message to the agent. */ return 0;
buf[0] = SSH_AGENTC_RSA_CHALLENGE; }
buffer_init(&buffer); buffer_init(&buffer);
buffer_append(&buffer, (char *) buf, 1); buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
buffer_put_int(&buffer, BN_num_bits(n)); buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
buffer_put_bignum(&buffer, e); buffer_put_bignum(&buffer, key->rsa->e);
buffer_put_bignum(&buffer, n); buffer_put_bignum(&buffer, key->rsa->n);
buffer_put_bignum(&buffer, challenge); buffer_put_bignum(&buffer, challenge);
buffer_append(&buffer, (char *) session_id, 16); buffer_append(&buffer, (char *) session_id, 16);
buffer_put_int(&buffer, response_type); buffer_put_int(&buffer, response_type);
/* Get the length of the message, and format it in the buffer. */ if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
len = buffer_len(&buffer);
PUT_32BIT(buf, len);
/* Send the length and then the packet to the agent. */
if (atomicio(write, auth->fd, buf, 4) != 4 ||
atomicio(write, auth->fd, buffer_ptr(&buffer),
buffer_len(&buffer)) != buffer_len(&buffer)) {
error("Error writing to authentication socket.");
error_cleanup:
buffer_free(&buffer); buffer_free(&buffer);
return 0; return 0;
} }
/* type = buffer_get_char(&buffer);
* Wait for response from the agent. First read the length of the
* response packet.
*/
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l <= 0) {
error("Error reading response length from authentication socket.");
goto error_cleanup;
}
len -= l;
}
/* Extract the length, and check it for sanity. */ if (type == SSH_AGENT_FAILURE) {
len = GET_32BIT(buf);
if (len > 256 * 1024)
fatal("Authentication response too long: %d", len);
/* Read the rest of the response in tothe buffer. */
buffer_clear(&buffer);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l <= 0) {
error("Error reading response from authentication socket.");
goto error_cleanup;
}
buffer_append(&buffer, (char *) buf, l);
len -= l;
}
/* Get the type of the packet. */
buffer_get(&buffer, (char *) buf, 1);
/* Check for agent failure message. */
if (buf[0] == SSH_AGENT_FAILURE) {
log("Agent admitted failure to authenticate using the key."); log("Agent admitted failure to authenticate using the key.");
goto error_cleanup; } else if (type != SSH_AGENT_RSA_RESPONSE) {
fatal("Bad authentication response: %d", type);
} else {
success = 1;
/*
* Get the response from the packet. This will abort with a
* fatal error if the packet is corrupt.
*/
for (i = 0; i < 16; i++)
response[i] = buffer_get_char(&buffer);
} }
/* Now it must be an authentication response packet. */
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
fatal("Bad authentication response: %d", buf[0]);
/*
* Get the response from the packet. This will abort with a fatal
* error if the packet is corrupt.
*/
for (i = 0; i < 16; i++)
response[i] = buffer_get_char(&buffer);
/* The buffer containing the packet is no longer needed. */
buffer_free(&buffer); buffer_free(&buffer);
return success;
}
/* Correct answer. */ /* ask agent to sign data, returns -1 on error, 0 on success */
return 1; int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen)
{
Buffer msg;
unsigned char *blob;
unsigned int blen;
int type;
int ret = -1;
if (dsa_make_key_blob(key, &blob, &blen) == 0)
return -1;
buffer_init(&msg);
buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
buffer_put_string(&msg, blob, blen);
buffer_put_string(&msg, data, datalen);
buffer_put_int(&msg, 0); /* flags, unused */
xfree(blob);
if (ssh_request_reply(auth, &msg, &msg) == 0) {
buffer_free(&msg);
return -1;
}
type = buffer_get_char(&msg);
if (type == SSH_AGENT_FAILURE) {
log("Agent admitted failure to sign using the key.");
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
fatal("Bad authentication response: %d", type);
} else {
ret = 0;
*sigp = buffer_get_string(&msg, lenp);
}
buffer_free(&msg);
return ret;
}
/* Encode key for a message to the agent. */
void
ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
buffer_put_int(b, BN_num_bits(key->n));
buffer_put_bignum(b, key->n);
buffer_put_bignum(b, key->e);
buffer_put_bignum(b, key->d);
/* To keep within the protocol: p < q for ssh. in SSL p > q */
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));
}
void
ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
buffer_put_cstring(b, KEX_DSS);
buffer_put_bignum2(b, key->p);
buffer_put_bignum2(b, key->q);
buffer_put_bignum2(b, key->g);
buffer_put_bignum2(b, key->pub_key);
buffer_put_bignum2(b, key->priv_key);
buffer_put_string(b, comment, strlen(comment));
} }
/* /*
@ -341,86 +432,32 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
*/ */
int int
ssh_add_identity(AuthenticationConnection *auth, ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
RSA * key, const char *comment)
{ {
Buffer buffer; Buffer msg;
unsigned char buf[8192]; int type;
int len, l, type;
/* Format a message to the agent. */ buffer_init(&msg);
buffer_init(&buffer);
buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
buffer_put_int(&buffer, BN_num_bits(key->n));
buffer_put_bignum(&buffer, key->n);
buffer_put_bignum(&buffer, key->e);
buffer_put_bignum(&buffer, key->d);
/* To keep within the protocol: p < q for ssh. in SSL p > q */
buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
buffer_put_string(&buffer, comment, strlen(comment));
/* Get the length of the message, and format it in the buffer. */ switch (key->type) {
len = buffer_len(&buffer); case KEY_RSA:
PUT_32BIT(buf, len); ssh_encode_identity_rsa(&msg, key->rsa, comment);
break;
/* Send the length and then the packet to the agent. */ case KEY_DSA:
if (atomicio(write, auth->fd, buf, 4) != 4 || ssh_encode_identity_dsa(&msg, key->dsa, comment);
atomicio(write, auth->fd, buffer_ptr(&buffer), break;
buffer_len(&buffer)) != buffer_len(&buffer)) {
error("Error writing to authentication socket.");
error_cleanup:
buffer_free(&buffer);
return 0;
}
/* Wait for response from the agent. First read the length of the
response packet. */
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l <= 0) {
error("Error reading response length from authentication socket.");
goto error_cleanup;
}
len -= l;
}
/* Extract the length, and check it for sanity. */
len = GET_32BIT(buf);
if (len > 256 * 1024)
fatal("Add identity response too long: %d", len);
/* Read the rest of the response in tothe buffer. */
buffer_clear(&buffer);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l <= 0) {
error("Error reading response from authentication socket.");
goto error_cleanup;
}
buffer_append(&buffer, (char *) buf, l);
len -= l;
}
/* Get the type of the packet. */
type = buffer_get_char(&buffer);
switch (type) {
case SSH_AGENT_FAILURE:
buffer_free(&buffer);
return 0;
case SSH_AGENT_SUCCESS:
buffer_free(&buffer);
return 1;
default: default:
fatal("Bad response to add identity from authentication agent: %d", buffer_free(&msg);
type); return 0;
break;
} }
/* NOTREACHED */ if (ssh_request_reply(auth, &msg, &msg) == 0) {
return 0; buffer_free(&msg);
return 0;
}
type = buffer_get_char(&msg);
buffer_free(&msg);
return decode_reply(type);
} }
/* /*
@ -429,81 +466,36 @@ ssh_add_identity(AuthenticationConnection *auth,
*/ */
int int
ssh_remove_identity(AuthenticationConnection *auth, RSA *key) ssh_remove_identity(AuthenticationConnection *auth, Key *key)
{ {
Buffer buffer; Buffer msg;
unsigned char buf[8192]; int type;
int len, l, type; unsigned char *blob;
unsigned int blen;
/* Format a message to the agent. */ buffer_init(&msg);
buffer_init(&buffer);
buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
buffer_put_int(&buffer, BN_num_bits(key->n));
buffer_put_bignum(&buffer, key->e);
buffer_put_bignum(&buffer, key->n);
/* Get the length of the message, and format it in the buffer. */ if (key->type == KEY_RSA) {
len = buffer_len(&buffer); buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
PUT_32BIT(buf, len); buffer_put_int(&msg, BN_num_bits(key->rsa->n));
buffer_put_bignum(&msg, key->rsa->e);
/* Send the length and then the packet to the agent. */ buffer_put_bignum(&msg, key->rsa->n);
if (atomicio(write, auth->fd, buf, 4) != 4 || } else if (key->type == KEY_DSA) {
atomicio(write, auth->fd, buffer_ptr(&buffer), dsa_make_key_blob(key, &blob, &blen);
buffer_len(&buffer)) != buffer_len(&buffer)) { buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
error("Error writing to authentication socket."); buffer_put_string(&msg, blob, blen);
error_cleanup: xfree(blob);
buffer_free(&buffer); } else {
buffer_free(&msg);
return 0; return 0;
} }
/* if (ssh_request_reply(auth, &msg, &msg) == 0) {
* Wait for response from the agent. First read the length of the buffer_free(&msg);
* response packet.
*/
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l <= 0) {
error("Error reading response length from authentication socket.");
goto error_cleanup;
}
len -= l;
}
/* Extract the length, and check it for sanity. */
len = GET_32BIT(buf);
if (len > 256 * 1024)
fatal("Remove identity response too long: %d", len);
/* Read the rest of the response in tothe buffer. */
buffer_clear(&buffer);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l <= 0) {
error("Error reading response from authentication socket.");
goto error_cleanup;
}
buffer_append(&buffer, (char *) buf, l);
len -= l;
}
/* Get the type of the packet. */
type = buffer_get_char(&buffer);
switch (type) {
case SSH_AGENT_FAILURE:
buffer_free(&buffer);
return 0; return 0;
case SSH_AGENT_SUCCESS:
buffer_free(&buffer);
return 1;
default:
fatal("Bad response to remove identity from authentication agent: %d",
type);
} }
/* NOTREACHED */ type = buffer_get_char(&msg);
return 0; buffer_free(&msg);
return decode_reply(type);
} }
/* /*
@ -512,68 +504,37 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
*/ */
int int
ssh_remove_all_identities(AuthenticationConnection *auth) ssh_remove_all_identities(AuthenticationConnection *auth, int version)
{ {
Buffer buffer; Buffer msg;
unsigned char buf[8192]; int type;
int len, l, type; int code = (version==1) ?
SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
/* Get the length of the message, and format it in the buffer. */ buffer_init(&msg);
PUT_32BIT(buf, 1); buffer_put_char(&msg, code);
buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
/* Send the length and then the packet to the agent. */ if (ssh_request_reply(auth, &msg, &msg) == 0) {
if (atomicio(write, auth->fd, buf, 5) != 5) { buffer_free(&msg);
error("Error writing to authentication socket.");
return 0; return 0;
} }
/* type = buffer_get_char(&msg);
* Wait for response from the agent. First read the length of the buffer_free(&msg);
* response packet. return decode_reply(type);
*/ }
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l <= 0) {
error("Error reading response length from authentication socket.");
return 0;
}
len -= l;
}
/* Extract the length, and check it for sanity. */ int
len = GET_32BIT(buf); decode_reply(int type)
if (len > 256 * 1024) {
fatal("Remove identity response too long: %d", len);
/* Read the rest of the response into the buffer. */
buffer_init(&buffer);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l <= 0) {
error("Error reading response from authentication socket.");
buffer_free(&buffer);
return 0;
}
buffer_append(&buffer, (char *) buf, l);
len -= l;
}
/* Get the type of the packet. */
type = buffer_get_char(&buffer);
switch (type) { switch (type) {
case SSH_AGENT_FAILURE: case SSH_AGENT_FAILURE:
buffer_free(&buffer); log("SSH_AGENT_FAILURE");
return 0; return 0;
case SSH_AGENT_SUCCESS: case SSH_AGENT_SUCCESS:
buffer_free(&buffer);
return 1; return 1;
default: default:
fatal("Bad response to remove identity from authentication agent: %d", fatal("Bad response from authentication agent: %d", type);
type);
} }
/* NOTREACHED */ /* NOTREACHED */
return 0; return 0;

View File

@ -1,22 +1,43 @@
/* /*
*
* authfile.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Mon Mar 27 03:52:05 1995 ylo
*
* This file contains functions for reading and writing identity files, and * This file contains functions for reading and writing identity files, and
* for reading the passphrase from the user. * for reading the passphrase from the user.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
*
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $"); RCSID("$OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
@ -263,6 +284,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
return 1; return 1;
} }
/* load public key from private-key file */
int int
load_public_key(const char *filename, Key * key, char **comment_return) load_public_key(const char *filename, Key * key, char **comment_return)
{ {
@ -492,3 +514,57 @@ load_private_key(const char *filename, const char *passphrase, Key *key,
close(fd); close(fd);
return ret; return ret;
} }
int
do_load_public_key(const char *filename, Key *k, char **commentp)
{
FILE *f;
unsigned int bits;
char line[1024];
char *cp;
f = fopen(filename, "r");
if (f != NULL) {
while (fgets(line, sizeof(line), f)) {
line[sizeof(line)-1] = '\0';
cp = line;
switch(*cp){
case '#':
case '\n':
case '\0':
continue;
}
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
if (*cp) {
bits = key_read(k, &cp);
if (bits != 0) {
if (commentp)
*commentp=xstrdup(filename);
fclose(f);
return 1;
}
}
}
fclose(f);
}
return 0;
}
/* load public key from pubkey file */
int
try_load_public_key(const char *filename, Key *k, char **commentp)
{
char pub[MAXPATHLEN];
if (do_load_public_key(filename, k, commentp) == 1)
return 1;
if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN)
return 0;
if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN)
return 0;
if (do_load_public_key(pub, k, commentp) == 1)
return 1;
return 0;
}

View File

@ -1,24 +1,44 @@
/* /*
*
* bufaux.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Wed Mar 29 02:24:47 1995 ylo
*
* Auxiliary functions for storing and retrieving various data types to/from * Auxiliary functions for storing and retrieving various data types to/from
* Buffers. * Buffers.
* *
* SSH2 packet format added by Markus Friedl * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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$ *
* SSH2 packet format added by Markus Friedl
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: bufaux.c,v 1.11 2000/04/14 10:30:30 markus Exp $"); RCSID("$OpenBSD: bufaux.c,v 1.13 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include <openssl/bn.h> #include <openssl/bn.h>

View File

@ -1,21 +1,19 @@
/* /*
*
* canohost.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sun Jul 2 17:52:22 1995 ylo
*
* Functions for returning the canonical host name of the remote site. * Functions for returning the canonical host name of the remote site.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: canohost.c,v 1.12 2000/04/14 10:30:30 markus Exp $"); RCSID("$OpenBSD: canohost.c,v 1.15 2000/09/07 21:13:37 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "xmalloc.h" #include "xmalloc.h"

View File

@ -1,19 +1,42 @@
/* /*
*
* cipher.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Created: Wed Apr 19 17:41:39 1995 ylo * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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$ *
* Copyright (c) 1999 Niels Provos. 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: cipher.c,v 1.27 2000/05/22 18:42:00 markus Exp $"); RCSID("$OpenBSD: cipher.c,v 1.30 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "cipher.h" #include "cipher.h"
@ -175,14 +198,15 @@ cipher_name(int cipher)
int int
ciphers_valid(const char *names) ciphers_valid(const char *names)
{ {
char *ciphers; char *ciphers, *cp;
char *p; char *p;
int i; int i;
if (names == NULL || strcmp(names, "") == 0) if (names == NULL || strcmp(names, "") == 0)
return 0; return 0;
ciphers = xstrdup(names); ciphers = cp = xstrdup(names);
for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) { for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
i = cipher_number(p); i = cipher_number(p);
if (i == -1 || !(cipher_mask2() & (1 << i))) { if (i == -1 || !(cipher_mask2() & (1 << i))) {
xfree(ciphers); xfree(ciphers);

View File

@ -1,18 +1,17 @@
/* /*
*
* cipher.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Created: Wed Apr 19 16:50:42 1995 ylo * As far as I am concerned, the code I have written for this software
* * can be used freely for any purpose. Any derived versions of this
* $FreeBSD$ * 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".
*/ */
/* RCSID("$Id: cipher.h,v 1.17 2000/05/08 17:12:15 markus Exp $"); */ /* RCSID("$OpenBSD: cipher.h,v 1.19 2000/09/07 20:27:50 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef CIPHER_H #ifndef CIPHER_H
#define CIPHER_H #define CIPHER_H

View File

@ -1,21 +1,43 @@
/* /*
*
* hostfile.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Thu Jun 29 07:10:56 1995 ylo
*
* Functions for manipulating the known hosts files. * Functions for manipulating the known hosts files.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
*
* 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
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.18 2000/04/29 18:11:52 markus Exp $"); RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "match.h" #include "match.h"
@ -130,7 +152,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
; ;
/* Check if the host name matches. */ /* Check if the host name matches. */
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp))) if (match_hostname(host, cp, (unsigned int) (cp2 - cp)) != 1)
continue; continue;
/* Got a match. Skip host name. */ /* Got a match. Skip host name. */

View File

@ -1,24 +1,22 @@
/* /*
*
* includes.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Thu Mar 23 16:29:37 1995 ylo
*
* This file includes most of the needed system headers. * This file includes most of the needed system headers.
* *
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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$ * $FreeBSD$
*/ */
#ifndef INCLUDES_H #ifndef INCLUDES_H
#define INCLUDES_H #define INCLUDES_H
#define RCSID(msg) \ #define RCSID(msg) __RCSID(msg)
static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -1,4 +1,14 @@
/* /*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -9,11 +19,6 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -25,12 +30,6 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*/ */
#include "includes.h" #include "includes.h"
@ -43,6 +42,9 @@
#include "dsa.h" #include "dsa.h"
#include "uuencode.h" #include "uuencode.h"
RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$FreeBSD$");
#define SSH_DSS "ssh-dss" #define SSH_DSS "ssh-dss"
Key * Key *
@ -123,8 +125,6 @@ key_equal(Key *a, Key *b)
return 0; return 0;
} }
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
/* /*
* Generate key fingerprint in ascii format. * Generate key fingerprint in ascii format.
* Based on ideas and code from Bjoern Groenvall <bg@sics.se> * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
@ -132,7 +132,7 @@ key_equal(Key *a, Key *b)
char * char *
key_fingerprint(Key *k) key_fingerprint(Key *k)
{ {
static char retval[80]; static char retval[(EVP_MAX_MD_SIZE+1)*3];
unsigned char *blob = NULL; unsigned char *blob = NULL;
int len = 0; int len = 0;
int nlen, elen; int nlen, elen;
@ -153,15 +153,22 @@ key_fingerprint(Key *k)
fatal("key_fingerprint: bad key type %d", k->type); fatal("key_fingerprint: bad key type %d", k->type);
break; break;
} }
retval[0] = '\0';
if (blob != NULL) { if (blob != NULL) {
unsigned char d[16]; int i;
EVP_MD_CTX md; unsigned char digest[EVP_MAX_MD_SIZE];
EVP_DigestInit(&md, EVP_md5()); EVP_MD *md = EVP_md5();
EVP_DigestUpdate(&md, blob, len); EVP_MD_CTX ctx;
EVP_DigestFinal(&md, d, NULL); EVP_DigestInit(&ctx, md);
snprintf(retval, sizeof(retval), FPRINT, EVP_DigestUpdate(&ctx, blob, len);
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], EVP_DigestFinal(&ctx, digest, NULL);
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); for(i = 0; i < md->md_size; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", digest[i]);
strlcat(retval, hex, sizeof(retval));
}
retval[strlen(retval) - 1] = '\0';
memset(blob, 0, len); memset(blob, 0, len);
xfree(blob); xfree(blob);
} }
@ -330,3 +337,15 @@ key_type(Key *k)
} }
return "unknown"; return "unknown";
} }
unsigned int
key_size(Key *k){
switch (k->type) {
case KEY_RSA:
return BN_num_bits(k->rsa->n);
break;
case KEY_DSA:
return BN_num_bits(k->dsa->p);
break;
}
return 0;
}

View File

@ -1,25 +1,46 @@
/* /*
*
* login.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Fri Mar 24 14:51:08 1995 ylo
*
* This file performs some of the things login(1) normally does. We cannot * This file performs some of the things login(1) normally does. We cannot
* easily use something like login -p -h host -f user, because there are * easily use something like login -p -h host -f user, because there are
* several different logins around, and it is hard to determined what kind of * several different logins around, and it is hard to determined what kind of
* login the current system has. Also, we want to be able to execute commands * login the current system has. Also, we want to be able to execute commands
* on a tty. * on a tty.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: login.c,v 1.13 2000/04/19 07:05:49 deraadt Exp $"); RCSID("$OpenBSD: login.c,v 1.15 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$FreeBSD$");
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#include <libutil.h> #include <libutil.h>

View File

@ -1,22 +1,20 @@
/* /*
*
* mpaux.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sun Jul 16 04:29:30 1995 ylo
*
* This file contains various auxiliary functions related to multiple * This file contains various auxiliary functions related to multiple
* precision integers. * precision integers.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
*/ * can be used freely for any purpose. Any derived versions of this
* 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".
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: mpaux.c,v 1.12 2000/04/14 10:30:32 markus Exp $"); RCSID("$OpenBSD: mpaux.c,v 1.14 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include "getput.h" #include "getput.h"

View File

@ -1,20 +1,18 @@
/* /*
*
* packet.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sat Mar 18 02:02:14 1995 ylo
*
* Interface for the packet protocol functions. * Interface for the packet protocol functions.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
/* RCSID("$Id: packet.h,v 1.15 2000/04/14 10:30:32 markus Exp $"); */ /* RCSID("$OpenBSD: packet.h,v 1.17 2000/09/07 20:27:52 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef PACKET_H #ifndef PACKET_H
#define PACKET_H #define PACKET_H

View File

@ -1,21 +1,19 @@
/* /*
*
* pty.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Fri Mar 17 04:37:25 1995 ylo
*
* Allocating a pseudo-terminal, and making it the controlling tty. * Allocating a pseudo-terminal, and making it the controlling tty.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: pty.c,v 1.13 2000/04/14 10:30:32 markus Exp $"); RCSID("$OpenBSD: pty.c,v 1.16 2000/09/07 21:13:37 markus Exp $");
RCSID("$FreeBSD$");
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#include <libutil.h> #include <libutil.h>

View File

@ -1,21 +1,19 @@
/* /*
*
* readconf.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sat Apr 22 00:03:10 1995 ylo
*
* Functions for reading the configuration files. * Functions for reading the configuration files.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: readconf.c,v 1.33 2000/05/29 20:20:46 markus Exp $"); RCSID("$OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "cipher.h" #include "cipher.h"
@ -93,7 +91,7 @@ typedef enum {
oBadOption, oBadOption,
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
oSkeyAuthentication, oSkeyAuthentication, oXAuthLocation,
#ifdef KRB4 #ifdef KRB4
oKrb4Authentication, oKrb4Authentication,
#endif /* KRB4 */ #endif /* KRB4 */
@ -120,6 +118,7 @@ static struct {
} keywords[] = { } keywords[] = {
{ "forwardagent", oForwardAgent }, { "forwardagent", oForwardAgent },
{ "forwardx11", oForwardX11 }, { "forwardx11", oForwardX11 },
{ "xauthlocation", oXAuthLocation },
{ "gatewayports", oGatewayPorts }, { "gatewayports", oGatewayPorts },
{ "useprivilegedport", oUsePrivilegedPort }, { "useprivilegedport", oUsePrivilegedPort },
{ "rhostsauthentication", oRhostsAuthentication }, { "rhostsauthentication", oRhostsAuthentication },
@ -171,10 +170,6 @@ static struct {
{ NULL, 0 } { NULL, 0 }
}; };
/* Characters considered whitespace in strtok calls. */
#define WHITESPACE " \t\r\n"
/* /*
* Adds a local TCP/IP port forward to options. Never returns if there is an * Adds a local TCP/IP port forward to options. Never returns if there is an
* error. * error.
@ -244,18 +239,20 @@ process_config_line(Options *options, const char *host,
char *line, const char *filename, int linenum, char *line, const char *filename, int linenum,
int *activep) int *activep)
{ {
char buf[256], *cp, *string, **charptr, *cp2; char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
int opcode, *intptr, value; int opcode, *intptr, value;
u_short fwd_port, fwd_host_port; u_short fwd_port, fwd_host_port;
/* Skip leading whitespace. */ s = line;
cp = line + strspn(line, WHITESPACE); /* Get the keyword. (Each line is supposed to begin with a keyword). */
if (!*cp || *cp == '\n' || *cp == '#') keyword = strdelim(&s);
/* Ignore leading whitespace. */
if (*keyword == '\0')
keyword = strdelim(&s);
if (!*keyword || *keyword == '\n' || *keyword == '#')
return 0; return 0;
/* Get the keyword. (Each line is supposed to begin with a keyword). */ opcode = parse_token(keyword, filename, linenum);
cp = strtok(cp, WHITESPACE);
opcode = parse_token(cp, filename, linenum);
switch (opcode) { switch (opcode) {
case oBadOption: case oBadOption:
@ -265,13 +262,13 @@ process_config_line(Options *options, const char *host,
case oForwardAgent: case oForwardAgent:
intptr = &options->forward_agent; intptr = &options->forward_agent;
parse_flag: parse_flag:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
value = 0; /* To avoid compiler warning... */ value = 0; /* To avoid compiler warning... */
if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1; value = 1;
else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
value = 0; value = 0;
else else
fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
@ -361,16 +358,16 @@ process_config_line(Options *options, const char *host,
case oStrictHostKeyChecking: case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking; intptr = &options->strict_host_key_checking;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no argument.", fatal("%.200s line %d: Missing yes/no argument.",
filename, linenum); filename, linenum);
value = 0; /* To avoid compiler warning... */ value = 0; /* To avoid compiler warning... */
if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1; value = 1;
else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
value = 0; value = 0;
else if (strcmp(cp, "ask") == 0) else if (strcmp(arg, "ask") == 0)
value = 2; value = 2;
else else
fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
@ -396,8 +393,8 @@ process_config_line(Options *options, const char *host,
case oIdentityFile: case oIdentityFile:
case oIdentityFile2: case oIdentityFile2:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep) { if (*activep) {
intptr = (opcode == oIdentityFile) ? intptr = (opcode == oIdentityFile) ?
@ -409,19 +406,23 @@ process_config_line(Options *options, const char *host,
charptr = (opcode == oIdentityFile) ? charptr = (opcode == oIdentityFile) ?
&options->identity_files[*intptr] : &options->identity_files[*intptr] :
&options->identity_files2[*intptr]; &options->identity_files2[*intptr];
*charptr = xstrdup(cp); *charptr = xstrdup(arg);
*intptr = *intptr + 1; *intptr = *intptr + 1;
} }
break; break;
case oXAuthLocation:
charptr=&options->xauth_location;
goto parse_string;
case oUser: case oUser:
charptr = &options->user; charptr = &options->user;
parse_string: parse_string:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep && *charptr == NULL) if (*activep && *charptr == NULL)
*charptr = xstrdup(cp); *charptr = xstrdup(arg);
break; break;
case oGlobalKnownHostsFile: case oGlobalKnownHostsFile:
@ -447,10 +448,10 @@ process_config_line(Options *options, const char *host,
case oProxyCommand: case oProxyCommand:
charptr = &options->proxy_command; charptr = &options->proxy_command;
string = xstrdup(""); string = xstrdup("");
while ((cp = strtok(NULL, WHITESPACE)) != NULL) { while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
string = xrealloc(string, strlen(string) + strlen(cp) + 2); string = xrealloc(string, strlen(string) + strlen(arg) + 2);
strcat(string, " "); strcat(string, " ");
strcat(string, cp); strcat(string, arg);
} }
if (*activep && *charptr == NULL) if (*activep && *charptr == NULL)
*charptr = string; *charptr = string;
@ -461,15 +462,15 @@ process_config_line(Options *options, const char *host,
case oPort: case oPort:
intptr = &options->port; intptr = &options->port;
parse_int: parse_int:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (cp[0] < '0' || cp[0] > '9') if (arg[0] < '0' || arg[0] > '9')
fatal("%.200s line %d: Bad number.", filename, linenum); fatal("%.200s line %d: Bad number.", filename, linenum);
/* Octal, decimal, or hex format? */ /* Octal, decimal, or hex format? */
value = strtol(cp, &cp2, 0); value = strtol(arg, &endofnumber, 0);
if (cp == cp2) if (arg == endofnumber)
fatal("%.200s line %d: Bad number.", filename, linenum); fatal("%.200s line %d: Bad number.", filename, linenum);
if (*activep && *intptr == -1) if (*activep && *intptr == -1)
*intptr = value; *intptr = value;
@ -481,65 +482,65 @@ process_config_line(Options *options, const char *host,
case oCipher: case oCipher:
intptr = &options->cipher; intptr = &options->cipher;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
value = cipher_number(cp); value = cipher_number(arg);
if (value == -1) if (value == -1)
fatal("%.200s line %d: Bad cipher '%s'.", fatal("%.200s line %d: Bad cipher '%s'.",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == -1) if (*activep && *intptr == -1)
*intptr = value; *intptr = value;
break; break;
case oCiphers: case oCiphers:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!ciphers_valid(cp)) if (!ciphers_valid(arg))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->ciphers == NULL) if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(cp); options->ciphers = xstrdup(arg);
break; break;
case oProtocol: case oProtocol:
intptr = &options->protocol; intptr = &options->protocol;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
value = proto_spec(cp); value = proto_spec(arg);
if (value == SSH_PROTO_UNKNOWN) if (value == SSH_PROTO_UNKNOWN)
fatal("%.200s line %d: Bad protocol spec '%s'.", fatal("%.200s line %d: Bad protocol spec '%s'.",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == SSH_PROTO_UNKNOWN) if (*activep && *intptr == SSH_PROTO_UNKNOWN)
*intptr = value; *intptr = value;
break; break;
case oLogLevel: case oLogLevel:
intptr = (int *) &options->log_level; intptr = (int *) &options->log_level;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
value = log_level_number(cp); value = log_level_number(arg);
if (value == (LogLevel) - 1) if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n", fatal("%.200s line %d: unsupported log level '%s'\n",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) * intptr == -1) if (*activep && (LogLevel) * intptr == -1)
*intptr = (LogLevel) value; *intptr = (LogLevel) value;
break; break;
case oRemoteForward: case oRemoteForward:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (cp[0] < '0' || cp[0] > '9') if (arg[0] < '0' || arg[0] > '9')
fatal("%.200s line %d: Badly formatted port number.", fatal("%.200s line %d: Badly formatted port number.",
filename, linenum); filename, linenum);
fwd_port = atoi(cp); fwd_port = atoi(arg);
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.", fatal("%.200s line %d: Missing second argument.",
filename, linenum); filename, linenum);
if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.", fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum); filename, linenum);
if (*activep) if (*activep)
@ -547,18 +548,18 @@ process_config_line(Options *options, const char *host,
break; break;
case oLocalForward: case oLocalForward:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (cp[0] < '0' || cp[0] > '9') if (arg[0] < '0' || arg[0] > '9')
fatal("%.200s line %d: Badly formatted port number.", fatal("%.200s line %d: Badly formatted port number.",
filename, linenum); filename, linenum);
fwd_port = atoi(cp); fwd_port = atoi(arg);
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.", fatal("%.200s line %d: Missing second argument.",
filename, linenum); filename, linenum);
if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.", fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum); filename, linenum);
if (*activep) if (*activep)
@ -567,26 +568,26 @@ process_config_line(Options *options, const char *host,
case oHost: case oHost:
*activep = 0; *activep = 0;
while ((cp = strtok(NULL, WHITESPACE)) != NULL) while ((arg = strdelim(&s)) != NULL && *arg != '\0')
if (match_pattern(host, cp)) { if (match_pattern(host, arg)) {
debug("Applying options for %.100s", cp); debug("Applying options for %.100s", arg);
*activep = 1; *activep = 1;
break; break;
} }
/* Avoid garbage check below, as strtok already returned NULL. */ /* Avoid garbage check below, as strdelim is done. */
return 0; return 0;
case oEscapeChar: case oEscapeChar:
intptr = &options->escape_char; intptr = &options->escape_char;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&s);
if (!cp) if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (cp[0] == '^' && cp[2] == 0 && if (arg[0] == '^' && arg[2] == 0 &&
(unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128) (unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
value = (unsigned char) cp[1] & 31; value = (unsigned char) arg[1] & 31;
else if (strlen(cp) == 1) else if (strlen(arg) == 1)
value = (unsigned char) cp[0]; value = (unsigned char) arg[0];
else if (strcmp(cp, "none") == 0) else if (strcmp(arg, "none") == 0)
value = -2; value = -2;
else { else {
fatal("%.200s line %d: Bad escape character.", fatal("%.200s line %d: Bad escape character.",
@ -603,9 +604,11 @@ process_config_line(Options *options, const char *host,
} }
/* Check that there is no garbage at end of line. */ /* Check that there is no garbage at end of line. */
if (strtok(NULL, WHITESPACE) != NULL) if ((arg = strdelim(&s)) != NULL && *arg != '\0')
fatal("%.200s line %d: garbage at end of line.", {
filename, linenum); fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
}
return 0; return 0;
} }
@ -662,6 +665,7 @@ initialize_options(Options * options)
memset(options, 'X', sizeof(*options)); memset(options, 'X', sizeof(*options));
options->forward_agent = -1; options->forward_agent = -1;
options->forward_x11 = -1; options->forward_x11 = -1;
options->xauth_location = NULL;
options->gateway_ports = -1; options->gateway_ports = -1;
options->use_privileged_port = -1; options->use_privileged_port = -1;
options->rhosts_authentication = -1; options->rhosts_authentication = -1;
@ -722,6 +726,10 @@ fill_default_options(Options * options)
options->forward_agent = 0; options->forward_agent = 0;
if (options->forward_x11 == -1) if (options->forward_x11 == -1)
options->forward_x11 = 0; options->forward_x11 = 0;
#ifdef XAUTH_PATH
if (options->xauth_location == NULL)
options->xauth_location = XAUTH_PATH;
#endif /* XAUTH_PATH */
if (options->gateway_ports == -1) if (options->gateway_ports == -1)
options->gateway_ports = 0; options->gateway_ports = 0;
if (options->use_privileged_port == -1) if (options->use_privileged_port == -1)

View File

@ -1,20 +1,18 @@
/* /*
*
* readconf.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Sat Apr 22 00:25:29 1995 ylo
*
* Functions for reading the configuration file. * Functions for reading the configuration file.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
/* RCSID("$Id: readconf.h,v 1.18 2000/05/08 17:12:15 markus Exp $"); */ /* RCSID("$OpenBSD: readconf.h,v 1.21 2000/09/07 20:27:53 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef READCONF_H #ifndef READCONF_H
#define READCONF_H #define READCONF_H
@ -31,6 +29,7 @@ typedef struct {
typedef struct { typedef struct {
int forward_agent; /* Forward authentication agent. */ int forward_agent; /* Forward authentication agent. */
int forward_x11; /* Forward X11 display. */ int forward_x11; /* Forward X11 display. */
char *xauth_location; /* Location for xauth program */
int gateway_ports; /* Allow remote connects to forwarded ports. */ int gateway_ports; /* Allow remote connects to forwarded ports. */
int use_privileged_port; /* Don't use privileged port if false. */ int use_privileged_port; /* Don't use privileged port if false. */
int rhosts_authentication; /* Try rhosts authentication. */ int rhosts_authentication; /* Try rhosts authentication. */

View File

@ -1,15 +1,40 @@
/* /*
*
* rsa.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Created: Fri Mar 3 22:07:06 1995 ylo * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
* *
* Description of the RSA algorithm can be found e.g. from the following sources: * Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Description of the RSA algorithm can be found e.g. from the following
* sources:
* *
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
* *
@ -25,18 +50,18 @@
* Hans Riesel: Prime Numbers and Computer Methods for Factorization. * Hans Riesel: Prime Numbers and Computer Methods for Factorization.
* Birkhauser, 1994. * Birkhauser, 1994.
* *
* The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995. * The RSA Frequently Asked Questions document by RSA Data Security,
* Inc., 1995.
* *
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included * RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as
* below: * included below:
* *
* [gone - had to be deleted - what a pity] * [gone - had to be deleted - what a pity]
* */
* $FreeBSD$
*/
#include "includes.h" #include "includes.h"
RCSID("$Id: rsa.c,v 1.14 2000/04/14 10:30:32 markus Exp $"); RCSID("$OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp $");
RCSID("$FreeBSD$");
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh.h"

View File

@ -1,20 +1,18 @@
/* /*
*
* rsa.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Fri Mar 3 22:01:06 1995 ylo
*
* RSA key generation, encryption and decryption. * RSA key generation, encryption and decryption.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
*/ * can be used freely for any purpose. Any derived versions of this
* 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".
*/
/* RCSID("$Id: rsa.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */ /* RCSID("$OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef RSA_H #ifndef RSA_H
#define RSA_H #define RSA_H

View File

@ -1,19 +1,17 @@
/* /*
*
* servconf.c
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Created: Mon Aug 21 15:48:58 1995 ylo * As far as I am concerned, the code I have written for this software
* * can be used freely for any purpose. Any derived versions of this
* $FreeBSD$ * 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: servconf.c,v 1.41 2000/05/22 18:42:01 markus Exp $"); RCSID("$OpenBSD: servconf.c,v 1.51 2000/09/07 20:27:53 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "servconf.h" #include "servconf.h"
@ -45,6 +43,7 @@ initialize_server_options(ServerOptions *options)
options->check_mail = -1; options->check_mail = -1;
options->x11_forwarding = -1; options->x11_forwarding = -1;
options->x11_display_offset = -1; options->x11_display_offset = -1;
options->xauth_location = NULL;
options->strict_modes = -1; options->strict_modes = -1;
options->keepalives = -1; options->keepalives = -1;
options->log_facility = (SyslogFacility) - 1; options->log_facility = (SyslogFacility) - 1;
@ -81,6 +80,10 @@ initialize_server_options(ServerOptions *options)
options->gateway_ports = -1; options->gateway_ports = -1;
options->connections_per_period = 0; options->connections_per_period = 0;
options->connections_period = 0; options->connections_period = 0;
options->num_subsystems = 0;
options->max_startups_begin = -1;
options->max_startups_rate = -1;
options->max_startups = -1;
} }
void void
@ -116,6 +119,10 @@ fill_default_server_options(ServerOptions *options)
options->x11_forwarding = 1; options->x11_forwarding = 1;
if (options->x11_display_offset == -1) if (options->x11_display_offset == -1)
options->x11_display_offset = 10; options->x11_display_offset = 10;
#ifdef XAUTH_PATH
if (options->xauth_location == NULL)
options->xauth_location = XAUTH_PATH;
#endif /* XAUTH_PATH */
if (options->strict_modes == -1) if (options->strict_modes == -1)
options->strict_modes = 1; options->strict_modes = 1;
if (options->keepalives == -1) if (options->keepalives == -1)
@ -166,10 +173,14 @@ fill_default_server_options(ServerOptions *options)
options->protocol = SSH_PROTO_1|SSH_PROTO_2; options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->gateway_ports == -1) if (options->gateway_ports == -1)
options->gateway_ports = 0; options->gateway_ports = 0;
if (options->max_startups == -1)
options->max_startups = 10;
if (options->max_startups_rate == -1)
options->max_startups_rate = 100; /* 100% */
if (options->max_startups_begin == -1)
options->max_startups_begin = options->max_startups;
} }
#define WHITESPACE " \t\r\n"
/* Keyword tokens. */ /* Keyword tokens. */
typedef enum { typedef enum {
sBadOption, /* == unknown option */ sBadOption, /* == unknown option */
@ -193,7 +204,8 @@ typedef enum {
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
sGatewayPorts, sDSAAuthentication, sConnectionsPerPeriod sGatewayPorts, sDSAAuthentication, sConnectionsPerPeriod, sXAuthLocation,
sSubsystem, sMaxStartups
} ServerOpCodes; } ServerOpCodes;
/* Textual representation of the tokens. */ /* Textual representation of the tokens. */
@ -239,6 +251,7 @@ static struct {
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts }, { "ignoreuserknownhosts", sIgnoreUserKnownHosts },
{ "x11forwarding", sX11Forwarding }, { "x11forwarding", sX11Forwarding },
{ "x11displayoffset", sX11DisplayOffset }, { "x11displayoffset", sX11DisplayOffset },
{ "xauthlocation", sXAuthLocation },
{ "strictmodes", sStrictModes }, { "strictmodes", sStrictModes },
{ "permitemptypasswords", sEmptyPasswd }, { "permitemptypasswords", sEmptyPasswd },
{ "uselogin", sUseLogin }, { "uselogin", sUseLogin },
@ -252,6 +265,8 @@ static struct {
{ "protocol", sProtocol }, { "protocol", sProtocol },
{ "gatewayports", sGatewayPorts }, { "gatewayports", sGatewayPorts },
{ "connectionsperperiod", sConnectionsPerPeriod }, { "connectionsperperiod", sConnectionsPerPeriod },
{ "subsystem", sSubsystem },
{ "maxstartups", sMaxStartups },
{ NULL, 0 } { NULL, 0 }
}; };
@ -313,10 +328,11 @@ read_server_config(ServerOptions *options, const char *filename)
{ {
FILE *f; FILE *f;
char line[1024]; char line[1024];
char *cp, **charptr; char *cp, **charptr, *arg;
int linenum, *intptr, value; int linenum, *intptr, value;
int bad_options = 0; int bad_options = 0;
ServerOpCodes opcode; ServerOpCodes opcode;
int i;
f = fopen(filename, "r"); f = fopen(filename, "r");
if (!f) { if (!f) {
@ -326,11 +342,14 @@ read_server_config(ServerOptions *options, const char *filename)
linenum = 0; linenum = 0;
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
linenum++; linenum++;
cp = line + strspn(line, WHITESPACE); cp = line;
if (!*cp || *cp == '#') arg = strdelim(&cp);
/* Ignore leading whitespace */
if (*arg == '\0')
arg = strdelim(&cp);
if (!*arg || *arg == '#')
continue; continue;
cp = strtok(cp, WHITESPACE); opcode = parse_token(arg, filename, linenum);
opcode = parse_token(cp, filename, linenum);
switch (opcode) { switch (opcode) {
case sBadOption: case sBadOption:
bad_options++; bad_options++;
@ -345,23 +364,24 @@ read_server_config(ServerOptions *options, const char *filename)
if (options->num_ports >= MAX_PORTS) if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.\n", fatal("%s line %d: too many ports.\n",
filename, linenum); filename, linenum);
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) if (!arg || *arg == '\0')
fatal("%s line %d: missing port number.\n", fatal("%s line %d: missing port number.\n",
filename, linenum); filename, linenum);
options->ports[options->num_ports++] = atoi(cp); options->ports[options->num_ports++] = atoi(arg);
break; break;
case sServerKeyBits: case sServerKeyBits:
intptr = &options->server_key_bits; intptr = &options->server_key_bits;
parse_int: parse_int:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) { if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing integer value.\n", fprintf(stderr, "%s line %d: missing integer value.\n",
filename, linenum); filename, linenum);
exit(1); exit(1);
} }
if (sscanf(cp, " %d ", &value) != 1) { value = atoi(arg);
if (value == 0) {
fprintf(stderr, "%s line %d: invalid integer value.\n", fprintf(stderr, "%s line %d: invalid integer value.\n",
filename, linenum); filename, linenum);
exit(1); exit(1);
@ -379,62 +399,55 @@ read_server_config(ServerOptions *options, const char *filename)
goto parse_int; goto parse_int;
case sListenAddress: case sListenAddress:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) if (!arg || *arg == '\0')
fatal("%s line %d: missing inet addr.\n", fatal("%s line %d: missing inet addr.\n",
filename, linenum); filename, linenum);
add_listen_addr(options, cp); add_listen_addr(options, arg);
break; break;
case sHostKeyFile: case sHostKeyFile:
case sHostDSAKeyFile: case sHostDSAKeyFile:
charptr = (opcode == sHostKeyFile ) ? charptr = (opcode == sHostKeyFile ) ?
&options->host_key_file : &options->host_dsa_key_file; &options->host_key_file : &options->host_dsa_key_file;
cp = strtok(NULL, WHITESPACE); parse_filename:
if (!cp) { arg = strdelim(&cp);
if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing file name.\n", fprintf(stderr, "%s line %d: missing file name.\n",
filename, linenum); filename, linenum);
exit(1); exit(1);
} }
if (*charptr == NULL) if (*charptr == NULL)
*charptr = tilde_expand_filename(cp, getuid()); *charptr = tilde_expand_filename(arg, getuid());
break; break;
case sPidFile: case sPidFile:
charptr = &options->pid_file; charptr = &options->pid_file;
cp = strtok(NULL, WHITESPACE); goto parse_filename;
if (!cp) {
fprintf(stderr, "%s line %d: missing file name.\n",
filename, linenum);
exit(1);
}
if (*charptr == NULL)
*charptr = tilde_expand_filename(cp, getuid());
break;
case sRandomSeedFile: case sRandomSeedFile:
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n", fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
filename, linenum); filename, linenum);
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
break; break;
case sPermitRootLogin: case sPermitRootLogin:
intptr = &options->permit_root_login; intptr = &options->permit_root_login;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) { if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n", fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
filename, linenum); filename, linenum);
exit(1); exit(1);
} }
if (strcmp(cp, "without-password") == 0) if (strcmp(arg, "without-password") == 0)
value = 2; value = 2;
else if (strcmp(cp, "yes") == 0) else if (strcmp(arg, "yes") == 0)
value = 1; value = 1;
else if (strcmp(cp, "no") == 0) else if (strcmp(arg, "no") == 0)
value = 0; value = 0;
else { else {
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n", fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
filename, linenum, cp); filename, linenum, arg);
exit(1); exit(1);
} }
if (*intptr == -1) if (*intptr == -1)
@ -444,19 +457,19 @@ read_server_config(ServerOptions *options, const char *filename)
case sIgnoreRhosts: case sIgnoreRhosts:
intptr = &options->ignore_rhosts; intptr = &options->ignore_rhosts;
parse_flag: parse_flag:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) { if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing yes/no argument.\n", fprintf(stderr, "%s line %d: missing yes/no argument.\n",
filename, linenum); filename, linenum);
exit(1); exit(1);
} }
if (strcmp(cp, "yes") == 0) if (strcmp(arg, "yes") == 0)
value = 1; value = 1;
else if (strcmp(cp, "no") == 0) else if (strcmp(arg, "no") == 0)
value = 0; value = 0;
else { else {
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n", fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
filename, linenum, cp); filename, linenum, arg);
exit(1); exit(1);
} }
if (*intptr == -1) if (*intptr == -1)
@ -543,6 +556,10 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->x11_display_offset; intptr = &options->x11_display_offset;
goto parse_int; goto parse_int;
case sXAuthLocation:
charptr = &options->xauth_location;
goto parse_filename;
case sStrictModes: case sStrictModes:
intptr = &options->strict_modes; intptr = &options->strict_modes;
goto parse_flag; goto parse_flag;
@ -565,92 +582,92 @@ read_server_config(ServerOptions *options, const char *filename)
case sLogFacility: case sLogFacility:
intptr = (int *) &options->log_facility; intptr = (int *) &options->log_facility;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
value = log_facility_number(cp); value = log_facility_number(arg);
if (value == (SyslogFacility) - 1) if (value == (SyslogFacility) - 1)
fatal("%.200s line %d: unsupported log facility '%s'\n", fatal("%.200s line %d: unsupported log facility '%s'\n",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1) if (*intptr == -1)
*intptr = (SyslogFacility) value; *intptr = (SyslogFacility) value;
break; break;
case sLogLevel: case sLogLevel:
intptr = (int *) &options->log_level; intptr = (int *) &options->log_level;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
value = log_level_number(cp); value = log_level_number(arg);
if (value == (LogLevel) - 1) if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n", fatal("%.200s line %d: unsupported log level '%s'\n",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1) if (*intptr == -1)
*intptr = (LogLevel) value; *intptr = (LogLevel) value;
break; break;
case sAllowUsers: case sAllowUsers:
while ((cp = strtok(NULL, WHITESPACE))) { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_users >= MAX_ALLOW_USERS) if (options->num_allow_users >= MAX_ALLOW_USERS)
fatal("%.200s line %d: too many allow users.\n", fatal("%.200s line %d: too many allow users.\n",
filename, linenum); filename, linenum);
options->allow_users[options->num_allow_users++] = xstrdup(cp); options->allow_users[options->num_allow_users++] = xstrdup(arg);
} }
break; break;
case sDenyUsers: case sDenyUsers:
while ((cp = strtok(NULL, WHITESPACE))) { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_users >= MAX_DENY_USERS) if (options->num_deny_users >= MAX_DENY_USERS)
fatal("%.200s line %d: too many deny users.\n", fatal("%.200s line %d: too many deny users.\n",
filename, linenum); filename, linenum);
options->deny_users[options->num_deny_users++] = xstrdup(cp); options->deny_users[options->num_deny_users++] = xstrdup(arg);
} }
break; break;
case sAllowGroups: case sAllowGroups:
while ((cp = strtok(NULL, WHITESPACE))) { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
fatal("%.200s line %d: too many allow groups.\n", fatal("%.200s line %d: too many allow groups.\n",
filename, linenum); filename, linenum);
options->allow_groups[options->num_allow_groups++] = xstrdup(cp); options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
} }
break; break;
case sDenyGroups: case sDenyGroups:
while ((cp = strtok(NULL, WHITESPACE))) { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_groups >= MAX_DENY_GROUPS) if (options->num_deny_groups >= MAX_DENY_GROUPS)
fatal("%.200s line %d: too many deny groups.\n", fatal("%.200s line %d: too many deny groups.\n",
filename, linenum); filename, linenum);
options->deny_groups[options->num_deny_groups++] = xstrdup(cp); options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
} }
break; break;
case sCiphers: case sCiphers:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum); fatal("%s line %d: Missing argument.", filename, linenum);
if (!ciphers_valid(cp)) if (!ciphers_valid(arg))
fatal("%s line %d: Bad SSH2 cipher spec '%s'.", fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (options->ciphers == NULL) if (options->ciphers == NULL)
options->ciphers = xstrdup(cp); options->ciphers = xstrdup(arg);
break; break;
case sProtocol: case sProtocol:
intptr = &options->protocol; intptr = &options->protocol;
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (!cp) if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum); fatal("%s line %d: Missing argument.", filename, linenum);
value = proto_spec(cp); value = proto_spec(arg);
if (value == SSH_PROTO_UNKNOWN) if (value == SSH_PROTO_UNKNOWN)
fatal("%s line %d: Bad protocol spec '%s'.", fatal("%s line %d: Bad protocol spec '%s'.",
filename, linenum, cp ? cp : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*intptr == SSH_PROTO_UNKNOWN) if (*intptr == SSH_PROTO_UNKNOWN)
*intptr = value; *intptr = value;
break; break;
case sConnectionsPerPeriod: case sConnectionsPerPeriod:
cp = strtok(NULL, WHITESPACE); arg = strdelim(&cp);
if (cp == NULL) if (cp == NULL)
fatal("%.200s line %d: missing (>= 0) number argument.\n", fatal("%.200s line %d: missing (>= 0) number argument.\n",
filename, linenum); filename, linenum);
if (sscanf(cp, " %u/%u ", &options->connections_per_period, if (sscanf(arg, "%u/%u", &options->connections_per_period,
&options->connections_period) != 2) &options->connections_period) != 2)
fatal("%.200s line %d: invalid numerical argument(s).\n", fatal("%.200s line %d: invalid numerical argument(s).\n",
filename, linenum); filename, linenum);
@ -660,13 +677,57 @@ read_server_config(ServerOptions *options, const char *filename)
filename, linenum); filename, linenum);
break; 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 (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;
default: default:
fatal("%.200s line %d: Missing handler for opcode %s (%d)\n", fatal("%.200s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, cp, opcode); filename, linenum,arg, opcode);
} }
if (strtok(NULL, WHITESPACE) != NULL) { if ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
fatal("%.200s line %d: garbage at end of line.\n", fprintf(stderr,
filename, linenum); "%s line %d: garbage at end of line; \"%.200s\".\n",
filename, linenum, arg);
exit(1);
} }
} }
fclose(f); fclose(f);

View File

@ -1,20 +1,18 @@
/* /*
*
* servconf.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*
* Created: Mon Aug 21 15:35:03 1995 ylo
*
* Definitions for server configuration data and for the functions reading it. * Definitions for server configuration data and for the functions reading it.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
/* RCSID("$Id: servconf.h,v 1.22 2000/05/06 17:45:37 markus Exp $"); */ /* RCSID("$OpenBSD: servconf.h,v 1.28 2000/09/07 20:27:53 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef SERVCONF_H #ifndef SERVCONF_H
#define SERVCONF_H #define SERVCONF_H
@ -25,6 +23,7 @@
#define MAX_DENY_USERS 256 /* Max # users on deny list. */ #define MAX_DENY_USERS 256 /* Max # users on deny list. */
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
typedef struct { typedef struct {
unsigned int num_ports; unsigned int num_ports;
@ -48,6 +47,7 @@ typedef struct {
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start int x11_display_offset; /* What DISPLAY number to start
* searching at */ * searching at */
char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */ int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */ int keepalives; /* If true, set SO_KEEPALIVE. */
char *ciphers; /* Ciphers in order of preference. */ char *ciphers; /* Ciphers in order of preference. */
@ -105,6 +105,15 @@ typedef struct {
* connections_period. * connections_period.
*/ */
unsigned int connections_period; unsigned int connections_period;
unsigned int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
int max_startups_begin;
int max_startups_rate;
int max_startups;
} ServerOptions; } ServerOptions;
/* /*
* Initializes the server options to special values that indicate that they * Initializes the server options to special values that indicate that they

View File

@ -1,16 +1,40 @@
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
*/ *
/* * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
* SSH2 support by Markus Friedl. * SSH2 support by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* $FreeBSD$ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: session.c,v 1.15 2000/05/30 17:23:37 markus Exp $"); RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -28,14 +52,15 @@ RCSID("$OpenBSD: session.c,v 1.15 2000/05/30 17:23:37 markus Exp $");
#include "bufaux.h" #include "bufaux.h"
#include "ssh2.h" #include "ssh2.h"
#include "auth.h" #include "auth.h"
#include "auth-options.h"
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#define _PATH_CHPASS "/usr/bin/passwd" #define _PATH_CHPASS "/usr/bin/passwd"
#endif /* __FreeBSD__ */ #endif /* __FreeBSD__ */
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
#include <login_cap.h> #include <login_cap.h>
#endif /* LOGIN_CAP */ #endif
#ifdef KRB5 #ifdef KRB5
extern krb5_context ssh_context; extern krb5_context ssh_context;
@ -74,6 +99,7 @@ void session_pty_cleanup(Session *s);
void session_proctitle(Session *s); void session_proctitle(Session *s);
void do_exec_pty(Session *s, const char *command, struct passwd * pw); void do_exec_pty(Session *s, const char *command, struct passwd * pw);
void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); void do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
char *do_login(Session *s, const char *command);
void void
do_child(const char *command, struct passwd * pw, const char *term, do_child(const char *command, struct passwd * pw, const char *term,
@ -85,25 +111,23 @@ extern ServerOptions options;
extern char *__progname; extern char *__progname;
extern int log_stderr; extern int log_stderr;
extern int debug_flag; extern int debug_flag;
extern unsigned int utmp_len;
extern int startup_pipe;
/* Local Xauthority file. */ /* Local Xauthority file. */
static char *xauthfile; static char *xauthfile;
/* original command from peer. */
char *original_command = NULL;
/* data */ /* data */
#define MAX_SESSIONS 10 #define MAX_SESSIONS 10
Session sessions[MAX_SESSIONS]; Session sessions[MAX_SESSIONS];
/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ #ifdef HAVE_LOGIN_CAP
int no_port_forwarding_flag = 0; static login_cap_t *lc;
int no_agent_forwarding_flag = 0; #endif
int no_x11_forwarding_flag = 0;
int no_pty_flag = 0;
/* RSA authentication "command=" option. */
char *forced_command = NULL;
/* RSA authentication "environment=" options. */
struct envstring *custom_environment = NULL;
/* /*
* Remove local Xauthority file. * Remove local Xauthority file.
@ -157,7 +181,7 @@ void
do_authenticated(struct passwd * pw) do_authenticated(struct passwd * pw)
{ {
Session *s; Session *s;
int type; int type, fd;
int compression_level = 0, enable_compression_after_reply = 0; int compression_level = 0, enable_compression_after_reply = 0;
int have_pty = 0; int have_pty = 0;
char *command; char *command;
@ -170,6 +194,10 @@ do_authenticated(struct passwd * pw)
* authentication. * authentication.
*/ */
alarm(0); alarm(0);
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
/* /*
* Inform the channel mechanism that we are the server side and that * Inform the channel mechanism that we are the server side and that
@ -184,6 +212,13 @@ do_authenticated(struct passwd * pw)
s = session_new(); s = session_new();
s->pw = pw; s->pw = pw;
#ifdef HAVE_LOGIN_CAP
if ((lc = login_getclass(pw->pw_class)) == NULL) {
error("unable to get login class");
return;
}
#endif
/* /*
* We stay in this loop until the client requests to execute a shell * We stay in this loop until the client requests to execute a shell
* or a command. * or a command.
@ -262,7 +297,10 @@ do_authenticated(struct passwd * pw)
packet_send_debug("X11 forwarding disabled in server configuration file."); packet_send_debug("X11 forwarding disabled in server configuration file.");
break; break;
} }
#ifdef XAUTH_PATH if (!options.xauth_location) {
packet_send_debug("No xauth program; cannot forward with spoofing.");
break;
}
if (no_x11_forwarding_flag) { if (no_x11_forwarding_flag) {
packet_send_debug("X11 forwarding not permitted for this authentication."); packet_send_debug("X11 forwarding not permitted for this authentication.");
break; break;
@ -298,15 +336,13 @@ do_authenticated(struct passwd * pw)
break; break;
} }
strlcat(xauthfile, "/cookies", MAXPATHLEN); strlcat(xauthfile, "/cookies", MAXPATHLEN);
open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd >= 0)
close(fd);
restore_uid(); restore_uid();
fatal_add_cleanup(xauthfile_cleanup_proc, NULL); fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
success = 1; success = 1;
break; break;
#else /* XAUTH_PATH */
packet_send_debug("No xauth program; cannot forward with spoofing.");
break;
#endif /* XAUTH_PATH */
case SSH_CMSG_AGENT_REQUEST_FORWARDING: case SSH_CMSG_AGENT_REQUEST_FORWARDING:
if (no_agent_forwarding_flag || compat13) { if (no_agent_forwarding_flag || compat13) {
@ -347,6 +383,7 @@ do_authenticated(struct passwd * pw)
packet_integrity_check(plen, 0, type); packet_integrity_check(plen, 0, type);
} }
if (forced_command != NULL) { if (forced_command != NULL) {
original_command = command;
command = forced_command; command = forced_command;
debug("Forced command '%.500s'", forced_command); debug("Forced command '%.500s'", forced_command);
} }
@ -506,50 +543,17 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
void void
do_exec_pty(Session *s, const char *command, struct passwd * pw) do_exec_pty(Session *s, const char *command, struct passwd * pw)
{ {
FILE *f;
char buf[100], *time_string;
char line[256];
const char *hostname;
int fdout, ptyfd, ttyfd, ptymaster; int fdout, ptyfd, ttyfd, ptymaster;
int quiet_login;
pid_t pid; pid_t pid;
socklen_t fromlen;
struct sockaddr_storage from;
struct stat st;
time_t last_login_time;
#ifdef LOGIN_CAP
login_cap_t *lc;
char *fname;
#endif /* LOGIN_CAP */
#ifdef __FreeBSD__
#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
struct timeval tv;
time_t warntime = DEFAULT_WARN;
#endif /* __FreeBSD__ */
if (s == NULL) if (s == NULL)
fatal("do_exec_pty: no session"); fatal("do_exec_pty: no session");
ptyfd = s->ptyfd; ptyfd = s->ptyfd;
ttyfd = s->ttyfd; ttyfd = s->ttyfd;
/* Get remote host name. */
hostname = get_canonical_hostname();
/*
* Get the time when the user last logged in. Buf will be set to
* contain the hostname the last login was from.
*/
if (!options.use_login) {
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
buf, sizeof(buf));
}
/* Fork the child. */ /* Fork the child. */
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
pid = getpid(); /* Child. Reinitialize the log because the pid has changed. */
/* Child. Reinitialize the log because the pid has
changed. */
log_init(__progname, options.log_level, options.log_facility, log_stderr); log_init(__progname, options.log_level, options.log_facility, log_stderr);
/* Close the master side of the pseudo tty. */ /* Close the master side of the pseudo tty. */
@ -573,152 +577,9 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
/* Close the extra descriptor for the pseudo tty. */ /* Close the extra descriptor for the pseudo tty. */
close(ttyfd); close(ttyfd);
/* XXXX ? move to do_child() ??*/ /* record login, etc. similar to login(1) */
/* if (!options.use_login)
* Get IP address of client. This is needed because we want command = do_login(s, command);
* to record where the user logged in from. If the
* connection is not a socket, let the ip address be 0.0.0.0.
*/
memset(&from, 0, sizeof(from));
if (packet_connection_is_on_socket()) {
fromlen = sizeof(from);
if (getpeername(packet_get_connection_in(),
(struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
fatal_cleanup();
}
}
/* Record that there was a login on that terminal. */
record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname,
(struct sockaddr *)&from);
/* Check if .hushlogin exists. */
snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
quiet_login = stat(line, &st) >= 0;
#ifdef LOGIN_CAP
lc = login_getpwclass(pw);
if (lc == NULL)
lc = login_getclassbyname(NULL, pw);
quiet_login = login_getcapbool(lc, "hushlogin", quiet_login);
#endif /* LOGIN_CAP */
#ifdef __FreeBSD__
if (pw->pw_change || pw->pw_expire)
(void)gettimeofday(&tv, NULL);
#ifdef LOGIN_CAP
warntime = login_getcaptime(lc, "warnpassword",
DEFAULT_WARN, DEFAULT_WARN);
#endif /* LOGIN_CAP */
/*
* If the password change time is set and has passed, give the
* user a password expiry notice and chance to change it.
*/
if (pw->pw_change != 0) {
if (tv.tv_sec >= pw->pw_change) {
(void)printf(
"Sorry -- your password has expired.\n");
log("%s Password expired - forcing change",
pw->pw_name);
command = _PATH_CHPASS;
} else if (pw->pw_change - tv.tv_sec < warntime &&
!quiet_login)
(void)printf(
"Warning: your password expires on %s",
ctime(&pw->pw_change));
}
#ifdef LOGIN_CAP
warntime = login_getcaptime(lc, "warnexpire",
DEFAULT_WARN, DEFAULT_WARN);
#endif /* LOGIN_CAP */
if (pw->pw_expire) {
if (tv.tv_sec >= pw->pw_expire) {
(void)printf(
"Sorry -- your account has expired.\n");
log(
"LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s",
pw->pw_name, hostname, s->tty);
exit(254);
} else if (pw->pw_expire - tv.tv_sec < warntime &&
!quiet_login)
(void)printf(
"Warning: your account expires on %s",
ctime(&pw->pw_expire));
}
#endif /* __FreeBSD__ */
#ifdef 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, hostname, s->tty);
exit(254);
}
#endif /* LOGIN_CAP */
/*
* If the user has logged in before, display the time of last
* login. However, don't display anything extra if a command
* has been specified (so that ssh can be used to execute
* commands on a remote machine without users knowing they
* are going to another machine). Login(1) will do this for
* us as well, so check if login(1) is used
*/
if (command == NULL && last_login_time != 0 && !quiet_login &&
!options.use_login) {
/* Convert the date to a string. */
time_string = ctime(&last_login_time);
/* Remove the trailing newline. */
if (strchr(time_string, '\n'))
*strchr(time_string, '\n') = 0;
/* Display the last login time. Host if displayed
if known. */
if (strcmp(buf, "") == 0)
printf("Last login: %s\r\n", time_string);
else
printf("Last login: %s from %s\r\n", time_string, buf);
}
#ifdef LOGIN_CAP
if (command == NULL && !quiet_login && !options.use_login) {
fname = login_getcapstr(lc, "copyright", NULL, NULL);
if (fname != NULL && (f = fopen(fname, "r")) != NULL) {
while (fgets(line, sizeof(line), f) != NULL)
fputs(line, stdout);
fclose(f);
} else
(void)printf("%s\n\t%s %s\n",
"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
"The Regents of the University of California. ",
"All rights reserved.");
}
#endif /* LOGIN_CAP */
/*
* Print /etc/motd unless a command was specified or printing
* it was disabled in server options or login(1) will be
* used. Note that some machines appear to print it in
* /etc/profile or similar.
*/
if (command == NULL && options.print_motd && !quiet_login &&
!options.use_login) {
#ifdef LOGIN_CAP
fname = login_getcapstr(lc, "welcome", NULL, NULL);
if (fname == NULL || (f = fopen(fname, "r")) == NULL)
f = fopen("/etc/motd", "r");
#else /* !LOGIN_CAP */
f = fopen("/etc/motd", "r");
#endif /* LOGIN_CAP */
/* Print /etc/motd if it exists. */
if (f) {
while (fgets(line, sizeof(line), f))
fputs(line, stdout);
fclose(f);
}
}
#ifdef LOGIN_CAP
login_close(lc);
#endif /* LOGIN_CAP */
/* Do common processing for the child, such as execing the command. */ /* Do common processing for the child, such as execing the command. */
do_child(command, pw, s->term, s->display, s->auth_proto, do_child(command, pw, s->term, s->display, s->auth_proto,
@ -757,6 +618,197 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
} }
} }
const char *
get_remote_name_or_ip(void)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname();
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
}
/* administrative, login(1)-like work */
char *
do_login(Session *s, const char *command)
{
FILE *f;
char *time_string, *newcommand;
char buf[256];
char hostname[MAXHOSTNAMELEN];
int quiet_login;
socklen_t fromlen;
struct sockaddr_storage from;
struct stat st;
time_t last_login_time;
struct passwd * pw = s->pw;
pid_t pid = getpid();
#ifdef HAVE_LOGIN_CAP
login_cap_t *lc;
char *fname;
#endif /* HAVE_LOGIN_CAP */
#ifdef __FreeBSD__
#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
struct timeval tv;
time_t warntime = DEFAULT_WARN;
#endif /* __FreeBSD__ */
newcommand = (char *)command;
/*
* Get IP address of client. If the connection is not a socket, let
* the address be 0.0.0.0.
*/
memset(&from, 0, sizeof(from));
if (packet_connection_is_on_socket()) {
fromlen = sizeof(from);
if (getpeername(packet_get_connection_in(),
(struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
fatal_cleanup();
}
}
/* Get the time and hostname when the user last logged in. */
hostname[0] = '\0';
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
hostname, sizeof(hostname));
/* 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(), (struct sockaddr *)&from);
/* Done if .hushlogin exists. */
snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
lc = login_getpwclass(pw);
if (lc == NULL)
lc = login_getclassbyname(NULL, pw);
quiet_login = login_getcapbool(lc, "hushlogin", quiet_login) || stat(buf, &st) >= 0;
#else
quiet_login = stat(line, &st) >= 0;
#endif /* HAVE_LOGIN_CAP */
#ifdef __FreeBSD__
if (pw->pw_change || pw->pw_expire)
(void)gettimeofday(&tv, NULL);
#ifdef HAVE_LOGIN_CAP
warntime = login_getcaptime(lc, "warnpassword",
DEFAULT_WARN, DEFAULT_WARN);
#endif /* HAVE_LOGIN_CAP */
/*
* If the password change time is set and has passed, give the
* user a password expiry notice and chance to change it.
*/
if (pw->pw_change != 0) {
if (tv.tv_sec >= pw->pw_change) {
(void)printf(
"Sorry -- your password has expired.\n");
log("%s Password expired - forcing change",
pw->pw_name);
newcommand = _PATH_CHPASS;
} else if (pw->pw_change - tv.tv_sec < warntime &&
!quiet_login)
(void)printf(
"Warning: your password expires on %s",
ctime(&pw->pw_change));
}
#ifdef HAVE_LOGIN_CAP
warntime = login_getcaptime(lc, "warnexpire",
DEFAULT_WARN, DEFAULT_WARN);
#endif /* HAVE_LOGIN_CAP */
if (pw->pw_expire) {
if (tv.tv_sec >= pw->pw_expire) {
(void)printf(
"Sorry -- your account has expired.\n");
log(
"LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s",
pw->pw_name, get_remote_name_or_ip(), s->tty);
exit(254);
} else if (pw->pw_expire - tv.tv_sec < warntime &&
!quiet_login)
(void)printf(
"Warning: your account expires on %s",
ctime(&pw->pw_expire));
}
#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(), s->tty);
exit(254);
}
#endif /* HAVE_LOGIN_CAP */
/*
* If the user has logged in before, display the time of last
* login. However, don't display anything extra if a command
* has been specified (so that ssh can be used to execute
* commands on a remote machine without users knowing they
* are going to another machine). Login(1) will do this for
* us as well, so check if login(1) is used
*/
if (newcommand == NULL && last_login_time != 0 && !quiet_login &&
!options.use_login) {
/* Convert the date to a string. */
time_string = ctime(&last_login_time);
/* Remove the trailing newline. */
if (strchr(time_string, '\n'))
*strchr(time_string, '\n') = 0;
/* Display the last login time. Host if displayed
if known. */
if (strcmp(buf, "") == 0)
printf("Last login: %s\r\n", time_string);
else
printf("Last login: %s from %s\r\n", time_string, hostname);
}
#ifdef HAVE_LOGIN_CAP
if (newcommand == NULL && !quiet_login && !options.use_login) {
fname = login_getcapstr(lc, "copyright", NULL, NULL);
if (fname != NULL && (f = fopen(fname, "r")) != NULL) {
while (fgets(buf, sizeof(buf), f) != NULL)
fputs(buf, stdout);
fclose(f);
} else
(void)printf("%s\n\t%s %s\n",
"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
"The Regents of the University of California. ",
"All rights reserved.");
}
#endif /* HAVE_LOGIN_CAP */
/*
* Print /etc/motd unless a command was specified or printing
* it was disabled in server options or login(1) will be
* used. Note that some machines appear to print it in
* /etc/profile or similar.
*/
if (newcommand == NULL && options.print_motd && !quiet_login &&
!options.use_login) {
#ifdef HAVE_LOGIN_CAP
f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
"/etc/motd"), "r");
#else /* !HAVE_LOGIN_CAP */
f = fopen("/etc/motd", "r");
#endif /* HAVE_LOGIN_CAP */
if (f) {
while (fgets(buf, sizeof(buf), f))
fputs(buf, stdout);
fclose(f);
}
}
#ifdef HAVE_LOGIN_CAP
login_close(lc);
#endif /* HAVE_LOGIN_CAP */
return newcommand;
}
/* /*
* Sets the value of the given variable in the environment. If the variable * Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden. * already exists, its value is overriden.
@ -847,16 +899,16 @@ do_child(const char *command, struct passwd * pw, const char *term,
const char *display, const char *auth_proto, const char *display, const char *auth_proto,
const char *auth_data, const char *ttyname) const char *auth_data, const char *ttyname)
{ {
char *shell; const char *shell, *hostname = NULL, *cp = NULL;
const char *cp = NULL;
char buf[256]; char buf[256];
FILE *f; char cmd[1024];
FILE *f = NULL;
unsigned int envsize, i; unsigned int envsize, i;
char **env = NULL; char **env = NULL;
extern char **environ; extern char **environ;
struct stat st; struct stat st;
char *argv[10]; char *argv[10];
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_cap_t *lc; login_cap_t *lc;
#endif #endif
@ -864,36 +916,32 @@ do_child(const char *command, struct passwd * pw, const char *term,
if (options.use_login && command != NULL) if (options.use_login && command != NULL)
options.use_login = 0; options.use_login = 0;
#ifdef LOGIN_CAP if (!options.use_login) {
lc = login_getpwclass(pw); #ifdef HAVE_LOGIN_CAP
if (lc == NULL) lc = login_getpwclass(pw);
lc = login_getclassbyname(NULL, pw); if (lc == NULL)
if (pw->pw_uid != 0) lc = login_getclassbyname(NULL, pw);
auth_checknologin(lc);
#else /* !LOGIN_CAP */
f = fopen("/etc/nologin", "r");
if (f) {
/* /etc/nologin exists. Print its contents and exit. */
while (fgets(buf, sizeof(buf), f))
fputs(buf, stderr);
fclose(f);
if (pw->pw_uid != 0) if (pw->pw_uid != 0)
auth_checknologin(lc);
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); exit(254);
}
} }
#endif /* LOGIN_CAP */ /* Set login name, uid, gid, and groups. */
#ifdef LOGIN_CAP
if (options.use_login)
#endif /* LOGIN_CAP */
/* Set login name in the kernel. */
if (setlogin(pw->pw_name) < 0)
error("setlogin failed: %s", strerror(errno));
/* Set uid, gid, and groups. */
/* Login(1) does this as well, and it needs uid 0 for the "-h" /* Login(1) does this as well, and it needs uid 0 for the "-h"
switch, so we let login(1) to this for us. */ switch, so we let login(1) to this for us. */
if (!options.use_login) { if (!options.use_login) {
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
char **tmpenv; char **tmpenv;
/* Initialize temp environment */ /* Initialize temp environment */
@ -928,8 +976,18 @@ do_child(const char *command, struct passwd * pw, const char *term,
envsize = (envsize < 100) ? 100 : envsize + 16; envsize = (envsize < 100) ? 100 : envsize + 16;
env = xrealloc(env, envsize * sizeof(char *)); env = xrealloc(env, envsize * sizeof(char *));
#else /* !LOGIN_CAP */ #endif /* !HAVE_LOGIN_CAP */
if (getuid() == 0 || geteuid() == 0) { 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) { if (setgid(pw->pw_gid) < 0) {
perror("setgid"); perror("setgid");
exit(1); exit(1);
@ -943,19 +1001,19 @@ do_child(const char *command, struct passwd * pw, const char *term,
/* Permanently switch to the desired uid. */ /* Permanently switch to the desired uid. */
permanently_set_uid(pw->pw_uid); permanently_set_uid(pw->pw_uid);
#endif /* HAVE_LOGIN_CAP */
} }
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %d.", (int) pw->pw_uid); fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
#endif /* LOGIN_CAP */
} }
/* /*
* Get the shell from the password data. An empty shell field is * Get the shell from the password data. An empty shell field is
* legal, and means /bin/sh. * legal, and means /bin/sh.
*/ */
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
shell = login_getcapstr(lc, "shell", shell, shell); shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
#endif /* LOGIN_CAP */ #endif
#ifdef AFS #ifdef AFS
/* Try to get AFS tokens for the local cell. */ /* Try to get AFS tokens for the local cell. */
@ -981,20 +1039,20 @@ do_child(const char *command, struct passwd * pw, const char *term,
child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "USER", pw->pw_name);
child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
child_set_env(&env, &envsize, "HOME", pw->pw_dir); child_set_env(&env, &envsize, "HOME", pw->pw_dir);
#ifndef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH);
child_set_env(&env, &envsize, "PATH", getenv("PATH"));
#else
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
#endif
snprintf(buf, sizeof buf, "%.200s/%.50s", snprintf(buf, sizeof buf, "%.200s/%.50s",
_PATH_MAILDIR, pw->pw_name); _PATH_MAILDIR, pw->pw_name);
child_set_env(&env, &envsize, "MAIL", buf); child_set_env(&env, &envsize, "MAIL", buf);
#endif /* !LOGIN_CAP */
/* Normal systems set SHELL by default. */ /* Normal systems set SHELL by default. */
child_set_env(&env, &envsize, "SHELL", shell); child_set_env(&env, &envsize, "SHELL", shell);
} }
#ifdef LOGIN_CAP
if (options.use_login)
#endif /* LOGIN_CAP */
if (getenv("TZ")) if (getenv("TZ"))
child_set_env(&env, &envsize, "TZ", getenv("TZ")); child_set_env(&env, &envsize, "TZ", getenv("TZ"));
@ -1023,6 +1081,9 @@ do_child(const char *command, struct passwd * pw, const char *term,
child_set_env(&env, &envsize, "TERM", term); child_set_env(&env, &envsize, "TERM", term);
if (display) if (display)
child_set_env(&env, &envsize, "DISPLAY", display); child_set_env(&env, &envsize, "DISPLAY", display);
if (original_command)
child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
original_command);
#ifdef KRB4 #ifdef KRB4
{ {
@ -1076,6 +1137,9 @@ do_child(const char *command, struct passwd * pw, const char *term,
for (i = 0; env[i]; i++) for (i = 0; env[i]; i++)
fprintf(stderr, " %.200s\n", env[i]); fprintf(stderr, " %.200s\n", env[i]);
} }
/* we have to stash the hostname before we close our socket. */
if (options.use_login)
hostname = get_remote_name_or_ip();
/* /*
* Close the connection descriptors; note that this is the child, and * Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important * the server will still have the socket open, and it is important
@ -1121,14 +1185,14 @@ do_child(const char *command, struct passwd * pw, const char *term,
#ifdef __FreeBSD__ #ifdef __FreeBSD__
int quiet_login = 0; int quiet_login = 0;
#endif /* __FreeBSD__ */ #endif /* __FreeBSD__ */
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "requirehome", 0)) { if (login_getcapbool(lc, "requirehome", 0)) {
(void)printf("Home directory not available\n"); (void)printf("Home directory not available\n");
log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s", log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s",
pw->pw_name, ttyname); pw->pw_name, ttyname);
exit(254); exit(254);
} }
#endif /* LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
#ifdef __FreeBSD__ #ifdef __FreeBSD__
if (chdir("/") < 0) { if (chdir("/") < 0) {
(void)printf("Cannot find root directory\n"); (void)printf("Cannot find root directory\n");
@ -1136,9 +1200,9 @@ do_child(const char *command, struct passwd * pw, const char *term,
pw->pw_name, ttyname); pw->pw_name, ttyname);
exit(254); exit(254);
} }
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
quiet_login = login_getcapbool(lc, "hushlogin", 0); quiet_login = login_getcapbool(lc, "hushlogin", 0);
#endif /* LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
if (!quiet_login || *pw->pw_dir) if (!quiet_login || *pw->pw_dir)
(void)printf( (void)printf(
"No home directory.\nLogging in with home = \"/\".\n"); "No home directory.\nLogging in with home = \"/\".\n");
@ -1149,9 +1213,9 @@ do_child(const char *command, struct passwd * pw, const char *term,
pw->pw_dir, strerror(errno)); pw->pw_dir, strerror(errno));
#endif /* __FreeBSD__ */ #endif /* __FreeBSD__ */
} }
#ifdef LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_close(lc); login_close(lc);
#endif /* LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
/* /*
* Must take new environment into use so that .ssh/rc, /etc/sshrc and * Must take new environment into use so that .ssh/rc, /etc/sshrc and
@ -1186,38 +1250,38 @@ do_child(const char *command, struct passwd * pw, const char *term,
pclose(f); pclose(f);
} else } else
fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
} } else if (options.xauth_location != NULL) {
#ifdef XAUTH_PATH
else {
/* Add authority data to .Xauthority if appropriate. */ /* Add authority data to .Xauthority if appropriate. */
if (auth_proto != NULL && auth_data != NULL) { if (auth_proto != NULL && auth_data != NULL) {
char *screen = strchr(display, ':'); char *screen = strchr(display, ':');
if (debug_flag) { if (debug_flag) {
fprintf(stderr, fprintf(stderr,
"Running %.100s add %.100s %.100s %.100s\n", "Running %.100s add %.100s %.100s %.100s\n",
XAUTH_PATH, display, auth_proto, auth_data); options.xauth_location, display,
auth_proto, auth_data);
if (screen != NULL) if (screen != NULL)
fprintf(stderr, fprintf(stderr,
"Adding %.*s/unix%s %s %s\n", "Adding %.*s/unix%s %s %s\n",
screen-display, display, (int)(screen-display), display,
screen, auth_proto, auth_data); screen, auth_proto, auth_data);
} }
f = popen(XAUTH_PATH " -q -", "w"); snprintf(cmd, sizeof cmd, "%s -q -",
options.xauth_location);
f = popen(cmd, "w");
if (f) { if (f) {
fprintf(f, "add %s %s %s\n", display, fprintf(f, "add %s %s %s\n", display,
auth_proto, auth_data); auth_proto, auth_data);
if (screen != NULL) if (screen != NULL)
fprintf(f, "add %.*s/unix%s %s %s\n", fprintf(f, "add %.*s/unix%s %s %s\n",
screen-display, display, (int)(screen-display), display,
screen, auth_proto, auth_data); screen, auth_proto, auth_data);
pclose(f); pclose(f);
} else } else {
fprintf(stderr, "Could not run %s -q -\n", fprintf(stderr, "Could not run %s\n",
XAUTH_PATH); cmd);
}
} }
} }
#endif /* XAUTH_PATH */
/* Get the last component of the shell name. */ /* Get the last component of the shell name. */
cp = strrchr(shell, '/'); cp = strrchr(shell, '/');
if (cp) if (cp)
@ -1273,8 +1337,8 @@ do_child(const char *command, struct passwd * pw, const char *term,
} else { } else {
/* Launch login(1). */ /* Launch login(1). */
execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(), execl("/usr/bin/login", "login", "-h", hostname,
"-p", "-f", "--", pw->pw_name, NULL); "-p", "-f", "--", pw->pw_name, NULL);
/* Login couldn't be executed, die. */ /* Login couldn't be executed, die. */
@ -1412,6 +1476,8 @@ session_pty_req(Session *s)
unsigned int len; unsigned int len;
char *term_modes; /* encoded terminal modes */ char *term_modes; /* encoded terminal modes */
if (no_pty_flag)
return 0;
if (s->ttyfd != -1) if (s->ttyfd != -1)
return 0; return 0;
s->term = packet_get_string(&len); s->term = packet_get_string(&len);
@ -1459,10 +1525,22 @@ session_subsystem_req(Session *s)
unsigned int len; unsigned int len;
int success = 0; int success = 0;
char *subsys = packet_get_string(&len); char *subsys = packet_get_string(&len);
int i;
packet_done(); packet_done();
log("subsystem request for %s", subsys); log("subsystem request for %s", 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]);
do_exec_no_pty(s, options.subsystem_command[i], s->pw);
success = 1;
}
}
if (!success)
log("subsystem request for %s failed, subsystem not found", subsys);
xfree(subsys); xfree(subsys);
return success; return success;
} }
@ -1470,6 +1548,11 @@ session_subsystem_req(Session *s)
int int
session_x11_req(Session *s) session_x11_req(Session *s)
{ {
int fd;
if (no_x11_forwarding_flag) {
debug("X11 forwarding disabled in user configuration file.");
return 0;
}
if (!options.x11_forwarding) { if (!options.x11_forwarding) {
debug("X11 forwarding disabled in server configuration file."); debug("X11 forwarding disabled in server configuration file.");
return 0; return 0;
@ -1510,12 +1593,49 @@ session_x11_req(Session *s)
return 0; return 0;
} }
strlcat(xauthfile, "/cookies", MAXPATHLEN); strlcat(xauthfile, "/cookies", MAXPATHLEN);
open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd >= 0)
close(fd);
restore_uid(); restore_uid();
fatal_add_cleanup(xauthfile_cleanup_proc, s); fatal_add_cleanup(xauthfile_cleanup_proc, s);
return 1; return 1;
} }
int
session_shell_req(Session *s)
{
/* if forced_command == NULL, the shell is execed */
char *shell = forced_command;
packet_done();
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, shell, s->pw);
else
do_exec_pty(s, shell, s->pw);
return 1;
}
int
session_exec_req(Session *s)
{
unsigned 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);
}
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, command, s->pw);
else
do_exec_pty(s, command, s->pw);
if (forced_command == NULL)
xfree(command);
return 1;
}
void void
session_input_channel_req(int id, void *arg) session_input_channel_req(int id, void *arg)
{ {
@ -1545,23 +1665,9 @@ session_input_channel_req(int id, void *arg)
*/ */
if (c->type == SSH_CHANNEL_LARVAL) { if (c->type == SSH_CHANNEL_LARVAL) {
if (strcmp(rtype, "shell") == 0) { if (strcmp(rtype, "shell") == 0) {
packet_done(); success = session_shell_req(s);
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, NULL, s->pw);
else
do_exec_pty(s, NULL, s->pw);
success = 1;
} else if (strcmp(rtype, "exec") == 0) { } else if (strcmp(rtype, "exec") == 0) {
char *command = packet_get_string(&len); success = session_exec_req(s);
packet_done();
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, command, s->pw);
else
do_exec_pty(s, command, s->pw);
xfree(command);
success = 1;
} else if (strcmp(rtype, "pty-req") == 0) { } else if (strcmp(rtype, "pty-req") == 0) {
success = session_pty_req(s); success = session_pty_req(s);
} else if (strcmp(rtype, "x11-req") == 0) { } else if (strcmp(rtype, "x11-req") == 0) {
@ -1765,11 +1871,24 @@ session_proctitle(Session *s)
void void
do_authenticated2(void) do_authenticated2(void)
{ {
struct passwd *pw;
/* /*
* Cancel the alarm we set to limit the time taken for * Cancel the alarm we set to limit the time taken for
* authentication. * authentication.
*/ */
alarm(0); alarm(0);
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
#ifdef HAVE_LOGIN_CAP
pw = auth_get_user();
if ((lc = login_getclass(pw->pw_class)) == NULL) {
error("unable to get login class");
return;
}
#endif
server_loop2(); server_loop2();
if (xauthfile) if (xauthfile)
xauthfile_cleanup_proc(NULL); xauthfile_cleanup_proc(NULL);

View File

@ -1,20 +1,45 @@
/* $FreeBSD$ */
/* $OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Wed Mar 29 03:46:59 1995 ylo
* The authentication agent program. * The authentication agent program.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*
* SSH2 implementation,
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $"); RCSID("$OpenBSD: ssh-agent.c,v 1.35 2000/09/07 20:27:54 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
#include "authfd.h"
#include "buffer.h" #include "buffer.h"
#include "bufaux.h" #include "bufaux.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -22,7 +47,14 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $");
#include "getput.h" #include "getput.h"
#include "mpaux.h" #include "mpaux.h"
#include <openssl/evp.h>
#include <openssl/md5.h> #include <openssl/md5.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "key.h"
#include "authfd.h"
#include "dsa.h"
#include "kex.h"
typedef struct { typedef struct {
int fd; int fd;
@ -37,12 +69,17 @@ unsigned int sockets_alloc = 0;
SocketEntry *sockets = NULL; SocketEntry *sockets = NULL;
typedef struct { typedef struct {
RSA *key; Key *key;
char *comment; char *comment;
} Identity; } Identity;
unsigned int num_identities = 0; typedef struct {
Identity *identities = NULL; int nentries;
Identity *identities;
} Idtab;
/* private key table, one per protocol version */
Idtab idtable[3];
int max_fd = 0; int max_fd = 0;
@ -56,175 +93,244 @@ char socket_dir[1024];
extern char *__progname; extern char *__progname;
void void
process_request_identity(SocketEntry *e) idtab_init(void)
{ {
int i;
for (i = 0; i <=2; i++){
idtable[i].identities = NULL;
idtable[i].nentries = 0;
}
}
/* return private key table for requested protocol version */
Idtab *
idtab_lookup(int version)
{
if (version < 1 || version > 2)
fatal("internal error, bad protocol version %d", version);
return &idtable[version];
}
/* return matching private key for given public key */
Key *
lookup_private_key(Key *key, int *idx, int version)
{
int i;
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;
}
}
return NULL;
}
/* send list of supported public keys to 'client' */
void
process_request_identities(SocketEntry *e, int version)
{
Idtab *tab = idtab_lookup(version);
Buffer msg; Buffer msg;
int i; int i;
buffer_init(&msg); buffer_init(&msg);
buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER); buffer_put_char(&msg, (version == 1) ?
buffer_put_int(&msg, num_identities); SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
for (i = 0; i < num_identities; i++) { buffer_put_int(&msg, tab->nentries);
buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); for (i = 0; i < tab->nentries; i++) {
buffer_put_bignum(&msg, identities[i].key->e); Identity *id = &tab->identities[i];
buffer_put_bignum(&msg, identities[i].key->n); if (id->key->type == KEY_RSA) {
buffer_put_string(&msg, identities[i].comment, buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
strlen(identities[i].comment)); buffer_put_bignum(&msg, id->key->rsa->e);
buffer_put_bignum(&msg, id->key->rsa->n);
} else {
unsigned char *blob;
unsigned int blen;
dsa_make_key_blob(id->key, &blob, &blen);
buffer_put_string(&msg, blob, blen);
xfree(blob);
}
buffer_put_cstring(&msg, id->comment);
} }
buffer_put_int(&e->output, buffer_len(&msg)); buffer_put_int(&e->output, buffer_len(&msg));
buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
buffer_free(&msg); buffer_free(&msg);
} }
/* ssh1 only */
void void
process_authentication_challenge(SocketEntry *e) process_authentication_challenge1(SocketEntry *e)
{ {
int i, pub_bits, len; Key *key, *private;
BIGNUM *pub_e, *pub_n, *challenge; BIGNUM *challenge;
int i, len;
Buffer msg; Buffer msg;
MD5_CTX md; MD5_CTX md;
unsigned char buf[32], mdbuf[16], session_id[16]; unsigned char buf[32], mdbuf[16], session_id[16];
unsigned int response_type; unsigned int response_type;
buffer_init(&msg); buffer_init(&msg);
pub_e = BN_new(); key = key_new(KEY_RSA);
pub_n = BN_new();
challenge = BN_new(); challenge = BN_new();
pub_bits = buffer_get_int(&e->input);
buffer_get_bignum(&e->input, pub_e); buffer_get_int(&e->input); /* ignored */
buffer_get_bignum(&e->input, pub_n); buffer_get_bignum(&e->input, key->rsa->e);
buffer_get_bignum(&e->input, key->rsa->n);
buffer_get_bignum(&e->input, challenge); buffer_get_bignum(&e->input, challenge);
if (buffer_len(&e->input) == 0) {
/* Compatibility code for old servers. */
memset(session_id, 0, 16);
response_type = 0;
} else {
/* New code. */
buffer_get(&e->input, (char *) session_id, 16);
response_type = buffer_get_int(&e->input);
}
for (i = 0; i < num_identities; i++)
if (pub_bits == BN_num_bits(identities[i].key->n) &&
BN_cmp(pub_e, identities[i].key->e) == 0 &&
BN_cmp(pub_n, identities[i].key->n) == 0) {
/* Decrypt the challenge using the private key. */
rsa_private_decrypt(challenge, challenge, identities[i].key);
/* Compute the desired response. */ /* Only protocol 1.1 is supported */
switch (response_type) { if (buffer_len(&e->input) == 0)
case 0:/* As of protocol 1.0 */ goto failure;
/* This response type is no longer supported. */ buffer_get(&e->input, (char *) session_id, 16);
log("Compatibility with ssh protocol 1.0 no longer supported."); response_type = buffer_get_int(&e->input);
buffer_put_char(&msg, SSH_AGENT_FAILURE); if (response_type != 1)
goto send; goto failure;
case 1:/* As of protocol 1.1 */ private = lookup_private_key(key, NULL, 1);
/* The response is MD5 of decrypted challenge plus session id. */ if (private != NULL) {
len = BN_num_bytes(challenge); /* Decrypt the challenge using the private key. */
rsa_private_decrypt(challenge, challenge, private->rsa);
if (len <= 0 || len > 32) { /* The response is MD5 of decrypted challenge plus session id. */
fatal("process_authentication_challenge: " len = BN_num_bytes(challenge);
"bad challenge length %d", len); if (len <= 0 || len > 32) {
} log("process_authentication_challenge: bad challenge length %d", len);
memset(buf, 0, 32); goto failure;
BN_bn2bin(challenge, buf + 32 - len);
MD5_Init(&md);
MD5_Update(&md, buf, 32);
MD5_Update(&md, session_id, 16);
MD5_Final(mdbuf, &md);
break;
default:
fatal("process_authentication_challenge: bad response_type %d",
response_type);
break;
}
/* Send the response. */
buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
for (i = 0; i < 16; i++)
buffer_put_char(&msg, mdbuf[i]);
goto send;
} }
/* Unknown identity. Send failure. */ memset(buf, 0, 32);
BN_bn2bin(challenge, buf + 32 - len);
MD5_Init(&md);
MD5_Update(&md, buf, 32);
MD5_Update(&md, session_id, 16);
MD5_Final(mdbuf, &md);
/* Send the response. */
buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
for (i = 0; i < 16; i++)
buffer_put_char(&msg, mdbuf[i]);
goto send;
}
failure:
/* Unknown identity or protocol error. Send failure. */
buffer_put_char(&msg, SSH_AGENT_FAILURE); buffer_put_char(&msg, SSH_AGENT_FAILURE);
send: send:
buffer_put_int(&e->output, buffer_len(&msg)); buffer_put_int(&e->output, buffer_len(&msg));
buffer_append(&e->output, buffer_ptr(&msg), buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
buffer_len(&msg)); key_free(key);
buffer_free(&msg);
BN_clear_free(pub_e);
BN_clear_free(pub_n);
BN_clear_free(challenge); BN_clear_free(challenge);
buffer_free(&msg);
} }
/* ssh2 only */
void void
process_remove_identity(SocketEntry *e) process_sign_request2(SocketEntry *e)
{ {
extern int datafellows;
Key *key, *private;
unsigned char *blob, *data, *signature = NULL;
unsigned int blen, dlen, slen = 0;
Buffer msg;
int ok = -1;
datafellows = 0;
blob = buffer_get_string(&e->input, &blen);
data = buffer_get_string(&e->input, &dlen);
buffer_get_int(&e->input); /* flags, unused */
key = dsa_key_from_blob(blob, blen);
if (key != NULL) {
private = lookup_private_key(key, NULL, 2);
if (private != NULL)
ok = dsa_sign(private, &signature, &slen, data, dlen);
}
key_free(key);
buffer_init(&msg);
if (ok == 0) {
buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
buffer_put_string(&msg, signature, slen);
} else {
buffer_put_char(&msg, SSH_AGENT_FAILURE);
}
buffer_put_int(&e->output, buffer_len(&msg));
buffer_append(&e->output, buffer_ptr(&msg),
buffer_len(&msg));
buffer_free(&msg);
xfree(data);
xfree(blob);
if (signature != NULL)
xfree(signature);
}
/* shared */
void
process_remove_identity(SocketEntry *e, int version)
{
Key *key = NULL, *private;
unsigned char *blob;
unsigned int blen;
unsigned int bits; unsigned int bits;
unsigned int i; int success = 0;
BIGNUM *dummy, *n;
dummy = BN_new(); switch(version){
n = BN_new(); case 1:
key = key_new(KEY_RSA);
bits = buffer_get_int(&e->input);
buffer_get_bignum(&e->input, key->rsa->e);
buffer_get_bignum(&e->input, key->rsa->n);
/* Get the key from the packet. */ if (bits != key_size(key))
bits = buffer_get_int(&e->input); log("Warning: identity keysize mismatch: actual %d, announced %d",
buffer_get_bignum(&e->input, dummy); key_size(key), bits);
buffer_get_bignum(&e->input, n); break;
case 2:
if (bits != BN_num_bits(n)) blob = buffer_get_string(&e->input, &blen);
log("Warning: identity keysize mismatch: actual %d, announced %d", key = dsa_key_from_blob(blob, blen);
BN_num_bits(n), bits); xfree(blob);
break;
/* Check if we have the key. */ }
for (i = 0; i < num_identities; i++) if (key != NULL) {
if (BN_cmp(identities[i].key->n, n) == 0) { int idx;
private = lookup_private_key(key, &idx, version);
if (private != NULL) {
/* /*
* We have this key. Free the old key. Since we * We have this key. Free the old key. Since we
* don\'t want to leave empty slots in the middle of * don\'t want to leave empty slots in the middle of
* the array, we actually free the key there and copy * the array, we actually free the key there and copy
* data from the last entry. * data from the last entry.
*/ */
RSA_free(identities[i].key); Idtab *tab = idtab_lookup(version);
xfree(identities[i].comment); key_free(tab->identities[idx].key);
if (i < num_identities - 1) xfree(tab->identities[idx].comment);
identities[i] = identities[num_identities - 1]; if (idx != tab->nentries)
num_identities--; tab->identities[idx] = tab->identities[tab->nentries];
BN_clear_free(dummy); tab->nentries--;
BN_clear_free(n); success = 1;
/* Send success. */
buffer_put_int(&e->output, 1);
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
return;
} }
/* We did not have the key. */ key_free(key);
BN_clear(dummy); }
BN_clear(n);
/* Send failure. */
buffer_put_int(&e->output, 1); buffer_put_int(&e->output, 1);
buffer_put_char(&e->output, SSH_AGENT_FAILURE); buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
} }
/*
* Removes all identities from the agent.
*/
void void
process_remove_all_identities(SocketEntry *e) process_remove_all_identities(SocketEntry *e, int version)
{ {
unsigned int i; unsigned int i;
Idtab *tab = idtab_lookup(version);
/* Loop over all identities and clear the keys. */ /* Loop over all identities and clear the keys. */
for (i = 0; i < num_identities; i++) { for (i = 0; i < tab->nentries; i++) {
RSA_free(identities[i].key); key_free(tab->identities[i].key);
xfree(identities[i].comment); xfree(tab->identities[i].comment);
} }
/* Mark that there are no identities. */ /* Mark that there are no identities. */
num_identities = 0; tab->nentries = 0;
/* Send success. */ /* Send success. */
buffer_put_int(&e->output, 1); buffer_put_int(&e->output, 1);
@ -232,79 +338,108 @@ process_remove_all_identities(SocketEntry *e)
return; return;
} }
/*
* Adds an identity to the agent.
*/
void void
process_add_identity(SocketEntry *e) process_add_identity(SocketEntry *e, int version)
{ {
RSA *k; Key *k = NULL;
int i; RSA *rsa;
BIGNUM *aux; BIGNUM *aux;
BN_CTX *ctx; BN_CTX *ctx;
char *type;
char *comment;
int success = 0;
Idtab *tab = idtab_lookup(version);
if (num_identities == 0) switch (version) {
identities = xmalloc(sizeof(Identity)); case 1:
else k = key_new(KEY_RSA);
identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); rsa = k->rsa;
identities[num_identities].key = RSA_new(); /* allocate mem for private key */
k = identities[num_identities].key; /* XXX rsa->n and rsa->e are already allocated */
buffer_get_int(&e->input); /* bits */ rsa->d = BN_new();
k->n = BN_new(); rsa->iqmp = BN_new();
buffer_get_bignum(&e->input, k->n); rsa->q = BN_new();
k->e = BN_new(); rsa->p = BN_new();
buffer_get_bignum(&e->input, k->e); rsa->dmq1 = BN_new();
k->d = BN_new(); rsa->dmp1 = BN_new();
buffer_get_bignum(&e->input, k->d);
k->iqmp = BN_new();
buffer_get_bignum(&e->input, k->iqmp);
/* SSH and SSL have p and q swapped */
k->q = BN_new();
buffer_get_bignum(&e->input, k->q); /* p */
k->p = BN_new();
buffer_get_bignum(&e->input, k->p); /* q */
/* Generate additional parameters */ buffer_get_int(&e->input); /* ignored */
aux = BN_new();
ctx = BN_CTX_new();
BN_sub(aux, k->q, BN_value_one()); buffer_get_bignum(&e->input, rsa->n);
k->dmq1 = BN_new(); buffer_get_bignum(&e->input, rsa->e);
BN_mod(k->dmq1, k->d, aux, ctx); buffer_get_bignum(&e->input, rsa->d);
buffer_get_bignum(&e->input, rsa->iqmp);
BN_sub(aux, k->p, BN_value_one()); /* SSH and SSL have p and q swapped */
k->dmp1 = BN_new(); buffer_get_bignum(&e->input, rsa->q); /* p */
BN_mod(k->dmp1, k->d, aux, ctx); buffer_get_bignum(&e->input, rsa->p); /* q */
BN_clear_free(aux); /* Generate additional parameters */
BN_CTX_free(ctx); aux = BN_new();
ctx = BN_CTX_new();
identities[num_identities].comment = buffer_get_string(&e->input, NULL); BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
/* Check if we already have the key. */ BN_sub(aux, rsa->p, BN_value_one());
for (i = 0; i < num_identities; i++) BN_mod(rsa->dmp1, rsa->d, aux, ctx);
if (BN_cmp(identities[i].key->n, k->n) == 0) {
/*
* We already have this key. Clear and free the new
* data and return success.
*/
RSA_free(k);
xfree(identities[num_identities].comment);
/* Send success. */ BN_clear_free(aux);
buffer_put_int(&e->output, 1); BN_CTX_free(ctx);
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
return; break;
case 2:
type = buffer_get_string(&e->input, NULL);
if (strcmp(type, KEX_DSS)) {
buffer_clear(&e->input);
xfree(type);
goto send;
} }
/* Increment the number of identities. */ xfree(type);
num_identities++;
/* Send a success message. */ k = key_new(KEY_DSA);
/* allocate mem for private key */
k->dsa->priv_key = BN_new();
buffer_get_bignum2(&e->input, k->dsa->p);
buffer_get_bignum2(&e->input, k->dsa->q);
buffer_get_bignum2(&e->input, k->dsa->g);
buffer_get_bignum2(&e->input, k->dsa->pub_key);
buffer_get_bignum2(&e->input, k->dsa->priv_key);
break;
}
comment = buffer_get_string(&e->input, NULL);
if (k == NULL) {
xfree(comment);
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;
/* Increment the number of identities. */
tab->nentries++;
} else {
key_free(k);
xfree(comment);
}
send:
buffer_put_int(&e->output, 1); buffer_put_int(&e->output, 1);
buffer_put_char(&e->output, SSH_AGENT_SUCCESS); buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
} }
/* dispatch incoming messages */
void void
process_message(SocketEntry *e) process_message(SocketEntry *e)
{ {
@ -327,20 +462,37 @@ process_message(SocketEntry *e)
type = buffer_get_char(&e->input); type = buffer_get_char(&e->input);
switch (type) { switch (type) {
case SSH_AGENTC_REQUEST_RSA_IDENTITIES: /* ssh1 */
process_request_identity(e);
break;
case SSH_AGENTC_RSA_CHALLENGE: case SSH_AGENTC_RSA_CHALLENGE:
process_authentication_challenge(e); process_authentication_challenge1(e);
break;
case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
process_request_identities(e, 1);
break; break;
case SSH_AGENTC_ADD_RSA_IDENTITY: case SSH_AGENTC_ADD_RSA_IDENTITY:
process_add_identity(e); process_add_identity(e, 1);
break; break;
case SSH_AGENTC_REMOVE_RSA_IDENTITY: case SSH_AGENTC_REMOVE_RSA_IDENTITY:
process_remove_identity(e); process_remove_identity(e, 1);
break; break;
case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
process_remove_all_identities(e); process_remove_all_identities(e, 1);
break;
/* ssh2 */
case SSH2_AGENTC_SIGN_REQUEST:
process_sign_request2(e);
break;
case SSH2_AGENTC_REQUEST_IDENTITIES:
process_request_identities(e, 2);
break;
case SSH2_AGENTC_ADD_IDENTITY:
process_add_identity(e, 2);
break;
case SSH2_AGENTC_REMOVE_IDENTITY:
process_remove_identity(e, 2);
break;
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e, 2);
break; break;
default: default:
/* Unknown message. Respond with failure. */ /* Unknown message. Respond with failure. */
@ -537,7 +689,7 @@ main(int ac, char **av)
if (ac > 0 && (c_flag || k_flag || s_flag)) if (ac > 0 && (c_flag || k_flag || s_flag))
usage(); usage();
if (ac == 0 && !c_flag && !s_flag) { if (ac == 0 && !c_flag && !k_flag && !s_flag) {
shell = getenv("SHELL"); shell = getenv("SHELL");
if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
c_flag = 1; c_flag = 1;
@ -641,6 +793,7 @@ main(int ac, char **av)
signal(SIGALRM, check_parent_exists); signal(SIGALRM, check_parent_exists);
alarm(10); alarm(10);
} }
idtab_init();
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_exit); signal(SIGHUP, cleanup_exit);

View File

@ -1,15 +1,39 @@
.\" -*- nroff -*- .\" -*- nroff -*-
.\" .\"
.\" ssh.1.in
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\"
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved .\" All rights reserved
.\" .\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo .\" As far as I am concerned, the code I have written for this software
.\" can be used freely for any purpose. Any derived versions of this
.\" 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".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $Id: ssh.1,v 1.54 2000/05/29 20:20:46 markus Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
@ -942,6 +966,13 @@ The argument must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
.It Cm XAuthLocation
Specifies the location of the
.Xr xauth 1
program.
The default is
.Pa /usr/X11R6/bin/xauth .
.El
.Sh ENVIRONMENT .Sh ENVIRONMENT
.Nm .Nm
will normally set the following environment variables: will normally set the following environment variables:
@ -1186,6 +1217,7 @@ above.
.It Pa libcrypto.so.X.1 .It Pa libcrypto.so.X.1
A version of this library which includes support for the RSA algorithm A version of this library which includes support for the RSA algorithm
is required for proper operation. is required for proper operation.
.El
.Sh AUTHOR .Sh AUTHOR
OpenSSH OpenSSH
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
@ -1214,10 +1246,6 @@ supports one-time password authentication with
.Xr skey 1 . .Xr skey 1 .
.El .El
.Pp .Pp
The libraries described in
.Xr ssl 8
are required for proper operation.
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl, OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song. Niels Provos, Theo de Raadt, and Dug Song.
.Pp .Pp

View File

@ -2,18 +2,45 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Sat Mar 18 16:36:11 1995 ylo
* Ssh client program. This program can be used to log into a remote machine. * Ssh client program. This program can be used to log into a remote machine.
* The software supports strong authentication, encryption, and forwarding * The software supports strong authentication, encryption, and forwarding
* of X11, TCP/IP, and authentication connections. * of X11, TCP/IP, and authentication connections.
* *
* Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada. * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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$ * Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Modified to work with SSL by Niels Provos <provos@citi.umich.edu>
* in Canada (German citizen).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh.c,v 1.54 2000/05/30 17:32:06 markus Exp $"); RCSID("$OpenBSD: ssh.c,v 1.65 2000/09/07 20:40:30 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
@ -23,7 +50,6 @@ RCSID("$Id: ssh.c,v 1.54 2000/05/30 17:32:06 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "packet.h"
#include "buffer.h" #include "buffer.h"
#include "authfd.h"
#include "readconf.h" #include "readconf.h"
#include "uidswap.h" #include "uidswap.h"
@ -31,6 +57,7 @@ RCSID("$Id: ssh.c,v 1.54 2000/05/30 17:32:06 markus Exp $");
#include "compat.h" #include "compat.h"
#include "channels.h" #include "channels.h"
#include "key.h" #include "key.h"
#include "authfd.h"
#include "authfile.h" #include "authfile.h"
extern char *__progname; extern char *__progname;
@ -117,7 +144,6 @@ usage()
#endif /* AFS */ #endif /* AFS */
fprintf(stderr, " -X Enable X11 connection forwarding.\n"); fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -x Disable X11 connection forwarding.\n"); fprintf(stderr, " -x Disable X11 connection forwarding.\n");
fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n"); fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
fprintf(stderr, " -T Do not allocate a tty.\n"); fprintf(stderr, " -T Do not allocate a tty.\n");
@ -249,8 +275,8 @@ main(int ac, char **av)
cp = strrchr(av0, '/') + 1; cp = strrchr(av0, '/') + 1;
else else
cp = av0; cp = av0;
if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 && if (strcmp(cp, "rsh") && strcmp(cp, "ssh") && strcmp(cp, "rlogin") &&
strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0) strcmp(cp, "slogin") && strcmp(cp, "remsh"))
host = cp; host = cp;
for (optind = 1; optind < ac; optind++) { for (optind = 1; optind < ac; optind++) {
@ -458,7 +484,7 @@ main(int ac, char **av)
} }
/* Cannot fork to background if no command. */ /* Cannot fork to background if no command. */
if (fork_after_authentication_flag && buffer_len(&command) == 0) if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag)
fatal("Cannot fork into background without a command to execute."); fatal("Cannot fork into background without a command to execute.");
/* Allocate a tty by default if no command specified. */ /* Allocate a tty by default if no command specified. */
@ -487,6 +513,7 @@ main(int ac, char **av)
pwcopy.pw_passwd = xstrdup(pw->pw_passwd); pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
pwcopy.pw_uid = pw->pw_uid; pwcopy.pw_uid = pw->pw_uid;
pwcopy.pw_gid = pw->pw_gid; pwcopy.pw_gid = pw->pw_gid;
pwcopy.pw_class = xstrdup(pw->pw_class);
pwcopy.pw_dir = xstrdup(pw->pw_dir); pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell); pwcopy.pw_shell = xstrdup(pw->pw_shell);
pwcopy.pw_class = xstrdup(pw->pw_class); pwcopy.pw_class = xstrdup(pw->pw_class);
@ -622,7 +649,7 @@ main(int ac, char **av)
*/ */
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR); snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
if (stat(buf, &st) < 0) if (stat(buf, &st) < 0)
if (mkdir(buf, 0755) < 0) if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf); error("Could not create directory '%.200s'.", buf);
/* Check if the connection failed, and try "rsh" if appropriate. */ /* Check if the connection failed, and try "rsh" if appropriate. */
@ -679,17 +706,17 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
FILE *f; FILE *f;
int got_data = 0, i; int got_data = 0, i;
#ifdef XAUTH_PATH if (options.xauth_location) {
/* Try to get Xauthority information for the display. */ /* Try to get Xauthority information for the display. */
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null", snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
XAUTH_PATH, getenv("DISPLAY")); options.xauth_location, getenv("DISPLAY"));
f = popen(line, "r"); f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) && if (f && fgets(line, sizeof(line), f) &&
sscanf(line, "%*s %s %s", proto, data) == 2) sscanf(line, "%*s %s %s", proto, data) == 2)
got_data = 1; got_data = 1;
if (f) if (f)
pclose(f); pclose(f);
#endif /* XAUTH_PATH */ }
/* /*
* If we didn't get authentication data, just make up some * If we didn't get authentication data, just make up some
* data. The forwarding code will check the validity of the * data. The forwarding code will check the validity of the
@ -871,7 +898,7 @@ ssh_session(void)
} }
/* Enter the interactive session. */ /* Enter the interactive session. */
return client_loop(have_tty, tty_flag ? options.escape_char : -1); return client_loop(have_tty, tty_flag ? options.escape_char : -1, 0);
} }
void void
@ -954,31 +981,40 @@ int
ssh_session2(void) ssh_session2(void)
{ {
int window, packetmax, id; int window, packetmax, id;
int in = dup(STDIN_FILENO); int in, out, err;
int out = dup(STDOUT_FILENO);
int err = dup(STDERR_FILENO); if (stdin_null_flag) {
in = open("/dev/null", O_RDONLY);
} else {
in = dup(STDIN_FILENO);
}
out = dup(STDOUT_FILENO);
err = dup(STDERR_FILENO);
if (in < 0 || out < 0 || err < 0) if (in < 0 || out < 0 || err < 0)
fatal("dump in/out/err failed"); fatal("dup() in/out/err failed");
/* should be pre-session */ /* should be pre-session */
init_local_fwd(); init_local_fwd();
window = 32*1024; /* If requested, let ssh continue in the background. */
if (tty_flag) { if (fork_after_authentication_flag)
packetmax = window/8; if (daemon(1, 1) < 0)
} else { fatal("daemon() failed: %.200s", strerror(errno));
window *= 2;
packetmax = window/2;
}
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
if (!tty_flag) {
window *= 2;
packetmax *=2;
}
id = channel_new( id = channel_new(
"session", SSH_CHANNEL_OPENING, in, out, err, "session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE, xstrdup("client-session")); window, packetmax, CHAN_EXTENDED_WRITE,
xstrdup("client-session"));
channel_open(id); channel_open(id);
channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0); channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
return client_loop(tty_flag, tty_flag ? options.escape_char : -1); return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id);
} }

View File

@ -1,20 +1,19 @@
/* /*
*
* ssh.h
*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Created: Fri Mar 17 17:09:37 1995 ylo
*
* Generic header file for ssh. * Generic header file for ssh.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
/* RCSID("$Id: ssh.h,v 1.46 2000/05/17 08:20:15 markus Exp $"); */ /* RCSID("$OpenBSD: ssh.h,v 1.50 2000/09/07 20:27:54 deraadt Exp $"); */
/* $FreeBSD$ */
#ifndef SSH_H #ifndef SSH_H
#define SSH_H #define SSH_H
@ -463,6 +462,9 @@ char *tilde_expand_filename(const char *filename, uid_t my_uid);
/* remove newline at end of string */ /* remove newline at end of string */
char *chop(char *s); char *chop(char *s);
/* return next token in configuration line */
char *strdelim(char **s);
/* set filedescriptor to non-blocking */ /* set filedescriptor to non-blocking */
void set_nonblock(int fd); void set_nonblock(int fd);
@ -477,7 +479,7 @@ void server_loop(pid_t pid, int fdin, int fdout, int fderr);
void server_loop2(void); void server_loop2(void);
/* Client side main loop for the interactive session. */ /* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char); int client_loop(int have_pty, int escape_char, int id);
/* Linked list of custom environment strings (see auth-rsa.c). */ /* Linked list of custom environment strings (see auth-rsa.c). */
struct envstring { struct envstring {

View File

@ -2,15 +2,19 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Sat Mar 18 22:15:47 1995 ylo
* Code to connect to a remote host, and to perform the client side of the * Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog. * login (authentication) dialog.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshconnect.c,v 1.74 2000/05/17 16:57:02 markus Exp $"); RCSID("$OpenBSD: sshconnect.c,v 1.78 2000/09/07 20:27:54 deraadt Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
@ -191,8 +195,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
int gaierr; int gaierr;
struct linger linger; struct linger linger;
debug("ssh_connect: getuid %d geteuid %d anon %d", debug("ssh_connect: getuid %u geteuid %u anon %d",
(int) getuid(), (int) geteuid(), anonymous); (u_int) getuid(), (u_int) geteuid(), anonymous);
/* Get default port if port has not been set. */ /* Get default port if port has not been set. */
if (port == 0) { if (port == 0) {
@ -312,23 +316,28 @@ ssh_exchange_identification()
int connection_out = packet_get_connection_out(); int connection_out = packet_get_connection_out();
/* Read other side\'s version identification. */ /* Read other side\'s version identification. */
for (i = 0; i < sizeof(buf) - 1; i++) { for (;;) {
int len = read(connection_in, &buf[i], 1); for (i = 0; i < sizeof(buf) - 1; i++) {
if (len < 0) int len = atomicio(read, connection_in, &buf[i], 1);
fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); if (len < 0)
if (len != 1) fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
fatal("ssh_exchange_identification: Connection closed by remote host"); if (len != 1)
if (buf[i] == '\r') { fatal("ssh_exchange_identification: Connection closed by remote host");
buf[i] = '\n'; if (buf[i] == '\r') {
buf[i + 1] = 0; buf[i] = '\n';
continue; /**XXX wait for \n */ buf[i + 1] = 0;
continue; /**XXX wait for \n */
}
if (buf[i] == '\n') {
buf[i + 1] = 0;
break;
}
} }
if (buf[i] == '\n') { buf[sizeof(buf) - 1] = 0;
buf[i + 1] = 0; if (strncmp(buf, "SSH-", 4) == 0)
break; break;
} debug("ssh_exchange_identification: %s", buf);
} }
buf[sizeof(buf) - 1] = 0;
server_version_string = xstrdup(buf); server_version_string = xstrdup(buf);
/* /*
@ -899,7 +908,7 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
/* Get local user name. Use it as server user if no user name was given. */ /* Get local user name. Use it as server user if no user name was given. */
pw = getpwuid(original_real_uid); pw = getpwuid(original_real_uid);
if (!pw) if (!pw)
fatal("User id %d not found from user database.", original_real_uid); fatal("User id %u not found from user database.", original_real_uid);
local_user = xstrdup(pw->pw_name); local_user = xstrdup(pw->pw_name);
server_user = options.user ? options.user : local_user; server_user = options.user ? options.user : local_user;

View File

@ -2,15 +2,19 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Sat Mar 18 22:15:47 1995 ylo
* Code to connect to a remote host, and to perform the client side of the * Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog. * login (authentication) dialog.
* *
* $FreeBSD$ * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshconnect1.c,v 1.3 2000/05/08 17:12:16 markus Exp $"); RCSID("$OpenBSD: sshconnect1.c,v 1.6 2000/09/07 20:27:54 deraadt Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
@ -22,12 +26,12 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.3 2000/05/08 17:12:16 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
#include "authfd.h"
#include "cipher.h" #include "cipher.h"
#include "mpaux.h" #include "mpaux.h"
#include "uidswap.h" #include "uidswap.h"
#include "readconf.h" #include "readconf.h"
#include "key.h" #include "key.h"
#include "authfd.h"
#include "sshconnect.h" #include "sshconnect.h"
#include "authfile.h" #include "authfile.h"
@ -45,27 +49,27 @@ extern char *__progname;
int int
try_agent_authentication() try_agent_authentication()
{ {
int status, type; int type;
char *comment; char *comment;
AuthenticationConnection *auth; AuthenticationConnection *auth;
unsigned char response[16]; unsigned char response[16];
unsigned int i; unsigned int i;
BIGNUM *e, *n, *challenge; int plen, clen;
Key *key;
BIGNUM *challenge;
/* Get connection to the agent. */ /* Get connection to the agent. */
auth = ssh_get_authentication_connection(); auth = ssh_get_authentication_connection();
if (!auth) if (!auth)
return 0; return 0;
e = BN_new();
n = BN_new();
challenge = BN_new(); challenge = BN_new();
key = key_new(KEY_RSA);
/* Loop through identities served by the agent. */ /* Loop through identities served by the agent. */
for (status = ssh_get_first_identity(auth, e, n, &comment); for (key = ssh_get_first_identity(auth, &comment, 1);
status; key != NULL;
status = ssh_get_next_identity(auth, e, n, &comment)) { key = ssh_get_next_identity(auth, &comment, 1)) {
int plen, clen;
/* Try this identity. */ /* Try this identity. */
debug("Trying RSA authentication via agent with '%.100s'", comment); debug("Trying RSA authentication via agent with '%.100s'", comment);
@ -73,7 +77,7 @@ try_agent_authentication()
/* Tell the server that we are willing to authenticate using this key. */ /* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RSA); packet_start(SSH_CMSG_AUTH_RSA);
packet_put_bignum(n); packet_put_bignum(key->rsa->n);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
@ -84,6 +88,7 @@ try_agent_authentication()
does not support RSA authentication. */ does not support RSA authentication. */
if (type == SSH_SMSG_FAILURE) { if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key."); debug("Server refused our key.");
key_free(key);
continue; continue;
} }
/* Otherwise it should have sent a challenge. */ /* Otherwise it should have sent a challenge. */
@ -98,13 +103,16 @@ try_agent_authentication()
debug("Received RSA challenge from server."); debug("Received RSA challenge from server.");
/* Ask the agent to decrypt the challenge. */ /* Ask the agent to decrypt the challenge. */
if (!ssh_decrypt_challenge(auth, e, n, challenge, if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) {
session_id, 1, response)) { /*
/* The agent failed to authenticate this identifier although it * The agent failed to authenticate this identifier
advertised it supports this. Just return a wrong value. */ * although it advertised it supports this. Just
* return a wrong value.
*/
log("Authentication agent failed to decrypt challenge."); log("Authentication agent failed to decrypt challenge.");
memset(response, 0, sizeof(response)); memset(response, 0, sizeof(response));
} }
key_free(key);
debug("Sending response to RSA challenge."); debug("Sending response to RSA challenge.");
/* Send the decrypted challenge back to the server. */ /* Send the decrypted challenge back to the server. */
@ -119,10 +127,8 @@ try_agent_authentication()
/* The server returns success if it accepted the authentication. */ /* The server returns success if it accepted the authentication. */
if (type == SSH_SMSG_SUCCESS) { if (type == SSH_SMSG_SUCCESS) {
debug("RSA authentication accepted by server.");
BN_clear_free(e);
BN_clear_free(n);
BN_clear_free(challenge); BN_clear_free(challenge);
debug("RSA authentication accepted by server.");
return 1; return 1;
} }
/* Otherwise it should return failure. */ /* Otherwise it should return failure. */
@ -130,11 +136,7 @@ try_agent_authentication()
packet_disconnect("Protocol error waiting RSA auth response: %d", packet_disconnect("Protocol error waiting RSA auth response: %d",
type); type);
} }
BN_clear_free(e);
BN_clear_free(n);
BN_clear_free(challenge); BN_clear_free(challenge);
debug("RSA authentication using agent refused."); debug("RSA authentication using agent refused.");
return 0; return 0;
} }

View File

@ -1,15 +1,39 @@
.\" -*- nroff -*- .\" -*- nroff -*-
.\" .\"
.\" sshd.8.in
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\"
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved .\" All rights reserved
.\" .\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo .\" As far as I am concerned, the code I have written for this software
.\" can be used freely for any purpose. Any derived versions of this
.\" 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".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $Id: sshd.8,v 1.51 2000/05/08 17:42:31 hugh Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
@ -27,6 +51,7 @@
.Op Fl h Ar host_key_file .Op Fl h Ar host_key_file
.Op Fl k Ar key_gen_time .Op Fl k Ar key_gen_time
.Op Fl p Ar port .Op Fl p Ar port
.Op Fl u Ar len
.Op Fl V Ar client_protocol_id .Op Fl V Ar client_protocol_id
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
@ -105,7 +130,7 @@ into the machine).
.Pp .Pp
.Ss SSH protocol version 2 .Ss SSH protocol version 2
.Pp .Pp
Version 2 works similar: Version 2 works similarly:
Each host has a host-specific DSA key used to identify the host. Each host has a host-specific DSA key used to identify the host.
However, when the daemon starts, it does not generate a server key. However, when the daemon starts, it does not generate a server key.
Forward security is provided through a Diffie-Hellman key agreement. Forward security is provided through a Diffie-Hellman key agreement.
@ -212,6 +237,22 @@ Quiet mode.
Nothing is sent to the system log. Nothing is sent to the system log.
Normally the beginning, Normally the beginning,
authentication, and termination of each connection is logged. authentication, and termination of each connection is logged.
.It Fl u Ar len
This option is used to specify the size of the field
in the
.Li utmp
structure that holds the remote host name.
If the resolved host name is longer than
.Ar len ,
the dotted decimal value will be used instead.
This allows hosts with very long host names that
overflow this field to still be uniquely identified.
Specifying
.Fl u0
indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
.It Fl Q .It Fl Q
Do not print an error message if RSA support is missing. Do not print an error message if RSA support is missing.
.It Fl V Ar client_protocol_id .It Fl V Ar client_protocol_id
@ -258,7 +299,7 @@ and
.Ql ? .Ql ?
can be used as can be used as
wildcards in the patterns. wildcards in the patterns.
Only group names are valid, a numerical group ID isn't recognized. Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the primary group. By default login is allowed regardless of the primary group.
.Pp .Pp
.It Cm AllowUsers .It Cm AllowUsers
@ -271,7 +312,7 @@ and
.Ql ? .Ql ?
can be used as can be used as
wildcards in the patterns. wildcards in the patterns.
Only user names are valid, a numerical user ID isn't recognized. Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name. By default login is allowed regardless of the user name.
.Pp .Pp
.It Cm Ciphers .It Cm Ciphers
@ -320,7 +361,7 @@ and
.Ql ? .Ql ?
can be used as can be used as
wildcards in the patterns. wildcards in the patterns.
Only group names are valid, a numerical group ID isn't recognized. Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the primary group. By default login is allowed regardless of the primary group.
.Pp .Pp
.It Cm DenyUsers .It Cm DenyUsers
@ -331,7 +372,7 @@ Login is disallowed for user names that match one of the patterns.
and and
.Ql ? .Ql ?
can be used as wildcards in the patterns. can be used as wildcards in the patterns.
Only user names are valid, a numerical user ID isn't recognized. Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name. By default login is allowed regardless of the user name.
.It Cm DSAAuthentication .It Cm DSAAuthentication
Specifies whether DSA authentication is allowed. Specifies whether DSA authentication is allowed.
@ -347,7 +388,7 @@ or
.Dq no . .Dq no .
The default is The default is
.Dq no . .Dq no .
.It Cm HostDsaKey .It Cm HostDSAKey
Specifies the file containing the private DSA host key (default Specifies the file containing the private DSA host key (default
.Pa /etc/ssh/ssh_host_dsa_key ) .Pa /etc/ssh/ssh_host_dsa_key )
used by SSH protocol 2.0. used by SSH protocol 2.0.
@ -409,7 +450,8 @@ Specifies whether Kerberos authentication is allowed.
This can be in the form of a Kerberos ticket, or if This can be in the form of a Kerberos ticket, or if
.Cm PasswordAuthentication .Cm PasswordAuthentication
is yes, the password provided by the user will be validated through is yes, the password provided by the user will be validated through
the Kerberos KDC. the Kerberos KDC. To use this option, the server needs a
Kerberos servtab which allows the verification of the KDC's identity.
Default is Default is
.Dq yes . .Dq yes .
.It Cm KerberosOrLocalPasswd .It Cm KerberosOrLocalPasswd
@ -461,11 +503,36 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO. The default is INFO.
Logging with level DEBUG violates the privacy of users Logging with level DEBUG violates the privacy of users
and is not recommended. and is not recommended.
.It Cm MaxStartups
Specifies the maximum number of concurrent unauthenticated connections to the
.Nm
daemon.
Additional connections will be dropped until authentication succeeds or the
.Cm LoginGraceTime
expires for a connection.
The default is 10.
.Pp
Alternatively, random early drop can be enabled by specifying
the three colon separated values
.Dq start:rate:full
(e.g. "10:30:60").
.Nm
will refuse connection attempts with a probabillity of
.Dq rate/100
(30%)
if there are currently
.Dq start
(10)
unauthenticated connections.
The probabillity increases linearly and all connection attempts
are refused if the number of unauthenticated connections reaches
.Dq full
(60).
.It Cm PasswordAuthentication .It Cm PasswordAuthentication
Specifies whether password authentication is allowed. Specifies whether password authentication is allowed.
The default is The default is
.Dq yes . .Dq yes .
Note that this option applies to both protocol version 1 and 2. Note that this option applies to both protocol versions 1 and 2.
.It Cm PermitEmptyPasswords .It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings. server allows login to accounts with empty password strings.
@ -574,6 +641,16 @@ This is normally desirable because novices sometimes accidentally leave their
directory or files world-writable. directory or files world-writable.
The default is The default is
.Dq yes . .Dq yes .
.It Cm Subsystem
Configures an external subsystem (e.g. file transfer daemon).
Arguments should be a subsystem name and a command to execute upon subsystem request.
The command
.Xr sftp-server 8
implements the
.Dq sftp
file transfer subsystem.
By default no subsystems are defined.
Note that this option applies to protocol version 2 only.
.It Cm SyslogFacility .It Cm SyslogFacility
Gives the facility code that is used when logging messages from Gives the facility code that is used when logging messages from
.Nm sshd . .Nm sshd .
@ -583,7 +660,10 @@ The default is AUTH.
.It Cm UseLogin .It Cm UseLogin
Specifies whether Specifies whether
.Xr login 1 .Xr login 1
is used. is used for interactive login sessions.
Note that
.Xr login 1
is never used for remote command execution.
The default is The default is
.Dq no . .Dq no .
.It Cm X11DisplayOffset .It Cm X11DisplayOffset
@ -600,6 +680,12 @@ The default is
.Dq no . .Dq no .
Note that disabling X11 forwarding does not improve security in any Note that disabling X11 forwarding does not improve security in any
way, as users can always install their own forwarders. way, as users can always install their own forwarders.
.It Cm XAuthLocation
Specifies the location of the
.Xr xauth 1
program.
The default is
.Pa /usr/X11R6/bin/xauth .
.El .El
.Sh LOGIN PROCESS .Sh LOGIN PROCESS
When a user successfully logs in, When a user successfully logs in,
@ -677,7 +763,7 @@ You don't want to type them in; instead, copy the
.Pa identity.pub .Pa identity.pub
file and edit it. file and edit it.
.Pp .Pp
The options (if present) consists of comma-separated option The options (if present) consist of comma-separated option
specifications. specifications.
No spaces are permitted, except within double quotes. No spaces are permitted, except within double quotes.
The following option specifications are supported: The following option specifications are supported:
@ -751,7 +837,7 @@ and
files contain host public keys for all known hosts. files contain host public keys for all known hosts.
The global file should The global file should
be prepared by the administrator (optional), and the per-user file is be prepared by the administrator (optional), and the per-user file is
maintained automatically: whenever the user connects an unknown host maintained automatically: whenever the user connects from an unknown host
its key is added to the per-user file. its key is added to the per-user file.
.Pp .Pp
Each line in these files contains the following fields: hostnames, Each line in these files contains the following fields: hostnames,
@ -828,7 +914,7 @@ Contains the process ID of the
listening for connections (if there are several daemons running listening for connections (if there are several daemons running
concurrently for different ports, this contains the pid of the one concurrently for different ports, this contains the pid of the one
started last). started last).
The contents of this file are not sensitive; it can be world-readable. The content of this file is not sensitive; it can be world-readable.
.It Pa $HOME/.ssh/authorized_keys .It Pa $HOME/.ssh/authorized_keys
Lists the RSA keys that can be used to log into the user's account. 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 This file must be readable by root (which may on some machines imply
@ -856,7 +942,7 @@ These files are consulted when using rhosts with RSA host
authentication to check the public key of the host. authentication to check the public key of the host.
The key must be listed in one of these files to be accepted. The key must be listed in one of these files to be accepted.
The client uses the same files The client uses the same files
to verify that the remote host is the one we intended to connect. to verify that the remote host is the one it intended to connect.
These files should be writable only by root/the owner. These files should be writable only by root/the owner.
.Pa /etc/ssh/ssh_known_hosts .Pa /etc/ssh/ssh_known_hosts
should be world-readable, and should be world-readable, and
@ -983,6 +1069,7 @@ Like
This can be used to specify This can be used to specify
machine-specific login-time initializations globally. machine-specific login-time initializations globally.
This file should be writable only by root, and should be world-readable. This file should be writable only by root, and should be world-readable.
.El
.Sh AUTHOR .Sh AUTHOR
OpenSSH OpenSSH
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
@ -1011,16 +1098,13 @@ supports one-time password authentication with
.Xr skey 1 . .Xr skey 1 .
.El .El
.Pp .Pp
The libraries described in
.Xr ssl 8
are required for proper operation.
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl, OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song. Niels Provos, Theo de Raadt, and Dug Song.
.Pp .Pp
The support for SSH protocol 2 was written by Markus Friedl. The support for SSH protocol 2 was written by Markus Friedl.
.Sh SEE ALSO .Sh SEE ALSO
.Xr scp 1 , .Xr scp 1 ,
.Xr sftp-server 8 ,
.Xr ssh 1 , .Xr ssh 1 ,
.Xr ssh-add 1 , .Xr ssh-add 1 ,
.Xr ssh-agent 1 , .Xr ssh-agent 1 ,

View File

@ -2,21 +2,46 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* Created: Fri Mar 17 17:09:28 1995 ylo * This program is the ssh daemon. It listens for connections from clients,
* This program is the ssh daemon. It listens for connections from clients, and * and performs authentication, executes use commands or shell, and forwards
* performs authentication, executes use commands or shell, and forwards
* information to/from the application to the user client over an encrypted * information to/from the application to the user client over an encrypted
* connection. This can also handle forwarding of X11, TCP/IP, and authentication * connection. This can also handle forwarding of X11, TCP/IP, and
* agent connections. * authentication agent connections.
* *
* SSH2 implementation, * As far as I am concerned, the code I have written for this software
* Copyright (c) 2000 Markus Friedl. All rights reserved. * can be used freely for any purpose. Any derived versions of this
* 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$ * SSH2 implementation:
*
* Copyright (c) 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshd.c,v 1.118 2000/05/25 20:45:20 markus Exp $"); RCSID("$OpenBSD: sshd.c,v 1.126 2000/09/07 20:27:55 deraadt Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -168,6 +193,9 @@ timevaldiff(struct timeval *tv1, struct timeval *tv2) {
return diff; return diff;
} }
/* record remote hostname or ip */
unsigned int utmp_len = MAXHOSTNAMELEN;
/* Prototypes for various functions defined later in this file. */ /* Prototypes for various functions defined later in this file. */
void do_ssh1_kex(); void do_ssh1_kex();
void do_ssh2_kex(); void do_ssh2_kex();
@ -327,7 +355,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
/* Read other side\'s version identification. */ /* Read other side\'s version identification. */
for (i = 0; i < sizeof(buf) - 1; i++) { for (i = 0; i < sizeof(buf) - 1; i++) {
if (read(sock_in, &buf[i], 1) != 1) { if (atomicio(read, sock_in, &buf[i], 1) != 1) {
log("Did not receive ident string from %s.", get_remote_ipaddr()); log("Did not receive ident string from %s.", get_remote_ipaddr());
fatal_cleanup(); fatal_cleanup();
} }
@ -380,7 +408,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
break; break;
} }
if (remote_minor < 3) { if (remote_minor < 3) {
packet_disconnect("Your ssh version is too old and" packet_disconnect("Your ssh version is too old and "
"is no longer supported. Please install a newer version."); "is no longer supported. Please install a newer version.");
} else if (remote_minor == 3) { } else if (remote_minor == 3) {
/* note that this disables agent-forwarding */ /* note that this disables agent-forwarding */
@ -430,6 +458,38 @@ destroy_sensitive_data(void)
key_free(sensitive_data.dsa_host_key); key_free(sensitive_data.dsa_host_key);
} }
/*
* returns 1 if connection should be dropped, 0 otherwise.
* dropping starts at connection #max_startups_begin with a probability
* of (max_startups_rate/100). the probability increases linearly until
* all connections are dropped for startups > max_startups
*/
int
drop_connection(int startups)
{
double p, r;
if (startups < options.max_startups_begin)
return 0;
if (startups >= options.max_startups)
return 1;
if (options.max_startups_rate == 100)
return 1;
p = 100 - options.max_startups_rate;
p *= startups - options.max_startups_begin;
p /= (double) (options.max_startups - options.max_startups_begin);
p += options.max_startups_rate;
p /= 100.0;
r = arc4random() / (double) UINT_MAX;
debug("drop_connection: p %g, r %g", p, r);
return (r < p) ? 1 : 0;
}
int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */
int startup_pipe; /* in child */
/* /*
* Main program for the daemon. * Main program for the daemon.
*/ */
@ -438,7 +498,7 @@ main(int ac, char **av)
{ {
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1; int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
pid_t pid; pid_t pid;
socklen_t fromlen; socklen_t fromlen;
int ratelim_exceeded = 0; int ratelim_exceeded = 0;
@ -452,6 +512,8 @@ main(int ac, char **av)
struct addrinfo *ai; struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; char ntop[NI_MAXHOST], strport[NI_MAXSERV];
int listen_sock, maxfd; int listen_sock, maxfd;
int startup_p[2];
int startups = 0;
/* Save argv[0]. */ /* Save argv[0]. */
saved_argv = av; saved_argv = av;
@ -464,7 +526,7 @@ main(int ac, char **av)
initialize_server_options(&options); initialize_server_options(&options);
/* Parse command-line arguments. */ /* Parse command-line arguments. */
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) { while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:diqQ46")) != EOF) {
switch (opt) { switch (opt) {
case '4': case '4':
IPv4or6 = AF_INET; IPv4or6 = AF_INET;
@ -511,6 +573,9 @@ main(int ac, char **av)
/* only makes sense with inetd_flag, i.e. no listen() */ /* only makes sense with inetd_flag, i.e. no listen() */
inetd_flag = 1; inetd_flag = 1;
break; break;
case 'u':
utmp_len = atoi(optarg);
break;
case '?': case '?':
default: default:
fprintf(stderr, "sshd version %s\n", SSH_VERSION); fprintf(stderr, "sshd version %s\n", SSH_VERSION);
@ -526,6 +591,7 @@ main(int ac, char **av)
fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\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", fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
HOST_KEY_FILE); HOST_KEY_FILE);
fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
fprintf(stderr, " -4 Use IPv4 only\n"); fprintf(stderr, " -4 Use IPv4 only\n");
fprintf(stderr, " -6 Use IPv6 only\n"); fprintf(stderr, " -6 Use IPv6 only\n");
exit(1); exit(1);
@ -665,6 +731,7 @@ main(int ac, char **av)
s2 = dup(s1); s2 = dup(s1);
sock_in = dup(0); sock_in = dup(0);
sock_out = dup(1); sock_out = dup(1);
startup_pipe = -1;
/* /*
* We intentionally do not close the descriptors 0, 1, and 2 * We intentionally do not close the descriptors 0, 1, and 2
* as our code for setting the descriptors won\'t work if * as our code for setting the descriptors won\'t work if
@ -773,6 +840,7 @@ main(int ac, char **av)
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */ /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler); signal(SIGHUP, sighup_handler);
signal(SIGTERM, sigterm_handler); signal(SIGTERM, sigterm_handler);
signal(SIGQUIT, sigterm_handler); signal(SIGQUIT, sigterm_handler);
@ -780,12 +848,15 @@ main(int ac, char **av)
signal(SIGCHLD, main_sigchld_handler); signal(SIGCHLD, main_sigchld_handler);
/* setup fd set for listen */ /* setup fd set for listen */
fdset = NULL;
maxfd = 0; maxfd = 0;
for (i = 0; i < num_listen_socks; i++) for (i = 0; i < num_listen_socks; i++)
if (listen_socks[i] > maxfd) if (listen_socks[i] > maxfd)
maxfd = listen_socks[i]; maxfd = listen_socks[i];
fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); /* pipes connected to unauthenticated childs */
fdset = (fd_set *)xmalloc(fdsetsz); startup_pipes = xmalloc(options.max_startups * sizeof(int));
for (i = 0; i < options.max_startups; i++)
startup_pipes[i] = -1;
ratelim_init(); ratelim_init();
@ -796,116 +867,165 @@ main(int ac, char **av)
for (;;) { for (;;) {
if (received_sighup) if (received_sighup)
sighup_restart(); sighup_restart();
/* Wait in select until there is a connection. */ if (fdset != NULL)
xfree(fdset);
fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
fdset = (fd_set *)xmalloc(fdsetsz);
memset(fdset, 0, fdsetsz); memset(fdset, 0, fdsetsz);
for (i = 0; i < num_listen_socks; i++) for (i = 0; i < num_listen_socks; i++)
FD_SET(listen_socks[i], fdset); FD_SET(listen_socks[i], fdset);
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1)
FD_SET(startup_pipes[i], fdset);
/* Wait in select until there is a connection. */
if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) { if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
if (errno != EINTR) if (errno != EINTR)
error("select: %.100s", strerror(errno)); error("select: %.100s", strerror(errno));
continue; continue;
} }
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1 &&
FD_ISSET(startup_pipes[i], fdset)) {
/*
* the read end of the pipe is ready
* if the child has closed the pipe
* after successfull authentication
* or if the child has died
*/
close(startup_pipes[i]);
startup_pipes[i] = -1;
startups--;
}
for (i = 0; i < num_listen_socks; i++) { for (i = 0; i < num_listen_socks; i++) {
if (!FD_ISSET(listen_socks[i], fdset)) if (!FD_ISSET(listen_socks[i], fdset))
continue; continue;
fromlen = sizeof(from); fromlen = sizeof(from);
newsock = accept(listen_socks[i], (struct sockaddr *)&from, newsock = accept(listen_socks[i], (struct sockaddr *)&from,
&fromlen); &fromlen);
if (newsock < 0) { if (newsock < 0) {
if (errno != EINTR && errno != EWOULDBLOCK) if (errno != EINTR && errno != EWOULDBLOCK)
error("accept: %.100s", strerror(errno)); error("accept: %.100s", strerror(errno));
continue; continue;
} }
if (fcntl(newsock, F_SETFL, 0) < 0) { if (fcntl(newsock, F_SETFL, 0) < 0) {
error("newsock del O_NONBLOCK: %s", strerror(errno)); error("newsock del O_NONBLOCK: %s", strerror(errno));
continue; continue;
} }
if (options.connections_per_period != 0) { if (drop_connection(startups) == 1) {
struct timeval diff, connections_end; debug("drop connection #%d", startups);
struct ratelim_connection *rc; close(newsock);
continue;
(void)gettimeofday(&connections_end, NULL); }
rc = &ratelim_connections[i]; if (pipe(startup_p) == -1) {
diff = timevaldiff(&rc->connections_begin, close(newsock);
&connections_end); continue;
if (diff.tv_sec >= options.connections_period) { }
/*
* Slide the window forward only after for (j = 0; j < options.max_startups; j++)
* completely leaving it. if (startup_pipes[j] == -1) {
*/ startup_pipes[j] = startup_p[0];
rc->connections_begin = connections_end; if (maxfd < startup_p[0])
rc->connections_this_period = 1; maxfd = startup_p[0];
} else { startups++;
if (++rc->connections_this_period > break;
options.connections_per_period) }
ratelim_exceeded = 1;
if (options.connections_per_period != 0) {
struct timeval diff, connections_end;
struct ratelim_connection *rc;
(void)gettimeofday(&connections_end, NULL);
rc = &ratelim_connections[i];
diff = timevaldiff(&rc->connections_begin,
&connections_end);
if (diff.tv_sec >= options.connections_period) {
/*
* Slide the window forward only after
* completely leaving it.
*/
rc->connections_begin = connections_end;
rc->connections_this_period = 1;
} else {
if (++rc->connections_this_period >
options.connections_per_period)
ratelim_exceeded = 1;
}
} }
}
/*
* Got connection. Fork a child to handle it unless
* we are in debugging mode or the maximum number of
* connections per period has been exceeded.
*/
if (debug_flag) {
/*
* In debugging mode. Close the listening
* socket, and start processing the
* connection without forking.
*/
debug("Server will not fork when running in debugging mode.");
close_listen_socks();
sock_in = newsock;
sock_out = newsock;
pid = getpid();
break;
} else if (ratelim_exceeded) {
const char *myaddr;
myaddr = get_ipaddr(newsock);
log("rate limit (%u/%u) on %s port %d "
"exceeded by %s",
options.connections_per_period,
options.connections_period, myaddr,
get_sock_port(newsock, 1), ntop);
free((void *)myaddr);
close(newsock);
ratelim_exceeded = 0;
continue;
} else {
/* /*
* Normal production daemon. Fork, and have * Got connection. Fork a child to handle it, unless
* the child process the connection. The * we are in debugging mode.
* parent continues listening.
*/ */
if ((pid = fork()) == 0) { if (debug_flag) {
/* /*
* Child. Close the listening socket, and start using the * In debugging mode. Close the listening
* accepted socket. Reinitialize logging (since our pid has * socket, and start processing the
* changed). We break out of the loop to handle the connection. * connection without forking.
*/ */
debug("Server will not fork when running in debugging mode.");
close_listen_socks(); close_listen_socks();
sock_in = newsock; sock_in = newsock;
sock_out = newsock; sock_out = newsock;
log_init(av0, options.log_level, options.log_facility, log_stderr); startup_pipe = -1;
pid = getpid();
break; break;
} else if (ratelim_exceeded) {
const char *myaddr;
myaddr = get_ipaddr(newsock);
log("rate limit (%u/%u) on %s port %d "
"exceeded by %s",
options.connections_per_period,
options.connections_period, myaddr,
get_sock_port(newsock, 1), ntop);
free((void *)myaddr);
close(newsock);
ratelim_exceeded = 0;
continue;
} else {
/*
* Normal production daemon. Fork, and have
* the child process the connection. The
* parent continues listening.
*/
if ((pid = fork()) == 0) {
/*
* Child. Close the listening and max_startup
* sockets. Start using the accepted socket.
* Reinitialize logging (since our pid has
* changed). We break out of the loop to handle
* 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_listen_socks();
sock_in = newsock;
sock_out = newsock;
log_init(av0, options.log_level, options.log_facility, log_stderr);
break;
}
} }
/* Parent. Stay in the loop. */
if (pid < 0)
error("fork: %.100s", strerror(errno));
else
debug("Forked child %d.", pid);
close(startup_p[1]);
/* Mark that the key has been used (it was "given" to the child). */
key_used = 1;
arc4random_stir();
/* Close the new socket (the child is now taking care of it). */
close(newsock);
} }
/* Parent. Stay in the loop. */
if (pid < 0)
error("fork: %.100s", strerror(errno));
else
debug("Forked child %d.", pid);
/* Mark that the key has been used (it was "given" to the child). */
key_used = 1;
arc4random_stir();
/* Close the new socket (the child is now taking care of it). */
close(newsock);
} /* for (i = 0; i < num_listen_socks; i++) */
/* child process check (or debug mode) */ /* child process check (or debug mode) */
if (num_listen_socks < 0) if (num_listen_socks < 0)
break; break;

View File

@ -53,3 +53,7 @@ PermitEmptyPasswords no
CheckMail yes CheckMail yes
#UseLogin no #UseLogin no
# Uncomment if you want to enable sftp
#Subsystem sftp /usr/libexec/sftp-server
#MaxStartups 10:30:60