Vendor import of OpenSSH 3.1
This commit is contained in:
parent
1e8db6e2f6
commit
ae1f160d56
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor-crypto/openssh/dist/; revision=92555
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
69
crypto/openssh/README.smartcard
Normal file
69
crypto/openssh/README.smartcard
Normal 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
|
@ -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"
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
116
crypto/openssh/auth-bsdauth.c
Normal file
116
crypto/openssh/auth-bsdauth.c
Normal 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
|
@ -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
|
||||
|
@ -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
273
crypto/openssh/auth-krb5.c
Normal 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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.");
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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':
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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]);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(®, check[i].pat, REG_EXTENDED|REG_NOSUB);
|
||||
if (ret != 0) {
|
||||
regerror(ret, ®, ebuf, sizeof(ebuf));
|
||||
ebuf[sizeof(ebuf)-1] = '\0';
|
||||
error("regerror: %s", ebuf);
|
||||
continue;
|
||||
}
|
||||
ret = regexec(®, version, 0, NULL, 0);
|
||||
regfree(®);
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
40
crypto/openssh/fatal.c
Normal 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();
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)));
|
||||
|
@ -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 */
|
||||
|
@ -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," \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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++; \
|
||||
} \
|
||||
|
@ -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 *);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
372
crypto/openssh/scard.c
Normal 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
40
crypto/openssh/scard.h
Normal 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
|
20
crypto/openssh/scard/Makefile
Normal file
20
crypto/openssh/scard/Makefile
Normal 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>
|
16
crypto/openssh/scard/Ssh.bin.uu
Normal file
16
crypto/openssh/scard/Ssh.bin.uu
Normal 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
|
143
crypto/openssh/scard/Ssh.java
Normal file
143
crypto/openssh/scard/Ssh.java
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
Loading…
Reference in New Issue
Block a user