Vendor import of OpenSSH 3.1

This commit is contained in:
Dag-Erling Smørgrav 2002-03-18 09:55:03 +00:00
parent 1e8db6e2f6
commit ae1f160d56
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor-crypto/openssh/dist/; revision=92555
165 changed files with 12593 additions and 8851 deletions

View File

@ -26,7 +26,7 @@ OpenSSH contains no GPL code.
[However, none of that term is relevant at this point in time. All of
these restrictively licenced software components which he talks about
have been removed from OpenSSH, ie.
have been removed from OpenSSH, i.e.,
- RSA is no longer included, found in the OpenSSL library
- IDEA is no longer included, its use is deprecated
@ -85,8 +85,7 @@ OpenSSH contains no GPL code.
3)
The 32-bit CRC compensation attack detector in deattack.c was
contributed by CORE SDI S.A. under a BSD-style license. See
http://www.core-sdi.com/english/ssh/ for details.
contributed by CORE SDI S.A. under a BSD-style license.
* Cryptographic attack detector for ssh - source code
*
@ -104,8 +103,83 @@ OpenSSH contains no GPL code.
*
* Ariel Futoransky <futo@core-sdi.com>
* <http://www.core-sdi.com>
4)
ssh-keygen was contributed by David Mazieres under a BSD-style
license.
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project by leaving this copyright notice intact.
5)
The Rijndael implementation by Vincent Rijmen, Antoon Bosselaers
and Paulo Barreto is in the public domain and distributed
with the following license:
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS OR CONTRIBUTORS 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.
6)
One component of the ssh source code is under a 4-clause BSD license,
held by the University of California, since we pulled these parts from
original Berkeley code. The Regents of the University of California
have declared that term 3 is no longer enforceable on their source code,
but we retain that license as is.
* Copyright (c) 1983, 1990, 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
7)
Remaining components of the software are provided under a standard
2-term BSD licence with the following names as copyright holders:
@ -114,6 +188,8 @@ OpenSSH contains no GPL code.
Niels Provos
Dug Song
Aaron Campbell
Damien Miller
Kevin Steves
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

View File

@ -1,14 +1,14 @@
# $OpenBSD: Makefile,v 1.8 2001/02/04 11:11:53 djm Exp $
# $OpenBSD: Makefile,v 1.10 2002/02/09 17:37:34 deraadt Exp $
.include <bsd.own.mk>
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server \
ssh-keyscan sftp
ssh-keyscan sftp scard
distribution:
install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \
${DESTDIR}/etc/ssh_config
${DESTDIR}/etc/ssh/ssh_config
install -C -o root -g wheel -m 0644 ${.CURDIR}/sshd_config \
${DESTDIR}/etc/sshd_config
${DESTDIR}/etc/ssh/sshd_config
.include <bsd.subdir.mk>

View File

@ -1,8 +1,19 @@
# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $
# $OpenBSD: Makefile.inc,v 1.23 2002/03/06 00:23:27 markus Exp $
CFLAGS+= -I${.CURDIR}/..
CFLAGS+= -Wall
CDIAGFLAGS= -Wall
#CDIAGFLAGS+= -Werror
CDIAGFLAGS+= -Wpointer-arith
CDIAGFLAGS+= -Wno-uninitialized
#CDIAGFLAGS+= -Wstrict-prototypes
CDIAGFLAGS+= -Wmissing-prototypes
CDIAGFLAGS+= -Wunused
#DEBUG=-g
#CFLAGS+= -DSMARTCARD
#LDADD+= -lsectok
.include <bsd.obj.mk>

View File

@ -1,9 +1,15 @@
[Note: This file has not been updated for OpenSSH versions after
OpenSSH-1.2 and should be considered OBSOLETE. It has been left in
the distribution because some of its information may still be useful
to developers.]
This document is intended for those who wish to read the ssh source
code. This tries to give an overview of the structure of the code.
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>
Updated 17 Nov 1995.
Updated 19 Oct 1999 for OpenSSH-1.2
Updated 20 May 2001 note obsolete for > OpenSSH-1.2
The software consists of ssh (client), sshd (server), scp, sdist, and
the auxiliary programs ssh-keygen, ssh-agent, ssh-add, and

View File

@ -14,7 +14,7 @@ To extract and install this release on your OpenBSD system use:
# make depend
# make
# make install
# cp ssh_config sshd_config /etc
# cp ssh_config sshd_config /etc/ssh
OpenSSH is a derivative of the original and free ssh 1.2.12 release
by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels

View File

@ -0,0 +1,69 @@
How to use smartcards with OpenSSH?
OpenSSH contains experimental support for authentication using
Cyberflex smartcards and TODOS card readers. To enable this you
need to:
(1) install sectok
$ cd /usr/src/lib/libsectok
$ make obj depend all install includes
$ cd /usr/src/usr.bin/sectok
$ make obj depend all install
(2) enable SMARTCARD support in OpenSSH:
$ vi /usr/src/usr.bin/ssh/Makefile.inc
and uncomment
CFLAGS+= -DSMARTCARD
LDADD+= -lsectok
(3) load the Java Cardlet to the Cyberflex card:
$ sectok
sectok> login -d
sectok> jload /usr/libdata/ssh/Ssh.bin
sectok> quit
(4) load a RSA key to the card:
please don't use your production RSA keys, since
with the current version of sectok/ssh-keygen
the private key file is still readable
$ ssh-keygen -f /path/to/rsakey -U 1
(where 1 is the reader number, you can also try 0)
In spite of the name, this does not generate a key.
It just loads an already existing key on to the card.
(5) optional:
Change the card password so that only you can
read the private key:
$ sectok
sectok> login -d
sectok> setpass
sectok> quit
This prevents reading the key but not use of the
key by the card applet.
Do not forget the passphrase. There is no way to
recover if you do.
IMPORTANT WARNING: If you attempt to login with the
wrong passphrase three times in a row, you will
destroy your card.
(6) tell the ssh client to use the card reader:
$ ssh -I 1 otherhost
(7) or tell the agent (don't forget to restart) to use the smartcard:
$ ssh-add -s 1
-markus,
Tue Jul 17 23:54:51 CEST 2001

View File

@ -24,9 +24,8 @@
*/
#include "includes.h"
RCSID("$OpenBSD: atomicio.c,v 1.9 2001/03/02 18:54:30 deraadt Exp $");
RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $");
#include "xmalloc.h"
#include "atomicio.h"
/*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */
/* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
@ -28,4 +28,4 @@
/*
* Ensure all of data on socket comes through. f==read || f==write
*/
ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n);
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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"
RCSID("$OpenBSD: auth-bsdauth.c,v 1.2 2001/12/19 07:18:56 deraadt Exp $");
#ifdef BSD_AUTH
#include "xmalloc.h"
#include "auth.h"
#include "log.h"
static void *
bsdauth_init_ctx(Authctxt *authctxt)
{
return authctxt;
}
static int
bsdauth_query(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on)
{
Authctxt *authctxt = ctx;
char *challenge = NULL;
if (authctxt->as != NULL) {
debug2("bsdauth_query: try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
if (challenge == NULL) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
}
if (challenge == NULL) {
debug2("bsdauth_query: new bsd auth session");
debug3("bsdauth_query: style %s",
authctxt->style ? authctxt->style : "<default>");
authctxt->as = auth_userchallenge(authctxt->user,
authctxt->style, "auth-ssh", &challenge);
if (authctxt->as == NULL)
challenge = NULL;
debug2("bsdauth_query: <%s>", challenge ? challenge : "empty");
}
if (challenge == NULL)
return -1;
*name = xstrdup("");
*infotxt = xstrdup("");
*numprompts = 1;
*prompts = xmalloc(*numprompts * sizeof(char*));
*echo_on = xmalloc(*numprompts * sizeof(u_int));
(*echo_on)[0] = 0;
(*prompts)[0] = xstrdup(challenge);
return 0;
}
static int
bsdauth_respond(void *ctx, u_int numresponses, char **responses)
{
Authctxt *authctxt = ctx;
int authok;
if (authctxt->as == 0)
error("bsdauth_respond: no bsd auth session");
if (numresponses != 1)
return -1;
authok = auth_userresponse(authctxt->as, responses[0], 0);
authctxt->as = NULL;
debug3("bsdauth_respond: <%s> = <%d>", responses[0], authok);
return (authok == 0) ? -1 : 0;
}
static void
bsdauth_free_ctx(void *ctx)
{
Authctxt *authctxt = ctx;
if (authctxt && authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
}
KbdintDevice bsdauth_device = {
"bsdauth",
bsdauth_init_ctx,
bsdauth_query,
bsdauth_respond,
bsdauth_free_ctx
};
#endif

View File

@ -23,82 +23,60 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
RCSID("$OpenBSD: auth-chall.c,v 1.8 2001/05/18 14:13:28 markus Exp $");
#include "auth.h"
#include "log.h"
#include "xmalloc.h"
/* limited protocol v1 interface to kbd-interactive authentication */
extern KbdintDevice *devices[];
static KbdintDevice *device;
#ifdef BSD_AUTH
char *
get_challenge(Authctxt *authctxt, char *devs)
get_challenge(Authctxt *authctxt)
{
char *challenge;
char *challenge, *name, *info, **prompts;
u_int i, numprompts;
u_int *echo_on;
if (authctxt->as != NULL) {
debug2("try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
if (challenge != NULL) {
debug2("reuse bsd auth session");
return challenge;
}
auth_close(authctxt->as);
authctxt->as = NULL;
device = devices[0]; /* we always use the 1st device for protocol 1 */
if (device == NULL)
return NULL;
if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
return NULL;
if (device->query(authctxt->kbdintctxt, &name, &info,
&numprompts, &prompts, &echo_on)) {
device->free_ctx(authctxt->kbdintctxt);
authctxt->kbdintctxt = NULL;
return NULL;
}
debug2("new bsd auth session");
if (devs == NULL || strlen(devs) == 0)
devs = authctxt->style;
debug3("bsd auth: devs %s", devs ? devs : "<default>");
authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
&challenge);
if (authctxt->as == NULL)
return NULL;
debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
return challenge;
}
int
verify_response(Authctxt *authctxt, char *response)
{
int authok;
if (numprompts < 1)
fatal("get_challenge: numprompts < 1");
challenge = xstrdup(prompts[0]);
for (i = 0; i < numprompts; i++)
xfree(prompts[i]);
xfree(prompts);
xfree(name);
xfree(echo_on);
xfree(info);
if (authctxt->as == 0)
error("verify_response: no bsd auth session");
authok = auth_userresponse(authctxt->as, response, 0);
authctxt->as = NULL;
debug("verify_response: <%s> = <%d>", response, authok);
return authok != 0;
return (challenge);
}
#else
#ifdef SKEY
#include <skey.h>
int
verify_response(Authctxt *authctxt, const char *response)
{
char *resp[1];
int res;
char *
get_challenge(Authctxt *authctxt, char *devs)
{
static char challenge[1024];
struct skey skey;
if (skeychallenge(&skey, authctxt->user, challenge) == -1)
return NULL;
strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
return challenge;
if (device == NULL)
return 0;
if (authctxt->kbdintctxt == NULL)
return 0;
resp[0] = (char *)response;
res = device->respond(authctxt->kbdintctxt, 1, resp);
device->free_ctx(authctxt->kbdintctxt);
authctxt->kbdintctxt = NULL;
return res ? 0 : 1;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return (authctxt->valid &&
skey_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, response) != -1);
}
#else
/* not available */
char *
get_challenge(Authctxt *authctxt, char *devs)
{
return NULL;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return 0;
}
#endif
#endif

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
RCSID("$OpenBSD: auth-krb4.c,v 1.25 2001/12/19 07:18:56 deraadt Exp $");
#include "ssh.h"
#include "ssh1.h"
@ -31,6 +31,7 @@ RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "auth.h"
#ifdef AFS
@ -38,48 +39,92 @@ RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
#endif
#ifdef KRB4
char *ticket = NULL;
extern ServerOptions options;
static int
krb4_init(void *context)
{
static int cleanup_registered = 0;
Authctxt *authctxt = (Authctxt *)context;
const char *tkt_root = TKT_ROOT;
struct stat st;
int fd;
if (!authctxt->krb4_ticket_file) {
/* Set unique ticket string manually since we're still root. */
authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
#ifdef AFS
if (lstat("/ticket", &st) != -1)
tkt_root = "/ticket/";
#endif /* AFS */
snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d",
tkt_root, authctxt->pw->pw_uid, getpid());
krb_set_tkt_string(authctxt->krb4_ticket_file);
}
/* Register ticket cleanup in case of fatal error. */
if (!cleanup_registered) {
fatal_add_cleanup(krb4_cleanup_proc, authctxt);
cleanup_registered = 1;
}
/* Try to create our ticket file. */
if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
close(fd);
return (1);
}
/* Ticket file exists - make sure user owns it (just passed ticket). */
if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
st.st_uid == authctxt->pw->pw_uid)
return (1);
}
/* Failure - cancel cleanup function, leaving ticket for inspection. */
log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
cleanup_registered = 0;
xfree(authctxt->krb4_ticket_file);
authctxt->krb4_ticket_file = NULL;
return (0);
}
/*
* try krb4 authentication,
* return 1 on success, 0 on failure, -1 if krb4 is not available
*/
int
auth_krb4_password(struct passwd * pw, const char *password)
auth_krb4_password(Authctxt *authctxt, const char *password)
{
AUTH_DAT adata;
KTEXT_ST tkt;
struct hostent *hp;
u_long faddr;
char localhost[MAXHOSTNAMELEN];
char phost[INST_SZ];
char realm[REALM_SZ];
struct passwd *pw;
char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
u_int32_t faddr;
int r;
if ((pw = authctxt->pw) == NULL)
return (0);
/*
* Try Kerberos password authentication only for non-root
* users and only if Kerberos is installed.
*/
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
/* Set up our ticket file. */
if (!krb4_init(pw->pw_uid)) {
if (!krb4_init(authctxt)) {
log("Couldn't initialize Kerberos ticket file for %s!",
pw->pw_name);
goto kerberos_auth_failure;
goto failure;
}
/* Try to get TGT using our password. */
r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
realm, "krbtgt", realm,
DEFAULT_TKT_LIFE, (char *) password);
r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
"krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
if (r != INTK_OK) {
packet_send_debug("Kerberos V4 password "
"authentication for %s failed: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
debug("Kerberos v4 password authentication for %s "
"failed: %s", pw->pw_name, krb_err_txt[r]);
goto failure;
}
/* Successful authentication. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
@ -89,17 +134,17 @@ auth_krb4_password(struct passwd * pw, const char *password)
* "rcmd" ticket to ensure that we are not talking
* to a bogus Kerberos server.
*/
(void) gethostname(localhost, sizeof(localhost));
(void) strlcpy(phost, (char *) krb_get_phost(localhost),
INST_SZ);
gethostname(localhost, sizeof(localhost));
strlcpy(phost, (char *)krb_get_phost(localhost),
sizeof(phost));
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
if (r == KSUCCESS) {
if (!(hp = gethostbyname(localhost))) {
if ((hp = gethostbyname(localhost)) == NULL) {
log("Couldn't get local host address!");
goto kerberos_auth_failure;
goto failure;
}
memmove((void *) &faddr, (void *) hp->h_addr,
memmove((void *)&faddr, (void *)hp->h_addr,
sizeof(faddr));
/* Verify our "rcmd" ticket. */
@ -110,116 +155,71 @@ auth_krb4_password(struct passwd * pw, const char *password)
* Probably didn't have a srvtab on
* localhost. Disallow login.
*/
log("Kerberos V4 TGT for %s unverifiable, "
log("Kerberos v4 TGT for %s unverifiable, "
"no srvtab installed? krb_rd_req: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
goto failure;
} else if (r != KSUCCESS) {
log("Kerberos V4 %s ticket unverifiable: %s",
log("Kerberos v4 %s ticket unverifiable: %s",
KRB4_SERVICE_NAME, krb_err_txt[r]);
goto kerberos_auth_failure;
goto failure;
}
} else if (r == KDC_PR_UNKNOWN) {
/*
* Disallow login if no rcmd service exists, and
* log the error.
*/
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
"not registered, or srvtab is wrong?", pw->pw_name,
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
goto kerberos_auth_failure;
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
goto failure;
} else {
/*
* TGT is bad, forget it. Possibly spoofed!
*/
packet_send_debug("WARNING: Kerberos V4 TGT "
"possibly spoofed for %s: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
debug("WARNING: Kerberos v4 TGT possibly spoofed "
"for %s: %s", pw->pw_name, krb_err_txt[r]);
goto failure;
}
/* Authentication succeeded. */
return 1;
kerberos_auth_failure:
krb4_cleanup_proc(NULL);
if (!options.kerberos_or_local_passwd)
return 0;
} else {
return (1);
} else
/* Logging in as root or no local Kerberos realm. */
packet_send_debug("Unable to authenticate to Kerberos.");
}
debug("Unable to authenticate to Kerberos.");
failure:
krb4_cleanup_proc(authctxt);
if (!options.kerberos_or_local_passwd)
return (0);
/* Fall back to ordinary passwd authentication. */
return -1;
return (-1);
}
void
krb4_cleanup_proc(void *ignore)
krb4_cleanup_proc(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
debug("krb4_cleanup_proc called");
if (ticket) {
if (authctxt->krb4_ticket_file) {
(void) dest_tkt();
xfree(ticket);
ticket = NULL;
xfree(authctxt->krb4_ticket_file);
authctxt->krb4_ticket_file = NULL;
}
}
int
krb4_init(uid_t uid)
{
static int cleanup_registered = 0;
const char *tkt_root = TKT_ROOT;
struct stat st;
int fd;
if (!ticket) {
/* Set unique ticket string manually since we're still root. */
ticket = xmalloc(MAXPATHLEN);
#ifdef AFS
if (lstat("/ticket", &st) != -1)
tkt_root = "/ticket/";
#endif /* AFS */
snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
(void) krb_set_tkt_string(ticket);
}
/* Register ticket cleanup in case of fatal error. */
if (!cleanup_registered) {
fatal_add_cleanup(krb4_cleanup_proc, NULL);
cleanup_registered = 1;
}
/* Try to create our ticket file. */
if ((fd = mkstemp(ticket)) != -1) {
close(fd);
return 1;
}
/* Ticket file exists - make sure user owns it (just passed ticket). */
if (lstat(ticket, &st) != -1) {
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
st.st_uid == uid)
return 1;
}
/* Failure - cancel cleanup function, leaving bad ticket for inspection. */
log("WARNING: bad ticket file %s", ticket);
fatal_remove_cleanup(krb4_cleanup_proc, NULL);
cleanup_registered = 0;
xfree(ticket);
ticket = NULL;
return 0;
}
int
auth_krb4(const char *server_user, KTEXT auth, char **client)
auth_krb4(Authctxt *authctxt, KTEXT auth, char **client)
{
AUTH_DAT adat = {0};
KTEXT_ST reply;
char instance[INST_SZ];
int r, s;
socklen_t slen;
u_int cksum;
Key_schedule schedule;
struct sockaddr_in local, foreign;
char instance[INST_SZ];
socklen_t slen;
u_int cksum;
int r, s;
s = packet_get_connection_in();
@ -237,9 +237,10 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
instance[1] = 0;
/* Get the encrypted request, challenge, and session key. */
if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
return 0;
if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
0, &adat, ""))) {
debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
return (0);
}
des_key_sched((des_cblock *) adat.session, schedule);
@ -248,12 +249,11 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
*adat.pinst ? "." : "", adat.pinst, adat.prealm);
/* Check ~/.klogin authorization now. */
if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
packet_send_debug("Kerberos V4 .klogin authorization failed!");
log("Kerberos V4 .klogin authorization failed for %s to account %s",
*client, server_user);
if (kuserok(&adat, authctxt->user) != KSUCCESS) {
log("Kerberos v4 .klogin authorization failed for %s to "
"account %s", *client, authctxt->user);
xfree(*client);
return 0;
return (0);
}
/* Increment the checksum, and return it encrypted with the
session key. */
@ -264,7 +264,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
empty message, admitting our failure. */
if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
schedule, &adat.session, &local, &foreign)) < 0) {
packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
reply.dat[0] = 0;
reply.length = 0;
} else
@ -277,89 +277,79 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
packet_put_string((char *) reply.dat, reply.length);
packet_send();
packet_write_wait();
return 1;
return (1);
}
#endif /* KRB4 */
#ifdef AFS
int
auth_kerberos_tgt(struct passwd *pw, const char *string)
auth_krb4_tgt(Authctxt *authctxt, const char *string)
{
CREDENTIALS creds;
struct passwd *pw;
if ((pw = authctxt->pw) == NULL)
goto failure;
temporarily_use_uid(pw);
if (pw == NULL)
goto auth_kerberos_tgt_failure;
if (!radix_to_creds(string, &creds)) {
log("Protocol error decoding Kerberos V4 tgt");
packet_send_debug("Protocol error decoding Kerberos V4 tgt");
goto auth_kerberos_tgt_failure;
log("Protocol error decoding Kerberos v4 TGT");
goto failure;
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "krbtgt", sizeof creds.service);
if (strcmp(creds.service, "krbtgt")) {
log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
pw->pw_name);
packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
creds.realm, pw->pw_name);
goto auth_kerberos_tgt_failure;
goto failure;
}
if (!krb4_init(pw->pw_uid))
goto auth_kerberos_tgt_failure;
if (!krb4_init(authctxt))
goto failure;
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
goto auth_kerberos_tgt_failure;
goto failure;
if (save_credentials(creds.service, creds.instance, creds.realm,
creds.session, creds.lifetime, creds.kvno,
&creds.ticket_st, creds.issue_date) != KSUCCESS) {
packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
goto auth_kerberos_tgt_failure;
creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
creds.issue_date) != KSUCCESS) {
debug("Kerberos v4 TGT refused: couldn't save credentials");
goto failure;
}
/* Successful authentication, passed all checks. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
creds.service, creds.instance, creds.realm, creds.pname,
creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
return 1;
auth_kerberos_tgt_failure:
krb4_cleanup_proc(NULL);
restore_uid();
return (1);
failure:
krb4_cleanup_proc(authctxt);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
restore_uid();
return (0);
}
int
auth_afs_token(struct passwd *pw, const char *token_string)
auth_afs_token(Authctxt *authctxt, const char *token_string)
{
CREDENTIALS creds;
struct passwd *pw;
uid_t uid;
if (pw == NULL) {
/* XXX fake protocol error */
packet_send_debug("Protocol error decoding AFS token");
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
}
if ((pw = authctxt->pw) == NULL)
return (0);
if (!radix_to_creds(token_string, &creds)) {
log("Protocol error decoding AFS token");
packet_send_debug("Protocol error decoding AFS token");
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
return (0);
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "afs", sizeof creds.service);
@ -370,22 +360,14 @@ auth_afs_token(struct passwd *pw, const char *token_string)
uid = pw->pw_uid;
if (kafs_settoken(creds.realm, uid, &creds)) {
log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
pw->pw_name);
packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
creds.realm, pw->pw_name);
log("AFS token (%s@%s) rejected for %s",
creds.pname, creds.realm, pw->pw_name);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
return (0);
}
packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
creds.realm, creds.pname, creds.realm);
debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
return 1;
return (1);
}
#endif /* AFS */

273
crypto/openssh/auth-krb5.c Normal file
View File

@ -0,0 +1,273 @@
/*
* Kerberos v5 authentication and ticket-passing routines.
*
* $FreeBSD$
*/
#include "includes.h"
RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $");
#include "ssh.h"
#include "ssh1.h"
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "auth.h"
#ifdef KRB5
#include <krb5.h>
extern ServerOptions options;
static int
krb5_init(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
krb5_error_code problem;
static int cleanup_registered = 0;
if (authctxt->krb5_ctx == NULL) {
problem = krb5_init_context(&authctxt->krb5_ctx);
if (problem)
return (problem);
krb5_init_ets(authctxt->krb5_ctx);
}
if (!cleanup_registered) {
fatal_add_cleanup(krb5_cleanup_proc, authctxt);
cleanup_registered = 1;
}
return (0);
}
/*
* Try krb5 authentication. server_user is passed for logging purposes
* only, in auth is received ticket, in client is returned principal
* from the ticket
*/
int
auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client)
{
krb5_error_code problem;
krb5_principal server;
krb5_data reply;
krb5_ticket *ticket;
int fd, ret;
ret = 0;
server = NULL;
ticket = NULL;
reply.length = 0;
problem = krb5_init(authctxt);
if (problem)
goto err;
problem = krb5_auth_con_init(authctxt->krb5_ctx,
&authctxt->krb5_auth_ctx);
if (problem)
goto err;
fd = packet_get_connection_in();
problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
authctxt->krb5_auth_ctx, &fd);
if (problem)
goto err;
problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL ,
KRB5_NT_SRV_HST, &server);
if (problem)
goto err;
problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
auth, server, NULL, NULL, &ticket);
if (problem)
goto err;
problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
&authctxt->krb5_user);
if (problem)
goto err;
/* if client wants mutual auth */
problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
&reply);
if (problem)
goto err;
/* Check .k5login authorization now. */
if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->pw->pw_name))
goto err;
if (client)
krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
client);
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
packet_put_string((char *) reply.data, reply.length);
packet_send();
packet_write_wait();
ret = 1;
err:
if (server)
krb5_free_principal(authctxt->krb5_ctx, server);
if (ticket)
krb5_free_ticket(authctxt->krb5_ctx, ticket);
if (reply.length)
xfree(reply.data);
if (problem) {
if (authctxt->krb5_ctx != NULL)
debug("Kerberos v5 authentication failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
else
debug("Kerberos v5 authentication failed: %d",
problem);
}
return (ret);
}
int
auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
{
krb5_error_code problem;
krb5_ccache ccache = NULL;
char *pname;
if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
return (0);
temporarily_use_uid(authctxt->pw);
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
if (problem)
goto fail;
problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
authctxt->krb5_user);
if (problem)
goto fail;
problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
ccache, tgt);
if (problem)
goto fail;
authctxt->krb5_fwd_ccache = ccache;
ccache = NULL;
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
&pname);
if (problem)
goto fail;
debug("Kerberos v5 TGT accepted (%s)", pname);
restore_uid();
return (1);
fail:
if (problem)
debug("Kerberos v5 TGT passing failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
if (ccache)
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
restore_uid();
return (0);
}
int
auth_krb5_password(Authctxt *authctxt, const char *password)
{
krb5_error_code problem;
if (authctxt->pw == NULL)
return (0);
temporarily_use_uid(authctxt->pw);
problem = krb5_init(authctxt);
if (problem)
goto out;
problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
&authctxt->krb5_user);
if (problem)
goto out;
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
&authctxt->krb5_fwd_ccache);
if (problem)
goto out;
problem = krb5_cc_initialize(authctxt->krb5_ctx,
authctxt->krb5_fwd_ccache, authctxt->krb5_user);
if (problem)
goto out;
restore_uid();
problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->krb5_fwd_ccache, password, 1, NULL);
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
out:
restore_uid();
if (problem) {
if (authctxt->krb5_ctx != NULL)
debug("Kerberos password authentication failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
else
debug("Kerberos password authentication failed: %d",
problem);
krb5_cleanup_proc(authctxt);
if (options.kerberos_or_local_passwd)
return (-1);
else
return (0);
}
return (1);
}
void
krb5_cleanup_proc(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
debug("krb5_cleanup_proc called");
if (authctxt->krb5_fwd_ccache) {
krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
authctxt->krb5_fwd_ccache = NULL;
}
if (authctxt->krb5_user) {
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
authctxt->krb5_user = NULL;
}
if (authctxt->krb5_auth_ctx) {
krb5_auth_con_free(authctxt->krb5_ctx,
authctxt->krb5_auth_ctx);
authctxt->krb5_auth_ctx = NULL;
}
if (authctxt->krb5_ctx) {
krb5_free_context(authctxt->krb5_ctx);
authctxt->krb5_ctx = NULL;
}
}
#endif /* KRB5 */

View File

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-options.c,v 1.16 2001/03/18 12:07:52 markus Exp $");
RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -20,6 +20,7 @@ RCSID("$OpenBSD: auth-options.c,v 1.16 2001/03/18 12:07:52 markus Exp $");
#include "channels.h"
#include "auth-options.h"
#include "servconf.h"
#include "misc.h"
/* Flags set authorized_keys flags */
int no_port_forwarding_flag = 0;
@ -167,10 +168,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "from=\"";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int mname, mip;
const char *remote_ip = get_remote_ipaddr();
const char *remote_host = get_canonical_hostname(
options.reverse_mapping_check);
options.verify_reverse_mapping);
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
@ -195,18 +195,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
patterns[i] = 0;
opts++;
/*
* Deny access if we get a negative
* match for the hostname or the ip
* or if we get not match at all
*/
mname = match_hostname(remote_host, patterns,
strlen(patterns));
mip = match_hostname(remote_ip, patterns,
strlen(patterns));
xfree(patterns);
if (mname == -1 || mip == -1 ||
(mname != 1 && mip != 1)) {
if (match_host_and_ip(remote_host, remote_ip,
patterns) != 1) {
xfree(patterns);
log("Authentication tried for %.100s with "
"correct key but not from a permitted "
"host (host=%.200s, ip=%.200s).",
@ -217,13 +208,14 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
/* deny access */
return 0;
}
xfree(patterns);
/* Host name matches. */
goto next_option;
}
cp = "permitopen=\"";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
char host[256], sport[6];
u_short port;
char *c, *ep;
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
@ -248,28 +240,25 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
patterns[i] = 0;
opts++;
c = strchr(patterns, ':');
if (c == NULL) {
debug("%.100s, line %lu: permitopen: missing colon <%.100s>",
file, linenum, patterns);
packet_send_debug("%.100s, line %lu: missing colon",
file, linenum);
if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
debug("%.100s, line %lu: Bad permitopen specification "
"<%.100s>", file, linenum, patterns);
packet_send_debug("%.100s, line %lu: "
"Bad permitopen specification", file, linenum);
xfree(patterns);
goto bad_option;
}
*c = 0;
c++;
port = strtol(c, &ep, 0);
if (c == ep) {
debug("%.100s, line %lu: permitopen: missing port <%.100s>",
file, linenum, patterns);
packet_send_debug("%.100s, line %lu: missing port",
file, linenum);
if ((port = a2port(sport)) == 0) {
debug("%.100s, line %lu: Bad permitopen port <%.100s>",
file, linenum, sport);
packet_send_debug("%.100s, line %lu: "
"Bad permitopen port", file, linenum);
xfree(patterns);
goto bad_option;
}
if (options.allow_tcp_forwarding)
channel_add_permitted_opens(patterns, port);
channel_add_permitted_opens(host, port);
xfree(patterns);
goto next_option;
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: auth-options.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,8 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: auth-options.h,v 1.8 2001/01/21 19:05:42 markus Exp $ */
#ifndef AUTH_OPTIONS_H
#define AUTH_OPTIONS_H
@ -30,15 +30,7 @@ extern int no_pty_flag;
extern char *forced_command;
extern struct envstring *custom_environment;
/*
* return 1 if access is granted, 0 if not.
* side effect: sets key option flags
*/
int
auth_parse_options(struct passwd *pw, char *options, char *file,
u_long linenum);
/* reset options flags */
int auth_parse_options(struct passwd *, char *, char *, u_long);
void auth_clear_options(void);
#endif

View File

@ -36,10 +36,9 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $");
RCSID("$OpenBSD: auth-passwd.c,v 1.24 2002/03/04 12:43:06 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
@ -64,6 +63,22 @@ auth_password(Authctxt *authctxt, const char *password)
return 0;
if (*password == '\0' && options.permit_empty_passwd == 0)
return 0;
#ifdef KRB5
if (options.kerberos_authentication == 1) {
int ret = auth_krb5_password(authctxt, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
#ifdef KRB4
if (options.kerberos_authentication == 1) {
int ret = auth_krb4_password(authctxt, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
#ifdef BSD_AUTH
if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
(char *)password) == 0)
@ -71,16 +86,6 @@ auth_password(Authctxt *authctxt, const char *password)
else
return 1;
#endif
#ifdef KRB4
if (options.kerberos_authentication == 1) {
int ret = auth_krb4_password(pw, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
/* Check for users with no password. */
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
return 1;

View File

@ -13,10 +13,9 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "log.h"
#include "servconf.h"
@ -24,7 +23,6 @@ RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
#include "hostfile.h"
#include "pathnames.h"
#include "auth.h"
#include "tildexpand.h"
#include "canohost.h"
/*
@ -33,16 +31,15 @@ RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
*/
int
auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key)
{
extern ServerOptions options;
const char *canonical_hostname;
HostStatus host_status;
Key *client_key, *found;
debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
if (pw == NULL || client_host_key == NULL)
if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL)
return 0;
/* Check if we would accept it using rhosts authentication. */
@ -50,45 +47,13 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
return 0;
canonical_hostname = get_canonical_hostname(
options.reverse_mapping_check);
options.verify_reverse_mapping);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
/* wrap the RSA key into a 'generic' key */
client_key = key_new(KEY_RSA1);
BN_copy(client_key->rsa->e, client_host_key->e);
BN_copy(client_key->rsa->n, client_host_key->n);
found = key_new(KEY_RSA1);
/* Check if we know the host and its host key. */
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
client_key, found, NULL);
/* Check user host file unless ignored. */
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
struct stat st;
char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
/*
* Check file permissions of _PATH_SSH_USER_HOSTFILE, auth_rsa()
* did already check pw->pw_dir, but there is a race XXX
*/
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
/* XXX race between stat and the following open() */
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
client_key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(client_key);
key_free(found);
host_status = check_key_in_hostfiles(pw, client_host_key,
canonical_hostname, _PATH_SSH_SYSTEM_HOSTFILE,
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
if (host_status != HOST_OK) {
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
@ -98,7 +63,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
/* A matching host key was found and is known. */
/* Perform the challenge-response dialog with the client for the host key. */
if (!auth_rsa_challenge_dialog(client_host_key)) {
if (!auth_rsa_challenge_dialog(client_host_key->rsa)) {
log("Client on %.800s failed to respond correctly to host authentication.",
canonical_hostname);
return 0;

View File

@ -14,10 +14,9 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rhosts.c,v 1.23 2001/04/12 19:15:24 markus Exp $");
RCSID("$OpenBSD: auth-rhosts.c,v 1.27 2002/03/04 12:43:06 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "pathnames.h"
#include "log.h"
@ -34,7 +33,7 @@ extern ServerOptions options;
* based on the file, and returns zero otherwise.
*/
int
static int
check_rhosts_file(const char *filename, const char *hostname,
const char *ipaddr, const char *client_user,
const char *server_user)
@ -156,7 +155,7 @@ auth_rhosts(struct passwd *pw, const char *client_user)
const char *hostname, *ipaddr;
int ret;
hostname = get_canonical_hostname(options.reverse_mapping_check);
hostname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
ret = auth_rhosts2(pw, client_user, hostname, ipaddr);
return ret;
@ -186,7 +185,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
* servers.
*/
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
rhosts_file_index++) {
rhosts_file_index++) {
/* Check users .rhosts or .shosts. */
snprintf(buf, sizeof buf, "%.500s/%.100s",
pw->pw_dir, rhosts_files[rhosts_file_index]);
@ -204,16 +203,16 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
if (pw->pw_uid != 0) {
if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user,
pw->pw_name)) {
if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr,
client_user, pw->pw_name)) {
packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
hostname, ipaddr);
hostname, ipaddr);
return 1;
}
if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
pw->pw_name)) {
if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr,
client_user, pw->pw_name)) {
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
return 1;
}
}
@ -230,7 +229,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
}
if (options.strict_modes &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
(st.st_mode & 022) != 0)) {
log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
pw->pw_name);
packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
@ -242,7 +241,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
/* Check all .rhosts files (currently .shosts and .rhosts). */
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
rhosts_file_index++) {
rhosts_file_index++) {
/* Check users .rhosts or .shosts. */
snprintf(buf, sizeof buf, "%.500s/%.100s",
pw->pw_dir, rhosts_files[rhosts_file_index]);
@ -257,7 +256,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
*/
if (options.strict_modes &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
(st.st_mode & 022) != 0)) {
log("Rhosts authentication refused for %.100s: bad modes for %.200s",
pw->pw_name, buf);
packet_send_debug("Bad file modes for %.200s", buf);

View File

@ -14,7 +14,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/md5.h>
@ -31,6 +31,7 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
#include "log.h"
#include "servconf.h"
#include "auth.h"
#include "hostfile.h"
/* import */
extern ServerOptions options;
@ -65,14 +66,17 @@ auth_rsa_challenge_dialog(RSA *pk)
u_char buf[32], mdbuf[16], response[16];
MD5_CTX md;
u_int i;
int plen, len;
int len;
encrypted_challenge = BN_new();
challenge = BN_new();
if ((encrypted_challenge = BN_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_new() failed");
if ((challenge = BN_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_new() failed");
/* Generate a random challenge. */
BN_rand(challenge, 256, 0, 0);
ctx = BN_CTX_new();
if ((ctx = BN_CTX_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_CTX_new() failed");
BN_mod(challenge, challenge, pk->n, ctx);
BN_CTX_free(ctx);
@ -87,10 +91,10 @@ auth_rsa_challenge_dialog(RSA *pk)
packet_write_wait();
/* Wait for a response. */
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
response[i] = packet_get_char();
packet_check_eom();
/* The response is MD5 of decrypted challenge plus session id. */
len = BN_num_bytes(challenge);
@ -122,13 +126,14 @@ auth_rsa_challenge_dialog(RSA *pk)
int
auth_rsa(struct passwd *pw, BIGNUM *client_n)
{
char line[8192], file[MAXPATHLEN];
char line[8192], *file;
int authenticated;
u_int bits;
FILE *f;
u_long linenum = 0;
struct stat st;
RSA *pk;
Key *key;
char *fp;
/* no user given */
if (pw == NULL)
@ -138,13 +143,14 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
_PATH_SSH_USER_PERMITTED_KEYS);
file = authorized_keys_file(pw);
debug("trying public RSA key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
/* Restore the privileged uid. */
restore_uid();
xfree(file);
return 0;
}
/* Open the file containing the authorized keys. */
@ -154,50 +160,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
packet_send_debug("Could not open %.900s for reading.", file);
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
xfree(file);
return 0;
}
if (options.strict_modes) {
int fail = 0;
char buf[1024];
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.", pw->pw_name, file);
fail = 1;
} else {
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.", pw->pw_name, line);
fail = 1;
break;
}
}
}
if (fail) {
fclose(f);
log("%s", buf);
packet_send_debug("%s", buf);
restore_uid();
return 0;
}
if (options.strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
xfree(file);
fclose(f);
log("Authentication refused: %s", line);
packet_send_debug("Authentication refused: %s", line);
restore_uid();
return 0;
}
/* Flag indicating whether authentication has succeeded. */
authenticated = 0;
pk = RSA_new();
pk->e = BN_new();
pk->n = BN_new();
key = key_new(KEY_RSA1);
/*
* Go though the accepted keys, looking for the current key. If
@ -235,24 +213,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
options = NULL;
/* Parse the key from the line. */
if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
debug("%.100s, line %lu: bad key syntax",
file, linenum);
packet_send_debug("%.100s, line %lu: bad key syntax",
if (hostfile_read_key(&cp, &bits, key) == 0) {
debug("%.100s, line %lu: non ssh1 key syntax",
file, linenum);
continue;
}
/* cp now points to the comment part. */
/* Check if the we have found the desired key (identified by its modulus). */
if (BN_cmp(pk->n, client_n) != 0)
if (BN_cmp(key->rsa->n, client_n) != 0)
continue;
/* check the real bits */
if (bits != BN_num_bits(pk->n))
log("Warning: %s, line %ld: keysize mismatch: "
if (bits != BN_num_bits(key->rsa->n))
log("Warning: %s, line %lu: keysize mismatch: "
"actual %d vs. announced %d.",
file, linenum, BN_num_bits(pk->n), bits);
file, linenum, BN_num_bits(key->rsa->n), bits);
/* We have found the desired key. */
/*
@ -263,11 +239,15 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
continue;
/* Perform the challenge-response dialog for this key. */
if (!auth_rsa_challenge_dialog(pk)) {
if (!auth_rsa_challenge_dialog(key->rsa)) {
/* Wrong response. */
verbose("Wrong response to RSA authentication challenge.");
packet_send_debug("Wrong response to RSA authentication challenge.");
continue;
/*
* Break out of the loop. Otherwise we might send
* another challenge and break the protocol.
*/
break;
}
/*
* Correct response. The client has been successfully
@ -278,6 +258,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
* otherwise continue searching.
*/
authenticated = 1;
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(key), fp);
xfree(fp);
break;
}
@ -285,9 +271,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
/* Close the file. */
xfree(file);
fclose(f);
RSA_free(pk);
key_free(key);
if (authenticated)
packet_send_debug("RSA authentication accepted.");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -21,185 +21,76 @@
* (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"
RCSID("$OpenBSD: auth-skey.c,v 1.9 2000/10/19 16:41:13 deraadt Exp $");
RCSID("$OpenBSD: auth-skey.c,v 1.16 2002/01/12 13:10:29 markus Exp $");
#include "ssh.h"
#include "packet.h"
#include <sha1.h>
#ifdef SKEY
/*
* try skey authentication,
* return 1 on success, 0 on failure, -1 if skey is not available
*/
#include <skey.h>
int
auth_skey_password(struct passwd * pw, const char *password)
#include "xmalloc.h"
#include "auth.h"
static void *
skey_init_ctx(Authctxt *authctxt)
{
if (strncasecmp(password, "s/key", 5) == 0) {
char *skeyinfo = skey_keyinfo(pw->pw_name);
if (skeyinfo == NULL) {
debug("generating fake skeyinfo for %.100s.",
pw->pw_name);
skeyinfo = skey_fake_keyinfo(pw->pw_name);
}
if (skeyinfo != NULL)
packet_send_debug("%s", skeyinfo);
/* Try again. */
return 0;
} else if (skey_haskey(pw->pw_name) == 0 &&
skey_passcheck(pw->pw_name, (char *) password) != -1) {
/* Authentication succeeded. */
return 1;
}
/* Fall back to ordinary passwd authentication. */
return authctxt;
}
#define PROMPT "\nS/Key Password: "
static int
skey_query(void *ctx, char **name, char **infotxt,
u_int* numprompts, char ***prompts, u_int **echo_on)
{
Authctxt *authctxt = ctx;
char challenge[1024], *p;
int len;
struct skey skey;
if (skeychallenge(&skey, authctxt->user, challenge) == -1)
return -1;
*name = xstrdup("");
*infotxt = xstrdup("");
*numprompts = 1;
*prompts = xmalloc(*numprompts * sizeof(char*));
*echo_on = xmalloc(*numprompts * sizeof(u_int));
(*echo_on)[0] = 0;
len = strlen(challenge) + strlen(PROMPT) + 1;
p = xmalloc(len);
strlcpy(p, challenge, len);
strlcat(p, PROMPT, len);
(*prompts)[0] = p;
return 0;
}
static int
skey_respond(void *ctx, u_int numresponses, char **responses)
{
Authctxt *authctxt = ctx;
if (authctxt->valid &&
numresponses == 1 &&
skey_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, responses[0]) != -1)
return 0;
return -1;
}
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
#define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \
((x)[3]))
/*
* hash_collapse()
*/
static u_int32_t
hash_collapse(s)
u_char *s;
static void
skey_free_ctx(void *ctx)
{
int len, target;
u_int32_t i;
if ((strlen(s) % sizeof(u_int32_t)) == 0)
target = strlen(s); /* Multiple of 4 */
else
target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
for (i = 0, len = 0; len < target; len += 4)
i ^= ROUND(s + len);
return i;
/* we don't have a special context */
}
char *
skey_fake_keyinfo(char *username)
{
int i;
u_int ptr;
u_char hseed[SKEY_MAX_SEED_LEN], flg = 1, *up;
char pbuf[SKEY_MAX_PW_LEN+1];
static char skeyprompt[SKEY_MAX_CHALLENGE+1];
char *secret = NULL;
size_t secretlen = 0;
SHA1_CTX ctx;
char *p, *u;
/*
* Base first 4 chars of seed on hostname.
* Add some filler for short hostnames if necessary.
*/
if (gethostname(pbuf, sizeof(pbuf)) == -1)
*(p = pbuf) = '.';
else
for (p = pbuf; *p && isalnum(*p); p++)
if (isalpha(*p) && isupper(*p))
*p = tolower(*p);
if (*p && pbuf - p < 4)
(void)strncpy(p, "asjd", 4 - (pbuf - p));
pbuf[4] = '\0';
/* Hash the username if possible */
if ((up = SHA1Data(username, strlen(username), NULL)) != NULL) {
struct stat sb;
time_t t;
int fd;
/* Collapse the hash */
ptr = hash_collapse(up);
memset(up, 0, strlen(up));
/* See if the random file's there, else use ctime */
if ((fd = open(_SKEY_RAND_FILE_PATH_, O_RDONLY)) != -1
&& fstat(fd, &sb) == 0 &&
sb.st_size > (off_t)SKEY_MAX_SEED_LEN &&
lseek(fd, ptr % (sb.st_size - SKEY_MAX_SEED_LEN),
SEEK_SET) != -1 && read(fd, hseed,
SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) {
close(fd);
fd = -1;
secret = hseed;
secretlen = SKEY_MAX_SEED_LEN;
flg = 0;
} else if (!stat(_PATH_MEM, &sb) || !stat("/", &sb)) {
t = sb.st_ctime;
secret = ctime(&t);
secretlen = strlen(secret);
flg = 0;
}
if (fd != -1)
close(fd);
}
/* Put that in your pipe and smoke it */
if (flg == 0) {
/* Hash secret value with username */
SHA1Init(&ctx);
SHA1Update(&ctx, secret, secretlen);
SHA1Update(&ctx, username, strlen(username));
SHA1End(&ctx, up);
/* Zero out */
memset(secret, 0, secretlen);
/* Now hash the hash */
SHA1Init(&ctx);
SHA1Update(&ctx, up, strlen(up));
SHA1End(&ctx, up);
ptr = hash_collapse(up + 4);
for (i = 4; i < 9; i++) {
pbuf[i] = (ptr % 10) + '0';
ptr /= 10;
}
pbuf[i] = '\0';
/* Sequence number */
ptr = ((up[2] + up[3]) % 99) + 1;
memset(up, 0, 20); /* SHA1 specific */
free(up);
(void)snprintf(skeyprompt, sizeof skeyprompt,
"otp-%.*s %d %.*s",
SKEY_MAX_HASHNAME_LEN,
skey_get_algorithm(),
ptr, SKEY_MAX_SEED_LEN,
pbuf);
} else {
/* Base last 8 chars of seed on username */
u = username;
i = 8;
p = &pbuf[4];
do {
if (*u == 0) {
/* Pad remainder with zeros */
while (--i >= 0)
*p++ = '0';
break;
}
*p++ = (*u++ % 10) + '0';
} while (--i != 0);
pbuf[12] = '\0';
(void)snprintf(skeyprompt, sizeof skeyprompt,
"otp-%.*s %d %.*s",
SKEY_MAX_HASHNAME_LEN,
skey_get_algorithm(),
99, SKEY_MAX_SEED_LEN, pbuf);
}
return skeyprompt;
}
KbdintDevice skey_device = {
"skey",
skey_init_ctx,
skey_query,
skey_respond,
skey_free_ctx
};
#endif /* SKEY */

View File

@ -23,7 +23,9 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
RCSID("$OpenBSD: auth.c,v 1.35 2002/03/01 13:12:10 markus Exp $");
#include <libgen.h>
#include "xmalloc.h"
#include "match.h"
@ -33,6 +35,10 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
#include "auth.h"
#include "auth-options.h"
#include "canohost.h"
#include "buffer.h"
#include "bufaux.h"
#include "uidswap.h"
#include "tildexpand.h"
/* import */
extern ServerOptions options;
@ -50,6 +56,7 @@ int
allowed_user(struct passwd * pw)
{
struct stat st;
const char *hostname = NULL, *ipaddr = NULL;
char *shell;
int i;
@ -64,36 +71,60 @@ allowed_user(struct passwd * pw)
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
/* deny if shell does not exists or is not executable */
if (stat(shell, &st) != 0)
if (stat(shell, &st) != 0) {
log("User %.100s not allowed because shell %.100s does not exist",
pw->pw_name, shell);
return 0;
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
}
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) {
log("User %.100s not allowed because shell %.100s is not executable",
pw->pw_name, shell);
return 0;
}
if (options.num_deny_users > 0 || options.num_allow_users > 0) {
hostname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
}
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
for (i = 0; i < options.num_deny_users; i++)
if (match_pattern(pw->pw_name, options.deny_users[i]))
if (match_user(pw->pw_name, hostname, ipaddr,
options.deny_users[i])) {
log("User %.100s not allowed because listed in DenyUsers",
pw->pw_name);
return 0;
}
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
for (i = 0; i < options.num_allow_users; i++)
if (match_pattern(pw->pw_name, options.allow_users[i]))
if (match_user(pw->pw_name, hostname, ipaddr,
options.allow_users[i]))
break;
/* i < options.num_allow_users iff we break for loop */
if (i >= options.num_allow_users)
if (i >= options.num_allow_users) {
log("User %.100s not allowed because not listed in AllowUsers",
pw->pw_name);
return 0;
}
}
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
/* Get the user's group access list (primary and supplementary) */
if (ga_init(pw->pw_name, pw->pw_gid) == 0)
if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
log("User %.100s not allowed because not in any group",
pw->pw_name);
return 0;
}
/* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0)
if (ga_match(options.deny_groups,
options.num_deny_groups)) {
ga_free();
log("User %.100s not allowed because a group is listed in DenyGroups",
pw->pw_name);
return 0;
}
/*
@ -104,6 +135,8 @@ allowed_user(struct passwd * pw)
if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
pw->pw_name);
return 0;
}
ga_free();
@ -142,7 +175,7 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
authctxt->valid && authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user,
authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
info);
@ -172,3 +205,184 @@ auth_root_allowed(char *method)
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}
/*
* Given a template and a passwd structure, build a filename
* by substituting % tokenised options. Currently, %% becomes '%',
* %h becomes the home directory and %u the username.
*
* This returns a buffer allocated by xmalloc.
*/
char *
expand_filename(const char *filename, struct passwd *pw)
{
Buffer buffer;
char *file;
const char *cp;
/*
* Build the filename string in the buffer by making the appropriate
* substitutions to the given file name.
*/
buffer_init(&buffer);
for (cp = filename; *cp; cp++) {
if (cp[0] == '%' && cp[1] == '%') {
buffer_append(&buffer, "%", 1);
cp++;
continue;
}
if (cp[0] == '%' && cp[1] == 'h') {
buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
cp++;
continue;
}
if (cp[0] == '%' && cp[1] == 'u') {
buffer_append(&buffer, pw->pw_name,
strlen(pw->pw_name));
cp++;
continue;
}
buffer_append(&buffer, cp, 1);
}
buffer_append(&buffer, "\0", 1);
/*
* Ensure that filename starts anchored. If not, be backward
* compatible and prepend the '%h/'
*/
file = xmalloc(MAXPATHLEN);
cp = buffer_ptr(&buffer);
if (*cp != '/')
snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
else
strlcpy(file, cp, MAXPATHLEN);
buffer_free(&buffer);
return file;
}
char *
authorized_keys_file(struct passwd *pw)
{
return expand_filename(options.authorized_keys_file, pw);
}
char *
authorized_keys_file2(struct passwd *pw)
{
return expand_filename(options.authorized_keys_file2, pw);
}
/* return ok if key exists in sysfile or userfile */
HostStatus
check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
const char *sysfile, const char *userfile)
{
Key *found;
char *user_hostfile;
struct stat st;
HostStatus host_status;
/* Check if we know the host and its host key. */
found = key_new(key->type);
host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
if (host_status != HOST_OK && userfile != NULL) {
user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
log("Authentication refused for %.100s: "
"bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile,
host, key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(found);
debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", host);
return host_status;
}
/*
* Check a given file for security. This is defined as all components
* of the path to the file must either be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes an open file descriptor, the file name, a uid and and
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
secure_filename(FILE *f, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
uid_t uid = pw->pw_uid;
char buf[MAXPATHLEN], homedir[MAXPATHLEN];
char *cp;
struct stat st;
if (realpath(file, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", file,
strerror(errno));
return -1;
}
if (realpath(pw->pw_dir, homedir) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir,
strerror(errno));
return -1;
}
/* check the open file to avoid races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
debug3("secure_filename: checking '%s'", buf);
if (stat(buf, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are passed the homedir then we can stop */
if (strcmp(homedir, buf) == 0) {
debug3("secure_filename: terminating check at '%s'",
buf);
break;
}
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: auth.h,v 1.29 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -21,11 +23,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
*/
#ifndef AUTH_H
#define AUTH_H
#include "key.h"
#include "hostfile.h"
#include <openssl/rsa.h>
#ifdef HAVE_LOGIN_CAP
@ -34,107 +38,115 @@
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
#ifdef KRB5
#include <krb5.h>
#endif
typedef struct Authctxt Authctxt;
typedef struct KbdintDevice KbdintDevice;
struct Authctxt {
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
void *kbdintctxt;
#ifdef BSD_AUTH
auth_session_t *as;
auth_session_t *as;
#endif
#ifdef KRB4
char *krb4_ticket_file;
#endif
#ifdef KRB5
krb5_context krb5_ctx;
krb5_auth_context krb5_auth_ctx;
krb5_ccache krb5_fwd_ccache;
krb5_principal krb5_user;
char *krb5_ticket_file;
#endif
};
/*
* Tries to authenticate the user using the .rhosts file. Returns true if
* authentication succeeds. If ignore_rhosts is non-zero, this will not
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
* Keyboard interactive device:
* init_ctx returns: non NULL upon success
* query returns: 0 - success, otherwise failure
* respond returns: 0 - success, 1 - need further interaction,
* otherwise - failure
*/
int auth_rhosts(struct passwd * pw, const char *client_user);
struct KbdintDevice
{
const char *name;
void* (*init_ctx)(Authctxt*);
int (*query)(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on);
int (*respond)(void *ctx, u_int numresp, char **responses);
void (*free_ctx)(void *ctx);
};
/* extended interface similar to auth_rhosts() */
int auth_rhosts(struct passwd *, const char *);
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr);
auth_rhosts2(struct passwd *, const char *, const char *, const char *);
/*
* Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int auth_password(Authctxt *authctxt, const char *password);
/*
* Performs the RSA authentication dialog with the client. This returns 0 if
* the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
/*
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Performs the RSA authentication challenge-response dialog with the client,
* and returns true (non-zero) if the client gave the correct answer to our
* challenge; returns zero if the client gives a wrong answer.
*/
int auth_rsa_challenge_dialog(RSA *pk);
int auth_rhosts_rsa(struct passwd *, const char *, Key *);
int auth_password(Authctxt *, const char *);
int auth_rsa(struct passwd *, BIGNUM *);
int auth_rsa_challenge_dialog(RSA *);
#ifdef KRB4
#include <krb.h>
/*
* Performs Kerberos v4 mutual authentication with the client. This returns 0
* if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_krb4(const char *server_user, KTEXT auth, char **client);
int krb4_init(uid_t uid);
void krb4_cleanup_proc(void *ignore);
int auth_krb4_password(struct passwd * pw, const char *password);
int auth_krb4(Authctxt *, KTEXT, char **);
int auth_krb4_password(Authctxt *, const char *);
void krb4_cleanup_proc(void *);
#ifdef AFS
#include <kafs.h>
int auth_krb4_tgt(Authctxt *, const char *);
int auth_afs_token(Authctxt *, const char *);
#endif /* AFS */
/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
int auth_kerberos_tgt(struct passwd * pw, const char *string);
int auth_afs_token(struct passwd * pw, const char *token_string);
#endif /* AFS */
#endif /* KRB4 */
#endif /* KRB4 */
#ifdef KRB5
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client);
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
int auth_krb5_password(Authctxt *authctxt, const char *password);
void krb5_cleanup_proc(void *authctxt);
#endif /* KRB5 */
void do_authentication(void);
void do_authentication2(void);
Authctxt *authctxt_new(void);
void auth_log(Authctxt *authctxt, int authenticated, char *method, char *info);
void userauth_finish(Authctxt *authctxt, int authenticated, char *method);
int auth_root_allowed(char *method);
void auth_log(Authctxt *, int, char *, char *);
void userauth_finish(Authctxt *, int, char *);
int auth_root_allowed(char *);
int auth2_challenge(Authctxt *authctxt, char *devs);
int auth2_challenge(Authctxt *, char *);
void auth2_challenge_stop(Authctxt *);
int allowed_user(struct passwd * pw);
int allowed_user(struct passwd *);
char *get_challenge(Authctxt *authctxt, char *devs);
int verify_response(Authctxt *authctxt, char *response);
char *get_challenge(Authctxt *);
int verify_response(Authctxt *, const char *);
struct passwd * auth_get_user(void);
char *expand_filename(const char *, struct passwd *);
char *authorized_keys_file(struct passwd *);
char *authorized_keys_file2(struct passwd *);
int
secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
HostStatus
check_key_in_hostfiles(struct passwd *, Key *, const char *,
const char *, const char *);
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"

View File

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
@ -22,8 +22,10 @@ RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
#include "servconf.h"
#include "compat.h"
#include "auth.h"
#include "channels.h"
#include "session.h"
#include "misc.h"
#include "uidswap.h"
/* import */
extern ServerOptions options;
@ -31,7 +33,7 @@ extern ServerOptions options;
/*
* convert ssh auth msg type into description
*/
char *
static char *
get_authname(int type)
{
static char buf[1024];
@ -47,7 +49,7 @@ get_authname(int type)
case SSH_CMSG_AUTH_TIS:
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "challenge-response";
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
case SSH_CMSG_AUTH_KERBEROS:
return "kerberos";
#endif
@ -60,27 +62,26 @@ get_authname(int type)
* read packets, try to authenticate the user and
* return only if authentication is successful
*/
void
static void
do_authloop(Authctxt *authctxt)
{
int authenticated = 0;
u_int bits;
RSA *client_host_key;
Key *client_host_key;
BIGNUM *n;
char *client_user, *password;
char info[1024];
u_int dlen;
int plen, nlen, elen;
u_int ulen;
int type = 0;
struct passwd *pw = authctxt->pw;
debug("Attempting authentication for %s%.100s.",
authctxt->valid ? "" : "illegal user ", authctxt->user);
authctxt->valid ? "" : "illegal user ", authctxt->user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
auth_password(authctxt, "")) {
@ -100,65 +101,66 @@ do_authloop(Authctxt *authctxt)
info[0] = '\0';
/* Get a packet from the client. */
type = packet_read(&plen);
type = packet_read();
/* Process the packet. */
switch (type) {
#ifdef AFS
case SSH_CMSG_HAVE_KERBEROS_TGT:
if (!options.kerberos_tgt_passing) {
verbose("Kerberos tgt passing disabled.");
break;
} else {
/* Accept Kerberos tgt. */
char *tgt = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_kerberos_tgt(pw, tgt))
verbose("Kerberos tgt REFUSED for %.100s", authctxt->user);
xfree(tgt);
}
continue;
case SSH_CMSG_HAVE_AFS_TOKEN:
if (!options.afs_token_passing || !k_hasafs()) {
verbose("AFS token passing disabled.");
break;
} else {
/* Accept AFS token. */
char *token_string = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_afs_token(pw, token_string))
verbose("AFS token REFUSED for %.100s", authctxt->user);
xfree(token_string);
}
continue;
#endif /* AFS */
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) {
verbose("Kerberos authentication disabled.");
break;
} else {
/* Try Kerberos v4 authentication. */
KTEXT_ST auth;
char *tkt_user = NULL;
char *kdata = packet_get_string((u_int *) &auth.length);
packet_integrity_check(plen, 4 + auth.length, type);
char *kdata = packet_get_string(&dlen);
packet_check_eom();
if (authctxt->valid) {
if (auth.length < MAX_KTXT_LEN)
memcpy(auth.dat, kdata, auth.length);
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
if (authenticated) {
snprintf(info, sizeof info,
" tktuser %.100s", tkt_user);
xfree(tkt_user);
if (kdata[0] == 4) { /* KRB_PROT_VERSION */
#ifdef KRB4
KTEXT_ST tkt;
tkt.length = dlen;
if (tkt.length < MAX_KTXT_LEN)
memcpy(tkt.dat, kdata, tkt.length);
if (auth_krb4(authctxt, &tkt, &client_user)) {
authenticated = 1;
snprintf(info, sizeof(info),
" tktuser %.100s",
client_user);
xfree(client_user);
}
#endif /* KRB4 */
} else {
#ifdef KRB5
krb5_data tkt;
tkt.length = dlen;
tkt.data = kdata;
if (auth_krb5(authctxt, &tkt, &client_user)) {
authenticated = 1;
snprintf(info, sizeof(info),
" tktuser %.100s",
client_user);
xfree(client_user);
}
#endif /* KRB5 */
}
xfree(kdata);
}
break;
#endif /* KRB4 */
#endif /* KRB4 || KRB5 */
#if defined(AFS) || defined(KRB5)
/* XXX - punt on backward compatibility here. */
case SSH_CMSG_HAVE_KERBEROS_TGT:
packet_send_debug("Kerberos TGT passing disabled before authentication.");
break;
#ifdef AFS
case SSH_CMSG_HAVE_AFS_TOKEN:
packet_send_debug("AFS token passing disabled before authentication.");
break;
#endif /* AFS */
#endif /* AFS || KRB5 */
case SSH_CMSG_AUTH_RHOSTS:
if (!options.rhosts_authentication) {
@ -172,7 +174,7 @@ do_authloop(Authctxt *authctxt)
* IP-spoofing on a local network.)
*/
client_user = packet_get_string(&ulen);
packet_integrity_check(plen, 4 + ulen, type);
packet_check_eom();
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
authenticated = auth_rhosts(pw, client_user);
@ -194,24 +196,20 @@ do_authloop(Authctxt *authctxt)
client_user = packet_get_string(&ulen);
/* Get the client host key. */
client_host_key = RSA_new();
if (client_host_key == NULL)
fatal("RSA_new failed");
client_host_key->e = BN_new();
client_host_key->n = BN_new();
if (client_host_key->e == NULL || client_host_key->n == NULL)
fatal("BN_new failed");
client_host_key = key_new(KEY_RSA1);
bits = packet_get_int();
packet_get_bignum(client_host_key->e, &elen);
packet_get_bignum(client_host_key->n, &nlen);
packet_get_bignum(client_host_key->rsa->e);
packet_get_bignum(client_host_key->rsa->n);
if (bits != BN_num_bits(client_host_key->n))
if (bits != BN_num_bits(client_host_key->rsa->n))
verbose("Warning: keysize mismatch for client_host_key: "
"actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
"actual %d, announced %d",
BN_num_bits(client_host_key->rsa->n), bits);
packet_check_eom();
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
RSA_free(client_host_key);
authenticated = auth_rhosts_rsa(pw, client_user,
client_host_key);
key_free(client_host_key);
snprintf(info, sizeof info, " ruser %.100s", client_user);
xfree(client_user);
@ -223,9 +221,10 @@ do_authloop(Authctxt *authctxt)
break;
}
/* RSA authentication requested. */
n = BN_new();
packet_get_bignum(n, &nlen);
packet_integrity_check(plen, nlen, type);
if ((n = BN_new()) == NULL)
fatal("do_authloop: BN_new failed");
packet_get_bignum(n);
packet_check_eom();
authenticated = auth_rsa(pw, n);
BN_clear_free(n);
break;
@ -241,7 +240,7 @@ do_authloop(Authctxt *authctxt)
* not visible to an outside observer.
*/
password = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
packet_check_eom();
/* Try authentication with the password. */
authenticated = auth_password(authctxt, password);
@ -252,12 +251,13 @@ do_authloop(Authctxt *authctxt)
case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS");
if (options.challenge_reponse_authentication == 1) {
char *challenge = get_challenge(authctxt, authctxt->style);
if (options.challenge_response_authentication == 1) {
char *challenge = get_challenge(authctxt);
if (challenge != NULL) {
debug("sending challenge '%s'", challenge);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_cstring(challenge);
xfree(challenge);
packet_send();
packet_write_wait();
continue;
@ -266,10 +266,10 @@ do_authloop(Authctxt *authctxt)
break;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (options.challenge_reponse_authentication == 1) {
if (options.challenge_response_authentication == 1) {
char *response = packet_get_string(&dlen);
debug("got response '%s'", response);
packet_integrity_check(plen, 4 + dlen, type);
packet_check_eom();
authenticated = verify_response(authctxt, response);
memset(response, 'r', dlen);
xfree(response);
@ -319,23 +319,26 @@ do_authloop(Authctxt *authctxt)
* been exchanged and encryption is enabled.
*/
void
do_authentication()
do_authentication(void)
{
Authctxt *authctxt;
struct passwd *pw;
int plen;
u_int ulen;
char *user, *style = NULL;
char *p, *user, *style = NULL;
/* Get the name of the user that we wish to log in as. */
packet_read_expect(&plen, SSH_CMSG_USER);
packet_read_expect(SSH_CMSG_USER);
/* Get the user name. */
user = packet_get_string(&ulen);
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
packet_check_eom();
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
*style++ = '\0';
/* XXX - SSH.com Kerberos v5 braindeath. */
if ((p = strchr(user, '@')) != NULL)
*p = '\0';
authctxt = authctxt_new();
authctxt->user = user;

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Per Allansson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -22,91 +23,290 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $");
RCSID("$OpenBSD: auth2-chall.c,v 1.16 2002/01/13 17:57:37 markus Exp $");
#include "ssh2.h"
#include "auth.h"
#include "buffer.h"
#include "packet.h"
#include "xmalloc.h"
#include "dispatch.h"
#include "auth.h"
#include "log.h"
void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo);
void input_userauth_info_response(int type, int plen, void *ctxt);
static int auth2_challenge_start(Authctxt *);
static int send_userauth_info_request(Authctxt *);
static void input_userauth_info_response(int, u_int32_t, void *);
#ifdef BSD_AUTH
extern KbdintDevice bsdauth_device;
#else
#ifdef SKEY
extern KbdintDevice skey_device;
#endif
#endif
KbdintDevice *devices[] = {
#ifdef BSD_AUTH
&bsdauth_device,
#else
#ifdef SKEY
&skey_device,
#endif
#endif
NULL
};
typedef struct KbdintAuthctxt KbdintAuthctxt;
struct KbdintAuthctxt
{
char *devices;
void *ctxt;
KbdintDevice *device;
};
static KbdintAuthctxt *
kbdint_alloc(const char *devs)
{
KbdintAuthctxt *kbdintctxt;
Buffer b;
int i;
kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
if (strcmp(devs, "") == 0) {
buffer_init(&b);
for (i = 0; devices[i]; i++) {
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, devices[i]->name,
strlen(devices[i]->name));
}
buffer_append(&b, "\0", 1);
kbdintctxt->devices = xstrdup(buffer_ptr(&b));
buffer_free(&b);
} else {
kbdintctxt->devices = xstrdup(devs);
}
debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
kbdintctxt->ctxt = NULL;
kbdintctxt->device = NULL;
return kbdintctxt;
}
static void
kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
{
if (kbdintctxt->ctxt) {
kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
kbdintctxt->ctxt = NULL;
}
kbdintctxt->device = NULL;
}
static void
kbdint_free(KbdintAuthctxt *kbdintctxt)
{
if (kbdintctxt->device)
kbdint_reset_device(kbdintctxt);
if (kbdintctxt->devices) {
xfree(kbdintctxt->devices);
kbdintctxt->devices = NULL;
}
xfree(kbdintctxt);
}
/* get next device */
static int
kbdint_next_device(KbdintAuthctxt *kbdintctxt)
{
size_t len;
char *t;
int i;
if (kbdintctxt->device)
kbdint_reset_device(kbdintctxt);
do {
len = kbdintctxt->devices ?
strcspn(kbdintctxt->devices, ",") : 0;
if (len == 0)
break;
for (i = 0; devices[i]; i++)
if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
kbdintctxt->device = devices[i];
t = kbdintctxt->devices;
kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
xfree(t);
debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
kbdintctxt->devices : "<empty>");
} while (kbdintctxt->devices && !kbdintctxt->device);
return kbdintctxt->device ? 1 : 0;
}
/*
* try challenge-reponse, return -1 (= postponed) if we have to
* try challenge-response, set authctxt->postponed if we have to
* wait for the response.
*/
int
auth2_challenge(Authctxt *authctxt, char *devs)
{
char *challenge;
debug("auth2_challenge: user=%s devs=%s",
authctxt->user ? authctxt->user : "<nouser>",
devs ? devs : "<no devs>");
if (!authctxt->valid || authctxt->user == NULL)
if (authctxt->user == NULL || !devs)
return 0;
if ((challenge = get_challenge(authctxt, devs)) == NULL)
if (authctxt->kbdintctxt == NULL)
authctxt->kbdintctxt = kbdint_alloc(devs);
return auth2_challenge_start(authctxt);
}
/* unregister kbd-int callbacks and context */
void
auth2_challenge_stop(Authctxt *authctxt)
{
/* unregister callback */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
if (authctxt->kbdintctxt != NULL) {
kbdint_free(authctxt->kbdintctxt);
authctxt->kbdintctxt = NULL;
}
}
/* side effect: sets authctxt->postponed if a reply was sent*/
static int
auth2_challenge_start(Authctxt *authctxt)
{
KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
debug2("auth2_challenge_start: devices %s",
kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
if (kbdint_next_device(kbdintctxt) == 0) {
auth2_challenge_stop(authctxt);
return 0;
send_userauth_into_request(authctxt, challenge, 0);
}
debug("auth2_challenge_start: trying authentication method '%s'",
kbdintctxt->device->name);
if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
auth2_challenge_stop(authctxt);
return 0;
}
if (send_userauth_info_request(authctxt) == 0) {
auth2_challenge_stop(authctxt);
return 0;
}
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
&input_userauth_info_response);
authctxt->postponed = 1;
return 0;
}
void
send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo)
static int
send_userauth_info_request(Authctxt *authctxt)
{
int nprompts = 1;
KbdintAuthctxt *kbdintctxt;
char *name, *instr, **prompts;
int i;
u_int numprompts, *echo_on;
kbdintctxt = authctxt->kbdintctxt;
if (kbdintctxt->device->query(kbdintctxt->ctxt,
&name, &instr, &numprompts, &prompts, &echo_on))
return 0;
packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
/* name, instruction and language are unused */
packet_put_cstring("");
packet_put_cstring("");
packet_put_cstring("");
packet_put_int(nprompts);
packet_put_cstring(challenge);
packet_put_char(echo);
packet_put_cstring(name);
packet_put_cstring(instr);
packet_put_cstring(""); /* language not used */
packet_put_int(numprompts);
for (i = 0; i < numprompts; i++) {
packet_put_cstring(prompts[i]);
packet_put_char(echo_on[i]);
}
packet_send();
packet_write_wait();
for (i = 0; i < numprompts; i++)
xfree(prompts[i]);
xfree(prompts);
xfree(echo_on);
xfree(name);
xfree(instr);
return 1;
}
void
input_userauth_info_response(int type, int plen, void *ctxt)
static void
input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
int authenticated = 0;
u_int nresp, rlen;
char *response, *method = "challenge-reponse";
KbdintAuthctxt *kbdintctxt;
int i, authenticated = 0, res, len;
u_int nresp;
char **response = NULL, *method;
if (authctxt == NULL)
fatal("input_userauth_info_response: no authctxt");
kbdintctxt = authctxt->kbdintctxt;
if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
fatal("input_userauth_info_response: no kbdintctxt");
if (kbdintctxt->device == NULL)
fatal("input_userauth_info_response: no device");
authctxt->postponed = 0; /* reset */
nresp = packet_get_int();
if (nresp == 1) {
response = packet_get_string(&rlen);
packet_done();
if (strlen(response) == 0) {
/*
* if we received an empty response, resend challenge
* with echo enabled
*/
char *challenge = get_challenge(authctxt, NULL);
if (challenge != NULL) {
send_userauth_into_request(authctxt,
challenge, 1);
authctxt->postponed = 1;
}
} else if (authctxt->valid) {
authenticated = verify_response(authctxt, response);
memset(response, 'r', rlen);
}
xfree(response);
if (nresp > 0) {
response = xmalloc(nresp * sizeof(char*));
for (i = 0; i < nresp; i++)
response[i] = packet_get_string(NULL);
}
/* unregister callback */
if (!authctxt->postponed)
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
packet_check_eom();
if (authctxt->valid) {
res = kbdintctxt->device->respond(kbdintctxt->ctxt,
nresp, response);
} else {
res = -1;
}
for (i = 0; i < nresp; i++) {
memset(response[i], 'r', strlen(response[i]));
xfree(response[i]);
}
if (response)
xfree(response);
switch (res) {
case 0:
/* Success! */
authenticated = 1;
break;
case 1:
/* Authentication needs further interaction */
if (send_userauth_info_request(authctxt) == 1)
authctxt->postponed = 1;
break;
default:
/* Failure! */
break;
}
len = strlen("keyboard-interactive") + 2 +
strlen(kbdintctxt->device->name);
method = xmalloc(len);
snprintf(method, len, "keyboard-interactive/%s",
kbdintctxt->device->name);
if (!authctxt->postponed) {
if (authenticated) {
auth2_challenge_stop(authctxt);
} else {
/* start next device */
/* may set authctxt->postponed */
auth2_challenge_start(authctxt);
}
}
userauth_finish(authctxt, authenticated, method);
xfree(method);
}

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $");
#include <openssl/evp.h>
@ -50,7 +50,7 @@ RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
#include "misc.h"
#include "hostfile.h"
#include "canohost.h"
#include "tildexpand.h"
#include "match.h"
/* import */
extern ServerOptions options;
@ -69,26 +69,22 @@ struct Authmethod {
/* protocol */
void input_service_request(int type, int plen, void *ctxt);
void input_userauth_request(int type, int plen, void *ctxt);
void protocol_error(int type, int plen, void *ctxt);
static void input_service_request(int, u_int32_t, void *);
static void input_userauth_request(int, u_int32_t, void *);
/* helper */
Authmethod *authmethod_lookup(const char *name);
char *authmethods_get(void);
int user_key_allowed(struct passwd *pw, Key *key);
int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key);
static Authmethod *authmethod_lookup(const char *);
static char *authmethods_get(void);
static int user_key_allowed(struct passwd *, Key *);
static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
/* auth */
void userauth_banner(void);
void userauth_reply(Authctxt *authctxt, int authenticated);
int userauth_none(Authctxt *authctxt);
int userauth_passwd(Authctxt *authctxt);
int userauth_pubkey(Authctxt *authctxt);
int userauth_hostbased(Authctxt *authctxt);
int userauth_kbdint(Authctxt *authctxt);
static void userauth_banner(void);
static int userauth_none(Authctxt *);
static int userauth_passwd(Authctxt *);
static int userauth_pubkey(Authctxt *);
static int userauth_hostbased(Authctxt *);
static int userauth_kbdint(Authctxt *);
Authmethod authmethods[] = {
{"none",
@ -114,40 +110,30 @@ Authmethod authmethods[] = {
*/
void
do_authentication2()
do_authentication2(void)
{
Authctxt *authctxt = authctxt_new();
x_authctxt = authctxt; /*XXX*/
/* challenge-reponse is implemented via keyboard interactive */
if (options.challenge_reponse_authentication)
/* challenge-response is implemented via keyboard interactive */
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
dispatch_init(&protocol_error);
dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated(authctxt);
}
void
protocol_error(int type, int plen, void *ctxt)
{
log("auth: protocol error: type %d plen %d", type, plen);
packet_start(SSH2_MSG_UNIMPLEMENTED);
packet_put_int(0);
packet_send();
packet_write_wait();
}
void
input_service_request(int type, int plen, void *ctxt)
static void
input_service_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
u_int len;
int accept = 0;
char *service = packet_get_string(&len);
packet_done();
packet_check_eom();
if (authctxt == NULL)
fatal("input_service_request: no authctxt");
@ -173,8 +159,8 @@ input_service_request(int type, int plen, void *ctxt)
xfree(service);
}
void
input_userauth_request(int type, int plen, void *ctxt)
static void
input_userauth_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
Authmethod *m = NULL;
@ -207,24 +193,16 @@ input_userauth_request(int type, int plen, void *ctxt)
setproctitle("%s", pw ? user : "unknown");
authctxt->user = xstrdup(user);
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
} else if (authctxt->valid) {
if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
user, service, authctxt->user, authctxt->service);
authctxt->valid = 0;
}
authctxt->style = style ? xstrdup(style) : NULL;
} else if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
packet_disconnect("Change of username or service not allowed: "
"(%s,%s) -> (%s,%s)",
authctxt->user, authctxt->service, user, service);
}
/* reset state */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
auth2_challenge_stop(authctxt);
authctxt->postponed = 0;
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
#endif
/* try to authenticate user */
m = authmethod_lookup(method);
@ -242,6 +220,8 @@ input_userauth_request(int type, int plen, void *ctxt)
void
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
{
char *methods;
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
@ -254,11 +234,32 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
/* Log before sending the reply */
auth_log(authctxt, authenticated, method, " ssh2");
if (!authctxt->postponed)
userauth_reply(authctxt, authenticated);
if (authctxt->postponed)
return;
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
/* now we can break out */
authctxt->success = 1;
} else {
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
xfree(methods);
}
}
void
static void
userauth_banner(void)
{
struct stat st;
@ -289,46 +290,19 @@ userauth_banner(void)
return;
}
void
userauth_reply(Authctxt *authctxt, int authenticated)
{
char *methods;
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
/* now we can break out */
authctxt->success = 1;
} else {
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
xfree(methods);
}
}
int
static int
userauth_none(Authctxt *authctxt)
{
/* disable method "none", only allowed one time */
Authmethod *m = authmethod_lookup("none");
if (m != NULL)
m->enabled = NULL;
packet_done();
packet_check_eom();
userauth_banner();
return authctxt->valid ? auth_password(authctxt, "") : 0;
}
int
static int
userauth_passwd(Authctxt *authctxt)
{
char *password;
@ -339,7 +313,7 @@ userauth_passwd(Authctxt *authctxt)
if (change)
log("password change not supported");
password = packet_get_string(&len);
packet_done();
packet_check_eom();
if (authctxt->valid &&
auth_password(authctxt, password) == 1)
authenticated = 1;
@ -348,33 +322,33 @@ userauth_passwd(Authctxt *authctxt)
return authenticated;
}
int
static int
userauth_kbdint(Authctxt *authctxt)
{
int authenticated = 0;
char *lang = NULL;
char *devs = NULL;
char *lang, *devs;
lang = packet_get_string(NULL);
devs = packet_get_string(NULL);
packet_done();
packet_check_eom();
debug("keyboard-interactive language %s devs %s", lang, devs);
debug("keyboard-interactive devs %s", devs);
if (options.challenge_reponse_authentication)
if (options.challenge_response_authentication)
authenticated = auth2_challenge(authctxt, devs);
xfree(lang);
xfree(devs);
xfree(lang);
return authenticated;
}
int
static int
userauth_pubkey(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig;
Key *key = NULL;
char *pkalg;
u_char *pkblob, *sig;
u_int alen, blen, slen;
int have_sig, pktype;
int authenticated = 0;
@ -400,83 +374,92 @@ userauth_pubkey(Authctxt *authctxt)
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
xfree(pkalg);
xfree(pkblob);
return 0;
log("userauth_pubkey: unsupported public key algorithm: %s",
pkalg);
goto done;
}
key = key_from_blob(pkblob, blen);
if (key != NULL) {
if (have_sig) {
sig = packet_get_string(&slen);
packet_done();
buffer_init(&b);
if (datafellows & SSH_OLD_SESSIONID) {
buffer_append(&b, session_id2, session_id2_len);
} else {
buffer_put_string(&b, session_id2, session_id2_len);
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" :
authctxt->service);
if (datafellows & SSH_BUG_PKAUTH) {
buffer_put_char(&b, have_sig);
} else {
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, pkalg);
}
buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_key_allowed(authctxt->pw, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
debug("test whether pkalg/pkblob are acceptable");
packet_done();
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
packet_send();
packet_write_wait();
authctxt->postponed = 1;
}
}
if (authenticated != 1)
auth_clear_options();
key_free(key);
if (key == NULL) {
error("userauth_pubkey: cannot decode key: %s", pkalg);
goto done;
}
if (key->type != pktype) {
error("userauth_pubkey: type mismatch for decoded key "
"(received %d, expected %d)", key->type, pktype);
goto done;
}
if (have_sig) {
sig = packet_get_string(&slen);
packet_check_eom();
buffer_init(&b);
if (datafellows & SSH_OLD_SESSIONID) {
buffer_append(&b, session_id2, session_id2_len);
} else {
buffer_put_string(&b, session_id2, session_id2_len);
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" :
authctxt->service);
if (datafellows & SSH_BUG_PKAUTH) {
buffer_put_char(&b, have_sig);
} else {
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, pkalg);
}
buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_key_allowed(authctxt->pw, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
debug("test whether pkalg/pkblob are acceptable");
packet_check_eom();
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
packet_send();
packet_write_wait();
authctxt->postponed = 1;
}
}
if (authenticated != 1)
auth_clear_options();
done:
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
if (key != NULL)
key_free(key);
xfree(pkalg);
xfree(pkblob);
return authenticated;
}
int
static int
userauth_hostbased(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
Key *key = NULL;
char *pkalg, *cuser, *chost, *service;
u_char *pkblob, *sig;
u_int alen, blen, slen;
int pktype;
int authenticated = 0;
@ -509,7 +492,12 @@ userauth_hostbased(Authctxt *authctxt)
}
key = key_from_blob(pkblob, blen);
if (key == NULL) {
debug("userauth_hostbased: cannot decode key: %s", pkalg);
error("userauth_hostbased: cannot decode key: %s", pkalg);
goto done;
}
if (key->type != pktype) {
error("userauth_hostbased: type mismatch for decoded key "
"(received %d, expected %d)", key->type, pktype);
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
@ -534,10 +522,10 @@ userauth_hostbased(Authctxt *authctxt)
authenticated = 1;
buffer_clear(&b);
key_free(key);
done:
debug2("userauth_hostbased: authenticated %d", authenticated);
if (key != NULL)
key_free(key);
xfree(pkalg);
xfree(pkblob);
xfree(cuser);
@ -556,39 +544,30 @@ auth_get_user(void)
#define DELIM ","
char *
static char *
authmethods_get(void)
{
Authmethod *method = NULL;
u_int size = 0;
Buffer b;
char *list;
buffer_init(&b);
for (method = authmethods; method->name != NULL; method++) {
if (strcmp(method->name, "none") == 0)
continue;
if (method->enabled != NULL && *(method->enabled) != 0) {
if (size != 0)
size += strlen(DELIM);
size += strlen(method->name);
}
}
size++; /* trailing '\0' */
list = xmalloc(size);
list[0] = '\0';
for (method = authmethods; method->name != NULL; method++) {
if (strcmp(method->name, "none") == 0)
continue;
if (method->enabled != NULL && *(method->enabled) != 0) {
if (list[0] != '\0')
strlcat(list, DELIM, size);
strlcat(list, method->name, size);
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, method->name, strlen(method->name));
}
}
buffer_append(&b, "\0", 1);
list = xstrdup(buffer_ptr(&b));
buffer_free(&b);
return list;
}
Authmethod *
static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
@ -603,15 +582,16 @@ authmethod_lookup(const char *name)
}
/* return 1 if user allows given key */
int
user_key_allowed(struct passwd *pw, Key *key)
static int
user_key_allowed2(struct passwd *pw, Key *key, char *file)
{
char line[8192], file[MAXPATHLEN];
char line[8192];
int found_key = 0;
FILE *f;
u_long linenum = 0;
struct stat st;
Key *found;
char *fp;
if (pw == NULL)
return 0;
@ -619,9 +599,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Temporarily use the user's uid. */
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
_PATH_SSH_USER_PERMITTED_KEYS2);
debug("trying public key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
@ -636,46 +614,14 @@ user_key_allowed(struct passwd *pw, Key *key)
restore_uid();
return 0;
}
if (options.strict_modes) {
int fail = 0;
char buf[1024];
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
key_type(key), pw->pw_name, file);
fail = 1;
} else {
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s",
pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
key_type(key), pw->pw_name, line);
fail = 1;
break;
}
}
}
if (fail) {
fclose(f);
log("%s", buf);
restore_uid();
return 0;
}
if (options.strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
fclose(f);
log("Authentication refused: %s", line);
restore_uid();
return 0;
}
found_key = 0;
found = key_new(key->type);
@ -688,7 +634,7 @@ user_key_allowed(struct passwd *pw, Key *key)
if (!*cp || *cp == '\n' || *cp == '#')
continue;
if (key_read(found, &cp) == -1) {
if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
@ -702,7 +648,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(found, &cp) == -1) {
if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
@ -711,8 +657,12 @@ user_key_allowed(struct passwd *pw, Key *key)
if (key_equal(found, key) &&
auth_parse_options(pw, options, file, linenum) == 1) {
found_key = 1;
debug("matching key found: file %s, line %ld",
debug("matching key found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(found), fp);
xfree(fp);
break;
}
}
@ -724,18 +674,36 @@ user_key_allowed(struct passwd *pw, Key *key)
return found_key;
}
/* check whether given key is in .ssh/authorized_keys* */
static int
user_key_allowed(struct passwd *pw, Key *key)
{
int success;
char *file;
file = authorized_keys_file(pw);
success = user_key_allowed2(pw, key, file);
xfree(file);
if (success)
return success;
/* try suffix "2" for backward compat, too */
file = authorized_keys_file2(pw);
success = user_key_allowed2(pw, key, file);
xfree(file);
return success;
}
/* return 1 if given hostkey is allowed */
int
static int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key)
{
Key *found;
const char *resolvedname, *ipaddr, *lookup;
struct stat st;
char *user_hostfile;
int host_status, len;
HostStatus host_status;
int len;
resolvedname = get_canonical_hostname(options.reverse_mapping_check);
resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
@ -760,32 +728,16 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
}
debug2("userauth_hostbased: access allowed by auth_rhosts2");
/* XXX this is copied from auth-rh-rsa.c and should be shared */
found = key_new(key->type);
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE2, lookup,
key, found, NULL);
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE,
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE2,
pw->pw_uid);
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
log("Hostbased authentication refused for %.100s: "
"bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile,
lookup, key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(found);
/* backward compat if no key has been found. */
if (host_status == HOST_NEW)
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE2,
options.ignore_user_known_hosts ? NULL :
_PATH_SSH_USER_HOSTFILE2);
debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", lookup);
return (host_status == HOST_OK);
}

View File

@ -35,7 +35,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfd.c,v 1.39 2001/04/05 10:42:48 markus Exp $");
RCSID("$OpenBSD: authfd.c,v 1.48 2002/02/24 19:14:59 markus Exp $");
#include <openssl/evp.h>
@ -58,7 +58,8 @@ int decode_reply(int type);
/* macro to check for "agent failure" message */
#define agent_failed(x) \
((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE))
((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
(x == SSH2_AGENT_FAILURE))
/* Returns the number of the authentication fd, or -1 if there is none. */
@ -66,7 +67,7 @@ int
ssh_get_authentication_socket(void)
{
const char *authsocket;
int sock, len;
int sock;
struct sockaddr_un sunaddr;
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
@ -75,8 +76,6 @@ ssh_get_authentication_socket(void)
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
len = SUN_LEN(&sunaddr)+1;
sunaddr.sun_len = len;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
@ -87,14 +86,14 @@ ssh_get_authentication_socket(void)
close(sock);
return -1;
}
if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
close(sock);
return -1;
}
return sock;
}
int
static int
ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
{
int l, len;
@ -218,7 +217,7 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version)
int type, code1 = 0, code2 = 0;
Buffer request;
switch(version){
switch (version) {
case 1:
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
@ -287,7 +286,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
* Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data.
*/
switch(version){
switch (version) {
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities);
@ -345,7 +344,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
buffer_put_bignum(&buffer, key->rsa->e);
buffer_put_bignum(&buffer, key->rsa->n);
buffer_put_bignum(&buffer, challenge);
buffer_append(&buffer, (char *) session_id, 16);
buffer_append(&buffer, session_id, 16);
buffer_put_int(&buffer, response_type);
if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
@ -375,8 +374,8 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
extern int datafellows;
Buffer msg;
@ -417,7 +416,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */
void
static void
ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{
buffer_clear(b);
@ -430,16 +429,16 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
buffer_put_bignum(b, key->iqmp); /* ssh key->u */
buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
buffer_put_string(b, comment, strlen(comment));
buffer_put_cstring(b, comment);
}
void
static void
ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
buffer_put_cstring(b, key_ssh_name(key));
switch(key->type){
switch (key->type) {
case KEY_RSA:
buffer_put_bignum2(b, key->rsa->n);
buffer_put_bignum2(b, key->rsa->e);
@ -532,6 +531,25 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
return decode_reply(type);
}
int
ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id)
{
Buffer msg;
int type;
buffer_init(&msg);
buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
SSH_AGENTC_REMOVE_SMARTCARD_KEY);
buffer_put_cstring(&msg, reader_id);
if (ssh_request_reply(auth, &msg, &msg) == 0) {
buffer_free(&msg);
return 0;
}
type = buffer_get_char(&msg);
buffer_free(&msg);
return decode_reply(type);
}
/*
* Removes all identities from the agent. This call is not meant to be used
* by normal applications.
@ -564,6 +582,7 @@ decode_reply(int type)
switch (type) {
case SSH_AGENT_FAILURE:
case SSH_COM_AGENT2_FAILURE:
case SSH2_AGENT_FAILURE:
log("SSH_AGENT_FAILURE");
return 0;
case SSH_AGENT_SUCCESS:

View File

@ -1,3 +1,5 @@
/* $OpenBSD: authfd.h,v 1.23 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,8 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: authfd.h,v 1.16 2000/12/20 19:37:21 markus Exp $"); */
#ifndef AUTHFD_H
#define AUTHFD_H
@ -38,101 +38,43 @@
#define SSH2_AGENTC_REMOVE_IDENTITY 18
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
/* smartcard */
#define SSH_AGENTC_ADD_SMARTCARD_KEY 20
#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21
/* extended failure messages */
#define SSH2_AGENT_FAILURE 30
/* additional error code for ssh.com's ssh-agent2 */
#define SSH_COM_AGENT2_FAILURE 102
#define SSH_COM_AGENT2_FAILURE 102
#define SSH_AGENT_OLD_SIGNATURE 0x01
typedef struct {
int fd;
Buffer identities;
int howmany;
} AuthenticationConnection;
/* Returns the number of the authentication fd, or -1 if there is none. */
int ssh_get_authentication_socket(void);
int ssh_get_authentication_socket(void);
void ssh_close_authentication_socket(int);
/*
* This should be called for any descriptor returned by
* ssh_get_authentication_socket(). Depending on the way the descriptor was
* obtained, this may close the descriptor.
*/
void ssh_close_authentication_socket(int authfd);
/*
* Opens and connects a private socket for communication with the
* authentication agent. Returns NULL if an error occurred and the
* connection could not be opened. The connection should be closed by the
* caller by calling ssh_close_authentication_connection().
*/
AuthenticationConnection *ssh_get_authentication_connection(void);
void ssh_close_authentication_connection(AuthenticationConnection *);
int ssh_get_num_identities(AuthenticationConnection *, int);
Key *ssh_get_first_identity(AuthenticationConnection *, char **, int);
Key *ssh_get_next_identity(AuthenticationConnection *, char **, int);
int ssh_add_identity(AuthenticationConnection *, Key *, const char *);
int ssh_remove_identity(AuthenticationConnection *, Key *);
int ssh_remove_all_identities(AuthenticationConnection *, int);
int ssh_update_card(AuthenticationConnection *, int, const char *);
/*
* Closes the connection to the authentication agent and frees any associated
* memory.
*/
void ssh_close_authentication_connection(AuthenticationConnection *auth);
/*
* Returns the number authentication identity held by the agent.
*/
int ssh_get_num_identities(AuthenticationConnection *auth, int version);
/*
* Returns the first authentication identity held by the agent or NULL if
* no identies are available. Caller must free comment and key.
* Note that you cannot mix calls with different versions.
*/
Key *ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version);
/*
* Returns the next authentication identity for the agent. Other functions
* can be called between this and ssh_get_first_identity or two calls of this
* function. This returns NULL if there are no more identities. The caller
* must free key and comment after a successful return.
*/
Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version);
/*
* Requests the agent to decrypt the given challenge. Returns true if the
* agent claims it was able to decrypt it.
*/
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
Key *key, BIGNUM * challenge,
u_char session_id[16],
u_int response_type,
u_char response[16]);
ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
u_int, u_char[16]);
/* Requests the agent to sign data using key */
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen);
/*
* Adds an identity to the authentication server. This call is not meant to
* be used by normal applications. This returns true if the identity was
* successfully added.
*/
int
ssh_add_identity(AuthenticationConnection *auth, Key *key,
const char *comment);
/*
* Removes the identity from the authentication server. This call is not
* meant to be used by normal applications. This returns true if the
* identity was successfully added.
*/
int ssh_remove_identity(AuthenticationConnection *auth, Key *key);
/*
* Removes all identities from the authentication agent. This call is not
* meant to be used by normal applications. This returns true if the
* operation was successful.
*/
int ssh_remove_all_identities(AuthenticationConnection *auth, int version);
ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *,
u_int);
#endif /* AUTHFD_H */

View File

@ -36,7 +36,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
RCSID("$OpenBSD: authfile.c,v 1.48 2002/02/28 15:46:33 markus Exp $");
#include <openssl/err.h>
#include <openssl/evp.h>
@ -50,6 +50,7 @@ RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "rsa.h"
/* Version identification string for SSH v1 identity files. */
static const char authfile_id_string[] =
@ -62,13 +63,13 @@ static const char authfile_id_string[] =
* passphrase.
*/
int
static int
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
const char *comment)
{
Buffer buffer, encrypted;
char buf[100], *cp;
int fd, i;
u_char buf[100], *cp;
int fd, i, cipher_num;
CipherContext ciphercontext;
Cipher *cipher;
u_int32_t rand;
@ -77,11 +78,9 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
*/
if (strcmp(passphrase, "") == 0)
cipher = cipher_by_number(SSH_CIPHER_NONE);
else
cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
if (cipher == NULL)
cipher_num = (strcmp(passphrase, "") == 0) ?
SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
if ((cipher = cipher_by_number(cipher_num)) == NULL)
fatal("save_private_key_rsa: bad cipher");
/* This buffer is used to built the secret part of the private key. */
@ -118,21 +117,23 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
buffer_put_char(&encrypted, 0);
/* Store cipher type. */
buffer_put_char(&encrypted, cipher->number);
buffer_put_char(&encrypted, cipher_num);
buffer_put_int(&encrypted, 0); /* For future extension */
/* Store public key. This will be in plain text. */
buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
buffer_put_bignum(&encrypted, key->rsa->n);
buffer_put_bignum(&encrypted, key->rsa->e);
buffer_put_string(&encrypted, comment, strlen(comment));
buffer_put_cstring(&encrypted, comment);
/* Allocate space for the private part of the key in the buffer. */
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
cp = buffer_append_space(&encrypted, buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_encrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_ENCRYPT);
cipher_crypt(&ciphercontext, cp,
buffer_ptr(&buffer), buffer_len(&buffer));
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
/* Destroy temporary data. */
@ -147,7 +148,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) {
error("write to key file %s failed: %s", filename,
strerror(errno));
strerror(errno));
buffer_free(&encrypted);
close(fd);
unlink(filename);
@ -159,7 +160,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
}
/* save SSH v2 key in OpenSSL PEM format */
int
static int
key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
const char *comment)
{
@ -167,8 +168,8 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
int fd;
int success = 0;
int len = strlen(_passphrase);
char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
if (len > 0 && len <= 4) {
error("passphrase too short: have %d bytes, need > 4", len);
@ -226,7 +227,7 @@ key_save_private(Key *key, const char *filename, const char *passphrase,
* otherwise.
*/
Key *
static Key *
key_load_public_rsa1(int fd, const char *filename, char **commentp)
{
Buffer buffer;
@ -239,7 +240,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@ -250,7 +251,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@ -260,7 +261,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@ -306,25 +307,23 @@ key_load_public_type(int type, const char *filename, char **commentp)
* Assumes we are called under uid of the owner of the file.
*/
Key *
static Key *
key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
char **commentp)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
u_char *cp;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
Key *prv = NULL;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@ -336,7 +335,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@ -347,7 +346,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@ -378,12 +377,14 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
}
/* Initialize space for decrypted data. */
buffer_init(&decrypted);
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
cp = buffer_append_space(&decrypted, buffer_len(&buffer));
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_decrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_DECRYPT);
cipher_crypt(&ciphercontext, cp,
buffer_ptr(&buffer), buffer_len(&buffer));
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&buffer);
@ -406,17 +407,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
/* calculate p-1 and q-1 */
ctx = BN_CTX_new();
aux = BN_new();
BN_sub(aux, prv->rsa->q, BN_value_one());
BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
BN_sub(aux, prv->rsa->p, BN_value_one());
BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
BN_clear_free(aux);
BN_CTX_free(ctx);
rsa_generate_additional_parameters(prv->rsa);
buffer_free(&decrypted);
close(fd);
@ -430,7 +421,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
return NULL;
}
Key *
static Key *
key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{
@ -450,7 +441,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
debug("PEM_read_PrivateKey failed");
(void)ERR_get_error();
} else if (pk->type == EVP_PKEY_RSA &&
(type == KEY_UNSPEC||type==KEY_RSA)) {
(type == KEY_UNSPEC||type==KEY_RSA)) {
prv = key_new(KEY_UNSPEC);
prv->rsa = EVP_PKEY_get1_RSA(pk);
prv->type = KEY_RSA;
@ -459,7 +450,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
RSA_print_fp(stderr, prv->rsa, 8);
#endif
} else if (pk->type == EVP_PKEY_DSA &&
(type == KEY_UNSPEC||type==KEY_DSA)) {
(type == KEY_UNSPEC||type==KEY_DSA)) {
prv = key_new(KEY_UNSPEC);
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
@ -481,20 +472,23 @@ key_load_private_pem(int fd, int type, const char *passphrase,
return prv;
}
int
static int
key_perm_ok(int fd, const char *filename)
{
struct stat st;
/* check owner and modes */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
close(fd);
if (fstat(fd, &st) < 0)
return 0;
/*
* if a key owned by the user is accessed, then we check the
* permissions of the file. if the key owned by a different user,
* then we don't care.
*/
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.",
error("Permissions 0%3.3o for '%s' are too open.",
st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
@ -540,7 +534,7 @@ Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp)
{
Key *pub;
Key *pub, *prv;
int fd;
fd = open(filename, O_RDONLY);
@ -555,16 +549,20 @@ key_load_private(const char *filename, const char *passphrase,
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
if (pub == NULL) {
/* closes fd */
return key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
/* use the filename as a comment for PEM */
if (commentp && prv)
*commentp = xstrdup(filename);
} else {
/* it's a SSH v1 key if the public key part is readable */
key_free(pub);
/* closes fd */
return key_load_private_rsa1(fd, filename, passphrase, NULL);
prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
}
return prv;
}
int
static int
key_try_load_public(Key *k, const char *filename, char **commentp)
{
FILE *f;
@ -576,7 +574,7 @@ key_try_load_public(Key *k, const char *filename, char **commentp)
while (fgets(line, sizeof(line), f)) {
line[sizeof(line)-1] = '\0';
cp = line;
switch(*cp){
switch (*cp) {
case '#':
case '\n':
case '\0':

View File

@ -1,3 +1,5 @@
/* $OpenBSD: authfile.h,v 1.9 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,27 +12,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: authfile.h,v 1.6 2001/03/26 08:07:08 markus Exp $ */
#ifndef AUTHFILE_H
#define AUTHFILE_H
int
key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment);
Key *
key_load_public(const char *filename, char **commentp);
Key *
key_load_public_type(int type, const char *filename, char **commentp);
Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp);
Key *
key_load_private_type(int type, const char *filename, const char *passphrase,
char **commentp);
int key_save_private(Key *, const char *, const char *, const char *);
Key *key_load_public(const char *, char **);
Key *key_load_public_type(int, const char *, char **);
Key *key_load_private(const char *, const char *, char **);
Key *key_load_private_type(int, const char *, const char *, char **);
#endif

View File

@ -37,7 +37,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
RCSID("$OpenBSD: bufaux.c,v 1.22 2002/01/18 18:14:17 stevesk Exp $");
#include <openssl/bn.h>
#include "bufaux.h"
@ -62,7 +62,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf);
if (oi != bin_size)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
oi, bin_size);
oi, bin_size);
/* Store the number of bits in the buffer in two bytes, msb first. */
PUT_16BIT(msg, bits);
@ -77,7 +77,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
/*
* Retrieves an BIGNUM from the buffer.
*/
int
void
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{
int bits, bytes;
@ -90,11 +90,9 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
bytes = (bits + 7) / 8;
if (buffer_len(buffer) < bytes)
fatal("buffer_get_bignum: input buffer too small");
bin = (u_char *) buffer_ptr(buffer);
bin = buffer_ptr(buffer);
BN_bin2bn(bin, bytes, value);
buffer_consume(buffer, bytes);
return 2 + bytes;
}
/*
@ -112,16 +110,16 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf+1);
if (oi != bytes-1)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
oi, bytes);
oi, bytes);
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
u_char *uc = buf;
log("negativ!");
for(i = bytes-1, carry = 1; i>=0; i--) {
for (i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
if(carry)
if (carry)
carry = !++uc[i];
}
}
@ -130,15 +128,14 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
xfree(buf);
}
int
void
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
/**XXX should be two's-complement */
int len;
u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
u_char *bin = buffer_get_string(buffer, (u_int *)&len);
BN_bin2bn(bin, len, value);
xfree(bin);
return len;
}
/*
@ -187,11 +184,11 @@ buffer_put_int64(Buffer *buffer, u_int64_t value)
* will be stored there. A null character will be automatically appended
* to the returned string, and is not counted in length.
*/
char *
void *
buffer_get_string(Buffer *buffer, u_int *length_ptr)
{
u_int len;
char *value;
u_char *value;
/* Get the length. */
len = buffer_get_int(buffer);
if (len > 256 * 1024)

View File

@ -1,3 +1,5 @@
/* $OpenBSD: bufaux.h,v 1.16 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,51 +12,28 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: bufaux.h,v 1.11 2001/01/21 19:05:45 markus Exp $"); */
#ifndef BUFAUX_H
#define BUFAUX_H
#include "buffer.h"
#include <openssl/bn.h>
/*
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
* by (bits+7)/8 bytes of binary data, msb first.
*/
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
void buffer_put_bignum2(Buffer * buffer, BIGNUM * value);
void buffer_put_bignum(Buffer *, BIGNUM *);
void buffer_put_bignum2(Buffer *, BIGNUM *);
void buffer_get_bignum(Buffer *, BIGNUM *);
void buffer_get_bignum2(Buffer *, BIGNUM *);
/* Retrieves an BIGNUM from the buffer. */
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
u_int buffer_get_int(Buffer *);
void buffer_put_int(Buffer *, u_int);
/* Returns an integer from the buffer (4 bytes, msb first). */
u_int buffer_get_int(Buffer * buffer);
u_int64_t buffer_get_int64(Buffer *buffer);
u_int64_t buffer_get_int64(Buffer *);
void buffer_put_int64(Buffer *, u_int64_t);
/* Stores an integer in the buffer in 4 bytes, msb first. */
void buffer_put_int(Buffer * buffer, u_int value);
void buffer_put_int64(Buffer *buffer, u_int64_t value);
int buffer_get_char(Buffer *);
void buffer_put_char(Buffer *, int);
/* Returns a character from the buffer (0 - 255). */
int buffer_get_char(Buffer * buffer);
/* Stores a character in the buffer. */
void buffer_put_char(Buffer * buffer, int value);
/*
* Returns an arbitrary binary string from the buffer. The string cannot be
* longer than 256k. The returned value points to memory allocated with
* xmalloc; it is the responsibility of the calling function to free the
* data. If length_ptr is non-NULL, the length of the returned data will be
* stored there. A null character will be automatically appended to the
* returned string, and is not counted in length.
*/
char *buffer_get_string(Buffer * buffer, u_int *length_ptr);
/* Stores and arbitrary binary string in the buffer. */
void buffer_put_string(Buffer * buffer, const void *buf, u_int len);
void buffer_put_cstring(Buffer *buffer, const char *s);
void *buffer_get_string(Buffer *, u_int *);
void buffer_put_string(Buffer *, const void *, u_int);
void buffer_put_cstring(Buffer *, const char *);
#endif /* BUFAUX_H */

View File

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $");
RCSID("$OpenBSD: buffer.c,v 1.15 2002/01/18 18:14:17 stevesk Exp $");
#include "xmalloc.h"
#include "buffer.h"
@ -53,11 +53,11 @@ buffer_clear(Buffer *buffer)
/* Appends data to the buffer, expanding it if necessary. */
void
buffer_append(Buffer *buffer, const char *data, u_int len)
buffer_append(Buffer *buffer, const void *data, u_int len)
{
char *cp;
buffer_append_space(buffer, &cp, len);
memcpy(cp, data, len);
void *p;
p = buffer_append_space(buffer, len);
memcpy(p, data, len);
}
/*
@ -66,9 +66,11 @@ buffer_append(Buffer *buffer, const char *data, u_int len)
* to the allocated region.
*/
void
buffer_append_space(Buffer *buffer, char **datap, u_int len)
void *
buffer_append_space(Buffer *buffer, u_int len)
{
void *p;
/* If the buffer is empty, start using it from the beginning. */
if (buffer->offset == buffer->end) {
buffer->offset = 0;
@ -77,9 +79,9 @@ buffer_append_space(Buffer *buffer, char **datap, u_int len)
restart:
/* If there is enough space to store all data, store it now. */
if (buffer->end + len < buffer->alloc) {
*datap = buffer->buf + buffer->end;
p = buffer->buf + buffer->end;
buffer->end += len;
return;
return p;
}
/*
* If the buffer is quite empty, but all data is at the end, move the
@ -96,6 +98,7 @@ buffer_append_space(Buffer *buffer, char **datap, u_int len)
buffer->alloc += len + 32768;
buffer->buf = xrealloc(buffer->buf, buffer->alloc);
goto restart;
/* NOTREACHED */
}
/* Returns the number of bytes of data in the buffer. */
@ -109,7 +112,7 @@ buffer_len(Buffer *buffer)
/* Gets data from the beginning of the buffer. */
void
buffer_get(Buffer *buffer, char *buf, u_int len)
buffer_get(Buffer *buffer, void *buf, u_int len)
{
if (len > buffer->end - buffer->offset)
fatal("buffer_get: trying to get more bytes %d than in buffer %d",
@ -140,7 +143,7 @@ buffer_consume_end(Buffer *buffer, u_int bytes)
/* Returns a pointer to the first used byte in the buffer. */
char *
void *
buffer_ptr(Buffer *buffer)
{
return buffer->buf + buffer->offset;
@ -152,7 +155,7 @@ void
buffer_dump(Buffer *buffer)
{
int i;
u_char *ucp = (u_char *) buffer->buf;
u_char *ucp = buffer->buf;
for (i = buffer->offset; i < buffer->end; i++) {
fprintf(stderr, "%02x", ucp[i]);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: buffer.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,56 +13,31 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: buffer.h,v 1.7 2000/12/19 23:17:55 markus Exp $"); */
#ifndef BUFFER_H
#define BUFFER_H
typedef struct {
char *buf; /* Buffer for data. */
u_int alloc; /* Number of bytes allocated for data. */
u_int offset; /* Offset of first byte containing data. */
u_int end; /* Offset of last byte containing data. */
u_char *buf; /* Buffer for data. */
u_int alloc; /* Number of bytes allocated for data. */
u_int offset; /* Offset of first byte containing data. */
u_int end; /* Offset of last byte containing data. */
} Buffer;
/* Initializes the buffer structure. */
void buffer_init(Buffer * buffer);
/* Frees any memory used for the buffer. */
void buffer_free(Buffer * buffer);
void buffer_init(Buffer *);
void buffer_clear(Buffer *);
void buffer_free(Buffer *);
/* Clears any data from the buffer, making it empty. This does not actually
zero the memory. */
void buffer_clear(Buffer * buffer);
u_int buffer_len(Buffer *);
void *buffer_ptr(Buffer *);
/* Appends data to the buffer, expanding it if necessary. */
void buffer_append(Buffer * buffer, const char *data, u_int len);
void buffer_append(Buffer *, const void *, u_int);
void *buffer_append_space(Buffer *, u_int);
/*
* Appends space to the buffer, expanding the buffer if necessary. This does
* not actually copy the data into the buffer, but instead returns a pointer
* to the allocated region.
*/
void buffer_append_space(Buffer * buffer, char **datap, u_int len);
void buffer_get(Buffer *, void *, u_int);
/* Returns the number of bytes of data in the buffer. */
u_int buffer_len(Buffer * buffer);
void buffer_consume(Buffer *, u_int);
void buffer_consume_end(Buffer *, u_int);
/* Gets data from the beginning of the buffer. */
void buffer_get(Buffer * buffer, char *buf, u_int len);
/* Consumes the given number of bytes from the beginning of the buffer. */
void buffer_consume(Buffer * buffer, u_int bytes);
/* Consumes the given number of bytes from the end of the buffer. */
void buffer_consume_end(Buffer * buffer, u_int bytes);
/* Returns a pointer to the first used byte in the buffer. */
char *buffer_ptr(Buffer * buffer);
/*
* Dumps the contents of the buffer to stderr in hex. This intended for
* debugging purposes only.
*/
void buffer_dump(Buffer * buffer);
void buffer_dump(Buffer *);
#endif /* BUFFER_H */

View File

@ -12,22 +12,22 @@
*/
#include "includes.h"
RCSID("$OpenBSD: canohost.c,v 1.26 2001/04/18 14:15:00 markus Exp $");
RCSID("$OpenBSD: canohost.c,v 1.31 2002/02/27 21:23:13 stevesk Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
#include "canohost.h"
void check_ip_options(int socket, char *ipaddr);
static void check_ip_options(int, char *);
/*
* Return the canonical name of the host at the other end of the socket. The
* caller should free the returned string with xfree.
*/
char *
get_remote_hostname(int socket, int reverse_mapping_check)
static char *
get_remote_hostname(int socket, int verify_reverse_mapping)
{
struct sockaddr_storage from;
int i;
@ -46,13 +46,13 @@ get_remote_hostname(int socket, int reverse_mapping_check)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
NULL, 0, NI_NAMEREQD) != 0) {
NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
log("Could not reverse map address %.100s.", ntop);
return xstrdup(ntop);
@ -68,7 +68,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
if (isupper(name[i]))
name[i] = tolower(name[i]);
if (!reverse_mapping_check)
if (!verify_reverse_mapping)
return xstrdup(name);
/*
* Map it back to an IP address and check that the given
@ -118,7 +118,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
* exit here if we detect any IP options.
*/
/* IPv4 only */
void
static void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200];
@ -132,7 +132,7 @@ check_ip_options(int socket, char *ipaddr)
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
if (getsockopt(socket, ipproto, IP_OPTIONS, options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
@ -152,14 +152,14 @@ check_ip_options(int socket, char *ipaddr)
*/
const char *
get_canonical_hostname(int reverse_mapping_check)
get_canonical_hostname(int verify_reverse_mapping)
{
static char *canonical_host_name = NULL;
static int reverse_mapping_checked = 0;
static int verify_reverse_mapping_done = 0;
/* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) {
if (reverse_mapping_checked != reverse_mapping_check)
if (verify_reverse_mapping_done != verify_reverse_mapping)
xfree(canonical_host_name);
else
return canonical_host_name;
@ -168,11 +168,11 @@ get_canonical_hostname(int reverse_mapping_check)
/* Get the real hostname if socket; otherwise return UNKNOWN. */
if (packet_connection_is_on_socket())
canonical_host_name = get_remote_hostname(
packet_get_connection_in(), reverse_mapping_check);
packet_get_connection_in(), verify_reverse_mapping);
else
canonical_host_name = xstrdup("UNKNOWN");
reverse_mapping_checked = reverse_mapping_check;
verify_reverse_mapping_done = verify_reverse_mapping;
return canonical_host_name;
}
@ -180,7 +180,7 @@ get_canonical_hostname(int reverse_mapping_check)
* Returns the remote IP-address of socket as a string. The returned
* string must be freed.
*/
char *
static char *
get_socket_address(int socket, int remote, int flags)
{
struct sockaddr_storage addr;
@ -208,7 +208,7 @@ get_socket_address(int socket, int remote, int flags)
}
/* Get the address in ascii. */
if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
NULL, 0, flags) != 0) {
NULL, 0, flags) != 0) {
error("get_socket_ipaddr: getnameinfo %d failed", flags);
return NULL;
}
@ -239,7 +239,7 @@ get_local_name(int socket)
*/
const char *
get_remote_ipaddr()
get_remote_ipaddr(void)
{
static char *canonical_host_ip = NULL;
@ -259,11 +259,11 @@ get_remote_ipaddr()
}
const char *
get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname(reverse_mapping_check);
remote = get_canonical_hostname(verify_reverse_mapping);
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
@ -271,7 +271,7 @@ get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
/* Returns the local/remote port for the socket. */
int
static int
get_sock_port(int sock, int local)
{
struct sockaddr_storage from;
@ -294,14 +294,14 @@ get_sock_port(int sock, int local)
}
/* Return port number. */
if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
strport, sizeof(strport), NI_NUMERICSERV) != 0)
strport, sizeof(strport), NI_NUMERICSERV) != 0)
fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
return atoi(strport);
}
/* Returns remote/local port number for the current connection. */
int
static int
get_port(int local)
{
/*
@ -322,13 +322,13 @@ get_peer_port(int sock)
}
int
get_remote_port()
get_remote_port(void)
{
return get_port(0);
}
int
get_local_port()
get_local_port(void)
{
return get_port(1);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */
/* $OpenBSD: canohost.h,v 1.8 2001/06/26 17:27:23 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -12,27 +12,14 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Return the canonical name of the host in the other side of the current
* connection (as returned by packet_get_connection). The host name is
* cached, so it is efficient to call this several times.
*/
const char *get_canonical_hostname(int reverse_mapping_check);
const char *get_canonical_hostname(int);
const char *get_remote_ipaddr(void);
const char *get_remote_name_or_ip(u_int, int);
/*
* Returns the IP-address of the remote host as a string. The returned
* string is cached and must not be freed.
*/
const char *get_remote_ipaddr(void);
char *get_peer_ipaddr(int);
int get_peer_port(int);
char *get_local_ipaddr(int);
char *get_local_name(int);
const char *get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check);
/* Returns the ipaddr/port number of the peer of the socket. */
char * get_peer_ipaddr(int socket);
int get_peer_port(int sock);
char * get_local_ipaddr(int socket);
char * get_local_name(int socket);
/* Returns the port number of the remote/local host. */
int get_remote_port(void);
int get_local_port(void);
int get_remote_port(void);
int get_local_port(void);

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
/* $OpenBSD: channels.h,v 1.65 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,7 +12,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,15 +34,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
#ifndef CHANNELS_H
#define CHANNELS_H
#ifndef CHANNEL_H
#define CHANNEL_H
#include "buffer.h"
/* Definitions for channel types. */
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
@ -54,38 +54,38 @@
#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
#define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13
#define SSH_CHANNEL_MAX_TYPE 14
#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */
#define SSH_CHANNEL_MAX_TYPE 15
#define SSH_CHANNEL_PATH_LEN 256
/*
* Data structure for channel data. This is iniailized in channel_allocate
* and cleared in channel_free.
*/
struct Channel;
typedef struct Channel Channel;
typedef void channel_callback_fn(int id, void *arg);
typedef int channel_filter_fn(struct Channel *c, char *buf, int len);
typedef void channel_callback_fn(int, void *);
typedef int channel_filter_fn(struct Channel *, char *, int);
struct Channel {
int type; /* channel type/state */
int self; /* my own channel identifier */
int remote_id; /* channel identifier for remote peer */
/* peer can be reached over encrypted connection, via packet-sent */
int istate; /* input from channel (state of receive half) */
int ostate; /* output to channel (state of transmit half) */
u_int istate; /* input from channel (state of receive half) */
u_int ostate; /* output to channel (state of transmit half) */
int flags; /* close sent/rcvd */
int rfd; /* read fd */
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
int isatty; /* rfd is a tty */
int force_drain; /* force close on iEOF */
int delayed; /* fdset hack */
Buffer input; /* data read from socket, to be sent over
* encrypted connection */
Buffer output; /* data received over encrypted connection for
* send on socket */
Buffer extended;
char path[200]; /* path for unix domain sockets, or host name
* for forwards */
char path[SSH_CHANNEL_PATH_LEN];
/* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */
@ -97,14 +97,13 @@ struct Channel {
int local_consumed;
int local_maxpacket;
int extended_usage;
int single_connection;
char *ctype; /* type */
/* callback */
channel_callback_fn *cb_fn;
void *cb_arg;
int cb_event;
channel_callback_fn *dettach_user;
channel_callback_fn *confirm;
channel_callback_fn *detach_user;
/* filter */
channel_filter_fn *input_filter;
@ -115,198 +114,111 @@ struct Channel {
#define CHAN_EXTENDED_WRITE 2
/* default window/packet sizes for tcp/x11-fwd-channel */
#define CHAN_SES_WINDOW_DEFAULT (32*1024)
#define CHAN_SES_PACKET_DEFAULT (CHAN_SES_WINDOW_DEFAULT/2)
#define CHAN_TCP_WINDOW_DEFAULT (32*1024)
#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2)
#define CHAN_X11_WINDOW_DEFAULT (4*1024)
#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2)
#define CHAN_SES_PACKET_DEFAULT (32*1024)
#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT)
#define CHAN_TCP_PACKET_DEFAULT (32*1024)
#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT)
#define CHAN_X11_PACKET_DEFAULT (16*1024)
#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT)
/* possible input states */
#define CHAN_INPUT_OPEN 0
#define CHAN_INPUT_WAIT_DRAIN 1
#define CHAN_INPUT_WAIT_OCLOSE 2
#define CHAN_INPUT_CLOSED 3
void channel_open(int id);
void channel_request(int id, char *service, int wantconfirm);
void channel_request_start(int id, char *service, int wantconfirm);
void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
void channel_register_cleanup(int id, channel_callback_fn *fn);
void channel_register_filter(int id, channel_filter_fn *fn);
void channel_cancel_cleanup(int id);
Channel *channel_lookup(int id);
/* possible output states */
#define CHAN_OUTPUT_OPEN 0
#define CHAN_OUTPUT_WAIT_DRAIN 1
#define CHAN_OUTPUT_WAIT_IEOF 2
#define CHAN_OUTPUT_CLOSED 3
int
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
int window, int maxpack, int extended_usage, char *remote_name,
int nonblock);
void
channel_set_fds(int id, int rfd, int wfd, int efd,
int extusage, int nonblock);
#define CHAN_CLOSE_SENT 0x01
#define CHAN_CLOSE_RCVD 0x02
void deny_input_open(int type, int plen, void *ctxt);
/* channel management */
void channel_input_channel_request(int type, int plen, void *ctxt);
void channel_input_close(int type, int plen, void *ctxt);
void channel_input_close_confirmation(int type, int plen, void *ctxt);
void channel_input_data(int type, int plen, void *ctxt);
void channel_input_extended_data(int type, int plen, void *ctxt);
void channel_input_ieof(int type, int plen, void *ctxt);
void channel_input_oclose(int type, int plen, void *ctxt);
void channel_input_open_confirmation(int type, int plen, void *ctxt);
void channel_input_open_failure(int type, int plen, void *ctxt);
void channel_input_port_open(int type, int plen, void *ctxt);
void channel_input_window_adjust(int type, int plen, void *ctxt);
Channel *channel_lookup(int);
Channel *channel_new(char *, int, int, int, int, int, int, int, char *, int);
void channel_set_fds(int, int, int, int, int, int, u_int);
void channel_free(Channel *);
void channel_free_all(void);
void channel_stop_listening(void);
/* Sets specific protocol options. */
void channel_set_options(int hostname_in_open);
void channel_send_open(int);
void channel_request_start(int, char *, int);
void channel_register_cleanup(int, channel_callback_fn *);
void channel_register_confirm(int, channel_callback_fn *);
void channel_register_filter(int, channel_filter_fn *);
void channel_cancel_cleanup(int);
int channel_close_fd(int *);
/*
* Allocate a new channel object and set its type and socket. Remote_name
* must have been allocated with xmalloc; this will free it when the channel
* is freed.
*/
int channel_allocate(int type, int sock, char *remote_name);
/* protocol handler */
/* Free the channel and close its socket. */
void channel_free(int channel);
void channel_input_close(int, u_int32_t, void *);
void channel_input_close_confirmation(int, u_int32_t, void *);
void channel_input_data(int, u_int32_t, void *);
void channel_input_extended_data(int, u_int32_t, void *);
void channel_input_ieof(int, u_int32_t, void *);
void channel_input_oclose(int, u_int32_t, void *);
void channel_input_open_confirmation(int, u_int32_t, void *);
void channel_input_open_failure(int, u_int32_t, void *);
void channel_input_port_open(int, u_int32_t, void *);
void channel_input_window_adjust(int, u_int32_t, void *);
/*
* Allocate/update select bitmasks and add any bits relevant to channels in
* select bitmasks.
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
int rekeying);
/* file descriptor handling (read/write) */
/*
* After select, perform any appropriate operations for channels which have
* events pending.
*/
void channel_after_select(fd_set * readset, fd_set * writeset);
void channel_prepare_select(fd_set **, fd_set **, int *, int*, int);
void channel_after_select(fd_set *, fd_set *);
void channel_output_poll(void);
/* If there is data to send to the connection, send some of it now. */
void channel_output_poll(void);
int channel_not_very_much_buffered_data(void);
void channel_close_all(void);
int channel_still_open(void);
char *channel_open_message(void);
int channel_find_open(void);
/* Returns true if no channel has too much buffered data. */
int channel_not_very_much_buffered_data(void);
/* tcp forwarding */
void channel_set_af(int af);
void channel_permit_all_opens(void);
void channel_add_permitted_opens(char *, int);
void channel_clear_permitted_opens(void);
void channel_input_port_forward_request(int, int);
int channel_connect_to(const char *, u_short);
int channel_connect_by_listen_address(u_short);
void channel_request_remote_forwarding(u_short, const char *, u_short);
int channel_setup_local_fwd_listener(u_short, const char *, u_short, int);
int channel_setup_remote_fwd_listener(const char *, u_short, int);
/* This closes any sockets that are listening for connections; this removes
any unix domain sockets. */
void channel_stop_listening(void);
/* x11 forwarding */
/*
* Closes the sockets of all channels. This is used to close extra file
* descriptors after a fork.
*/
void channel_close_all(void);
int x11_connect_display(void);
int x11_create_display_inet(int, int, int);
void x11_input_open(int, u_int32_t, void *);
void x11_request_forwarding_with_spoofing(int, const char *, const char *);
void deny_input_open(int, u_int32_t, void *);
/* Returns true if there is still an open channel over the connection. */
int channel_still_open(void);
/* agent forwarding */
/*
* Returns a string containing a list of all open channels. The list is
* suitable for displaying to the user. It uses crlf instead of newlines.
* The caller should free the string with xfree.
*/
char *channel_open_message(void);
void auth_request_forwarding(void);
char *auth_get_socket_name(void);
void auth_sock_cleanup_proc(void *);
int auth_input_request_forwarding(struct passwd *);
void auth_input_open_request(int, u_int32_t, void *);
/*
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side.
*/
int
channel_request_local_forwarding(u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports);
int
channel_request_forwarding(const char *listen_address, u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports,
int remote_fwd);
/* channel close */
/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side. This never returns if
* there was an error. This registers that open requests for that port are
* permitted.
*/
void
channel_request_remote_forwarding(u_short port, const char *host,
u_short remote_port);
int chan_is_dead(Channel *, int);
void chan_mark_dead(Channel *);
/*
* Permits opening to any host/port if permitted_opens[] is empty. This is
* usually called by the server, because the user could connect to any port
* anyway, and the server has no way to know but to trust the client anyway.
*/
void channel_permit_all_opens(void);
/* channel events */
/* Add host/port to list of allowed targets for port forwarding */
void channel_add_permitted_opens(char *host, int port);
void chan_rcvd_oclose(Channel *);
void chan_read_failed(Channel *);
void chan_ibuf_empty(Channel *);
/* Flush list */
void channel_clear_permitted_opens(void);
/*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
* listening for the port, and sends back a success reply (or disconnect
* message if there was an error). This never returns if there was an error.
*/
void channel_input_port_forward_request(int is_root, int gateway_ports);
/*
* Creates a port for X11 connections, and starts listening for it. Returns
* the display name, or NULL if an error was encountered.
*/
char *x11_create_display(int screen);
/*
* Creates an internet domain socket for listening for X11 connections.
* Returns a suitable value for the DISPLAY variable, or NULL if an error
* occurs.
*/
char *x11_create_display_inet(int screen, int x11_display_offset);
/*
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
* the remote channel number. We should do whatever we want, and respond
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
*/
void x11_input_open(int type, int plen, void *ctxt);
/*
* Requests forwarding of X11 connections. This should be called on the
* client only.
*/
void x11_request_forwarding(void);
/*
* Requests forwarding for X11 connections, with authentication spoofing.
* This should be called in the client only.
*/
void
x11_request_forwarding_with_spoofing(int client_session_id,
const char *proto, const char *data);
/* Sends a message to the server to request authentication fd forwarding. */
void auth_request_forwarding(void);
/*
* Returns the name of the forwarded authentication socket. Returns NULL if
* there is no forwarded authentication socket. The returned value points to
* a static buffer.
*/
char *auth_get_socket_name(void);
/*
* This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
* This starts forwarding authentication requests.
*/
int auth_input_request_forwarding(struct passwd * pw);
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
void auth_input_open_request(int type, int plen, void *ctxt);
/* XXX */
int channel_connect_to(const char *host, u_short host_port);
int channel_connect_by_listen_adress(u_short listen_port);
int x11_connect_display(void);
int channel_find_open(void);
void chan_rcvd_ieof(Channel *);
void chan_write_failed(Channel *);
void chan_obuf_empty(Channel *);
#endif

View File

@ -11,7 +11,7 @@
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -35,396 +35,60 @@
*/
#include "includes.h"
RCSID("$OpenBSD: cipher.c,v 1.43 2001/02/04 15:32:23 stevesk Exp $");
RCSID("$OpenBSD: cipher.c,v 1.52 2002/02/18 13:05:32 markus Exp $");
#include "xmalloc.h"
#include "log.h"
#include "cipher.h"
#include <openssl/md5.h>
#include "rijndael.h"
static EVP_CIPHER *evp_ssh1_3des(void);
static EVP_CIPHER *evp_ssh1_bf(void);
static EVP_CIPHER *evp_rijndael(void);
/* no encryption */
void
none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
}
void
none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
}
void
none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
memcpy(dest, src, len);
}
struct Cipher {
char *name;
int number; /* for ssh1 only */
u_int block_size;
u_int key_len;
EVP_CIPHER *(*evptype)(void);
} ciphers[] = {
{ "none", SSH_CIPHER_NONE, 8, 0, EVP_enc_null },
{ "des", SSH_CIPHER_DES, 8, 8, EVP_des_cbc },
{ "3des", SSH_CIPHER_3DES, 8, 16, evp_ssh1_3des },
{ "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, evp_ssh1_bf },
/* DES */
void
des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
static int dowarn = 1;
if (dowarn) {
error("Warning: use of DES is strongly discouraged "
"due to cryptographic weaknesses");
dowarn = 0;
}
des_set_key((void *)key, cc->u.des.key);
}
void
des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));
}
void
des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
DES_ENCRYPT);
}
void
des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
DES_DECRYPT);
}
{ "3des-cbc", SSH_CIPHER_SSH2, 8, 24, EVP_des_ede3_cbc },
{ "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc },
{ "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_cast5_cbc },
{ "arcfour", SSH_CIPHER_SSH2, 8, 16, EVP_rc4 },
{ "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, evp_rijndael },
{ "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, evp_rijndael },
{ "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, evp_rijndael },
/* 3DES */
void
des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
des_set_key((void *) key, cc->u.des3.key1);
des_set_key((void *) (key+8), cc->u.des3.key2);
des_set_key((void *) (key+16), cc->u.des3.key3);
}
void
des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));
memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));
if (iv == NULL)
return;
memcpy(cc->u.des3.iv3, (char *)iv, 8);
}
void
des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ede3_cbc_encrypt(src, dest, len,
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
&cc->u.des3.iv3, DES_ENCRYPT);
}
void
des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ede3_cbc_encrypt(src, dest, len,
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
&cc->u.des3.iv3, DES_DECRYPT);
}
/*
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
* If only iv3 was used, then, this would till effect have been
* outer-cbc. However, there is also a private iv1 == iv2 which
* perhaps makes differential analysis easier. On the other hand, the
* private iv1 probably makes the CRC-32 attack ineffective. This is a
* result of that there is no longer any known iv1 to use when
* choosing the X block.
*/
void
des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
des_set_key((void *) key, cc->u.des3.key1);
des_set_key((void *) (key+8), cc->u.des3.key2);
if (keylen <= 16)
des_set_key((void *) key, cc->u.des3.key3);
else
des_set_key((void *) (key+16), cc->u.des3.key3);
}
void
des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
des_cblock iv1;
des_cblock *iv2 = &cc->u.des3.iv2;
des_cblock *iv3 = &cc->u.des3.iv3;
memcpy(&iv1, iv2, 8);
des_ncbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
}
void
des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
des_cblock iv1;
des_cblock *iv2 = &cc->u.des3.iv2;
des_cblock *iv3 = &cc->u.des3.iv3;
memcpy(&iv1, iv2, 8);
des_ncbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
}
/* Blowfish */
void
blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
}
void
blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
memset(cc->u.bf.iv, 0, 8);
else
memcpy(cc->u.bf.iv, (char *)iv, 8);
}
void
blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_ENCRYPT);
}
void
blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_DECRYPT);
}
/*
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
swap_bytes(const u_char *src, u_char *dst, int n)
{
char c[4];
/* Process 4 bytes every lap. */
for (n = n / 4; n > 0; n--) {
c[3] = *src++;
c[2] = *src++;
c[1] = *src++;
c[0] = *src++;
*dst++ = c[0];
*dst++ = c[1];
*dst++ = c[2];
*dst++ = c[3];
}
}
void
blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
swap_bytes(src, dest, len);
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_ENCRYPT);
swap_bytes(dest, dest, len);
}
void
blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
swap_bytes(src, dest, len);
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_DECRYPT);
swap_bytes(dest, dest, len);
}
/* alleged rc4 */
void
arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);
}
void
arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
RC4(&cc->u.rc4, len, (u_char *)src, dest);
}
/* CAST */
void
cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);
}
void
cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy(cc->u.cast.iv, (char *)iv, 8);
}
void
cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
CAST_ENCRYPT);
}
void
cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
CAST_DECRYPT);
}
/* RIJNDAEL */
#define RIJNDAEL_BLOCKSIZE 16
void
rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1);
rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0);
}
void
rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
}
void
rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
rijndael_ctx *ctx = &cc->u.rijndael.enc;
u4byte *iv = cc->u.rijndael.iv;
u4byte in[4];
u4byte *cprev, *cnow, *plain;
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return;
if (len % RIJNDAEL_BLOCKSIZE)
fatal("rijndael_cbc_encrypt: bad len %d", len);
cnow = (u4byte*) dest;
plain = (u4byte*) src;
cprev = iv;
for(i = 0; i < blocks; i++, plain+=4, cnow+=4) {
in[0] = plain[0] ^ cprev[0];
in[1] = plain[1] ^ cprev[1];
in[2] = plain[2] ^ cprev[2];
in[3] = plain[3] ^ cprev[3];
rijndael_encrypt(ctx, in, cnow);
cprev = cnow;
}
memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);
}
void
rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
rijndael_ctx *ctx = &cc->u.rijndael.dec;
u4byte *iv = cc->u.rijndael.iv;
u4byte ivsaved[4];
u4byte *cnow = (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE);
u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE);
u4byte *ivp;
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return;
if (len % RIJNDAEL_BLOCKSIZE)
fatal("rijndael_cbc_decrypt: bad len %d", len);
memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);
for(i = blocks; i > 0; i--, cnow-=4, plain-=4) {
rijndael_decrypt(ctx, cnow, plain);
ivp = (i == 1) ? iv : cnow-4;
plain[0] ^= ivp[0];
plain[1] ^= ivp[1];
plain[2] ^= ivp[2];
plain[3] ^= ivp[3];
}
memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);
}
Cipher ciphers[] = {
{ "none",
SSH_CIPHER_NONE, 8, 0,
none_setkey, none_setiv,
none_crypt, none_crypt },
{ "des",
SSH_CIPHER_DES, 8, 8,
des_ssh1_setkey, des_ssh1_setiv,
des_ssh1_encrypt, des_ssh1_decrypt },
{ "3des",
SSH_CIPHER_3DES, 8, 16,
des3_ssh1_setkey, des3_setiv,
des3_ssh1_encrypt, des3_ssh1_decrypt },
{ "blowfish",
SSH_CIPHER_BLOWFISH, 8, 16,
blowfish_setkey, blowfish_setiv,
blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },
{ "3des-cbc",
SSH_CIPHER_SSH2, 8, 24,
des3_setkey, des3_setiv,
des3_cbc_encrypt, des3_cbc_decrypt },
{ "blowfish-cbc",
SSH_CIPHER_SSH2, 8, 16,
blowfish_setkey, blowfish_setiv,
blowfish_cbc_encrypt, blowfish_cbc_decrypt },
{ "cast128-cbc",
SSH_CIPHER_SSH2, 8, 16,
cast_setkey, cast_setiv,
cast_cbc_encrypt, cast_cbc_decrypt },
{ "arcfour",
SSH_CIPHER_SSH2, 8, 16,
arcfour_setkey, none_setiv,
arcfour_crypt, arcfour_crypt },
{ "aes128-cbc",
SSH_CIPHER_SSH2, 16, 16,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "aes192-cbc",
SSH_CIPHER_SSH2, 16, 24,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "aes256-cbc",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael128-cbc",
SSH_CIPHER_SSH2, 16, 16,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael192-cbc",
SSH_CIPHER_SSH2, 16, 24,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael256-cbc",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael-cbc@lysator.liu.se",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL }
};
/*--*/
u_int
cipher_blocksize(Cipher *c)
{
return (c->block_size);
}
u_int
cipher_keylen(Cipher *c)
{
return (c->key_len);
}
u_int
cipher_mask_ssh1(int client)
{
u_int mask = 0;
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH;
if (client) {
mask |= 1 << SSH_CIPHER_DES;
@ -464,7 +128,7 @@ ciphers_valid(const char *names)
return 0;
ciphers = cp = xstrdup(names);
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
(p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
debug("bad cipher %s [%s]", p, names);
@ -503,8 +167,24 @@ cipher_name(int id)
void
cipher_init(CipherContext *cc, Cipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int encrypt)
{
static int dowarn = 1;
const EVP_CIPHER *type;
int klen;
if (cipher->number == SSH_CIPHER_DES) {
if (dowarn) {
error("Warning: use of DES is strongly discouraged "
"due to cryptographic weaknesses");
dowarn = 0;
}
if (keylen > 8)
keylen = 8;
}
cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
if (keylen < cipher->key_len)
fatal("cipher_init: key length %d is insufficient for %s.",
keylen, cipher->name);
@ -512,24 +192,40 @@ cipher_init(CipherContext *cc, Cipher *cipher,
fatal("cipher_init: iv length %d is insufficient for %s.",
ivlen, cipher->name);
cc->cipher = cipher;
cipher->setkey(cc, key, keylen);
cipher->setiv(cc, iv, ivlen);
type = (*cipher->evptype)();
EVP_CIPHER_CTX_init(&cc->evp);
if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
(encrypt == CIPHER_ENCRYPT)) == 0)
fatal("cipher_init: EVP_CipherInit failed for %s",
cipher->name);
klen = EVP_CIPHER_CTX_key_length(&cc->evp);
if (klen > 0 && keylen != klen) {
debug("cipher_init: set keylen (%d -> %d)", klen, keylen);
if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
fatal("cipher_init: set keylen failed (%d -> %d)",
klen, keylen);
}
if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
fatal("cipher_init: EVP_CipherInit: set key failed for %s",
cipher->name);
}
void
cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
if (len % cc->cipher->block_size)
fatal("cipher_encrypt: bad plaintext length %d", len);
cc->cipher->encrypt(cc, dest, src, len);
if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0)
fatal("evp_crypt: EVP_Cipher failed");
}
void
cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
cipher_cleanup(CipherContext *cc)
{
if (len % cc->cipher->block_size)
fatal("cipher_decrypt: bad ciphertext length %d", len);
cc->cipher->decrypt(cc, dest, src, len);
if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
}
/*
@ -539,7 +235,7 @@ cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
void
cipher_set_key_string(CipherContext *cc, Cipher *cipher,
const char *passphrase)
const char *passphrase, int encrypt)
{
MD5_CTX md;
u_char digest[16];
@ -548,8 +244,257 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
MD5_Final(digest, &md);
cipher_init(cc, cipher, digest, 16, NULL, 0);
cipher_init(cc, cipher, digest, 16, NULL, 0, encrypt);
memset(digest, 0, sizeof(digest));
memset(&md, 0, sizeof(md));
}
/* Implementations for other non-EVP ciphers */
/*
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
* If only iv3 was used, then, this would till effect have been
* outer-cbc. However, there is also a private iv1 == iv2 which
* perhaps makes differential analysis easier. On the other hand, the
* private iv1 probably makes the CRC-32 attack ineffective. This is a
* result of that there is no longer any known iv1 to use when
* choosing the X block.
*/
struct ssh1_3des_ctx
{
EVP_CIPHER_CTX k1, k2, k3;
};
static int
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
int enc)
{
struct ssh1_3des_ctx *c;
u_char *k1, *k2, *k3;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
c = xmalloc(sizeof(*c));
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key == NULL)
return (1);
if (enc == -1)
enc = ctx->encrypt;
k1 = k2 = k3 = (u_char *) key;
k2 += 8;
if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
if (enc)
k3 += 16;
else
k1 += 16;
}
EVP_CIPHER_CTX_init(&c->k1);
EVP_CIPHER_CTX_init(&c->k2);
EVP_CIPHER_CTX_init(&c->k3);
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
return (0);
}
return (1);
}
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
error("ssh1_3des_cbc: no context");
return (0);
}
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
EVP_Cipher(&c->k3, dest, dest, len) == 0)
return (0);
return (1);
}
static int
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
return (1);
}
static EVP_CIPHER *
evp_ssh1_3des(void)
{
static EVP_CIPHER ssh1_3des;
memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
ssh1_3des.nid = NID_undef;
ssh1_3des.block_size = 8;
ssh1_3des.iv_len = 0;
ssh1_3des.key_len = 16;
ssh1_3des.init = ssh1_3des_init;
ssh1_3des.cleanup = ssh1_3des_cleanup;
ssh1_3des.do_cipher = ssh1_3des_cbc;
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
return (&ssh1_3des);
}
/*
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
swap_bytes(const u_char *src, u_char *dst, int n)
{
u_char c[4];
/* Process 4 bytes every lap. */
for (n = n / 4; n > 0; n--) {
c[3] = *src++;
c[2] = *src++;
c[1] = *src++;
c[0] = *src++;
*dst++ = c[0];
*dst++ = c[1];
*dst++ = c[2];
*dst++ = c[3];
}
}
static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *, const u_char *, u_int) = NULL;
static int
bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int len)
{
int ret;
swap_bytes(in, out, len);
ret = (*orig_bf)(ctx, out, out, len);
swap_bytes(out, out, len);
return (ret);
}
static EVP_CIPHER *
evp_ssh1_bf(void)
{
static EVP_CIPHER ssh1_bf;
memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
orig_bf = ssh1_bf.do_cipher;
ssh1_bf.nid = NID_undef;
ssh1_bf.do_cipher = bf_ssh1_cipher;
ssh1_bf.key_len = 32;
return (&ssh1_bf);
}
/* RIJNDAEL */
#define RIJNDAEL_BLOCKSIZE 16
struct ssh_rijndael_ctx
{
rijndael_ctx r_ctx;
u_char r_iv[RIJNDAEL_BLOCKSIZE];
};
static int
ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
int enc)
{
struct ssh_rijndael_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
c = xmalloc(sizeof(*c));
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key != NULL) {
if (enc == -1)
enc = ctx->encrypt;
rijndael_set_key(&c->r_ctx, (u_char *)key,
8*EVP_CIPHER_CTX_key_length(ctx), enc);
}
if (iv != NULL)
memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE);
return (1);
}
static int
ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
u_int len)
{
struct ssh_rijndael_ctx *c;
u_char buf[RIJNDAEL_BLOCKSIZE];
u_char *cprev, *cnow, *plain, *ivp;
int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return (1);
if (len % RIJNDAEL_BLOCKSIZE)
fatal("ssh_rijndael_cbc: bad len %d", len);
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
error("ssh_rijndael_cbc: no context");
return (0);
}
if (ctx->encrypt) {
cnow = dest;
plain = (u_char *)src;
cprev = c->r_iv;
for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
cnow+=RIJNDAEL_BLOCKSIZE) {
for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
buf[j] = plain[j] ^ cprev[j];
rijndael_encrypt(&c->r_ctx, buf, cnow);
cprev = cnow;
}
memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE);
} else {
cnow = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
plain = dest+len-RIJNDAEL_BLOCKSIZE;
memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE);
for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
plain-=RIJNDAEL_BLOCKSIZE) {
rijndael_decrypt(&c->r_ctx, cnow, plain);
ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE;
for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
plain[j] ^= ivp[j];
}
memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE);
}
return (1);
}
static int
ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx)
{
struct ssh_rijndael_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
return (1);
}
static EVP_CIPHER *
evp_rijndael(void)
{
static EVP_CIPHER rijndal_cbc;
memset(&rijndal_cbc, 0, sizeof(EVP_CIPHER));
rijndal_cbc.nid = NID_undef;
rijndal_cbc.block_size = RIJNDAEL_BLOCKSIZE;
rijndal_cbc.iv_len = RIJNDAEL_BLOCKSIZE;
rijndal_cbc.key_len = 16;
rijndal_cbc.init = ssh_rijndael_init;
rijndal_cbc.cleanup = ssh_rijndael_cleanup;
rijndal_cbc.do_cipher = ssh_rijndael_cbc;
rijndal_cbc.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
EVP_CIPH_ALWAYS_CALL_INIT;
return (&rijndal_cbc);
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: cipher.h,v 1.32 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -32,16 +34,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
#ifndef CIPHER_H
#define CIPHER_H
#include <openssl/des.h>
#include <openssl/blowfish.h>
#include <openssl/rc4.h>
#include <openssl/cast.h>
#include "rijndael.h"
#include <openssl/evp.h>
/*
* Cipher types for SSH-1. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
@ -59,59 +55,30 @@
#define SSH_CIPHER_RESERVED 7
#define SSH_CIPHER_MAX 31
#define CIPHER_ENCRYPT 1
#define CIPHER_DECRYPT 0
typedef struct Cipher Cipher;
typedef struct CipherContext CipherContext;
struct Cipher;
struct CipherContext {
union {
struct {
des_key_schedule key;
des_cblock iv;
} des;
struct {
des_key_schedule key1;
des_key_schedule key2;
des_cblock iv2;
des_key_schedule key3;
des_cblock iv3;
} des3;
struct {
struct bf_key_st key;
u_char iv[8];
} bf;
struct {
CAST_KEY key;
u_char iv[8];
} cast;
struct {
u4byte iv[4];
rijndael_ctx enc;
rijndael_ctx dec;
} rijndael;
RC4_KEY rc4;
} u;
int plaintext;
EVP_CIPHER_CTX evp;
Cipher *cipher;
};
struct Cipher {
char *name;
int number; /* for ssh1 only */
u_int block_size;
u_int key_len;
void (*setkey)(CipherContext *, const u_char *, u_int);
void (*setiv)(CipherContext *, const u_char *, u_int);
void (*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
};
u_int cipher_mask_ssh1(int client);
Cipher *cipher_by_name(const char *name);
Cipher *cipher_by_number(int id);
int cipher_number(const char *name);
char *cipher_name(int id);
int ciphers_valid(const char *names);
void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int);
void cipher_encrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
void cipher_decrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
void cipher_set_key_string(CipherContext *context, Cipher *cipher, const char *passphrase);
u_int cipher_mask_ssh1(int);
Cipher *cipher_by_name(const char *);
Cipher *cipher_by_number(int);
int cipher_number(const char *);
char *cipher_name(int);
int ciphers_valid(const char *);
void cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
const u_char *, u_int, int);
void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
void cipher_cleanup(CipherContext *);
void cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
u_int cipher_blocksize(Cipher *);
u_int cipher_keylen(Cipher *);
#endif /* CIPHER_H */

View File

@ -35,7 +35,7 @@
*
*
* SSH2 support added by Markus Friedl.
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -59,7 +59,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: clientloop.c,v 1.65 2001/04/20 07:17:51 djm Exp $");
RCSID("$OpenBSD: clientloop.c,v 1.96 2002/02/06 14:55:15 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@ -101,7 +101,8 @@ extern char *host;
* window size to be sent to the server a little later. This is volatile
* because this is updated in a signal handler.
*/
static volatile int received_window_change_signal = 0;
static volatile sig_atomic_t received_window_change_signal = 0;
static volatile sig_atomic_t received_signal = 0;
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
static int in_non_blocking_mode = 0;
@ -123,7 +124,7 @@ static int connection_out; /* Connection to server (output). */
static int need_rekeying; /* Set to non-zero if rekeying is requested. */
static int session_closed = 0; /* In SSH2: login session closed. */
void client_init_dispatch(void);
static void client_init_dispatch(void);
int session_ident = -1;
/*XXX*/
@ -131,7 +132,7 @@ extern Kex *xxx_kex;
/* Restores stdin to blocking mode. */
void
static void
leave_non_blocking(void)
{
if (in_non_blocking_mode) {
@ -143,7 +144,7 @@ leave_non_blocking(void)
/* Puts stdin terminal in non-blocking mode. */
void
static void
enter_non_blocking(void)
{
in_non_blocking_mode = 1;
@ -156,7 +157,7 @@ enter_non_blocking(void)
* flag indicating that the window has changed.
*/
void
static void
window_change_handler(int sig)
{
received_window_change_signal = 1;
@ -168,16 +169,11 @@ window_change_handler(int sig)
* signals must be trapped to restore terminal modes.
*/
void
static void
signal_handler(int sig)
{
if (in_raw_mode())
leave_raw_mode();
if (in_non_blocking_mode)
leave_non_blocking();
channel_stop_listening();
packet_close();
fatal("Killed by signal %d.", sig);
received_signal = sig;
quit_pending = 1;
}
/*
@ -185,7 +181,7 @@ signal_handler(int sig)
* available resolution.
*/
double
static double
get_current_time(void)
{
struct timeval tv;
@ -199,7 +195,7 @@ get_current_time(void)
* not appear to wake up when redirecting from /dev/null.
*/
void
static void
client_check_initial_eof_on_stdin(void)
{
int len;
@ -251,14 +247,14 @@ client_check_initial_eof_on_stdin(void)
* connection.
*/
void
static void
client_make_packets_from_stdin_data(void)
{
u_int len;
/* Send buffered stdin data to the server. */
while (buffer_len(&stdin_buffer) > 0 &&
packet_not_very_much_data_to_write()) {
packet_not_very_much_data_to_write()) {
len = buffer_len(&stdin_buffer);
/* Keep the packets at reasonable size. */
if (len > packet_get_maxsize())
@ -283,7 +279,7 @@ client_make_packets_from_stdin_data(void)
* appropriate.
*/
void
static void
client_check_window_change(void)
{
struct winsize ws;
@ -320,12 +316,12 @@ client_check_window_change(void)
* one of the file descriptors).
*/
void
static void
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
int *maxfdp, int *nallocp, int rekeying)
{
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
if (!compat20) {
/* Read from the connection, unless our buffers are full. */
@ -346,7 +342,16 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), *writesetp);
} else {
FD_SET(connection_in, *readsetp);
/* channel_prepare_select could have closed the last channel */
if (session_closed && !channel_still_open() &&
!packet_have_data_to_write()) {
/* clear mask since we did not call select() */
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
return;
} else {
FD_SET(connection_in, *readsetp);
}
}
/* Select server connection if have data to write to the server. */
@ -370,8 +375,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
* We have to return, because the mainloop checks for the flags
* set by the signal handlers.
*/
memset(*readsetp, 0, *maxfdp);
memset(*writesetp, 0, *maxfdp);
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
if (errno == EINTR)
return;
@ -382,7 +387,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
}
}
void
static void
client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
{
struct winsize oldws, newws;
@ -412,9 +417,9 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
/* Check if the window size has changed. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
(oldws.ws_row != newws.ws_row ||
oldws.ws_col != newws.ws_col ||
oldws.ws_xpixel != newws.ws_xpixel ||
oldws.ws_ypixel != newws.ws_ypixel))
oldws.ws_col != newws.ws_col ||
oldws.ws_xpixel != newws.ws_xpixel ||
oldws.ws_ypixel != newws.ws_ypixel))
received_window_change_signal = 1;
/* OK, we have been continued by the user. Reinitialize buffers. */
@ -425,7 +430,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
enter_raw_mode();
}
void
static void
client_process_net_input(fd_set * readset)
{
int len;
@ -466,7 +471,7 @@ client_process_net_input(fd_set * readset)
}
/* process the characters one by one */
int
static int
process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
{
char string[1024];
@ -517,14 +522,36 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
continue;
case '&':
/* XXX does not work yet with proto 2 */
if (compat20)
continue;
/*
* Detach the program (continue to serve connections,
* but put in background and no more new connections).
*/
if (!stdin_eof) {
/* Restore tty modes. */
leave_raw_mode();
/* Stop listening for new connections. */
channel_stop_listening();
snprintf(string, sizeof string,
"%c& [backgrounded]\n", escape_char);
buffer_append(berr, string, strlen(string));
/* Fork into background. */
pid = fork();
if (pid < 0) {
error("fork: %.100s", strerror(errno));
continue;
}
if (pid != 0) { /* This is the parent. */
/* The parent just exits. */
exit(0);
}
/* The child continues serving connections. */
if (compat20) {
buffer_append(bin, "\004", 1);
/* fake EOF on stdin */
return -1;
} else if (!stdin_eof) {
/*
* Sending SSH_CMSG_EOF alone does not always appear
* to be enough. So we try to send an EOF character
@ -540,33 +567,14 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
packet_send();
}
}
/* Restore tty modes. */
leave_raw_mode();
/* Stop listening for new connections. */
channel_stop_listening();
printf("%c& [backgrounded]\n", escape_char);
/* Fork into background. */
pid = fork();
if (pid < 0) {
error("fork: %.100s", strerror(errno));
continue;
}
if (pid != 0) { /* This is the parent. */
/* The parent just exits. */
exit(0);
}
/* The child continues serving connections. */
continue; /*XXX ? */
continue;
case '?':
snprintf(string, sizeof string,
"%c?\r\n\
Supported escape sequences:\r\n\
~. - terminate connection\r\n\
~R - Request rekey (SSH protocol 2 only)\r\n\
~R - Request rekey (SSH protocol 2 only)\r\n\
~^Z - suspend ssh\r\n\
~# - list forwarded connections\r\n\
~& - background ssh (when waiting for connections to terminate)\r\n\
@ -616,7 +624,7 @@ Supported escape sequences:\r\n\
return bytes;
}
void
static void
client_process_input(fd_set * readset)
{
int len;
@ -651,7 +659,7 @@ client_process_input(fd_set * readset)
packet_start(SSH_CMSG_EOF);
packet_send();
}
} else if (escape_char == -1) {
} else if (escape_char == SSH_ESCAPECHAR_NONE) {
/*
* Normal successful read, and no escape character.
* Just append the data to buffer.
@ -669,7 +677,7 @@ client_process_input(fd_set * readset)
}
}
void
static void
client_process_output(fd_set * writeset)
{
int len;
@ -730,7 +738,7 @@ client_process_output(fd_set * writeset)
* preparatory phase.
*/
void
static void
client_process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
@ -738,19 +746,20 @@ client_process_buffered_input_packets(void)
/* scan buf[] for '~' before sending data to the peer */
int
static int
simple_escape_filter(Channel *c, char *buf, int len)
{
/* XXX we assume c->extended is writeable */
return process_escapes(&c->input, &c->output, &c->extended, buf, len);
}
void
static void
client_channel_closed(int id, void *arg)
{
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
channel_cancel_cleanup(id);
session_closed = 1;
if (in_raw_mode())
leave_raw_mode();
@ -759,8 +768,8 @@ client_channel_closed(int id, void *arg)
/*
* Implements the interactive session with the server. This is called after
* the user has been authenticated, and a command has been started on the
* remote host. If escape_char != -1, it is the character used as an escape
* character for terminating or suspending the session.
* remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character
* used as an escape character for terminating or suspending the session.
*/
int
@ -768,7 +777,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
int max_fd = 0, len, rekeying = 0;
int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;
char buf[100];
debug("Entering interactive session.");
@ -814,7 +823,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGPIPE, SIG_IGN);
if (have_pty)
signal(SIGWINCH, window_change_handler);
@ -823,7 +831,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (compat20) {
session_ident = ssh2_chan_id;
if (escape_char != -1)
if (escape_char != SSH_ESCAPECHAR_NONE)
channel_register_filter(session_ident,
simple_escape_filter);
if (session_ident != -1)
@ -875,8 +883,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
* Wait until we have something to do (something becomes
* available on one of the descriptors).
*/
max_fd2 = max_fd;
client_wait_until_can_do_something(&readset, &writeset,
&max_fd, rekeying);
&max_fd2, &nalloc, rekeying);
if (quit_pending)
break;
@ -924,8 +933,24 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (have_pty)
signal(SIGWINCH, SIG_DFL);
/* Stop listening for connections. */
channel_stop_listening();
channel_free_all();
if (have_pty)
leave_raw_mode();
/* restore blocking io */
if (!isatty(fileno(stdin)))
unset_nonblock(fileno(stdin));
if (!isatty(fileno(stdout)))
unset_nonblock(fileno(stdout));
if (!isatty(fileno(stderr)))
unset_nonblock(fileno(stderr));
if (received_signal) {
if (in_non_blocking_mode) /* XXX */
leave_non_blocking();
fatal("Killed by signal %d.", (int) received_signal);
}
/*
* In interactive mode (with pseudo tty) display a message indicating
@ -935,6 +960,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
buffer_append(&stderr_buffer, buf, strlen(buf));
}
/* Output any buffered data for stdout. */
while (buffer_len(&stdout_buffer) > 0) {
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
@ -959,9 +985,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
stderr_bytes += len;
}
if (have_pty)
leave_raw_mode();
/* Clear and free any buffers. */
memset(buf, 0, sizeof(buf));
buffer_free(&stdin_buffer);
@ -971,11 +994,11 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/* Report bytes transferred, and transfer rates. */
total_time = get_current_time() - start_time;
debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
stdin_bytes, stdout_bytes, stderr_bytes, total_time);
stdin_bytes, stdout_bytes, stderr_bytes, total_time);
if (total_time > 0)
debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
stdin_bytes / total_time, stdout_bytes / total_time,
stderr_bytes / total_time);
stdin_bytes / total_time, stdout_bytes / total_time,
stderr_bytes / total_time);
/* Return the exit status of the program. */
debug("Exit status %d", exit_status);
@ -984,31 +1007,31 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/*********/
void
client_input_stdout_data(int type, int plen, void *ctxt)
static void
client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
{
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
packet_check_eom();
buffer_append(&stdout_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
}
void
client_input_stderr_data(int type, int plen, void *ctxt)
static void
client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
{
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
packet_check_eom();
buffer_append(&stderr_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
}
void
client_input_exit_status(int type, int plen, void *ctxt)
static void
client_input_exit_status(int type, u_int32_t seq, void *ctxt)
{
packet_integrity_check(plen, 4, type);
exit_status = packet_get_int();
packet_check_eom();
/* Acknowledge the exit. */
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
packet_send();
@ -1021,44 +1044,46 @@ client_input_exit_status(int type, int plen, void *ctxt)
quit_pending = 1;
}
Channel *
static Channel *
client_request_forwarded_tcpip(const char *request_type, int rchan)
{
Channel* c = NULL;
char *listen_address, *originator_address;
int listen_port, originator_port;
int sock, newch;
int sock;
/* Get rest of the packet */
listen_address = packet_get_string(NULL);
listen_port = packet_get_int();
originator_address = packet_get_string(NULL);
originator_port = packet_get_int();
packet_done();
packet_check_eom();
debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d",
listen_address, listen_port, originator_address, originator_port);
sock = channel_connect_by_listen_adress(listen_port);
if (sock >= 0) {
newch = channel_new("forwarded-tcpip",
SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup(originator_address), 1);
c = channel_lookup(newch);
sock = channel_connect_by_listen_address(listen_port);
if (sock < 0) {
xfree(originator_address);
xfree(listen_address);
return NULL;
}
c = channel_new("forwarded-tcpip",
SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup(originator_address), 1);
xfree(originator_address);
xfree(listen_address);
return c;
}
Channel*
static Channel*
client_request_x11(const char *request_type, int rchan)
{
Channel *c = NULL;
char *originator;
int originator_port;
int sock, newch;
int sock;
if (!options.forward_x11) {
error("Warning: ssh server tried X11 forwarding.");
@ -1072,27 +1097,27 @@ client_request_x11(const char *request_type, int rchan)
} else {
originator_port = packet_get_int();
}
packet_done();
packet_check_eom();
/* XXX check permission */
debug("client_request_x11: request from %s %d", originator,
originator_port);
sock = x11_connect_display();
if (sock >= 0) {
newch = channel_new("x11",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0,
xstrdup("x11"), 1);
c = channel_lookup(newch);
}
xfree(originator);
sock = x11_connect_display();
if (sock < 0)
return NULL;
c = channel_new("x11",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0,
xstrdup("x11"), 1);
c->force_drain = 1;
return c;
}
Channel*
static Channel*
client_request_agent(const char *request_type, int rchan)
{
Channel *c = NULL;
int sock, newch;
int sock;
if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding.");
@ -1100,19 +1125,19 @@ client_request_agent(const char *request_type, int rchan)
return NULL;
}
sock = ssh_get_authentication_socket();
if (sock >= 0) {
newch = channel_new("authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup("authentication agent connection"), 1);
c = channel_lookup(newch);
}
if (sock < 0)
return NULL;
c = channel_new("authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup("authentication agent connection"), 1);
c->force_drain = 1;
return c;
}
/* XXXX move to generic input handler */
void
client_input_channel_open(int type, int plen, void *ctxt)
static void
client_input_channel_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
char *ctype;
@ -1142,26 +1167,29 @@ client_input_channel_open(int type, int plen, void *ctxt)
c->remote_id = rchan;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
packet_put_int(c->remote_id);
packet_put_int(c->self);
packet_put_int(c->local_window);
packet_put_int(c->local_maxpacket);
packet_send();
if (c->type != SSH_CHANNEL_CONNECTING) {
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
packet_put_int(c->remote_id);
packet_put_int(c->self);
packet_put_int(c->local_window);
packet_put_int(c->local_maxpacket);
packet_send();
}
} else {
debug("failure %s", ctype);
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan);
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
packet_put_cstring("bla bla");
packet_put_cstring("");
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
packet_put_cstring("open failed");
packet_put_cstring("");
}
packet_send();
}
xfree(ctype);
}
void
client_input_channel_req(int type, int plen, void *ctxt)
static void
client_input_channel_req(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
int id, reply, success = 0;
@ -1186,7 +1214,7 @@ client_input_channel_req(int type, int plen, void *ctxt)
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
packet_check_eom();
}
if (reply) {
packet_start(success ?
@ -1196,8 +1224,26 @@ client_input_channel_req(int type, int plen, void *ctxt)
}
xfree(rtype);
}
static void
client_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
int success = 0;
void
rtype = packet_get_string(NULL);
want_reply = packet_get_char();
debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply);
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
packet_send();
packet_write_wait();
}
xfree(rtype);
}
static void
client_init_dispatch_20(void)
{
dispatch_init(&dispatch_protocol_error);
@ -1210,11 +1256,12 @@ client_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
static void
client_init_dispatch_13(void)
{
dispatch_init(NULL);
@ -1233,14 +1280,14 @@ client_init_dispatch_13(void)
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
&x11_input_open : &deny_input_open);
}
void
static void
client_init_dispatch_15(void)
{
client_init_dispatch_13();
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
}
void
static void
client_init_dispatch(void)
{
if (compat20)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.4 2001/02/06 22:43:02 markus Exp $ */
/* $OpenBSD: clientloop.h,v 1.6 2001/06/26 17:27:23 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -36,4 +36,4 @@
*/
/* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char, int id);
int client_loop(int, int, int);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,14 +23,14 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $");
#include <regex.h>
RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $");
#include "buffer.h"
#include "packet.h"
#include "xmalloc.h"
#include "compat.h"
#include "log.h"
#include "match.h"
int compat13 = 0;
int compat20 = 0;
@ -52,76 +52,97 @@ enable_compat13(void)
void
compat_datafellows(const char *version)
{
int i, ret;
char ebuf[1024];
regex_t reg;
int i;
static struct {
char *pat;
int bugs;
} check[] = {
{ "^OpenSSH[-_]2\\.[012]",
SSH_OLD_SESSIONID|SSH_BUG_BANNER|
{ "OpenSSH-2.0*,"
"OpenSSH-2.1*,"
"OpenSSH_2.1*,"
"OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
{ "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.3\\.", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
{ "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.5\\.[01]p1",
{ "OpenSSH_2.5.0p1*,"
"OpenSSH_2.5.1p1*",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.[012]",
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.3",
SSH_BUG_NOREKEY },
{ "^OpenSSH", 0 },
{ "MindTerm", 0 },
{ "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "OpenSSH_2.5.0*,"
"OpenSSH_2.5.1*,"
"OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "OpenSSH_2.5.3*", SSH_BUG_NOREKEY },
{ "Sun_SSH_1.0*", SSH_BUG_NOREKEY },
{ "OpenSSH*", 0 },
{ "*MindTerm*", 0 },
{ "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.1 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "2.0.13*,"
"2.0.14*,"
"2.0.15*,"
"2.0.16*,"
"2.0.17*,"
"2.0.18*,"
"2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
SSH_BUG_HBSERVICE },
{ "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE|
SSH_BUG_DUMMYCHAN },
{ "2.0.11*,"
"2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
SSH_BUG_DUMMYCHAN },
{ "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN },
{ "2.2.0*,"
"2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5 },
{ "^2\\.[23]\\.0", SSH_BUG_HMAC|SSH_BUG_RSASIGMD5 },
{ "^2\\.3\\.", SSH_BUG_RSASIGMD5 },
{ "^2\\.[2-9]\\.", 0 },
{ "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
{ "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "^SSH Compatible Server", /* Netscreen */
{ "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5 },
{ "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "2.*", SSH_BUG_DEBUG },
{ "3.0.*", SSH_BUG_DEBUG },
{ "3.0 SecureCRT*", SSH_OLD_SESSIONID },
{ "1.7 SecureFX*", SSH_OLD_SESSIONID },
{ "1.2.18*,"
"1.2.19*,"
"1.2.20*,"
"1.2.21*,"
"1.2.22*", SSH_BUG_IGNOREMSG },
{ "1.3.2*", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "*SSH Compatible Server*", /* Netscreen */
SSH_BUG_PASSWORDPAD },
{ "^OSU_0", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.5alpha[1-3]",
SSH_BUG_PASSWORDPAD },
{ "^SSH_Version_Mapper",
{ "*OSU_0*,"
"OSU_1.0*,"
"OSU_1.1*,"
"OSU_1.2*,"
"OSU_1.3*,"
"OSU_1.4*,"
"OSU_1.5alpha1*,"
"OSU_1.5alpha2*,"
"OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD },
{ "*SSH_Version_Mapper*",
SSH_BUG_SCANNER },
{ NULL, 0 }
};
/* process table, return first match */
for (i = 0; check[i].pat; i++) {
ret = regcomp(&reg, check[i].pat, REG_EXTENDED|REG_NOSUB);
if (ret != 0) {
regerror(ret, &reg, ebuf, sizeof(ebuf));
ebuf[sizeof(ebuf)-1] = '\0';
error("regerror: %s", ebuf);
continue;
}
ret = regexec(&reg, version, 0, NULL, 0);
regfree(&reg);
if (ret == 0) {
if (match_pattern_list(version, check[i].pat,
strlen(check[i].pat), 0) == 1) {
debug("match: %s pat %s", version, check[i].pat);
datafellows = check[i].bugs;
return;
@ -141,7 +162,7 @@ proto_spec(const char *spec)
return ret;
q = s = xstrdup(spec);
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
switch(atoi(p)) {
switch (atoi(p)) {
case 1:
if (ret == SSH_PROTO_UNKNOWN)
ret |= SSH_PROTO_1_PREFERRED;
@ -162,24 +183,25 @@ proto_spec(const char *spec)
char *
compat_cipher_proposal(char *cipher_prop)
{
Buffer b;
char *orig_prop, *fix_ciphers;
char *cp, *tmp;
size_t len;
if (!(datafellows & SSH_BUG_BIGENDIANAES))
return(cipher_prop);
len = strlen(cipher_prop) + 1;
fix_ciphers = xmalloc(len);
*fix_ciphers = '\0';
buffer_init(&b);
tmp = orig_prop = xstrdup(cipher_prop);
while((cp = strsep(&tmp, ",")) != NULL) {
if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) {
if (*fix_ciphers)
strlcat(fix_ciphers, ",", len);
strlcat(fix_ciphers, cp, len);
while ((cp = strsep(&tmp, ",")) != NULL) {
if (strncmp(cp, "aes", 3) != 0) {
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, cp, strlen(cp));
}
}
buffer_append(&b, "\0", 1);
fix_ciphers = xstrdup(buffer_ptr(&b));
buffer_free(&b);
xfree(orig_prop);
debug2("Original cipher proposal: %s", cipher_prop);
debug2("Compat cipher proposal: %s", fix_ciphers);

View File

@ -1,5 +1,7 @@
/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -21,7 +23,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */
#ifndef COMPAT_H
#define COMPAT_H
@ -31,29 +32,33 @@
#define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04
#define SSH_BUG_SIGBLOB 0x0001
#define SSH_BUG_PKSERVICE 0x0002
#define SSH_BUG_HMAC 0x0004
#define SSH_BUG_X11FWD 0x0008
#define SSH_OLD_SESSIONID 0x0010
#define SSH_BUG_PKAUTH 0x0020
#define SSH_BUG_DEBUG 0x0040
#define SSH_BUG_BANNER 0x0080
#define SSH_BUG_IGNOREMSG 0x0100
#define SSH_BUG_PKOK 0x0200
#define SSH_BUG_PASSWORDPAD 0x0400
#define SSH_BUG_SCANNER 0x0800
#define SSH_BUG_BIGENDIANAES 0x1000
#define SSH_BUG_RSASIGMD5 0x2000
#define SSH_OLD_DHGEX 0x4000
#define SSH_BUG_NOREKEY 0x8000
#define SSH_BUG_HBSERVICE 0x10000
#define SSH_BUG_SIGBLOB 0x00000001
#define SSH_BUG_PKSERVICE 0x00000002
#define SSH_BUG_HMAC 0x00000004
#define SSH_BUG_X11FWD 0x00000008
#define SSH_OLD_SESSIONID 0x00000010
#define SSH_BUG_PKAUTH 0x00000020
#define SSH_BUG_DEBUG 0x00000040
#define SSH_BUG_BANNER 0x00000080
#define SSH_BUG_IGNOREMSG 0x00000100
#define SSH_BUG_PKOK 0x00000200
#define SSH_BUG_PASSWORDPAD 0x00000400
#define SSH_BUG_SCANNER 0x00000800
#define SSH_BUG_BIGENDIANAES 0x00001000
#define SSH_BUG_RSASIGMD5 0x00002000
#define SSH_OLD_DHGEX 0x00004000
#define SSH_BUG_NOREKEY 0x00008000
#define SSH_BUG_HBSERVICE 0x00010000
#define SSH_BUG_OPENFAILURE 0x00020000
#define SSH_BUG_DERIVEKEY 0x00040000
#define SSH_BUG_DUMMYCHAN 0x00100000
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *);
int proto_spec(const char *);
char *compat_cipher_proposal(char *);
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *s);
int proto_spec(const char *spec);
char *compat_cipher_proposal(char *cipher_prop);
extern int compat13;
extern int compat20;
extern int datafellows;

View File

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compress.c,v 1.14 2001/04/05 10:39:01 markus Exp $");
RCSID("$OpenBSD: compress.c,v 1.17 2001/12/29 21:56:01 stevesk Exp $");
#include "log.h"
#include "buffer.h"
@ -33,7 +33,7 @@ void
buffer_compress_init_send(int level)
{
if (compress_init_send_called == 1)
deflateEnd(&incoming_stream);
deflateEnd(&outgoing_stream);
compress_init_send_called = 1;
debug("Enabling compression at level %d.", level);
if (level < 1 || level > 9)
@ -55,13 +55,13 @@ void
buffer_compress_uninit(void)
{
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
outgoing_stream.total_in, outgoing_stream.total_out,
outgoing_stream.total_in == 0 ? 0.0 :
(double) outgoing_stream.total_out / outgoing_stream.total_in);
outgoing_stream.total_in, outgoing_stream.total_out,
outgoing_stream.total_in == 0 ? 0.0 :
(double) outgoing_stream.total_out / outgoing_stream.total_in);
debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
incoming_stream.total_out, incoming_stream.total_in,
incoming_stream.total_out == 0 ? 0.0 :
(double) incoming_stream.total_in / incoming_stream.total_out);
incoming_stream.total_out, incoming_stream.total_in,
incoming_stream.total_out == 0 ? 0.0 :
(double) incoming_stream.total_in / incoming_stream.total_out);
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
if (compress_init_send_called == 1)
@ -80,7 +80,7 @@ buffer_compress_uninit(void)
void
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
{
char buf[4096];
u_char buf[4096];
int status;
/* This case is not handled below. */
@ -88,13 +88,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
return;
/* Input is the contents of the input buffer. */
outgoing_stream.next_in = (u_char *) buffer_ptr(input_buffer);
outgoing_stream.next_in = buffer_ptr(input_buffer);
outgoing_stream.avail_in = buffer_len(input_buffer);
/* Loop compressing until deflate() returns with avail_out != 0. */
do {
/* Set up fixed-size output buffer. */
outgoing_stream.next_out = (u_char *)buf;
outgoing_stream.next_out = buf;
outgoing_stream.avail_out = sizeof(buf);
/* Compress as much data into the buffer as possible. */
@ -124,15 +124,15 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
void
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
{
char buf[4096];
u_char buf[4096];
int status;
incoming_stream.next_in = (u_char *) buffer_ptr(input_buffer);
incoming_stream.next_in = buffer_ptr(input_buffer);
incoming_stream.avail_in = buffer_len(input_buffer);
for (;;) {
/* Set up fixed-size output buffer. */
incoming_stream.next_out = (u_char *) buf;
incoming_stream.next_out = buf;
incoming_stream.avail_out = sizeof(buf);
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: compress.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,39 +13,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: compress.h,v 1.8 2001/04/05 10:39:02 markus Exp $"); */
#ifndef COMPRESS_H
#define COMPRESS_H
/*
* Initializes compression; level is compression level from 1 to 9 (as in
* gzip).
*/
void buffer_compress_init_send(int level);
void buffer_compress_init_recv(void);
/* Frees any data structures allocated by buffer_compress_init. */
void buffer_compress_uninit(void);
/*
* Compresses the contents of input_buffer into output_buffer. All packets
* compressed using this function will form a single compressed data stream;
* however, data will be flushed at the end of every call so that each
* output_buffer can be decompressed independently (but in the appropriate
* order since they together form a single compression stream) by the
* receiver. This appends the compressed data to the output buffer.
*/
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
/*
* Uncompresses the contents of input_buffer into output_buffer. All packets
* uncompressed using this function will form a single compressed data
* stream; however, data will be flushed at the end of every call so that
* each output_buffer. This must be called for the same size units that the
* buffer_compress was called, and in the same order that buffers compressed
* with that. This appends the uncompressed data to the output buffer.
*/
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
void buffer_compress_init_send(int);
void buffer_compress_init_recv(void);
void buffer_compress_uninit(void);
void buffer_compress(Buffer *, Buffer *);
void buffer_uncompress(Buffer *, Buffer *);
#endif /* COMPRESS_H */

View File

@ -1,3 +1,5 @@
/* $OpenBSD: crc32.h,v 1.13 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1992 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,15 +13,9 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: crc32.h,v 1.10 2001/03/02 18:54:31 deraadt Exp $"); */
#ifndef CRC32_H
#define CRC32_H
/*
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
* The polynomial used is 0xedb88320.
*/
u_int ssh_crc32(const u_char *buf, u_int len);
u_int ssh_crc32(const u_char *, u_int);
#endif /* CRC32_H */

View File

@ -1,5 +1,3 @@
/* $OpenBSD: deattack.c,v 1.13 2001/03/01 02:45:10 deraadt Exp $ */
/*
* Cryptographic attack detector for ssh - source code
*
@ -20,11 +18,14 @@
*/
#include "includes.h"
RCSID("$OpenBSD: deattack.c,v 1.18 2002/03/04 17:27:39 stevesk Exp $");
#include "deattack.h"
#include "log.h"
#include "crc32.h"
#include "getput.h"
#include "xmalloc.h"
#include "deattack.h"
/* SSH Constants */
#define SSH_MAXBLOCKS (32 * 1024)
@ -36,7 +37,7 @@
#define HASH_FACTOR(x) ((x)*3/2)
#define HASH_UNUSEDCHAR (0xff)
#define HASH_UNUSED (0xffff)
#define HASH_IV (0xfffe)
#define HASH_IV (0xfffe)
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
@ -46,8 +47,7 @@
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
void
static void
crc_update(u_int32_t *a, u_int32_t b)
{
b ^= *a;
@ -55,7 +55,7 @@ crc_update(u_int32_t *a, u_int32_t b)
}
/* detect if a block is used in a particular pattern */
int
static int
check_crc(u_char *S, u_char *buf, u_int32_t len,
u_char *IV)
{
@ -86,9 +86,9 @@ detect_attack(u_char *buf, u_int32_t len, u_char *IV)
{
static u_int16_t *h = (u_int16_t *) NULL;
static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
register u_int32_t i, j;
u_int32_t i, j;
u_int32_t l;
register u_char *c;
u_char *c;
u_char *d;
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
@ -135,7 +135,7 @@ detect_attack(u_char *buf, u_int32_t len, u_char *IV)
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
i = (i + 1) & (n - 1)) {
i = (i + 1) & (n - 1)) {
if (h[i] == HASH_IV) {
if (!CMP(c, IV)) {
if (check_crc(c, buf, len, IV))

View File

@ -1,4 +1,4 @@
/* $OpenBSD: deattack.h,v 1.5 2001/01/29 01:58:15 niklas Exp $ */
/* $OpenBSD: deattack.h,v 1.7 2001/06/26 17:27:23 markus Exp $ */
/*
* Cryptographic attack detector for ssh - Header file
@ -26,5 +26,5 @@
#define DEATTACK_OK 0
#define DEATTACK_DETECTED 1
int detect_attack(u_char *buf, u_int32_t len, u_char IV[8]);
int detect_attack(u_char *, u_int32_t, u_char[8]);
#endif

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: dh.c,v 1.14 2001/04/15 08:43:45 markus Exp $");
RCSID("$OpenBSD: dh.c,v 1.21 2002/03/06 00:23:27 markus Exp $");
#include "xmalloc.h"
@ -39,7 +39,7 @@ RCSID("$OpenBSD: dh.c,v 1.14 2001/04/15 08:43:45 markus Exp $");
#include "log.h"
#include "misc.h"
int
static int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
{
char *cp, *arg;
@ -78,8 +78,10 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
if (cp != NULL || *prime == '\0')
goto fail;
dhg->g = BN_new();
dhg->p = BN_new();
if ((dhg->g = BN_new()) == NULL)
fatal("parse_prime: BN_new failed");
if ((dhg->p = BN_new()) == NULL)
fatal("parse_prime: BN_new failed");
if (BN_hex2bn(&dhg->g, gen) == 0)
goto failclean;
@ -92,8 +94,8 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
return (1);
failclean:
BN_free(dhg->g);
BN_free(dhg->p);
BN_clear_free(dhg->g);
BN_clear_free(dhg->p);
fail:
error("Bad prime description in line %d", linenum);
return (0);
@ -103,14 +105,14 @@ DH *
choose_dh(int min, int wantbits, int max)
{
FILE *f;
char line[1024];
char line[2048];
int best, bestcount, which;
int linenum;
struct dhgroup dhg;
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
log("WARNING: %s does not exist, using old prime", _PATH_DH_PRIMES);
if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
(f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
log("WARNING: %s does not exist, using old modulus", _PATH_DH_MODULI);
return (dh_new_group1());
}
@ -120,8 +122,8 @@ choose_dh(int min, int wantbits, int max)
linenum++;
if (!parse_prime(linenum, line, &dhg))
continue;
BN_free(dhg.g);
BN_free(dhg.p);
BN_clear_free(dhg.g);
BN_clear_free(dhg.p);
if (dhg.size > max || dhg.size < min)
continue;
@ -134,18 +136,14 @@ choose_dh(int min, int wantbits, int max)
if (dhg.size == best)
bestcount++;
}
fclose (f);
rewind(f);
if (bestcount == 0) {
fclose(f);
log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
return (NULL);
}
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
fatal("WARNING: %s disappeared, giving up", _PATH_DH_PRIMES);
}
linenum = 0;
which = arc4random() % bestcount;
while (fgets(line, sizeof(line), f)) {
@ -154,8 +152,8 @@ choose_dh(int min, int wantbits, int max)
if ((dhg.size > max || dhg.size < min) ||
dhg.size != best ||
linenum++ != which) {
BN_free(dhg.g);
BN_free(dhg.p);
BN_clear_free(dhg.g);
BN_clear_free(dhg.p);
continue;
}
break;
@ -205,9 +203,8 @@ dh_gen_key(DH *dh, int need)
BN_num_bits(dh->p), 2*need);
do {
if (dh->priv_key != NULL)
BN_free(dh->priv_key);
dh->priv_key = BN_new();
if (dh->priv_key == NULL)
BN_clear_free(dh->priv_key);
if ((dh->priv_key = BN_new()) == NULL)
fatal("dh_gen_key: BN_new failed");
/* generate a 2*need bits random private exponent */
if (!BN_rand(dh->priv_key, 2*need, 0, 0))
@ -229,9 +226,8 @@ dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if ((dh = DH_new()) == NULL)
fatal("dh_new_group_asc: DH_new");
if (BN_hex2bn(&dh->p, modulus) == 0)
fatal("BN_hex2bn p");
@ -251,9 +247,8 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if ((dh = DH_new()) == NULL)
fatal("dh_new_group: DH_new");
dh->p = modulus;
dh->g = gen;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dh.h,v 1.5 2001/04/03 19:53:29 markus Exp $ */
/* $OpenBSD: dh.h,v 1.7 2001/06/26 17:27:23 markus Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
@ -32,15 +32,15 @@ struct dhgroup {
BIGNUM *p;
};
DH *choose_dh(int min, int nbits, int max);
DH *choose_dh(int, int, int);
DH *dh_new_group_asc(const char *, const char *);
DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1(void);
void dh_gen_key(DH *, int);
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
void dh_gen_key(DH *, int);
int dh_pub_is_valid(DH *, BIGNUM *);
int dh_estimate(int bits);
int dh_estimate(int);
#define DH_GRP_MIN 1024
#define DH_GRP_MAX 8192

View File

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: dispatch.c,v 1.10 2001/02/18 18:33:53 markus Exp $");
RCSID("$OpenBSD: dispatch.c,v 1.15 2002/01/11 13:39:36 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
@ -37,20 +37,40 @@ RCSID("$OpenBSD: dispatch.c,v 1.10 2001/02/18 18:33:53 markus Exp $");
dispatch_fn *dispatch[DISPATCH_MAX];
void
dispatch_protocol_error(int type, int plen, void *ctxt)
dispatch_protocol_error(int type, u_int32_t seq, void *ctxt)
{
error("Hm, dispatch protocol error: type %d plen %d", type, plen);
if (compat20 && type == SSH2_MSG_KEXINIT)
fatal("dispatch_protocol_error: rekeying is not supported");
log("dispatch_protocol_error: type %d seq %u", type, seq);
if (!compat20)
fatal("protocol error");
packet_start(SSH2_MSG_UNIMPLEMENTED);
packet_put_int(seq);
packet_send();
packet_write_wait();
}
void
dispatch_protocol_ignore(int type, u_int32_t seq, void *ctxt)
{
log("dispatch_protocol_ignore: type %d seq %u", type, seq);
}
void
dispatch_init(dispatch_fn *dflt)
{
int i;
u_int i;
for (i = 0; i < DISPATCH_MAX; i++)
dispatch[i] = dflt;
}
void
dispatch_range(u_int from, u_int to, dispatch_fn *fn)
{
u_int i;
for (i = from; i <= to; i++) {
if (i >= DISPATCH_MAX)
break;
dispatch[i] = fn;
}
}
void
dispatch_set(int type, dispatch_fn *fn)
{
dispatch[type] = fn;
@ -59,18 +79,18 @@ void
dispatch_run(int mode, int *done, void *ctxt)
{
for (;;) {
int plen;
int type;
u_int32_t seqnr;
if (mode == DISPATCH_BLOCK) {
type = packet_read(&plen);
type = packet_read_seqnr(&seqnr);
} else {
type = packet_read_poll(&plen);
type = packet_read_poll_seqnr(&seqnr);
if (type == SSH_MSG_NONE)
return;
}
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
(*dispatch[type])(type, plen, ctxt);
(*dispatch[type])(type, seqnr, ctxt);
else
packet_disconnect("protocol error: rcvd type %d", type);
if (done != NULL && *done)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dispatch.h,v 1.4 2001/01/29 01:58:15 niklas Exp $ */
/* $OpenBSD: dispatch.h,v 1.9 2002/01/11 13:39:36 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -28,9 +28,11 @@ enum {
DISPATCH_NONBLOCK
};
typedef void dispatch_fn(int type, int plen, void *ctxt);
typedef void dispatch_fn(int, u_int32_t, void *);
void dispatch_init(dispatch_fn *dflt);
void dispatch_set(int type, dispatch_fn *fn);
void dispatch_run(int mode, int *done, void *ctxt);
void dispatch_protocol_error(int type, int plen, void *ctxt);
void dispatch_init(dispatch_fn *);
void dispatch_set(int, dispatch_fn *);
void dispatch_range(u_int, u_int, dispatch_fn *);
void dispatch_run(int, int *, void *);
void dispatch_protocol_error(int, u_int32_t, void *);
void dispatch_protocol_ignore(int, u_int32_t, void *);

40
crypto/openssh/fatal.c Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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"
RCSID("$OpenBSD: fatal.c,v 1.1 2002/02/22 12:20:34 markus Exp $");
#include "log.h"
/* Fatal messages. This function never returns. */
void
fatal(const char *fmt,...)
{
va_list args;
va_start(args, fmt);
do_log(SYSLOG_LEVEL_FATAL, fmt, args);
va_end(args);
fatal_cleanup();
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: getput.h,v 1.8 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,8 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: getput.h,v 1.7 2001/01/10 22:56:22 markus Exp $"); */
#ifndef GETPUT_H
#define GETPUT_H

View File

@ -1,5 +1,3 @@
/* $OpenBSD: groupaccess.c,v 1.3 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
*
@ -25,6 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: groupaccess.c,v 1.5 2002/03/04 17:27:39 stevesk Exp $");
#include "groupaccess.h"
#include "xmalloc.h"
@ -34,6 +33,10 @@
static int ngroups;
static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */
/*
* Initialize group access list for user with primary (base) and
* supplementary groups. Return the number of groups in the list.
*/
int
ga_init(const char *user, gid_t base)
{
@ -53,6 +56,10 @@ ga_init(const char *user, gid_t base)
return (ngroups = j);
}
/*
* Return 1 if one of user's groups is contained in groups.
* Return 0 otherwise. Use match_pattern() for string comparison.
*/
int
ga_match(char * const *groups, int n)
{
@ -65,6 +72,9 @@ ga_match(char * const *groups, int n)
return 0;
}
/*
* Free memory allocated for group access list.
*/
void
ga_free(void)
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: groupaccess.h,v 1.2 2001/01/29 01:58:15 niklas Exp $ */
/* $OpenBSD: groupaccess.h,v 1.4 2001/06/26 17:27:23 markus Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
@ -29,21 +29,8 @@
#include <grp.h>
/*
* Initialize group access list for user with primary (base) and
* supplementary groups. Return the number of groups in the list.
*/
int ga_init(const char *user, gid_t base);
/*
* Return 1 if one of user's groups is contained in groups.
* Return 0 otherwise. Use match_pattern() for string comparison.
*/
int ga_match(char * const *groups, int ngroups);
/*
* Free memory allocated for group access list.
*/
void ga_free(void);
int ga_init(const char *, gid_t);
int ga_match(char * const *, int);
void ga_free(void);
#endif

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,7 +36,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $");
RCSID("$OpenBSD: hostfile.c,v 1.29 2001/12/18 10:04:21 jakob Exp $");
#include "packet.h"
#include "match.h"
@ -71,18 +71,7 @@ hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
return 1;
}
int
auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
{
Key *k = key_new(KEY_RSA1);
int ret = hostfile_read_key(cpp, bitsp, k);
BN_copy(e, k->rsa->e);
BN_copy(n, k->rsa->n);
key_free(k);
return ret;
}
int
static int
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
{
if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hostfile.h,v 1.7 2001/02/08 19:30:51 itojun Exp $ */
/* $OpenBSD: hostfile.h,v 1.10 2001/12/18 10:04:21 jakob Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -14,27 +14,13 @@
#ifndef HOSTFILE_H
#define HOSTFILE_H
int
auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Checks whether the given host is already in the list of our known hosts.
* Returns HOST_OK if the host is known and has the specified key, HOST_NEW
* if the host is not known, and HOST_CHANGED if the host is known but used
* to have a different host key. The host must be in all lowercase.
*/
typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED
} HostStatus;
int hostfile_read_key(char **, u_int *, Key *);
HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key,
Key *found, int *line);
/*
* Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
int add_host_to_hostfile(const char *filename, const char *host, Key *key);
check_host_in_hostfile(const char *, const char *, Key *, Key *, int *);
int add_host_to_hostfile(const char *, const char *, Key *);
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: includes.h,v 1.14 2001/01/29 01:58:16 niklas Exp $ */
/* $OpenBSD: includes.h,v 1.17 2002/01/26 16:44:22 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -57,9 +57,6 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
#include "version.h"
/* Define this to be the path of the xauth program. */
#define XAUTH_PATH "/usr/X11R6/bin/xauth"
/*
* Define this to use pipes instead of socketpairs for communicating with the
* client program. Socketpairs do not seem to work on all systems.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 markus Exp $");
RCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $");
#include <openssl/crypto.h>
@ -43,11 +43,12 @@ RCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 markus Exp $");
#define KEX_COOKIE_LEN 16
void kex_kexinit_finish(Kex *kex);
void kex_choose_conf(Kex *k);
/* prototype */
static void kex_kexinit_finish(Kex *);
static void kex_choose_conf(Kex *);
/* put algorithm proposal into buffer */
void
static void
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
{
u_int32_t rand = 0;
@ -67,7 +68,7 @@ kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
}
/* parse buffer and return algorithm proposal */
char **
static char **
kex_buf2prop(Buffer *raw)
{
Buffer b;
@ -95,7 +96,7 @@ kex_buf2prop(Buffer *raw)
return proposal;
}
void
static void
kex_prop_free(char **proposal)
{
int i;
@ -105,28 +106,24 @@ kex_prop_free(char **proposal)
xfree(proposal);
}
void
kex_protocol_error(int type, int plen, void *ctxt)
static void
kex_protocol_error(int type, u_int32_t seq, void *ctxt)
{
error("Hm, kex protocol error: type %d plen %d", type, plen);
error("Hm, kex protocol error: type %d seq %u", type, seq);
}
void
kex_clear_dispatch(void)
static void
kex_reset_dispatch(void)
{
int i;
/* Numbers 30-49 are used for kex packets */
for (i = 30; i <= 49; i++)
dispatch_set(i, &kex_protocol_error);
dispatch_range(SSH2_MSG_TRANSPORT_MIN,
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
kex_finish(Kex *kex)
{
int plen;
kex_clear_dispatch();
kex_reset_dispatch();
packet_start(SSH2_MSG_NEWKEYS);
packet_send();
@ -134,7 +131,8 @@ kex_finish(Kex *kex)
debug("SSH2_MSG_NEWKEYS sent");
debug("waiting for SSH2_MSG_NEWKEYS");
packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
packet_read_expect(SSH2_MSG_NEWKEYS);
packet_check_eom();
debug("SSH2_MSG_NEWKEYS received");
kex->done = 1;
@ -165,7 +163,7 @@ kex_send_kexinit(Kex *kex)
}
void
kex_input_kexinit(int type, int plen, void *ctxt)
kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
{
char *ptr;
int dlen;
@ -186,7 +184,7 @@ kex_input_kexinit(int type, int plen, void *ctxt)
xfree(packet_get_string(NULL));
packet_get_char();
packet_get_int();
packet_done();
packet_check_eom();
kex_kexinit_finish(kex);
}
@ -204,13 +202,12 @@ kex_setup(char *proposal[PROPOSAL_MAX])
kex->done = 0;
kex_send_kexinit(kex); /* we start */
kex_clear_dispatch();
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
kex_reset_dispatch();
return kex;
}
void
static void
kex_kexinit_finish(Kex *kex)
{
if (!(kex->flags & KEX_INIT_SENT))
@ -218,7 +215,7 @@ kex_kexinit_finish(Kex *kex)
kex_choose_conf(kex);
switch(kex->kex_type) {
switch (kex->kex_type) {
case DH_GRP1_SHA1:
kexdh(kex);
break;
@ -230,21 +227,22 @@ kex_kexinit_finish(Kex *kex)
}
}
void
static void
choose_enc(Enc *enc, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching cipher found: client %s server %s", client, server);
enc->cipher = cipher_by_name(name);
if (enc->cipher == NULL)
if ((enc->cipher = cipher_by_name(name)) == NULL)
fatal("matching cipher is not supported: %s", name);
enc->name = name;
enc->enabled = 0;
enc->iv = NULL;
enc->key = NULL;
enc->key_len = cipher_keylen(enc->cipher);
enc->block_size = cipher_blocksize(enc->cipher);
}
void
static void
choose_mac(Mac *mac, char *client, char *server)
{
char *name = match_list(client, server, NULL);
@ -259,7 +257,7 @@ choose_mac(Mac *mac, char *client, char *server)
mac->key = NULL;
mac->enabled = 0;
}
void
static void
choose_comp(Comp *comp, char *client, char *server)
{
char *name = match_list(client, server, NULL);
@ -274,7 +272,7 @@ choose_comp(Comp *comp, char *client, char *server)
}
comp->name = name;
}
void
static void
choose_kex(Kex *k, char *client, char *server)
{
k->name = match_list(client, server, NULL);
@ -287,7 +285,7 @@ choose_kex(Kex *k, char *client, char *server)
} else
fatal("bad kex alg %s", k->name);
}
void
static void
choose_hostkeyalg(Kex *k, char *client, char *server)
{
char *hostkeyalg = match_list(client, server, NULL);
@ -299,7 +297,7 @@ choose_hostkeyalg(Kex *k, char *client, char *server)
xfree(hostkeyalg);
}
void
static void
kex_choose_conf(Kex *kex)
{
Newkeys *newkeys;
@ -345,10 +343,10 @@ kex_choose_conf(Kex *kex)
need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode];
if (need < newkeys->enc.cipher->key_len)
need = newkeys->enc.cipher->key_len;
if (need < newkeys->enc.cipher->block_size)
need = newkeys->enc.cipher->block_size;
if (need < newkeys->enc.key_len)
need = newkeys->enc.key_len;
if (need < newkeys->enc.block_size)
need = newkeys->enc.block_size;
if (need < newkeys->mac.key_len)
need = newkeys->mac.key_len;
}
@ -359,15 +357,15 @@ kex_choose_conf(Kex *kex)
kex_prop_free(peer);
}
u_char *
static u_char *
derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
{
Buffer b;
EVP_MD *evp_md = EVP_sha1();
const EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
int mdsz = EVP_MD_size(evp_md);
u_char *digest = xmalloc(roundup(need, mdsz));
buffer_init(&b);
@ -375,7 +373,8 @@ derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
/* K1 = HASH(K || H || "A" || session_id) */
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
if (!(datafellows & SSH_BUG_DERIVEKEY))
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, &c, 1);
EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
@ -388,7 +387,8 @@ derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
*/
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
if (!(datafellows & SSH_BUG_DERIVEKEY))
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, digest, have);
EVP_DigestFinal(&md, digest + have, NULL);
@ -441,7 +441,7 @@ dump_digest(char *msg, u_char *digest, int len)
int i;
fprintf(stderr, "%s\n", msg);
for (i = 0; i< len; i++){
for (i = 0; i< len; i++) {
fprintf(stderr, "%02x", digest[i]);
if (i%32 == 31)
fprintf(stderr, "\n");

View File

@ -1,7 +1,7 @@
/* $OpenBSD: kex.h,v 1.22 2001/04/04 20:25:37 markus Exp $ */
/* $OpenBSD: kex.h,v 1.29 2002/02/14 23:41:01 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -71,6 +71,8 @@ struct Enc {
char *name;
Cipher *cipher;
int enabled;
u_int key_len;
u_int block_size;
u_char *key;
u_char *iv;
};
@ -107,24 +109,24 @@ struct Kex {
int flags;
char *client_version_string;
char *server_version_string;
int (*check_host_key)(Key *hostkey);
Key *(*load_host_key)(int type);
int (*verify_host_key)(Key *);
Key *(*load_host_key)(int);
};
Kex *kex_setup(char *proposal[PROPOSAL_MAX]);
void kex_finish(Kex *kex);
Kex *kex_setup(char *[PROPOSAL_MAX]);
void kex_finish(Kex *);
void kex_send_kexinit(Kex *kex);
void kex_input_kexinit(int type, int plen, void *ctxt);
void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret);
void kex_send_kexinit(Kex *);
void kex_input_kexinit(int, u_int32_t, void *);
void kex_derive_keys(Kex *, u_char *, BIGNUM *);
void kexdh(Kex *);
void kexgex(Kex *);
void kexdh(Kex *);
void kexgex(Kex *);
Newkeys *kex_get_newkeys(int mode);
Newkeys *kex_get_newkeys(int);
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
void dump_digest(char *msg, u_char *digest, int len);
void dump_digest(char *, u_char *, int);
#endif
#endif

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $");
RCSID("$OpenBSD: kexdh.c,v 1.17 2002/02/28 15:46:33 markus Exp $");
#include <openssl/crypto.h>
#include <openssl/bn.h>
@ -38,25 +38,25 @@ RCSID("$OpenBSD: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $");
#include "dh.h"
#include "ssh2.h"
u_char *
static u_char *
kex_dh_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
u_char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
{
Buffer b;
static u_char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
const EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
@ -81,23 +81,22 @@ kex_dh_hash(
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, evp_md->md_size);
dump_digest("hash", digest, EVP_MD_size(evp_md));
#endif
return digest;
}
/* client */
void
static void
kexdh_client(Kex *kex)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
DH *dh;
Key *server_host_key;
char *server_host_key_blob = NULL, *signature = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, kout, slen, sbloblen;
int dlen, plen;
/* generate and send 'e', client DH public key */
dh = dh_new_group1();
@ -115,23 +114,24 @@ kexdh_client(Kex *kex)
#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
packet_read_expect(SSH2_MSG_KEXDH_REPLY);
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (kex->check_host_key == NULL)
fatal("cannot check server_host_key");
kex->check_host_key(server_host_key);
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
if ((dh_server_pub = BN_new()) == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
packet_get_bignum2(dh_server_pub);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
@ -142,7 +142,7 @@ kexdh_client(Kex *kex)
/* signed H */
signature = packet_get_string(&slen);
packet_done();
packet_check_eom();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
@ -153,7 +153,8 @@ kexdh_client(Kex *kex)
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
if ((shared_secret = BN_new()) == NULL)
fatal("kexdh_client: BN_new failed");
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
@ -170,10 +171,10 @@ kexdh_client(Kex *kex)
shared_secret
);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
BN_clear_free(dh_server_pub);
DH_free(dh);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
@ -192,7 +193,7 @@ kexdh_client(Kex *kex)
/* server */
void
static void
kexdh_server(Kex *kex)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
@ -200,14 +201,14 @@ kexdh_server(Kex *kex)
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, kout;
int dlen, slen, plen;
u_int slen;
/* generate server DH public key */
dh = dh_new_group1();
dh_gen_key(dh, kex->we_need * 8);
debug("expecting SSH2_MSG_KEXDH_INIT");
packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT);
packet_read_expect(SSH2_MSG_KEXDH_INIT);
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
@ -216,10 +217,10 @@ kexdh_server(Kex *kex)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
if ((dh_client_pub = BN_new()) == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
packet_get_bignum2(dh_client_pub);
packet_check_eom();
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
@ -243,7 +244,8 @@ kexdh_server(Kex *kex)
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
if ((shared_secret = BN_new()) == NULL)
fatal("kexdh_server: BN_new failed");
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
@ -256,12 +258,12 @@ kexdh_server(Kex *kex)
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
(char *)server_host_key_blob, sbloblen,
server_host_key_blob, sbloblen,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
BN_clear_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
@ -279,9 +281,9 @@ kexdh_server(Kex *kex)
/* send server hostkey, DH pubkey 'f' and singed H */
packet_start(SSH2_MSG_KEXDH_REPLY);
packet_put_string((char *)server_host_key_blob, sbloblen);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_put_string(signature, slen);
packet_send();
xfree(signature);

View File

@ -24,7 +24,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $");
RCSID("$OpenBSD: kexgex.c,v 1.20 2002/02/28 15:46:33 markus Exp $");
#include <openssl/bn.h>
@ -39,13 +39,13 @@ RCSID("$OpenBSD: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $");
#include "ssh2.h"
#include "compat.h"
u_char *
static u_char *
kexgex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
u_char *serverhostkeyblob, int sbloblen,
int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
@ -53,12 +53,12 @@ kexgex_hash(
{
Buffer b;
static u_char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
const EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
@ -92,14 +92,14 @@ kexgex_hash(
buffer_free(&b);
#ifdef DEBUG_KEXDH
dump_digest("hash", digest, evp_md->md_size);
dump_digest("hash", digest, EVP_MD_size(evp_md));
#endif
return digest;
}
/* client */
void
static void
kexgex_client(Kex *kex)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
@ -107,7 +107,7 @@ kexgex_client(Kex *kex)
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int klen, kout, slen, sbloblen;
int dlen, plen, min, max, nbits;
int min, max, nbits;
DH *dh;
nbits = dh_estimate(kex->we_need * 8);
@ -138,15 +138,15 @@ kexgex_client(Kex *kex)
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
if ((p = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(p, &dlen);
packet_get_bignum2(p);
if ((g = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(g, &dlen);
packet_done();
packet_get_bignum2(g);
packet_check_eom();
if (BN_num_bits(p) < min || BN_num_bits(p) > max)
fatal("DH_GEX group out of range: %d !< %d !< %d",
@ -169,23 +169,24 @@ kexgex_client(Kex *kex)
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (kex->check_host_key == NULL)
fatal("cannot check server_host_key");
kex->check_host_key(server_host_key);
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
if ((dh_server_pub = BN_new()) == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
packet_get_bignum2(dh_server_pub);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
@ -196,7 +197,7 @@ kexgex_client(Kex *kex)
/* signed H */
signature = packet_get_string(&slen);
packet_done();
packet_check_eom();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
@ -207,7 +208,8 @@ kexgex_client(Kex *kex)
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
if ((shared_secret = BN_new()) == NULL)
fatal("kexgex_client: BN_new failed");
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
@ -231,9 +233,9 @@ kexgex_client(Kex *kex)
/* have keys, free DH */
DH_free(dh);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
BN_clear_free(dh_server_pub);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
@ -252,15 +254,15 @@ kexgex_client(Kex *kex)
/* server */
void
static void
kexgex_server(Kex *kex)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
Key *server_host_key;
DH *dh = dh;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, kout;
int min = -1, max = -1, nbits = -1, type, plen, dlen, slen;
u_int sbloblen, klen, kout, slen;
int min = -1, max = -1, nbits = -1, type;
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
@ -268,8 +270,8 @@ kexgex_server(Kex *kex)
if (server_host_key == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
type = packet_read(&plen);
switch(type){
type = packet_read();
switch (type) {
case SSH2_MSG_KEX_DH_GEX_REQUEST:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
min = packet_get_int();
@ -288,7 +290,7 @@ kexgex_server(Kex *kex)
default:
fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
}
packet_done();
packet_check_eom();
if (max < min || nbits < min || max < nbits)
fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
@ -311,13 +313,13 @@ kexgex_server(Kex *kex)
dh_gen_key(dh, kex->we_need * 8);
debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT);
packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
if ((dh_client_pub = BN_new()) == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
packet_get_bignum2(dh_client_pub);
packet_check_eom();
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
@ -341,7 +343,8 @@ kexgex_server(Kex *kex)
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
if ((shared_secret = BN_new()) == NULL)
fatal("kexgex_server: BN_new failed");
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
@ -357,14 +360,14 @@ kexgex_server(Kex *kex)
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
(char *)server_host_key_blob, sbloblen,
server_host_key_blob, sbloblen,
min, nbits, max,
dh->p, dh->g,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
BN_clear_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
@ -383,9 +386,9 @@ kexgex_server(Kex *kex)
/* send server hostkey, DH pubkey 'f' and singed H */
debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
packet_put_string((char *)server_host_key_blob, sbloblen);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_put_string(signature, slen);
packet_send();
xfree(signature);
xfree(server_host_key_blob);

View File

@ -9,7 +9,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,7 +32,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
RCSID("$OpenBSD: key.c,v 1.41 2002/02/28 15:46:33 markus Exp $");
#include <openssl/evp.h>
@ -54,22 +54,31 @@ key_new(int type)
DSA *dsa;
k = xmalloc(sizeof(*k));
k->type = type;
k->flags = 0;
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
rsa = RSA_new();
rsa->n = BN_new();
rsa->e = BN_new();
if ((rsa = RSA_new()) == NULL)
fatal("key_new: RSA_new failed");
if ((rsa->n = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((rsa->e = BN_new()) == NULL)
fatal("key_new: BN_new failed");
k->rsa = rsa;
break;
case KEY_DSA:
dsa = DSA_new();
dsa->p = BN_new();
dsa->q = BN_new();
dsa->g = BN_new();
dsa->pub_key = BN_new();
if ((dsa = DSA_new()) == NULL)
fatal("key_new: DSA_new failed");
if ((dsa->p = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->q = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->g = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->pub_key = BN_new()) == NULL)
fatal("key_new: BN_new failed");
k->dsa = dsa;
break;
case KEY_UNSPEC:
@ -87,15 +96,22 @@ key_new_private(int type)
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
k->rsa->d = BN_new();
k->rsa->iqmp = BN_new();
k->rsa->q = BN_new();
k->rsa->p = BN_new();
k->rsa->dmq1 = BN_new();
k->rsa->dmp1 = BN_new();
if ((k->rsa->d = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->iqmp = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->q = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->p = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->dmq1 = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->dmp1 = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
break;
case KEY_DSA:
k->dsa->priv_key = BN_new();
if ((k->dsa->priv_key = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
break;
case KEY_UNSPEC:
break;
@ -153,14 +169,14 @@ key_equal(Key *a, Key *b)
return 0;
}
u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
static u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
{
EVP_MD *md = NULL;
const EVP_MD *md = NULL;
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
int len = 0;
u_int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
@ -200,8 +216,7 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
retval = xmalloc(EVP_MAX_MD_SIZE);
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, blob, len);
EVP_DigestFinal(&ctx, retval, NULL);
*dgst_raw_length = md->md_size;
EVP_DigestFinal(&ctx, retval, dgst_raw_length);
memset(blob, 0, len);
xfree(blob);
} else {
@ -210,15 +225,15 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
return retval;
}
char*
key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
static char*
key_fingerprint_hex(u_char* dgst_raw, u_int dgst_raw_len)
{
char *retval;
int i;
retval = xmalloc(dgst_raw_len * 3 + 1);
retval[0] = '\0';
for(i = 0; i < dgst_raw_len; i++) {
for (i = 0; i < dgst_raw_len; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
strlcat(retval, hex, dgst_raw_len * 3);
@ -227,8 +242,8 @@ key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
return retval;
}
char*
key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
static char*
key_fingerprint_bubblebabble(u_char* dgst_raw, u_int dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
@ -279,12 +294,12 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
{
char *retval = NULL;
u_char *dgst_raw;
size_t dgst_raw_len;
u_int dgst_raw_len;
dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
if (!dgst_raw)
fatal("key_fingerprint: null from key_fingerprint_raw()");
switch(dgst_rep) {
switch (dgst_rep) {
case SSH_FP_HEX:
retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
break;
@ -308,7 +323,7 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
* last processed (and maybe modified) character. Note that this may modify
* the buffer containing the number.
*/
int
static int
read_bignum(char **cpp, BIGNUM * value)
{
char *cp = *cpp;
@ -344,7 +359,7 @@ read_bignum(char **cpp, BIGNUM * value)
*cpp = cp;
return 1;
}
int
static int
write_bignum(FILE *f, BIGNUM *num)
{
char *buf = BN_bn2dec(num);
@ -353,11 +368,11 @@ write_bignum(FILE *f, BIGNUM *num)
return 0;
}
fprintf(f, " %s", buf);
xfree(buf);
OPENSSL_free(buf);
return 1;
}
/* returns 1 ok, -1 error, 0 type mismatch */
/* returns 1 ok, -1 error */
int
key_read(Key *ret, char **cpp)
{
@ -370,7 +385,7 @@ key_read(Key *ret, char **cpp)
cp = *cpp;
switch(ret->type) {
switch (ret->type) {
case KEY_RSA1:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
@ -412,21 +427,22 @@ key_read(Key *ret, char **cpp)
} else if (ret->type != type) {
/* is a key, but different type */
debug3("key_read: type mismatch");
return 0;
return -1;
}
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("key_read: uudecode %s failed", cp);
xfree(blob);
return -1;
}
k = key_from_blob(blob, n);
xfree(blob);
if (k == NULL) {
error("key_read: key_from_blob %s failed", cp);
return -1;
}
xfree(blob);
if (k->type != type) {
error("key_read: type mismatch: encoding error");
key_free(k);
@ -453,9 +469,9 @@ key_read(Key *ret, char **cpp)
#endif
}
/*XXXX*/
key_free(k);
if (success != 1)
break;
key_free(k);
/* advance cp: skip whitespace and data */
while (*cp == ' ' || *cp == '\t')
cp++;
@ -472,8 +488,9 @@ key_read(Key *ret, char **cpp)
int
key_write(Key *key, FILE *f)
{
int success = 0;
u_int bits = 0;
int n, success = 0;
u_int len, bits = 0;
u_char *blob, *uu;
if (key->type == KEY_RSA1 && key->rsa != NULL) {
/* size of modulus 'n' */
@ -487,8 +504,6 @@ key_write(Key *key, FILE *f)
}
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
int len, n;
u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
@ -531,7 +546,8 @@ key_ssh_name(Key *k)
return "ssh-unknown";
}
u_int
key_size(Key *k){
key_size(Key *k)
{
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@ -544,7 +560,7 @@ key_size(Key *k){
return 0;
}
RSA *
static RSA *
rsa_generate_private_key(u_int bits)
{
RSA *private;
@ -554,7 +570,7 @@ rsa_generate_private_key(u_int bits)
return private;
}
DSA*
static DSA*
dsa_generate_private_key(u_int bits)
{
DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
@ -614,15 +630,15 @@ key_from_private(Key *k)
int
key_type_from_name(char *name)
{
if (strcmp(name, "rsa1") == 0){
if (strcmp(name, "rsa1") == 0) {
return KEY_RSA1;
} else if (strcmp(name, "rsa") == 0){
} else if (strcmp(name, "rsa") == 0) {
return KEY_RSA;
} else if (strcmp(name, "dsa") == 0){
} else if (strcmp(name, "dsa") == 0) {
return KEY_DSA;
} else if (strcmp(name, "ssh-rsa") == 0){
} else if (strcmp(name, "ssh-rsa") == 0) {
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
} else if (strcmp(name, "ssh-dss") == 0) {
return KEY_DSA;
}
debug2("key_type_from_name: unknown key type '%s'", name);
@ -638,7 +654,7 @@ key_names_valid2(const char *names)
return 0;
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
(p = strsep(&cp, ","))) {
switch (key_type_from_name(p)) {
case KEY_RSA1:
case KEY_UNSPEC:
@ -652,7 +668,7 @@ key_names_valid2(const char *names)
}
Key *
key_from_blob(char *blob, int blen)
key_from_blob(u_char *blob, int blen)
{
Buffer b;
char *ktype;
@ -667,7 +683,7 @@ key_from_blob(char *blob, int blen)
ktype = buffer_get_string(&b, NULL);
type = key_type_from_name(ktype);
switch(type){
switch (type) {
case KEY_RSA:
key = key_new(type);
buffer_get_bignum2(&b, key->rsa->e);
@ -713,7 +729,7 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
return 0;
}
buffer_init(&b);
switch(key->type){
switch (key->type) {
case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p);
@ -727,8 +743,9 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
buffer_put_bignum2(&b, key->rsa->n);
break;
default:
error("key_to_blob: illegal key type %d", key->type);
break;
error("key_to_blob: unsupported key type %d", key->type);
buffer_free(&b);
return 0;
}
len = buffer_len(&b);
buf = xmalloc(len);
@ -745,10 +762,10 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
switch(key->type){
switch (key->type) {
case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen);
break;
@ -765,10 +782,13 @@ key_sign(
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
u_char *signature, u_int signaturelen,
u_char *data, u_int datalen)
{
switch(key->type){
if (signaturelen == 0)
return -1;
switch (key->type) {
case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen);
break;

View File

@ -1,7 +1,7 @@
/* $OpenBSD: key.h,v 1.12 2001/04/17 10:53:24 markus Exp $ */
/* $OpenBSD: key.h,v 1.18 2002/02/24 19:14:59 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -44,41 +44,37 @@ enum fp_rep {
SSH_FP_HEX,
SSH_FP_BUBBLEBABBLE
};
/* key is stored in external hardware */
#define KEY_FLAG_EXT 0x0001
struct Key {
int type;
int type;
int flags;
RSA *rsa;
DSA *dsa;
};
Key *key_new(int type);
Key *key_new_private(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
char *key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
int key_read(Key *key, char **cpp);
u_int key_size(Key *k);
Key *key_new(int);
Key *key_new_private(int);
void key_free(Key *);
int key_equal(Key *, Key *);
char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
char *key_type(Key *);
int key_write(Key *, FILE *);
int key_read(Key *, char **);
u_int key_size(Key *);
Key *key_generate(int type, u_int bits);
Key *key_from_private(Key *k);
int key_type_from_name(char *name);
Key *key_generate(int, u_int);
Key *key_from_private(Key *);
int key_type_from_name(char *);
Key *key_from_blob(char *blob, int blen);
int key_to_blob(Key *key, u_char **blobp, u_int *lenp);
char *key_ssh_name(Key *k);
int key_names_valid2(const char *names);
Key *key_from_blob(u_char *, int);
int key_to_blob(Key *, u_char **, u_int *);
char *key_ssh_name(Key *);
int key_names_valid2(const char *);
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen);
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen);
int key_sign(Key *, u_char **, u_int *, u_char *, u_int);
int key_verify(Key *, u_char *, u_int, u_char *, u_int);
#endif

View File

@ -1,15 +1,17 @@
# $OpenBSD: Makefile,v 1.22 2001/04/03 19:53:30 markus Exp $
# $OpenBSD: Makefile,v 1.31 2002/02/22 12:20:34 markus Exp $
.PATH: ${.CURDIR}/..
LIB= ssh
SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
cipher.c compat.c compress.c crc32.c deattack.c \
cipher.c compat.c compress.c crc32.c deattack.c fatal.c \
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
key.c dispatch.c kex.c mac.c uuencode.c misc.c \
cli.c rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c
rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \
scard.c
DEBUGLIBS= no
NOPROFILE= yes
NOPIC= yes
@ -26,4 +28,8 @@ SRCS+= radix.c
.endif # AFS
.endif # KERBEROS
.if (${KERBEROS5:L} == "yes")
CFLAGS+= -DKRB5 -I${DESTDIR}/usr/include/kerberosV
.endif # KERBEROS5
.include <bsd.lib.mk>

View File

@ -34,7 +34,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: log.c,v 1.17 2001/03/04 17:42:28 millert Exp $");
RCSID("$OpenBSD: log.c,v 1.22 2002/02/22 12:20:34 markus Exp $");
#include "log.h"
#include "xmalloc.h"
@ -65,7 +65,7 @@ static struct {
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, 0 }
{ NULL, SYSLOG_FACILITY_NOT_SET }
};
static struct {
@ -82,7 +82,7 @@ static struct {
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, 0 }
{ NULL, SYSLOG_LEVEL_NOT_SET }
};
SyslogFacility
@ -93,7 +93,7 @@ log_facility_number(char *name)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return (SyslogFacility) - 1;
return SYSLOG_FACILITY_NOT_SET;
}
LogLevel
@ -104,18 +104,7 @@ log_level_number(char *name)
for (i = 0; log_levels[i].name; i++)
if (strcasecmp(log_levels[i].name, name) == 0)
return log_levels[i].val;
return (LogLevel) - 1;
}
/* Fatal messages. This function never returns. */
void
fatal(const char *fmt,...)
{
va_list args;
va_start(args, fmt);
do_log(SYSLOG_LEVEL_FATAL, fmt, args);
va_end(args);
fatal_cleanup();
return SYSLOG_LEVEL_NOT_SET;
}
/* Error messages that should be logged. */
@ -237,7 +226,7 @@ fatal_cleanup(void)
for (cu = fatal_cleanups; cu; cu = next_cu) {
next_cu = cu->next;
debug("Calling cleanup 0x%lx(0x%lx)",
(u_long) cu->proc, (u_long) cu->context);
(u_long) cu->proc, (u_long) cu->context);
(*cu->proc) (cu->context);
}
exit(255);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: log.h,v 1.2 2001/01/29 01:58:16 niklas Exp $ */
/* $OpenBSD: log.h,v 1.6 2002/02/22 12:20:34 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -27,7 +27,8 @@ typedef enum {
SYSLOG_FACILITY_LOCAL4,
SYSLOG_FACILITY_LOCAL5,
SYSLOG_FACILITY_LOCAL6,
SYSLOG_FACILITY_LOCAL7
SYSLOG_FACILITY_LOCAL7,
SYSLOG_FACILITY_NOT_SET = -1,
} SyslogFacility;
typedef enum {
@ -38,38 +39,27 @@ typedef enum {
SYSLOG_LEVEL_VERBOSE,
SYSLOG_LEVEL_DEBUG1,
SYSLOG_LEVEL_DEBUG2,
SYSLOG_LEVEL_DEBUG3
SYSLOG_LEVEL_DEBUG3,
SYSLOG_LEVEL_NOT_SET = -1,
} LogLevel;
/* Initializes logging. */
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
/* Logging implementation, depending on server or client */
void do_log(LogLevel level, const char *fmt, va_list args);
void log_init(char *, LogLevel, SyslogFacility, int);
/* name to facility/level */
SyslogFacility log_facility_number(char *name);
LogLevel log_level_number(char *name);
SyslogFacility log_facility_number(char *);
LogLevel log_level_number(char *);
/* Output a message to syslog or stderr */
void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void fatal(const char *, ...) __attribute__((format(printf, 1, 2)));
void error(const char *, ...) __attribute__((format(printf, 1, 2)));
void log(const char *, ...) __attribute__((format(printf, 1, 2)));
void verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
void debug(const char *, ...) __attribute__((format(printf, 1, 2)));
void debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
void debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
/* same as fatal() but w/o logging */
void fatal_cleanup(void);
void fatal_cleanup(void);
void fatal_add_cleanup(void (*) (void *), void *);
void fatal_remove_cleanup(void (*) (void *), void *);
/*
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
* before exiting. It is permissible to call fatal_remove_cleanup for the
* function itself from the function.
*/
void fatal_add_cleanup(void (*proc) (void *context), void *context);
/* Removes a cleanup function to be called at fatal(). */
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
void do_log(LogLevel, const char *, va_list);
#endif

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $");
RCSID("$OpenBSD: mac.c,v 1.4 2002/01/25 22:07:40 markus Exp $");
#include <openssl/hmac.h>
@ -56,7 +56,7 @@ mac_init(Mac *mac, char *name)
if (strcmp(name, macs[i].name) == 0) {
if (mac != NULL) {
mac->md = (*macs[i].mdfunc)();
mac->key_len = mac->mac_len = mac->md->md_size;
mac->key_len = mac->mac_len = EVP_MD_size(mac->md);
if (macs[i].truncatebits != 0)
mac->mac_len = macs[i].truncatebits/8;
}
@ -99,7 +99,7 @@ mac_valid(const char *names)
return (0);
maclist = cp = xstrdup(names);
for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
(p = strsep(&cp, MAC_SEP))) {
(p = strsep(&cp, MAC_SEP))) {
if (mac_init(NULL, p) < 0) {
debug("bad mac %s [%s]", p, names);
xfree(maclist);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: mac.h,v 1.1 2001/02/11 12:59:24 markus Exp $ */
/* $OpenBSD: mac.h,v 1.3 2001/06/26 17:27:24 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -23,6 +23,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int mac_valid(const char *names);
int mac_init(Mac *mac, char *name);
u_char *mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen);
int mac_valid(const char *);
int mac_init(Mac *, char *);
u_char *mac_compute(Mac *, u_int32_t, u_char *, int);

View File

@ -35,7 +35,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: match.c,v 1.12 2001/03/10 17:51:04 markus Exp $");
RCSID("$OpenBSD: match.c,v 1.19 2002/03/01 13:12:10 markus Exp $");
#include "match.h"
#include "xmalloc.h"
@ -104,14 +104,15 @@ match_pattern(const char *s, const char *pattern)
}
/*
* Tries to match the host name (which must be in all lowercase) against the
* Tries to match the string against the
* comma-separated sequence of subpatterns (each possibly preceded by ! to
* indicate negation). Returns -1 if negation matches, 1 if there is
* a positive match, 0 if there is no match at all.
*/
int
match_hostname(const char *host, const char *pattern, u_int len)
match_pattern_list(const char *string, const char *pattern, u_int len,
int dolower)
{
char sub[1024];
int negated;
@ -132,9 +133,10 @@ match_hostname(const char *host, const char *pattern, u_int len)
* subpattern to lowercase.
*/
for (subi = 0;
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
subi++, i++)
sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
subi++, i++)
sub[subi] = dolower && isupper(pattern[i]) ?
tolower(pattern[i]) : pattern[i];
/* If subpattern too long, return failure (no match). */
if (subi >= sizeof(sub) - 1)
return 0;
@ -146,8 +148,8 @@ match_hostname(const char *host, const char *pattern, u_int len)
/* Null-terminate the subpattern. */
sub[subi] = '\0';
/* Try to match the subpattern against the host name. */
if (match_pattern(host, sub)) {
/* Try to match the subpattern against the string. */
if (match_pattern(string, sub)) {
if (negated)
return -1; /* Negative */
else
@ -162,8 +164,69 @@ match_hostname(const char *host, const char *pattern, u_int len)
return got_positive;
}
/*
* Tries to match the host name (which must be in all lowercase) against the
* comma-separated sequence of subpatterns (each possibly preceded by ! to
* indicate negation). Returns -1 if negation matches, 1 if there is
* a positive match, 0 if there is no match at all.
*/
int
match_hostname(const char *host, const char *pattern, u_int len)
{
return match_pattern_list(host, pattern, len, 1);
}
#define MAX_PROP 20
/*
* returns 0 if we get a negative match for the hostname or the ip
* or if we get no match at all. returns 1 otherwise.
*/
int
match_host_and_ip(const char *host, const char *ipaddr,
const char *patterns)
{
int mhost, mip;
/* negative ipaddr match */
if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1)
return 0;
/* negative hostname match */
if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1)
return 0;
/* no match at all */
if (mhost == 0 && mip == 0)
return 0;
return 1;
}
/*
* match user, user@host_or_ip, user@host_or_ip_list against pattern
*/
int
match_user(const char *user, const char *host, const char *ipaddr,
const char *pattern)
{
char *p, *pat;
int ret;
if ((p = strchr(pattern,'@')) == NULL)
return match_pattern(user, pattern);
pat = xstrdup(pattern);
p = strchr(pat, '@');
*p++ = '\0';
if ((ret = match_pattern(user, pat)) == 1)
ret = match_host_and_ip(host, ipaddr, p);
xfree(pat);
return ret;
}
/*
* Returns first item from client-list that is also supported by server-list,
* caller must xfree() returned string.
*/
#define MAX_PROP 40
#define SEP ","
char *
match_list(const char *client, const char *server, u_int *next)
@ -176,7 +239,7 @@ match_list(const char *client, const char *server, u_int *next)
s = sp = xstrdup(server);
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
(p = strsep(&sp, SEP)), i++) {
(p = strsep(&sp, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
@ -185,7 +248,7 @@ match_list(const char *client, const char *server, u_int *next)
nproposals = i;
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
(p = strsep(&cp, SEP)), i++) {
(p = strsep(&cp, SEP)), i++) {
for (j = 0; j < nproposals; j++) {
if (strcmp(p, sproposals[j]) == 0) {
ret = xstrdup(p);

View File

@ -1,11 +1,9 @@
/* $OpenBSD: match.h,v 1.7 2001/03/10 17:51:04 markus Exp $ */
/* $OpenBSD: match.h,v 1.12 2002/03/01 13:12:10 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* This file contains various auxiliary functions related to multiple
* precision integers.
*
* 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
@ -16,24 +14,11 @@
#ifndef MATCH_H
#define MATCH_H
/*
* Returns true if the given string matches the pattern (which may contain ?
* and * as wildcards), and zero if it does not match.
*/
int match_pattern(const char *s, const char *pattern);
/*
* Tries to match the host name (which must be in all lowercase) against the
* comma-separated sequence of subpatterns (each possibly preceded by ! to
* indicate negation). Returns -1 if negation matches, 1 if there is
* a positive match, 0 if there is no match at all.
*/
int match_hostname(const char *host, const char *pattern, u_int len);
/*
* Returns first item from client-list that is also supported by server-list,
* caller must xfree() returned string.
*/
char *match_list(const char *client, const char *server, u_int *next);
int match_pattern(const char *, const char *);
int match_pattern_list(const char *, const char *, u_int, int);
int match_hostname(const char *, const char *, u_int);
int match_host_and_ip(const char *, const char *, const char *);
int match_user(const char *, const char *, const char *, const char *);
char *match_list(const char *, const char *, u_int *);
#endif

View File

@ -1,5 +1,3 @@
/* $OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -25,18 +23,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $");
RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $");
#include "misc.h"
#include "log.h"
#include "xmalloc.h"
/* remove newline at end of string */
char *
chop(char *s)
{
char *t = s;
while (*t) {
if(*t == '\n' || *t == '\r') {
if (*t == '\n' || *t == '\r') {
*t = '\0';
return s;
}
@ -46,30 +45,75 @@ chop(char *s)
}
/* set/unset filedescriptor to non-blocking */
void
set_nonblock(int fd)
{
int val;
val = fcntl(fd, F_GETFL, 0);
if (val < 0) {
error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
return;
}
if (val & O_NONBLOCK) {
debug("fd %d IS O_NONBLOCK", fd);
debug2("fd %d is O_NONBLOCK", fd);
return;
}
debug("fd %d setting O_NONBLOCK", fd);
val |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, val) == -1)
if (errno != ENODEV)
error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
fd, strerror(errno));
debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
fd, strerror(errno));
}
void
unset_nonblock(int fd)
{
int val;
val = fcntl(fd, F_GETFL, 0);
if (val < 0) {
error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
return;
}
if (!(val & O_NONBLOCK)) {
debug2("fd %d is not O_NONBLOCK", fd);
return;
}
debug("fd %d clearing O_NONBLOCK", fd);
val &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, val) == -1)
debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
fd, strerror(errno));
}
/* disable nagle on socket */
void
set_nodelay(int fd)
{
int opt;
socklen_t optlen;
optlen = sizeof opt;
if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
error("getsockopt TCP_NODELAY: %.100s", strerror(errno));
return;
}
if (opt == 1) {
debug2("fd %d is TCP_NODELAY", fd);
return;
}
opt = 1;
debug("fd %d setting TCP_NODELAY", fd);
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
/* return next token in configuration line */
char *
strdelim(char **s)
{
@ -108,13 +152,21 @@ pwcopy(struct passwd *pw)
copy->pw_gecos = xstrdup(pw->pw_gecos);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
copy->pw_expire = pw->pw_expire;
copy->pw_change = pw->pw_change;
copy->pw_class = xstrdup(pw->pw_class);
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
return copy;
}
int a2port(const char *s)
/*
* Convert ASCII string to TCP/IP port number.
* Port must be >0 and <=65535.
* Return 0 if invalid.
*/
int
a2port(const char *s)
{
long port;
char *endp;
@ -128,3 +180,140 @@ int a2port(const char *s)
return port;
}
#define SECONDS 1
#define MINUTES (SECONDS * 60)
#define HOURS (MINUTES * 60)
#define DAYS (HOURS * 24)
#define WEEKS (DAYS * 7)
/*
* Convert a time string into seconds; format is
* a sequence of:
* time[qualifier]
*
* Valid time qualifiers are:
* <none> seconds
* s|S seconds
* m|M minutes
* h|H hours
* d|D days
* w|W weeks
*
* Examples:
* 90m 90 minutes
* 1h30m 90 minutes
* 2d 2 days
* 1w 1 week
*
* Return -1 if time string is invalid.
*/
long
convtime(const char *s)
{
long total, secs;
const char *p;
char *endp;
errno = 0;
total = 0;
p = s;
if (p == NULL || *p == '\0')
return -1;
while (*p) {
secs = strtol(p, &endp, 10);
if (p == endp ||
(errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
secs < 0)
return -1;
switch (*endp++) {
case '\0':
endp--;
case 's':
case 'S':
break;
case 'm':
case 'M':
secs *= MINUTES;
break;
case 'h':
case 'H':
secs *= HOURS;
break;
case 'd':
case 'D':
secs *= DAYS;
break;
case 'w':
case 'W':
secs *= WEEKS;
break;
default:
return -1;
}
total += secs;
if (total < 0)
return -1;
p = endp;
}
return total;
}
char *
cleanhostname(char *host)
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
char *
colon(char *cp)
{
int flag = 0;
if (*cp == ':') /* Leading colon is part of file name. */
return (0);
if (*cp == '[')
flag = 1;
for (; *cp; ++cp) {
if (*cp == '@' && *(cp+1) == '[')
flag = 1;
if (*cp == ']' && *(cp+1) == ':' && flag)
return (cp+1);
if (*cp == ':' && !flag)
return (cp);
if (*cp == '/')
return (0);
}
return (0);
}
/* function to assist building execv() arguments */
void
addargs(arglist *args, char *fmt, ...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (args->list == NULL) {
args->nalloc = 32;
args->num = 0;
} else if (args->num+2 >= args->nalloc)
args->nalloc *= 2;
args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
args->list[args->num++] = xstrdup(buf);
args->list[args->num] = NULL;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $ */
/* $OpenBSD: misc.h,v 1.11 2002/01/24 21:09:25 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -11,20 +11,23 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/* remove newline at end of string */
char *chop(char *s);
/* return next token in configuration line */
char *strdelim(char **s);
char *chop(char *);
char *strdelim(char **);
void set_nonblock(int);
void unset_nonblock(int);
void set_nodelay(int);
int a2port(const char *);
char *cleanhostname(char *);
char *colon(char *);
long convtime(const char *);
/* set filedescriptor to non-blocking */
void set_nonblock(int fd);
struct passwd *pwcopy(struct passwd *);
struct passwd * pwcopy(struct passwd *pw);
/*
* Convert ASCII string to TCP/IP port number.
* Port must be >0 and <=65535.
* Return 0 if invalid.
*/
int a2port(const char *s);
typedef struct arglist arglist;
struct arglist {
char **list;
int num;
int nalloc;
};
void addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3)));

View File

@ -1,3 +1,5 @@
/* $OpenBSD: mpaux.h,v 1.12 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -12,20 +14,9 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: mpaux.h,v 1.9 2000/12/19 23:17:57 markus Exp $"); */
#ifndef MPAUX_H
#define MPAUX_H
/*
* Computes a 16-byte session id in the global variable session_id. The
* session id is computed by concatenating the linearized, msb first
* representations of host_key_n, session_key_n, and the cookie.
*/
void
compute_session_id(u_char session_id[16],
u_char cookie[8],
BIGNUM * host_key_n,
BIGNUM * session_key_n);
void compute_session_id(u_char[16], u_char[8], BIGNUM *, BIGNUM *);
#endif /* MPAUX_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: myproposal.h,v 1.12 2001/03/05 15:56:16 deraadt Exp $ */
/* $OpenBSD: myproposal.h,v 1.13 2002/01/21 22:30:12 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -27,9 +27,7 @@
#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss"
#define KEX_DEFAULT_ENCRYPT \
"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
"aes192-cbc,aes256-cbc," \
"rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \
"rijndael-cbc@lysator.liu.se"
"aes192-cbc,aes256-cbc"
#define KEX_DEFAULT_MAC \
"hmac-md5,hmac-sha1,hmac-ripemd160," \
"hmac-ripemd160@openssh.com," \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,40 +23,79 @@
*/
#include "includes.h"
RCSID("$OpenBSD: nchan.c,v 1.23 2001/02/28 08:54:55 markus Exp $");
RCSID("$OpenBSD: nchan.c,v 1.44 2002/01/21 23:27:10 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
#include "buffer.h"
#include "packet.h"
#include "channels.h"
#include "nchan.h"
#include "compat.h"
#include "log.h"
/*
* SSH Protocol 1.5 aka New Channel Protocol
* Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
* Written by Markus Friedl in October 1999
*
* Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
* tear down of channels:
*
* 1.3: strict request-ack-protocol:
* CLOSE ->
* <- CLOSE_CONFIRM
*
* 1.5: uses variations of:
* IEOF ->
* <- OCLOSE
* <- IEOF
* OCLOSE ->
* i.e. both sides have to close the channel
*
* 2.0: the EOF messages are optional
*
* See the debugging output from 'ssh -v' and 'sshd -d' of
* ssh-1.2.27 as an example.
*
*/
/* functions manipulating channel states */
/*
* EVENTS update channel input/output states execute ACTIONS
*/
/* events concerning the INPUT from socket for channel (istate) */
chan_event_fn *chan_rcvd_oclose = NULL;
chan_event_fn *chan_read_failed = NULL;
chan_event_fn *chan_ibuf_empty = NULL;
/* events concerning the OUTPUT from channel for socket (ostate) */
chan_event_fn *chan_rcvd_ieof = NULL;
chan_event_fn *chan_write_failed = NULL;
chan_event_fn *chan_obuf_empty = NULL;
/*
* ACTIONS: should never update the channel states
*/
static void chan_send_ieof1(Channel *c);
static void chan_send_oclose1(Channel *c);
static void chan_send_close2(Channel *c);
static void chan_send_eof2(Channel *c);
static void chan_send_ieof1(Channel *);
static void chan_send_oclose1(Channel *);
static void chan_send_close2(Channel *);
static void chan_send_eof2(Channel *);
/* helper */
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
static void chan_shutdown_write(Channel *);
static void chan_shutdown_read(Channel *);
static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
static void
chan_set_istate(Channel *c, u_int next)
{
if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED)
fatal("chan_set_istate: bad state %d -> %d", c->istate, next);
debug("channel %d: input %s -> %s", c->self, istates[c->istate],
istates[next]);
c->istate = next;
}
static void
chan_set_ostate(Channel *c, u_int next)
{
if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED)
fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next);
debug("channel %d: output %s -> %s", c->self, ostates[c->ostate],
ostates[next]);
c->ostate = next;
}
/*
* SSH1 specific implementation of event functions
@ -68,64 +107,61 @@ chan_rcvd_oclose1(Channel *c)
debug("channel %d: rcvd oclose", c->self);
switch (c->istate) {
case CHAN_INPUT_WAIT_OCLOSE:
debug("channel %d: input wait_oclose -> closed", c->self);
c->istate = CHAN_INPUT_CLOSED;
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
case CHAN_INPUT_OPEN:
debug("channel %d: input open -> closed", c->self);
chan_shutdown_read(c);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_CLOSED;
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
case CHAN_INPUT_WAIT_DRAIN:
/* both local read_failed and remote write_failed */
log("channel %d: input drain -> closed", c->self);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_CLOSED;
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
default:
error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
error("channel %d: protocol error: rcvd_oclose for istate %d",
c->self, c->istate);
return;
}
}
static void
chan_read_failed_12(Channel *c)
void
chan_read_failed(Channel *c)
{
debug("channel %d: read failed", c->self);
switch (c->istate) {
case CHAN_INPUT_OPEN:
debug("channel %d: input open -> drain", c->self);
chan_shutdown_read(c);
c->istate = CHAN_INPUT_WAIT_DRAIN;
if (buffer_len(&c->input) == 0) {
debug("channel %d: input: no drain shortcut", c->self);
chan_ibuf_empty(c);
}
chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
break;
default:
error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
error("channel %d: chan_read_failed for istate %d",
c->self, c->istate);
break;
}
}
static void
chan_ibuf_empty1(Channel *c)
void
chan_ibuf_empty(Channel *c)
{
debug("channel %d: ibuf empty", c->self);
if (buffer_len(&c->input)) {
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
error("channel %d: chan_ibuf_empty for non empty buffer",
c->self);
return;
}
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: input drain -> wait_oclose", c->self);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_WAIT_OCLOSE;
if (compat20) {
if (!(c->flags & CHAN_CLOSE_SENT))
chan_send_eof2(c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
} else {
chan_send_ieof1(c);
chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
}
break;
default:
error("channel %d: internal error: chan_ibuf_empty for istate %d",
error("channel %d: chan_ibuf_empty for istate %d",
c->self, c->istate);
break;
}
@ -134,36 +170,15 @@ static void
chan_rcvd_ieof1(Channel *c)
{
debug("channel %d: rcvd ieof", c->self);
if (c->type != SSH_CHANNEL_OPEN) {
debug("channel %d: non-open", c->self);
if (c->istate == CHAN_INPUT_OPEN) {
debug("channel %d: non-open: input open -> wait_oclose", c->self);
chan_shutdown_read(c);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_WAIT_OCLOSE;
} else {
error("channel %d: istate %d != open", c->self, c->istate);
}
if (c->ostate == CHAN_OUTPUT_OPEN) {
debug("channel %d: non-open: output open -> closed", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
} else {
error("channel %d: ostate %d != open", c->self, c->ostate);
}
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
break;
case CHAN_OUTPUT_WAIT_IEOF:
debug("channel %d: output wait_ieof -> closed", c->self);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
error("channel %d: protocol error: rcvd_ieof for ostate %d",
c->self, c->ostate);
break;
}
@ -174,38 +189,39 @@ chan_write_failed1(Channel *c)
debug("channel %d: write failed", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: output open -> wait_ieof", c->self);
chan_shutdown_write(c);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
break;
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output wait_drain -> closed", c->self);
chan_shutdown_write(c);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
error("channel %d: internal error: chan_write_failed for ostate %d",
error("channel %d: chan_write_failed for ostate %d",
c->self, c->ostate);
break;
}
}
static void
chan_obuf_empty1(Channel *c)
void
chan_obuf_empty(Channel *c)
{
debug("channel %d: obuf empty", c->self);
if (buffer_len(&c->output)) {
error("channel %d: internal error: chan_obuf_empty for non empty buffer",
error("channel %d: chan_obuf_empty for non empty buffer",
c->self);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output drain -> closed", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_shutdown_write(c);
if (!compat20)
chan_send_oclose1(c);
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
error("channel %d: internal error: chan_obuf_empty for ostate %d",
error("channel %d: internal error: obuf_empty for ostate %d",
c->self, c->ostate);
break;
}
@ -222,7 +238,7 @@ chan_send_ieof1(Channel *c)
packet_send();
break;
default:
error("channel %d: internal error: cannot send ieof for istate %d",
error("channel %d: cannot send ieof for istate %d",
c->self, c->istate);
break;
}
@ -234,15 +250,14 @@ chan_send_oclose1(Channel *c)
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
case CHAN_OUTPUT_WAIT_DRAIN:
chan_shutdown_write(c);
buffer_consume(&c->output, buffer_len(&c->output));
buffer_clear(&c->output);
packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
packet_put_int(c->remote_id);
packet_send();
break;
default:
error("channel %d: internal error: cannot send oclose for ostate %d",
c->self, c->ostate);
error("channel %d: cannot send oclose for ostate %d",
c->self, c->ostate);
break;
}
}
@ -251,7 +266,7 @@ chan_send_oclose1(Channel *c)
* the same for SSH2
*/
static void
chan_rcvd_oclose2(Channel *c)
chan_rcvd_close2(Channel *c)
{
debug("channel %d: rcvd close", c->self);
if (c->flags & CHAN_CLOSE_RCVD)
@ -259,59 +274,36 @@ chan_rcvd_oclose2(Channel *c)
c->flags |= CHAN_CLOSE_RCVD;
if (c->type == SSH_CHANNEL_LARVAL) {
/* tear down larval channels immediately */
c->ostate = CHAN_OUTPUT_CLOSED;
c->istate = CHAN_INPUT_CLOSED;
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
chan_set_istate(c, CHAN_INPUT_CLOSED);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
/* wait until a data from the channel is consumed if a CLOSE is received */
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
/*
* wait until a data from the channel is consumed if a CLOSE
* is received
*/
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
break;
}
switch (c->istate) {
case CHAN_INPUT_OPEN:
debug("channel %d: input open -> closed", c->self);
chan_shutdown_read(c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: input drain -> closed", c->self);
chan_send_eof2(c);
break;
}
c->istate = CHAN_INPUT_CLOSED;
}
static void
chan_ibuf_empty2(Channel *c)
{
debug("channel %d: ibuf empty", c->self);
if (buffer_len(&c->input)) {
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
c->self);
return;
}
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: input drain -> closed", c->self);
if (!(c->flags & CHAN_CLOSE_SENT))
chan_send_eof2(c);
c->istate = CHAN_INPUT_CLOSED;
break;
default:
error("channel %d: internal error: chan_ibuf_empty for istate %d",
c->self, c->istate);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
}
}
static void
chan_rcvd_ieof2(Channel *c)
chan_rcvd_eof2(Channel *c)
{
debug("channel %d: rcvd eof", c->self);
if (c->ostate == CHAN_OUTPUT_OPEN) {
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
}
if (c->ostate == CHAN_OUTPUT_OPEN)
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
}
static void
chan_write_failed2(Channel *c)
@ -319,38 +311,12 @@ chan_write_failed2(Channel *c)
debug("channel %d: write failed", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: output open -> closed", c->self);
chan_shutdown_write(c); /* ?? */
c->ostate = CHAN_OUTPUT_CLOSED;
break;
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output drain -> closed", c->self);
chan_shutdown_write(c);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
error("channel %d: internal error: chan_write_failed for ostate %d",
c->self, c->ostate);
break;
}
}
static void
chan_obuf_empty2(Channel *c)
{
debug("channel %d: obuf empty", c->self);
if (buffer_len(&c->output)) {
error("internal error: chan_obuf_empty %d for non empty buffer",
c->self);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output drain -> closed", c->self);
chan_shutdown_write(c);
c->ostate = CHAN_OUTPUT_CLOSED;
break;
default:
error("channel %d: internal error: chan_obuf_empty for ostate %d",
error("channel %d: chan_write_failed for ostate %d",
c->self, c->ostate);
break;
}
@ -366,7 +332,7 @@ chan_send_eof2(Channel *c)
packet_send();
break;
default:
error("channel %d: internal error: cannot send eof for istate %d",
error("channel %d: cannot send eof for istate %d",
c->self, c->istate);
break;
}
@ -377,10 +343,10 @@ chan_send_close2(Channel *c)
debug("channel %d: send close", c->self);
if (c->ostate != CHAN_OUTPUT_CLOSED ||
c->istate != CHAN_INPUT_CLOSED) {
error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
error("channel %d: cannot send close for istate/ostate %d/%d",
c->self, c->istate, c->ostate);
} else if (c->flags & CHAN_CLOSE_SENT) {
error("channel %d: internal error: already sent close", c->self);
error("channel %d: already sent close", c->self);
} else {
packet_start(SSH2_MSG_CHANNEL_CLOSE);
packet_put_int(c->remote_id);
@ -391,9 +357,47 @@ chan_send_close2(Channel *c)
/* shared */
int
chan_is_dead(Channel *c)
void
chan_rcvd_ieof(Channel *c)
{
if (compat20)
chan_rcvd_eof2(c);
else
chan_rcvd_ieof1(c);
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
buffer_len(&c->output) == 0)
chan_obuf_empty(c);
}
void
chan_rcvd_oclose(Channel *c)
{
if (compat20)
chan_rcvd_close2(c);
else
chan_rcvd_oclose1(c);
}
void
chan_write_failed(Channel *c)
{
if (compat20)
chan_write_failed2(c);
else
chan_write_failed1(c);
}
void
chan_mark_dead(Channel *c)
{
c->type = SSH_CHANNEL_ZOMBIE;
}
int
chan_is_dead(Channel *c, int send)
{
if (c->type == SSH_CHANNEL_ZOMBIE) {
debug("channel %d: zombie", c->self);
return 1;
}
if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
return 0;
if (!compat20) {
@ -414,10 +418,19 @@ chan_is_dead(Channel *c)
debug2("channel %d: active efd: %d len %d type %s",
c->self, c->efd, buffer_len(&c->extended),
c->extended_usage==CHAN_EXTENDED_READ ?
"read": "write");
"read": "write");
} else {
if (!(c->flags & CHAN_CLOSE_SENT)) {
chan_send_close2(c);
if (send) {
chan_send_close2(c);
} else {
/* channel would be dead if we sent a close */
if (c->flags & CHAN_CLOSE_RCVD) {
debug("channel %d: almost dead",
c->self);
return 1;
}
}
}
if ((c->flags & CHAN_CLOSE_SENT) &&
(c->flags & CHAN_CLOSE_RCVD)) {
@ -428,55 +441,25 @@ chan_is_dead(Channel *c)
return 0;
}
void
chan_init_iostates(Channel *c)
{
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
c->flags = 0;
}
/* init */
void
chan_init(void)
{
if (compat20) {
chan_rcvd_oclose = chan_rcvd_oclose2;
chan_read_failed = chan_read_failed_12;
chan_ibuf_empty = chan_ibuf_empty2;
chan_rcvd_ieof = chan_rcvd_ieof2;
chan_write_failed = chan_write_failed2;
chan_obuf_empty = chan_obuf_empty2;
} else {
chan_rcvd_oclose = chan_rcvd_oclose1;
chan_read_failed = chan_read_failed_12;
chan_ibuf_empty = chan_ibuf_empty1;
chan_rcvd_ieof = chan_rcvd_ieof1;
chan_write_failed = chan_write_failed1;
chan_obuf_empty = chan_obuf_empty1;
}
}
/* helper */
static void
chan_shutdown_write(Channel *c)
{
buffer_consume(&c->output, buffer_len(&c->output));
buffer_clear(&c->output);
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
return;
/* shutdown failure is allowed if write failed already */
debug("channel %d: close_write", c->self);
if (c->sock != -1) {
if (shutdown(c->sock, SHUT_WR) < 0)
debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
debug("channel %d: chan_shutdown_write: "
"shutdown() failed for fd%d: %.100s",
c->self, c->sock, strerror(errno));
} else {
if (close(c->wfd) < 0)
log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
if (channel_close_fd(&c->wfd) < 0)
log("channel %d: chan_shutdown_write: "
"close() failed for fd%d: %.100s",
c->self, c->wfd, strerror(errno));
c->wfd = -1;
}
}
static void
@ -487,12 +470,14 @@ chan_shutdown_read(Channel *c)
debug("channel %d: close_read", c->self);
if (c->sock != -1) {
if (shutdown(c->sock, SHUT_RD) < 0)
error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
c->self, c->sock, c->istate, c->ostate, strerror(errno));
error("channel %d: chan_shutdown_read: "
"shutdown() failed for fd%d [i%d o%d]: %.100s",
c->self, c->sock, c->istate, c->ostate,
strerror(errno));
} else {
if (close(c->rfd) < 0)
log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
if (channel_close_fd(&c->rfd) < 0)
log("channel %d: chan_shutdown_read: "
"close() failed for fd%d: %.100s",
c->self, c->rfd, strerror(errno));
c->rfd = -1;
}
}

View File

@ -1,3 +1,27 @@
.\" $OpenBSD: nchan2.ms,v 1.2 2001/10/03 10:05:57 markus Exp $
.\"
.\" 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.
.\"
.TL
OpenSSH Channel Close Protocol 2.0 Implementation
.SH

View File

@ -13,7 +13,7 @@
*
*
* SSH2 packet format added by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -37,7 +37,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
RCSID("$OpenBSD: packet.c,v 1.90 2002/02/27 21:23:13 stevesk Exp $");
#include "xmalloc.h"
#include "buffer.h"
@ -59,6 +59,7 @@ RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
#include "mac.h"
#include "log.h"
#include "canohost.h"
#include "misc.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
@ -75,12 +76,6 @@ RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
static int connection_in = -1;
static int connection_out = -1;
/*
* Cipher type. This value is only used to determine whether to pad the
* packets with zeroes or random data.
*/
static int cipher_type = SSH_CIPHER_NONE;
/* Protocol flags for the remote side. */
static u_int remote_protocol_flags = 0;
@ -118,19 +113,11 @@ static int initialized = 0;
/* Set to true if the connection is interactive. */
static int interactive_mode = 0;
/* True if SSH2 packet format is used */
int use_ssh2_packet_format = 0;
/* Session key information for Encryption and MAC */
Newkeys *newkeys[MODE_MAX];
void
packet_set_ssh2_format(void)
{
DBG(debug("use_ssh2_packet_format"));
use_ssh2_packet_format = 1;
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
}
/* roundup current message to extra_pad bytes */
static u_char extra_pad = 0;
/*
* Sets the descriptors used for communication. Disables encryption until
@ -144,9 +131,9 @@ packet_set_connection(int fd_in, int fd_out)
fatal("packet_set_connection: cannot load cipher 'none'");
connection_in = fd_in;
connection_out = fd_out;
cipher_type = SSH_CIPHER_NONE;
cipher_init(&send_context, none, (u_char *) "", 0, NULL, 0);
cipher_init(&receive_context, none, (u_char *) "", 0, NULL, 0);
cipher_init(&send_context, none, "", 0, NULL, 0, CIPHER_ENCRYPT);
cipher_init(&receive_context, none, "", 0, NULL, 0, CIPHER_DECRYPT);
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
if (!initialized) {
initialized = 1;
buffer_init(&input);
@ -161,7 +148,7 @@ packet_set_connection(int fd_in, int fd_out)
/* Returns 1 if remote host is connected via socket, 0 if not. */
int
packet_connection_is_on_socket()
packet_connection_is_on_socket(void)
{
struct sockaddr_storage from, to;
socklen_t fromlen, tolen;
@ -187,7 +174,7 @@ packet_connection_is_on_socket()
/* returns 1 if connection is via ipv4 */
int
packet_connection_is_ipv4()
packet_connection_is_ipv4(void)
{
struct sockaddr_storage to;
socklen_t tolen = sizeof(to);
@ -203,7 +190,7 @@ packet_connection_is_ipv4()
/* Sets the connection into non-blocking mode. */
void
packet_set_nonblocking()
packet_set_nonblocking(void)
{
/* Set the socket into non-blocking mode. */
if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
@ -218,7 +205,7 @@ packet_set_nonblocking()
/* Returns the socket used for reading. */
int
packet_get_connection_in()
packet_get_connection_in(void)
{
return connection_in;
}
@ -226,7 +213,7 @@ packet_get_connection_in()
/* Returns the descriptor used for writing. */
int
packet_get_connection_out()
packet_get_connection_out(void)
{
return connection_out;
}
@ -234,7 +221,7 @@ packet_get_connection_out()
/* Closes the connection and clears and frees internal data structures. */
void
packet_close()
packet_close(void)
{
if (!initialized)
return;
@ -254,6 +241,8 @@ packet_close()
buffer_free(&compression_buffer);
buffer_compress_uninit();
}
cipher_cleanup(&send_context);
cipher_cleanup(&receive_context);
}
/* Sets remote side protocol flags. */
@ -262,13 +251,12 @@ void
packet_set_protocol_flags(u_int protocol_flags)
{
remote_protocol_flags = protocol_flags;
channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
}
/* Returns the remote protocol flags set earlier by the above function. */
u_int
packet_get_protocol_flags()
packet_get_protocol_flags(void)
{
return remote_protocol_flags;
}
@ -278,8 +266,8 @@ packet_get_protocol_flags()
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
void
packet_init_compression()
static void
packet_init_compression(void)
{
if (compression_buffer_ready == 1)
return;
@ -290,7 +278,7 @@ packet_init_compression()
void
packet_start_compression(int level)
{
if (packet_compression && !use_ssh2_packet_format)
if (packet_compression && !compat20)
fatal("Compression already enabled.");
packet_compression = 1;
packet_init_compression();
@ -298,44 +286,11 @@ packet_start_compression(int level)
buffer_compress_init_recv();
}
/*
* Encrypts the given number of bytes, copying from src to dest. bytes is
* known to be a multiple of 8.
*/
void
packet_encrypt(CipherContext * cc, void *dest, void *src,
u_int bytes)
{
cipher_encrypt(cc, dest, src, bytes);
}
/*
* Decrypts the given number of bytes, copying from src to dest. bytes is
* known to be a multiple of 8.
*/
void
packet_decrypt(CipherContext *context, void *dest, void *src, u_int bytes)
{
/*
* Cryptographic attack detector for ssh - Modifications for packet.c
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
*/
if (!compat20 &&
context->cipher->number != SSH_CIPHER_NONE &&
detect_attack(src, bytes, NULL) == DEATTACK_DETECTED)
packet_disconnect("crc32 compensation attack: network attack detected");
cipher_decrypt(context, dest, src, bytes);
}
/*
* Causes any further packets to be encrypted using the given key. The same
* key is used for both sending and reception. However, both directions are
* encrypted independently of each other.
*/
void
packet_set_encryption_key(const u_char *key, u_int keylen,
int number)
@ -345,85 +300,52 @@ packet_set_encryption_key(const u_char *key, u_int keylen,
fatal("packet_set_encryption_key: unknown cipher number %d", number);
if (keylen < 20)
fatal("packet_set_encryption_key: keylen too small: %d", keylen);
cipher_init(&receive_context, cipher, key, keylen, NULL, 0);
cipher_init(&send_context, cipher, key, keylen, NULL, 0);
cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
}
/* Starts constructing a packet to send. */
/* Start constructing a packet to send. */
void
packet_start1(int type)
packet_start(u_char type)
{
char buf[9];
u_char buf[9];
int len;
buffer_clear(&outgoing_packet);
memset(buf, 0, 8);
buf[8] = type;
buffer_append(&outgoing_packet, buf, 9);
}
void
packet_start2(int type)
{
char buf[4+1+1];
buffer_clear(&outgoing_packet);
memset(buf, 0, sizeof buf);
/* buf[0..3] = payload_len; */
/* buf[4] = pad_len; */
buf[5] = type & 0xff;
buffer_append(&outgoing_packet, buf, sizeof buf);
}
void
packet_start(int type)
{
DBG(debug("packet_start[%d]", type));
if (use_ssh2_packet_format)
packet_start2(type);
else
packet_start1(type);
len = compat20 ? 6 : 9;
memset(buf, 0, len - 1);
buf[len - 1] = type;
buffer_clear(&outgoing_packet);
buffer_append(&outgoing_packet, buf, len);
}
/* Appends a character to the packet data. */
/* Append payload. */
void
packet_put_char(int value)
{
char ch = value;
buffer_append(&outgoing_packet, &ch, 1);
}
/* Appends an integer to the packet data. */
void
packet_put_int(u_int value)
{
buffer_put_int(&outgoing_packet, value);
}
/* Appends a string to packet data. */
void
packet_put_string(const char *buf, u_int len)
packet_put_string(const void *buf, u_int len)
{
buffer_put_string(&outgoing_packet, buf, len);
}
void
packet_put_cstring(const char *str)
{
buffer_put_string(&outgoing_packet, str, strlen(str));
buffer_put_cstring(&outgoing_packet, str);
}
void
packet_put_raw(const char *buf, u_int len)
packet_put_raw(const void *buf, u_int len)
{
buffer_append(&outgoing_packet, buf, len);
}
/* Appends an arbitrary precision integer to packet data. */
void
packet_put_bignum(BIGNUM * value)
{
@ -440,10 +362,10 @@ packet_put_bignum2(BIGNUM * value)
* encrypts the packet before sending.
*/
void
static void
packet_send1(void)
{
char buf[8], *cp;
u_char buf[8], *cp;
int i, padding, len;
u_int checksum;
u_int32_t rand = 0;
@ -461,14 +383,14 @@ packet_send1(void)
buffer_compress(&outgoing_packet, &compression_buffer);
buffer_clear(&outgoing_packet);
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
buffer_len(&compression_buffer));
buffer_len(&compression_buffer));
}
/* Compute packet length without padding (add checksum, remove padding). */
len = buffer_len(&outgoing_packet) + 4 - 8;
/* Insert padding. Initialized to zero in packet_start1() */
padding = 8 - len % 8;
if (cipher_type != SSH_CIPHER_NONE) {
if (!send_context.plaintext) {
cp = buffer_ptr(&outgoing_packet);
for (i = 0; i < padding; i++) {
if (i % 4 == 0)
@ -480,7 +402,7 @@ packet_send1(void)
buffer_consume(&outgoing_packet, 8 - padding);
/* Add check bytes. */
checksum = ssh_crc32((u_char *) buffer_ptr(&outgoing_packet),
checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
PUT_32BIT(buf, checksum);
buffer_append(&outgoing_packet, buf, 4);
@ -493,9 +415,9 @@ packet_send1(void)
/* Append to output. */
PUT_32BIT(buf, len);
buffer_append(&output, buf, 4);
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
#ifdef PACKET_DEBUG
fprintf(stderr, "encrypted: ");
@ -511,21 +433,27 @@ packet_send1(void)
*/
}
void
static void
set_newkeys(int mode)
{
Enc *enc;
Mac *mac;
Comp *comp;
CipherContext *cc;
int encrypt;
debug("newkeys: mode %d", mode);
cc = (mode == MODE_OUT) ? &send_context : &receive_context;
if (mode == MODE_OUT) {
cc = &send_context;
encrypt = CIPHER_ENCRYPT;
} else {
cc = &receive_context;
encrypt = CIPHER_DECRYPT;
}
if (newkeys[mode] != NULL) {
debug("newkeys: rekeying");
/* todo: free old keys, reset compression/cipher-ctxt; */
memset(cc, 0, sizeof(*cc));
cipher_cleanup(cc);
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
@ -547,10 +475,10 @@ set_newkeys(int mode)
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init_context: %d", mode));
cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
memset(enc->iv, 0, enc->cipher->block_size);
memset(enc->key, 0, enc->cipher->key_len);
cipher_init(cc, enc->cipher, enc->key, enc->key_len,
enc->iv, enc->block_size, encrypt);
memset(enc->iv, 0, enc->block_size);
memset(enc->key, 0, enc->key_len);
if (comp->type != 0 && comp->enabled == 0) {
packet_init_compression();
if (mode == MODE_OUT)
@ -564,16 +492,15 @@ set_newkeys(int mode)
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
void
static void
packet_send2(void)
{
static u_int32_t seqnr = 0;
u_char *macbuf = NULL;
char *cp;
u_char type, *cp, *macbuf = NULL;
u_char padlen, pad;
u_int packet_length = 0;
u_int i, padlen, len;
u_int i, len;
u_int32_t rand = 0;
int type;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
@ -584,10 +511,10 @@ packet_send2(void)
mac = &newkeys[MODE_OUT]->mac;
comp = &newkeys[MODE_OUT]->comp;
}
block_size = enc ? enc->cipher->block_size : 8;
block_size = enc ? enc->block_size : 8;
cp = buffer_ptr(&outgoing_packet);
type = cp[5] & 0xff;
type = cp[5];
#ifdef PACKET_DEBUG
fprintf(stderr, "plain: ");
@ -618,8 +545,17 @@ packet_send2(void)
padlen = block_size - (len % block_size);
if (padlen < 4)
padlen += block_size;
buffer_append_space(&outgoing_packet, &cp, padlen);
if (enc && enc->cipher->number != SSH_CIPHER_NONE) {
if (extra_pad) {
/* will wrap if extra_pad+padlen > 255 */
extra_pad = roundup(extra_pad, block_size);
pad = extra_pad - ((len + padlen) % extra_pad);
debug("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
pad, len, padlen, extra_pad);
padlen += pad;
extra_pad = 0;
}
cp = buffer_append_space(&outgoing_packet, padlen);
if (enc && !send_context.plaintext) {
/* random padding */
for (i = 0; i < padlen; i++) {
if (i % 4 == 0)
@ -635,19 +571,19 @@ packet_send2(void)
packet_length = buffer_len(&outgoing_packet) - 4;
cp = buffer_ptr(&outgoing_packet);
PUT_32BIT(cp, packet_length);
cp[4] = padlen & 0xff;
cp[4] = padlen;
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled) {
macbuf = mac_compute(mac, seqnr,
(u_char *) buffer_ptr(&outgoing_packet),
buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
DBG(debug("done calc MAC out #%d", seqnr));
}
/* encrypt packet and append to output buffer. */
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
/* append unencrypted MAC */
if (mac && mac->enabled)
@ -666,9 +602,9 @@ packet_send2(void)
}
void
packet_send()
packet_send(void)
{
if (use_ssh2_packet_format)
if (compat20)
packet_send2();
else
packet_send1();
@ -682,7 +618,7 @@ packet_send()
*/
int
packet_read(int *payload_len_ptr)
packet_read_seqnr(u_int32_t *seqnr_p)
{
int type, len;
fd_set *setp;
@ -698,13 +634,13 @@ packet_read(int *payload_len_ptr)
/* Stay in the loop until we have received a complete packet. */
for (;;) {
/* Try to read a packet from the buffer. */
type = packet_read_poll(payload_len_ptr);
if (!use_ssh2_packet_format && (
type = packet_read_poll_seqnr(seqnr_p);
if (!compat20 && (
type == SSH_SMSG_SUCCESS
|| type == SSH_SMSG_FAILURE
|| type == SSH_CMSG_EOF
|| type == SSH_CMSG_EXIT_CONFIRMATION))
packet_integrity_check(*payload_len_ptr, 0, type);
packet_check_eom();
/* If we got a packet, return it. */
if (type != SSH_MSG_NONE) {
xfree(setp);
@ -737,17 +673,23 @@ packet_read(int *payload_len_ptr)
/* NOTREACHED */
}
int
packet_read(void)
{
return packet_read_seqnr(NULL);
}
/*
* Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
void
packet_read_expect(int *payload_len_ptr, int expected_type)
packet_read_expect(int expected_type)
{
int type;
type = packet_read(payload_len_ptr);
type = packet_read();
if (type != expected_type)
packet_disconnect("Protocol error: expected packet type %d, got %d",
expected_type, type);
@ -760,28 +702,21 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
* SSH_MSG_DISCONNECT is handled specially here. Also,
* SSH_MSG_IGNORE messages are skipped by this function and are never returned
* to higher levels.
*
* The returned payload_len does include space consumed by:
* Packet length
* Padding
* Packet type
* Check bytes
*/
int
packet_read_poll1(int *payload_len_ptr)
static int
packet_read_poll1(void)
{
u_int len, padded_len;
u_char *ucp;
char buf[8], *cp;
u_char *cp, type;
u_int checksum, stored_checksum;
/* Check if input size is less than minimum packet size. */
if (buffer_len(&input) < 4 + 8)
return SSH_MSG_NONE;
/* Get length of incoming packet. */
ucp = (u_char *) buffer_ptr(&input);
len = GET_32BIT(ucp);
cp = buffer_ptr(&input);
len = GET_32BIT(cp);
if (len < 1 + 2 + 2 || len > 256 * 1024)
packet_disconnect("Bad packet length %d.", len);
padded_len = (len + 8) & ~7;
@ -795,10 +730,20 @@ packet_read_poll1(int *payload_len_ptr)
/* Consume packet length. */
buffer_consume(&input, 4);
/* Copy data to incoming_packet. */
/*
* Cryptographic attack detector for ssh
* (C)1998 CORE-SDI, Buenos Aires Argentina
* Ariel Futoransky(futo@core-sdi.com)
*/
if (!receive_context.plaintext &&
detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED)
packet_disconnect("crc32 compensation attack: network attack detected");
/* Decrypt data to incoming_packet. */
buffer_clear(&incoming_packet);
buffer_append_space(&incoming_packet, &cp, padded_len);
packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
cp = buffer_append_space(&incoming_packet, padded_len);
cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
buffer_consume(&input, padded_len);
#ifdef PACKET_DEBUG
@ -807,25 +752,23 @@ packet_read_poll1(int *payload_len_ptr)
#endif
/* Compute packet checksum. */
checksum = ssh_crc32((u_char *) buffer_ptr(&incoming_packet),
checksum = ssh_crc32(buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet) - 4);
/* Skip padding. */
buffer_consume(&incoming_packet, 8 - len % 8);
/* Test check bytes. */
if (len != buffer_len(&incoming_packet))
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
len, buffer_len(&incoming_packet));
ucp = (u_char *) buffer_ptr(&incoming_packet) + len - 4;
stored_checksum = GET_32BIT(ucp);
cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
stored_checksum = GET_32BIT(cp);
if (checksum != stored_checksum)
packet_disconnect("Corrupted check bytes on input.");
buffer_consume_end(&incoming_packet, 4);
/* If using packet compression, decompress the packet. */
if (packet_compression) {
buffer_clear(&compression_buffer);
buffer_uncompress(&incoming_packet, &compression_buffer);
@ -833,26 +776,17 @@ packet_read_poll1(int *payload_len_ptr)
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
buffer_len(&compression_buffer));
}
/* Get packet type. */
buffer_get(&incoming_packet, &buf[0], 1);
/* Return length of payload (without type field). */
*payload_len_ptr = buffer_len(&incoming_packet);
/* Return type. */
return (u_char) buf[0];
type = buffer_get_char(&incoming_packet);
return type;
}
int
packet_read_poll2(int *payload_len_ptr)
static int
packet_read_poll2(u_int32_t *seqnr_p)
{
static u_int32_t seqnr = 0;
static u_int packet_length = 0;
u_int padlen, need;
u_char buf[8], *macbuf;
u_char *ucp;
char *cp;
int type;
u_char *macbuf, *cp, type;
int maclen, block_size;
Enc *enc = NULL;
Mac *mac = NULL;
@ -864,7 +798,7 @@ packet_read_poll2(int *payload_len_ptr)
comp = &newkeys[MODE_IN]->comp;
}
maclen = mac && mac->enabled ? mac->mac_len : 0;
block_size = enc ? enc->cipher->block_size : 8;
block_size = enc ? enc->block_size : 8;
if (packet_length == 0) {
/*
@ -874,11 +808,11 @@ packet_read_poll2(int *payload_len_ptr)
if (buffer_len(&input) < block_size)
return SSH_MSG_NONE;
buffer_clear(&incoming_packet);
buffer_append_space(&incoming_packet, &cp, block_size);
packet_decrypt(&receive_context, cp, buffer_ptr(&input),
cp = buffer_append_space(&incoming_packet, block_size);
cipher_crypt(&receive_context, cp, buffer_ptr(&input),
block_size);
ucp = (u_char *) buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(ucp);
cp = buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(cp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
buffer_dump(&incoming_packet);
packet_disconnect("Bad packet length %d.", packet_length);
@ -903,8 +837,8 @@ packet_read_poll2(int *payload_len_ptr)
fprintf(stderr, "read_poll enc/full: ");
buffer_dump(&input);
#endif
buffer_append_space(&incoming_packet, &cp, need);
packet_decrypt(&receive_context, cp, buffer_ptr(&input), need);
cp = buffer_append_space(&incoming_packet, need);
cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
buffer_consume(&input, need);
/*
* compute MAC over seqnr and packet,
@ -912,19 +846,21 @@ packet_read_poll2(int *payload_len_ptr)
*/
if (mac && mac->enabled) {
macbuf = mac_compute(mac, seqnr,
(u_char *) buffer_ptr(&incoming_packet),
buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet));
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
packet_disconnect("Corrupted MAC on input.");
DBG(debug("MAC #%d ok", seqnr));
buffer_consume(&input, mac->mac_len);
}
if (seqnr_p != NULL)
*seqnr_p = seqnr;
if (++seqnr == 0)
log("incoming seqnr wraps around");
/* get padlen */
cp = buffer_ptr(&incoming_packet) + 4;
padlen = *cp & 0xff;
cp = buffer_ptr(&incoming_packet);
padlen = cp[4];
DBG(debug("input: padlen %d", padlen));
if (padlen < 4)
packet_disconnect("Corrupted padlen %d on input.", padlen);
@ -946,39 +882,31 @@ packet_read_poll2(int *payload_len_ptr)
* get packet type, implies consume.
* return length of payload (without type field)
*/
buffer_get(&incoming_packet, (char *)&buf[0], 1);
*payload_len_ptr = buffer_len(&incoming_packet);
/* reset for next packet */
packet_length = 0;
/* extract packet type */
type = (u_char)buf[0];
type = buffer_get_char(&incoming_packet);
if (type == SSH2_MSG_NEWKEYS)
set_newkeys(MODE_IN);
#ifdef PACKET_DEBUG
fprintf(stderr, "read/plain[%d]:\r\n", type);
buffer_dump(&incoming_packet);
#endif
return (u_char)type;
/* reset for next packet */
packet_length = 0;
return type;
}
int
packet_read_poll(int *payload_len_ptr)
packet_read_poll_seqnr(u_int32_t *seqnr_p)
{
int reason, seqnr;
u_char type;
char *msg;
for (;;) {
int type = use_ssh2_packet_format ?
packet_read_poll2(payload_len_ptr):
packet_read_poll1(payload_len_ptr);
if(compat20) {
int reason;
if (type != 0)
for (;;) {
if (compat20) {
type = packet_read_poll2(seqnr_p);
if (type)
DBG(debug("received packet type %d", type));
switch(type) {
switch (type) {
case SSH2_MSG_IGNORE:
break;
case SSH2_MSG_DEBUG:
@ -997,12 +925,17 @@ packet_read_poll(int *payload_len_ptr)
xfree(msg);
fatal_cleanup();
break;
case SSH2_MSG_UNIMPLEMENTED:
seqnr = packet_get_int();
debug("Received SSH2_MSG_UNIMPLEMENTED for %d", seqnr);
break;
default:
return type;
break;
}
} else {
switch(type) {
type = packet_read_poll1();
switch (type) {
case SSH_MSG_IGNORE:
break;
case SSH_MSG_DEBUG:
@ -1018,7 +951,7 @@ packet_read_poll(int *payload_len_ptr)
xfree(msg);
break;
default:
if (type != 0)
if (type)
DBG(debug("received packet type %d", type));
return type;
break;
@ -1027,6 +960,12 @@ packet_read_poll(int *payload_len_ptr)
}
}
int
packet_read_poll(void)
{
return packet_read_poll_seqnr(NULL);
}
/*
* Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
@ -1041,7 +980,7 @@ packet_process_incoming(const char *buf, u_int len)
/* Returns a character from the packet. */
u_int
packet_get_char()
packet_get_char(void)
{
char ch;
buffer_get(&incoming_packet, &ch, 1);
@ -1051,7 +990,7 @@ packet_get_char()
/* Returns an integer from the packet data. */
u_int
packet_get_int()
packet_get_int(void)
{
return buffer_get_int(&incoming_packet);
}
@ -1062,18 +1001,18 @@ packet_get_int()
*/
void
packet_get_bignum(BIGNUM * value, int *length_ptr)
packet_get_bignum(BIGNUM * value)
{
*length_ptr = buffer_get_bignum(&incoming_packet, value);
buffer_get_bignum(&incoming_packet, value);
}
void
packet_get_bignum2(BIGNUM * value, int *length_ptr)
packet_get_bignum2(BIGNUM * value)
{
*length_ptr = buffer_get_bignum2(&incoming_packet, value);
buffer_get_bignum2(&incoming_packet, value);
}
char *
void *
packet_get_raw(int *length_ptr)
{
int bytes = buffer_len(&incoming_packet);
@ -1095,7 +1034,7 @@ packet_remaining(void)
* integer into which the length of the string is stored.
*/
char *
void *
packet_get_string(u_int *length_ptr)
{
return buffer_get_string(&incoming_packet, length_ptr);
@ -1169,13 +1108,13 @@ packet_disconnect(const char *fmt,...)
packet_put_cstring("");
} else {
packet_start(SSH_MSG_DISCONNECT);
packet_put_string(buf, strlen(buf));
packet_put_cstring(buf);
}
packet_send();
packet_write_wait();
/* Stop listening for connections. */
channel_stop_listening();
channel_close_all();
/* Close the connection. */
packet_close();
@ -1188,7 +1127,7 @@ packet_disconnect(const char *fmt,...)
/* Checks if there is any buffered output, and tries to write some of the output. */
void
packet_write_poll()
packet_write_poll(void)
{
int len = buffer_len(&output);
if (len > 0) {
@ -1209,7 +1148,7 @@ packet_write_poll()
*/
void
packet_write_wait()
packet_write_wait(void)
{
fd_set *setp;
@ -1231,7 +1170,7 @@ packet_write_wait()
/* Returns true if there is buffered data to write to the connection. */
int
packet_have_data_to_write()
packet_have_data_to_write(void)
{
return buffer_len(&output) != 0;
}
@ -1239,7 +1178,7 @@ packet_have_data_to_write()
/* Returns true if there is not too much data to write to the connection. */
int
packet_not_very_much_data_to_write()
packet_not_very_much_data_to_write(void)
{
if (interactive_mode)
return buffer_len(&output) < 16384;
@ -1255,7 +1194,6 @@ packet_set_interactive(int interactive)
static int called = 0;
int lowdelay = IPTOS_LOWDELAY;
int throughput = IPTOS_THROUGHPUT;
int on = 1;
if (called)
return;
@ -1277,19 +1215,17 @@ packet_set_interactive(int interactive)
*/
if (packet_connection_is_ipv4()) {
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
(void *) &lowdelay, sizeof(lowdelay)) < 0)
&lowdelay, sizeof(lowdelay)) < 0)
error("setsockopt IPTOS_LOWDELAY: %.100s",
strerror(errno));
}
if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
sizeof(on)) < 0)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
set_nodelay(connection_in);
} else if (packet_connection_is_ipv4()) {
/*
* Set IP options for a non-interactive connection. Use
* IPTOS_THROUGHPUT.
*/
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
sizeof(throughput)) < 0)
error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
}
@ -1298,7 +1234,7 @@ packet_set_interactive(int interactive)
/* Returns true if the current connection is interactive. */
int
packet_is_interactive()
packet_is_interactive(void)
{
return interactive_mode;
}
@ -1316,11 +1252,19 @@ packet_set_maxsize(int s)
log("packet_set_maxsize: bad size %d", s);
return -1;
}
log("packet_set_maxsize: setting to %d", s);
called = 1;
debug("packet_set_maxsize: setting to %d", s);
max_packet_size = s;
return s;
}
/* roundup current message to pad bytes */
void
packet_add_padding(u_char pad)
{
extra_pad = pad;
}
/*
* 9.2. Ignored Data Message
*
@ -1332,41 +1276,6 @@ packet_set_maxsize(int s)
* required to send them. This message can be used as an additional
* protection measure against advanced traffic analysis techniques.
*/
/* size of current + ignore message should be n*sumlen bytes (w/o mac) */
void
packet_inject_ignore(int sumlen)
{
int blocksize, padlen, have, need, nb, mini, nbytes;
Enc *enc = NULL;
if (use_ssh2_packet_format == 0)
return;
have = buffer_len(&outgoing_packet);
debug2("packet_inject_ignore: current %d", have);
if (newkeys[MODE_OUT] != NULL)
enc = &newkeys[MODE_OUT]->enc;
blocksize = enc ? enc->cipher->block_size : 8;
padlen = blocksize - (have % blocksize);
if (padlen < 4)
padlen += blocksize;
have += padlen;
have /= blocksize; /* # of blocks for current message */
nb = roundup(sumlen, blocksize) / blocksize; /* blocks for both */
mini = roundup(5+1+4+4, blocksize) / blocksize; /* minsize ignore msg */
need = nb - (have % nb); /* blocks for ignore */
if (need <= mini)
need += nb;
nbytes = (need - mini) * blocksize; /* size of ignore payload */
debug2("packet_inject_ignore: block %d have %d nb %d mini %d need %d",
blocksize, have, nb, mini, need);
/* enqueue current message and append a ignore message */
packet_send();
packet_send_ignore(nbytes);
}
void
packet_send_ignore(int nbytes)
{
@ -1375,7 +1284,7 @@ packet_send_ignore(int nbytes)
packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
packet_put_int(nbytes);
for(i = 0; i < nbytes; i++) {
for (i = 0; i < nbytes; i++) {
if (i % 4 == 0)
rand = arc4random();
packet_put_char(rand & 0xff);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: packet.h,v 1.33 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,190 +13,69 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
#ifndef PACKET_H
#define PACKET_H
#include <openssl/bn.h>
/*
* Sets the socket used for communication. Disables encryption until
* packet_set_encryption_key is called. It is permissible that fd_in and
* fd_out are the same descriptor; in that case it is assumed to be a socket.
*/
void packet_set_connection(int fd_in, int fd_out);
void packet_set_connection(int, int);
void packet_set_nonblocking(void);
int packet_get_connection_in(void);
int packet_get_connection_out(void);
void packet_close(void);
void packet_set_encryption_key(const u_char *, u_int, int);
void packet_set_protocol_flags(u_int);
u_int packet_get_protocol_flags(void);
void packet_start_compression(int);
void packet_set_interactive(int);
int packet_is_interactive(void);
/* Puts the connection file descriptors into non-blocking mode. */
void packet_set_nonblocking(void);
void packet_start(u_char);
void packet_put_char(int ch);
void packet_put_int(u_int value);
void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value);
void packet_put_string(const void *buf, u_int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const void *buf, u_int len);
void packet_send(void);
/* Returns the file descriptor used for input. */
int packet_get_connection_in(void);
int packet_read(void);
void packet_read_expect(int type);
int packet_read_poll(void);
void packet_process_incoming(const char *buf, u_int len);
int packet_read_seqnr(u_int32_t *seqnr_p);
int packet_read_poll_seqnr(u_int32_t *seqnr_p);
/* Returns the file descriptor used for output. */
int packet_get_connection_out(void);
u_int packet_get_char(void);
u_int packet_get_int(void);
void packet_get_bignum(BIGNUM * value);
void packet_get_bignum2(BIGNUM * value);
void *packet_get_raw(int *length_ptr);
void *packet_get_string(u_int *length_ptr);
void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/*
* Closes the connection (both descriptors) and clears and frees internal
* data structures.
*/
void packet_close(void);
void packet_write_poll(void);
void packet_write_wait(void);
int packet_have_data_to_write(void);
int packet_not_very_much_data_to_write(void);
/*
* Causes any further packets to be encrypted using the given key. The same
* key is used for both sending and reception. However, both directions are
* encrypted independently of each other. Cipher types are defined in ssh.h.
*/
void
packet_set_encryption_key(const u_char *key, u_int keylen,
int cipher_type);
int packet_connection_is_on_socket(void);
int packet_connection_is_ipv4(void);
int packet_remaining(void);
void packet_send_ignore(int);
void packet_add_padding(u_char);
/*
* Sets remote side protocol flags for the current connection. This can be
* called at any time.
*/
void packet_set_protocol_flags(u_int flags);
void tty_make_modes(int, struct termios *);
void tty_parse_modes(int, int *);
/* Returns the remote protocol flags set earlier by the above function. */
u_int packet_get_protocol_flags(void);
/* Enables compression in both directions starting from the next packet. */
void packet_start_compression(int level);
/*
* Informs that the current session is interactive. Sets IP flags for
* optimal performance in interactive use.
*/
void packet_set_interactive(int interactive);
/* Returns true if the current connection is interactive. */
int packet_is_interactive(void);
/* Starts constructing a packet to send. */
void packet_start(int type);
/* Appends a character to the packet data. */
void packet_put_char(int ch);
/* Appends an integer to the packet data. */
void packet_put_int(u_int value);
/* Appends an arbitrary precision integer to packet data. */
void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value);
/* Appends a string to packet data. */
void packet_put_string(const char *buf, u_int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const char *buf, u_int len);
/*
* Finalizes and sends the packet. If the encryption key has been set,
* encrypts the packet before sending.
*/
void packet_send(void);
/* Waits until a packet has been received, and returns its type. */
int packet_read(int *payload_len_ptr);
/*
* Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
void packet_read_expect(int *payload_len_ptr, int type);
/*
* Checks if a full packet is available in the data received so far via
* packet_process_incoming. If so, reads the packet; otherwise returns
* SSH_MSG_NONE. This does not wait for data from the connection.
* SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
* messages are skipped by this function and are never returned to higher
* levels.
*/
int packet_read_poll(int *packet_len_ptr);
/*
* Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
*/
void packet_process_incoming(const char *buf, u_int len);
/* Returns a character (0-255) from the packet data. */
u_int packet_get_char(void);
/* Returns an integer from the packet data. */
u_int packet_get_int(void);
/*
* Returns an arbitrary precision integer from the packet data. The integer
* must have been initialized before this call.
*/
void packet_get_bignum(BIGNUM * value, int *length_ptr);
void packet_get_bignum2(BIGNUM * value, int *length_ptr);
char *packet_get_raw(int *length_ptr);
/*
* Returns a string from the packet data. The string is allocated using
* xmalloc; it is the responsibility of the calling program to free it when
* no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored.
*/
char *packet_get_string(u_int *length_ptr);
/*
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
* packet, closes the connection, and exits. This function never returns.
* The error message should not contain a newline. The total length of the
* message must not exceed 1024 bytes.
*/
void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/*
* Sends a diagnostic message to the other side. This message can be sent at
* any time (but not while constructing another message). The message is
* printed immediately, but only if the client is being executed in verbose
* mode. These messages are primarily intended to ease debugging
* authentication problems. The total length of the message must not exceed
* 1024 bytes. This will automatically call packet_write_wait. If the
* remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
* this will do nothing.
*/
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/* Checks if there is any buffered output, and tries to write some of the output. */
void packet_write_poll(void);
/* Waits until all pending output data has been written. */
void packet_write_wait(void);
/* Returns true if there is buffered data to write to the connection. */
int packet_have_data_to_write(void);
/* Returns true if there is not too much data to write to the connection. */
int packet_not_very_much_data_to_write(void);
/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */
extern int max_packet_size;
int packet_set_maxsize(int s);
#define packet_get_maxsize() max_packet_size
int packet_set_maxsize(int);
#define packet_get_maxsize() max_packet_size
/* Stores tty modes from the fd or tiop into current packet. */
void tty_make_modes(int fd, struct termios *tiop);
/* Parses tty modes for the fd from the current packet. */
void tty_parse_modes(int fd, int *n_bytes_ptr);
#define packet_integrity_check(payload_len, expected_len, type) \
do { \
int _p = (payload_len), _e = (expected_len); \
if (_p != _e) { \
log("Packet integrity error (%d != %d) at %s:%d", \
_p, _e, __FILE__, __LINE__); \
packet_disconnect("Packet integrity error. (%d)", (type)); \
} \
} while (0)
#define packet_done() \
/* don't allow remaining bytes after the end of the message */
#define packet_check_eom() \
do { \
int _len = packet_remaining(); \
if (_len > 0) { \
@ -204,20 +85,4 @@ do { \
} \
} while (0)
/* remote host is connected via a socket/ipv4 */
int packet_connection_is_on_socket(void);
int packet_connection_is_ipv4(void);
/* enable SSH2 packet format */
void packet_set_ssh2_format(void);
/* returns remaining payload bytes */
int packet_remaining(void);
/* append an ignore message */
void packet_send_ignore(int nbytes);
/* add an ignore message and make sure size (current+ignore) = n*sumlen */
void packet_inject_ignore(int sumlen);
#endif /* PACKET_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
/* $OpenBSD: pathnames.h,v 1.11 2002/02/09 17:37:34 deraadt Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -13,24 +13,28 @@
*/
#define ETCDIR "/etc"
#define SSHDIR ETCDIR "/ssh"
#define _PATH_SSH_PIDDIR "/var/run"
/*
* System-wide file containing host keys of known hosts. This file should be
* world-readable.
*/
#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
#define _PATH_SSH_SYSTEM_HOSTFILE SSHDIR "/ssh_known_hosts"
/* backward compat for protocol 2 */
#define _PATH_SSH_SYSTEM_HOSTFILE2 SSHDIR "/ssh_known_hosts2"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
* should be world-readable.
*/
#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
#define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE SSHDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
#define _PATH_DH_MODULI ETCDIR "/moduli"
/* Backwards compatibility */
#define _PATH_DH_PRIMES ETCDIR "/primes"
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
@ -53,6 +57,7 @@
* contain anything particularly secret.
*/
#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
/* backward compat for protocol 2 */
#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
@ -80,6 +85,8 @@
* running as root.)
*/
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
/* backward compat for protocol v2 */
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
@ -89,7 +96,7 @@
* use. xauth will be run if neither of these exists.
*/
#define _PATH_SSH_USER_RC ".ssh/rc"
#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
#define _PATH_SSH_SYSTEM_RC SSHDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
@ -103,6 +110,12 @@
*/
#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
/* xauth for X11 forwarding */
#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
/* UNIX domain socket for X11 server; displaynum will replace %u */
#define _PATH_UNIX_X "/tmp/.X11-unix/X%u"
/* for scp */
#define _PATH_CP "cp"

View File

@ -25,11 +25,13 @@
#include "includes.h"
#include "uuencode.h"
RCSID("$OpenBSD: radix.c,v 1.15 2001/01/16 23:58:09 deraadt Exp $");
RCSID("$OpenBSD: radix.c,v 1.17 2001/11/19 19:02:16 mpech Exp $");
#ifdef AFS
#include <krb.h>
#include <radix.h>
typedef u_char my_u_char;
typedef u_int my_u_int32_t;
typedef u_short my_u_short;
@ -37,7 +39,7 @@ typedef u_short my_u_short;
/* Nasty macros from BIND-4.9.2 */
#define GETSHORT(s, cp) { \
register my_u_char *t_cp = (my_u_char *)(cp); \
my_u_char *t_cp = (my_u_char *)(cp); \
(s) = (((my_u_short)t_cp[0]) << 8) \
| (((my_u_short)t_cp[1])) \
; \
@ -45,7 +47,7 @@ typedef u_short my_u_short;
}
#define GETLONG(l, cp) { \
register my_u_char *t_cp = (my_u_char *)(cp); \
my_u_char *t_cp = (my_u_char *)(cp); \
(l) = (((my_u_int32_t)t_cp[0]) << 24) \
| (((my_u_int32_t)t_cp[1]) << 16) \
| (((my_u_int32_t)t_cp[2]) << 8) \
@ -55,16 +57,16 @@ typedef u_short my_u_short;
}
#define PUTSHORT(s, cp) { \
register my_u_short t_s = (my_u_short)(s); \
register my_u_char *t_cp = (my_u_char *)(cp); \
my_u_short t_s = (my_u_short)(s); \
my_u_char *t_cp = (my_u_char *)(cp); \
*t_cp++ = t_s >> 8; \
*t_cp = t_s; \
(cp) += 2; \
}
#define PUTLONG(l, cp) { \
register my_u_int32_t t_l = (my_u_int32_t)(l); \
register my_u_char *t_cp = (my_u_char *)(cp); \
my_u_int32_t t_l = (my_u_int32_t)(l); \
my_u_char *t_cp = (my_u_char *)(cp); \
*t_cp++ = t_l >> 24; \
*t_cp++ = t_l >> 16; \
*t_cp++ = t_l >> 8; \
@ -73,9 +75,9 @@ typedef u_short my_u_short;
}
#define GETSTRING(s, p, p_l) { \
register char *p_targ = (p) + p_l; \
register char *s_c = (s); \
register char *p_c = (p); \
char *p_targ = (p) + p_l; \
char *s_c = (s); \
char *p_c = (p); \
while (*p_c && (p_c < p_targ)) { \
*s_c++ = *p_c++; \
} \

View File

@ -1,4 +1,4 @@
/* $OpenBSD: radix.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/* $OpenBSD: radix.h,v 1.4 2001/06/26 17:27:24 markus Exp $ */
/*
* Copyright (c) 1999 Dug Song. All rights reserved.
@ -24,5 +24,5 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int creds_to_radix(CREDENTIALS * creds, u_char *buf, size_t buflen);
int radix_to_creds(const char *buf, CREDENTIALS * creds);
int creds_to_radix(CREDENTIALS *, u_char *, size_t);
int radix_to_creds(const char *, CREDENTIALS *);

View File

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.76 2001/04/17 10:53:25 markus Exp $");
RCSID("$OpenBSD: readconf.c,v 1.95 2002/02/04 12:15:25 markus Exp $");
#include "ssh.h"
#include "xmalloc.h"
@ -96,11 +96,14 @@ typedef enum {
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
oChallengeResponseAuthentication, oXAuthLocation,
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
oKerberosAuthentication,
#endif /* KRB4 */
#endif
#if defined(AFS) || defined(KRB5)
oKerberosTgtPassing,
#endif
#ifdef AFS
oKerberosTgtPassing, oAFSTokenPassing,
oAFSTokenPassing,
#endif
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
@ -111,7 +114,8 @@ typedef enum {
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost
} OpCodes;
/* Textual representations of the tokens. */
@ -137,11 +141,13 @@ static struct {
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", oKerberosAuthentication },
#endif /* KRB4 */
#ifdef AFS
#endif
#if defined(AFS) || defined(KRB5)
{ "kerberostgtpassing", oKerberosTgtPassing },
#endif
#ifdef AFS
{ "afstokenpassing", oAFSTokenPassing },
#endif
{ "fallbacktorsh", oFallBackToRsh },
@ -162,9 +168,9 @@ static struct {
{ "host", oHost },
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
@ -177,7 +183,11 @@ static struct {
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
{ NULL, 0 }
{ "bindaddress", oBindAddress },
{ "smartcarddevice", oSmartcardDevice },
{ "clearallforwardings", oClearAllForwardings },
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ NULL, oBadOption }
};
/*
@ -213,13 +223,26 @@ add_remote_forward(Options *options, u_short port, const char *host,
Forward *fwd;
if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many remote forwards (max %d).",
SSH_MAX_FORWARDS_PER_DIRECTION);
SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->remote_forwards[options->num_remote_forwards++];
fwd->port = port;
fwd->host = xstrdup(host);
fwd->host_port = host_port;
}
static void
clear_forwardings(Options *options)
{
int i;
for (i = 0; i < options->num_local_forwards; i++)
xfree(options->local_forwards[i].host);
options->num_local_forwards = 0;
for (i = 0; i < options->num_remote_forwards; i++)
xfree(options->remote_forwards[i].host);
options->num_remote_forwards = 0;
}
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@ -251,6 +274,7 @@ process_config_line(Options *options, const char *host,
char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
int opcode, *intptr, value;
u_short fwd_port, fwd_host_port;
char sfwd_host_port[6];
s = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
@ -330,25 +354,23 @@ process_config_line(Options *options, const char *host,
goto parse_flag;
case oChallengeResponseAuthentication:
intptr = &options->challenge_reponse_authentication;
intptr = &options->challenge_response_authentication;
goto parse_flag;
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
case oKerberosAuthentication:
intptr = &options->kerberos_authentication;
goto parse_flag;
#endif /* KRB4 */
#ifdef AFS
#endif
#if defined(AFS) || defined(KRB5)
case oKerberosTgtPassing:
intptr = &options->kerberos_tgt_passing;
goto parse_flag;
#endif
#ifdef AFS
case oAFSTokenPassing:
intptr = &options->afs_token_passing;
goto parse_flag;
#endif
case oFallBackToRsh:
intptr = &options->fallback_to_rsh;
goto parse_flag;
@ -370,7 +392,7 @@ process_config_line(Options *options, const char *host,
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no/ask argument.",
filename, linenum);
filename, linenum);
value = 0; /* To avoid compiler warning... */
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1;
@ -392,6 +414,10 @@ process_config_line(Options *options, const char *host,
intptr = &options->keepalives;
goto parse_flag;
case oNoHostAuthenticationForLocalhost:
intptr = &options->no_host_authentication_for_localhost;
goto parse_flag;
case oNumberOfPasswordPrompts:
intptr = &options->number_of_password_prompts;
goto parse_int;
@ -408,7 +434,7 @@ process_config_line(Options *options, const char *host,
intptr = &options->num_identity_files;
if (*intptr >= SSH_MAX_IDENTITY_FILES)
fatal("%.200s line %d: Too many identity files specified (max %d).",
filename, linenum, SSH_MAX_IDENTITY_FILES);
filename, linenum, SSH_MAX_IDENTITY_FILES);
charptr = &options->identity_files[*intptr];
*charptr = xstrdup(arg);
*intptr = *intptr + 1;
@ -457,6 +483,14 @@ process_config_line(Options *options, const char *host,
charptr = &options->preferred_authentications;
goto parse_string;
case oBindAddress:
charptr = &options->bind_address;
goto parse_string;
case oSmartcardDevice:
charptr = &options->smartcard_device;
goto parse_string;
case oProxyCommand:
charptr = &options->proxy_command;
string = xstrdup("");
@ -500,7 +534,7 @@ process_config_line(Options *options, const char *host,
value = cipher_number(arg);
if (value == -1)
fatal("%.200s line %d: Bad cipher '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == -1)
*intptr = value;
break;
@ -511,7 +545,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!ciphers_valid(arg))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
@ -522,7 +556,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
@ -533,7 +567,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!key_names_valid2(arg))
fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->hostkeyalgorithms == NULL)
options->hostkeyalgorithms = xstrdup(arg);
break;
@ -546,7 +580,7 @@ process_config_line(Options *options, const char *host,
value = proto_spec(arg);
if (value == SSH_PROTO_UNKNOWN)
fatal("%.200s line %d: Bad protocol spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
*intptr = value;
break;
@ -555,49 +589,41 @@ process_config_line(Options *options, const char *host,
intptr = (int *) &options->log_level;
arg = strdelim(&s);
value = log_level_number(arg);
if (value == (LogLevel) - 1)
if (value == SYSLOG_LEVEL_NOT_SET)
fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) * intptr == -1)
filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
*intptr = (LogLevel) value;
break;
case oLocalForward:
case oRemoteForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
if ((fwd_port = a2port(arg)) == 0)
fatal("%.200s line %d: Bad listen port.",
filename, linenum);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
filename, linenum);
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum);
if (*activep)
add_remote_forward(options, fwd_port, buf, fwd_host_port);
break;
case oLocalForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
filename, linenum);
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum);
if (*activep)
add_local_forward(options, fwd_port, buf, fwd_host_port);
filename, linenum);
if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
fatal("%.200s line %d: Bad forwarding specification.",
filename, linenum);
if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
fatal("%.200s line %d: Bad forwarding port.",
filename, linenum);
if (*activep) {
if (opcode == oLocalForward)
add_local_forward(options, fwd_port, buf,
fwd_host_port);
else if (opcode == oRemoteForward)
add_remote_forward(options, fwd_port, buf,
fwd_host_port);
}
break;
case oDynamicForward:
@ -609,9 +635,14 @@ process_config_line(Options *options, const char *host,
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
add_local_forward(options, fwd_port, "socks4", 0);
if (*activep)
add_local_forward(options, fwd_port, "socks4", 0);
break;
case oClearAllForwardings:
intptr = &options->clear_forwardings;
goto parse_flag;
case oHost:
*activep = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@ -634,10 +665,10 @@ process_config_line(Options *options, const char *host,
else if (strlen(arg) == 1)
value = (u_char) arg[0];
else if (strcmp(arg, "none") == 0)
value = -2;
value = SSH_ESCAPECHAR_NONE;
else {
fatal("%.200s line %d: Bad escape character.",
filename, linenum);
filename, linenum);
/* NOTREACHED */
value = 0; /* Avoid compiler warning. */
}
@ -652,7 +683,7 @@ process_config_line(Options *options, const char *host,
/* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
filename, linenum, arg);
}
return 0;
}
@ -661,10 +692,10 @@ process_config_line(Options *options, const char *host,
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
* there is an error. If the file does not exist, this returns 0.
*/
void
int
read_config_file(const char *filename, const char *host, Options *options)
{
FILE *f;
@ -675,7 +706,7 @@ read_config_file(const char *filename, const char *host, Options *options)
/* Open the file. */
f = fopen(filename, "r");
if (!f)
return;
return 0;
debug("Reading configuration data %.200s", filename);
@ -694,7 +725,8 @@ read_config_file(const char *filename, const char *host, Options *options)
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
filename, bad_options);
return 1;
}
/*
@ -716,12 +748,14 @@ initialize_options(Options * options)
options->rhosts_authentication = -1;
options->rsa_authentication = -1;
options->pubkey_authentication = -1;
options->challenge_reponse_authentication = -1;
#ifdef KRB4
options->challenge_response_authentication = -1;
#if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1;
#endif
#ifdef AFS
#if defined(AFS) || defined(KRB5)
options->kerberos_tgt_passing = -1;
#endif
#ifdef AFS
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
@ -757,8 +791,12 @@ initialize_options(Options * options)
options->user_hostfile2 = NULL;
options->num_local_forwards = 0;
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->clear_forwardings = -1;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->preferred_authentications = NULL;
options->bind_address = NULL;
options->smartcard_device = NULL;
options->no_host_authentication_for_localhost = - 1;
}
/*
@ -775,10 +813,8 @@ fill_default_options(Options * options)
options->forward_agent = 0;
if (options->forward_x11 == -1)
options->forward_x11 = 0;
#ifdef XAUTH_PATH
if (options->xauth_location == NULL)
options->xauth_location = XAUTH_PATH;
#endif /* XAUTH_PATH */
options->xauth_location = _PATH_XAUTH;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->use_privileged_port == -1)
@ -789,18 +825,20 @@ fill_default_options(Options * options)
options->rsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_reponse_authentication == -1)
options->challenge_reponse_authentication = 0;
#ifdef KRB4
if (options->challenge_response_authentication == -1)
options->challenge_response_authentication = 1;
#if defined(KRB4) || defined(KRB5)
if (options->kerberos_authentication == -1)
options->kerberos_authentication = 1;
#endif /* KRB4 */
#ifdef AFS
#endif
#if defined(AFS) || defined(KRB5)
if (options->kerberos_tgt_passing == -1)
options->kerberos_tgt_passing = 1;
#endif
#ifdef AFS
if (options->afs_token_passing == -1)
options->afs_token_passing = 1;
#endif /* AFS */
#endif
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
@ -828,7 +866,7 @@ fill_default_options(Options * options)
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->connection_attempts == -1)
options->connection_attempts = 4;
options->connection_attempts = 1;
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
/* Selected in ssh_login(). */
@ -871,8 +909,12 @@ fill_default_options(Options * options)
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL)
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
if (options->log_level == (LogLevel) - 1)
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
if (options->clear_forwardings == 1)
clear_forwardings(options);
if (options->no_host_authentication_for_localhost == - 1)
options->no_host_authentication_for_localhost = 0;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */

View File

@ -1,3 +1,5 @@
/* $OpenBSD: readconf.h,v 1.42 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,8 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
#ifndef READCONF_H
#define READCONF_H
@ -39,14 +39,15 @@ typedef struct {
int rsa_authentication; /* Try RSA authentication. */
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int hostbased_authentication; /* ssh2's rhosts_rsa */
int challenge_reponse_authentication;
int challenge_response_authentication;
/* Try S/Key or TIS, authentication. */
#ifdef KRB4
int kerberos_authentication; /* Try Kerberos
* authentication. */
#if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* Try Kerberos authentication. */
#endif
#if defined(AFS) || defined(KRB5)
int kerberos_tgt_passing; /* Try Kerberos TGT passing. */
#endif
#ifdef AFS
int kerberos_tgt_passing; /* Try Kerberos tgt passing. */
int afs_token_passing; /* Try AFS token passing. */
#endif
int password_authentication; /* Try password
@ -80,11 +81,13 @@ typedef struct {
char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
char *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2;
char *user_hostfile2;
char *preferred_authentications;
char *bind_address; /* local socket address for connection to sshd */
char *smartcard_device; /* Smartcard reader device */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
@ -97,56 +100,19 @@ typedef struct {
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
int clear_forwardings;
int no_host_authentication_for_localhost;
} Options;
/*
* Initializes options to special values that indicate that they have not yet
* been set. Read_config_file will only set options with this value. Options
* are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void initialize_options(Options * options);
void initialize_options(Options *);
void fill_default_options(Options *);
int read_config_file(const char *, const char *, Options *);
/*
* Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
void fill_default_options(Options * options);
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set. Returns 0 for legal
* options
*/
int
process_config_line(Options * options, const char *host,
char *line, const char *filename, int linenum,
int *activep);
process_config_line(Options *, const char *, char *, const char *, int, int *);
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
*/
void
read_config_file(const char *filename, const char *host,
Options * options);
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void
add_local_forward(Options * options, u_short port, const char *host,
u_short host_port);
/*
* Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void
add_remote_forward(Options * options, u_short port, const char *host,
u_short host_port);
void add_local_forward(Options *, u_short, const char *, u_short);
void add_remote_forward(Options *, u_short, const char *, u_short);
#endif /* READCONF_H */

View File

@ -1,6 +1,5 @@
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -10,55 +9,51 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
* 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"
RCSID("$OpenBSD: readpass.c,v 1.15 2001/04/18 21:57:41 markus Exp $");
RCSID("$OpenBSD: readpass.c,v 1.26 2002/02/13 00:39:15 markus Exp $");
#include <readpassphrase.h>
#include "xmalloc.h"
#include "cli.h"
#include "readpass.h"
#include "pathnames.h"
#include "log.h"
#include "atomicio.h"
#include "ssh.h"
char *
ssh_askpass(char *askpass, char *msg)
static char *
ssh_askpass(char *askpass, const char *msg)
{
pid_t pid;
size_t len;
char *nl, *pass;
int p[2], status;
char *pass;
int p[2], status, ret;
char buf[1024];
if (fflush(stdout) != 0)
error("ssh_askpass: fflush: %s", strerror(errno));
if (askpass == NULL)
fatal("internal error: askpass undefined");
if (pipe(p) < 0)
fatal("ssh_askpass: pipe: %s", strerror(errno));
if ((pid = fork()) < 0)
fatal("ssh_askpass: fork: %s", strerror(errno));
if (pipe(p) < 0) {
error("ssh_askpass: pipe: %s", strerror(errno));
return xstrdup("");
}
if ((pid = fork()) < 0) {
error("ssh_askpass: fork: %s", strerror(errno));
return xstrdup("");
}
if (pid == 0) {
seteuid(getuid());
setuid(getuid());
@ -69,43 +64,48 @@ ssh_askpass(char *askpass, char *msg)
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
}
close(p[1]);
len = read(p[0], buf, sizeof buf);
len = ret = 0;
do {
ret = read(p[0], buf + len, sizeof(buf) - 1 - len);
if (ret == -1 && errno == EINTR)
continue;
if (ret <= 0)
break;
len += ret;
} while (sizeof(buf) - 1 - len > 0);
buf[len] = '\0';
close(p[0]);
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
if (len <= 1)
return xstrdup("");
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
buf[strcspn(buf, "\r\n")] = '\0';
pass = xstrdup(buf);
memset(buf, 0, sizeof(buf));
return pass;
}
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc), being very careful to ensure that
* no other userland buffer is storing the password.
*/
/*
* Note: the funcationallity of this routing has been moved to
* cli_read_passphrase(). This routing remains to maintain
* compatibility with existing code.
* Reads a passphrase from /dev/tty with echo turned off/on. Returns the
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no
* tty is available
*/
char *
read_passphrase(char *prompt, int from_stdin)
read_passphrase(const char *prompt, int flags)
{
char *askpass = NULL;
int use_askpass = 0, ttyfd;
char *askpass = NULL, *ret, buf[1024];
int rppflags, use_askpass = 0, ttyfd;
if (from_stdin) {
rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
if (flags & RP_ALLOW_STDIN) {
if (!isatty(STDIN_FILENO))
use_askpass = 1;
} else {
ttyfd = open("/dev/tty", O_RDWR);
rppflags |= RPP_REQUIRE_TTY;
ttyfd = open(_PATH_TTY, O_RDWR);
if (ttyfd >= 0)
close(ttyfd);
else
@ -120,5 +120,10 @@ read_passphrase(char *prompt, int from_stdin)
return ssh_askpass(askpass, prompt);
}
return cli_read_passphrase(prompt, from_stdin, 0);
if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL)
return xstrdup("");
ret = xstrdup(buf);
memset(buf, 'x', sizeof buf);
return ret;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readpass.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/* $OpenBSD: readpass.h,v 1.6 2001/06/26 17:27:24 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -12,9 +12,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* from_stdin is true, the passphrase will be read from stdin instead.
*/
char *read_passphrase(char *prompt, int from_stdin);
#define RP_ECHO 0x0001
#define RP_ALLOW_STDIN 0x0002
char *read_passphrase(const char *, int);

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +1,51 @@
/* $OpenBSD: rijndael.h,v 1.7 2001/03/01 03:38:33 deraadt Exp $ */
/* $OpenBSD: rijndael.h,v 1.12 2001/12/19 07:18:56 deraadt Exp $ */
/* This is an independent implementation of the encryption algorithm: */
/* */
/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
/* */
/* which is a candidate algorithm in the Advanced Encryption Standard */
/* programme of the US National Institute of Standards and Technology. */
/* */
/* Copyright in this implementation is held by Dr B R Gladman but I */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions */
/* that the originators of the algorithm place on its exploitation. */
/* */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
/**
* rijndael-alg-fst.h
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS OR CONTRIBUTORS 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.
*/
#ifndef __RIJNDAEL_H
#define __RIJNDAEL_H
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_
#define MAXKC (256/32)
#define MAXKB (256/8)
#define MAXNR 14
/* 1. Standard types for AES cryptography source code */
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef u_int8_t u1byte; /* an 8 bit unsigned character type */
typedef u_int16_t u2byte; /* a 16 bit unsigned integer type */
typedef u_int32_t u4byte; /* a 32 bit unsigned integer type */
typedef int8_t s1byte; /* an 8 bit signed character type */
typedef int16_t s2byte; /* a 16 bit signed integer type */
typedef int32_t s4byte; /* a 32 bit signed integer type */
typedef struct _rijndael_ctx {
u4byte k_len;
int decrypt;
u4byte e_key[64];
u4byte d_key[64];
/* The structure for key information */
typedef struct {
int decrypt;
int Nr; /* key-length-dependent number of rounds */
u32 ek[4*(MAXNR + 1)]; /* encrypt key schedule */
u32 dk[4*(MAXNR + 1)]; /* decrypt key schedule */
} rijndael_ctx;
void rijndael_set_key(rijndael_ctx *, u_char *, int, int);
void rijndael_decrypt(rijndael_ctx *, u_char *, u_char *);
void rijndael_encrypt(rijndael_ctx *, u_char *, u_char *);
/* 2. Standard interface for AES cryptographic routines */
/* These are all based on 32 bit unsigned values and will therefore */
/* require endian conversions for big-endian architectures */
rijndael_ctx *rijndael_set_key __P((rijndael_ctx *, const u4byte *, u4byte, int));
void rijndael_encrypt __P((rijndael_ctx *, const u4byte *, u4byte *));
void rijndael_decrypt __P((rijndael_ctx *, const u4byte *, u4byte *));
#endif /* _RIJNDAEL_H_ */
#endif /* __RIJNDAEL_H */

View File

@ -60,7 +60,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: rsa.c,v 1.22 2001/03/26 23:23:23 markus Exp $");
RCSID("$OpenBSD: rsa.c,v 1.24 2001/12/27 18:22:16 markus Exp $");
#include "rsa.h"
#include "log.h"
@ -120,14 +120,17 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
return len;
}
/* calculate p-1 and q-1 */
void
generate_additional_parameters(RSA *rsa)
rsa_generate_additional_parameters(RSA *rsa)
{
BIGNUM *aux;
BN_CTX *ctx;
/* Generate additional parameters */
aux = BN_new();
ctx = BN_CTX_new();
if ((aux = BN_new()) == NULL)
fatal("rsa_generate_additional_parameters: BN_new failed");
if ((ctx = BN_CTX_new()) == NULL)
fatal("rsa_generate_additional_parameters: BN_CTX_new failed");
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: rsa.h,v 1.15 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,17 +13,14 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
#ifndef RSA_H
#define RSA_H
#include <openssl/bn.h>
#include <openssl/rsa.h>
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
void generate_additional_parameters __P((RSA *rsa));
void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
void rsa_generate_additional_parameters(RSA *);
#endif /* RSA_H */

372
crypto/openssh/scard.c Normal file
View File

@ -0,0 +1,372 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*/
#ifdef SMARTCARD
#include "includes.h"
RCSID("$OpenBSD: scard.c,v 1.17 2001/12/27 18:22:16 markus Exp $");
#include <openssl/engine.h>
#include <sectok.h>
#include "key.h"
#include "log.h"
#include "xmalloc.h"
#include "scard.h"
#define CLA_SSH 0x05
#define INS_DECRYPT 0x10
#define INS_GET_KEYLENGTH 0x20
#define INS_GET_PUBKEY 0x30
#define INS_GET_RESPONSE 0xc0
#define MAX_BUF_SIZE 256
static int sc_fd = -1;
static char *sc_reader_id = NULL;
static int cla = 0x00; /* class */
/* interface to libsectok */
static int
sc_open(void)
{
int sw;
if (sc_fd >= 0)
return sc_fd;
sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
if (sc_fd < 0) {
error("sectok_open failed: %s", sectok_get_sw(sw));
return SCARD_ERROR_FAIL;
}
if (! sectok_cardpresent(sc_fd)) {
debug("smartcard in reader %s not present, skipping",
sc_reader_id);
sc_close();
return SCARD_ERROR_NOCARD;
}
if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
error("sectok_reset failed: %s", sectok_get_sw(sw));
sc_fd = -1;
return SCARD_ERROR_FAIL;
}
if ((cla = cyberflex_inq_class(sc_fd)) < 0)
cla = 0;
debug("sc_open ok %d", sc_fd);
return sc_fd;
}
static int
sc_enable_applet(void)
{
static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
int sw = 0;
/* select applet id */
sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
if (!sectok_swOK(sw)) {
error("sectok_apdu failed: %s", sectok_get_sw(sw));
sc_close();
return -1;
}
return 0;
}
static int
sc_init(void)
{
int status;
status = sc_open();
if (status == SCARD_ERROR_NOCARD) {
return SCARD_ERROR_NOCARD;
}
if (status < 0 ) {
error("sc_open failed");
return status;
}
if (sc_enable_applet() < 0) {
error("sc_enable_applet failed");
return SCARD_ERROR_APPLET;
}
return 0;
}
static int
sc_read_pubkey(Key * k)
{
u_char buf[2], *n;
char *p;
int len, sw, status = -1;
len = sw = 0;
n = NULL;
if (sc_fd < 0) {
status = sc_init();
if (status < 0 )
goto err;
}
/* get key size */
sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
sizeof(buf), buf, &sw);
if (!sectok_swOK(sw)) {
error("could not obtain key length: %s", sectok_get_sw(sw));
goto err;
}
len = (buf[0] << 8) | buf[1];
len /= 8;
debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
n = xmalloc(len);
/* get n */
sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
if (!sectok_swOK(sw)) {
error("could not obtain public key: %s", sectok_get_sw(sw));
goto err;
}
debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
error("c_read_pubkey: BN_bin2bn failed");
goto err;
}
/* currently the java applet just stores 'n' */
if (!BN_set_word(k->rsa->e, 35)) {
error("c_read_pubkey: BN_set_word(e, 35) failed");
goto err;
}
status = 0;
p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
debug("fingerprint %d %s", key_size(k), p);
xfree(p);
err:
if (n != NULL)
xfree(n);
sc_close();
return status;
}
/* private key operations */
static int
sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
{
u_char *padded = NULL;
int sw, len, olen, status = -1;
debug("sc_private_decrypt called");
olen = len = sw = 0;
if (sc_fd < 0) {
status = sc_init();
if (status < 0 )
goto err;
}
if (padding != RSA_PKCS1_PADDING)
goto err;
len = BN_num_bytes(rsa->n);
padded = xmalloc(len);
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
if (!sectok_swOK(sw)) {
error("sc_private_decrypt: INS_DECRYPT failed: %s",
sectok_get_sw(sw));
goto err;
}
sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
len, padded, &sw);
if (!sectok_swOK(sw)) {
error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
sectok_get_sw(sw));
goto err;
}
olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
len);
err:
if (padded)
xfree(padded);
sc_close();
return (olen >= 0 ? olen : status);
}
static int
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
{
u_char *padded = NULL;
int sw, len, status = -1;
len = sw = 0;
if (sc_fd < 0) {
status = sc_init();
if (status < 0 )
goto err;
}
if (padding != RSA_PKCS1_PADDING)
goto err;
debug("sc_private_encrypt called");
len = BN_num_bytes(rsa->n);
padded = xmalloc(len);
if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
error("RSA_padding_add_PKCS1_type_1 failed");
goto err;
}
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
if (!sectok_swOK(sw)) {
error("sc_private_decrypt: INS_DECRYPT failed: %s",
sectok_get_sw(sw));
goto err;
}
sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
len, to, &sw);
if (!sectok_swOK(sw)) {
error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
sectok_get_sw(sw));
goto err;
}
err:
if (padded)
xfree(padded);
sc_close();
return (len >= 0 ? len : status);
}
/* called on free */
static int (*orig_finish)(RSA *rsa) = NULL;
static int
sc_finish(RSA *rsa)
{
if (orig_finish)
orig_finish(rsa);
sc_close();
return 1;
}
/* engine for overloading private key operations */
static ENGINE *smart_engine = NULL;
static RSA_METHOD smart_rsa =
{
"sectok",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
};
ENGINE *
sc_get_engine(void)
{
RSA_METHOD *def;
def = RSA_get_default_openssl_method();
/* overload */
smart_rsa.rsa_priv_enc = sc_private_encrypt;
smart_rsa.rsa_priv_dec = sc_private_decrypt;
/* save original */
orig_finish = def->finish;
smart_rsa.finish = sc_finish;
/* just use the OpenSSL version */
smart_rsa.rsa_pub_enc = def->rsa_pub_enc;
smart_rsa.rsa_pub_dec = def->rsa_pub_dec;
smart_rsa.rsa_mod_exp = def->rsa_mod_exp;
smart_rsa.bn_mod_exp = def->bn_mod_exp;
smart_rsa.init = def->init;
smart_rsa.flags = def->flags;
smart_rsa.app_data = def->app_data;
smart_rsa.rsa_sign = def->rsa_sign;
smart_rsa.rsa_verify = def->rsa_verify;
if ((smart_engine = ENGINE_new()) == NULL)
fatal("ENGINE_new failed");
ENGINE_set_id(smart_engine, "sectok");
ENGINE_set_name(smart_engine, "libsectok");
ENGINE_set_RSA(smart_engine, &smart_rsa);
ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
ENGINE_set_RAND(smart_engine, RAND_SSLeay());
ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
return smart_engine;
}
void
sc_close(void)
{
if (sc_fd >= 0) {
sectok_close(sc_fd);
sc_fd = -1;
}
}
Key *
sc_get_key(const char *id)
{
Key *k;
int status;
if (sc_reader_id != NULL)
xfree(sc_reader_id);
sc_reader_id = xstrdup(id);
k = key_new(KEY_RSA);
if (k == NULL) {
return NULL;
}
status = sc_read_pubkey(k);
if (status == SCARD_ERROR_NOCARD) {
key_free(k);
return NULL;
}
if (status < 0 ) {
error("sc_read_pubkey failed");
key_free(k);
return NULL;
}
return k;
}
#endif /* SMARTCARD */

40
crypto/openssh/scard.h Normal file
View File

@ -0,0 +1,40 @@
/* $OpenBSD: scard.h,v 1.7 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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 <openssl/engine.h>
#ifndef SCARD_H
#define SCARD_H
#define SCARD_ERROR_FAIL -1
#define SCARD_ERROR_NOCARD -2
#define SCARD_ERROR_APPLET -3
Key *sc_get_key(const char*);
ENGINE *sc_get_engine(void);
void sc_close(void);
#endif

View File

@ -0,0 +1,20 @@
# $OpenBSD: Makefile,v 1.2 2001/06/29 07:02:09 markus Exp $
.PATH: ${.CURDIR}/..
CARDLET= Ssh.bin
DATADIR= /usr/libdata/ssh
all: ${CARDLET}
clean:
rm -f ${CARDLET}
install: ${CARDLET}
install -c -m ${LIBMODE} -o ${LIBOWN} -g ${LIBGRP} \
${CARDLET} ${DESTDIR}${DATADIR}
Ssh.bin: ${.CURDIR}/Ssh.bin.uu
uudecode ${.CURDIR}/$@.uu
.include <bsd.prog.mk>

View File

@ -0,0 +1,16 @@
begin 644 Ssh.bin
M`P)!%P`501P`;``!`C@"`/Y@\`4`_J'P!0!!%T$;`?Z@\`4`01=!&@'^>/,!
M`4$701P!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$7L`4`_F'3``!!%T$9
M`?YATP4`_G/5"P7^8=,'`OZAT`$!_J#0$@1!%T$8`0```$$7!`$&`/Y@`;@`
M`$$8\`H(`$$9\`H``$$:\@\``$$;\B$``$$<\A```/`&__(```0(`!8```9C
M""T#"<(H+00$*"T%""A;`&19``#P$/_R`P(&`0#(```38`!!70!&$UP`1@09
M":1+``D*D`!@`"@37`!&!!E6`````*(````$____P````*$````0````*@``
M`"````"-````,````&H37`!&`QD(2@`)"FX`8``H$UP`1@<9"@#_/2!@`$L1
M2@`)"F<`8``H$UP`'A-<`$8($1-<`$8(7@!0"!%@`%59"C\`8`!:*PIS:&``
M6BL37`!&`P,*`(!@`%\K`PH`@&``55D37`!&`P<H$UP`1@0#*`,%8`!565D*
M;0!@`"A9`/`"__(!`0$)``@```J0`&``*%D`\!/_\@$!`@D`#```8D$7+5\`
M/"M9````\!+_]@$!`P$`&```$UP`'EX`,D4`#Q-<`!X*`,@)$%X`-P17L`7_
M\@$!!`(`/```$U\``!-B_J$M7P`%70`*$V+^H"U?``]=`!038OYX+0H$`%\`
<&5T`'@H$`&``(T4`"0IG`&``*!->`"U9````````
`
end

View File

@ -0,0 +1,143 @@
// $Id: Ssh.java,v 1.2 2001/07/30 20:08:14 rees Exp $
//
// Ssh.java
// SSH / smartcard integration project, smartcard side
//
// Tomoko Fukuzawa, created, Feb., 2000
//
// Naomaru Itoi, modified, Apr., 2000
//
// copyright 2000
// the regents of the university of michigan
// all rights reserved
//
// permission is granted to use, copy, create derivative works
// and redistribute this software and such derivative works
// for any purpose, so long as the name of the university of
// michigan is not used in any advertising or publicity
// pertaining to the use or distribution of this software
// without specific, written prior authorization. if the
// above copyright notice or any other identification of the
// university of michigan is included in any copy of any
// portion of this software, then the disclaimer below must
// also be included.
//
// this software is provided as is, without representation
// from the university of michigan as to its fitness for any
// purpose, and without warranty by the university of
// michigan of any kind, either express or implied, including
// without limitation the implied warranties of
// merchantability and fitness for a particular purpose. the
// regents of the university of michigan shall not be liable
// for any damages, including special, indirect, incidental, or
// consequential damages, with respect to any claim arising
// out of or in connection with the use of the software, even
// if it has been or is hereafter advised of the possibility of
// such damages.
import javacard.framework.*;
import javacardx.framework.*;
import javacardx.crypto.*;
public class Ssh extends javacard.framework.Applet
{
/* constants declaration */
// code of CLA byte in the command APDU header
static final byte Ssh_CLA =(byte)0x05;
// codes of INS byte in the command APDU header
static final byte DECRYPT = (byte) 0x10;
static final byte GET_KEYLENGTH = (byte) 0x20;
static final byte GET_PUBKEY = (byte) 0x30;
static final byte GET_RESPONSE = (byte) 0xc0;
/* instance variables declaration */
static final short keysize = 1024;
//RSA_CRT_PrivateKey rsakey;
AsymKey rsakey;
CyberflexFile file;
CyberflexOS os;
byte buffer[];
static byte[] keyHdr = {(byte)0xC2, (byte)0x01, (byte)0x05};
private Ssh()
{
file = new CyberflexFile();
os = new CyberflexOS();
rsakey = new RSA_CRT_PrivateKey (keysize);
if ( ! rsakey.isSupportedLength (keysize) )
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
register();
} // end of the constructor
public boolean select() {
if (!rsakey.isInitialized())
rsakey.setKeyInstance ((short)0xc8, (short)0x10);
return true;
}
public static void install(APDU apdu)
{
new Ssh(); // create a Ssh applet instance (card)
} // end of install method
public static void main(String args[]) {
ISOException.throwIt((short) 0x9000);
}
public void process(APDU apdu)
{
// APDU object carries a byte array (buffer) to
// transfer incoming and outgoing APDU header
// and data bytes between card and CAD
buffer = apdu.getBuffer();
// verify that if the applet can accept this
// APDU message
// NI: change suggested by Wayne Dyksen, Purdue
if (buffer[ISO.OFFSET_INS] == ISO.INS_SELECT)
ISOException.throwIt(ISO.SW_NO_ERROR);
switch (buffer[ISO.OFFSET_INS]) {
case DECRYPT:
if (buffer[ISO.OFFSET_CLA] != Ssh_CLA)
ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);
//decrypt (apdu);
short size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF);
if (apdu.setIncomingAndReceive() != size)
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
rsakey.cryptoUpdate (buffer, (short) ISO.OFFSET_CDATA, size,
buffer, (short) ISO.OFFSET_CDATA);
apdu.setOutgoingAndSend ((short) ISO.OFFSET_CDATA, size);
return;
case GET_PUBKEY:
file.selectFile((short)(0x3f<<8)); // select root
file.selectFile((short)(('s'<<8)|'h')); // select public key file
os.readBinaryFile (buffer, (short)0, (short)0, (short)(keysize/8));
apdu.setOutgoingAndSend((short)0, (short)(keysize/8));
return;
case GET_KEYLENGTH:
buffer[0] = (byte)((keysize >> 8) & 0xff);
buffer[1] = (byte)(keysize & 0xff);
apdu.setOutgoingAndSend ((short)0, (short)2);
return;
case GET_RESPONSE:
return;
default:
ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED);
}
} // end of process method
} // end of class Ssh

View File

@ -9,7 +9,7 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.14 2001/02/04 11:11:53 djm Exp $
.\" $OpenBSD: scp.1,v 1.21 2002/01/29 23:50:37 markus Exp $
.\"
.Dd September 25, 1999
.Dt SCP 1
@ -19,12 +19,13 @@
.Nd secure copy (remote file copy program)
.Sh SYNOPSIS
.Nm scp
.Op Fl pqrvC46
.Op Fl pqrvBC46
.Op Fl F Ar ssh_config
.Op Fl S Ar program
.Op Fl P Ar port
.Op Fl c Ar cipher
.Op Fl i Ar identity_file
.Op Fl o Ar option
.Op Fl o Ar ssh_option
.Sm off
.Oo
.Op Ar user@
@ -92,6 +93,12 @@ Passes the
flag to
.Xr ssh 1
to enable compression.
.It Fl F Ar ssh_config
Specifies an alternative
per-user configuration file for
.Nm ssh .
This option is directly passed to
.Xr ssh 1 .
.It Fl P Ar port
Specifies the port to connect to on the remote host.
Note that this option is written with a capital
@ -107,9 +114,17 @@ to use for the encrypted connection.
The program must understand
.Xr ssh 1
options.
.It Fl o Ar option
The given option is directly passed to
.Xr ssh 1 .
.It Fl o Ar ssh_option
Can be used to pass options to
.Nm ssh
in the format used in the
.Xr ssh 1
configuration file. This is useful for specifying options
for which there is no separate
.Nm scp
command-line flag. For example, forcing the use of protocol
version 1 is specified using
.Ic scp -oProtocol=1 .
.It Fl 4
Forces
.Nm
@ -119,6 +134,9 @@ Forces
.Nm
to use IPv6 addresses only.
.El
.Sh DIAGNOSTICS
.Nm
exits with 0 on success or >0 if an error occurred.
.Sh AUTHORS
Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi>
.Sh HISTORY

View File

@ -75,16 +75,18 @@
*/
#include "includes.h"
RCSID("$OpenBSD: scp.c,v 1.68 2001/04/22 12:34:05 markus Exp $");
RCSID("$OpenBSD: scp.c,v 1.86 2001/12/05 03:56:39 itojun Exp $");
#include "xmalloc.h"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
#include "scp-common.h"
#include "misc.h"
/* For progressmeter() -- number of seconds before xfer considered "stalled" */
#define STALLTIME 5
/* alarm() interval for updating progress meter */
#define PROGRESSTIME 1
/* Visual statistics about files as they are transferred. */
void progressmeter(int);
@ -93,8 +95,8 @@ void progressmeter(int);
int getttywidth(void);
int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
/* setup arguments for the call to ssh */
void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
/* Struct for addargs */
arglist args;
/* Time a transfer started. */
static struct timeval start;
@ -117,13 +119,6 @@ int showprogress = 1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM;
/* This is the list of arguments that scp passes to ssh */
struct {
char **list;
int num;
int nalloc;
} args;
/*
* This function executes the given command as the specified user on the
* given host. This returns < 0 if execution fails, and >= 0 otherwise. This
@ -136,8 +131,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
int pin[2], pout[2], reserved[2];
if (verbose_mode)
fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n",
ssh_program, host, remuser ? remuser : "(unspecified)", cmd);
fprintf(stderr,
"Executing: program %s host %s, user %s, command %s\n",
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
/*
* Reserve two descriptors so that the real pipes won't get
@ -167,9 +164,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
args.list[0] = ssh_program;
if (remuser != NULL)
addargs("-l%s", remuser);
addargs("%s", host);
addargs("%s", cmd);
addargs(&args, "-l%s", remuser);
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
execvp(ssh_program, args.list);
perror(ssh_program);
@ -222,29 +219,32 @@ main(argc, argv)
extern int optind;
args.list = NULL;
addargs("ssh"); /* overwritten with ssh_program */
addargs("-x");
addargs("-oFallBackToRsh no");
addargs(&args, "ssh"); /* overwritten with ssh_program */
addargs(&args, "-x");
addargs(&args, "-oForwardAgent no");
addargs(&args, "-oFallBackToRsh no");
addargs(&args, "-oClearAllForwardings yes");
fflag = tflag = 0;
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1)
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)
switch (ch) {
/* User-visible flags. */
case '4':
case '6':
case 'C':
addargs("-%c", ch);
addargs(&args, "-%c", ch);
break;
case 'o':
case 'c':
case 'i':
addargs("-%c%s", ch, optarg);
case 'F':
addargs(&args, "-%c%s", ch, optarg);
break;
case 'P':
addargs("-p%s", optarg);
addargs(&args, "-p%s", optarg);
break;
case 'B':
addargs("-oBatchmode yes");
addargs(&args, "-oBatchmode yes");
break;
case 'p':
pflag = 1;
@ -256,6 +256,7 @@ main(argc, argv)
ssh_program = xstrdup(optarg);
break;
case 'v':
addargs(&args, "-v");
verbose_mode = 1;
break;
case 'q':
@ -352,13 +353,17 @@ toremote(targ, argc, argv)
for (i = 0; i < argc - 1; i++) {
src = colon(argv[i]);
if (src) { /* remote to remote */
static char *ssh_options =
"-x -o'FallBackToRsh no' "
"-o'ClearAllForwardings yes'";
*src++ = 0;
if (*src == 0)
src = ".";
host = strchr(argv[i], '@');
len = strlen(ssh_program) + strlen(argv[i]) +
strlen(src) + (tuser ? strlen(tuser) : 0) +
strlen(thost) + strlen(targ) + CMDNEEDS + 32;
strlen(thost) + strlen(targ) +
strlen(ssh_options) + CMDNEEDS + 20;
bp = xmalloc(len);
if (host) {
*host++ = 0;
@ -369,19 +374,19 @@ toremote(targ, argc, argv)
else if (!okname(suser))
continue;
snprintf(bp, len,
"%s%s -x -o'FallBackToRsh no' -n "
"%s%s %s -n "
"-l %s %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
suser, host, cmd, src,
ssh_options, suser, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
} else {
host = cleanhostname(argv[i]);
snprintf(bp, len,
"exec %s%s -x -o'FallBackToRsh no' -n %s "
"exec %s%s %s -n %s "
"%s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
host, cmd, src,
ssh_options, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
}
@ -479,6 +484,11 @@ source(argc, argv)
len = strlen(name);
while (len > 1 && name[len-1] == '/')
name[--len] = '\0';
if (strchr(name, '\n') != NULL) {
run_err("%s: skipping, filename contains a newline",
name);
goto next;
}
if ((fd = open(name, O_RDONLY, 0)) < 0)
goto syserr;
if (fstat(fd, &stb) < 0) {
@ -641,7 +651,7 @@ sink(argc, argv)
#define atime tv[0]
#define mtime tv[1]
#define SCREWUP(str) { why = str; goto screwup; }
#define SCREWUP(str) do { why = str; goto screwup; } while (0)
setimes = targisdir = 0;
mask = umask(0);
@ -784,7 +794,7 @@ sink(argc, argv)
}
omode = mode;
mode |= S_IWRITE;
if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) {
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
bad: run_err("%s: %s", np, strerror(errno));
continue;
}
@ -808,7 +818,8 @@ bad: run_err("%s: %s", np, strerror(errno));
count += amt;
do {
j = read(remin, cp, amt);
if (j == -1 && (errno == EINTR || errno == EAGAIN)) {
if (j == -1 && (errno == EINTR ||
errno == EAGAIN)) {
continue;
} else if (j <= 0) {
run_err("%s", j ? strerror(errno) :
@ -839,12 +850,10 @@ bad: run_err("%s: %s", np, strerror(errno));
wrerr = YES;
wrerrno = j >= 0 ? EIO : errno;
}
#if 0
if (ftruncate(ofd, size)) {
run_err("%s: truncate: %s", np, strerror(errno));
wrerr = DISPLAYED;
}
#endif
if (pflag) {
if (exists || omode != mode)
if (fchmod(ofd, omode))
@ -886,7 +895,7 @@ bad: run_err("%s: %s", np, strerror(errno));
}
int
response()
response(void)
{
char ch, *cp, resp, rbuf[2048];
@ -919,10 +928,11 @@ response()
}
void
usage()
usage(void)
{
(void) fprintf(stderr, "usage: scp "
"[-pqrvBC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2\n"
(void) fprintf(stderr,
"usage: scp [-pqrvBC46] [-F config] [-S ssh] [-P port] [-c cipher] [-i identity]\n"
" [-o option] f1 f2\n"
" or: scp [options] f1 ... fn directory\n");
exit(1);
}
@ -932,22 +942,24 @@ run_err(const char *fmt,...)
{
static FILE *fp;
va_list ap;
va_start(ap, fmt);
++errs;
if (fp == NULL && !(fp = fdopen(remout, "w")))
return;
(void) fprintf(fp, "%c", 0x01);
(void) fprintf(fp, "scp: ");
va_start(ap, fmt);
(void) vfprintf(fp, fmt, ap);
va_end(ap);
(void) fprintf(fp, "\n");
(void) fflush(fp);
if (!iamremote) {
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
va_end(ap);
}
void
@ -974,7 +986,7 @@ okname(cp0)
cp = cp0;
do {
c = *cp;
c = (int)*cp;
if (c & 0200)
goto bad;
if (!isalpha(c) && !isdigit(c) &&
@ -1010,6 +1022,7 @@ allocbuf(bp, fd, blksize)
bp->buf = xmalloc(size);
else
bp->buf = xrealloc(bp->buf, size);
memset(bp->buf, 0, size);
bp->cnt = size;
return (bp);
}
@ -1019,32 +1032,25 @@ lostconn(signo)
int signo;
{
if (!iamremote)
fprintf(stderr, "lost connection\n");
exit(1);
write(STDERR_FILENO, "lost connection\n", 16);
if (signo)
_exit(1);
else
exit(1);
}
void
alarmtimer(int wait)
{
struct itimerval itv;
itv.it_value.tv_sec = wait;
itv.it_value.tv_usec = 0;
itv.it_interval = itv.it_value;
setitimer(ITIMER_REAL, &itv, NULL);
}
void
static void
updateprogressmeter(int ignore)
{
int save_errno = errno;
progressmeter(0);
signal(SIGALRM, updateprogressmeter);
alarm(PROGRESSTIME);
errno = save_errno;
}
int
static int
foregroundproc(void)
{
static pid_t pgrp = -1;
@ -1093,8 +1099,10 @@ progressmeter(int flag)
i = barlength * ratio / 100;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"|%.*s%*s|", i,
"*****************************************************************************"
"*****************************************************************************",
"***************************************"
"***************************************"
"***************************************"
"***************************************",
barlength - i, "");
}
i = 0;
@ -1150,9 +1158,9 @@ progressmeter(int flag)
if (flag == -1) {
signal(SIGALRM, updateprogressmeter);
alarmtimer(1);
alarm(PROGRESSTIME);
} else if (flag == 1) {
alarmtimer(0);
alarm(0);
atomicio(write, fileno(stdout), "\n", 1);
statbytes = 0;
}
@ -1168,25 +1176,3 @@ getttywidth(void)
else
return (80);
}
void
addargs(char *fmt, ...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (args.list == NULL) {
args.nalloc = 32;
args.num = 0;
args.list = xmalloc(args.nalloc * sizeof(char *));
} else if (args.num+2 >= args.nalloc) {
args.nalloc *= 2;
args.list = xrealloc(args.list, args.nalloc * sizeof(char *));
}
args.list[args.num++] = xstrdup(buf);
args.list[args.num] = NULL;
}

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.12 2001/04/16 02:31:48 mouring Exp $
# $OpenBSD: Makefile,v 1.13 2001/05/03 23:09:55 mouring Exp $
.PATH: ${.CURDIR}/..
@ -10,6 +10,6 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= scp.1
SRCS= scp.c scp-common.c
SRCS= scp.c misc.c
.include <bsd.prog.mk>

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
/* $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,8 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@ -52,10 +52,10 @@ typedef struct {
* for RhostsRsaAuth */
int print_motd; /* If true, print /etc/motd. */
int print_lastlog; /* If true, print lastlog */
int check_mail; /* If true, check for new mail. */
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start
* searching at */
int x11_use_localhost; /* If true, use localhost for fake X11 server. */
char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */
@ -73,7 +73,7 @@ typedef struct {
int hostbased_uses_name_from_packet_only; /* experimental */
int rsa_authentication; /* If true, permit RSA authentication. */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
#ifdef KRB4
#if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* If true, permit Kerberos
* authentication. */
int kerberos_or_local_passwd; /* If true, permit kerberos
@ -84,15 +84,17 @@ typedef struct {
int kerberos_ticket_cleanup; /* If true, destroy ticket
* file on logout. */
#endif
#ifdef AFS
int kerberos_tgt_passing; /* If true, permit Kerberos tgt
#if defined(AFS) || defined(KRB5)
int kerberos_tgt_passing; /* If true, permit Kerberos TGT
* passing. */
#endif
#ifdef AFS
int afs_token_passing; /* If true, permit AFS token passing. */
#endif
int password_authentication; /* If true, permit password
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
int challenge_reponse_authentication;
int challenge_response_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int use_login; /* If true, login(1) is used */
@ -114,31 +116,26 @@ typedef struct {
int max_startups_rate;
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
int verify_reverse_mapping; /* cross-check ip and dns */
int client_alive_interval; /*
* poke the client this often to
* see if it's still there
* poke the client this often to
* see if it's still there
*/
int client_alive_count_max; /*
*If the client is unresponsive
* for this many intervals, above
* diconnect the session
* If the client is unresponsive
* for this many intervals above,
* disconnect the session
*/
char *authorized_keys_file; /* File containing public keys */
char *authorized_keys_file2;
} ServerOptions;
/*
* Initializes the server options to special values that indicate that they
* have not yet been set.
*/
void initialize_server_options(ServerOptions * options);
/*
* Reads the server configuration file. This only sets the values for those
* options that have the special value indicating they have not been set.
*/
void read_server_config(ServerOptions * options, const char *filename);
void initialize_server_options(ServerOptions *);
void read_server_config(ServerOptions *, const char *);
void fill_default_server_options(ServerOptions *);
int process_server_config_line(ServerOptions *, char *, const char *, int);
/* Sets values for those values that have not yet been set. */
void fill_default_server_options(ServerOptions * options);
#endif /* SERVCONF_H */

Some files were not shown because too many files have changed in this diff Show More