Say "hi" to the latest in the OpenSSH series, version 2.9!

Happy birthday to:	rwatson
This commit is contained in:
Brian Feldman 2001-05-04 03:57:05 +00:00
parent 5b9b2fafd4
commit 1e8db6e2f6
162 changed files with 16037 additions and 7255 deletions

View file

@ -1,7 +1,7 @@
This file is part of the ssh software.
This file is part of the OpenSSH software.
The licences which components of this software falls under are as
follows. First, we will summarize and say that that all components
The licences which components of this software fall under are as
follows. First, we will summarize and say that all components
are under a BSD licence, or a licence more free than that.
OpenSSH contains no GPL code.
@ -29,7 +29,7 @@ OpenSSH contains no GPL code.
have been removed from OpenSSH, ie.
- RSA is no longer included, found in the OpenSSL library
- IDEA is no longer included, it's use is depricated
- IDEA is no longer included, its use is deprecated
- DES is now external, in the OpenSSL library
- GMP is no longer used, and instead we call BN code from OpenSSL
- Zlib is now external, in a library

View file

@ -1,8 +1,9 @@
# $OpenBSD: Makefile,v 1.6 2000/08/31 21:52:23 markus Exp $
# $OpenBSD: Makefile,v 1.8 2001/02/04 11:11:53 djm Exp $
.include <bsd.own.mk>
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server \
ssh-keyscan sftp
distribution:
install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \

View file

@ -1,3 +1,5 @@
# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $
CFLAGS+= -I${.CURDIR}/..
CFLAGS+= -Wall

View file

@ -1,567 +1,25 @@
[ Please note that this file has not been updated for OpenSSH and
covers the ssh-1.2.12 release from Dec 1995 only. ]
Ssh (Secure Shell) is a program to log into another computer over a
network, to execute commands in a remote machine, and to move files
from one machine to another. It provides strong authentication and
secure communications over insecure channels. It is intended as a
replacement for rlogin, rsh, rcp, and rdist.
See the file INSTALL for installation instructions. See COPYING for
license terms and other legal issues. See RFC for a description of
the protocol. There is a WWW page for ssh; see http://www.cs.hut.fi/ssh.
This file has been updated to match ssh-1.2.12.
FEATURES
o Strong authentication. Closes several security holes (e.g., IP,
routing, and DNS spoofing). New authentication methods: .rhosts
together with RSA based host authentication, and pure RSA
authentication.
o Improved privacy. All communications are automatically and
transparently encrypted. RSA is used for key exchange, and a
conventional cipher (normally IDEA, DES, or triple-DES) for
encrypting the session. Encryption is started before
authentication, and no passwords or other information is
transmitted in the clear. Encryption is also used to protect
against spoofed packets.
o Secure X11 sessions. The program automatically sets DISPLAY on
the server machine, and forwards any X11 connections over the
secure channel. Fake Xauthority information is automatically
generated and forwarded to the remote machine; the local client
automatically examines incoming X11 connections and replaces the
fake authorization data with the real data (never telling the
remote machine the real information).
o Arbitrary TCP/IP ports can be redirected through the encrypted channel
in both directions (e.g., for e-cash transactions).
o No retraining needed for normal users; everything happens
automatically, and old .rhosts files will work with strong
authentication if administration installs host key files.
o Never trusts the network. Minimal trust on the remote side of
the connection. Minimal trust on domain name servers. Pure RSA
authentication never trusts anything but the private key.
o Client RSA-authenticates the server machine in the beginning of
every connection to prevent trojan horses (by routing or DNS
spoofing) and man-in-the-middle attacks, and the server
RSA-authenticates the client machine before accepting .rhosts or
/etc/hosts.equiv authentication (to prevent DNS, routing, or
IP-spoofing).
o Host authentication key distribution can be centrally by the
administration, automatically when the first connection is made
to a machine (the key obtained on the first connection will be
recorded and used for authentication in the future), or manually
by each user for his/her own use. The central and per-user host
key repositories are both used and complement each other. Host
keys can be generated centrally or automatically when the software
is installed. Host authentication keys are typically 1024 bits.
o Any user can create any number of user authentication RSA keys for
his/her own use. Each user has a file which lists the RSA public
keys for which proof of possession of the corresponding private
key is accepted as authentication. User authentication keys are
typically 1024 bits.
o The server program has its own server RSA key which is
automatically regenerated every hour. This key is never saved in
any file. Exchanged session keys are encrypted using both the
server key and the server host key. The purpose of the separate
server key is to make it impossible to decipher a captured session by
breaking into the server machine at a later time; one hour from
the connection even the server machine cannot decipher the session
key. The key regeneration interval is configurable. The server
key is normally 768 bits.
o An authentication agent, running in the user's laptop or local
workstation, can be used to hold the user's RSA authentication
keys. Ssh automatically forwards the connection to the
authentication agent over any connections, and there is no need to
store the RSA authentication keys on any machine in the network
(except the user's own local machine). The authentication
protocols never reveal the keys; they can only be used to verify
that the user's agent has a certain key. Eventually the agent
could rely on a smart card to perform all authentication
computations.
o The software can be installed and used (with restricted
functionality) even without root privileges.
o The client is customizable in system-wide and per-user
configuration files. Most aspects of the client's operation can
be configured. Different options can be specified on a per-host basis.
o Automatically executes conventional rsh (after displaying a
warning) if the server machine is not running sshd.
o Optional compression of all data with gzip (including forwarded X11
and TCP/IP port data), which may result in significant speedups on
slow connections.
o Complete replacement for rlogin, rsh, and rcp.
WHY TO USE SECURE SHELL
Currently, almost all communications in computer networks are done
without encryption. As a consequence, anyone who has access to any
machine connected to the network can listen in on any communication.
This is being done by hackers, curious administrators, employers,
criminals, industrial spies, and governments. Some networks leak off
enough electromagnetic radiation that data may be captured even from a
distance.
When you log in, your password goes in the network in plain
text. Thus, any listener can then use your account to do any evil he
likes. Many incidents have been encountered worldwide where crackers
have started programs on workstations without the owners knowledge
just to listen to the network and collect passwords. Programs for
doing this are available on the Internet, or can be built by a
competent programmer in a few hours.
Any information that you type or is printed on your screen can be
monitored, recorded, and analyzed. For example, an intruder who has
penetrated a host connected to a major network can start a program
that listens to all data flowing in the network, and whenever it
encounters a 16-digit string, it checks if it is a valid credit card
number (using the check digit), and saves the number plus any
surrounding text (to catch expiration date and holder) in a file.
When the intruder has collected a few thousand credit card numbers, he
makes smallish mail-order purchases from a few thousand stores around
the world, and disappears when the goods arrive but before anyone
suspects anything.
Businesses have trade secrets, patent applications in preparation,
pricing information, subcontractor information, client data, personnel
data, financial information, etc. Currently, anyone with access to
the network (any machine on the network) can listen to anything that
goes in the network, without any regard to normal access restrictions.
Many companies are not aware that information can so easily be
recovered from the network. They trust that their data is safe
since nobody is supposed to know that there is sensitive information
in the network, or because so much other data is transferred in the
network. This is not a safe policy.
Individual persons also have confidential information, such as
diaries, love letters, health care documents, information about their
personal interests and habits, professional data, job applications,
tax reports, political documents, unpublished manuscripts, etc.
One should also be aware that economical intelligence and industrial
espionage has recently become a major priority of the intelligence
agencies of major governments. President Clinton recently assigned
economical espionage as the primary task of the CIA, and the French
have repeatedly been publicly boasting about their achievements on
this field.
There is also another frightening aspect about the poor security of
communications. Computer storage and analysis capability has
increased so much that it is feasible for governments, major
companies, and criminal organizations to automatically analyze,
identify, classify, and file information about millions of people over
the years. Because most of the work can be automated, the cost of
collecting this information is getting very low.
Government agencies may be able to monitor major communication
systems, telephones, fax, computer networks, etc., and passively
collect huge amounts of information about all people with any
significant position in the society. Most of this information is not
sensitive, and many people would say there is no harm in someone
getting that information. However, the information starts to get
sensitive when someone has enough of it. You may not mind someone
knowing what you bought from the shop one random day, but you might
not like someone knowing every small thing you have bought in the last
ten years.
If the government some day starts to move into a more totalitarian
direction (one should remember that Nazi Germany was created by
democratic elections), there is considerable danger of an ultimate
totalitarian state. With enough information (the automatically
collected records of an individual can be manually analyzed when the
person becomes interesting), one can form a very detailed picture of
the individual's interests, opinions, beliefs, habits, friends,
lovers, weaknesses, etc. This information can be used to 1) locate
any persons who might oppose the new system 2) use deception to
disturb any organizations which might rise against the government 3)
eliminate difficult individuals without anyone understanding what
happened. Additionally, if the government can monitor communications
too effectively, it becomes too easy to locate and eliminate any
persons distributing information contrary to the official truth.
Fighting crime and terrorism are often used as grounds for domestic
surveillance and restricting encryption. These are good goals, but
there is considerable danger that the surveillance data starts to get
used for questionable purposes. I find that it is better to tolerate
a small amount of crime in the society than to let the society become
fully controlled. I am in favor of a fairly strong state, but the
state must never get so strong that people become unable to spread
contra-offical information and unable to overturn the government if it
is bad. The danger is that when you notice that the government is
too powerful, it is too late. Also, the real power may not be where
the official government is.
For these reasons (privacy, protecting trade secrets, and making it
more difficult to create a totalitarian state), I think that strong
cryptography should be integrated to the tools we use every day.
Using it causes no harm (except for those who wish to monitor
everything), but not using it can cause huge problems. If the society
changes in undesirable ways, then it will be to late to start
encrypting.
Encryption has had a "military" or "classified" flavor to it. There
are no longer any grounds for this. The military can and will use its
own encryption; that is no excuse to prevent the civilians from
protecting their privacy and secrets. Information on strong
encryption is available in every major bookstore, scientific library,
and patent office around the world, and strong encryption software is
available in every country on the Internet.
Some people would like to make it illegal to use encryption, or to
force people to use encryption that governments can break. This
approach offers no protection if the government turns bad. Also, the
"bad guys" will be using true strong encryption anyway. Good
encryption techniques are too widely known to make them disappear.
Thus, any "key escrow encryption" or other restrictions will only help
monitor ordinary people and petty criminals. It does not help against
powerful criminals, terrorists, or espionage, because they will know
how to use strong encryption anyway. (One source for internationally
available encryption software is http://www.cs.hut.fi/crypto.)
OVERVIEW OF SECURE SHELL
The software consists of a number of programs.
sshd Server program run on the server machine. This
listens for connections from client machines, and
whenever it receives a connection, it performs
authentication and starts serving the client.
ssh This is the client program used to log into another
machine or to execute commands on the other machine.
"slogin" is another name for this program.
scp Securely copies files from one machine to another.
ssh-keygen Used to create RSA keys (host keys and user
authentication keys).
ssh-agent Authentication agent. This can be used to hold RSA
keys for authentication.
ssh-add Used to register new keys with the agent.
make-ssh-known-hosts
Used to create the /etc/ssh_known_hosts file.
Ssh is the program users normally use. It is started as
ssh host
or
ssh host command
The first form opens a new shell on the remote machine (after
authentication). The latter form executes the command on the remote
machine.
When started, the ssh connects sshd on the server machine, verifies
that the server machine really is the machine it wanted to connect,
exchanges encryption keys (in a manner which prevents an outside
listener from getting the keys), performs authentication using .rhosts
and /etc/hosts.equiv, RSA authentication, or conventional password
based authentication. The server then (normally) allocates a
pseudo-terminal and starts an interactive shell or user program.
The TERM environment variable (describing the type of the user's
terminal) is passed from the client side to the remote side. Also,
terminal modes will be copied from the client side to the remote side
to preserve user preferences (e.g., the erase character).
If the DISPLAY variable is set on the client side, the server will
create a dummy X server and set DISPLAY accordingly. Any connections
to the dummy X server will be forwarded through the secure channel,
and will be made to the real X server from the client side. An
arbitrary number of X programs can be started during the session, and
starting them does not require anything special from the user. (Note
that the user must not manually set DISPLAY, because then it would
connect directly to the real display instead of going through the
encrypted channel). This behavior can be disabled in the
configuration file or by giving the -x option to the client.
Arbitrary IP ports can be forwarded over the secure channel. The
program then creates a port on one side, and whenever a connection is
opened to this port, it will be passed over the secure channel, and a
connection will be made from the other side to a specified host:port
pair. Arbitrary IP forwarding must always be explicitly requested,
and cannot be used to forward privileged ports (unless the user is
root). It is possible to specify automatic forwards in a per-user
configuration file, for example to make electronic cash systems work
securely.
If there is an authentication agent on the client side, connection to
it will be automatically forwarded to the server side.
For more infomation, see the manual pages ssh(1), sshd(8), scp(1),
ssh-keygen(1), ssh-agent(1), ssh-add(1), and make-ssh-known-hosts(1)
included in this distribution.
X11 CONNECTION FORWARDING
X11 forwarding serves two purposes: it is a convenience to the user
because there is no need to set the DISPLAY variable, and it provides
encrypted X11 connections. I cannot think of any other easy way to
make X11 connections encrypted; modifying the X server, clients or
libraries would require special work for each machine, vendor and
application. Widely used IP-level encryption does not seem likely for
several years. Thus what we have left is faking an X server on the
same machine where the clients are run, and forwarding the connections
to a real X server over the secure channel.
X11 forwarding works as follows. The client extracts Xauthority
information for the server. It then creates random authorization
data, and sends the random data to the server. The server allocates
an X11 display number, and stores the (fake) Xauthority data for this
display. Whenever an X11 connection is opened, the server forwards
the connection over the secure channel to the client, and the client
parses the first packet of the X11 protocol, substitutes real
authentication data for the fake data (if the fake data matched), and
forwards the connection to the real X server.
If the display does not have Xauthority data, the server will create a
unix domain socket in /tmp/.X11-unix, and use the unix domain socket
as the display. No authentication information is forwarded in this
case. X11 connections are again forwarded over the secure channel.
To the X server the connections appear to come from the client
machine, and the server must have connections allowed from the local
machine. Using authentication data is always recommended because not
using it makes the display insecure. If XDM is used, it automatically
generates the authentication data.
One should be careful not to use "xin" or "xstart" or other similar
scripts that explicitly set DISPLAY to start X sessions in a remote
machine, because the connection will then not go over the secure
channel. The recommended way to start a shell in a remote machine is
xterm -e ssh host &
and the recommended way to execute an X11 application in a remote
machine is
ssh -n host emacs &
If you need to type a password/passphrase for the remote machine,
ssh -f host emacs
may be useful.
RSA AUTHENTICATION
RSA authentication is based on public key cryptograpy. The idea is
that there are two encryption keys, one for encryption and another for
decryption. It is not possible (on human timescale) to derive the
decryption key from the encryption key. The encryption key is called
the public key, because it can be given to anyone and it is not
secret. The decryption key, on the other hand, is secret, and is
called the private key.
RSA authentication is based on the impossibility of deriving the
private key from the public key. The public key is stored on the
server machine in the user's $HOME/.ssh/authorized_keys file. The
private key is only kept on the user's local machine, laptop, or other
secure storage. Then the user tries to log in, the client tells the
server the public key that the user wishes to use for authentication.
The server then checks if this public key is admissible. If so, it
generates a 256 bit random number, encrypts it with the public key,
and sends the value to the client. The client then decrypts the
number with its private key, computes a 128 bit MD5 checksum from the
resulting data, and sends the checksum back to the server. (Only a
checksum is sent to prevent chosen-plaintext attacks against RSA.)
The server checks computes a checksum from the correct data,
and compares the checksums. Authentication is accepted if the
checksums match. (Theoretically this indicates that the client
only probably knows the correct key, but for all practical purposes
there is no doubt.)
The RSA private key can be protected with a passphrase. The
passphrase can be any string; it is hashed with MD5 to produce an
encryption key for IDEA, which is used to encrypt the private part of
the key file. With passphrase, authorization requires access to the key
file and the passphrase. Without passphrase, authorization only
depends on possession of the key file.
RSA authentication is the most secure form of authentication supported
by this software. It does not rely on the network, routers, domain
name servers, or the client machine. The only thing that matters is
access to the private key.
All this, of course, depends on the security of the RSA algorithm
itself. RSA has been widely known since about 1978, and no effective
methods for breaking it are known if it is used properly. Care has
been taken to avoid the well-known pitfalls. Breaking RSA is widely
believed to be equivalent to factoring, which is a very hard
mathematical problem that has received considerable public research.
So far, no effective methods are known for numbers bigger than about
512 bits. However, as computer speeds and factoring methods are
increasing, 512 bits can no longer be considered secure. The
factoring work is exponential, and 768 or 1024 bits are widely
considered to be secure in the near future.
RHOSTS AUTHENTICATION
Conventional .rhosts and hosts.equiv based authentication mechanisms
are fundamentally insecure due to IP, DNS (domain name server) and
routing spoofing attacks. Additionally this authentication method
relies on the integrity of the client machine. These weaknesses is
tolerable, and been known and exploited for a long time.
Ssh provides an improved version of these types of authentication,
because they are very convenient for the user (and allow easy
transition from rsh and rlogin). It permits these types of
authentication, but additionally requires that the client host be
authenticated using RSA.
The server has a list of host keys stored in /etc/ssh_known_host, and
additionally each user has host keys in $HOME/.ssh/known_hosts. Ssh
uses the name servers to obtain the canonical name of the client host,
looks for its public key in its known host files, and requires the
client to prove that it knows the private host key. This prevents IP
and routing spoofing attacks (as long as the client machine private
host key has not been compromized), but is still vulnerable to DNS
attacks (to a limited extent), and relies on the integrity of the
client machine as to who is requesting to log in. This prevents
outsiders from attacking, but does not protect against very powerful
attackers. If maximal security is desired, only RSA authentication
should be used.
It is possible to enable conventional .rhosts and /etc/hosts.equiv
authentication (without host authentication) at compile time by giving
the option --with-rhosts to configure. However, this is not
recommended, and is not done by default.
These weaknesses are present in rsh and rlogin. No improvement in
security will be obtained unless rlogin and rsh are completely
disabled (commented out in /etc/inetd.conf). This is highly
recommended.
WEAKEST LINKS IN SECURITY
One should understand that while this software may provide
cryptographically secure communications, it may be easy to
monitor the communications at their endpoints.
Basically, anyone with root access on the local machine on which you
are running the software may be able to do anything. Anyone with root
access on the server machine may be able to monitor your
communications, and a very talented root user might even be able to
send his/her own requests to your authentication agent.
One should also be aware that computers send out electromagnetic
radition that can sometimes be picked up hundreds of meters away.
Your keyboard is particularly easy to listen to. The image on your
monitor might also be seen on another monitor in a van parked behind
your house.
Beware that unwanted visitors might come to your home or office and
use your machine while you are away. They might also make
modifications or install bugs in your hardware or software.
Beware that the most effective way for someone to decrypt your data
may be with a rubber hose.
LEGAL ISSUES
As far as I am concerned, anyone is permitted to use this software
freely. However, see the file COPYING for detailed copying,
licensing, and distribution information.
In some countries, particularly France, Russia, Iraq, and Pakistan,
it may be illegal to use any encryption at all without a special
permit, and the rumor has it that you cannot get a permit for any
strong encryption.
This software may be freely imported into the United States; however,
the United States Government may consider re-exporting it a criminal
offence.
Note that any information and cryptographic algorithms used in this
software are publicly available on the Internet and at any major
bookstore, scientific library, or patent office worldwide.
THERE IS NO WARRANTY FOR THIS PROGRAM. Please consult the file
COPYING for more information.
MAILING LISTS AND OTHER INFORMATION
There is a mailing list for ossh. It is ossh@sics.se. If you would
like to join, send a message to majordomo@sics.se with "subscribe
ssh" in body.
The WWW home page for ssh is http://www.cs.hut.fi/ssh. It contains an
archive of the mailing list, and detailed information about new
releases, mailing lists, and other relevant issues.
Bug reports should be sent to ossh-bugs@sics.se.
ABOUT THE AUTHOR
This software was written by Tatu Ylonen <ylo@cs.hut.fi>. I work as a
researcher at Helsinki University of Technology, Finland. For more
information, see http://www.cs.hut.fi/~ylo/. My PGP public key is
available via finger from ylo@cs.hut.fi and from the key servers. I
prefer PGP encrypted mail.
The author can be contacted via ordinary mail at
Tatu Ylonen
Helsinki University of Technology
Otakaari 1
FIN-02150 ESPOO
Finland
Fax. +358-0-4513293
ACKNOWLEDGEMENTS
I thank Tero Kivinen, Timo Rinne, Janne Snabb, and Heikki Suonsivu for
their help and comments in the design, implementation and porting of
this software. I also thank numerous contributors, including but not
limited to Walker Aumann, Jurgen Botz, Hans-Werner Braun, Stephane
Bortzmeyer, Adrian Colley, Michael Cooper, David Dombek, Jerome
Etienne, Bill Fithen, Mark Fullmer, Bert Gijsbers, Andreas Gustafsson,
Michael Henits, Steve Johnson, Thomas Koenig, Felix Leitner, Gunnar
Lindberg, Andrew Macpherson, Marc Martinec, Paul Mauvais, Donald
McKillican, Leon Mlakar, Robert Muchsel, Mark Treacy, Bryan
O'Sullivan, Mikael Suokas, Ollivier Robert, Jakob Schlyter, Tomasz
Surmacz, Alvar Vinacua, Petri Virkkula, Michael Warfield, and
Cristophe Wolfhugel.
Thanks also go to Philip Zimmermann, whose PGP software and the
associated legal battle provided inspiration, motivation, and many
useful techniques, and to Bruce Schneier whose book Applied
Cryptography has done a great service in widely distributing knowledge
about cryptographic methods.
Copyright (c) 1995 Tatu Ylonen, Espoo, Finland.
This release of OpenSSH is for OpenBSD systems only.
Please read
http://www.openssh.com/portable.html
if you want to install OpenSSH on other operating systems.
To extract and install this release on your OpenBSD system use:
# cd /usr/src/usr.bin
# tar xvfz .../openssh-x.y.tgz
# cd ssh
# make obj
# make cleandir
# make depend
# make
# make install
# cp ssh_config sshd_config /etc
OpenSSH is a derivative of the original and free ssh 1.2.12 release
by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels
Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer
features and created OpenSSH. Markus Friedl contributed the support
for SSH protocol versions 1.5 and 2.0.
See http://www.openssh.com/ for more information.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995,1999 Theo de Raadt
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -24,10 +24,10 @@
*/
#include "includes.h"
RCSID("$OpenBSD: atomicio.c,v 1.7 2000/10/18 18:04:02 markus Exp $");
RCSID("$OpenBSD: atomicio.c,v 1.9 2001/03/02 18:54:30 deraadt Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==write

31
crypto/openssh/atomicio.h Normal file
View file

@ -0,0 +1,31 @@
/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* 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.
*/
/*
* 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);

104
crypto/openssh/auth-chall.c Normal file
View file

@ -0,0 +1,104 @@
/*
* 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-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
#include "auth.h"
#include "log.h"
#ifdef BSD_AUTH
char *
get_challenge(Authctxt *authctxt, char *devs)
{
char *challenge;
if (authctxt->as != NULL) {
debug2("try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
if (challenge != NULL) {
debug2("reuse bsd auth session");
return challenge;
}
auth_close(authctxt->as);
authctxt->as = NULL;
}
debug2("new bsd auth session");
if (devs == NULL || strlen(devs) == 0)
devs = authctxt->style;
debug3("bsd auth: devs %s", devs ? devs : "<default>");
authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
&challenge);
if (authctxt->as == NULL)
return NULL;
debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
return challenge;
}
int
verify_response(Authctxt *authctxt, char *response)
{
int authok;
if (authctxt->as == 0)
error("verify_response: no bsd auth session");
authok = auth_userresponse(authctxt->as, response, 0);
authctxt->as = NULL;
debug("verify_response: <%s> = <%d>", response, authok);
return authok != 0;
}
#else
#ifdef SKEY
#include <skey.h>
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;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return (authctxt->valid &&
skey_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, response) != -1);
}
#else
/* not available */
char *
get_challenge(Authctxt *authctxt, char *devs)
{
return NULL;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return 0;
}
#endif
#endif

View file

@ -23,12 +23,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
#include "packet.h"
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.19 2000/10/03 18:03:02 markus Exp $");
#ifdef AFS
#include "radix.h"
#endif
#ifdef KRB4
char *ticket = NULL;
@ -46,7 +53,7 @@ auth_krb4_password(struct passwd * pw, const char *password)
AUTH_DAT adata;
KTEXT_ST tkt;
struct hostent *hp;
unsigned long faddr;
u_long faddr;
char localhost[MAXHOSTNAMELEN];
char phost[INST_SZ];
char realm[REALM_SZ];

View file

@ -2,10 +2,6 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* RSA-based authentication. This code determines whether to admit a login
* based on RSA authentication. This file also contains functions to check
* validity of the host key.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
@ -14,12 +10,16 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-options.c,v 1.5 2000/10/09 21:32:34 markus Exp $");
RCSID("$OpenBSD: auth-options.c,v 1.16 2001/03/18 12:07:52 markus Exp $");
#include "ssh.h"
#include "packet.h"
#include "xmalloc.h"
#include "match.h"
#include "log.h"
#include "canohost.h"
#include "channels.h"
#include "auth-options.h"
#include "servconf.h"
/* Flags set authorized_keys flags */
int no_port_forwarding_flag = 0;
@ -33,6 +33,8 @@ char *forced_command = NULL;
/* "environment=" options. */
struct envstring *custom_environment = NULL;
extern ServerOptions options;
void
auth_clear_options(void)
{
@ -50,105 +52,113 @@ auth_clear_options(void)
xfree(forced_command);
forced_command = NULL;
}
channel_clear_permitted_opens();
}
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
/*
* return 1 if access is granted, 0 if not.
* side effect: sets key option flags
*/
int
auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
{
const char *cp;
if (!options)
return 1;
int i;
/* reset options */
auth_clear_options();
while (*options && *options != ' ' && *options != '\t') {
if (!opts)
return 1;
while (*opts && *opts != ' ' && *opts != '\t') {
cp = "no-port-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
no_port_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-agent-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Agent forwarding disabled.");
no_agent_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-X11-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("X11 forwarding disabled.");
no_x11_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-pty";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Pty allocation disabled.");
no_pty_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "command=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
options += strlen(cp);
forced_command = xmalloc(strlen(options) + 1);
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
opts += strlen(cp);
forced_command = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
forced_command[i++] = '"';
continue;
}
forced_command[i++] = *options++;
forced_command[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(forced_command);
forced_command = NULL;
goto bad_option;
}
forced_command[i] = 0;
packet_send_debug("Forced command: %.900s", forced_command);
options++;
opts++;
goto next_option;
}
cp = "environment=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
char *s;
struct envstring *new_envstring;
options += strlen(cp);
s = xmalloc(strlen(options) + 1);
opts += strlen(cp);
s = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
s[i++] = '"';
continue;
}
s[i++] = *options++;
s[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(s);
goto bad_option;
}
s[i] = 0;
packet_send_debug("Adding to environment: %.900s", s);
debug("Adding to environment: %.900s", s);
options++;
opts++;
new_envstring = xmalloc(sizeof(struct envstring));
new_envstring->s = s;
new_envstring->next = custom_environment;
@ -156,66 +166,125 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
goto next_option;
}
cp = "from=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int mname, mip;
char *patterns = xmalloc(strlen(options) + 1);
int i;
options += strlen(cp);
const char *remote_ip = get_remote_ipaddr();
const char *remote_host = get_canonical_hostname(
options.reverse_mapping_check);
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *options++;
patterns[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(patterns);
goto bad_option;
}
patterns[i] = 0;
options++;
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(get_canonical_hostname(),
patterns, strlen(patterns));
mip = match_hostname(get_remote_ipaddr(),
patterns, strlen(patterns));
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)) {
log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
pw->pw_name, get_canonical_hostname(),
get_remote_ipaddr());
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
get_canonical_hostname());
log("Authentication tried for %.100s with "
"correct key but not from a permitted "
"host (host=%.200s, ip=%.200s).",
pw->pw_name, remote_host, remote_ip);
packet_send_debug("Your host '%.200s' is not "
"permitted to use this key for login.",
remote_host);
/* deny access */
return 0;
}
/* Host name matches. */
goto next_option;
}
cp = "permitopen=\"";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
u_short port;
char *c, *ep;
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
i = 0;
while (*opts) {
if (*opts == '"')
break;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *opts++;
}
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
file, linenum);
xfree(patterns);
goto bad_option;
}
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);
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);
xfree(patterns);
goto bad_option;
}
if (options.allow_tcp_forwarding)
channel_add_permitted_opens(patterns, port);
xfree(patterns);
goto next_option;
}
next_option:
/*
* Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (!*options)
if (!*opts)
fatal("Bugs in auth-options.c option processing.");
if (*options == ' ' || *options == '\t')
if (*opts == ' ' || *opts == '\t')
break; /* End of options. */
if (*options != ',')
if (*opts != ',')
goto bad_option;
options++;
opts++;
/* Process the next option. */
}
/* grant access */
@ -223,9 +292,9 @@ next_option:
bad_option:
log("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
file, linenum, opts);
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
file, linenum, opts);
/* deny access */
return 0;
}

View file

@ -11,10 +11,17 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: auth-options.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: auth-options.h,v 1.8 2001/01/21 19:05:42 markus Exp $ */
#ifndef AUTH_OPTIONS_H
#define AUTH_OPTIONS_H
/* Linked list of custom environment strings */
struct envstring {
struct envstring *next;
char *s;
};
/* Flags that may be set in authorized_keys options. */
extern int no_port_forwarding_flag;
extern int no_agent_forwarding_flag;
@ -23,8 +30,14 @@ 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, unsigned long linenum);
/*
* 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 */
void auth_clear_options(void);

View file

@ -11,30 +11,7 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999 Dug Song. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -59,39 +36,42 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-passwd.c,v 1.18 2000/10/03 18:03:03 markus Exp $");
RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $");
#include "packet.h"
#include "ssh.h"
#include "servconf.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
extern ServerOptions options;
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int
auth_password(struct passwd * pw, const char *password)
auth_password(Authctxt *authctxt, const char *password)
{
extern ServerOptions options;
struct passwd * pw = authctxt->pw;
char *encrypted_password;
/* deny if no user. */
if (pw == NULL)
return 0;
if (pw->pw_uid == 0 && options.permit_root_login == 2)
if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
return 0;
if (*password == '\0' && options.permit_empty_passwd == 0)
return 0;
#ifdef SKEY_VIA_PASSWD_IS_DISABLED
if (options.skey_authentication == 1) {
int ret = auth_skey_password(pw, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#ifdef BSD_AUTH
if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
(char *)password) == 0)
return 0;
else
return 1;
#endif
#ifdef KRB4
if (options.kerberos_authentication == 1) {
int ret = auth_krb4_password(pw, password);

View file

@ -13,18 +13,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $");
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
#include "packet.h"
#include "ssh.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "log.h"
#include "servconf.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h"
#include "hostfile.h"
#include "pathnames.h"
#include "auth.h"
#include "tildexpand.h"
#include "canohost.h"
/*
* Tries to authenticate the user using the .rhosts file and the host using
@ -48,26 +49,27 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
if (!auth_rhosts(pw, client_user))
return 0;
canonical_hostname = get_canonical_hostname();
canonical_hostname = get_canonical_hostname(
options.reverse_mapping_check);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
/* wrap the RSA key into a 'generic' key */
client_key = key_new(KEY_RSA);
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_RSA);
found = key_new(KEY_RSA1);
/* Check if we know the host and its host key. */
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
client_key, found);
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(SSH_USER_HOSTFILE, pw->pw_uid);
char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
/*
* Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
* 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 &&
@ -78,9 +80,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
pw->pw_name, user_hostfile);
} else {
/* XXX race between stat and the following open() */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
client_key, found);
client_key, found, NULL);
restore_uid();
}
xfree(user_hostfile);

View file

@ -14,13 +14,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rhosts.c,v 1.16 2000/10/03 18:03:03 markus Exp $");
RCSID("$OpenBSD: auth-rhosts.c,v 1.23 2001/04/12 19:15:24 markus Exp $");
#include "packet.h"
#include "ssh.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
#include "canohost.h"
#include "auth.h"
/* import */
extern ServerOptions options;
/*
* This function processes an rhosts-style file (.rhosts, .shosts, or
@ -147,18 +153,33 @@ check_rhosts_file(const char *filename, const char *hostname,
int
auth_rhosts(struct passwd *pw, const char *client_user)
{
extern ServerOptions options;
char buf[1024];
const char *hostname, *ipaddr;
int ret;
hostname = get_canonical_hostname(options.reverse_mapping_check);
ipaddr = get_remote_ipaddr();
ret = auth_rhosts2(pw, client_user, hostname, ipaddr);
return ret;
}
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr)
{
char buf[1024];
struct stat st;
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
unsigned int rhosts_file_index;
u_int rhosts_file_index;
debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
client_user, hostname, ipaddr);
/* no user given */
if (pw == NULL)
return 0;
/* Switch to the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/*
* Quick check: if the user has no .shosts or .rhosts files, return
* failure immediately without doing costly lookups from name
@ -177,25 +198,22 @@ auth_rhosts(struct passwd *pw, const char *client_user)
/* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
if (!rhosts_files[rhosts_file_index] &&
stat("/etc/hosts.equiv", &st) < 0 &&
stat(SSH_HOSTS_EQUIV, &st) < 0)
stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
return 0;
hostname = get_canonical_hostname();
ipaddr = get_remote_ipaddr();
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
if (pw->pw_uid != 0) {
if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
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);
return 1;
}
if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
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, SSH_HOSTS_EQUIV);
hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
return 1;
}
}
@ -220,7 +238,7 @@ auth_rhosts(struct passwd *pw, const char *client_user)
return 0;
}
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/* Check all .rhosts files (currently .shosts and .rhosts). */
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];

View file

@ -14,21 +14,23 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rsa.c,v 1.32 2000/10/14 12:19:45 markus Exp $");
#include "rsa.h"
#include "packet.h"
#include "xmalloc.h"
#include "ssh.h"
#include "mpaux.h"
#include "uidswap.h"
#include "match.h"
#include "servconf.h"
#include "auth-options.h"
RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/md5.h>
#include "rsa.h"
#include "packet.h"
#include "xmalloc.h"
#include "ssh1.h"
#include "mpaux.h"
#include "uidswap.h"
#include "match.h"
#include "auth-options.h"
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
/* import */
extern ServerOptions options;
@ -37,7 +39,7 @@ extern ServerOptions options;
* Session identifier that is used to bind key exchange and authentication
* responses to a particular session.
*/
extern unsigned char session_id[16];
extern u_char session_id[16];
/*
* The .ssh/authorized_keys file contains public keys, one per line, in the
@ -60,9 +62,9 @@ auth_rsa_challenge_dialog(RSA *pk)
{
BIGNUM *challenge, *encrypted_challenge;
BN_CTX *ctx;
unsigned char buf[32], mdbuf[16], response[16];
u_char buf[32], mdbuf[16], response[16];
MD5_CTX md;
unsigned int i;
u_int i;
int plen, len;
encrypted_challenge = BN_new();
@ -120,11 +122,11 @@ auth_rsa_challenge_dialog(RSA *pk)
int
auth_rsa(struct passwd *pw, BIGNUM *client_n)
{
char line[8192], file[1024];
char line[8192], file[MAXPATHLEN];
int authenticated;
unsigned int bits;
u_int bits;
FILE *f;
unsigned long linenum = 0;
u_long linenum = 0;
struct stat st;
RSA *pk;
@ -133,11 +135,11 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
return 0;
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
SSH_USER_PERMITTED_KEYS);
_PATH_SSH_USER_PERMITTED_KEYS);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
@ -165,10 +167,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
"bad ownership or modes for '%s'.", pw->pw_name, file);
fail = 1;
} else {
/* Check path to SSH_USER_PERMITTED_KEYS */
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", SSH_USER_DIR, NULL
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
@ -184,8 +186,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
}
if (fail) {
fclose(f);
log("%s",buf);
packet_send_debug("%s",buf);
log("%s", buf);
packet_send_debug("%s", buf);
restore_uid();
return 0;
}
@ -231,19 +233,13 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
}
} else
options = NULL;
/*
* If our options do not allow this key to be used,
* do not send challenge.
*/
if (!auth_parse_options(pw, options, linenum))
continue;
/* Parse the key from the line. */
if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
continue;
}
/* cp now points to the comment part. */
@ -259,6 +255,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
file, linenum, BN_num_bits(pk->n), bits);
/* We have found the desired key. */
/*
* If our options do not allow this key to be used,
* do not send challenge.
*/
if (!auth_parse_options(pw, options, file, linenum))
continue;
/* Perform the challenge-response dialog for this key. */
if (!auth_rsa_challenge_dialog(pk)) {

View file

@ -1,15 +1,5 @@
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -33,34 +23,26 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.11 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "pty.h"
#include "packet.h"
#include "buffer.h"
#include "mpaux.h"
#include "servconf.h"
#include "compat.h"
#include "channels.h"
#include "match.h"
#include "bufaux.h"
#include "ssh2.h"
#include "groupaccess.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
#include "session.h"
#include "auth-options.h"
#include "canohost.h"
/* import */
extern ServerOptions options;
/*
* Check if the user is allowed to log in via ssh. If user is listed in
* DenyUsers or user's primary group is listed in DenyGroups, false will
* be returned. If AllowUsers isn't empty and user isn't listed there, or
* if AllowGroups isn't empty and user isn't listed there, false will be
* returned.
* Check if the user is allowed to log in via ssh. If user is listed
* in DenyUsers or one of user's groups is listed in DenyGroups, false
* will be returned. If AllowUsers isn't empty and user isn't listed
* there, or if AllowGroups isn't empty and one of user's groups isn't
* listed there, false will be returned.
* If the user's shell is not executable, false will be returned.
* Otherwise true is returned.
*/
@ -68,12 +50,11 @@ int
allowed_user(struct passwd * pw)
{
struct stat st;
struct group *grp;
char *shell;
int i;
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
if (!pw)
if (!pw || !pw->pw_name)
return 0;
/*
@ -90,16 +71,12 @@ allowed_user(struct passwd * pw)
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_deny_users; i++)
if (match_pattern(pw->pw_name, options.deny_users[i]))
return 0;
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_allow_users; i++)
if (match_pattern(pw->pw_name, options.allow_users[i]))
break;
@ -107,36 +84,91 @@ allowed_user(struct passwd * pw)
if (i >= options.num_allow_users)
return 0;
}
/* Get the primary group name if we need it. Return false if it fails */
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
grp = getgrgid(pw->pw_gid);
if (!grp)
/* Get the user's group access list (primary and supplementary) */
if (ga_init(pw->pw_name, pw->pw_gid) == 0)
return 0;
/* Return false if user's group is listed in DenyGroups */
if (options.num_deny_groups > 0) {
if (!grp->gr_name)
/* 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();
return 0;
for (i = 0; i < options.num_deny_groups; i++)
if (match_pattern(grp->gr_name, options.deny_groups[i]))
return 0;
}
}
/*
* Return false if AllowGroups isn't empty and user's group
* Return false if AllowGroups isn't empty and one of user's groups
* isn't listed there
*/
if (options.num_allow_groups > 0) {
if (!grp->gr_name)
if (options.num_allow_groups > 0)
if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
return 0;
for (i = 0; i < options.num_allow_groups; i++)
if (match_pattern(grp->gr_name, options.allow_groups[i]))
break;
/* i < options.num_allow_groups iff we break for
loop */
if (i >= options.num_allow_groups)
return 0;
}
}
ga_free();
}
/* We found no reason not to let this user try to log on... */
return 1;
}
Authctxt *
authctxt_new(void)
{
Authctxt *authctxt = xmalloc(sizeof(*authctxt));
memset(authctxt, 0, sizeof(*authctxt));
return authctxt;
}
void
auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
{
void (*authlog) (const char *fmt,...) = verbose;
char *authmsg;
/* Raise logging level */
if (authenticated == 1 ||
!authctxt->valid ||
authctxt->failures >= AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
if (authctxt->postponed)
authmsg = "Postponed";
else
authmsg = authenticated ? "Accepted" : "Failed";
authlog("%s %s for %s%.100s from %.200s port %d%s",
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
authctxt->valid && authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
info);
}
/*
* Check whether root logins are disallowed.
*/
int
auth_root_allowed(char *method)
{
switch (options.permit_root_login) {
case PERMIT_YES:
return 1;
break;
case PERMIT_NO_PASSWD:
if (strcmp(method, "password") != 0)
return 1;
break;
case PERMIT_FORCED_ONLY:
if (forced_command) {
log("Root login accepted for forced command.");
return 1;
}
break;
}
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}

View file

@ -21,30 +21,118 @@
* (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.7 2000/10/16 09:38:44 djm Exp $
* $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
*/
#ifndef AUTH_H
#define AUTH_H
#include <openssl/rsa.h>
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
#endif
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
typedef struct Authctxt Authctxt;
struct Authctxt {
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
#ifdef BSD_AUTH
auth_session_t *as;
#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).
*/
int auth_rhosts(struct passwd * pw, const char *client_user);
/* extended interface similar to auth_rhosts() */
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr);
/*
* 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);
#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);
#ifdef AFS
#include <kafs.h>
/* 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 */
void do_authentication(void);
void do_authentication2(void);
void userauth_log(Authctxt *authctxt, int authenticated, char *method);
void userauth_reply(Authctxt *authctxt, int authenticated);
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);
int auth2_skey(Authctxt *authctxt);
int auth2_challenge(Authctxt *authctxt, char *devs);
int allowed_user(struct passwd * pw);
char *get_challenge(Authctxt *authctxt, char *devs);
int verify_response(Authctxt *authctxt, char *response);
struct passwd * auth_get_user(void);
#define AUTH_FAIL_MAX 6

View file

@ -10,22 +10,23 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "ssh1.h"
#include "packet.h"
#include "buffer.h"
#include "mpaux.h"
#include "log.h"
#include "servconf.h"
#include "compat.h"
#include "auth.h"
#include "session.h"
#include "misc.h"
/* import */
extern ServerOptions options;
extern char *forced_command;
/*
* convert ssh auth msg type into description
@ -43,13 +44,12 @@ get_authname(int type)
return "rhosts-rsa";
case SSH_CMSG_AUTH_RHOSTS:
return "rhosts";
case SSH_CMSG_AUTH_TIS:
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "challenge-response";
#ifdef KRB4
case SSH_CMSG_AUTH_KERBEROS:
return "kerberos";
#endif
#ifdef SKEY
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "s/key";
#endif
}
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
@ -57,38 +57,47 @@ get_authname(int type)
}
/*
* read packets and try to authenticate local user 'luser'.
* return if authentication is successfull. not that pw == NULL
* if the user does not exists or is not allowed to login.
* each auth method has to 'fake' authentication for nonexisting
* users.
* read packets, try to authenticate the user and
* return only if authentication is successful
*/
void
do_authloop(struct passwd * pw, char *luser)
do_authloop(Authctxt *authctxt)
{
int authenticated = 0;
int attempt = 0;
unsigned int bits;
u_int bits;
RSA *client_host_key;
BIGNUM *n;
char *client_user, *password;
char user[1024];
unsigned int dlen;
char info[1024];
u_int dlen;
int plen, nlen, elen;
unsigned int ulen;
u_int ulen;
int type = 0;
void (*authlog) (const char *fmt,...) = verbose;
struct passwd *pw = authctxt->pw;
debug("Attempting authentication for %s%.100s.",
authctxt->valid ? "" : "illegal user ", authctxt->user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#ifdef KRB4
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
auth_password(authctxt, "")) {
auth_log(authctxt, 1, "without authentication", "");
return;
}
/* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
for (attempt = 1;; attempt++) {
for (;;) {
/* default to fail */
authenticated = 0;
strlcpy(user, "", sizeof user);
info[0] = '\0';
/* Get a packet from the client. */
type = packet_read(&plen);
@ -105,7 +114,7 @@ do_authloop(struct passwd * pw, char *luser)
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", luser);
verbose("Kerberos tgt REFUSED for %.100s", authctxt->user);
xfree(tgt);
}
continue;
@ -119,7 +128,7 @@ do_authloop(struct passwd * pw, char *luser)
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", luser);
verbose("AFS token REFUSED for %.100s", authctxt->user);
xfree(token_string);
}
continue;
@ -127,27 +136,26 @@ do_authloop(struct passwd * pw, char *luser)
#ifdef KRB4
case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) {
/* packet_get_all(); */
verbose("Kerberos authentication disabled.");
break;
} else {
/* Try Kerberos v4 authentication. */
KTEXT_ST auth;
char *tkt_user = NULL;
char *kdata = packet_get_string((unsigned int *) &auth.length);
char *kdata = packet_get_string((u_int *) &auth.length);
packet_integrity_check(plen, 4 + auth.length, type);
if (auth.length < MAX_KTXT_LEN)
memcpy(auth.dat, kdata, auth.length);
xfree(kdata);
if (pw != NULL) {
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(user, sizeof user, " tktuser %s", tkt_user);
snprintf(info, sizeof info,
" tktuser %.100s", tkt_user);
xfree(tkt_user);
}
}
xfree(kdata);
}
break;
#endif /* KRB4 */
@ -169,7 +177,7 @@ do_authloop(struct passwd * pw, char *luser)
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
authenticated = auth_rhosts(pw, client_user);
snprintf(user, sizeof user, " ruser %s", client_user);
snprintf(info, sizeof info, " ruser %.100s", client_user);
xfree(client_user);
break;
@ -205,7 +213,7 @@ do_authloop(struct passwd * pw, char *luser)
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
RSA_free(client_host_key);
snprintf(user, sizeof user, " ruser %s", client_user);
snprintf(info, sizeof info, " ruser %.100s", client_user);
xfree(client_user);
break;
@ -236,28 +244,20 @@ do_authloop(struct passwd * pw, char *luser)
packet_integrity_check(plen, 4 + dlen, type);
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
authenticated = auth_password(authctxt, password);
memset(password, 0, strlen(password));
xfree(password);
break;
#ifdef SKEY
case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS");
if (options.skey_authentication == 1) {
char *skeyinfo = NULL;
if (pw != NULL)
skey_keyinfo(pw->pw_name);
if (skeyinfo == NULL) {
debug("generating fake skeyinfo for %.100s.", luser);
skeyinfo = skey_fake_keyinfo(luser);
}
if (skeyinfo != NULL) {
/* we send our s/key- in tis-challenge messages */
debug("sending challenge '%s'", skeyinfo);
if (options.challenge_reponse_authentication == 1) {
char *challenge = get_challenge(authctxt, authctxt->style);
if (challenge != NULL) {
debug("sending challenge '%s'", challenge);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_cstring(skeyinfo);
packet_put_cstring(challenge);
packet_send();
packet_write_wait();
continue;
@ -266,22 +266,15 @@ do_authloop(struct passwd * pw, char *luser)
break;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (options.skey_authentication == 1) {
if (options.challenge_reponse_authentication == 1) {
char *response = packet_get_string(&dlen);
debug("skey response == '%s'", response);
debug("got response '%s'", response);
packet_integrity_check(plen, 4 + dlen, type);
authenticated = (pw != NULL &&
skey_haskey(pw->pw_name) == 0 &&
skey_passcheck(pw->pw_name, response) != -1);
authenticated = verify_response(authctxt, response);
memset(response, 'r', dlen);
xfree(response);
}
break;
#else
case SSH_CMSG_AUTH_TIS:
/* TIS Authentication is unsupported */
log("TIS authentication unsupported.");
break;
#endif
default:
/*
@ -291,46 +284,30 @@ do_authloop(struct passwd * pw, char *luser)
log("Unknown message during authentication: type %d", type);
break;
}
if (authenticated && pw == NULL)
fatal("internal error: authenticated for pw == NULL");
/*
* Check if the user is logging in as root and root logins
* are disallowed.
* Note that root login is allowed for forced commands.
*/
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
if (forced_command) {
log("Root login accepted for forced command.");
} else {
authenticated = 0;
log("ROOT LOGIN REFUSED FROM %.200s",
get_canonical_hostname());
}
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
#endif
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
/* Raise logging level */
if (authenticated ||
attempt == AUTH_FAIL_LOG ||
type == SSH_CMSG_AUTH_PASSWORD)
authlog = log;
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(get_authname(type)))
authenticated = 0;
authlog("%s %s for %s%.100s from %.200s port %d%s",
authenticated ? "Accepted" : "Failed",
get_authname(type),
pw ? "" : "illegal user ",
pw && pw->pw_uid == 0 ? "ROOT" : luser,
get_remote_ipaddr(),
get_remote_port(),
user);
/* Log before sending the reply */
auth_log(authctxt, authenticated, get_authname(type), info);
if (authenticated)
return;
if (attempt > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, luser);
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
/* Send a message indicating that the authentication attempt failed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
@ -344,10 +321,11 @@ do_authloop(struct passwd * pw, char *luser)
void
do_authentication()
{
struct passwd *pw, pwcopy;
Authctxt *authctxt;
struct passwd *pw;
int plen;
unsigned int ulen;
char *user;
u_int ulen;
char *user, *style = NULL;
/* Get the name of the user that we wish to log in as. */
packet_read_expect(&plen, SSH_CMSG_USER);
@ -356,32 +334,25 @@ do_authentication()
user = packet_get_string(&ulen);
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
setproctitle("%s", user);
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
k_setpag();
k_unlog();
}
#endif /* AFS */
authctxt = authctxt_new();
authctxt->user = user;
authctxt->style = style;
/* Verify that the user is a valid user. */
pw = getpwnam(user);
if (pw && allowed_user(pw)) {
/* Take a copy of the returned structure. */
memset(&pwcopy, 0, sizeof(pwcopy));
pwcopy.pw_name = xstrdup(pw->pw_name);
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
pwcopy.pw_uid = pw->pw_uid;
pwcopy.pw_gid = pw->pw_gid;
pwcopy.pw_class = xstrdup(pw->pw_class);
pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell);
pw = &pwcopy;
authctxt->valid = 1;
pw = pwcopy(pw);
} else {
debug("do_authentication: illegal user %s", user);
pw = NULL;
}
authctxt->pw = pw;
setproctitle("%s", pw ? user : "unknown");
/*
* If we are not running as root, the user must have the same uid as
@ -390,25 +361,11 @@ do_authentication()
if (getuid() != 0 && pw && pw->pw_uid != getuid())
packet_disconnect("Cannot change user when server not running as root.");
debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#ifdef KRB4
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif /* KRB4 */
auth_password(pw, "")) {
/* Authentication with empty password succeeded. */
log("Login for user %s from %.100s, accepted without authentication.",
user, get_remote_ipaddr());
} else {
/* Loop until the user has been authenticated or the
connection is closed, do_authloop() returns only if
authentication is successfull */
do_authloop(pw, user);
}
if (pw == NULL)
fatal("internal error, authentication successfull for user '%.100s'", user);
/*
* Loop until the user has been authenticated or the connection is
* closed, do_authloop() returns only if authentication is successful
*/
do_authloop(authctxt);
/* The user has been authenticated and accepted. */
packet_start(SSH_SMSG_SUCCESS);
@ -416,5 +373,5 @@ do_authentication()
packet_write_wait();
/* Perform session preparation. */
do_authenticated(pw);
do_authenticated(authctxt);
}

View file

@ -0,0 +1,112 @@
/*
* 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: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $");
#include "ssh2.h"
#include "auth.h"
#include "packet.h"
#include "xmalloc.h"
#include "dispatch.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);
/*
* try challenge-reponse, return -1 (= postponed) if we have to
* wait for the response.
*/
int
auth2_challenge(Authctxt *authctxt, char *devs)
{
char *challenge;
if (!authctxt->valid || authctxt->user == NULL)
return 0;
if ((challenge = get_challenge(authctxt, devs)) == NULL)
return 0;
send_userauth_into_request(authctxt, challenge, 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)
{
int nprompts = 1;
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_send();
packet_write_wait();
}
void
input_userauth_info_response(int type, int plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
int authenticated = 0;
u_int nresp, rlen;
char *response, *method = "challenge-reponse";
if (authctxt == NULL)
fatal("input_userauth_info_response: no authctxt");
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);
}
/* unregister callback */
if (!authctxt->postponed)
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
userauth_finish(authctxt, authenticated, method);
}

View file

@ -23,37 +23,38 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $");
RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include "ssh2.h"
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "pty.h"
#include "sshpty.h"
#include "packet.h"
#include "buffer.h"
#include "log.h"
#include "servconf.h"
#include "compat.h"
#include "channels.h"
#include "bufaux.h"
#include "ssh2.h"
#include "auth.h"
#include "session.h"
#include "dispatch.h"
#include "auth.h"
#include "key.h"
#include "cipher.h"
#include "kex.h"
#include "dsa.h"
#include "pathnames.h"
#include "uidswap.h"
#include "auth-options.h"
#include "misc.h"
#include "hostfile.h"
#include "canohost.h"
#include "tildexpand.h"
/* import */
extern ServerOptions options;
extern unsigned char *session_id2;
extern u_char *session_id2;
extern int session_id2_len;
static Authctxt *x_authctxt = NULL;
@ -72,17 +73,21 @@ 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);
/* helper */
Authmethod *authmethod_lookup(const char *name);
struct passwd *pwcopy(struct passwd *pw);
int user_dsa_key_allowed(struct passwd *pw, Key *key);
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);
/* 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);
Authmethod authmethods[] = {
@ -91,13 +96,16 @@ Authmethod authmethods[] = {
&one},
{"publickey",
userauth_pubkey,
&options.dsa_authentication},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication},
&options.pubkey_authentication},
{"password",
userauth_passwd,
&options.password_authentication},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication},
{"hostbased",
userauth_hostbased,
&options.hostbased_authentication},
{NULL, NULL, NULL}
};
@ -108,21 +116,18 @@ Authmethod authmethods[] = {
void
do_authentication2()
{
Authctxt *authctxt = xmalloc(sizeof(*authctxt));
memset(authctxt, 'a', sizeof(*authctxt));
authctxt->valid = 0;
authctxt->attempt = 0;
authctxt->success = 0;
Authctxt *authctxt = authctxt_new();
x_authctxt = authctxt; /*XXX*/
#ifdef KRB4
/* turn off kerberos, not supported by SSH2 */
options.kerberos_authentication = 0;
#endif
/* challenge-reponse is implemented via keyboard interactive */
if (options.challenge_reponse_authentication)
options.kbd_interactive_authentication = 1;
dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated2();
do_authenticated(authctxt);
}
void
@ -139,7 +144,7 @@ void
input_service_request(int type, int plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
unsigned int len;
u_int len;
int accept = 0;
char *service = packet_get_string(&len);
packet_done();
@ -173,24 +178,24 @@ input_userauth_request(int type, int plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Authmethod *m = NULL;
char *user, *service, *method;
char *user, *service, *method, *style = NULL;
int authenticated = 0;
if (authctxt == NULL)
fatal("input_userauth_request: no authctxt");
if (authctxt->attempt++ >= AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests");
user = packet_get_string(NULL);
service = packet_get_string(NULL);
method = packet_get_string(NULL);
debug("userauth-request for user %s service %s method %s", user, service, method);
debug("attempt #%d", authctxt->attempt);
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if (authctxt->attempt == 1) {
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
if (authctxt->attempt++ == 0) {
/* setup auth context */
struct passwd *pw = NULL;
setproctitle("%s", user);
pw = getpwnam(user);
if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
authctxt->pw = pwcopy(pw);
@ -199,84 +204,96 @@ input_userauth_request(int type, int plen, void *ctxt)
} else {
log("input_userauth_request: illegal user %s", user);
}
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: missmatch: (%s,%s)!=(%s,%s)",
log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
user, service, authctxt->user, authctxt->service);
authctxt->valid = 0;
}
}
/* reset state */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
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);
if (m != NULL) {
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(authctxt);
} else {
debug2("input_userauth_request: unsupported method %s", method);
}
if (!authctxt->valid && authenticated == 1) {
log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
authenticated = 0;
}
/* Special handling for root */
if (authenticated == 1 &&
authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
authenticated = 0;
log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
}
/* Log before sending the reply */
userauth_log(authctxt, authenticated, method);
userauth_reply(authctxt, authenticated);
userauth_finish(authctxt, authenticated, method);
xfree(service);
xfree(user);
xfree(method);
}
void
userauth_log(Authctxt *authctxt, int authenticated, char *method)
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
{
void (*authlog) (const char *fmt,...) = verbose;
char *user = NULL, *authmsg = NULL;
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
/* Raise logging level */
if (authenticated == 1 ||
!authctxt->valid ||
authctxt->attempt >= AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(method))
authenticated = 0;
if (authenticated == 1) {
authmsg = "Accepted";
} else if (authenticated == 0) {
authmsg = "Failed";
} else {
authmsg = "Postponed";
}
/* Log before sending the reply */
auth_log(authctxt, authenticated, method, " ssh2");
if (authctxt->valid) {
user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
} else {
user = "NOUSER";
}
authlog("%s %s for %.200s from %.200s port %d ssh2",
authmsg,
method,
user,
get_remote_ipaddr(),
get_remote_port());
if (!authctxt->postponed)
userauth_reply(authctxt, authenticated);
}
void
void
userauth_banner(void)
{
struct stat st;
char *banner = NULL;
off_t len, n;
int fd;
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
return;
if ((fd = open(options.banner, O_RDONLY)) < 0)
return;
if (fstat(fd, &st) < 0)
goto done;
len = st.st_size;
banner = xmalloc(len + 1);
if ((n = read(fd, banner, len)) < 0)
goto done;
banner[n] = '\0';
packet_start(SSH2_MSG_USERAUTH_BANNER);
packet_put_cstring(banner);
packet_put_cstring(""); /* language, unused */
packet_send();
debug("userauth_banner: sent");
done:
if (banner)
xfree(banner);
close(fd);
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 */
@ -286,16 +303,16 @@ userauth_reply(Authctxt *authctxt, int authenticated)
packet_write_wait();
/* now we can break out */
authctxt->success = 1;
} else if (authenticated == 0) {
char *methods = authmethods_get();
} 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);
} else {
/* do nothing, we did already send a reply */
}
}
@ -307,7 +324,8 @@ userauth_none(Authctxt *authctxt)
if (m != NULL)
m->enabled = NULL;
packet_done();
return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
userauth_banner();
return authctxt->valid ? auth_password(authctxt, "") : 0;
}
int
@ -316,14 +334,14 @@ userauth_passwd(Authctxt *authctxt)
char *password;
int authenticated = 0;
int change;
unsigned int len;
u_int len;
change = packet_get_char();
if (change)
log("password change not supported");
password = packet_get_string(&len);
packet_done();
if (authctxt->valid &&
auth_password(authctxt->pw, password) == 1)
auth_password(authctxt, password) == 1)
authenticated = 1;
memset(password, 0, len);
xfree(password);
@ -342,11 +360,10 @@ userauth_kbdint(Authctxt *authctxt)
packet_done();
debug("keyboard-interactive language %s devs %s", lang, devs);
#ifdef SKEY
/* XXX hardcoded, we should look at devs */
if (options.skey_authentication != 0)
authenticated = auth2_skey(authctxt);
#endif
if (options.challenge_reponse_authentication)
authenticated = auth2_challenge(authctxt, devs);
xfree(lang);
xfree(devs);
return authenticated;
@ -358,8 +375,8 @@ userauth_pubkey(Authctxt *authctxt)
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig;
unsigned int alen, blen, slen;
int have_sig;
u_int alen, blen, slen;
int have_sig, pktype;
int authenticated = 0;
if (!authctxt->valid) {
@ -367,14 +384,28 @@ userauth_pubkey(Authctxt *authctxt)
return 0;
}
have_sig = packet_get_char();
pkalg = packet_get_string(&alen);
if (strcmp(pkalg, KEX_DSS) != 0) {
log("bad pkalg %s", pkalg); /*XXX*/
if (datafellows & SSH_BUG_PKAUTH) {
debug2("userauth_pubkey: SSH_BUG_PKAUTH");
/* no explicit pkalg given */
pkblob = packet_get_string(&blen);
buffer_init(&b);
buffer_append(&b, pkblob, blen);
/* so we have to extract the pkalg from the pkblob */
pkalg = buffer_get_string(&b, &alen);
buffer_free(&b);
} else {
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
}
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;
}
pkblob = packet_get_string(&blen);
key = dsa_key_from_blob(pkblob, blen);
key = key_from_blob(pkblob, blen);
if (key != NULL) {
if (have_sig) {
sig = packet_get_string(&slen);
@ -389,19 +420,23 @@ userauth_pubkey(Authctxt *authctxt)
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PUBKEYAUTH ?
datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" :
authctxt->service);
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS);
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_DSS
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_dsa_key_allowed(authctxt->pw, key) &&
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
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);
@ -417,24 +452,100 @@ userauth_pubkey(Authctxt *authctxt)
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_dsa_key_allowed(authctxt->pw, key)) {
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();
authenticated = -1;
authctxt->postponed = 1;
}
}
if (authenticated != 1)
auth_clear_options();
key_free(key);
}
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
xfree(pkalg);
xfree(pkblob);
return authenticated;
}
int
userauth_hostbased(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
u_int alen, blen, slen;
int pktype;
int authenticated = 0;
if (!authctxt->valid) {
debug2("userauth_hostbased: disabled because of invalid user");
return 0;
}
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
chost = packet_get_string(NULL);
cuser = packet_get_string(NULL);
sig = packet_get_string(&slen);
debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
cuser, chost, pkalg, slen);
#ifdef DEBUG_PK
debug("signature:");
buffer_init(&b);
buffer_append(&b, sig, slen);
buffer_dump(&b);
buffer_free(&b);
#endif
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
log("userauth_hostbased: unsupported "
"public key algorithm: %s", pkalg);
goto done;
}
key = key_from_blob(pkblob, blen);
if (key == NULL) {
debug("userauth_hostbased: cannot decode key: %s", pkalg);
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
authctxt->service;
buffer_init(&b);
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, service);
buffer_put_cstring(&b, "hostbased");
buffer_put_string(&b, pkalg, alen);
buffer_put_string(&b, pkblob, blen);
buffer_put_cstring(&b, chost);
buffer_put_cstring(&b, cuser);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for allowed key and correct signature */
if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
key_free(key);
done:
debug2("userauth_hostbased: authenticated %d", authenticated);
xfree(pkalg);
xfree(pkblob);
xfree(cuser);
xfree(chost);
xfree(sig);
return authenticated;
}
/* get current user */
struct passwd*
@ -449,7 +560,7 @@ char *
authmethods_get(void)
{
Authmethod *method = NULL;
unsigned int size = 0;
u_int size = 0;
char *list;
for (method = authmethods; method->name != NULL; method++) {
@ -493,13 +604,12 @@ authmethod_lookup(const char *name)
/* return 1 if user allows given key */
int
user_dsa_key_allowed(struct passwd *pw, Key *key)
user_key_allowed(struct passwd *pw, Key *key)
{
char line[8192], file[1024];
char line[8192], file[MAXPATHLEN];
int found_key = 0;
unsigned int bits = -1;
FILE *f;
unsigned long linenum = 0;
u_long linenum = 0;
struct stat st;
Key *found;
@ -507,11 +617,11 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
return 0;
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
SSH_USER_PERMITTED_KEYS2);
_PATH_SSH_USER_PERMITTED_KEYS2);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
@ -539,10 +649,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
key_type(key), pw->pw_name, file);
fail = 1;
} else {
/* Check path to SSH_USER_PERMITTED_KEYS */
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", SSH_USER_DIR, NULL
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s",
@ -561,7 +671,7 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
}
if (fail) {
fclose(f);
log("%s",buf);
log("%s", buf);
restore_uid();
return 0;
}
@ -578,10 +688,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
if (!*cp || *cp == '\n' || *cp == '#')
continue;
bits = key_read(found, &cp);
if (bits == 0) {
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);
options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
@ -592,14 +702,14 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
bits = key_read(found, &cp);
if (bits == 0) {
if (key_read(found, &cp) == -1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
}
}
if (key_equal(found, key) &&
auth_parse_options(pw, options, linenum) == 1) {
auth_parse_options(pw, options, file, linenum) == 1) {
found_key = 1;
debug("matching key found: file %s, line %ld",
file, linenum);
@ -609,20 +719,73 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
restore_uid();
fclose(f);
key_free(found);
if (!found_key)
debug2("key not found");
return found_key;
}
struct passwd *
pwcopy(struct passwd *pw)
/* return 1 if given hostkey is allowed */
int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key)
{
struct passwd *copy = xmalloc(sizeof(*copy));
memset(copy, 0, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
copy->pw_class = xstrdup(pw->pw_class);
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
return copy;
Key *found;
const char *resolvedname, *ipaddr, *lookup;
struct stat st;
char *user_hostfile;
int host_status, len;
resolvedname = get_canonical_hostname(options.reverse_mapping_check);
ipaddr = get_remote_ipaddr();
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
chost, resolvedname, ipaddr);
if (options.hostbased_uses_name_from_packet_only) {
if (auth_rhosts2(pw, cuser, chost, chost) == 0)
return 0;
lookup = chost;
} else {
if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
debug2("stripping trailing dot from chost %s", chost);
chost[len - 1] = '\0';
}
if (strcasecmp(resolvedname, chost) != 0)
log("userauth_hostbased mismatch: "
"client sends %s, but we resolve %s to %s",
chost, ipaddr, resolvedname);
if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
return 0;
lookup = resolvedname;
}
debug2("userauth_hostbased: access allowed by auth_rhosts2");
/* XXX this is copied from auth-rh-rsa.c and should be shared */
found = key_new(key->type);
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE2, lookup,
key, found, NULL);
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE2,
pw->pw_uid);
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
log("Hostbased authentication refused for %.100s: "
"bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile,
lookup, key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(found);
debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", lookup);
return (host_status == HOST_OK);
}

View file

@ -35,7 +35,9 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $");
RCSID("$OpenBSD: authfd.c,v 1.39 2001/04/05 10:42:48 markus Exp $");
#include <openssl/evp.h>
#include "ssh.h"
#include "rsa.h"
@ -43,15 +45,13 @@ RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $");
#include "bufaux.h"
#include "xmalloc.h"
#include "getput.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "key.h"
#include "authfd.h"
#include "cipher.h"
#include "kex.h"
#include "dsa.h"
#include "compat.h"
#include "log.h"
#include "atomicio.h"
/* helper */
int decode_reply(int type);
@ -63,7 +63,7 @@ int decode_reply(int type);
/* Returns the number of the authentication fd, or -1 if there is none. */
int
ssh_get_authentication_socket()
ssh_get_authentication_socket(void)
{
const char *authsocket;
int sock, len;
@ -75,7 +75,8 @@ ssh_get_authentication_socket()
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1;
len = SUN_LEN(&sunaddr)+1;
sunaddr.sun_len = len;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
@ -117,6 +118,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
len = 4;
while (len > 0) {
l = read(auth->fd, buf + 4 - len, len);
if (l == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (l <= 0) {
error("Error reading response length from authentication socket.");
return 0;
@ -136,6 +139,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
if (l > sizeof(buf))
l = sizeof(buf);
l = read(auth->fd, buf, l);
if (l == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (l <= 0) {
error("Error reading response from authentication socket.");
return 0;
@ -168,7 +173,7 @@ ssh_close_authentication_socket(int sock)
*/
AuthenticationConnection *
ssh_get_authentication_connection()
ssh_get_authentication_connection(void)
{
AuthenticationConnection *auth;
int sock;
@ -207,8 +212,8 @@ ssh_close_authentication_connection(AuthenticationConnection *auth)
* Returns the first authentication identity held by the agent.
*/
Key *
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
int
ssh_get_num_identities(AuthenticationConnection *auth, int version)
{
int type, code1 = 0, code2 = 0;
Buffer request;
@ -223,7 +228,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
code2 = SSH2_AGENT_IDENTITIES_ANSWER;
break;
default:
return NULL;
return 0;
}
/*
@ -236,14 +241,14 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
buffer_clear(&auth->identities);
if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
buffer_free(&request);
return NULL;
return 0;
}
buffer_free(&request);
/* Get message type, and verify that we got a proper answer. */
type = buffer_get_char(&auth->identities);
if (agent_failed(type)) {
return NULL;
return 0;
} else if (type != code2) {
fatal("Bad authentication reply message type: %d", type);
}
@ -251,19 +256,27 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
/* Get the number of entries in the response and check it for sanity. */
auth->howmany = buffer_get_int(&auth->identities);
if (auth->howmany > 1024)
fatal("Too many identities in authentication reply: %d\n",
fatal("Too many identities in authentication reply: %d",
auth->howmany);
/* Return the first entry (if any). */
return ssh_get_next_identity(auth, comment, version);
return auth->howmany;
}
Key *
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
{
/* get number of identities and return the first entry (if any). */
if (ssh_get_num_identities(auth, version) > 0)
return ssh_get_next_identity(auth, comment, version);
return NULL;
}
Key *
ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
{
unsigned int bits;
unsigned char *blob;
unsigned int blen;
u_int bits;
u_char *blob;
u_int blen;
Key *key = NULL;
/* Return failure if no more entries. */
@ -276,7 +289,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
*/
switch(version){
case 1:
key = key_new(KEY_RSA);
key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities);
buffer_get_bignum(&auth->identities, key->rsa->e);
buffer_get_bignum(&auth->identities, key->rsa->n);
@ -288,7 +301,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
case 2:
blob = buffer_get_string(&auth->identities, &blen);
*comment = buffer_get_string(&auth->identities, NULL);
key = dsa_key_from_blob(blob, blen);
key = key_from_blob(blob, blen);
xfree(blob);
break;
default:
@ -311,16 +324,16 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
Key* key, BIGNUM *challenge,
unsigned char session_id[16],
unsigned int response_type,
unsigned char response[16])
u_char session_id[16],
u_int response_type,
u_char response[16])
{
Buffer buffer;
int success = 0;
int i;
int type;
if (key->type != KEY_RSA)
if (key->type != KEY_RSA1)
return 0;
if (response_type == 0) {
log("Compatibility with ssh protocol version 1.0 no longer supported.");
@ -362,17 +375,17 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen)
u_char **sigp, int *lenp,
u_char *data, int datalen)
{
extern int datafellows;
Buffer msg;
unsigned char *blob;
unsigned int blen;
u_char *blob;
u_int blen;
int type, flags = 0;
int ret = -1;
if (dsa_make_key_blob(key, &blob, &blen) == 0)
if (key_to_blob(key, &blob, &blen) == 0)
return -1;
if (datafellows & SSH_BUG_SIGBLOB)
@ -405,7 +418,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */
void
ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
@ -421,17 +434,29 @@ ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
}
void
ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
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, KEX_DSS);
buffer_put_bignum2(b, key->p);
buffer_put_bignum2(b, key->q);
buffer_put_bignum2(b, key->g);
buffer_put_bignum2(b, key->pub_key);
buffer_put_bignum2(b, key->priv_key);
buffer_put_string(b, comment, strlen(comment));
buffer_put_cstring(b, key_ssh_name(key));
switch(key->type){
case KEY_RSA:
buffer_put_bignum2(b, key->rsa->n);
buffer_put_bignum2(b, key->rsa->e);
buffer_put_bignum2(b, key->rsa->d);
buffer_put_bignum2(b, key->rsa->iqmp);
buffer_put_bignum2(b, key->rsa->p);
buffer_put_bignum2(b, key->rsa->q);
break;
case KEY_DSA:
buffer_put_bignum2(b, key->dsa->p);
buffer_put_bignum2(b, key->dsa->q);
buffer_put_bignum2(b, key->dsa->g);
buffer_put_bignum2(b, key->dsa->pub_key);
buffer_put_bignum2(b, key->dsa->priv_key);
break;
}
buffer_put_cstring(b, comment);
}
/*
@ -448,11 +473,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
buffer_init(&msg);
switch (key->type) {
case KEY_RSA:
ssh_encode_identity_rsa(&msg, key->rsa, comment);
case KEY_RSA1:
ssh_encode_identity_rsa1(&msg, key->rsa, comment);
break;
case KEY_RSA:
case KEY_DSA:
ssh_encode_identity_dsa(&msg, key->dsa, comment);
ssh_encode_identity_ssh2(&msg, key, comment);
break;
default:
buffer_free(&msg);
@ -478,18 +504,18 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
{
Buffer msg;
int type;
unsigned char *blob;
unsigned int blen;
u_char *blob;
u_int blen;
buffer_init(&msg);
if (key->type == KEY_RSA) {
if (key->type == KEY_RSA1) {
buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
buffer_put_int(&msg, BN_num_bits(key->rsa->n));
buffer_put_bignum(&msg, key->rsa->e);
buffer_put_bignum(&msg, key->rsa->n);
} else if (key->type == KEY_DSA) {
dsa_make_key_blob(key, &blob, &blen);
} else if (key->type == KEY_DSA || key->type == KEY_RSA) {
key_to_blob(key, &blob, &blen);
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
buffer_put_string(&msg, blob, blen);
xfree(blob);
@ -532,7 +558,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth, int version)
return decode_reply(type);
}
int
int
decode_reply(int type)
{
switch (type) {

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */
/* RCSID("$OpenBSD: authfd.h,v 1.16 2000/12/20 19:37:21 markus Exp $"); */
#ifndef AUTHFD_H
#define AUTHFD_H
@ -51,7 +51,7 @@ typedef struct {
} AuthenticationConnection;
/* Returns the number of the authentication fd, or -1 if there is none. */
int ssh_get_authentication_socket();
int ssh_get_authentication_socket(void);
/*
* This should be called for any descriptor returned by
@ -66,7 +66,7 @@ void ssh_close_authentication_socket(int authfd);
* connection could not be opened. The connection should be closed by the
* caller by calling ssh_close_authentication_connection().
*/
AuthenticationConnection *ssh_get_authentication_connection();
AuthenticationConnection *ssh_get_authentication_connection(void);
/*
* Closes the connection to the authentication agent and frees any associated
@ -74,6 +74,11 @@ AuthenticationConnection *ssh_get_authentication_connection();
*/
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.
@ -96,16 +101,16 @@ Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int v
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
Key *key, BIGNUM * challenge,
unsigned char session_id[16],
unsigned int response_type,
unsigned char response[16]);
u_char session_id[16],
u_int response_type,
u_char response[16]);
/* Requests the agent to sign data using key */
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen);
u_char **sigp, int *lenp,
u_char *data, int datalen);
/*
* Adds an identity to the authentication server. This call is not meant to

View file

@ -36,22 +36,24 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include "cipher.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "ssh.h"
#include "key.h"
#include "ssh.h"
#include "log.h"
#include "authfile.h"
/* Version identification string for identity files. */
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
/* Version identification string for SSH v1 identity files. */
static const char authfile_id_string[] =
"SSH PRIVATE KEY FILE FORMAT 1.1\n";
/*
* Saves the authentication (private) key in a file, encrypting it with
@ -61,8 +63,8 @@ RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $");
*/
int
save_private_key_rsa(const char *filename, const char *passphrase,
RSA *key, const char *comment)
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
const char *comment)
{
Buffer buffer, encrypted;
char buf[100], *cp;
@ -98,10 +100,10 @@ save_private_key_rsa(const char *filename, const char *passphrase,
* will be stored in plain text, and storing them also in encrypted
* format would just give known plaintext).
*/
buffer_put_bignum(&buffer, key->d);
buffer_put_bignum(&buffer, key->iqmp);
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
buffer_put_bignum(&buffer, key->rsa->d);
buffer_put_bignum(&buffer, key->rsa->iqmp);
buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
/* Pad the part to be encrypted until its size is a multiple of 8. */
while (buffer_len(&buffer) % 8 != 0)
@ -111,9 +113,8 @@ save_private_key_rsa(const char *filename, const char *passphrase,
buffer_init(&encrypted);
/* First store keyfile id string. */
cp = AUTHFILE_ID_STRING;
for (i = 0; cp[i]; i++)
buffer_put_char(&encrypted, cp[i]);
for (i = 0; authfile_id_string[i]; i++)
buffer_put_char(&encrypted, authfile_id_string[i]);
buffer_put_char(&encrypted, 0);
/* Store cipher type. */
@ -121,17 +122,17 @@ save_private_key_rsa(const char *filename, const char *passphrase,
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->n));
buffer_put_bignum(&encrypted, key->n);
buffer_put_bignum(&encrypted, key->e);
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));
/* Allocate space for the private part of the key in the buffer. */
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_encrypt(&ciphercontext, (unsigned char *) cp,
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_encrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
memset(&ciphercontext, 0, sizeof(ciphercontext));
/* Destroy temporary data. */
@ -139,15 +140,17 @@ save_private_key_rsa(const char *filename, const char *passphrase,
buffer_free(&buffer);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
if (fd < 0) {
error("open %s failed: %s.", filename, strerror(errno));
return 0;
}
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) {
debug("Write to key file %.200s failed: %.100s", filename,
error("write to key file %s failed: %s", filename,
strerror(errno));
buffer_free(&encrypted);
close(fd);
remove(filename);
unlink(filename);
return 0;
}
close(fd);
@ -155,80 +158,168 @@ save_private_key_rsa(const char *filename, const char *passphrase,
return 1;
}
/* save DSA key in OpenSSL PEM format */
/* save SSH v2 key in OpenSSL PEM format */
int
save_private_key_dsa(const char *filename, const char *passphrase,
DSA *dsa, const char *comment)
key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
const char *comment)
{
FILE *fp;
int fd;
int success = 1;
int len = strlen(passphrase);
int success = 0;
int len = strlen(_passphrase);
char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
if (len > 0 && len <= 4) {
error("passphrase too short: %d bytes", len);
errno = 0;
error("passphrase too short: have %d bytes, need > 4", len);
return 0;
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) {
debug("open %s failed", filename);
error("open %s failed: %s.", filename, strerror(errno));
return 0;
}
fp = fdopen(fd, "w");
if (fp == NULL ) {
debug("fdopen %s failed", filename);
error("fdopen %s failed: %s.", filename, strerror(errno));
close(fd);
return 0;
}
if (len > 0) {
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
(char *)passphrase, strlen(passphrase), NULL, NULL))
success = 0;
} else {
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
NULL, 0, NULL, NULL))
success = 0;
switch (key->type) {
case KEY_DSA:
success = PEM_write_DSAPrivateKey(fp, key->dsa,
cipher, passphrase, len, NULL, NULL);
break;
case KEY_RSA:
success = PEM_write_RSAPrivateKey(fp, key->rsa,
cipher, passphrase, len, NULL, NULL);
break;
}
fclose(fp);
return success;
}
int
save_private_key(const char *filename, const char *passphrase, Key *key,
key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment)
{
switch (key->type) {
case KEY_RSA:
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
case KEY_RSA1:
return key_save_private_rsa1(key, filename, passphrase,
comment);
break;
case KEY_DSA:
return save_private_key_dsa(filename, passphrase, key->dsa, comment);
case KEY_RSA:
return key_save_private_pem(key, filename, passphrase,
comment);
break;
default:
break;
}
error("key_save_private: cannot save key type %d", key->type);
return 0;
}
/*
* Loads the public part of the key file. Returns 0 if an error was
* encountered (the file does not exist or is not readable), and non-zero
* Loads the public part of the ssh v1 key file. Returns NULL if an error was
* encountered (the file does not exist or is not readable), and the key
* otherwise.
*/
int
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
Key *
key_load_public_rsa1(int fd, const char *filename, char **commentp)
{
int fd, i;
off_t len;
Buffer buffer;
Key *pub;
char *cp;
int i;
off_t len;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno));
buffer_free(&buffer);
return NULL;
}
/* 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);
buffer_free(&buffer);
return NULL;
}
/*
* Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
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);
buffer_free(&buffer);
return NULL;
}
/* Skip cipher type and reserved data. */
(void) buffer_get_char(&buffer); /* cipher type */
(void) buffer_get_int(&buffer); /* reserved */
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
pub = key_new(KEY_RSA1);
buffer_get_bignum(&buffer, pub->rsa->n);
buffer_get_bignum(&buffer, pub->rsa->e);
if (commentp)
*commentp = buffer_get_string(&buffer, NULL);
/* The encrypted private part is not parsed by this function. */
buffer_free(&buffer);
return pub;
}
/* load public key from private-key file, works only for SSH v1 */
Key *
key_load_public_type(int type, const char *filename, char **commentp)
{
Key *pub;
int fd;
if (type == KEY_RSA1) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
pub = key_load_public_rsa1(fd, filename, commentp);
close(fd);
return pub;
}
return NULL;
}
/*
* Loads the private key from the file. Returns 0 if an error is encountered
* (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key.
* Assumes we are called under uid of the owner of the file.
*/
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;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
Key *prv = NULL;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
@ -240,127 +331,40 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
strerror(errno));
buffer_free(&buffer);
close(fd);
return 0;
return NULL;
}
close(fd);
/* Check that it is at least big enought to contain the ID string. */
if (len < strlen(AUTHFILE_ID_STRING) + 1) {
debug("Bad key file %.200s.", filename);
buffer_free(&buffer);
return 0;
}
/*
* Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) {
debug("Bad key file %.200s.", filename);
buffer_free(&buffer);
return 0;
}
/* Skip cipher type and reserved data. */
(void) buffer_get_char(&buffer); /* cipher type */
(void) buffer_get_int(&buffer); /* reserved */
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
/* XXX alloc */
if (pub->n == NULL)
pub->n = BN_new();
buffer_get_bignum(&buffer, pub->n);
/* XXX alloc */
if (pub->e == NULL)
pub->e = BN_new();
buffer_get_bignum(&buffer, pub->e);
if (comment_return)
*comment_return = buffer_get_string(&buffer, NULL);
/* The encrypted private part is not parsed by this function. */
buffer_free(&buffer);
return 1;
}
/* load public key from private-key file */
int
load_public_key(const char *filename, Key * key, char **comment_return)
{
switch (key->type) {
case KEY_RSA:
return load_public_key_rsa(filename, key->rsa, comment_return);
break;
case KEY_DSA:
default:
break;
}
return 0;
}
/*
* Loads the private key from the file. Returns 0 if an error is encountered
* (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key.
* Assumes we are called under uid of the owner of the file.
*/
int
load_private_key_rsa(int fd, const char *filename,
const char *passphrase, RSA * prv, char **comment_return)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno));
/* 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);
buffer_free(&buffer);
close(fd);
return 0;
}
close(fd);
/* Check that it is at least big enought to contain the ID string. */
if (len < strlen(AUTHFILE_ID_STRING) + 1) {
debug("Bad key file %.200s.", filename);
buffer_free(&buffer);
return 0;
return NULL;
}
/*
* Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
debug("Bad key file %.200s.", filename);
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);
buffer_free(&buffer);
return 0;
close(fd);
return NULL;
}
/* Read cipher type. */
cipher_type = buffer_get_char(&buffer);
(void) buffer_get_int(&buffer); /* Reserved data. */
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
prv->n = BN_new();
buffer_get_bignum(&buffer, prv->n);
prv->e = BN_new();
buffer_get_bignum(&buffer, prv->e);
if (comment_return)
*comment_return = buffer_get_string(&buffer, NULL);
prv = key_new_private(KEY_RSA1);
buffer_get_bignum(&buffer, prv->rsa->n);
buffer_get_bignum(&buffer, prv->rsa->e);
if (commentp)
*commentp = buffer_get_string(&buffer, NULL);
else
xfree(buffer_get_string(&buffer, NULL));
@ -378,8 +382,8 @@ load_private_key_rsa(int fd, const char *filename,
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_decrypt(&ciphercontext, (unsigned char *) cp,
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_decrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&buffer);
@ -388,138 +392,183 @@ load_private_key_rsa(int fd, const char *filename,
if (check1 != buffer_get_char(&decrypted) ||
check2 != buffer_get_char(&decrypted)) {
if (strcmp(passphrase, "") != 0)
debug("Bad passphrase supplied for key file %.200s.", filename);
debug("Bad passphrase supplied for key file %.200s.",
filename);
/* Bad passphrase. */
buffer_free(&decrypted);
fail:
BN_clear_free(prv->n);
prv->n = NULL;
BN_clear_free(prv->e);
prv->e = NULL;
if (comment_return)
xfree(*comment_return);
return 0;
goto fail;
}
/* Read the rest of the private key. */
prv->d = BN_new();
buffer_get_bignum(&decrypted, prv->d);
prv->iqmp = BN_new();
buffer_get_bignum(&decrypted, prv->iqmp); /* u */
/* in SSL and SSH p and q are exchanged */
prv->q = BN_new();
buffer_get_bignum(&decrypted, prv->q); /* p */
prv->p = BN_new();
buffer_get_bignum(&decrypted, prv->p); /* q */
buffer_get_bignum(&decrypted, prv->rsa->d);
buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
/* in SSL and SSH v1 p and q are exchanged */
buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
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->q, BN_value_one());
prv->dmq1 = BN_new();
BN_mod(prv->dmq1, prv->d, aux, ctx);
BN_sub(aux, prv->rsa->q, BN_value_one());
BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
BN_sub(aux, prv->p, BN_value_one());
prv->dmp1 = BN_new();
BN_mod(prv->dmp1, prv->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);
buffer_free(&decrypted);
close(fd);
return prv;
return 1;
fail:
if (commentp)
xfree(*commentp);
close(fd);
key_free(prv);
return NULL;
}
int
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
Key *
key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{
DSA *dsa;
BIO *in;
FILE *fp;
EVP_PKEY *pk = NULL;
Key *prv = NULL;
char *name = "<no key>";
in = BIO_new(BIO_s_file());
if (in == NULL) {
error("BIO_new failed");
return 0;
}
fp = fdopen(fd, "r");
if (fp == NULL) {
error("fdopen failed");
return 0;
error("fdopen failed: %s", strerror(errno));
close(fd);
return NULL;
}
BIO_set_fp(in, fp, BIO_NOCLOSE);
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
if (dsa == NULL) {
debug("PEM_read_bio_DSAPrivateKey failed");
} else {
/* replace k->dsa with loaded key */
DSA_free(k->dsa);
k->dsa = dsa;
}
BIO_free(in);
fclose(fp);
if (comment_return)
*comment_return = xstrdup("dsa w/o comment");
debug("read DSA private key done");
#ifdef DEBUG_DSS
DSA_print_fp(stderr, dsa, 8);
pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
if (pk == NULL) {
debug("PEM_read_PrivateKey failed");
(void)ERR_get_error();
} else if (pk->type == EVP_PKEY_RSA &&
(type == KEY_UNSPEC||type==KEY_RSA)) {
prv = key_new(KEY_UNSPEC);
prv->rsa = EVP_PKEY_get1_RSA(pk);
prv->type = KEY_RSA;
name = "rsa w/o comment";
#ifdef DEBUG_PK
RSA_print_fp(stderr, prv->rsa, 8);
#endif
return dsa != NULL ? 1 : 0;
} else if (pk->type == EVP_PKEY_DSA &&
(type == KEY_UNSPEC||type==KEY_DSA)) {
prv = key_new(KEY_UNSPEC);
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
name = "dsa w/o comment";
#ifdef DEBUG_PK
DSA_print_fp(stderr, prv->dsa, 8);
#endif
} else {
error("PEM_read_PrivateKey: mismatch or "
"unknown EVP_PKEY save_type %d", pk->save_type);
}
fclose(fp);
if (pk != NULL)
EVP_PKEY_free(pk);
if (prv != NULL && commentp)
*commentp = xstrdup(name);
debug("read PEM private key done: type %s",
prv ? key_type(prv) : "<unknown>");
return prv;
}
int
load_private_key(const char *filename, const char *passphrase, Key *key,
char **comment_return)
key_perm_ok(int fd, const char *filename)
{
int fd;
int ret = 0;
struct stat st;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
/* check owner and modes */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) ||
(st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
close(fd);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.",
st.st_mode & 0777, filename);
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.");
return 0;
}
switch (key->type) {
case KEY_RSA:
if (key->rsa->e != NULL) {
BN_clear_free(key->rsa->e);
key->rsa->e = NULL;
}
if (key->rsa->n != NULL) {
BN_clear_free(key->rsa->n);
key->rsa->n = NULL;
}
ret = load_private_key_rsa(fd, filename, passphrase,
key->rsa, comment_return);
return 1;
}
Key *
key_load_private_type(int type, const char *filename, const char *passphrase,
char **commentp)
{
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
if (!key_perm_ok(fd, filename)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
}
switch (type) {
case KEY_RSA1:
return key_load_private_rsa1(fd, filename, passphrase,
commentp);
/* closes fd */
break;
case KEY_DSA:
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
case KEY_RSA:
case KEY_UNSPEC:
return key_load_private_pem(fd, type, passphrase, commentp);
/* closes fd */
break;
default:
close(fd);
break;
}
close(fd);
return ret;
return NULL;
}
Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp)
{
Key *pub;
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
if (!key_perm_ok(fd, filename)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
}
pub = key_load_public_rsa1(fd, filename, commentp);
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
if (pub == NULL) {
/* closes fd */
return key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
} 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);
}
}
int
do_load_public_key(const char *filename, Key *k, char **commentp)
key_try_load_public(Key *k, const char *filename, char **commentp)
{
FILE *f;
unsigned int bits;
char line[1024];
char line[4096];
char *cp;
f = fopen(filename, "r");
@ -537,8 +586,7 @@ do_load_public_key(const char *filename, Key *k, char **commentp)
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
if (*cp) {
bits = key_read(k, &cp);
if (bits != 0) {
if (key_read(k, &cp) == 1) {
if (commentp)
*commentp=xstrdup(filename);
fclose(f);
@ -551,19 +599,23 @@ do_load_public_key(const char *filename, Key *k, char **commentp)
return 0;
}
/* load public key from pubkey file */
int
try_load_public_key(const char *filename, Key *k, char **commentp)
/* load public key from ssh v1 private or any pubkey file */
Key *
key_load_public(const char *filename, char **commentp)
{
char pub[MAXPATHLEN];
Key *pub;
char file[MAXPATHLEN];
if (do_load_public_key(filename, k, commentp) == 1)
return 1;
if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN)
return 0;
if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN)
return 0;
if (do_load_public_key(pub, k, commentp) == 1)
return 1;
return 0;
pub = key_load_public_type(KEY_RSA1, filename, commentp);
if (pub != NULL)
return pub;
pub = key_new(KEY_UNSPEC);
if (key_try_load_public(pub, filename, commentp) == 1)
return pub;
if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
(strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
(key_try_load_public(pub, file, commentp) == 1))
return pub;
key_free(pub);
return NULL;
}

View file

@ -2,7 +2,6 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
*
* 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
@ -11,41 +10,27 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: authfile.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: authfile.h,v 1.6 2001/03/26 08:07:08 markus Exp $ */
#ifndef AUTHFILE_H
#define AUTHFILE_H
/*
* Saves the authentication (private) key in a file, encrypting it with
* passphrase.
* For RSA keys: The identification of the file (lowest 64 bits of n)
* will precede the key to provide identification of the key without
* needing a passphrase.
*/
int
save_private_key(const char *filename, const char *passphrase,
Key * private_key, const char *comment);
key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment);
/*
* Loads the public part of the key file (public key and comment). Returns 0
* if an error occurred; zero if the public key was successfully read. The
* comment of the key is returned in comment_return if it is non-NULL; the
* caller must free the value with xfree.
*/
int load_public_key(const char *filename, Key * pub, char **comment_return);
int try_load_public_key(const char *filename, Key * pub, char **comment_return);
Key *
key_load_public(const char *filename, char **commentp);
/*
* Loads the private key from the file. Returns 0 if an error is encountered
* (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key. The comment of the key is returned in
* comment_return if it is non-NULL; the caller must free the value with
* xfree.
*/
int
load_private_key(const char *filename, const char *passphrase,
Key * private_key, char **comment_return);
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);
#endif

View file

@ -37,13 +37,13 @@
*/
#include "includes.h"
RCSID("$OpenBSD: bufaux.c,v 1.13 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
#include "ssh.h"
#include <openssl/bn.h>
#include "bufaux.h"
#include "xmalloc.h"
#include "getput.h"
#include "log.h"
/*
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
@ -54,7 +54,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
{
int bits = BN_num_bits(value);
int bin_size = (bits + 7) / 8;
char unsigned *buf = xmalloc(bin_size);
u_char *buf = xmalloc(bin_size);
int oi;
char msg[2];
@ -81,7 +81,7 @@ int
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{
int bits, bytes;
unsigned char buf[2], *bin;
u_char buf[2], *bin;
/* Get the number for bits. */
buffer_get(buffer, (char *) buf, 2);
@ -90,7 +90,7 @@ 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 = (unsigned char*) buffer_ptr(buffer);
bin = (u_char *) buffer_ptr(buffer);
BN_bin2bn(bin, bytes, value);
buffer_consume(buffer, bytes);
@ -104,7 +104,7 @@ void
buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
{
int bytes = BN_num_bytes(value) + 1;
unsigned char *buf = xmalloc(bytes);
u_char *buf = xmalloc(bytes);
int oi;
int hasnohigh = 0;
buf[0] = '\0';
@ -117,7 +117,7 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
unsigned char *uc = buf;
u_char *uc = buf;
log("negativ!");
for(i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
@ -135,7 +135,7 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
/**XXX should be two's-complement */
int len;
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len);
u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
BN_bin2bn(bin, len, value);
xfree(bin);
return len;
@ -144,25 +144,41 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
/*
* Returns an integer from the buffer (4 bytes, msb first).
*/
unsigned int
u_int
buffer_get_int(Buffer *buffer)
{
unsigned char buf[4];
u_char buf[4];
buffer_get(buffer, (char *) buf, 4);
return GET_32BIT(buf);
}
u_int64_t
buffer_get_int64(Buffer *buffer)
{
u_char buf[8];
buffer_get(buffer, (char *) buf, 8);
return GET_64BIT(buf);
}
/*
* Stores an integer in the buffer in 4 bytes, msb first.
*/
void
buffer_put_int(Buffer *buffer, unsigned int value)
buffer_put_int(Buffer *buffer, u_int value)
{
char buf[4];
PUT_32BIT(buf, value);
buffer_append(buffer, buf, 4);
}
void
buffer_put_int64(Buffer *buffer, u_int64_t value)
{
char buf[8];
PUT_64BIT(buf, value);
buffer_append(buffer, buf, 8);
}
/*
* Returns an arbitrary binary string from the buffer. The string cannot
* be longer than 256k. The returned value points to memory allocated
@ -172,9 +188,9 @@ buffer_put_int(Buffer *buffer, unsigned int value)
* to the returned string, and is not counted in length.
*/
char *
buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
buffer_get_string(Buffer *buffer, u_int *length_ptr)
{
unsigned int len;
u_int len;
char *value;
/* Get the length. */
len = buffer_get_int(buffer);
@ -196,7 +212,7 @@ buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
* Stores and arbitrary binary string in the buffer.
*/
void
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
buffer_put_string(Buffer *buffer, const void *buf, u_int len)
{
buffer_put_int(buffer, len);
buffer_append(buffer, buf, len);
@ -215,7 +231,7 @@ buffer_get_char(Buffer *buffer)
{
char ch;
buffer_get(buffer, &ch, 1);
return (unsigned char) ch;
return (u_char) ch;
}
/*

View file

@ -10,12 +10,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: bufaux.h,v 1.8 2000/09/07 20:27:50 deraadt Exp $"); */
/* 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
@ -29,10 +30,12 @@ int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
/* Returns an integer from the buffer (4 bytes, msb first). */
unsigned int buffer_get_int(Buffer * buffer);
u_int buffer_get_int(Buffer * buffer);
u_int64_t buffer_get_int64(Buffer *buffer);
/* Stores an integer in the buffer in 4 bytes, msb first. */
void buffer_put_int(Buffer * buffer, unsigned int value);
void buffer_put_int(Buffer * buffer, u_int value);
void buffer_put_int64(Buffer *buffer, u_int64_t value);
/* Returns a character from the buffer (0 - 255). */
int buffer_get_char(Buffer * buffer);
@ -48,10 +51,10 @@ void buffer_put_char(Buffer * buffer, int value);
* stored there. A null character will be automatically appended to the
* returned string, and is not counted in length.
*/
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
char *buffer_get_string(Buffer * buffer, u_int *length_ptr);
/* Stores and arbitrary binary string in the buffer. */
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
void buffer_put_string(Buffer * buffer, const void *buf, u_int len);
void buffer_put_cstring(Buffer *buffer, const char *s);
#endif /* BUFAUX_H */

View file

@ -12,11 +12,11 @@
*/
#include "includes.h"
RCSID("$OpenBSD: buffer.c,v 1.8 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
#include "ssh.h"
#include "log.h"
/* Initializes the buffer structure. */
@ -53,7 +53,7 @@ buffer_clear(Buffer *buffer)
/* Appends data to the buffer, expanding it if necessary. */
void
buffer_append(Buffer *buffer, const char *data, unsigned int len)
buffer_append(Buffer *buffer, const char *data, u_int len)
{
char *cp;
buffer_append_space(buffer, &cp, len);
@ -67,7 +67,7 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
*/
void
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
buffer_append_space(Buffer *buffer, char **datap, u_int len)
{
/* If the buffer is empty, start using it from the beginning. */
if (buffer->offset == buffer->end) {
@ -100,7 +100,7 @@ restart:
/* Returns the number of bytes of data in the buffer. */
unsigned int
u_int
buffer_len(Buffer *buffer)
{
return buffer->end - buffer->offset;
@ -109,10 +109,11 @@ buffer_len(Buffer *buffer)
/* Gets data from the beginning of the buffer. */
void
buffer_get(Buffer *buffer, char *buf, unsigned int len)
buffer_get(Buffer *buffer, char *buf, u_int len)
{
if (len > buffer->end - buffer->offset)
fatal("buffer_get: trying to get more bytes than in buffer");
fatal("buffer_get: trying to get more bytes %d than in buffer %d",
len, buffer->end - buffer->offset);
memcpy(buf, buffer->buf + buffer->offset, len);
buffer->offset += len;
}
@ -120,7 +121,7 @@ buffer_get(Buffer *buffer, char *buf, unsigned int len)
/* Consumes the given number of bytes from the beginning of the buffer. */
void
buffer_consume(Buffer *buffer, unsigned int bytes)
buffer_consume(Buffer *buffer, u_int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_consume: trying to get more bytes than in buffer");
@ -130,7 +131,7 @@ buffer_consume(Buffer *buffer, unsigned int bytes)
/* Consumes the given number of bytes from the end of the buffer. */
void
buffer_consume_end(Buffer *buffer, unsigned int bytes)
buffer_consume_end(Buffer *buffer, u_int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_consume_end: trying to get more bytes than in buffer");
@ -151,9 +152,14 @@ void
buffer_dump(Buffer *buffer)
{
int i;
unsigned char *ucp = (unsigned char *) buffer->buf;
u_char *ucp = (u_char *) buffer->buf;
for (i = buffer->offset; i < buffer->end; i++)
fprintf(stderr, " %02x", ucp[i]);
fprintf(stderr, "\n");
for (i = buffer->offset; i < buffer->end; i++) {
fprintf(stderr, "%02x", ucp[i]);
if ((i-buffer->offset)%16==15)
fprintf(stderr, "\r\n");
else if ((i-buffer->offset)%2==1)
fprintf(stderr, " ");
}
fprintf(stderr, "\r\n");
}

View file

@ -11,16 +11,16 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: buffer.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */
/* 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. */
unsigned int alloc; /* Number of bytes allocated for data. */
unsigned int offset; /* Offset of first byte containing data. */
unsigned int end; /* Offset of last byte containing 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);
@ -33,26 +33,26 @@ void buffer_free(Buffer * buffer);
void buffer_clear(Buffer * buffer);
/* Appends data to the buffer, expanding it if necessary. */
void buffer_append(Buffer * buffer, const char *data, unsigned int len);
void buffer_append(Buffer * buffer, const char *data, u_int len);
/*
* 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, unsigned int len);
void buffer_append_space(Buffer * buffer, char **datap, u_int len);
/* Returns the number of bytes of data in the buffer. */
unsigned int buffer_len(Buffer * buffer);
u_int buffer_len(Buffer * buffer);
/* Gets data from the beginning of the buffer. */
void buffer_get(Buffer * buffer, char *buf, unsigned int len);
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, unsigned int bytes);
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, unsigned int bytes);
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);

View file

@ -12,11 +12,14 @@
*/
#include "includes.h"
RCSID("$OpenBSD: canohost.c,v 1.16 2000/10/21 17:04:22 markus Exp $");
RCSID("$OpenBSD: canohost.c,v 1.26 2001/04/18 14:15:00 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "canohost.h"
void check_ip_options(int socket, char *ipaddr);
/*
* Return the canonical name of the host at the other end of the socket. The
@ -24,121 +27,124 @@ RCSID("$OpenBSD: canohost.c,v 1.16 2000/10/21 17:04:22 markus Exp $");
*/
char *
get_remote_hostname(int socket)
get_remote_hostname(int socket, int reverse_mapping_check)
{
struct sockaddr_storage from;
int i;
socklen_t fromlen;
struct addrinfo hints, *ai, *aitop;
char name[MAXHOSTNAMELEN];
char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
if (from.ss_family == AF_INET)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
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) {
/* Got host name. */
name[sizeof(name) - 1] = '\0';
/*
* Convert it to all lowercase (which is expected by the rest
* of this software).
*/
for (i = 0; name[i]; i++)
if (isupper(name[i]))
name[i] = tolower(name[i]);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Address was found for the host name. We accept the host name. */
} else {
/* Host name not found. Use ascii representation of the address. */
strlcpy(name, ntop, sizeof name);
log("Could not reverse map address %.100s.", name);
NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
log("Could not reverse map address %.100s.", ntop);
return xstrdup(ntop);
}
check_ip_options:
/* Got host name. */
name[sizeof(name) - 1] = '\0';
/*
* If IP options are supported, make sure there are none (log and
* disconnect them if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
* Convert it to all lowercase (which is expected by the rest
* of this software).
*/
/* IP options -- IPv4 only */
if (from.ss_family == AF_INET) {
unsigned char options[200], *ucp;
char text[1024], *cp;
socklen_t option_size;
int ipproto;
struct protoent *ip;
for (i = 0; name[i]; i++)
if (isupper(name[i]))
name[i] = tolower(name[i]);
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options,
&option_size) >= 0 && option_size != 0) {
cp = text;
/* Note: "text" buffer must be at least 3x as big as options. */
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
sprintf(cp, " %2.2x", *ucp);
log("Connection from %.100s with IP options:%.800s",
ntop, text);
packet_disconnect("Connection from %.100s with IP options:%.800s",
ntop, text);
}
if (!reverse_mapping_check)
return xstrdup(name);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
log("reverse mapping checking getaddrinfo for %.700s "
"failed - POSSIBLE BREAKIN ATTEMPT!", name);
return xstrdup(ntop);
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not "
"map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
return xstrdup(ntop);
}
return xstrdup(name);
}
/*
* If IP options are supported, make sure there are none (log and
* disconnect them if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
*/
/* IPv4 only */
void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200];
char text[sizeof(options) * 3 + 1];
socklen_t option_size;
int i, ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
snprintf(text + i*3, sizeof(text) - i*3,
" %2.2x", options[i]);
log("Connection from %.100s with IP options:%.800s",
ipaddr, text);
packet_disconnect("Connection from %.100s with IP options:%.800s",
ipaddr, text);
}
}
/*
* Return the canonical name of the host in the other side of the current
* connection. The host name is cached, so it is efficient to call this
@ -146,23 +152,87 @@ check_ip_options:
*/
const char *
get_canonical_hostname()
get_canonical_hostname(int reverse_mapping_check)
{
static char *canonical_host_name = NULL;
static int reverse_mapping_checked = 0;
/* Check if we have previously retrieved this same name. */
if (canonical_host_name != NULL)
return canonical_host_name;
/* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) {
if (reverse_mapping_checked != reverse_mapping_check)
xfree(canonical_host_name);
else
return canonical_host_name;
}
/* 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());
canonical_host_name = get_remote_hostname(
packet_get_connection_in(), reverse_mapping_check);
else
canonical_host_name = xstrdup("UNKNOWN");
reverse_mapping_checked = reverse_mapping_check;
return canonical_host_name;
}
/*
* Returns the remote IP-address of socket as a string. The returned
* string must be freed.
*/
char *
get_socket_address(int socket, int remote, int flags)
{
struct sockaddr_storage addr;
socklen_t addrlen;
char ntop[NI_MAXHOST];
/* Get IP address of client. */
addrlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
if (remote) {
if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
< 0) {
debug("get_socket_ipaddr: getpeername failed: %.100s",
strerror(errno));
return NULL;
}
} else {
if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
< 0) {
debug("get_socket_ipaddr: getsockname failed: %.100s",
strerror(errno));
return NULL;
}
}
/* Get the address in ascii. */
if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
NULL, 0, flags) != 0) {
error("get_socket_ipaddr: getnameinfo %d failed", flags);
return NULL;
}
return xstrdup(ntop);
}
char *
get_peer_ipaddr(int socket)
{
return get_socket_address(socket, 1, NI_NUMERICHOST);
}
char *
get_local_ipaddr(int socket)
{
return get_socket_address(socket, 0, NI_NUMERICHOST);
}
char *
get_local_name(int socket)
{
return get_socket_address(socket, 0, NI_NAMEREQD);
}
/*
* Returns the IP-address of the remote host as a string. The returned
* string must not be freed.
@ -172,41 +242,33 @@ const char *
get_remote_ipaddr()
{
static char *canonical_host_ip = NULL;
struct sockaddr_storage from;
socklen_t fromlen;
int socket;
char ntop[NI_MAXHOST];
/* Check whether we have chached the name. */
if (canonical_host_ip != NULL)
return canonical_host_ip;
/* If not a socket, return UNKNOWN. */
if (!packet_connection_is_on_socket()) {
canonical_host_ip = xstrdup("UNKNOWN");
return canonical_host_ip;
/* Check whether we have cached the ipaddr. */
if (canonical_host_ip == NULL) {
if (packet_connection_is_on_socket()) {
canonical_host_ip =
get_peer_ipaddr(packet_get_connection_in());
if (canonical_host_ip == NULL)
fatal_cleanup();
} else {
/* If not on socket, return UNKNOWN. */
canonical_host_ip = xstrdup("UNKNOWN");
}
}
/* Get client socket. */
socket = packet_get_connection_in();
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Get the IP address in ascii. */
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
canonical_host_ip = xstrdup(ntop);
/* Return ip address string. */
return canonical_host_ip;
}
const char *
get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname(reverse_mapping_check);
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
}
/* Returns the local/remote port for the socket. */
int

38
crypto/openssh/canohost.h Normal file
View file

@ -0,0 +1,38 @@
/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* 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);
/*
* 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);
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);

File diff suppressed because it is too large Load diff

View file

@ -32,11 +32,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.22 2000/10/27 07:48:22 markus Exp $"); */
/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
#ifndef CHANNELS_H
#define CHANNELS_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. */
@ -49,7 +51,10 @@
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
#define SSH_CHANNEL_LARVAL 10 /* larval session */
#define SSH_CHANNEL_MAX_TYPE 11
#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
/*
* Data structure for channel data. This is iniailized in channel_allocate
@ -73,6 +78,7 @@ struct Channel {
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
int isatty; /* rfd is a tty */
Buffer input; /* data read from socket, to be sent over
* encrypted connection */
Buffer output; /* data received over encrypted connection for
@ -147,7 +153,6 @@ 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);
void channel_input_open(int type, int plen, void *ctxt);
/* Sets specific protocol options. */
void channel_set_options(int hostname_in_open);
@ -162,8 +167,13 @@ int channel_allocate(int type, int sock, char *remote_name);
/* Free the channel and close its socket. */
void channel_free(int channel);
/* Add any bits relevant to channels in select bitmasks. */
void channel_prepare_select(fd_set * readset, fd_set * writeset);
/*
* Allocate/update select bitmasks and add any bits relevant to channels in
* select bitmasks.
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
int rekeying);
/*
* After select, perform any appropriate operations for channels which have
@ -187,9 +197,6 @@ void channel_stop_listening(void);
*/
void channel_close_all(void);
/* Returns the maximum file descriptor number used by the channels. */
int channel_max_fd(void);
/* Returns true if there is still an open channel over the connection. */
int channel_still_open(void);
@ -202,12 +209,15 @@ char *channel_open_message(void);
/*
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side. This never returns if there was an
* error.
* channel to host:port from remote side.
*/
void
channel_request_local_forwarding(u_short port, const char *host,
u_short remote_port, int gateway_ports);
int
channel_request_local_forwarding(u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports);
int
channel_request_forwarding(const char *listen_address, u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports,
int remote_fwd);
/*
* Initiate forwarding of connections to port "port" on remote host through
@ -220,12 +230,18 @@ channel_request_remote_forwarding(u_short port, const char *host,
u_short remote_port);
/*
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
* called by the server, because the user could connect to any port anyway,
* and the server has no way to know but to trust the client anyway.
* Permits opening to any host/port if permitted_opens[] is empty. This is
* usually called by the server, because the user could connect to any port
* anyway, and the server has no way to know but to trust the client anyway.
*/
void channel_permit_all_opens(void);
/* Add host/port to list of allowed targets for port forwarding */
void channel_add_permitted_opens(char *host, int port);
/* Flush list */
void channel_clear_permitted_opens(void);
/*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
* listening for the port, and sends back a success reply (or disconnect
@ -288,6 +304,9 @@ 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);
#endif

View file

@ -35,10 +35,11 @@
*/
#include "includes.h"
RCSID("$OpenBSD: cipher.c,v 1.37 2000/10/23 19:31:54 markus Exp $");
RCSID("$OpenBSD: cipher.c,v 1.43 2001/02/04 15:32:23 stevesk Exp $");
#include "ssh.h"
#include "xmalloc.h"
#include "log.h"
#include "cipher.h"
#include <openssl/md5.h>
@ -154,14 +155,9 @@ des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
memcpy(&iv1, iv2, 8);
des_cbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
memcpy(&iv1, dest + len - 8, 8);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
des_cbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
memcpy(iv3, dest + len - 8, 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,
@ -173,22 +169,16 @@ des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
memcpy(&iv1, iv2, 8);
des_cbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
memcpy(iv3, src + len - 8, 8);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
memcpy(iv2, dest + len - 8, 8);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
/* memcpy(&iv1, iv2, 8); */
/* Note how iv1 == iv2 on entry and exit. */
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, (unsigned char *)key);
BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
}
void
blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
@ -218,7 +208,7 @@ blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
swap_bytes(const unsigned char *src, unsigned char *dst, int n)
swap_bytes(const u_char *src, u_char *dst, int n)
{
char c[4];
@ -271,12 +261,12 @@ arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
void
cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
CAST_set_key(&cc->u.cast.key, keylen, (unsigned char *) key);
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)
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy(cc->u.cast.iv, (char *)iv, 8);
}
@ -305,7 +295,7 @@ rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
void
rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
}
@ -425,15 +415,15 @@ Cipher ciphers[] = {
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, NULL, NULL, NULL }
};
/*--*/
unsigned int
u_int
cipher_mask_ssh1(int client)
{
unsigned int mask = 0;
u_int mask = 0;
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH;
if (client) {
@ -552,7 +542,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
const char *passphrase)
{
MD5_CTX md;
unsigned char digest[16];
u_char digest[16];
MD5_Init(&md);
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));

View file

@ -32,7 +32,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: cipher.h,v 1.22 2000/10/13 18:59:14 markus Exp $"); */
/* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
#ifndef CIPHER_H
#define CIPHER_H
@ -103,7 +103,7 @@ struct Cipher {
void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
};
unsigned int cipher_mask_ssh1(int client);
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);

View file

@ -1,8 +1,36 @@
/* $OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt 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.
*/
#include "includes.h"
RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $");
RCSID("$OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "cli.h"
#include <vis.h>
static int cli_input = -1;
@ -32,7 +60,7 @@ cli_open(int from_stdin)
cli_input = STDIN_FILENO;
cli_output = STDERR_FILENO;
} else {
cli_input = cli_output = open("/dev/tty", O_RDWR);
cli_input = cli_output = open(_PATH_TTY, O_RDWR);
if (cli_input < 0)
fatal("You have no controlling tty. Cannot read passphrase.");
}
@ -43,7 +71,7 @@ cli_open(int from_stdin)
}
static void
cli_close()
cli_close(void)
{
if (!cli_from_stdin && cli_input >= 0)
close(cli_input);
@ -54,13 +82,13 @@ cli_close()
}
void
intrcatch()
intrcatch(int sig)
{
intr = 1;
}
static void
cli_echo_disable()
cli_echo_disable(void)
{
sigemptyset(&nset);
sigaddset(&nset, SIGTSTP);
@ -83,7 +111,7 @@ cli_echo_disable()
}
static void
cli_echo_restore()
cli_echo_restore(void)
{
if (echo_modified != 0) {
tcsetattr(cli_input, TCSANOW, &otio);
@ -108,12 +136,16 @@ cli_read(char* buf, int size, int echo)
{
char ch = 0;
int i = 0;
int n;
if (!echo)
cli_echo_disable();
while (ch != '\n') {
if (read(cli_input, &ch, 1) != 1)
n = read(cli_input, &ch, 1);
if (n == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (n != 1)
break;
if (ch == '\n' || intr != 0)
break;
@ -137,18 +169,21 @@ cli_write(char* buf, int size)
output = xmalloc(4*size);
for (p = output, i = 0; i < size; i++) {
if (buf[i] == '\n')
*p++ = buf[i];
else
p = vis(p, buf[i], 0, 0);
}
if (buf[i] == '\n' || buf[i] == '\r')
*p++ = buf[i];
else
p = vis(p, buf[i], 0, 0);
}
len = p - output;
for (pos = 0; pos < len; pos += ret) {
ret = write(cli_output, output + pos, len - pos);
if (ret == -1)
if (ret == -1) {
xfree(output);
return -1;
}
}
xfree(output);
return 0;
}

View file

@ -1,4 +1,30 @@
/* $OpenBSD: cli.h,v 1.2 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt 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.
*/
/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt Exp $ */
#ifndef CLI_H
#define CLI_H
@ -9,8 +35,8 @@
* of response depending on arg. Tries to ensure that no other userland
* buffer is storing the response.
*/
char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable);
char* cli_prompt(char* prompt, int echo_enable);
void cli_mesg(char* mesg);
char * cli_read_passphrase(char * prompt, int from_stdin, int echo_enable);
char * cli_prompt(char * prompt, int echo_enable);
void cli_mesg(char * mesg);
#endif /* CLI_H */

View file

@ -59,22 +59,28 @@
*/
#include "includes.h"
RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $");
RCSID("$OpenBSD: clientloop.c,v 1.65 2001/04/20 07:17:51 djm Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "ssh1.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "packet.h"
#include "buffer.h"
#include "readconf.h"
#include "ssh2.h"
#include "compat.h"
#include "channels.h"
#include "dispatch.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "readconf.h"
#include "clientloop.h"
#include "authfd.h"
#include "atomicio.h"
#include "sshtty.h"
#include "misc.h"
/* import options */
extern Options options;
@ -97,15 +103,6 @@ extern char *host;
*/
static volatile int received_window_change_signal = 0;
/* Terminal modes, as saved by enter_raw_mode. */
static struct termios saved_tio;
/*
* Flag indicating whether we are in raw mode. This is used by
* enter_raw_mode and leave_raw_mode.
*/
static int in_raw_mode = 0;
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
static int in_non_blocking_mode = 0;
@ -119,60 +116,23 @@ static int stdin_eof; /* EOF has been encountered on standard error. */
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
static Buffer stderr_buffer; /* Buffer for stderr data. */
static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
static unsigned int buffer_high;/* Soft max buffer size. */
static int max_fd; /* Maximum file descriptor number in select(). */
static u_long stdin_bytes, stdout_bytes, stderr_bytes;
static u_int buffer_high;/* Soft max buffer size. */
static int connection_in; /* Connection to server (input). */
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);
int session_ident = -1;
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
void
leave_raw_mode()
{
if (!in_raw_mode)
return;
in_raw_mode = 0;
if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
perror("tcsetattr");
fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
}
/* Puts the user\'s terminal in raw mode. */
void
enter_raw_mode()
{
struct termios tio;
if (tcgetattr(fileno(stdin), &tio) < 0)
perror("tcgetattr");
saved_tio = tio;
tio.c_iflag |= IGNPAR;
tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
#ifdef IEXTEN
tio.c_lflag &= ~IEXTEN;
#endif /* IEXTEN */
tio.c_oflag &= ~OPOST;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
perror("tcsetattr");
in_raw_mode = 1;
fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
}
/*XXX*/
extern Kex *xxx_kex;
/* Restores stdin to blocking mode. */
void
leave_non_blocking()
leave_non_blocking(void)
{
if (in_non_blocking_mode) {
(void) fcntl(fileno(stdin), F_SETFL, 0);
@ -184,7 +144,7 @@ leave_non_blocking()
/* Puts stdin terminal in non-blocking mode. */
void
enter_non_blocking()
enter_non_blocking(void)
{
in_non_blocking_mode = 1;
(void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
@ -211,7 +171,7 @@ window_change_handler(int sig)
void
signal_handler(int sig)
{
if (in_raw_mode)
if (in_raw_mode())
leave_raw_mode();
if (in_non_blocking_mode)
leave_non_blocking();
@ -226,7 +186,7 @@ signal_handler(int sig)
*/
double
get_current_time()
get_current_time(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
@ -240,7 +200,7 @@ get_current_time()
*/
void
client_check_initial_eof_on_stdin()
client_check_initial_eof_on_stdin(void)
{
int len;
char buf[1];
@ -276,12 +236,10 @@ client_check_initial_eof_on_stdin()
* and also process it as an escape character if
* appropriate.
*/
if ((unsigned char) buf[0] == escape_char)
if ((u_char) buf[0] == escape_char)
escape_pending = 1;
else {
else
buffer_append(&stdin_buffer, buf, 1);
stdin_bytes += 1;
}
}
leave_non_blocking();
}
@ -294,9 +252,9 @@ client_check_initial_eof_on_stdin()
*/
void
client_make_packets_from_stdin_data()
client_make_packets_from_stdin_data(void)
{
unsigned int len;
u_int len;
/* Send buffered stdin data to the server. */
while (buffer_len(&stdin_buffer) > 0 &&
@ -309,6 +267,7 @@ client_make_packets_from_stdin_data()
packet_put_string(buffer_ptr(&stdin_buffer), len);
packet_send();
buffer_consume(&stdin_buffer, len);
stdin_bytes += len;
/* If we have a pending EOF, send it now. */
if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
packet_start(SSH_CMSG_EOF);
@ -325,7 +284,7 @@ client_make_packets_from_stdin_data()
*/
void
client_check_window_change()
client_check_window_change(void)
{
struct winsize ws;
@ -362,45 +321,37 @@ client_check_window_change()
*/
void
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
{
/* Initialize select masks. */
FD_ZERO(readset);
FD_ZERO(writeset);
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
if (!compat20) {
/* Read from the connection, unless our buffers are full. */
if (buffer_len(&stdout_buffer) < buffer_high &&
buffer_len(&stderr_buffer) < buffer_high &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
/*
* Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
if (!stdin_eof && packet_not_very_much_data_to_write())
FD_SET(fileno(stdin), readset);
FD_SET(fileno(stdin), *readsetp);
/* Select stdout/stderr if have data in buffer. */
if (buffer_len(&stdout_buffer) > 0)
FD_SET(fileno(stdout), writeset);
FD_SET(fileno(stdout), *writesetp);
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), writeset);
FD_SET(fileno(stderr), *writesetp);
} else {
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
}
/* Add any selections by the channel mechanism. */
channel_prepare_select(readset, writeset);
/* Select server connection if have data to write to the server. */
if (packet_have_data_to_write())
FD_SET(connection_out, writeset);
/* move UP XXX */
/* Update maximum file descriptor number, if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
FD_SET(connection_out, *writesetp);
/*
* Wait for something to happen. This will suspend the process until
@ -411,17 +362,22 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
* SSH_MSG_IGNORE packet when the timeout expires.
*/
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
char buf[100];
/* Some systems fail to clear these automatically. */
FD_ZERO(readset);
FD_ZERO(writeset);
/*
* We have to clear the select masks, because we return.
* We have to return, because the mainloop checks for the flags
* set by the signal handlers.
*/
memset(*readsetp, 0, *maxfdp);
memset(*writesetp, 0, *maxfdp);
if (errno == EINTR)
return;
/* Note: we might still have data in the buffers. */
snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
}
}
@ -487,7 +443,6 @@ client_process_net_input(fd_set * readset)
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
host);
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
@ -495,7 +450,7 @@ client_process_net_input(fd_set * readset)
* There is a kernel bug on Solaris that causes select to
* sometimes wake up even though there is no data available.
*/
if (len < 0 && errno == EAGAIN)
if (len < 0 && (errno == EAGAIN || errno == EINTR))
len = 0;
if (len < 0) {
@ -503,7 +458,6 @@ client_process_net_input(fd_set * readset)
snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
host, strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
@ -518,8 +472,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
char string[1024];
pid_t pid;
int bytes = 0;
unsigned int i;
unsigned char ch;
u_int i;
u_char ch;
char *s;
for (i = 0; i < len; i++) {
@ -537,7 +491,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* Terminate the connection. */
snprintf(string, sizeof string, "%c.\r\n", escape_char);
buffer_append(berr, string, strlen(string));
/*stderr_bytes += strlen(string); XXX*/
quit_pending = 1;
return -1;
@ -547,7 +500,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* Print a message to that effect to the user. */
snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
buffer_append(berr, string, strlen(string));
/*stderr_bytes += strlen(string); XXX*/
/* Restore terminal modes and suspend. */
client_suspend_self(bin, bout, berr);
@ -555,6 +507,15 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* We have been continued. */
continue;
case 'R':
if (compat20) {
if (datafellows & SSH_BUG_NOREKEY)
log("Server does not support re-keying");
else
need_rekeying = 1;
}
continue;
case '&':
/* XXX does not work yet with proto 2 */
if (compat20)
@ -605,6 +566,7 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
"%c?\r\n\
Supported escape sequences:\r\n\
~. - terminate connection\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\
@ -657,7 +619,6 @@ Supported escape sequences:\r\n\
void
client_process_input(fd_set * readset)
{
int ret;
int len;
char buf[8192];
@ -665,6 +626,8 @@ client_process_input(fd_set * readset)
if (FD_ISSET(fileno(stdin), readset)) {
/* Read as much as possible. */
len = read(fileno(stdin), buf, sizeof(buf));
if (len < 0 && (errno == EAGAIN || errno == EINTR))
return; /* we'll try again later */
if (len <= 0) {
/*
* Received EOF or error. They are treated
@ -674,7 +637,6 @@ client_process_input(fd_set * readset)
if (len < 0) {
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
}
/* Mark that we have seen EOF. */
stdin_eof = 1;
@ -695,16 +657,14 @@ client_process_input(fd_set * readset)
* Just append the data to buffer.
*/
buffer_append(&stdin_buffer, buf, len);
stdin_bytes += len;
} else {
/*
* Normal, successful read. But we have an escape character
* and have to process the characters one by one.
*/
ret = process_escapes(&stdin_buffer, &stdout_buffer, &stderr_buffer, buf, len);
if (ret == -1)
if (process_escapes(&stdin_buffer, &stdout_buffer,
&stderr_buffer, buf, len) == -1)
return;
stdout_bytes += ret;
}
}
}
@ -721,7 +681,7 @@ client_process_output(fd_set * writeset)
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
buffer_len(&stdout_buffer));
if (len <= 0) {
if (errno == EAGAIN)
if (errno == EINTR || errno == EAGAIN)
len = 0;
else {
/*
@ -730,13 +690,13 @@ client_process_output(fd_set * writeset)
*/
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
}
/* Consume printed data from the buffer. */
buffer_consume(&stdout_buffer, len);
stdout_bytes += len;
}
/* Write buffered output to stderr. */
if (FD_ISSET(fileno(stderr), writeset)) {
@ -744,7 +704,7 @@ client_process_output(fd_set * writeset)
len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
buffer_len(&stderr_buffer));
if (len <= 0) {
if (errno == EAGAIN)
if (errno == EINTR || errno == EAGAIN)
len = 0;
else {
/* EOF or error, but can't even print error message. */
@ -754,6 +714,7 @@ client_process_output(fd_set * writeset)
}
/* Consume printed characters from the buffer. */
buffer_consume(&stderr_buffer, len);
stderr_bytes += len;
}
}
@ -770,9 +731,9 @@ client_process_output(fd_set * writeset)
*/
void
client_process_buffered_input_packets()
client_process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, NULL);
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
}
/* scan buf[] for '~' before sending data to the peer */
@ -784,6 +745,17 @@ simple_escape_filter(Channel *c, char *buf, int len)
return process_escapes(&c->input, &c->output, &c->extended, buf, len);
}
void
client_channel_closed(int id, void *arg)
{
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
session_closed = 1;
if (in_raw_mode())
leave_raw_mode();
}
/*
* Implements the interactive session with the server. This is called after
* the user has been authenticated, and a command has been started on the
@ -794,8 +766,9 @@ simple_escape_filter(Channel *c, char *buf, int len)
int
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 len;
int max_fd = 0, len, rekeying = 0;
char buf[100];
debug("Entering interactive session.");
@ -810,9 +783,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
buffer_high = 64 * 1024;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
max_fd = connection_in;
if (connection_out > max_fd)
max_fd = connection_out;
max_fd = MAX(connection_in, connection_out);
if (!compat20) {
/* enable nonblocking unless tty */
if (!isatty(fileno(stdin)))
set_nonblock(fileno(stdin));
if (!isatty(fileno(stdout)))
set_nonblock(fileno(stdout));
if (!isatty(fileno(stderr)))
set_nonblock(fileno(stderr));
max_fd = MAX(max_fd, fileno(stdin));
max_fd = MAX(max_fd, fileno(stdout));
max_fd = MAX(max_fd, fileno(stderr));
}
stdin_bytes = 0;
stdout_bytes = 0;
stderr_bytes = 0;
@ -837,80 +821,102 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (have_pty)
enter_raw_mode();
/* Check if we should immediately send eof on stdin. */
if (!compat20)
if (compat20) {
session_ident = ssh2_chan_id;
if (escape_char != -1)
channel_register_filter(session_ident,
simple_escape_filter);
if (session_ident != -1)
channel_register_cleanup(session_ident,
client_channel_closed);
} else {
/* Check if we should immediately send eof on stdin. */
client_check_initial_eof_on_stdin();
if (compat20 && escape_char != -1)
channel_register_filter(ssh2_chan_id, simple_escape_filter);
}
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
fd_set readset, writeset;
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
if (compat20 && !channel_still_open()) {
debug2("!channel_still_open.");
if (compat20 && session_closed && !channel_still_open())
break;
rekeying = (xxx_kex != NULL && !xxx_kex->done);
if (rekeying) {
debug("rekeying in progress");
} else {
/*
* Make packets of buffered stdin data, and buffer
* them for sending to the server.
*/
if (!compat20)
client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and
* enqueue them for sending to the server.
*/
if (packet_not_very_much_data_to_write())
channel_output_poll();
/*
* Check if the window size has changed, and buffer a
* message about it to the server if so.
*/
client_check_window_change();
if (quit_pending)
break;
}
/*
* Make packets of buffered stdin data, and buffer them for
* sending to the server.
*/
if (!compat20)
client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and buffer them
* for sending to the server.
*/
if (packet_not_very_much_data_to_write())
channel_output_poll();
/*
* Check if the window size has changed, and buffer a message
* about it to the server if so.
*/
client_check_window_change();
if (quit_pending)
break;
/*
* Wait until we have something to do (something becomes
* available on one of the descriptors).
*/
client_wait_until_can_do_something(&readset, &writeset);
client_wait_until_can_do_something(&readset, &writeset,
&max_fd, rekeying);
if (quit_pending)
break;
/* Do channel operations. */
channel_after_select(&readset, &writeset);
/* Do channel operations unless rekeying in progress. */
if (!rekeying) {
channel_after_select(readset, writeset);
if (need_rekeying) {
debug("user requests rekeying");
xxx_kex->done = 0;
kex_send_kexinit(xxx_kex);
need_rekeying = 0;
}
}
/* Buffer input from the connection. */
client_process_net_input(&readset);
client_process_net_input(readset);
if (quit_pending)
break;
if (!compat20) {
/* Buffer data from stdin */
client_process_input(&readset);
client_process_input(readset);
/*
* Process output to stdout and stderr. Output to
* the connection is processed elsewhere (above).
*/
client_process_output(&writeset);
client_process_output(writeset);
}
/* Send as much buffered packet data as possible to the sender. */
if (FD_ISSET(connection_out, &writeset))
if (FD_ISSET(connection_out, writeset))
packet_write_poll();
}
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
/* Terminate the session. */
@ -928,7 +934,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
}
/* Output any buffered data for stdout. */
while (buffer_len(&stdout_buffer) > 0) {
@ -939,6 +944,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
break;
}
buffer_consume(&stdout_buffer, len);
stdout_bytes += len;
}
/* Output any buffered data for stderr. */
@ -950,6 +956,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
break;
}
buffer_consume(&stderr_buffer, len);
stderr_bytes += len;
}
if (have_pty)
@ -980,22 +987,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
void
client_input_stdout_data(int type, int plen, void *ctxt)
{
unsigned int data_len;
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stdout_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
void
client_input_stderr_data(int type, int plen, void *ctxt)
{
unsigned int data_len;
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stderr_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
@ -1016,14 +1021,102 @@ client_input_exit_status(int type, int plen, void *ctxt)
quit_pending = 1;
}
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;
/* 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();
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);
}
xfree(originator_address);
xfree(listen_address);
return c;
}
Channel*
client_request_x11(const char *request_type, int rchan)
{
Channel *c = NULL;
char *originator;
int originator_port;
int sock, newch;
if (!options.forward_x11) {
error("Warning: ssh server tried X11 forwarding.");
error("Warning: this is probably a break in attempt by a malicious server.");
return NULL;
}
originator = packet_get_string(NULL);
if (datafellows & SSH_BUG_X11FWD) {
debug2("buggy server: x11 request w/o originator_port");
originator_port = 0;
} else {
originator_port = packet_get_int();
}
packet_done();
/* 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);
return c;
}
Channel*
client_request_agent(const char *request_type, int rchan)
{
Channel *c = NULL;
int sock, newch;
if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding.");
error("Warning: this is probably a break in attempt by a malicious server.");
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);
}
return c;
}
/* XXXX move to generic input handler */
void
client_input_channel_open(int type, int plen, void *ctxt)
{
Channel *c = NULL;
char *ctype;
int id;
unsigned int len;
u_int len;
int rchan;
int rmaxpack;
int rwindow;
@ -1036,28 +1129,12 @@ client_input_channel_open(int type, int plen, void *ctxt)
debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "x11") == 0 && options.forward_x11) {
int sock;
char *originator;
int originator_port;
originator = packet_get_string(NULL);
if (datafellows & SSH_BUG_X11FWD) {
debug2("buggy server: x11 request w/o originator_port");
originator_port = 0;
} else {
originator_port = packet_get_int();
}
packet_done();
/* XXX check permission */
xfree(originator);
/* XXX move to channels.c */
sock = x11_connect_display();
if (sock >= 0) {
id = channel_new("x11", SSH_CHANNEL_X11_OPEN,
sock, sock, -1, CHAN_X11_WINDOW_DEFAULT,
CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1);
c = channel_lookup(id);
}
if (strcmp(ctype, "forwarded-tcpip") == 0) {
c = client_request_forwarded_tcpip(ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
c = client_request_x11(ctype, rchan);
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
c = client_request_agent(ctype, rchan);
}
/* XXX duplicate : */
if (c != NULL) {
@ -1083,9 +1160,45 @@ client_input_channel_open(int type, int plen, void *ctxt)
}
xfree(ctype);
}
void
client_input_channel_req(int type, int plen, void *ctxt)
{
Channel *c = NULL;
int id, reply, success = 0;
char *rtype;
id = packet_get_int();
rtype = packet_get_string(NULL);
reply = packet_get_char();
debug("client_input_channel_req: channel %d rtype %s reply %d",
id, rtype, reply);
if (session_ident == -1) {
error("client_input_channel_req: no channel %d", session_ident);
} else if (id != session_ident) {
error("client_input_channel_req: channel %d: wrong channel: %d",
session_ident, id);
}
c = channel_lookup(id);
if (c == NULL) {
error("client_input_channel_req: channel %d: unknown channel", id);
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
}
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
void
client_init_dispatch_20()
client_init_dispatch_20(void)
{
dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
@ -1095,11 +1208,14 @@ client_init_dispatch_20()
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
client_init_dispatch_13()
client_init_dispatch_13(void)
{
dispatch_init(NULL);
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
@ -1118,14 +1234,14 @@ client_init_dispatch_13()
&x11_input_open : &deny_input_open);
}
void
client_init_dispatch_15()
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
client_init_dispatch()
client_init_dispatch(void)
{
if (compat20)
client_init_dispatch_20();
@ -1134,49 +1250,3 @@ client_init_dispatch()
else
client_init_dispatch_15();
}
void
client_input_channel_req(int id, void *arg)
{
Channel *c = NULL;
unsigned int len;
int success = 0;
int reply;
char *rtype;
rtype = packet_get_string(&len);
reply = packet_get_char();
debug("client_input_channel_req: rtype %s reply %d", rtype, reply);
c = channel_lookup(id);
if (c == NULL)
fatal("client_input_channel_req: channel %d: bad channel", id);
if (session_ident == -1) {
error("client_input_channel_req: no channel %d", id);
} else if (id != session_ident) {
error("client_input_channel_req: bad channel %d != %d",
id, session_ident);
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
}
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
void
client_set_session_ident(int id)
{
debug2("client_set_session_ident: id %d", id);
session_ident = id;
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
client_input_channel_req, (void *)0);
}

View file

@ -0,0 +1,39 @@
/* $OpenBSD: clientloop.h,v 1.4 2001/02/06 22:43:02 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 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.
*/
/* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char, int id);

View file

@ -23,13 +23,14 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compat.c,v 1.27 2000/10/31 09:31:58 markus Exp $");
RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $");
#include <regex.h>
#include "ssh.h"
#include "packet.h"
#include "xmalloc.h"
#include "compat.h"
#include <regex.h>
#include "log.h"
int compat13 = 0;
int compat20 = 0;
@ -58,19 +59,55 @@ compat_datafellows(const char *version)
char *pat;
int bugs;
} check[] = {
{ "^OpenSSH[-_]2\\.[012]", SSH_OLD_SESSIONID },
{ "^OpenSSH[-_]2\\.[012]",
SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^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|
SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.5\\.[01]p1",
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|
SSH_OLD_SESSIONID },
{ "^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|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.0\\.1[3-9]", 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_OLD_SESSIONID|
SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD },
{ "^2\\.[23]\\.0 ", SSH_BUG_HMAC},
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
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},
{ "^2\\.", SSH_BUG_HMAC}, /* XXX fallback */
{ "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
{ "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "^SSH Compatible Server", /* Netscreen */
SSH_BUG_PASSWORDPAD },
{ "^OSU_0", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.5alpha[1-3]",
SSH_BUG_PASSWORDPAD },
{ "^SSH_Version_Mapper",
SSH_BUG_SCANNER },
{ NULL, 0 }
};
/* process table, return first match */
@ -85,7 +122,7 @@ compat_datafellows(const char *version)
ret = regexec(&reg, version, 0, NULL, 0);
regfree(&reg);
if (ret == 0) {
debug("match: %s pat %s\n", version, check[i].pat);
debug("match: %s pat %s", version, check[i].pat);
datafellows = check[i].bugs;
return;
}
@ -121,3 +158,33 @@ proto_spec(const char *spec)
xfree(s);
return ret;
}
char *
compat_cipher_proposal(char *cipher_prop)
{
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';
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);
}
}
xfree(orig_prop);
debug2("Original cipher proposal: %s", cipher_prop);
debug2("Compat cipher proposal: %s", fix_ciphers);
if (!*fix_ciphers)
fatal("No available ciphers found.");
return(fix_ciphers);
}

View file

@ -21,7 +21,7 @@
* (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.11 2000/10/14 12:16:56 markus Exp $"); */
/* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */
#ifndef COMPAT_H
#define COMPAT_H
@ -31,16 +31,29 @@
#define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04
#define SSH_BUG_SIGBLOB 0x01
#define SSH_BUG_PUBKEYAUTH 0x02
#define SSH_BUG_HMAC 0x04
#define SSH_BUG_X11FWD 0x08
#define SSH_OLD_SESSIONID 0x10
#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
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *s);
int proto_spec(const char *spec);
char *compat_cipher_proposal(char *cipher_prop);
extern int compat13;
extern int compat20;
extern int datafellows;

View file

@ -12,14 +12,17 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compress.c,v 1.9 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$OpenBSD: compress.c,v 1.14 2001/04/05 10:39:01 markus Exp $");
#include "ssh.h"
#include "log.h"
#include "buffer.h"
#include "zlib.h"
#include "compress.h"
static z_stream incoming_stream;
static z_stream outgoing_stream;
static int compress_init_send_called = 0;
static int compress_init_recv_called = 0;
/*
* Initializes compression; level is compression level from 1 to 9
@ -27,19 +30,29 @@ static z_stream outgoing_stream;
*/
void
buffer_compress_init(int level)
buffer_compress_init_send(int level)
{
if (compress_init_send_called == 1)
deflateEnd(&incoming_stream);
compress_init_send_called = 1;
debug("Enabling compression at level %d.", level);
if (level < 1 || level > 9)
fatal("Bad compression level %d.", level);
inflateInit(&incoming_stream);
deflateInit(&outgoing_stream, level);
}
void
buffer_compress_init_recv(void)
{
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
compress_init_recv_called = 1;
inflateInit(&incoming_stream);
}
/* Frees any data structures allocated for compression. */
void
buffer_compress_uninit()
buffer_compress_uninit(void)
{
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
outgoing_stream.total_in, outgoing_stream.total_out,
@ -49,8 +62,10 @@ buffer_compress_uninit()
incoming_stream.total_out, incoming_stream.total_in,
incoming_stream.total_out == 0 ? 0.0 :
(double) incoming_stream.total_in / incoming_stream.total_out);
inflateEnd(&incoming_stream);
deflateEnd(&outgoing_stream);
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
if (compress_init_send_called == 1)
deflateEnd(&outgoing_stream);
}
/*
@ -73,13 +88,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
return;
/* Input is the contents of the input buffer. */
outgoing_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
outgoing_stream.next_in = (u_char *) 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 = (unsigned char *)buf;
outgoing_stream.next_out = (u_char *)buf;
outgoing_stream.avail_out = sizeof(buf);
/* Compress as much data into the buffer as possible. */
@ -112,12 +127,12 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
char buf[4096];
int status;
incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
incoming_stream.next_in = (u_char *) buffer_ptr(input_buffer);
incoming_stream.avail_in = buffer_len(input_buffer);
for (;;) {
/* Set up fixed-size output buffer. */
incoming_stream.next_out = (unsigned char *) buf;
incoming_stream.next_out = (u_char *) buf;
incoming_stream.avail_out = sizeof(buf);
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: compress.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */
/* RCSID("$OpenBSD: compress.h,v 1.8 2001/04/05 10:39:02 markus Exp $"); */
#ifndef COMPRESS_H
#define COMPRESS_H
@ -20,10 +20,11 @@
* Initializes compression; level is compression level from 1 to 9 (as in
* gzip).
*/
void buffer_compress_init(int level);
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 buffer_compress_uninit(void);
/*
* Compresses the contents of input_buffer into output_buffer. All packets

View file

@ -31,7 +31,7 @@
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* logic; the shift must be u_(bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
@ -39,11 +39,11 @@
#include "includes.h"
RCSID("$OpenBSD: crc32.c,v 1.7 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$OpenBSD: crc32.c,v 1.8 2000/12/19 23:17:56 markus Exp $");
#include "crc32.h"
static unsigned int crc32_tab[] = {
static u_int crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
@ -100,11 +100,11 @@ static unsigned int crc32_tab[] = {
/* Return a 32-bit CRC of the contents of the buffer. */
unsigned int
ssh_crc32(const unsigned char *s, unsigned int len)
u_int
ssh_crc32(const u_char *s, u_int len)
{
unsigned int i;
unsigned int crc32val;
u_int i;
u_int crc32val;
crc32val = 0;
for (i = 0; i < len; i ++) {

View file

@ -1,6 +1,6 @@
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
* Copyright (c) 1992 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for computing 32-bit CRC.
*
@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: crc32.h,v 1.8 2000/09/07 20:27:51 deraadt Exp $"); */
/* RCSID("$OpenBSD: crc32.h,v 1.10 2001/03/02 18:54:31 deraadt Exp $"); */
#ifndef CRC32_H
#define CRC32_H
@ -20,6 +20,6 @@
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
* The polynomial used is 0xedb88320.
*/
unsigned int ssh_crc32(const unsigned char *buf, unsigned int len);
u_int ssh_crc32(const u_char *buf, u_int len);
#endif /* CRC32_H */

View file

@ -1,4 +1,4 @@
/* $OpenBSD: deattack.c,v 1.10 2000/10/31 13:18:53 markus Exp $ */
/* $OpenBSD: deattack.c,v 1.13 2001/03/01 02:45:10 deraadt Exp $ */
/*
* Cryptographic attack detector for ssh - source code
@ -21,7 +21,7 @@
#include "includes.h"
#include "deattack.h"
#include "ssh.h"
#include "log.h"
#include "crc32.h"
#include "getput.h"
#include "xmalloc.h"
@ -44,23 +44,23 @@
/* Hash function (Input keys are cipher results) */
#define HASH(x) GET_32BIT(x)
#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
void
crc_update(u_int32_t *a, u_int32_t b)
{
b ^= *a;
*a = ssh_crc32((unsigned char *) &b, sizeof(b));
*a = ssh_crc32((u_char *) &b, sizeof(b));
}
/* detect if a block is used in a particular pattern */
int
check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
unsigned char *IV)
check_crc(u_char *S, u_char *buf, u_int32_t len,
u_char *IV)
{
u_int32_t crc;
unsigned char *c;
u_char *c;
crc = 0;
if (IV && !CMP(S, IV)) {
@ -82,14 +82,14 @@ check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
/* Detect a crc32 compensation attack on a packet */
int
detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
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 l;
register unsigned char *c;
unsigned char *d;
register u_char *c;
u_char *d;
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
len % SSH_BLOCKSIZE != 0) {

View file

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

View file

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
RCSID("$OpenBSD: dh.c,v 1.14 2001/04/15 08:43:45 markus Exp $");
#include "xmalloc.h"
@ -31,10 +31,13 @@ RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
#include <openssl/dh.h>
#include <openssl/evp.h>
#include "ssh.h"
#include "buffer.h"
#include "cipher.h"
#include "kex.h"
#include "dh.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
@ -66,6 +69,8 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
if (cp == NULL || *strsize == '\0' ||
(dhg->size = atoi(strsize)) == 0)
goto fail;
/* The whole group is one bit larger */
dhg->size++;
gen = strsep(&cp, " "); /* gen */
if (cp == NULL || *gen == '\0')
goto fail;
@ -74,25 +79,28 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail;
dhg->g = BN_new();
if (BN_hex2bn(&dhg->g, gen) < 0) {
BN_free(dhg->g);
goto fail;
}
dhg->p = BN_new();
if (BN_hex2bn(&dhg->p, prime) < 0) {
BN_free(dhg->g);
BN_free(dhg->p);
goto fail;
}
if (BN_hex2bn(&dhg->g, gen) == 0)
goto failclean;
if (BN_hex2bn(&dhg->p, prime) == 0)
goto failclean;
if (BN_num_bits(dhg->p) != dhg->size)
goto failclean;
return (1);
failclean:
BN_free(dhg->g);
BN_free(dhg->p);
fail:
fprintf(stderr, "Bad prime description in line %d\n", linenum);
error("Bad prime description in line %d", linenum);
return (0);
}
DH *
choose_dh(int minbits)
choose_dh(int min, int wantbits, int max)
{
FILE *f;
char line[1024];
@ -100,10 +108,9 @@ choose_dh(int minbits)
int linenum;
struct dhgroup dhg;
f = fopen(DH_PRIMES, "r");
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
perror(DH_PRIMES);
log("WARNING: %s does not exist, using old prime", DH_PRIMES);
log("WARNING: %s does not exist, using old prime", _PATH_DH_PRIMES);
return (dh_new_group1());
}
@ -116,8 +123,11 @@ choose_dh(int minbits)
BN_free(dhg.g);
BN_free(dhg.p);
if ((dhg.size > minbits && dhg.size < best) ||
(dhg.size > best && best < minbits)) {
if (dhg.size > max || dhg.size < min)
continue;
if ((dhg.size > wantbits && dhg.size < best) ||
(dhg.size > best && best < wantbits)) {
best = dhg.size;
bestcount = 0;
}
@ -127,14 +137,13 @@ choose_dh(int minbits)
fclose (f);
if (bestcount == 0) {
log("WARNING: no primes in %s, using old prime", DH_PRIMES);
return (dh_new_group1());
log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
return (NULL);
}
f = fopen(DH_PRIMES, "r");
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
perror(DH_PRIMES);
exit(1);
fatal("WARNING: %s disappeared, giving up", _PATH_DH_PRIMES);
}
linenum = 0;
@ -142,9 +151,9 @@ choose_dh(int minbits)
while (fgets(line, sizeof(line), f)) {
if (!parse_prime(linenum, line, &dhg))
continue;
if (dhg.size != best)
continue;
if (linenum++ != which) {
if ((dhg.size > max || dhg.size < min) ||
dhg.size != best ||
linenum++ != which) {
BN_free(dhg.g);
BN_free(dhg.p);
continue;
@ -152,6 +161,134 @@ choose_dh(int minbits)
break;
}
fclose(f);
if (linenum != which+1)
fatal("WARNING: line %d disappeared in %s, giving up",
which, _PATH_DH_PRIMES);
return (dh_new_group(dhg.g, dhg.p));
}
/* diffie-hellman-group1-sha1 */
int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
if (dh_pub->neg) {
log("invalid public DH value: negativ");
return 0;
}
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
return 1;
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
return 0;
}
void
dh_gen_key(DH *dh, int need)
{
int i, bits_set = 0, tries = 0;
if (dh->p == NULL)
fatal("dh_gen_key: dh->p == NULL");
if (2*need >= BN_num_bits(dh->p))
fatal("dh_gen_key: group too small: %d (2*need %d)",
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)
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))
fatal("dh_gen_key: BN_rand failed");
if (DH_generate_key(dh) == 0)
fatal("DH_generate_key");
for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
if (BN_is_bit_set(dh->priv_key, i))
bits_set++;
debug("dh_gen_key: priv key bits set: %d/%d",
bits_set, BN_num_bits(dh->priv_key));
if (tries++ > 10)
fatal("dh_gen_key: too many bad keys: giving up");
} while (!dh_pub_is_valid(dh, dh->pub_key));
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if (BN_hex2bn(&dh->p, modulus) == 0)
fatal("BN_hex2bn p");
if (BN_hex2bn(&dh->g, gen) == 0)
fatal("BN_hex2bn g");
return (dh);
}
/*
* This just returns the group, we still need to generate the exchange
* value.
*/
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
dh->p = modulus;
dh->g = gen;
return (dh);
}
DH *
dh_new_group1(void)
{
static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1));
}
/*
* Estimates the group order for a Diffie-Hellman group that has an
* attack complexity approximately the same as O(2**bits). Estimate
* with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
*/
int
dh_estimate(int bits)
{
if (bits < 64)
return (512); /* O(2**63) */
if (bits < 128)
return (1024); /* O(2**86) */
if (bits < 192)
return (2048); /* O(2**116) */
return (4096); /* O(2**156) */
}

View file

@ -1,3 +1,5 @@
/* $OpenBSD: dh.h,v 1.5 2001/04/03 19:53:29 markus Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
*
@ -30,6 +32,17 @@ struct dhgroup {
BIGNUM *p;
};
DH *choose_dh(int minbits);
DH *choose_dh(int min, int nbits, int max);
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);
int dh_estimate(int bits);
#define DH_GRP_MIN 1024
#define DH_GRP_MAX 8192
#endif

View file

@ -22,10 +22,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: dispatch.c,v 1.5 2000/09/21 11:25:34 markus Exp $");
#include "ssh.h"
RCSID("$OpenBSD: dispatch.c,v 1.10 2001/02/18 18:33:53 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
#include "log.h"
#include "dispatch.h"
#include "packet.h"
#include "compat.h"
#define DISPATCH_MIN 0
#define DISPATCH_MAX 255
@ -36,6 +40,8 @@ void
dispatch_protocol_error(int type, int plen, 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");
}
void
dispatch_init(dispatch_fn *dflt)
@ -66,7 +72,7 @@ dispatch_run(int mode, int *done, void *ctxt)
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
(*dispatch[type])(type, plen, ctxt);
else
packet_disconnect("protocol error: rcvd type %d", type);
packet_disconnect("protocol error: rcvd type %d", type);
if (done != NULL && *done)
return;
}

View file

@ -1,3 +1,5 @@
/* $OpenBSD: dispatch.h,v 1.4 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*

View file

@ -11,20 +11,39 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: getput.h,v 1.5 2000/09/07 20:27:51 deraadt Exp $"); */
/* RCSID("$OpenBSD: getput.h,v 1.7 2001/01/10 22:56:22 markus Exp $"); */
#ifndef GETPUT_H
#define GETPUT_H
/*------------ macros for storing/extracting msb first words -------------*/
#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
((unsigned long)(unsigned char)(cp)[2] << 8) | \
((unsigned long)(unsigned char)(cp)[3]))
#define GET_64BIT(cp) (((u_int64_t)(u_char)(cp)[0] << 56) | \
((u_int64_t)(u_char)(cp)[1] << 48) | \
((u_int64_t)(u_char)(cp)[2] << 40) | \
((u_int64_t)(u_char)(cp)[3] << 32) | \
((u_int64_t)(u_char)(cp)[4] << 24) | \
((u_int64_t)(u_char)(cp)[5] << 16) | \
((u_int64_t)(u_char)(cp)[6] << 8) | \
((u_int64_t)(u_char)(cp)[7]))
#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \
((unsigned long)(unsigned char)(cp)[1]))
#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \
((u_long)(u_char)(cp)[1] << 16) | \
((u_long)(u_char)(cp)[2] << 8) | \
((u_long)(u_char)(cp)[3]))
#define GET_16BIT(cp) (((u_long)(u_char)(cp)[0] << 8) | \
((u_long)(u_char)(cp)[1]))
#define PUT_64BIT(cp, value) do { \
(cp)[0] = (value) >> 56; \
(cp)[1] = (value) >> 48; \
(cp)[2] = (value) >> 40; \
(cp)[3] = (value) >> 32; \
(cp)[4] = (value) >> 24; \
(cp)[5] = (value) >> 16; \
(cp)[6] = (value) >> 8; \
(cp)[7] = (value); } while (0)
#define PUT_32BIT(cp, value) do { \
(cp)[0] = (value) >> 24; \
@ -36,26 +55,4 @@
(cp)[0] = (value) >> 8; \
(cp)[1] = (value); } while (0)
/*------------ macros for storing/extracting lsb first words -------------*/
#define GET_32BIT_LSB_FIRST(cp) \
(((unsigned long)(unsigned char)(cp)[0]) | \
((unsigned long)(unsigned char)(cp)[1] << 8) | \
((unsigned long)(unsigned char)(cp)[2] << 16) | \
((unsigned long)(unsigned char)(cp)[3] << 24))
#define GET_16BIT_LSB_FIRST(cp) \
(((unsigned long)(unsigned char)(cp)[0]) | \
((unsigned long)(unsigned char)(cp)[1] << 8))
#define PUT_32BIT_LSB_FIRST(cp, value) do { \
(cp)[0] = (value); \
(cp)[1] = (value) >> 8; \
(cp)[2] = (value) >> 16; \
(cp)[3] = (value) >> 24; } while (0)
#define PUT_16BIT_LSB_FIRST(cp, value) do { \
(cp)[0] = (value); \
(cp)[1] = (value) >> 8; } while (0)
#endif /* GETPUT_H */

View file

@ -0,0 +1,78 @@
/* $OpenBSD: groupaccess.c,v 1.3 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include "groupaccess.h"
#include "xmalloc.h"
#include "match.h"
#include "log.h"
static int ngroups;
static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */
int
ga_init(const char *user, gid_t base)
{
gid_t groups_bygid[NGROUPS_MAX + 1];
int i, j;
struct group *gr;
if (ngroups > 0)
ga_free();
ngroups = sizeof(groups_bygid) / sizeof(gid_t);
if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
log("getgrouplist: groups list too small");
for (i = 0, j = 0; i < ngroups; i++)
if ((gr = getgrgid(groups_bygid[i])) != NULL)
groups_byname[j++] = xstrdup(gr->gr_name);
return (ngroups = j);
}
int
ga_match(char * const *groups, int n)
{
int i, j;
for (i = 0; i < ngroups; i++)
for (j = 0; j < n; j++)
if (match_pattern(groups_byname[i], groups[j]))
return 1;
return 0;
}
void
ga_free(void)
{
int i;
if (ngroups > 0) {
for (i = 0; i < ngroups; i++)
xfree(groups_byname[i]);
ngroups = 0;
}
}

View file

@ -0,0 +1,49 @@
/* $OpenBSD: groupaccess.h,v 1.2 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. 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.
*/
#ifndef GROUPACCESS_H
#define GROUPACCESS_H
#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);
#endif

View file

@ -36,15 +36,13 @@
*/
#include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $");
#include "packet.h"
#include "match.h"
#include "ssh.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h"
#include "hostfile.h"
#include "log.h"
/*
* Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
@ -52,17 +50,15 @@ RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $");
*/
int
hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
{
unsigned int bits;
char *cp;
/* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
bits = key_read(ret, &cp);
if (bits == 0)
if (key_read(ret, &cp) != 1)
return 0;
/* Skip trailing whitespace. */
@ -71,14 +67,14 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
/* Return results. */
*cpp = cp;
*bitsp = bits;
*bitsp = key_size(ret);
return 1;
}
int
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
{
Key *k = key_new(KEY_RSA);
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);
@ -89,7 +85,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
int
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
{
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL)
if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
return 1;
if (bits != BN_num_bits(key->rsa->n)) {
log("Warning: %s, line %d: keysize mismatch for host %s: "
@ -109,15 +105,17 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i
*/
HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found)
check_host_in_hostfile(const char *filename, const char *host, Key *key,
Key *found, int *numret)
{
FILE *f;
char line[8192];
int linenum = 0;
unsigned int kbits, hostlen;
u_int kbits;
char *cp, *cp2;
HostStatus end_return;
debug3("check_host_in_hostfile: filename %s", filename);
if (key == NULL)
fatal("no key to look up");
/* Open the file containing the list of known hosts. */
@ -125,9 +123,6 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
if (!f)
return HOST_NEW;
/* Cache the length of the host name. */
hostlen = strlen(host);
/*
* Return value when the loop terminates. This is set to
* HOST_CHANGED if we have seen a different key for the host and have
@ -135,7 +130,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
*/
end_return = HOST_NEW;
/* Go trough the file. */
/* Go through the file. */
while (fgets(line, sizeof(line), f)) {
cp = line;
linenum++;
@ -151,7 +146,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
;
/* Check if the host name matches. */
if (match_hostname(host, cp, (unsigned int) (cp2 - cp)) != 1)
if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1)
continue;
/* Got a match. Skip host name. */
@ -166,9 +161,13 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
if (!hostfile_check_key(kbits, found, host, filename, linenum))
continue;
if (numret != NULL)
*numret = linenum;
/* Check if the current key is the same as the given key. */
if (key_equal(key, found)) {
/* Ok, they match. */
debug3("check_host_in_hostfile: match line %d", linenum);
fclose(f);
return HOST_OK;
}

View file

@ -1,3 +1,5 @@
/* $OpenBSD: hostfile.h,v 1.7 2001/02/08 19:30:51 itojun Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -12,6 +14,9 @@
#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
@ -21,8 +26,10 @@
typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED
} HostStatus;
HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found);
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

View file

@ -1,3 +1,5 @@
/* $OpenBSD: includes.h,v 1.14 2001/01/29 01:58:16 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland

View file

@ -23,375 +23,217 @@
*/
#include "includes.h"
RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 markus Exp $");
#include <openssl/crypto.h>
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "packet.h"
#include "compat.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/pem.h>
#include "cipher.h"
#include "kex.h"
#include "key.h"
#include "log.h"
#include "mac.h"
#include "match.h"
#include "dispatch.h"
#define KEX_COOKIE_LEN 16
Buffer *
kex_init(char *myproposal[PROPOSAL_MAX])
void kex_kexinit_finish(Kex *kex);
void kex_choose_conf(Kex *k);
/* put algorithm proposal into buffer */
void
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
{
int first_kex_packet_follows = 0;
unsigned char cookie[KEX_COOKIE_LEN];
u_int32_t rand = 0;
int i;
Buffer *ki = xmalloc(sizeof(*ki));
buffer_clear(b);
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if (i % 4 == 0)
rand = arc4random();
cookie[i] = rand & 0xff;
buffer_put_char(b, rand & 0xff);
rand >>= 8;
}
buffer_init(ki);
buffer_append(ki, (char *)cookie, sizeof cookie);
for (i = 0; i < PROPOSAL_MAX; i++)
buffer_put_cstring(ki, myproposal[i]);
buffer_put_char(ki, first_kex_packet_follows);
buffer_put_int(ki, 0); /* uint32 reserved */
return ki;
buffer_put_cstring(b, proposal[i]);
buffer_put_char(b, 0); /* first_kex_packet_follows */
buffer_put_int(b, 0); /* uint32 reserved */
}
/* send kexinit, parse and save reply */
void
kex_exchange_kexinit(
Buffer *my_kexinit, Buffer *peer_kexint,
char *peer_proposal[PROPOSAL_MAX])
/* parse buffer and return algorithm proposal */
char **
kex_buf2prop(Buffer *raw)
{
Buffer b;
int i;
char *ptr;
int plen;
char **proposal;
debug("send KEXINIT");
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
packet_send();
packet_write_wait();
debug("done");
proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
/*
* read and save raw KEXINIT payload in buffer. this is used during
* computation of the session_id and the session keys.
*/
debug("wait KEXINIT");
packet_read_expect(&plen, SSH2_MSG_KEXINIT);
ptr = packet_get_raw(&plen);
buffer_append(peer_kexint, ptr, plen);
/* parse packet and save algorithm proposal */
buffer_init(&b);
buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
/* skip cookie */
for (i = 0; i < KEX_COOKIE_LEN; i++)
packet_get_char();
buffer_get_char(&b);
/* extract kex init proposal strings */
for (i = 0; i < PROPOSAL_MAX; i++) {
peer_proposal[i] = packet_get_string(NULL);
debug("got kexinit: %s", peer_proposal[i]);
proposal[i] = buffer_get_string(&b,NULL);
debug2("kex_parse_kexinit: %s", proposal[i]);
}
/* first kex follow / reserved */
i = packet_get_char();
debug("first kex follow: %d ", i);
i = packet_get_int();
debug("reserved: %d ", i);
packet_done();
debug("done");
}
/* diffie-hellman-group1-sha1 */
int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
if (dh_pub->neg) {
log("invalid public DH value: negativ");
return 0;
}
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
return 1;
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
return 0;
}
DH *
dh_gen_key(DH *dh)
{
int tries = 0;
do {
if (DH_generate_key(dh) == 0)
fatal("DH_generate_key");
if (tries++ > 10)
fatal("dh_new_group1: too many bad keys: giving up");
} while (!dh_pub_is_valid(dh, dh->pub_key));
return dh;
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
int ret;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
fatal("BN_hex2bn p");
if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
fatal("BN_hex2bn g");
return (dh_gen_key(dh));
}
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
dh->p = modulus;
dh->g = gen;
return (dh_gen_key(dh));
}
DH *
dh_new_group1()
{
static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1));
/* first kex follows / reserved */
i = buffer_get_char(&b);
debug2("kex_parse_kexinit: first_kex_follows %d ", i);
i = buffer_get_int(&b);
debug2("kex_parse_kexinit: reserved %d ", i);
buffer_free(&b);
return proposal;
}
void
dump_digest(unsigned char *digest, int len)
kex_prop_free(char **proposal)
{
int i;
for (i = 0; i< len; i++){
fprintf(stderr, "%02x", digest[i]);
if(i%2!=0)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
for (i = 0; i < PROPOSAL_MAX; i++)
xfree(proposal[i]);
xfree(proposal);
}
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
void
kex_protocol_error(int type, int plen, void *ctxt)
{
Buffer b;
static unsigned char digest[EVP_MAX_MD_SIZE];
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));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest(digest, evp_md->md_size);
#endif
return digest;
error("Hm, kex protocol error: type %d plen %d", type, plen);
}
unsigned char *
kex_hash_gex(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int minbits, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
void
kex_clear_dispatch(void)
{
Buffer b;
static unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
int i;
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));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_int(&b, minbits);
buffer_put_bignum2(&b, prime);
buffer_put_bignum2(&b, gen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest(digest, evp_md->md_size);
#endif
return digest;
/* Numbers 30-49 are used for kex packets */
for (i = 30; i <= 49; i++)
dispatch_set(i, &kex_protocol_error);
}
unsigned char *
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
void
kex_finish(Kex *kex)
{
Buffer b;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
int plen;
buffer_init(&b);
buffer_put_bignum2(&b, shared_secret);
kex_clear_dispatch();
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
EVP_DigestUpdate(&md, &c, 1); /* key id */
EVP_DigestUpdate(&md, hash, mdsz); /* session id */
EVP_DigestFinal(&md, digest, NULL);
packet_start(SSH2_MSG_NEWKEYS);
packet_send();
/* packet_write_wait(); */
debug("SSH2_MSG_NEWKEYS sent");
/* expand */
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
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);
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "Digest '%c'== ", c);
dump_digest(digest, need);
#endif
return digest;
debug("waiting for SSH2_MSG_NEWKEYS");
packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
debug("SSH2_MSG_NEWKEYS received");
kex->done = 1;
buffer_clear(&kex->peer);
/* buffer_clear(&kex->my); */
kex->flags &= ~KEX_INIT_SENT;
xfree(kex->name);
kex->name = NULL;
}
#define NKEYS 6
#define MAX_PROP 20
#define SEP ","
char *
get_match(char *client, char *server)
void
kex_send_kexinit(Kex *kex)
{
char *sproposals[MAX_PROP];
char *c, *s, *p, *ret, *cp, *sp;
int i, j, nproposals;
c = cp = xstrdup(client);
s = sp = xstrdup(server);
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
(p = strsep(&sp, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
break;
if (kex == NULL) {
error("kex_send_kexinit: no kex, cannot rekey");
return;
}
nproposals = i;
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
(p = strsep(&cp, SEP)), i++) {
for (j = 0; j < nproposals; j++) {
if (strcmp(p, sproposals[j]) == 0) {
ret = xstrdup(p);
xfree(c);
xfree(s);
return ret;
}
}
if (kex->flags & KEX_INIT_SENT) {
debug("KEX_INIT_SENT");
return;
}
xfree(c);
xfree(s);
return NULL;
kex->done = 0;
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
packet_send();
debug("SSH2_MSG_KEXINIT sent");
kex->flags |= KEX_INIT_SENT;
}
void
kex_input_kexinit(int type, int plen, void *ctxt)
{
char *ptr;
int dlen;
int i;
Kex *kex = (Kex *)ctxt;
debug("SSH2_MSG_KEXINIT received");
if (kex == NULL)
fatal("kex_input_kexinit: no kex, cannot rekey");
ptr = packet_get_raw(&dlen);
buffer_append(&kex->peer, ptr, dlen);
/* discard packet */
for (i = 0; i < KEX_COOKIE_LEN; i++)
packet_get_char();
for (i = 0; i < PROPOSAL_MAX; i++)
xfree(packet_get_string(NULL));
packet_get_char();
packet_get_int();
packet_done();
kex_kexinit_finish(kex);
}
Kex *
kex_setup(char *proposal[PROPOSAL_MAX])
{
Kex *kex;
kex = xmalloc(sizeof(*kex));
memset(kex, 0, sizeof(*kex));
buffer_init(&kex->peer);
buffer_init(&kex->my);
kex_prop2buf(&kex->my, proposal);
kex->done = 0;
kex_send_kexinit(kex); /* we start */
kex_clear_dispatch();
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
return kex;
}
void
kex_kexinit_finish(Kex *kex)
{
if (!(kex->flags & KEX_INIT_SENT))
kex_send_kexinit(kex);
kex_choose_conf(kex);
switch(kex->kex_type) {
case DH_GRP1_SHA1:
kexdh(kex);
break;
case DH_GEX_SHA1:
kexgex(kex);
break;
default:
fatal("Unsupported key exchange %d", kex->kex_type);
}
}
void
choose_enc(Enc *enc, char *client, char *server)
{
char *name = get_match(client, 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);
@ -405,28 +247,22 @@ choose_enc(Enc *enc, char *client, char *server)
void
choose_mac(Mac *mac, char *client, char *server)
{
char *name = get_match(client, server);
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching mac found: client %s server %s", client, server);
if (strcmp(name, "hmac-md5") == 0) {
mac->md = EVP_md5();
} else if (strcmp(name, "hmac-sha1") == 0) {
mac->md = EVP_sha1();
} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
mac->md = EVP_ripemd160();
} else {
if (mac_init(mac, name) < 0)
fatal("unsupported mac %s", name);
}
/* truncate the key */
if (datafellows & SSH_BUG_HMAC)
mac->key_len = 16;
mac->name = name;
mac->mac_len = mac->md->md_size;
mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
mac->key = NULL;
mac->enabled = 0;
}
void
choose_comp(Comp *comp, char *client, char *server)
{
char *name = get_match(client, server);
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching comp found: client %s server %s", client, server);
if (strcmp(name, "zlib") == 0) {
@ -441,7 +277,7 @@ choose_comp(Comp *comp, char *client, char *server)
void
choose_kex(Kex *k, char *client, char *server)
{
k->name = get_match(client, server);
k->name = match_list(client, server, NULL);
if (k->name == NULL)
fatal("no kex alg");
if (strcmp(k->name, KEX_DH1) == 0) {
@ -454,73 +290,164 @@ choose_kex(Kex *k, char *client, char *server)
void
choose_hostkeyalg(Kex *k, char *client, char *server)
{
k->hostkeyalg = get_match(client, server);
if (k->hostkeyalg == NULL)
char *hostkeyalg = match_list(client, server, NULL);
if (hostkeyalg == NULL)
fatal("no hostkey alg");
if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
fatal("bad hostkey alg %s", k->hostkeyalg);
k->hostkey_type = key_type_from_name(hostkeyalg);
if (k->hostkey_type == KEY_UNSPEC)
fatal("bad hostkey alg '%s'", hostkeyalg);
xfree(hostkeyalg);
}
Kex *
kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
void
kex_choose_conf(Kex *kex)
{
Newkeys *newkeys;
char **my, **peer;
char **cprop, **sprop;
int nenc, nmac, ncomp;
int mode;
int ctos; /* direction: if true client-to-server */
int need;
Kex *k;
k = xmalloc(sizeof(*k));
memset(k, 0, sizeof(*k));
k->server = server;
my = kex_buf2prop(&kex->my);
peer = kex_buf2prop(&kex->peer);
if (kex->server) {
cprop=peer;
sprop=my;
} else {
cprop=my;
sprop=peer;
}
/* Algorithm Negotiation */
for (mode = 0; mode < MODE_MAX; mode++) {
int nenc, nmac, ncomp;
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
newkeys = xmalloc(sizeof(*newkeys));
memset(newkeys, 0, sizeof(*newkeys));
kex->newkeys[mode] = newkeys;
ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]);
choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]);
choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
debug("kex: %s %s %s %s",
ctos ? "client->server" : "server->client",
k->enc[mode].name,
k->mac[mode].name,
k->comp[mode].name);
newkeys->enc.name,
newkeys->mac.name,
newkeys->comp.name);
}
choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
if (need < k->enc[mode].cipher->key_len)
need = k->enc[mode].cipher->key_len;
if (need < k->enc[mode].cipher->block_size)
need = k->enc[mode].cipher->block_size;
if (need < k->mac[mode].key_len)
need = k->mac[mode].key_len;
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->mac.key_len)
need = newkeys->mac.key_len;
}
/* XXX need runden? */
k->we_need = need;
return k;
kex->we_need = need;
kex_prop_free(my);
kex_prop_free(peer);
}
int
kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
u_char *
derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
{
int i;
int mode;
int ctos;
unsigned char *keys[NKEYS];
Buffer b;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
u_char *digest = xmalloc(roundup(need, mdsz));
buffer_init(&b);
buffer_put_bignum2(&b, shared_secret);
/* K1 = HASH(K || H || "A" || session_id) */
EVP_DigestInit(&md, evp_md);
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);
EVP_DigestFinal(&md, digest, NULL);
/*
* expand key:
* Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
* Key = K1 || K2 || ... || Kn
*/
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
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);
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "key '%c'== ", c);
dump_digest("key", digest, need);
#endif
return digest;
}
Newkeys *current_keys[MODE_MAX];
#define NKEYS 6
void
kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret)
{
u_char *keys[NKEYS];
int i, mode, ctos;
for (i = 0; i < NKEYS; i++)
keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret);
debug("kex_derive_keys");
for (mode = 0; mode < MODE_MAX; mode++) {
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
k->enc[mode].iv = keys[ctos ? 0 : 1];
k->enc[mode].key = keys[ctos ? 2 : 3];
k->mac[mode].key = keys[ctos ? 4 : 5];
current_keys[mode] = kex->newkeys[mode];
kex->newkeys[mode] = NULL;
ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
current_keys[mode]->enc.iv = keys[ctos ? 0 : 1];
current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
}
return 0;
}
Newkeys *
kex_get_newkeys(int mode)
{
Newkeys *ret;
ret = current_keys[mode];
current_keys[mode] = NULL;
return ret;
}
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
void
dump_digest(char *msg, u_char *digest, int len)
{
int i;
fprintf(stderr, "%s\n", msg);
for (i = 0; i< len; i++){
fprintf(stderr, "%02x", digest[i]);
if (i%32 == 31)
fprintf(stderr, "\n");
else if (i%8 == 7)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
}
#endif

View file

@ -1,3 +1,5 @@
/* $OpenBSD: kex.h,v 1.22 2001/04/04 20:25:37 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,9 +26,13 @@
#ifndef KEX_H
#define KEX_H
#include <openssl/evp.h>
#include "buffer.h"
#include "cipher.h"
#include "key.h"
#define KEX_DH1 "diffie-hellman-group1-sha1"
#define KEX_DHGEX "diffie-hellman-group-exchange-sha1"
#define KEX_DSS "ssh-dss"
enum kex_init_proposals {
PROPOSAL_KEX_ALGS,
@ -52,78 +58,73 @@ enum kex_exchange {
DH_GRP1_SHA1,
DH_GEX_SHA1
};
#define KEX_INIT_SENT 0x0001
typedef struct Kex Kex;
typedef struct Mac Mac;
typedef struct Comp Comp;
typedef struct Enc Enc;
typedef struct Newkeys Newkeys;
struct Enc {
char *name;
Cipher *cipher;
int enabled;
unsigned char *key;
unsigned char *iv;
char *name;
Cipher *cipher;
int enabled;
u_char *key;
u_char *iv;
};
struct Mac {
char *name;
int enabled;
EVP_MD *md;
int mac_len;
unsigned char *key;
int key_len;
char *name;
int enabled;
EVP_MD *md;
int mac_len;
u_char *key;
int key_len;
};
struct Comp {
int type;
int enabled;
char *name;
int type;
int enabled;
char *name;
};
struct Newkeys {
Enc enc;
Mac mac;
Comp comp;
};
struct Kex {
Enc enc [MODE_MAX];
Mac mac [MODE_MAX];
Comp comp[MODE_MAX];
int we_need;
int server;
char *name;
char *hostkeyalg;
int kex_type;
u_char *session_id;
int session_id_len;
Newkeys *newkeys[MODE_MAX];
int we_need;
int server;
char *name;
int hostkey_type;
int kex_type;
Buffer my;
Buffer peer;
int done;
int flags;
char *client_version_string;
char *server_version_string;
int (*check_host_key)(Key *hostkey);
Key *(*load_host_key)(int type);
};
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
void
kex_exchange_kexinit(
Buffer *my_kexinit, Buffer *peer_kexint,
char *peer_proposal[PROPOSAL_MAX]);
Kex *
kex_choose_conf(char *cprop[PROPOSAL_MAX],
char *sprop[PROPOSAL_MAX], int server);
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
void packet_set_kex(Kex *k);
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
DH *dh_new_group_asc(const char *, const char *);
DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1();
Kex *kex_setup(char *proposal[PROPOSAL_MAX]);
void kex_finish(Kex *kex);
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret);
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 kexdh(Kex *);
void kexgex(Kex *);
Newkeys *kex_get_newkeys(int mode);
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
void dump_digest(char *msg, u_char *digest, int len);
#endif
unsigned char *
kex_hash_gex(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int minbits, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret);
#endif

304
crypto/openssh/kexdh.c Normal file
View file

@ -0,0 +1,304 @@
/*
* 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: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $");
#include <openssl/crypto.h>
#include <openssl/bn.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
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,
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();
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));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, evp_md->md_size);
#endif
return digest;
}
/* client */
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 *kbuf, *hash;
u_int klen, kout, slen, sbloblen;
int dlen, plen;
/* generate and send 'e', client DH public key */
dh = dh_new_group1();
dh_gen_key(dh, kex->we_need * 8);
packet_start(SSH2_MSG_KEXDH_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("sending SSH2_MSG_KEXDH_INIT");
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
packet_read_expect(&plen, 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);
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_done();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_server_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
/* calc and verify H */
hash = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
server_host_key_blob, sbloblen,
dh->pub_key,
dh_server_pub,
shared_secret
);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
DH_free(dh);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
/* server */
void
kexdh_server(Kex *kex)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
DH *dh;
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, kout;
int dlen, slen, plen;
/* 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);
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type);
if (server_host_key == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
BN_print_fp(stderr, dh_client_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_client_pub));
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_client_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
/* calc H */
hash = kex_dh_hash(
kex->client_version_string,
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,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
/* XXX hashlen depends on KEX */
key_sign(server_host_key, &signature, &slen, hash, 20);
/* destroy_sensitive_data(); */
/* 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_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_send();
xfree(signature);
xfree(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
void
kexdh(Kex *kex)
{
if (kex->server)
kexdh_server(kex);
else
kexdh_client(kex);
}

408
crypto/openssh/kexgex.c Normal file
View file

@ -0,0 +1,408 @@
/*
* Copyright (c) 2000 Niels Provos. 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
* 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: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $");
#include <openssl/bn.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
#include "compat.h"
u_char *
kexgex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
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();
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));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
if (min == -1 || max == -1)
buffer_put_int(&b, wantbits);
else {
buffer_put_int(&b, min);
buffer_put_int(&b, wantbits);
buffer_put_int(&b, max);
}
buffer_put_bignum2(&b, prime);
buffer_put_bignum2(&b, gen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEXDH
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEXDH
dump_digest("hash", digest, evp_md->md_size);
#endif
return digest;
}
/* client */
void
kexgex_client(Kex *kex)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
BIGNUM *p = NULL, *g = NULL;
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;
DH *dh;
nbits = dh_estimate(kex->we_need * 8);
if (datafellows & SSH_OLD_DHGEX) {
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
/* Old GEX request */
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
packet_put_int(nbits);
min = DH_GRP_MIN;
max = DH_GRP_MAX;
} else {
debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
/* New GEX request */
min = DH_GRP_MIN;
max = DH_GRP_MAX;
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
packet_put_int(min);
packet_put_int(nbits);
packet_put_int(max);
}
#ifdef DEBUG_KEXDH
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
min, nbits, max);
#endif
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
if ((p = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(p, &dlen);
if ((g = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(g, &dlen);
packet_done();
if (BN_num_bits(p) < min || BN_num_bits(p) > max)
fatal("DH_GEX group out of range: %d !< %d !< %d",
min, BN_num_bits(p), max);
dh = dh_new_group(g, p);
dh_gen_key(dh, kex->we_need * 8);
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
/* generate and send 'e', client DH public key */
packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
packet_read_expect(&plen, 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);
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_done();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_server_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
if (datafellows & SSH_OLD_DHGEX)
min = max = -1;
/* calc and verify H */
hash = kexgex_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
server_host_key_blob, sbloblen,
min, nbits, max,
dh->p, dh->g,
dh->pub_key,
dh_server_pub,
shared_secret
);
/* have keys, free DH */
DH_free(dh);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
/* server */
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;
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type);
if (server_host_key == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
type = packet_read(&plen);
switch(type){
case SSH2_MSG_KEX_DH_GEX_REQUEST:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
min = packet_get_int();
nbits = packet_get_int();
max = packet_get_int();
min = MAX(DH_GRP_MIN, min);
max = MIN(DH_GRP_MAX, max);
break;
case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
nbits = packet_get_int();
min = DH_GRP_MIN;
max = DH_GRP_MAX;
/* unused for old GEX */
break;
default:
fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
}
packet_done();
if (max < min || nbits < min || max < nbits)
fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
min, nbits, max);
dh = choose_dh(min, nbits, max);
if (dh == NULL)
packet_disconnect("Protocol error: no matching DH grp found");
debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
packet_put_bignum2(dh->p);
packet_put_bignum2(dh->g);
packet_send();
/* flush */
packet_write_wait();
/* Compute our exchange value in parallel with the client */
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);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
BN_print_fp(stderr, dh_client_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_client_pub));
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_client_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
min = max = -1;
/* calc H */ /* XXX depends on 'kex' */
hash = kexgex_hash(
kex->client_version_string,
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,
min, nbits, max,
dh->p, dh->g,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
/* XXX hashlen depends on KEX */
key_sign(server_host_key, &signature, &slen, hash, 20);
/* destroy_sensitive_data(); */
/* 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_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_send();
xfree(signature);
xfree(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
void
kexgex(Kex *kex)
{
if (kex->server)
kexgex_server(kex);
else
kexgex_client(kex);
}

View file

@ -31,20 +31,20 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include "ssh.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "dsa.h"
#include "rsa.h"
#include "ssh-dss.h"
#include "ssh-rsa.h"
#include "uuencode.h"
RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
#define SSH_DSS "ssh-dss"
#include "buffer.h"
#include "bufaux.h"
#include "log.h"
Key *
key_new(int type)
@ -57,6 +57,7 @@ key_new(int type)
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
rsa = RSA_new();
rsa->n = BN_new();
@ -71,7 +72,7 @@ key_new(int type)
dsa->pub_key = BN_new();
k->dsa = dsa;
break;
case KEY_EMPTY:
case KEY_UNSPEC:
break;
default:
fatal("key_new: bad key type %d", k->type);
@ -79,10 +80,35 @@ key_new(int type)
}
return k;
}
Key *
key_new_private(int type)
{
Key *k = key_new(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();
break;
case KEY_DSA:
k->dsa->priv_key = BN_new();
break;
case KEY_UNSPEC:
break;
default:
break;
}
return k;
}
void
key_free(Key *k)
{
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
if (k->rsa != NULL)
RSA_free(k->rsa);
@ -93,6 +119,8 @@ key_free(Key *k)
DSA_free(k->dsa);
k->dsa = NULL;
break;
case KEY_UNSPEC:
break;
default:
fatal("key_free: bad key type %d", k->type);
break;
@ -105,6 +133,7 @@ key_equal(Key *a, Key *b)
if (a == NULL || b == NULL || a->type != b->type)
return 0;
switch (a->type) {
case KEY_RSA1:
case KEY_RSA:
return a->rsa != NULL && b->rsa != NULL &&
BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
@ -124,20 +153,31 @@ key_equal(Key *a, Key *b)
return 0;
}
/*
* Generate key fingerprint in ascii format.
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
*/
char *
key_fingerprint(Key *k)
u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
{
static char retval[(EVP_MAX_MD_SIZE+1)*3];
unsigned char *blob = NULL;
EVP_MD *md = NULL;
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
switch (dgst_type) {
case SSH_FP_MD5:
md = EVP_md5();
break;
case SSH_FP_SHA1:
md = EVP_sha1();
break;
default:
fatal("key_fingerprint_raw: bad digest type %d",
dgst_type);
}
switch (k->type) {
case KEY_RSA:
case KEY_RSA1:
nlen = BN_num_bytes(k->rsa->n);
elen = BN_num_bytes(k->rsa->e);
len = nlen + elen;
@ -146,34 +186,121 @@ key_fingerprint(Key *k)
BN_bn2bin(k->rsa->e, blob + nlen);
break;
case KEY_DSA:
dsa_make_key_blob(k, &blob, &len);
case KEY_RSA:
key_to_blob(k, &blob, &len);
break;
case KEY_UNSPEC:
return retval;
break;
default:
fatal("key_fingerprint: bad key type %d", k->type);
fatal("key_fingerprint_raw: bad key type %d", k->type);
break;
}
retval[0] = '\0';
if (blob != NULL) {
int i;
unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *md = EVP_md5();
EVP_MD_CTX ctx;
retval = xmalloc(EVP_MAX_MD_SIZE);
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, blob, len);
EVP_DigestFinal(&ctx, digest, NULL);
for(i = 0; i < md->md_size; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", digest[i]);
strlcat(retval, hex, sizeof(retval));
}
retval[strlen(retval) - 1] = '\0';
EVP_DigestFinal(&ctx, retval, NULL);
*dgst_raw_length = md->md_size;
memset(blob, 0, len);
xfree(blob);
} else {
fatal("key_fingerprint_raw: blob is null");
}
return retval;
}
char*
key_fingerprint_hex(u_char* dgst_raw, size_t 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++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
strlcat(retval, hex, dgst_raw_len * 3);
}
retval[(dgst_raw_len * 3) - 1] = '\0';
return retval;
}
char*
key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
u_int i, j = 0, rounds, seed = 1;
char *retval;
rounds = (dgst_raw_len / 2) + 1;
retval = xmalloc(sizeof(char) * (rounds*6));
retval[j++] = 'x';
for (i = 0; i < rounds; i++) {
u_int idx0, idx1, idx2, idx3, idx4;
if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
seed) % 6;
idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
(seed / 6)) % 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
if ((i + 1) < rounds) {
idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
retval[j++] = consonants[idx3];
retval[j++] = '-';
retval[j++] = consonants[idx4];
seed = ((seed * 5) +
((((u_int)(dgst_raw[2 * i])) * 7) +
((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
}
} else {
idx0 = seed % 6;
idx1 = 16;
idx2 = seed / 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
}
}
retval[j++] = 'x';
retval[j++] = '\0';
return retval;
}
char*
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;
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) {
case SSH_FP_HEX:
retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
break;
case SSH_FP_BUBBLEBABBLE:
retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
break;
default:
fatal("key_fingerprint_ex: bad digest representation %d",
dgst_rep);
break;
}
memset(dgst_raw, 0, dgst_raw_len);
xfree(dgst_raw);
return retval;
}
/*
* Reads a multiple-precision integer in decimal from the buffer, and advances
* the pointer. The integer must already be initialized. This function is
@ -226,59 +353,109 @@ write_bignum(FILE *f, BIGNUM *num)
return 0;
}
fprintf(f, " %s", buf);
free(buf);
xfree(buf);
return 1;
}
unsigned int
/* returns 1 ok, -1 error, 0 type mismatch */
int
key_read(Key *ret, char **cpp)
{
Key *k;
unsigned int bits = 0;
char *cp;
int len, n;
unsigned char *blob;
int success = -1;
char *cp, *space;
int len, n, type;
u_int bits;
u_char *blob;
cp = *cpp;
switch(ret->type) {
case KEY_RSA:
case KEY_RSA1:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
return 0; /* Bad bit count... */
return -1; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0';
if (bits == 0)
return 0;
return -1;
*cpp = cp;
/* Get public exponent, public modulus. */
if (!read_bignum(cpp, ret->rsa->e))
return 0;
return -1;
if (!read_bignum(cpp, ret->rsa->n))
return 0;
return -1;
success = 1;
break;
case KEY_UNSPEC:
case KEY_RSA:
case KEY_DSA:
if (strncmp(cp, SSH_DSS " ", 7) != 0)
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: no space");
return -1;
}
*space = '\0';
type = key_type_from_name(cp);
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: no key found");
return -1;
}
cp = space+1;
if (*cp == '\0') {
debug3("key_read: short string");
return -1;
}
if (ret->type == KEY_UNSPEC) {
ret->type = type;
} else if (ret->type != type) {
/* is a key, but different type */
debug3("key_read: type mismatch");
return 0;
cp += 7;
}
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("key_read: uudecode %s failed", cp);
return 0;
return -1;
}
k = dsa_key_from_blob(blob, n);
k = key_from_blob(blob, n);
if (k == NULL) {
error("key_read: dsa_key_from_blob %s failed", cp);
return 0;
error("key_read: key_from_blob %s failed", cp);
return -1;
}
xfree(blob);
if (ret->dsa != NULL)
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
if (k->type != type) {
error("key_read: type mismatch: encoding error");
key_free(k);
return -1;
}
/*XXXX*/
if (ret->type == KEY_RSA) {
if (ret->rsa != NULL)
RSA_free(ret->rsa);
ret->rsa = k->rsa;
k->rsa = NULL;
success = 1;
#ifdef DEBUG_PK
RSA_print_fp(stderr, ret->rsa, 8);
#endif
} else {
if (ret->dsa != NULL)
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
success = 1;
#ifdef DEBUG_PK
DSA_print_fp(stderr, ret->dsa, 8);
#endif
}
/*XXXX*/
if (success != 1)
break;
key_free(k);
bits = BN_num_bits(ret->dsa->p);
/* advance cp: skip whitespace and data */
while (*cp == ' ' || *cp == '\t')
cp++;
@ -290,15 +467,15 @@ key_read(Key *ret, char **cpp)
fatal("key_read: bad key type: %d", ret->type);
break;
}
return bits;
return success;
}
int
key_write(Key *key, FILE *f)
{
int success = 0;
unsigned int bits = 0;
u_int bits = 0;
if (key->type == KEY_RSA && key->rsa != NULL) {
if (key->type == KEY_RSA1 && key->rsa != NULL) {
/* size of modulus 'n' */
bits = BN_num_bits(key->rsa->n);
fprintf(f, "%u", bits);
@ -308,14 +485,15 @@ key_write(Key *key, FILE *f)
} else {
error("key_write: failed for RSA key");
}
} else if (key->type == KEY_DSA && key->dsa != NULL) {
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
int len, n;
unsigned char *blob, *uu;
dsa_make_key_blob(key, &blob, &len);
u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
if (n > 0) {
fprintf(f, "%s %s", SSH_DSS, uu);
fprintf(f, "%s %s", key_ssh_name(key), uu);
success = 1;
}
xfree(blob);
@ -327,6 +505,9 @@ char *
key_type(Key *k)
{
switch (k->type) {
case KEY_RSA1:
return "RSA1";
break;
case KEY_RSA:
return "RSA";
break;
@ -336,9 +517,23 @@ key_type(Key *k)
}
return "unknown";
}
unsigned int
char *
key_ssh_name(Key *k)
{
switch (k->type) {
case KEY_RSA:
return "ssh-rsa";
break;
case KEY_DSA:
return "ssh-dss";
break;
}
return "ssh-unknown";
}
u_int
key_size(Key *k){
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
return BN_num_bits(k->rsa->n);
break;
@ -348,3 +543,241 @@ key_size(Key *k){
}
return 0;
}
RSA *
rsa_generate_private_key(u_int bits)
{
RSA *private;
private = RSA_generate_key(bits, 35, NULL, NULL);
if (private == NULL)
fatal("rsa_generate_private_key: key generation failed.");
return private;
}
DSA*
dsa_generate_private_key(u_int bits)
{
DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
if (private == NULL)
fatal("dsa_generate_private_key: DSA_generate_parameters failed");
if (!DSA_generate_key(private))
fatal("dsa_generate_private_key: DSA_generate_key failed.");
if (private == NULL)
fatal("dsa_generate_private_key: NULL.");
return private;
}
Key *
key_generate(int type, u_int bits)
{
Key *k = key_new(KEY_UNSPEC);
switch (type) {
case KEY_DSA:
k->dsa = dsa_generate_private_key(bits);
break;
case KEY_RSA:
case KEY_RSA1:
k->rsa = rsa_generate_private_key(bits);
break;
default:
fatal("key_generate: unknown type %d", type);
}
k->type = type;
return k;
}
Key *
key_from_private(Key *k)
{
Key *n = NULL;
switch (k->type) {
case KEY_DSA:
n = key_new(k->type);
BN_copy(n->dsa->p, k->dsa->p);
BN_copy(n->dsa->q, k->dsa->q);
BN_copy(n->dsa->g, k->dsa->g);
BN_copy(n->dsa->pub_key, k->dsa->pub_key);
break;
case KEY_RSA:
case KEY_RSA1:
n = key_new(k->type);
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
break;
default:
fatal("key_from_private: unknown type %d", k->type);
break;
}
return n;
}
int
key_type_from_name(char *name)
{
if (strcmp(name, "rsa1") == 0){
return KEY_RSA1;
} else if (strcmp(name, "rsa") == 0){
return KEY_RSA;
} else if (strcmp(name, "dsa") == 0){
return KEY_DSA;
} else if (strcmp(name, "ssh-rsa") == 0){
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
return KEY_DSA;
}
debug2("key_type_from_name: unknown key type '%s'", name);
return KEY_UNSPEC;
}
int
key_names_valid2(const char *names)
{
char *s, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return 0;
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
switch (key_type_from_name(p)) {
case KEY_RSA1:
case KEY_UNSPEC:
xfree(s);
return 0;
}
}
debug3("key names ok: [%s]", names);
xfree(s);
return 1;
}
Key *
key_from_blob(char *blob, int blen)
{
Buffer b;
char *ktype;
int rlen, type;
Key *key = NULL;
#ifdef DEBUG_PK
dump_base64(stderr, blob, blen);
#endif
buffer_init(&b);
buffer_append(&b, blob, blen);
ktype = buffer_get_string(&b, NULL);
type = key_type_from_name(ktype);
switch(type){
case KEY_RSA:
key = key_new(type);
buffer_get_bignum2(&b, key->rsa->e);
buffer_get_bignum2(&b, key->rsa->n);
#ifdef DEBUG_PK
RSA_print_fp(stderr, key->rsa, 8);
#endif
break;
case KEY_DSA:
key = key_new(type);
buffer_get_bignum2(&b, key->dsa->p);
buffer_get_bignum2(&b, key->dsa->q);
buffer_get_bignum2(&b, key->dsa->g);
buffer_get_bignum2(&b, key->dsa->pub_key);
#ifdef DEBUG_PK
DSA_print_fp(stderr, key->dsa, 8);
#endif
break;
case KEY_UNSPEC:
key = key_new(type);
break;
default:
error("key_from_blob: cannot handle type %s", ktype);
break;
}
rlen = buffer_len(&b);
if (key != NULL && rlen != 0)
error("key_from_blob: remaining bytes in key blob %d", rlen);
xfree(ktype);
buffer_free(&b);
return key;
}
int
key_to_blob(Key *key, u_char **blobp, u_int *lenp)
{
Buffer b;
int len;
u_char *buf;
if (key == NULL) {
error("key_to_blob: key == NULL");
return 0;
}
buffer_init(&b);
switch(key->type){
case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p);
buffer_put_bignum2(&b, key->dsa->q);
buffer_put_bignum2(&b, key->dsa->g);
buffer_put_bignum2(&b, key->dsa->pub_key);
break;
case KEY_RSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->rsa->e);
buffer_put_bignum2(&b, key->rsa->n);
break;
default:
error("key_to_blob: illegal key type %d", key->type);
break;
}
len = buffer_len(&b);
buf = xmalloc(len);
memcpy(buf, buffer_ptr(&b), len);
memset(buffer_ptr(&b), 0, len);
buffer_free(&b);
if (lenp != NULL)
*lenp = len;
if (blobp != NULL)
*blobp = buf;
return len;
}
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
{
switch(key->type){
case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen);
break;
case KEY_RSA:
return ssh_rsa_sign(key, sigp, lenp, data, datalen);
break;
default:
error("key_sign: illegal key type %d", key->type);
return -1;
break;
}
}
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
{
switch(key->type){
case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen);
break;
case KEY_RSA:
return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
break;
default:
error("key_verify: illegal key type %d", key->type);
return -1;
break;
}
}

View file

@ -1,3 +1,5 @@
/* $OpenBSD: key.h,v 1.12 2001/04/17 10:53:24 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,11 +26,23 @@
#ifndef KEY_H
#define KEY_H
#include <openssl/rsa.h>
#include <openssl/dsa.h>
typedef struct Key Key;
enum types {
KEY_RSA1,
KEY_RSA,
KEY_DSA,
KEY_EMPTY
KEY_UNSPEC
};
enum fp_type {
SSH_FP_SHA1,
SSH_FP_MD5
};
enum fp_rep {
SSH_FP_HEX,
SSH_FP_BUBBLEBABBLE
};
struct Key {
int type;
@ -37,12 +51,34 @@ struct Key {
};
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);
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);
unsigned int key_read(Key *key, char **cpp);
unsigned int key_size(Key *k);
int key_read(Key *key, char **cpp);
u_int key_size(Key *k);
Key *key_generate(int type, u_int bits);
Key *key_from_private(Key *k);
int key_type_from_name(char *name);
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);
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);
#endif

View file

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.22 2001/04/03 19:53:30 markus Exp $
.PATH: ${.CURDIR}/..
LIB= ssh
@ -5,8 +7,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
cipher.c compat.c compress.c crc32.c deattack.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 dsa.c kex.c hmac.c uuencode.c util.c \
cli.c rijndael.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
NOPROFILE= yes
NOPIC= yes

View file

@ -10,8 +10,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Shared versions of debug(), log(), etc.
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,11 +34,78 @@
*/
#include "includes.h"
RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $");
RCSID("$OpenBSD: log.c,v 1.17 2001/03/04 17:42:28 millert Exp $");
#include "ssh.h"
#include "log.h"
#include "xmalloc.h"
#include <syslog.h>
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 1;
static int log_facility = LOG_AUTH;
static char *argv0;
extern char *__progname;
/* textual representation of log-facilities/levels */
static struct {
const char *name;
SyslogFacility val;
} log_facilities[] = {
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
{ "USER", SYSLOG_FACILITY_USER },
{ "AUTH", SYSLOG_FACILITY_AUTH },
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, 0 }
};
static struct {
const char *name;
LogLevel val;
} log_levels[] =
{
{ "QUIET", SYSLOG_LEVEL_QUIET },
{ "FATAL", SYSLOG_LEVEL_FATAL },
{ "ERROR", SYSLOG_LEVEL_ERROR },
{ "INFO", SYSLOG_LEVEL_INFO },
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, 0 }
};
SyslogFacility
log_facility_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return (SyslogFacility) - 1;
}
LogLevel
log_level_number(char *name)
{
int i;
if (name != NULL)
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
@ -154,8 +219,8 @@ fatal_remove_cleanup(void (*proc) (void *context), void *context)
return;
}
}
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
(unsigned long) proc, (unsigned long) context);
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
(u_long) proc, (u_long) context);
}
/* Cleanup and exit */
@ -172,67 +237,143 @@ fatal_cleanup(void)
for (cu = fatal_cleanups; cu; cu = next_cu) {
next_cu = cu->next;
debug("Calling cleanup 0x%lx(0x%lx)",
(unsigned long) cu->proc, (unsigned long) cu->context);
(u_long) cu->proc, (u_long) cu->context);
(*cu->proc) (cu->context);
}
exit(255);
}
/* textual representation of log-facilities/levels */
static struct {
const char *name;
SyslogFacility val;
} log_facilities[] = {
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
{ "USER", SYSLOG_FACILITY_USER },
{ "AUTH", SYSLOG_FACILITY_AUTH },
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, 0 }
};
/*
* Initialize the log.
*/
static struct {
const char *name;
LogLevel val;
} log_levels[] =
void
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
{
{ "QUIET", SYSLOG_LEVEL_QUIET },
{ "FATAL", SYSLOG_LEVEL_FATAL },
{ "ERROR", SYSLOG_LEVEL_ERROR },
{ "INFO", SYSLOG_LEVEL_INFO },
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, 0 }
};
argv0 = av0;
SyslogFacility
log_facility_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return (SyslogFacility) - 1;
switch (level) {
case SYSLOG_LEVEL_QUIET:
case SYSLOG_LEVEL_FATAL:
case SYSLOG_LEVEL_ERROR:
case SYSLOG_LEVEL_INFO:
case SYSLOG_LEVEL_VERBOSE:
case SYSLOG_LEVEL_DEBUG1:
case SYSLOG_LEVEL_DEBUG2:
case SYSLOG_LEVEL_DEBUG3:
log_level = level;
break;
default:
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
(int) level);
exit(1);
}
log_on_stderr = on_stderr;
if (on_stderr)
return;
switch (facility) {
case SYSLOG_FACILITY_DAEMON:
log_facility = LOG_DAEMON;
break;
case SYSLOG_FACILITY_USER:
log_facility = LOG_USER;
break;
case SYSLOG_FACILITY_AUTH:
log_facility = LOG_AUTH;
break;
case SYSLOG_FACILITY_LOCAL0:
log_facility = LOG_LOCAL0;
break;
case SYSLOG_FACILITY_LOCAL1:
log_facility = LOG_LOCAL1;
break;
case SYSLOG_FACILITY_LOCAL2:
log_facility = LOG_LOCAL2;
break;
case SYSLOG_FACILITY_LOCAL3:
log_facility = LOG_LOCAL3;
break;
case SYSLOG_FACILITY_LOCAL4:
log_facility = LOG_LOCAL4;
break;
case SYSLOG_FACILITY_LOCAL5:
log_facility = LOG_LOCAL5;
break;
case SYSLOG_FACILITY_LOCAL6:
log_facility = LOG_LOCAL6;
break;
case SYSLOG_FACILITY_LOCAL7:
log_facility = LOG_LOCAL7;
break;
default:
fprintf(stderr,
"Unrecognized internal syslog facility code %d\n",
(int) facility);
exit(1);
}
}
LogLevel
log_level_number(char *name)
#define MSGBUFSIZ 1024
void
do_log(LogLevel level, const char *fmt, va_list args)
{
int i;
if (name != NULL)
for (i = 0; log_levels[i].name; i++)
if (strcasecmp(log_levels[i].name, name) == 0)
return log_levels[i].val;
return (LogLevel) - 1;
char msgbuf[MSGBUFSIZ];
char fmtbuf[MSGBUFSIZ];
char *txt = NULL;
int pri = LOG_INFO;
if (level > log_level)
return;
switch (level) {
case SYSLOG_LEVEL_FATAL:
if (!log_on_stderr)
txt = "fatal";
pri = LOG_CRIT;
break;
case SYSLOG_LEVEL_ERROR:
if (!log_on_stderr)
txt = "error";
pri = LOG_ERR;
break;
case SYSLOG_LEVEL_INFO:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_VERBOSE:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_DEBUG1:
txt = "debug1";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG2:
txt = "debug2";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG3:
txt = "debug3";
pri = LOG_DEBUG;
break;
default:
txt = "internal error";
pri = LOG_ERR;
break;
}
if (txt != NULL) {
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
} else {
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
}
if (log_on_stderr) {
fprintf(stderr, "%s\r\n", msgbuf);
} else {
openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
syslog(pri, "%.500s", msgbuf);
closelog();
}
}

75
crypto/openssh/log.h Normal file
View file

@ -0,0 +1,75 @@
/* $OpenBSD: log.h,v 1.2 2001/01/29 01:58:16 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef SSH_LOG_H
#define SSH_LOG_H
/* Supported syslog facilities and levels. */
typedef enum {
SYSLOG_FACILITY_DAEMON,
SYSLOG_FACILITY_USER,
SYSLOG_FACILITY_AUTH,
SYSLOG_FACILITY_LOCAL0,
SYSLOG_FACILITY_LOCAL1,
SYSLOG_FACILITY_LOCAL2,
SYSLOG_FACILITY_LOCAL3,
SYSLOG_FACILITY_LOCAL4,
SYSLOG_FACILITY_LOCAL5,
SYSLOG_FACILITY_LOCAL6,
SYSLOG_FACILITY_LOCAL7
} SyslogFacility;
typedef enum {
SYSLOG_LEVEL_QUIET,
SYSLOG_LEVEL_FATAL,
SYSLOG_LEVEL_ERROR,
SYSLOG_LEVEL_INFO,
SYSLOG_LEVEL_VERBOSE,
SYSLOG_LEVEL_DEBUG1,
SYSLOG_LEVEL_DEBUG2,
SYSLOG_LEVEL_DEBUG3
} 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);
/* name to facility/level */
SyslogFacility log_facility_number(char *name);
LogLevel log_level_number(char *name);
/* 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)));
/* same as fatal() but w/o logging */
void fatal_cleanup(void);
/*
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
* before exiting. It is permissible to call fatal_remove_cleanup for the
* function itself 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);
#endif

114
crypto/openssh/mac.c Normal file
View file

@ -0,0 +1,114 @@
/*
* 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: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $");
#include <openssl/hmac.h>
#include "xmalloc.h"
#include "getput.h"
#include "log.h"
#include "cipher.h"
#include "kex.h"
#include "mac.h"
struct {
char *name;
EVP_MD * (*mdfunc)(void);
int truncatebits; /* truncate digest if != 0 */
} macs[] = {
{ "hmac-sha1", EVP_sha1, 0, },
{ "hmac-sha1-96", EVP_sha1, 96 },
{ "hmac-md5", EVP_md5, 0 },
{ "hmac-md5-96", EVP_md5, 96 },
{ "hmac-ripemd160", EVP_ripemd160, 0 },
{ "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 },
{ NULL, NULL, 0 }
};
int
mac_init(Mac *mac, char *name)
{
int i;
for (i = 0; macs[i].name; i++) {
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;
if (macs[i].truncatebits != 0)
mac->mac_len = macs[i].truncatebits/8;
}
debug2("mac_init: found %s", name);
return (0);
}
}
debug2("mac_init: unknown %s", name);
return (-1);
}
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
{
HMAC_CTX c;
static u_char m[EVP_MAX_MD_SIZE];
u_char b[4];
if (mac->key == NULL)
fatal("mac_compute: no key");
if (mac->mac_len > sizeof(m))
fatal("mac_compute: mac too long");
HMAC_Init(&c, mac->key, mac->key_len, mac->md);
PUT_32BIT(b, seqno);
HMAC_Update(&c, b, sizeof(b));
HMAC_Update(&c, data, datalen);
HMAC_Final(&c, m, NULL);
HMAC_cleanup(&c);
return (m);
}
/* XXX copied from ciphers_valid */
#define MAC_SEP ","
int
mac_valid(const char *names)
{
char *maclist, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return (0);
maclist = cp = xstrdup(names);
for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
(p = strsep(&cp, MAC_SEP))) {
if (mac_init(NULL, p) < 0) {
debug("bad mac %s [%s]", p, names);
xfree(maclist);
return (0);
} else {
debug3("mac ok: %s [%s]", p, names);
}
}
debug3("macs ok: [%s]", names);
xfree(maclist);
return (1);
}

28
crypto/openssh/mac.h Normal file
View file

@ -0,0 +1,28 @@
/* $OpenBSD: mac.h,v 1.1 2001/02/11 12:59:24 markus 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.
*/
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);

View file

@ -10,11 +10,35 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: match.c,v 1.9 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$OpenBSD: match.c,v 1.12 2001/03/10 17:51:04 markus Exp $");
#include "ssh.h"
#include "match.h"
#include "xmalloc.h"
/*
* Returns true if the given string matches the pattern (which may contain ?
@ -87,12 +111,12 @@ match_pattern(const char *s, const char *pattern)
*/
int
match_hostname(const char *host, const char *pattern, unsigned int len)
match_hostname(const char *host, const char *pattern, u_int len)
{
char sub[1024];
int negated;
int got_positive;
unsigned int i, subi;
u_int i, subi;
got_positive = 0;
for (i = 0; i < len;) {
@ -137,3 +161,46 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
*/
return got_positive;
}
#define MAX_PROP 20
#define SEP ","
char *
match_list(const char *client, const char *server, u_int *next)
{
char *sproposals[MAX_PROP];
char *c, *s, *p, *ret, *cp, *sp;
int i, j, nproposals;
c = cp = xstrdup(client);
s = sp = xstrdup(server);
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
(p = strsep(&sp, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
break;
}
nproposals = i;
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
(p = strsep(&cp, SEP)), i++) {
for (j = 0; j < nproposals; j++) {
if (strcmp(p, sproposals[j]) == 0) {
ret = xstrdup(p);
if (next != NULL)
*next = (cp == NULL) ?
strlen(c) : cp - c;
xfree(c);
xfree(s);
return ret;
}
}
}
if (next != NULL)
*next = strlen(c);
xfree(c);
xfree(s);
return NULL;
}

View file

@ -1,3 +1,5 @@
/* $OpenBSD: match.h,v 1.7 2001/03/10 17:51:04 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -26,6 +28,12 @@ int match_pattern(const char *s, const char *pattern);
* 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, unsigned int len);
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);
#endif

130
crypto/openssh/misc.c Normal file
View file

@ -0,0 +1,130 @@
/* $OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk 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.
*/
#include "includes.h"
RCSID("$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $");
#include "misc.h"
#include "log.h"
#include "xmalloc.h"
char *
chop(char *s)
{
char *t = s;
while (*t) {
if(*t == '\n' || *t == '\r') {
*t = '\0';
return s;
}
t++;
}
return s;
}
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);
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));
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
char *
strdelim(char **s)
{
char *old;
int wspace = 0;
if (*s == NULL)
return NULL;
old = *s;
*s = strpbrk(*s, WHITESPACE "=");
if (*s == NULL)
return (old);
/* Allow only one '=' to be skipped */
if (*s[0] == '=')
wspace = 1;
*s[0] = '\0';
*s += strspn(*s + 1, WHITESPACE) + 1;
if (*s[0] == '=' && !wspace)
*s += strspn(*s + 1, WHITESPACE) + 1;
return (old);
}
struct passwd *
pwcopy(struct passwd *pw)
{
struct passwd *copy = xmalloc(sizeof(*copy));
memset(copy, 0, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_gecos = xstrdup(pw->pw_gecos);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
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)
{
long port;
char *endp;
errno = 0;
port = strtol(s, &endp, 0);
if (s == endp || *endp != '\0' ||
(errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
port <= 0 || port > 65535)
return 0;
return port;
}

30
crypto/openssh/misc.h Normal file
View file

@ -0,0 +1,30 @@
/* $OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/* remove newline at end of string */
char *chop(char *s);
/* return next token in configuration line */
char *strdelim(char **s);
/* set filedescriptor to non-blocking */
void set_nonblock(int fd);
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);

View file

@ -13,7 +13,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: mpaux.c,v 1.14 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$OpenBSD: mpaux.c,v 1.16 2001/02/08 19:30:52 itojun Exp $");
#include <openssl/bn.h>
#include "getput.h"
@ -21,16 +21,18 @@ RCSID("$OpenBSD: mpaux.c,v 1.14 2000/09/07 20:27:52 deraadt Exp $");
#include <openssl/md5.h>
#include "mpaux.h"
void
compute_session_id(unsigned char session_id[16],
unsigned char cookie[8],
compute_session_id(u_char session_id[16],
u_char cookie[8],
BIGNUM* host_key_n,
BIGNUM* session_key_n)
{
unsigned int host_key_bytes = BN_num_bytes(host_key_n);
unsigned int session_key_bytes = BN_num_bytes(session_key_n);
unsigned int bytes = host_key_bytes + session_key_bytes;
unsigned char *buf = xmalloc(bytes);
u_int host_key_bytes = BN_num_bytes(host_key_n);
u_int session_key_bytes = BN_num_bytes(session_key_n);
u_int bytes = host_key_bytes + session_key_bytes;
u_char *buf = xmalloc(bytes);
MD5_CTX md;
BN_bn2bin(host_key_n, buf);

View file

@ -12,7 +12,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: mpaux.h,v 1.8 2000/09/07 20:27:52 deraadt Exp $"); */
/* RCSID("$OpenBSD: mpaux.h,v 1.9 2000/12/19 23:17:57 markus Exp $"); */
#ifndef MPAUX_H
#define MPAUX_H
@ -23,8 +23,8 @@
* representations of host_key_n, session_key_n, and the cookie.
*/
void
compute_session_id(unsigned char session_id[16],
unsigned char cookie[8],
compute_session_id(u_char session_id[16],
u_char cookie[8],
BIGNUM * host_key_n,
BIGNUM * session_key_n);

View file

@ -1,3 +1,5 @@
/* $OpenBSD: myproposal.h,v 1.12 2001/03/05 15:56:16 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -22,13 +24,16 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1"
#define KEX_DEFAULT_PK_ALG "ssh-dss"
#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss"
#define KEX_DEFAULT_ENCRYPT \
"3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
"aes128-cbc,aes192-cbc,aes256-cbc," \
"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
"aes192-cbc,aes256-cbc," \
"rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \
"rijndael-cbc@lysator.liu.se"
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
#define KEX_DEFAULT_MAC \
"hmac-md5,hmac-sha1,hmac-ripemd160," \
"hmac-ripemd160@openssh.com," \
"hmac-sha1-96,hmac-md5-96"
#define KEX_DEFAULT_COMP "none,zlib"
#define KEX_DEFAULT_LANG ""

View file

@ -23,17 +23,16 @@
*/
#include "includes.h"
RCSID("$OpenBSD: nchan.c,v 1.19 2000/09/07 20:27:52 deraadt Exp $");
#include "ssh.h"
RCSID("$OpenBSD: nchan.c,v 1.23 2001/02/28 08:54:55 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
#include "buffer.h"
#include "packet.h"
#include "channels.h"
#include "nchan.h"
#include "ssh2.h"
#include "compat.h"
#include "log.h"
/* functions manipulating channel states */
/*
@ -55,9 +54,6 @@ static void chan_send_oclose1(Channel *c);
static void chan_send_close2(Channel *c);
static void chan_send_eof2(Channel *c);
/* channel cleanup */
chan_event_fn *chan_delete_if_full_closed = NULL;
/* helper */
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
@ -250,14 +246,6 @@ chan_send_oclose1(Channel *c)
break;
}
}
static void
chan_delete_if_full_closed1(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
debug("channel %d: full closed", c->self);
channel_free(c->self);
}
}
/*
* the same for SSH2
@ -400,22 +388,46 @@ chan_send_close2(Channel *c)
c->flags |= CHAN_CLOSE_SENT;
}
}
static void
chan_delete_if_full_closed2(Channel *c)
/* shared */
int
chan_is_dead(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
return 0;
if (!compat20) {
debug("channel %d: is dead", c->self);
return 1;
}
/*
* we have to delay the close message if the efd (for stderr) is
* still active
*/
if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
buffer_len(&c->extended) > 0)
#if 0
|| ((c->extended_usage == CHAN_EXTENDED_READ) &&
c->efd != -1)
#endif
) {
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");
} else {
if (!(c->flags & CHAN_CLOSE_SENT)) {
chan_send_close2(c);
}
if ((c->flags & CHAN_CLOSE_SENT) &&
(c->flags & CHAN_CLOSE_RCVD)) {
debug("channel %d: full closed2", c->self);
channel_free(c->self);
debug("channel %d: is dead", c->self);
return 1;
}
}
return 0;
}
/* shared */
void
chan_init_iostates(Channel *c)
{
@ -436,8 +448,6 @@ chan_init(void)
chan_rcvd_ieof = chan_rcvd_ieof2;
chan_write_failed = chan_write_failed2;
chan_obuf_empty = chan_obuf_empty2;
chan_delete_if_full_closed = chan_delete_if_full_closed2;
} else {
chan_rcvd_oclose = chan_rcvd_oclose1;
chan_read_failed = chan_read_failed_12;
@ -446,8 +456,6 @@ chan_init(void)
chan_rcvd_ieof = chan_rcvd_ieof1;
chan_write_failed = chan_write_failed1;
chan_obuf_empty = chan_obuf_empty1;
chan_delete_if_full_closed = chan_delete_if_full_closed1;
}
}

View file

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: nchan.h,v 1.9 2000/09/07 20:27:52 deraadt Exp $"); */
/* RCSID("$OpenBSD: nchan.h,v 1.10 2001/02/28 08:54:55 markus Exp $"); */
#ifndef NCHAN_H
#define NCHAN_H
@ -84,7 +84,7 @@ extern chan_event_fn *chan_rcvd_ieof;
extern chan_event_fn *chan_write_failed;
extern chan_event_fn *chan_obuf_empty;
extern chan_event_fn *chan_delete_if_full_closed;
int chan_is_dead(Channel * c);
void chan_init_iostates(Channel * c);
void chan_init(void);

View file

@ -1,3 +1,5 @@
.\" $OpenBSD: nchan.ms,v 1.7 2001/01/29 01:58:17 niklas Exp $
.\"
.\"
.\" Copyright (c) 1999 Markus Friedl. All rights reserved.
.\"

View file

@ -37,13 +37,12 @@
*/
#include "includes.h"
RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $");
RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
#include "packet.h"
#include "bufaux.h"
#include "ssh.h"
#include "crc32.h"
#include "getput.h"
@ -52,15 +51,14 @@ RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $");
#include "channels.h"
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include "buffer.h"
#include "cipher.h"
#include "kex.h"
#include "hmac.h"
#include "mac.h"
#include "log.h"
#include "canohost.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
@ -84,7 +82,7 @@ static int connection_out = -1;
static int cipher_type = SSH_CIPHER_NONE;
/* Protocol flags for the remote side. */
static unsigned int remote_protocol_flags = 0;
static u_int remote_protocol_flags = 0;
/* Encryption context for receiving data. This is only used for decryption. */
static CipherContext receive_context;
@ -106,6 +104,7 @@ static Buffer incoming_packet;
/* Scratch buffer for packet compression/decompression. */
static Buffer compression_buffer;
static int compression_buffer_ready = 0;
/* Flag indicating whether packet compression/decompression is enabled. */
static int packet_compression = 0;
@ -123,35 +122,14 @@ static int interactive_mode = 0;
int use_ssh2_packet_format = 0;
/* Session key information for Encryption and MAC */
Kex *kex = NULL;
Newkeys *newkeys[MODE_MAX];
void
packet_set_kex(Kex *k)
{
if( k->mac[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].iv == NULL ||
k->mac[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].iv == NULL)
fatal("bad KEX");
kex = k;
}
void
clear_enc_keys(Enc *enc, int len)
{
memset(enc->iv, 0, len);
memset(enc->key, 0, len);
xfree(enc->iv);
xfree(enc->key);
enc->iv = NULL;
enc->key = NULL;
}
void
packet_set_ssh2_format(void)
{
DBG(debug("use_ssh2_packet_format"));
use_ssh2_packet_format = 1;
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
}
/*
@ -167,8 +145,8 @@ packet_set_connection(int fd_in, int fd_out)
connection_in = fd_in;
connection_out = fd_out;
cipher_type = SSH_CIPHER_NONE;
cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0);
cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0);
cipher_init(&send_context, none, (u_char *) "", 0, NULL, 0);
cipher_init(&receive_context, none, (u_char *) "", 0, NULL, 0);
if (!initialized) {
initialized = 1;
buffer_init(&input);
@ -272,7 +250,7 @@ packet_close()
buffer_free(&output);
buffer_free(&outgoing_packet);
buffer_free(&incoming_packet);
if (packet_compression) {
if (compression_buffer_ready) {
buffer_free(&compression_buffer);
buffer_compress_uninit();
}
@ -281,7 +259,7 @@ packet_close()
/* Sets remote side protocol flags. */
void
packet_set_protocol_flags(unsigned int protocol_flags)
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);
@ -289,7 +267,7 @@ packet_set_protocol_flags(unsigned int protocol_flags)
/* Returns the remote protocol flags set earlier by the above function. */
unsigned int
u_int
packet_get_protocol_flags()
{
return remote_protocol_flags;
@ -300,15 +278,24 @@ packet_get_protocol_flags()
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
/*** XXXXX todo: kex means re-init */
void
packet_init_compression()
{
if (compression_buffer_ready == 1)
return;
compression_buffer_ready = 1;
buffer_init(&compression_buffer);
}
void
packet_start_compression(int level)
{
if (packet_compression)
if (packet_compression && !use_ssh2_packet_format)
fatal("Compression already enabled.");
packet_compression = 1;
buffer_init(&compression_buffer);
buffer_compress_init(level);
packet_init_compression();
buffer_compress_init_send(level);
buffer_compress_init_recv();
}
/*
@ -318,7 +305,7 @@ packet_start_compression(int level)
void
packet_encrypt(CipherContext * cc, void *dest, void *src,
unsigned int bytes)
u_int bytes)
{
cipher_encrypt(cc, dest, src, bytes);
}
@ -329,7 +316,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
*/
void
packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes)
packet_decrypt(CipherContext *context, void *dest, void *src, u_int bytes)
{
/*
* Cryptographic attack detector for ssh - Modifications for packet.c
@ -350,7 +337,7 @@ packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes
*/
void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
packet_set_encryption_key(const u_char *key, u_int keylen,
int number)
{
Cipher *cipher = cipher_by_number(number);
@ -391,7 +378,7 @@ packet_start2(int type)
void
packet_start(int type)
{
DBG(debug("packet_start[%d]",type));
DBG(debug("packet_start[%d]", type));
if (use_ssh2_packet_format)
packet_start2(type);
else
@ -410,7 +397,7 @@ packet_put_char(int value)
/* Appends an integer to the packet data. */
void
packet_put_int(unsigned int value)
packet_put_int(u_int value)
{
buffer_put_int(&outgoing_packet, value);
}
@ -418,7 +405,7 @@ packet_put_int(unsigned int value)
/* Appends a string to packet data. */
void
packet_put_string(const char *buf, unsigned int len)
packet_put_string(const char *buf, u_int len)
{
buffer_put_string(&outgoing_packet, buf, len);
}
@ -429,7 +416,7 @@ packet_put_cstring(const char *str)
}
void
packet_put_raw(const char *buf, unsigned int len)
packet_put_raw(const char *buf, u_int len)
{
buffer_append(&outgoing_packet, buf, len);
}
@ -454,11 +441,11 @@ packet_put_bignum2(BIGNUM * value)
*/
void
packet_send1()
packet_send1(void)
{
char buf[8], *cp;
int i, padding, len;
unsigned int checksum;
u_int checksum;
u_int32_t rand = 0;
/*
@ -493,7 +480,7 @@ packet_send1()
buffer_consume(&outgoing_packet, 8 - padding);
/* Add check bytes. */
checksum = ssh_crc32((unsigned char *) buffer_ptr(&outgoing_packet),
checksum = ssh_crc32((u_char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
PUT_32BIT(buf, checksum);
buffer_append(&outgoing_packet, buf, 4);
@ -524,28 +511,78 @@ packet_send1()
*/
}
void
set_newkeys(int mode)
{
Enc *enc;
Mac *mac;
Comp *comp;
CipherContext *cc;
debug("newkeys: mode %d", mode);
cc = (mode == MODE_OUT) ? &send_context : &receive_context;
if (newkeys[mode] != NULL) {
debug("newkeys: rekeying");
/* todo: free old keys, reset compression/cipher-ctxt; */
memset(cc, 0, sizeof(*cc));
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
memset(mac->key, 0, mac->key_len);
xfree(enc->name);
xfree(enc->iv);
xfree(enc->key);
xfree(mac->name);
xfree(mac->key);
xfree(comp->name);
xfree(newkeys[mode]);
}
newkeys[mode] = kex_get_newkeys(mode);
if (newkeys[mode] == NULL)
fatal("newkeys: no keys for mode %d", mode);
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
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);
if (comp->type != 0 && comp->enabled == 0) {
packet_init_compression();
if (mode == MODE_OUT)
buffer_compress_init_send(6);
else
buffer_compress_init_recv();
comp->enabled = 1;
}
}
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
void
packet_send2()
packet_send2(void)
{
unsigned char *macbuf = NULL;
static u_int32_t seqnr = 0;
u_char *macbuf = NULL;
char *cp;
unsigned int packet_length = 0;
unsigned int i, padlen, len;
u_int packet_length = 0;
u_int i, padlen, len;
u_int32_t rand = 0;
static unsigned int seqnr = 0;
int type;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
int block_size;
if (kex != NULL) {
enc = &kex->enc[MODE_OUT];
mac = &kex->mac[MODE_OUT];
comp = &kex->comp[MODE_OUT];
if (newkeys[MODE_OUT] != NULL) {
enc = &newkeys[MODE_OUT]->enc;
mac = &newkeys[MODE_OUT]->mac;
comp = &newkeys[MODE_OUT]->comp;
}
block_size = enc ? enc->cipher->block_size : 8;
@ -588,7 +625,7 @@ packet_send2()
if (i % 4 == 0)
rand = arc4random();
cp[i] = rand & 0xff;
rand <<= 8;
rand >>= 8;
}
} else {
/* clear padding */
@ -603,11 +640,9 @@ packet_send2()
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet),
mac->key, mac->key_len
);
macbuf = mac_compute(mac, seqnr,
(u_char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
DBG(debug("done calc MAC out #%d", seqnr));
}
/* encrypt packet and append to output buffer. */
@ -626,22 +661,8 @@ packet_send2()
log("outgoing seqnr wraps around");
buffer_clear(&outgoing_packet);
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_send2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init send_context"));
cipher_init(&send_context, enc->cipher,
enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
if (type == SSH2_MSG_NEWKEYS)
set_newkeys(MODE_OUT);
}
void
@ -664,10 +685,13 @@ int
packet_read(int *payload_len_ptr)
{
int type, len;
fd_set set;
fd_set *setp;
char buf[8192];
DBG(debug("packet_read()"));
setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
sizeof(fd_mask));
/* Since we are blocking, ensure that all written packets have been sent. */
packet_write_wait();
@ -682,17 +706,22 @@ packet_read(int *payload_len_ptr)
|| type == SSH_CMSG_EXIT_CONFIRMATION))
packet_integrity_check(*payload_len_ptr, 0, type);
/* If we got a packet, return it. */
if (type != SSH_MSG_NONE)
if (type != SSH_MSG_NONE) {
xfree(setp);
return type;
}
/*
* Otherwise, wait for some data to arrive, add it to the
* buffer, and try again.
*/
FD_ZERO(&set);
FD_SET(connection_in, &set);
memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
sizeof(fd_mask));
FD_SET(connection_in, setp);
/* Wait for some data to arrive. */
select(connection_in + 1, &set, NULL, NULL, NULL);
while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
/* Read data from the socket. */
len = read(connection_in, buf, sizeof(buf));
@ -742,16 +771,16 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
int
packet_read_poll1(int *payload_len_ptr)
{
unsigned int len, padded_len;
unsigned char *ucp;
u_int len, padded_len;
u_char *ucp;
char buf[8], *cp;
unsigned int checksum, stored_checksum;
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 = (unsigned char *) buffer_ptr(&input);
ucp = (u_char *) buffer_ptr(&input);
len = GET_32BIT(ucp);
if (len < 1 + 2 + 2 || len > 256 * 1024)
packet_disconnect("Bad packet length %d.", len);
@ -778,7 +807,7 @@ packet_read_poll1(int *payload_len_ptr)
#endif
/* Compute packet checksum. */
checksum = ssh_crc32((unsigned char *) buffer_ptr(&incoming_packet),
checksum = ssh_crc32((u_char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet) - 4);
/* Skip padding. */
@ -790,7 +819,7 @@ packet_read_poll1(int *payload_len_ptr)
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
len, buffer_len(&incoming_packet));
ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
ucp = (u_char *) buffer_ptr(&incoming_packet) + len - 4;
stored_checksum = GET_32BIT(ucp);
if (checksum != stored_checksum)
packet_disconnect("Corrupted check bytes on input.");
@ -811,28 +840,28 @@ packet_read_poll1(int *payload_len_ptr)
*payload_len_ptr = buffer_len(&incoming_packet);
/* Return type. */
return (unsigned char) buf[0];
return (u_char) buf[0];
}
int
packet_read_poll2(int *payload_len_ptr)
{
unsigned int padlen, need;
unsigned char buf[8], *macbuf;
unsigned char *ucp;
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;
static unsigned int packet_length = 0;
static unsigned int seqnr = 0;
int type;
int maclen, block_size;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
if (kex != NULL) {
enc = &kex->enc[MODE_IN];
mac = &kex->mac[MODE_IN];
comp = &kex->comp[MODE_IN];
if (newkeys[MODE_IN] != NULL) {
enc = &newkeys[MODE_IN]->enc;
mac = &newkeys[MODE_IN]->mac;
comp = &newkeys[MODE_IN]->comp;
}
maclen = mac && mac->enabled ? mac->mac_len : 0;
block_size = enc ? enc->cipher->block_size : 8;
@ -848,7 +877,7 @@ packet_read_poll2(int *payload_len_ptr)
buffer_append_space(&incoming_packet, &cp, block_size);
packet_decrypt(&receive_context, cp, buffer_ptr(&input),
block_size);
ucp = (unsigned char *) buffer_ptr(&incoming_packet);
ucp = (u_char *) buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(ucp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
buffer_dump(&incoming_packet);
@ -882,11 +911,9 @@ packet_read_poll2(int *payload_len_ptr)
* increment sequence number for incoming packet
*/
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet),
mac->key, mac->key_len
);
macbuf = mac_compute(mac, seqnr,
(u_char *) 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));
@ -926,30 +953,16 @@ packet_read_poll2(int *payload_len_ptr)
packet_length = 0;
/* extract packet type */
type = (unsigned char)buf[0];
type = (u_char)buf[0];
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_read_poll2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init receive_context"));
cipher_init(&receive_context, enc->cipher,
enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
if (type == SSH2_MSG_NEWKEYS)
set_newkeys(MODE_IN);
#ifdef PACKET_DEBUG
fprintf(stderr, "read/plain[%d]:\r\n",type);
fprintf(stderr, "read/plain[%d]:\r\n", type);
buffer_dump(&incoming_packet);
#endif
return (unsigned char)type;
return (u_char)type;
}
int
@ -979,14 +992,15 @@ packet_read_poll(int *payload_len_ptr)
case SSH2_MSG_DISCONNECT:
reason = packet_get_int();
msg = packet_get_string(NULL);
log("Received disconnect: %d: %.900s", reason, msg);
log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(),
reason, msg);
xfree(msg);
fatal_cleanup();
break;
default:
return type;
break;
}
}
} else {
switch(type) {
case SSH_MSG_IGNORE:
@ -998,7 +1012,8 @@ packet_read_poll(int *payload_len_ptr)
break;
case SSH_MSG_DISCONNECT:
msg = packet_get_string(NULL);
log("Received disconnect: %.900s", msg);
log("Received disconnect from %s: %.400s", get_remote_ipaddr(),
msg);
fatal_cleanup();
xfree(msg);
break;
@ -1007,7 +1022,7 @@ packet_read_poll(int *payload_len_ptr)
DBG(debug("received packet type %d", type));
return type;
break;
}
}
}
}
}
@ -1018,24 +1033,24 @@ packet_read_poll(int *payload_len_ptr)
*/
void
packet_process_incoming(const char *buf, unsigned int len)
packet_process_incoming(const char *buf, u_int len)
{
buffer_append(&input, buf, len);
}
/* Returns a character from the packet. */
unsigned int
u_int
packet_get_char()
{
char ch;
buffer_get(&incoming_packet, &ch, 1);
return (unsigned char) ch;
return (u_char) ch;
}
/* Returns an integer from the packet data. */
unsigned int
u_int
packet_get_int()
{
return buffer_get_int(&incoming_packet);
@ -1081,7 +1096,7 @@ packet_remaining(void)
*/
char *
packet_get_string(unsigned int *length_ptr)
packet_get_string(u_int *length_ptr)
{
return buffer_get_string(&incoming_packet, length_ptr);
}
@ -1101,6 +1116,9 @@ packet_send_debug(const char *fmt,...)
char buf[1024];
va_list args;
if (compat20 && (datafellows & SSH_BUG_DEBUG))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
@ -1193,14 +1211,21 @@ packet_write_poll()
void
packet_write_wait()
{
fd_set *setp;
setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
packet_write_poll();
while (packet_have_data_to_write()) {
fd_set set;
FD_ZERO(&set);
FD_SET(connection_out, &set);
select(connection_out + 1, NULL, &set, NULL, NULL);
memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
FD_SET(connection_out, setp);
while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
packet_write_poll();
}
xfree(setp);
}
/* Returns true if there is buffered data to write to the connection. */
@ -1225,45 +1250,45 @@ packet_not_very_much_data_to_write()
/* Informs that the current session is interactive. Sets IP flags for that. */
void
packet_set_interactive(int interactive, int keepalives)
packet_set_interactive(int interactive)
{
static int called = 0;
int lowdelay = IPTOS_LOWDELAY;
int throughput = IPTOS_THROUGHPUT;
int on = 1;
if (called)
return;
called = 1;
/* Record that we are in interactive mode. */
interactive_mode = interactive;
/* Only set socket options if using a socket. */
if (!packet_connection_is_on_socket())
return;
if (keepalives) {
/* Set keepalives if requested. */
if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
}
/*
* IPTOS_LOWDELAY, TCP_NODELAY and IPTOS_THROUGHPUT are IPv4 only
* IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
*/
if (!packet_connection_is_ipv4())
return;
if (interactive) {
/*
* Set IP options for an interactive connection. Use
* IPTOS_LOWDELAY and TCP_NODELAY.
*/
int lowdelay = IPTOS_LOWDELAY;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
sizeof(lowdelay)) < 0)
error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
if (packet_connection_is_ipv4()) {
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
(void *) &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));
} else {
} else if (packet_connection_is_ipv4()) {
/*
* Set IP options for a non-interactive connection. Use
* IPTOS_THROUGHPUT.
*/
int throughput = IPTOS_THROUGHPUT;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
sizeof(throughput)) < 0)
error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
@ -1295,3 +1320,65 @@ packet_set_maxsize(int s)
max_packet_size = s;
return s;
}
/*
* 9.2. Ignored Data Message
*
* byte SSH_MSG_IGNORE
* string data
*
* All implementations MUST understand (and ignore) this message at any
* time (after receiving the protocol version). No implementation is
* 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)
{
u_int32_t rand = 0;
int i;
packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
packet_put_int(nbytes);
for(i = 0; i < nbytes; i++) {
if (i % 4 == 0)
rand = arc4random();
packet_put_char(rand & 0xff);
rand >>= 8;
}
}

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: packet.h,v 1.17 2000/09/07 20:27:52 deraadt Exp $"); */
/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
#ifndef PACKET_H
#define PACKET_H
@ -46,17 +46,17 @@ void packet_close(void);
* encrypted independently of each other. Cipher types are defined in ssh.h.
*/
void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
packet_set_encryption_key(const u_char *key, u_int keylen,
int cipher_type);
/*
* Sets remote side protocol flags for the current connection. This can be
* called at any time.
*/
void packet_set_protocol_flags(unsigned int flags);
void packet_set_protocol_flags(u_int flags);
/* Returns the remote protocol flags set earlier by the above function. */
unsigned int packet_get_protocol_flags(void);
u_int packet_get_protocol_flags(void);
/* Enables compression in both directions starting from the next packet. */
void packet_start_compression(int level);
@ -65,7 +65,7 @@ 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, int keepalives);
void packet_set_interactive(int interactive);
/* Returns true if the current connection is interactive. */
int packet_is_interactive(void);
@ -77,16 +77,16 @@ void packet_start(int type);
void packet_put_char(int ch);
/* Appends an integer to the packet data. */
void packet_put_int(unsigned int value);
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, unsigned int len);
void packet_put_string(const char *buf, u_int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const char *buf, unsigned int len);
void packet_put_raw(const char *buf, u_int len);
/*
* Finalizes and sends the packet. If the encryption key has been set,
@ -117,13 +117,13 @@ 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, unsigned int len);
void packet_process_incoming(const char *buf, u_int len);
/* Returns a character (0-255) from the packet data. */
unsigned int packet_get_char(void);
u_int packet_get_char(void);
/* Returns an integer from the packet data. */
unsigned int packet_get_int(void);
u_int packet_get_int(void);
/*
* Returns an arbitrary precision integer from the packet data. The integer
@ -139,7 +139,7 @@ char *packet_get_raw(int *length_ptr);
* no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored.
*/
char *packet_get_string(unsigned int *length_ptr);
char *packet_get_string(u_int *length_ptr);
/*
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
@ -178,8 +178,8 @@ extern int max_packet_size;
int packet_set_maxsize(int s);
#define packet_get_maxsize() max_packet_size
/* Stores tty modes from the fd into current packet. */
void tty_make_modes(int fd);
/* 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);
@ -214,4 +214,10 @@ 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 */

111
crypto/openssh/pathnames.h Normal file
View file

@ -0,0 +1,111 @@
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#define ETCDIR "/etc"
#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"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
* should be world-readable.
*/
#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
#define _PATH_DH_PRIMES ETCDIR "/primes"
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
/*
* The process id of the daemon listening for connections is saved here to
* make it easier to kill the correct daemon when necessary.
*/
#define _PATH_SSH_DAEMON_PID_FILE _PATH_SSH_PIDDIR "/sshd.pid"
/*
* The directory in user\'s home directory in which the files reside. The
* directory should be world-readable (though not all files are).
*/
#define _PATH_SSH_USER_DIR ".ssh"
/*
* Per-user file containing host keys of known hosts. This file need not be
* readable by anyone except the user him/herself, though this does not
* contain anything particularly secret.
*/
#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
* Name of the default file containing client-side authentication key. This
* file should only be readable by the user him/herself.
*/
#define _PATH_SSH_CLIENT_IDENTITY ".ssh/identity"
#define _PATH_SSH_CLIENT_ID_DSA ".ssh/id_dsa"
#define _PATH_SSH_CLIENT_ID_RSA ".ssh/id_rsa"
/*
* Configuration file in user\'s home directory. This file need not be
* readable by anyone but the user him/herself, but does not contain anything
* particularly secret. If the user\'s home directory resides on an NFS
* volume where root is mapped to nobody, this may need to be world-readable.
*/
#define _PATH_SSH_USER_CONFFILE ".ssh/config"
/*
* File containing a list of those rsa keys that permit logging in as this
* user. This file need not be readable by anyone but the user him/herself,
* but does not contain anything particularly secret. If the user\'s home
* directory resides on an NFS volume where root is mapped to nobody, this
* may need to be world-readable. (This file is read by the daemon which is
* running as root.)
*/
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
* Per-user and system-wide ssh "rc" files. These files are executed with
* /bin/sh before starting the shell or command if they exist. They will be
* passed "proto cookie" as arguments if X11 forwarding with spoofing is in
* use. xauth will be run if neither of these exists.
*/
#define _PATH_SSH_USER_RC ".ssh/rc"
#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv"
/*
* Default location of askpass
*/
#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
/* for scp */
#define _PATH_CP "cp"
/* for sftp */
#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server"
#define _PATH_LS "ls"

View file

@ -25,19 +25,19 @@
#include "includes.h"
#include "uuencode.h"
RCSID("$OpenBSD: radix.c,v 1.13 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$OpenBSD: radix.c,v 1.15 2001/01/16 23:58:09 deraadt Exp $");
#ifdef AFS
#include <krb.h>
typedef unsigned char my_u_char;
typedef unsigned int my_u_int32_t;
typedef unsigned short my_u_short;
typedef u_char my_u_char;
typedef u_int my_u_int32_t;
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); \
register 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 +45,7 @@ typedef unsigned short my_u_short;
}
#define GETLONG(l, cp) { \
register my_u_char *t_cp = (my_u_char*)(cp); \
register 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) \
@ -56,7 +56,7 @@ typedef unsigned 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); \
register my_u_char *t_cp = (my_u_char *)(cp); \
*t_cp++ = t_s >> 8; \
*t_cp = t_s; \
(cp) += 2; \
@ -64,7 +64,7 @@ typedef unsigned short my_u_short;
#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); \
register 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 +73,9 @@ typedef unsigned 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); \
register char *p_targ = (p) + p_l; \
register char *s_c = (s); \
register char *p_c = (p); \
while (*p_c && (p_c < p_targ)) { \
*s_c++ = *p_c++; \
} \
@ -89,7 +89,7 @@ typedef unsigned short my_u_short;
int
creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
creds_to_radix(CREDENTIALS *creds, u_char *buf, size_t buflen)
{
char *p, *s;
int len;
@ -123,8 +123,8 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
PUTLONG(creds->issue_date, p);
{
unsigned int endTime;
endTime = (unsigned int) krb_life_to_time(creds->issue_date,
u_int endTime;
endTime = (u_int) krb_life_to_time(creds->issue_date,
creds->lifetime);
PUTLONG(endTime, p);
}
@ -139,7 +139,7 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
p += creds->ticket_st.length;
len = p - temp;
return (uuencode((unsigned char *)temp, len, (char *)buf, buflen));
return (uuencode((u_char *)temp, len, (char *)buf, buflen));
}
int
@ -151,7 +151,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
char version;
char temp[2048];
len = uudecode(buf, (unsigned char *)temp, sizeof(temp));
len = uudecode(buf, (u_char *)temp, sizeof(temp));
if (len < 0)
return 0;
@ -184,7 +184,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
GETLONG(creds->issue_date, p);
len -= 4;
{
unsigned int endTime;
u_int endTime;
GETLONG(endTime, p);
len -= 4;
creds->lifetime = krb_time_to_life(creds->issue_date, endTime);

28
crypto/openssh/radix.h Normal file
View file

@ -0,0 +1,28 @@
/* $OpenBSD: radix.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Copyright (c) 1999 Dug Song. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int creds_to_radix(CREDENTIALS * creds, u_char *buf, size_t buflen);
int radix_to_creds(const char *buf, CREDENTIALS * creds);

View file

@ -12,13 +12,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: readconf.c,v 1.76 2001/04/17 10:53:25 markus Exp $");
#include "ssh.h"
#include "readconf.h"
#include "match.h"
#include "xmalloc.h"
#include "compat.h"
#include "cipher.h"
#include "pathnames.h"
#include "log.h"
#include "readconf.h"
#include "match.h"
#include "misc.h"
#include "kex.h"
#include "mac.h"
/* Format of the configuration file:
@ -68,7 +74,7 @@ RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $");
# Defaults for various options
Host *
ForwardAgent no
ForwardX11 yes
ForwardX11 no
RhostsAuthentication yes
PasswordAuthentication yes
RSAAuthentication yes
@ -89,7 +95,7 @@ typedef enum {
oBadOption,
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
oSkeyAuthentication, oXAuthLocation,
oChallengeResponseAuthentication, oXAuthLocation,
#ifdef KRB4
oKerberosAuthentication,
#endif /* KRB4 */
@ -100,10 +106,12 @@ typedef enum {
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms
} OpCodes;
/* Textual representations of the tokens. */
@ -122,8 +130,13 @@ static struct {
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
{ "kbdinteractivedevices", oKbdInteractiveDevices },
{ "rsaauthentication", oRSAAuthentication },
{ "dsaauthentication", oDSAAuthentication },
{ "skeyauthentication", oSkeyAuthentication },
{ "pubkeyauthentication", oPubkeyAuthentication },
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "hostbasedauthentication", oHostbasedAuthentication },
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
#ifdef KRB4
{ "kerberosauthentication", oKerberosAuthentication },
#endif /* KRB4 */
@ -134,19 +147,20 @@ static struct {
{ "fallbacktorsh", oFallBackToRsh },
{ "usersh", oUseRsh },
{ "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile2 },
{ "identityfile2", oIdentityFile }, /* alias */
{ "hostname", oHostName },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand },
{ "port", oPort },
{ "cipher", oCipher },
{ "ciphers", oCiphers },
{ "macs", oMacs },
{ "protocol", oProtocol },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
{ "user", oUser },
{ "host", oHost },
{ "escapechar", oEscapeChar },
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile },
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
@ -159,8 +173,10 @@ static struct {
{ "compressionlevel", oCompressionLevel },
{ "keepalive", oKeepAlives },
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
{ "tisauthentication", oTISAuthentication },
{ "loglevel", oLogLevel },
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
{ NULL, 0 }
};
@ -176,7 +192,7 @@ add_local_forward(Options *options, u_short port, const char *host,
Forward *fwd;
extern uid_t original_real_uid;
if (port < IPPORT_RESERVED && original_real_uid != 0)
fatal("Privileged ports can only be forwarded by root.\n");
fatal("Privileged ports can only be forwarded by root.");
if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->local_forwards[options->num_local_forwards++];
@ -205,21 +221,20 @@ add_remote_forward(Options *options, u_short port, const char *host,
}
/*
* Returns the number of the token pointed to by cp of length len. Never
* returns if the token is not known.
* Returns the number of the token pointed to by cp or oBadOption.
*/
static OpCodes
parse_token(const char *cp, const char *filename, int linenum)
{
unsigned int i;
u_int i;
for (i = 0; keywords[i].name; i++)
if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
filename, linenum, cp);
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
return oBadOption;
}
@ -243,7 +258,7 @@ process_config_line(Options *options, const char *host,
/* Ignore leading whitespace. */
if (*keyword == '\0')
keyword = strdelim(&s);
if (!*keyword || *keyword == '\n' || *keyword == '#')
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
return 0;
opcode = parse_token(keyword, filename, linenum);
@ -298,8 +313,8 @@ parse_flag:
charptr = &options->kbd_interactive_devices;
goto parse_string;
case oDSAAuthentication:
intptr = &options->dsa_authentication;
case oPubkeyAuthentication:
intptr = &options->pubkey_authentication;
goto parse_flag;
case oRSAAuthentication:
@ -310,10 +325,12 @@ parse_flag:
intptr = &options->rhosts_rsa_authentication;
goto parse_flag;
case oTISAuthentication:
/* fallthrough, there is no difference on the client side */
case oSkeyAuthentication:
intptr = &options->skey_authentication;
case oHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
case oChallengeResponseAuthentication:
intptr = &options->challenge_reponse_authentication;
goto parse_flag;
#ifdef KRB4
@ -352,7 +369,7 @@ parse_flag:
intptr = &options->strict_host_key_checking;
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no argument.",
fatal("%.200s line %d: Missing yes/no/ask argument.",
filename, linenum);
value = 0; /* To avoid compiler warning... */
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
@ -384,20 +401,15 @@ parse_flag:
goto parse_int;
case oIdentityFile:
case oIdentityFile2:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep) {
intptr = (opcode == oIdentityFile) ?
&options->num_identity_files :
&options->num_identity_files2;
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);
charptr = (opcode == oIdentityFile) ?
&options->identity_files[*intptr] :
&options->identity_files2[*intptr];
charptr = &options->identity_files[*intptr];
*charptr = xstrdup(arg);
*intptr = *intptr + 1;
}
@ -437,6 +449,14 @@ parse_string:
charptr = &options->hostname;
goto parse_string;
case oHostKeyAlias:
charptr = &options->host_key_alias;
goto parse_string;
case oPreferredAuthentications:
charptr = &options->preferred_authentications;
goto parse_string;
case oProxyCommand:
charptr = &options->proxy_command;
string = xstrdup("");
@ -496,6 +516,28 @@ parse_int:
options->ciphers = xstrdup(arg);
break;
case oMacs:
arg = strdelim(&s);
if (!arg || *arg == '\0')
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>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
case oHostKeyAlgorithms:
arg = strdelim(&s);
if (!arg || *arg == '\0')
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>");
if (*activep && options->hostkeyalgorithms == NULL)
options->hostkeyalgorithms = xstrdup(arg);
break;
case oProtocol:
intptr = &options->protocol;
arg = strdelim(&s);
@ -514,7 +556,7 @@ parse_int:
arg = strdelim(&s);
value = log_level_number(arg);
if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n",
fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) * intptr == -1)
*intptr = (LogLevel) value;
@ -524,10 +566,10 @@ parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] < '0' || arg[0] > '9')
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
fwd_port = atoi(arg);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
@ -543,10 +585,10 @@ parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] < '0' || arg[0] > '9')
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
fwd_port = atoi(arg);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
@ -558,6 +600,18 @@ parse_int:
add_local_forward(options, fwd_port, buf, fwd_host_port);
break;
case oDynamicForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
add_local_forward(options, fwd_port, "socks4", 0);
break;
case oHost:
*activep = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@ -575,10 +629,10 @@ parse_int:
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] == '^' && arg[2] == 0 &&
(unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
value = (unsigned char) arg[1] & 31;
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
value = (u_char) arg[1] & 31;
else if (strlen(arg) == 1)
value = (unsigned char) arg[0];
value = (u_char) arg[0];
else if (strcmp(arg, "none") == 0)
value = -2;
else {
@ -596,8 +650,7 @@ parse_int:
}
/* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0')
{
if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
}
@ -640,7 +693,7 @@ read_config_file(const char *filename, const char *host, Options *options)
}
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options\n",
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
}
@ -662,8 +715,8 @@ initialize_options(Options * options)
options->use_privileged_port = -1;
options->rhosts_authentication = -1;
options->rsa_authentication = -1;
options->dsa_authentication = -1;
options->skey_authentication = -1;
options->pubkey_authentication = -1;
options->challenge_reponse_authentication = -1;
#ifdef KRB4
options->kerberos_authentication = -1;
#endif
@ -675,6 +728,7 @@ initialize_options(Options * options)
options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL;
options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
options->fallback_to_rsh = -1;
options->use_rsh = -1;
options->batch_mode = -1;
@ -688,10 +742,12 @@ initialize_options(Options * options)
options->number_of_password_prompts = -1;
options->cipher = -1;
options->ciphers = NULL;
options->macs = NULL;
options->hostkeyalgorithms = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->num_identity_files = 0;
options->num_identity_files2 = 0;
options->hostname = NULL;
options->host_key_alias = NULL;
options->proxy_command = NULL;
options->user = NULL;
options->escape_char = -1;
@ -702,6 +758,7 @@ initialize_options(Options * options)
options->num_local_forwards = 0;
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->preferred_authentications = NULL;
}
/*
@ -712,6 +769,8 @@ initialize_options(Options * options)
void
fill_default_options(Options * options)
{
int len;
if (options->forward_agent == -1)
options->forward_agent = 0;
if (options->forward_x11 == -1)
@ -723,15 +782,15 @@ fill_default_options(Options * options)
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->use_privileged_port == -1)
options->use_privileged_port = 1;
options->use_privileged_port = 0;
if (options->rhosts_authentication == -1)
options->rhosts_authentication = 1;
if (options->rsa_authentication == -1)
options->rsa_authentication = 1;
if (options->dsa_authentication == -1)
options->dsa_authentication = 1;
if (options->skey_authentication == -1)
options->skey_authentication = 0;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_reponse_authentication == -1)
options->challenge_reponse_authentication = 0;
#ifdef KRB4
if (options->kerberos_authentication == -1)
options->kerberos_authentication = 1;
@ -745,9 +804,11 @@ fill_default_options(Options * options)
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0;
options->kbd_interactive_authentication = 1;
if (options->rhosts_rsa_authentication == -1)
options->rhosts_rsa_authentication = 1;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->fallback_to_rsh == -1)
options->fallback_to_rsh = 0;
if (options->use_rsh == -1)
@ -774,33 +835,47 @@ fill_default_options(Options * options)
if (options->cipher == -1)
options->cipher = SSH_CIPHER_NOT_SET;
/* options->ciphers, default set in myproposals.h */
/* options->macs, default set in myproposals.h */
/* options->hostkeyalgorithms, default set in myproposals.h */
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->num_identity_files == 0) {
options->identity_files[0] =
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
options->num_identity_files = 1;
}
if (options->num_identity_files2 == 0) {
options->identity_files2[0] =
xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
options->num_identity_files2 = 1;
if (options->protocol & SSH_PROTO_1) {
len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
options->identity_files[options->num_identity_files] =
xmalloc(len);
snprintf(options->identity_files[options->num_identity_files++],
len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
}
if (options->protocol & SSH_PROTO_2) {
len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
options->identity_files[options->num_identity_files] =
xmalloc(len);
snprintf(options->identity_files[options->num_identity_files++],
len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
options->identity_files[options->num_identity_files] =
xmalloc(len);
snprintf(options->identity_files[options->num_identity_files++],
len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
}
}
if (options->escape_char == -1)
options->escape_char = '~';
if (options->system_hostfile == NULL)
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
if (options->user_hostfile == NULL)
options->user_hostfile = SSH_USER_HOSTFILE;
options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
if (options->system_hostfile2 == NULL)
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL)
options->user_hostfile2 = SSH_USER_HOSTFILE2;
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
if (options->log_level == (LogLevel) - 1)
options->log_level = SYSLOG_LEVEL_INFO;
/* 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 */
/* options->host_key_alias should not be set by default */
/* options->preferred_authentications will be set in ssh */
}

View file

@ -11,11 +11,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */
/* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
#ifndef READCONF_H
#define READCONF_H
#include "key.h"
/* Data structure for representing a forwarding request. */
typedef struct {
@ -35,8 +37,10 @@ typedef struct {
int rhosts_rsa_authentication; /* Try rhosts with RSA
* authentication. */
int rsa_authentication; /* Try RSA authentication. */
int dsa_authentication; /* Try DSA authentication. */
int skey_authentication; /* Try S/Key or TIS authentication. */
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int hostbased_authentication; /* ssh2's rhosts_rsa */
int challenge_reponse_authentication;
/* Try S/Key or TIS, authentication. */
#ifdef KRB4
int kerberos_authentication; /* Try Kerberos
* authentication. */
@ -67,8 +71,11 @@ typedef struct {
* prompts. */
int cipher; /* Cipher to use. */
char *ciphers; /* SSH2 ciphers in order of preference. */
char *macs; /* SSH2 macs in order of preference. */
char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */
int protocol; /* Protocol in order of preference. */
char *hostname; /* Real host to connect. */
char *host_key_alias; /* hostname alias for .ssh/known_hosts */
char *proxy_command; /* Proxy command for connecting the host. */
char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */
@ -77,11 +84,11 @@ typedef struct {
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2;
char *user_hostfile2;
char *preferred_authentications;
int num_identity_files; /* Number of files for RSA identities. */
int num_identity_files2; /* DSA identities. */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
char *identity_files2[SSH_MAX_IDENTITY_FILES];
Key *identity_keys[SSH_MAX_IDENTITY_FILES];
/* Local TCP/IP forward requests. */
int num_local_forwards;

View file

@ -32,11 +32,58 @@
*/
#include "includes.h"
RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
RCSID("$OpenBSD: readpass.c,v 1.15 2001/04/18 21:57:41 markus Exp $");
#include "xmalloc.h"
#include "ssh.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)
{
pid_t pid;
size_t len;
char *nl, *pass;
int p[2], status;
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 (pid == 0) {
seteuid(getuid());
setuid(getuid());
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) < 0)
fatal("ssh_askpass: dup2: %s", strerror(errno));
execlp(askpass, askpass, msg, (char *) 0);
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
}
close(p[1]);
len = read(p[0], buf, sizeof buf);
close(p[0]);
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
if (len <= 1)
return xstrdup("");
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
pass = xstrdup(buf);
memset(buf, 0, sizeof(buf));
return pass;
}
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
@ -51,5 +98,27 @@ RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
char *
read_passphrase(char *prompt, int from_stdin)
{
char *askpass = NULL;
int use_askpass = 0, ttyfd;
if (from_stdin) {
if (!isatty(STDIN_FILENO))
use_askpass = 1;
} else {
ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd >= 0)
close(ttyfd);
else
use_askpass = 1;
}
if (use_askpass && getenv("DISPLAY")) {
if (getenv(SSH_ASKPASS_ENV))
askpass = getenv(SSH_ASKPASS_ENV);
else
askpass = _PATH_SSH_ASKPASS_DEFAULT;
return ssh_askpass(askpass, prompt);
}
return cli_read_passphrase(prompt, from_stdin, 0);
}

20
crypto/openssh/readpass.h Normal file
View file

@ -0,0 +1,20 @@
/* $OpenBSD: readpass.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* 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);

View file

@ -1,4 +1,4 @@
/* $OpenBSD: rijndael.c,v 1.2 2000/10/15 14:14:01 markus Exp $ */
/* $OpenBSD: rijndael.c,v 1.7 2001/02/04 15:32:24 stevesk Exp $ */
/* This is an independent implementation of the encryption algorithm: */
/* */
@ -52,21 +52,14 @@ void gen_tabs __P((void));
/* Invert byte order in a 32 bit variable */
#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)
#define bswap(x) ((rotl(x, 8) & 0x00ff00ff) | (rotr(x, 8) & 0xff00ff00))
/* Extract byte from a 32 bit quantity (little endian notation) */
/* Extract byte from a 32 bit quantity (little endian notation) */
#define byte(x,n) ((u1byte)((x) >> (8 * n)))
#if BYTE_ORDER != LITTLE_ENDIAN
#define BLOCK_SWAP
#endif
/* For inverting byte order in input/output 32 bit words if needed */
#ifdef BLOCK_SWAP
#define BYTE_SWAP
#define WORD_SWAP
#endif
#ifdef BYTE_SWAP
@ -75,84 +68,6 @@ void gen_tabs __P((void));
#define io_swap(x) (x)
#endif
/* For inverting the byte order of input/output blocks if needed */
#ifdef WORD_SWAP
#define get_block(x) \
((u4byte*)(x))[0] = io_swap(in_blk[3]); \
((u4byte*)(x))[1] = io_swap(in_blk[2]); \
((u4byte*)(x))[2] = io_swap(in_blk[1]); \
((u4byte*)(x))[3] = io_swap(in_blk[0])
#define put_block(x) \
out_blk[3] = io_swap(((u4byte*)(x))[0]); \
out_blk[2] = io_swap(((u4byte*)(x))[1]); \
out_blk[1] = io_swap(((u4byte*)(x))[2]); \
out_blk[0] = io_swap(((u4byte*)(x))[3])
#define get_key(x,len) \
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
switch((((len) + 63) / 64)) { \
case 2: \
((u4byte*)(x))[0] = io_swap(in_key[3]); \
((u4byte*)(x))[1] = io_swap(in_key[2]); \
((u4byte*)(x))[2] = io_swap(in_key[1]); \
((u4byte*)(x))[3] = io_swap(in_key[0]); \
break; \
case 3: \
((u4byte*)(x))[0] = io_swap(in_key[5]); \
((u4byte*)(x))[1] = io_swap(in_key[4]); \
((u4byte*)(x))[2] = io_swap(in_key[3]); \
((u4byte*)(x))[3] = io_swap(in_key[2]); \
((u4byte*)(x))[4] = io_swap(in_key[1]); \
((u4byte*)(x))[5] = io_swap(in_key[0]); \
break; \
case 4: \
((u4byte*)(x))[0] = io_swap(in_key[7]); \
((u4byte*)(x))[1] = io_swap(in_key[6]); \
((u4byte*)(x))[2] = io_swap(in_key[5]); \
((u4byte*)(x))[3] = io_swap(in_key[4]); \
((u4byte*)(x))[4] = io_swap(in_key[3]); \
((u4byte*)(x))[5] = io_swap(in_key[2]); \
((u4byte*)(x))[6] = io_swap(in_key[1]); \
((u4byte*)(x))[7] = io_swap(in_key[0]); \
}
#else
#define get_block(x) \
((u4byte*)(x))[0] = io_swap(in_blk[0]); \
((u4byte*)(x))[1] = io_swap(in_blk[1]); \
((u4byte*)(x))[2] = io_swap(in_blk[2]); \
((u4byte*)(x))[3] = io_swap(in_blk[3])
#define put_block(x) \
out_blk[0] = io_swap(((u4byte*)(x))[0]); \
out_blk[1] = io_swap(((u4byte*)(x))[1]); \
out_blk[2] = io_swap(((u4byte*)(x))[2]); \
out_blk[3] = io_swap(((u4byte*)(x))[3])
#define get_key(x,len) \
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
switch((((len) + 63) / 64)) { \
case 4: \
((u4byte*)(x))[6] = io_swap(in_key[6]); \
((u4byte*)(x))[7] = io_swap(in_key[7]); \
case 3: \
((u4byte*)(x))[4] = io_swap(in_key[4]); \
((u4byte*)(x))[5] = io_swap(in_key[5]); \
case 2: \
((u4byte*)(x))[0] = io_swap(in_key[0]); \
((u4byte*)(x))[1] = io_swap(in_key[1]); \
((u4byte*)(x))[2] = io_swap(in_key[2]); \
((u4byte*)(x))[3] = io_swap(in_key[3]); \
}
#endif
#define LARGE_TABLES
u1byte pow_tab[256];
@ -174,15 +89,15 @@ u4byte tab_gen = 0;
#define f_rn(bo, bi, n, k) \
bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rn(bo, bi, n, k) \
bo[n] = it_tab[0][byte(bi[n],0)] ^ \
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#ifdef LARGE_TABLES
@ -194,15 +109,15 @@ u4byte tab_gen = 0;
#define f_rl(bo, bi, n, k) \
bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = il_tab[0][byte(bi[n],0)] ^ \
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#else
@ -214,15 +129,15 @@ u4byte tab_gen = 0;
#define f_rl(bo, bi, n, k) \
bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
#endif
@ -245,7 +160,7 @@ gen_tabs(void)
log_tab[1] = 0; p = 1;
for(i = 0; i < 10; ++i) {
rco_tab[i] = p;
rco_tab[i] = p;
p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
}
@ -257,19 +172,19 @@ gen_tabs(void)
/* least significant end of a byte. */
for(i = 0; i < 256; ++i) {
p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
}
for(i = 0; i < 256; ++i) {
p = sbx_tab[i];
p = sbx_tab[i];
#ifdef LARGE_TABLES
#ifdef LARGE_TABLES
t = p; fl_tab[0][i] = t;
fl_tab[1][i] = rotl(t, 8);
fl_tab[2][i] = rotl(t, 16);
@ -279,30 +194,30 @@ gen_tabs(void)
((u4byte)p << 8) |
((u4byte)p << 16) |
((u4byte)ff_mult(3, p) << 24);
ft_tab[0][i] = t;
ft_tab[1][i] = rotl(t, 8);
ft_tab[2][i] = rotl(t, 16);
ft_tab[3][i] = rotl(t, 24);
p = isb_tab[i];
p = isb_tab[i];
#ifdef LARGE_TABLES
t = p; il_tab[0][i] = t;
il_tab[1][i] = rotl(t, 8);
il_tab[2][i] = rotl(t, 16);
#ifdef LARGE_TABLES
t = p; il_tab[0][i] = t;
il_tab[1][i] = rotl(t, 8);
il_tab[2][i] = rotl(t, 16);
il_tab[3][i] = rotl(t, 24);
#endif
#endif
t = ((u4byte)ff_mult(14, p)) |
((u4byte)ff_mult( 9, p) << 8) |
((u4byte)ff_mult(13, p) << 16) |
((u4byte)ff_mult(11, p) << 24);
it_tab[0][i] = t;
it_tab[1][i] = rotl(t, 8);
it_tab[2][i] = rotl(t, 16);
it_tab[3][i] = rotl(t, 24);
it_tab[0][i] = t;
it_tab[1][i] = rotl(t, 8);
it_tab[2][i] = rotl(t, 16);
it_tab[3][i] = rotl(t, 24);
}
tab_gen = 1;
@ -317,8 +232,8 @@ gen_tabs(void)
t = w ^ (x); \
(y) = u ^ v ^ w; \
(y) ^= rotr(u ^ t, 8) ^ \
rotr(v ^ t, 16) ^ \
rotr(t,24)
rotr(v ^ t, 16) ^ \
rotr(t,24)
/* initialise the key schedule from the user supplied key */
@ -356,7 +271,7 @@ gen_tabs(void)
rijndael_ctx *
rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
int encrypt)
{
{
u4byte i, t, u, v, w;
u4byte *e_key = ctx->e_key;
u4byte *d_key = ctx->d_key;
@ -368,25 +283,25 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
ctx->k_len = (key_len + 31) / 32;
e_key[0] = in_key[0]; e_key[1] = in_key[1];
e_key[2] = in_key[2]; e_key[3] = in_key[3];
e_key[0] = io_swap(in_key[0]); e_key[1] = io_swap(in_key[1]);
e_key[2] = io_swap(in_key[2]); e_key[3] = io_swap(in_key[3]);
switch(ctx->k_len) {
case 4: t = e_key[3];
for(i = 0; i < 10; ++i)
case 4: t = e_key[3];
for(i = 0; i < 10; ++i)
loop4(i);
break;
break;
case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
for(i = 0; i < 8; ++i)
case 6: e_key[4] = io_swap(in_key[4]); t = e_key[5] = io_swap(in_key[5]);
for(i = 0; i < 8; ++i)
loop6(i);
break;
break;
case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
for(i = 0; i < 7; ++i)
case 8: e_key[4] = io_swap(in_key[4]); e_key[5] = io_swap(in_key[5]);
e_key[6] = io_swap(in_key[6]); t = e_key[7] = io_swap(in_key[7]);
for(i = 0; i < 7; ++i)
loop8(i);
break;
break;
}
if (!encrypt) {
@ -418,13 +333,15 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
void
rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
{
{
u4byte k_len = ctx->k_len;
u4byte *e_key = ctx->e_key;
u4byte b0[4], b1[4], *kp;
b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
b0[0] = io_swap(in_blk[0]) ^ e_key[0];
b0[1] = io_swap(in_blk[1]) ^ e_key[1];
b0[2] = io_swap(in_blk[2]) ^ e_key[2];
b0[3] = io_swap(in_blk[3]) ^ e_key[3];
kp = e_key + 4;
@ -442,8 +359,8 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_lround(b0, b1, kp);
out_blk[0] = b0[0]; out_blk[1] = b0[1];
out_blk[2] = b0[2]; out_blk[3] = b0[3];
out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]);
out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]);
}
/* decrypt a block of text */
@ -463,14 +380,16 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
void
rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
{
{
u4byte b0[4], b1[4], *kp;
u4byte k_len = ctx->k_len;
u4byte *e_key = ctx->e_key;
u4byte *d_key = ctx->d_key;
b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
b0[0] = io_swap(in_blk[0]) ^ e_key[4 * k_len + 24];
b0[1] = io_swap(in_blk[1]) ^ e_key[4 * k_len + 25];
b0[2] = io_swap(in_blk[2]) ^ e_key[4 * k_len + 26];
b0[3] = io_swap(in_blk[3]) ^ e_key[4 * k_len + 27];
kp = d_key + 4 * (k_len + 5);
@ -488,6 +407,6 @@ rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_lround(b0, b1, kp);
out_blk[0] = b0[0]; out_blk[1] = b0[1];
out_blk[2] = b0[2]; out_blk[3] = b0[3];
out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]);
out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]);
}

View file

@ -1,3 +1,19 @@
/* $OpenBSD: rijndael.h,v 1.7 2001/03/01 03:38:33 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 */
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_

View file

@ -8,7 +8,7 @@
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
@ -60,82 +60,16 @@
*/
#include "includes.h"
RCSID("$OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp $");
RCSID("$OpenBSD: rsa.c,v 1.22 2001/03/26 23:23:23 markus Exp $");
#include "rsa.h"
#include "ssh.h"
#include "log.h"
#include "xmalloc.h"
int rsa_verbose = 1;
int
rsa_alive()
{
RSA *key;
key = RSA_generate_key(32, 3, NULL, NULL);
if (key == NULL)
return (0);
RSA_free(key);
return (1);
}
/*
* Generates RSA public and private keys. This initializes the data
* structures; they should be freed with rsa_clear_private_key and
* rsa_clear_public_key.
*/
void
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
{
RSA *key;
if (rsa_verbose) {
printf("Generating RSA keys: ");
fflush(stdout);
}
key = RSA_generate_key(bits, 35, NULL, NULL);
if (key == NULL)
fatal("rsa_generate_key: key generation failed.");
/* Copy public key parameters */
pub->n = BN_new();
BN_copy(pub->n, key->n);
pub->e = BN_new();
BN_copy(pub->e, key->e);
/* Copy private key parameters */
prv->n = BN_new();
BN_copy(prv->n, key->n);
prv->e = BN_new();
BN_copy(prv->e, key->e);
prv->d = BN_new();
BN_copy(prv->d, key->d);
prv->p = BN_new();
BN_copy(prv->p, key->p);
prv->q = BN_new();
BN_copy(prv->q, key->q);
prv->dmp1 = BN_new();
BN_copy(prv->dmp1, key->dmp1);
prv->dmq1 = BN_new();
BN_copy(prv->dmq1, key->dmq1);
prv->iqmp = BN_new();
BN_copy(prv->iqmp, key->iqmp);
RSA_free(key);
if (rsa_verbose)
printf("Key generation complete.\n");
}
void
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
unsigned char *inbuf, *outbuf;
u_char *inbuf, *outbuf;
int len, ilen, olen;
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
@ -160,10 +94,10 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
xfree(inbuf);
}
void
int
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
unsigned char *inbuf, *outbuf;
u_char *inbuf, *outbuf;
int len, ilen, olen;
olen = BN_num_bytes(key->n);
@ -174,21 +108,34 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
BN_bn2bin(in, inbuf);
if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0)
fatal("rsa_private_decrypt() failed");
BN_bin2bn(outbuf, len, out);
RSA_PKCS1_PADDING)) <= 0) {
error("rsa_private_decrypt() failed");
} else {
BN_bin2bn(outbuf, len, out);
}
memset(outbuf, 0, olen);
memset(inbuf, 0, ilen);
xfree(outbuf);
xfree(inbuf);
return len;
}
/* Set whether to output verbose messages during key generation. */
void
rsa_set_verbose(int verbose)
generate_additional_parameters(RSA *rsa)
{
rsa_verbose = verbose;
BIGNUM *aux;
BN_CTX *ctx;
/* Generate additional parameters */
aux = BN_new();
ctx = BN_CTX_new();
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
BN_sub(aux, rsa->p, BN_value_one());
BN_mod(rsa->dmp1, rsa->d, aux, ctx);
BN_clear_free(aux);
BN_CTX_free(ctx);
}

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp $"); */
/* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
#ifndef RSA_H
#define RSA_H
@ -19,18 +19,9 @@
#include <openssl/bn.h>
#include <openssl/rsa.h>
/* Calls SSL RSA_generate_key, only copies to prv and pub */
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
/*
* Indicates whether the rsa module is permitted to show messages on the
* terminal.
*/
void rsa_set_verbose __P((int verbose));
int rsa_alive __P((void));
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
void rsa_private_decrypt __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));
#endif /* RSA_H */

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. 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.
*/
/*
* Parts from:
*
* 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.
*
*/
#include "includes.h"
RCSID("$OpenBSD: scp-common.c,v 1.1 2001/04/16 02:31:43 mouring Exp $");
char *
cleanhostname(host)
char *host;
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
char *
colon(cp)
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);
}

View file

@ -0,0 +1,64 @@
/* $OpenBSD: scp-common.h,v 1.1 2001/04/16 02:31:43 mouring Exp $ */
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. 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.
*/
/*
* Parts from:
*
* 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.
*
*/
char *cleanhostname(char *host);
char *colon(char *cp);

View file

@ -9,7 +9,7 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.13 2000/10/16 09:38:44 djm Exp $
.\" $OpenBSD: scp.1,v 1.14 2001/02/04 11:11:53 djm Exp $
.\"
.Dd September 25, 1999
.Dt SCP 1
@ -129,6 +129,7 @@ program in BSD source code from the Regents of the University of
California.
.Sh SEE ALSO
.Xr rcp 1 ,
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,

View file

@ -14,8 +14,8 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -75,12 +75,13 @@
*/
#include "includes.h"
RCSID("$OpenBSD: scp.c,v 1.43 2000/10/18 18:23:02 markus Exp $");
RCSID("$OpenBSD: scp.c,v 1.68 2001/04/22 12:34:05 markus Exp $");
#include "ssh.h"
#include "xmalloc.h"
#define _PATH_CP "cp"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
#include "scp-common.h"
/* For progressmeter() -- number of seconds before xfer considered "stalled" */
#define STALLTIME 5
@ -99,7 +100,7 @@ void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
static struct timeval start;
/* Number of bytes of current file transferred so far. */
volatile unsigned long statbytes;
volatile off_t statbytes;
/* Total size of current file. */
off_t totalbytes = 0;
@ -110,14 +111,11 @@ char *curfile;
/* This is set to non-zero to enable verbose mode. */
int verbose_mode = 0;
/* This is set to non-zero if compression is desired. */
int compress = 0;
/* This is set to zero if the progressmeter is not desired. */
int showprogress = 1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = SSH_PROGRAM;
char *ssh_program = _PATH_SSH_PROGRAM;
/* This is the list of arguments that scp passes to ssh */
struct {
@ -185,28 +183,12 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
return 0;
}
void
fatal(const char *fmt,...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", buf);
exit(255);
}
typedef struct {
int cnt;
char *buf;
} BUF;
extern int iamremote;
BUF *allocbuf(BUF *, int, int);
char *colon(char *);
void lostconn(int);
void nospace(void);
int okname(char *);
@ -245,7 +227,7 @@ main(argc, argv)
addargs("-oFallBackToRsh no");
fflag = tflag = 0;
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF)
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1)
switch (ch) {
/* User-visible flags. */
case '4':
@ -292,7 +274,6 @@ main(argc, argv)
iamremote = 1;
tflag = 1;
break;
case '?':
default:
usage();
}
@ -308,7 +289,7 @@ main(argc, argv)
remin = STDIN_FILENO;
remout = STDOUT_FILENO;
if (fflag) {
if (fflag) {
/* Follow "protocol", send data. */
(void) response();
source(argc, argv);
@ -326,7 +307,8 @@ main(argc, argv)
remin = remout = -1;
/* Command to be executed on remote system using "ssh". */
(void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "",
(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
verbose_mode ? " -v" : "",
iamrecursive ? " -r" : "", pflag ? " -p" : "",
targetshouldbedirectory ? " -d" : "");
@ -342,17 +324,6 @@ main(argc, argv)
exit(errs != 0);
}
char *
cleanhostname(host)
char *host;
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
void
toremote(targ, argc, argv)
char *targ, *argv[];
@ -397,20 +368,22 @@ toremote(targ, argc, argv)
suser = pwd->pw_name;
else if (!okname(suser))
continue;
(void) sprintf(bp,
"%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
suser, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
snprintf(bp, len,
"%s%s -x -o'FallBackToRsh no' -n "
"-l %s %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
suser, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
} else {
host = cleanhostname(argv[i]);
(void) sprintf(bp,
"exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
snprintf(bp, len,
"exec %s%s -x -o'FallBackToRsh no' -n %s "
"%s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
}
if (verbose_mode)
fprintf(stderr, "Executing: %s\n", bp);
@ -420,7 +393,7 @@ toremote(targ, argc, argv)
if (remin == -1) {
len = strlen(targ) + CMDNEEDS + 20;
bp = xmalloc(len);
(void) sprintf(bp, "%s -t %s", cmd, targ);
(void) snprintf(bp, len, "%s -t %s", cmd, targ);
host = cleanhostname(thost);
if (do_cmd(host, tuser, bp, &remin,
&remout, argc) < 0)
@ -447,7 +420,7 @@ tolocal(argc, argv)
len = strlen(_PATH_CP) + strlen(argv[i]) +
strlen(argv[argc - 1]) + 20;
bp = xmalloc(len);
(void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP,
(void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
iamrecursive ? " -r" : "", pflag ? " -p" : "",
argv[i], argv[argc - 1]);
if (verbose_mode)
@ -474,7 +447,7 @@ tolocal(argc, argv)
host = cleanhostname(host);
len = strlen(src) + CMDNEEDS + 20;
bp = xmalloc(len);
(void) sprintf(bp, "%s -f %s", cmd, src);
(void) snprintf(bp, len, "%s -f %s", cmd, src);
if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {
(void) xfree(bp);
++errs;
@ -495,13 +468,17 @@ source(argc, argv)
struct stat stb;
static BUF buffer;
BUF *bp;
off_t i;
int amt, fd, haderr, indx, result;
off_t i, amt, result;
int fd, haderr, indx;
char *last, *name, buf[2048];
int len;
for (indx = 0; indx < argc; ++indx) {
name = argv[indx];
statbytes = 0;
len = strlen(name);
while (len > 1 && name[len-1] == '/')
name[--len] = '\0';
if ((fd = open(name, O_RDONLY, 0)) < 0)
goto syserr;
if (fstat(fd, &stb) < 0) {
@ -531,18 +508,17 @@ syserr: run_err("%s: %s", name, strerror(errno));
* Make it compatible with possible future
* versions expecting microseconds.
*/
(void) sprintf(buf, "T%lu 0 %lu 0\n",
(unsigned long) stb.st_mtime,
(unsigned long) stb.st_atime);
(void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
(u_long) stb.st_mtime,
(u_long) stb.st_atime);
(void) atomicio(write, remout, buf, strlen(buf));
if (response() < 0)
goto next;
}
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
(void) sprintf(buf, "C%04o %lu %s\n",
(unsigned int) (stb.st_mode & FILEMODEMASK),
(unsigned long) stb.st_size,
last);
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last);
if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf);
fflush(stderr);
@ -609,17 +585,17 @@ rsource(name, statp)
else
last++;
if (pflag) {
(void) sprintf(path, "T%lu 0 %lu 0\n",
(unsigned long) statp->st_mtime,
(unsigned long) statp->st_atime);
(void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
(u_long) statp->st_mtime,
(u_long) statp->st_atime);
(void) atomicio(write, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
return;
}
}
(void) sprintf(path, "D%04o %d %.1024s\n",
(unsigned int) (statp->st_mode & FILEMODEMASK), 0, last);
(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
(u_int) (statp->st_mode & FILEMODEMASK), 0, last);
if (verbose_mode)
fprintf(stderr, "Entering directory: %s", path);
(void) atomicio(write, remout, path, strlen(path));
@ -627,7 +603,7 @@ rsource(name, statp)
closedir(dirp);
return;
}
while ((dp = readdir(dirp))) {
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_ino == 0)
continue;
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
@ -636,7 +612,7 @@ rsource(name, statp)
run_err("%s/%s: name too long", name, dp->d_name);
continue;
}
(void) sprintf(path, "%s/%s", name, dp->d_name);
(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
vect[0] = path;
source(1, vect);
}
@ -661,9 +637,10 @@ sink(argc, argv)
off_t size;
int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
int dummy_usec;
struct timeval tv[2];
#define atime tv[0]
#define mtime tv[1]
#define SCREWUP(str) { why = str; goto screwup; }
setimes = targisdir = 0;
@ -697,7 +674,7 @@ sink(argc, argv)
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
(void) atomicio(write, STDERR_FILENO,
buf + 1, strlen(buf + 1));
buf + 1, strlen(buf + 1));
if (buf[0] == '\02')
exit(1);
++errs;
@ -710,25 +687,21 @@ sink(argc, argv)
if (ch == '\n')
*--cp = 0;
#define getnum(t) (t) = 0; \
while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0');
cp = buf;
if (*cp == 'T') {
setimes++;
cp++;
getnum(tv[1].tv_sec);
if (*cp++ != ' ')
mtime.tv_sec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("mtime.sec not delimited");
getnum(dummy_usec);
tv[1].tv_usec = 0;
if (*cp++ != ' ')
mtime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("mtime.usec not delimited");
getnum(tv[0].tv_sec);
if (*cp++ != ' ')
atime.tv_sec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("atime.sec not delimited");
getnum(dummy_usec);
tv[0].tv_usec = 0;
if (*cp++ != '\0')
atime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != '\0')
SCREWUP("atime.usec not delimited");
(void) atomicio(write, remout, "", 1);
continue;
@ -756,7 +729,7 @@ sink(argc, argv)
if (*cp++ != ' ')
SCREWUP("mode not delimited");
for (size = 0; *cp >= '0' && *cp <= '9';)
for (size = 0; isdigit(*cp);)
size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ')
SCREWUP("size not delimited");
@ -766,9 +739,13 @@ sink(argc, argv)
size_t need;
need = strlen(targ) + strlen(cp) + 250;
if (need > cursize)
if (need > cursize) {
if (namebuf)
xfree(namebuf);
namebuf = xmalloc(need);
(void) sprintf(namebuf, "%s%s%s", targ,
cursize = need;
}
(void) snprintf(namebuf, need, "%s%s%s", targ,
*targ ? "/" : "", cp);
np = namebuf;
} else
@ -791,16 +768,18 @@ sink(argc, argv)
if (mkdir(np, mode | S_IRWXU) < 0)
goto bad;
}
vect[0] = np;
vect[0] = xstrdup(np);
sink(1, vect);
if (setimes) {
setimes = 0;
if (utimes(np, tv) < 0)
if (utimes(vect[0], tv) < 0)
run_err("%s: set times: %s",
np, strerror(errno));
vect[0], strerror(errno));
}
if (mod_flag)
(void) chmod(np, mode);
(void) chmod(vect[0], mode);
if (vect[0])
xfree(vect[0]);
continue;
}
omode = mode;
@ -833,7 +812,7 @@ bad: run_err("%s: %s", np, strerror(errno));
continue;
} else if (j <= 0) {
run_err("%s", j ? strerror(errno) :
"dropped connection");
"dropped connection");
exit(1);
}
amt -= j;
@ -870,12 +849,12 @@ bad: run_err("%s: %s", np, strerror(errno));
if (exists || omode != mode)
if (fchmod(ofd, omode))
run_err("%s: set mode: %s",
np, strerror(errno));
np, strerror(errno));
} else {
if (!exists && omode != mode)
if (fchmod(ofd, omode & ~mask))
run_err("%s: set mode: %s",
np, strerror(errno));
np, strerror(errno));
}
if (close(ofd) == -1) {
wrerr = YES;
@ -886,7 +865,7 @@ bad: run_err("%s: %s", np, strerror(errno));
setimes = 0;
if (utimes(np, tv) < 0) {
run_err("%s: set times: %s",
np, strerror(errno));
np, strerror(errno));
wrerr = DISPLAYED;
}
}
@ -943,8 +922,8 @@ void
usage()
{
(void) fprintf(stderr, "usage: scp "
"[-pqrvC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2; or:\n"
" scp [options] f1 ... fn directory\n");
"[-pqrvBC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2\n"
" or: scp [options] f1 ... fn directory\n");
exit(1);
}
@ -971,30 +950,6 @@ run_err(const char *fmt,...)
va_end(ap);
}
char *
colon(cp)
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);
}
void
verifydir(cp)
char *cp;
@ -1022,7 +977,8 @@ okname(cp0)
c = *cp;
if (c & 0200)
goto bad;
if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
if (!isalpha(c) && !isdigit(c) &&
c != '_' && c != '-' && c != '.' && c != '+')
goto bad;
} while (*++cp);
return (1);
@ -1089,7 +1045,7 @@ updateprogressmeter(int ignore)
}
int
foregroundproc()
foregroundproc(void)
{
static pid_t pgrp = -1;
int ctty_pgrp;
@ -1147,9 +1103,9 @@ progressmeter(int flag)
i++;
abbrevsize >>= 10;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5qd %c%c ",
(quad_t) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
'B');
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5llu %c%c ",
(unsigned long long) abbrevsize, prefixes[i],
prefixes[i] == ' ' ? ' ' : 'B');
timersub(&now, &lastupdate, &wait);
if (cursize > lastsize) {
@ -1164,16 +1120,17 @@ progressmeter(int flag)
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
if (flag != 1 &&
(statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
" --:-- ETA");
" --:-- ETA");
} else if (wait.tv_sec >= STALLTIME) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
" - stalled -");
" - stalled -");
} else {
if (flag != 1)
remaining =
(int)(totalbytes / (statbytes / elapsed) - elapsed);
remaining = (int)(totalbytes / (statbytes / elapsed) -
elapsed);
else
remaining = elapsed;

View file

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.12 2001/04/16 02:31:48 mouring Exp $
.PATH: ${.CURDIR}/..
PROG= scp
@ -8,6 +10,6 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= scp.1
SRCS= scp.c
SRCS= scp.c scp-common.c
.include <bsd.prog.mk>

View file

@ -10,15 +10,32 @@
*/
#include "includes.h"
RCSID("$OpenBSD: servconf.c,v 1.53 2000/10/14 12:12:09 markus Exp $");
RCSID("$OpenBSD: servconf.c,v 1.78 2001/04/15 21:28:35 stevesk Exp $");
#ifdef KRB4
#include <krb.h>
#endif
#ifdef AFS
#include <kafs.h>
#endif
#include "ssh.h"
#include "log.h"
#include "servconf.h"
#include "xmalloc.h"
#include "compat.h"
#include "pathnames.h"
#include "tildexpand.h"
#include "misc.h"
#include "cipher.h"
#include "kex.h"
#include "mac.h"
/* add listen address */
void add_listen_addr(ServerOptions *options, char *addr);
void add_listen_addr(ServerOptions *options, char *addr, u_short port);
void add_one_listen_addr(ServerOptions *options, char *addr, u_short port);
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
/* Initializes the server options to their default values. */
@ -29,16 +46,16 @@ initialize_server_options(ServerOptions *options)
options->num_ports = 0;
options->ports_from_cmdline = 0;
options->listen_addrs = NULL;
options->host_key_file = NULL;
options->host_dsa_key_file = NULL;
options->num_host_key_files = 0;
options->pid_file = NULL;
options->server_key_bits = -1;
options->login_grace_time = -1;
options->key_regeneration_time = -1;
options->permit_root_login = -1;
options->permit_root_login = PERMIT_NOT_SET;
options->ignore_rhosts = -1;
options->ignore_user_known_hosts = -1;
options->print_motd = -1;
options->print_lastlog = -1;
options->check_mail = -1;
options->x11_forwarding = -1;
options->x11_display_offset = -1;
@ -49,8 +66,10 @@ initialize_server_options(ServerOptions *options)
options->log_level = (LogLevel) - 1;
options->rhosts_authentication = -1;
options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
options->hostbased_uses_name_from_packet_only = -1;
options->rsa_authentication = -1;
options->dsa_authentication = -1;
options->pubkey_authentication = -1;
#ifdef KRB4
options->kerberos_authentication = -1;
options->kerberos_or_local_passwd = -1;
@ -62,9 +81,7 @@ initialize_server_options(ServerOptions *options)
#endif
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
#ifdef SKEY
options->skey_authentication = -1;
#endif
options->challenge_reponse_authentication = -1;
options->permit_empty_passwd = -1;
options->use_login = -1;
options->allow_tcp_forwarding = -1;
@ -73,35 +90,45 @@ initialize_server_options(ServerOptions *options)
options->num_allow_groups = 0;
options->num_deny_groups = 0;
options->ciphers = NULL;
options->macs = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->gateway_ports = -1;
options->num_subsystems = 0;
options->max_startups_begin = -1;
options->max_startups_rate = -1;
options->max_startups = -1;
options->banner = NULL;
options->reverse_mapping_check = -1;
options->client_alive_interval = -1;
options->client_alive_count_max = -1;
}
void
fill_default_server_options(ServerOptions *options)
{
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
if (options->protocol & SSH_PROTO_1)
options->host_key_files[options->num_host_key_files++] = _PATH_HOST_KEY_FILE;
if (options->protocol & SSH_PROTO_2)
options->host_key_files[options->num_host_key_files++] = _PATH_HOST_DSA_KEY_FILE;
}
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
if (options->listen_addrs == NULL)
add_listen_addr(options, NULL);
if (options->host_key_file == NULL)
options->host_key_file = HOST_KEY_FILE;
if (options->host_dsa_key_file == NULL)
options->host_dsa_key_file = HOST_DSA_KEY_FILE;
add_listen_addr(options, NULL, 0);
if (options->pid_file == NULL)
options->pid_file = SSH_DAEMON_PID_FILE;
options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
if (options->server_key_bits == -1)
options->server_key_bits = 768;
if (options->login_grace_time == -1)
options->login_grace_time = 600;
if (options->key_regeneration_time == -1)
options->key_regeneration_time = 3600;
if (options->permit_root_login == -1)
options->permit_root_login = 1; /* yes */
if (options->permit_root_login == PERMIT_NOT_SET)
options->permit_root_login = PERMIT_YES;
if (options->ignore_rhosts == -1)
options->ignore_rhosts = 1;
if (options->ignore_user_known_hosts == -1)
@ -110,6 +137,8 @@ fill_default_server_options(ServerOptions *options)
options->check_mail = 0;
if (options->print_motd == -1)
options->print_motd = 1;
if (options->print_lastlog == -1)
options->print_lastlog = 1;
if (options->x11_forwarding == -1)
options->x11_forwarding = 0;
if (options->x11_display_offset == -1)
@ -130,10 +159,14 @@ fill_default_server_options(ServerOptions *options)
options->rhosts_authentication = 0;
if (options->rhosts_rsa_authentication == -1)
options->rhosts_rsa_authentication = 0;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->hostbased_uses_name_from_packet_only == -1)
options->hostbased_uses_name_from_packet_only = 0;
if (options->rsa_authentication == -1)
options->rsa_authentication = 1;
if (options->dsa_authentication == -1)
options->dsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
#ifdef KRB4
if (options->kerberos_authentication == -1)
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
@ -152,18 +185,14 @@ fill_default_server_options(ServerOptions *options)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0;
#ifdef SKEY
if (options->skey_authentication == -1)
options->skey_authentication = 1;
#endif
if (options->challenge_reponse_authentication == -1)
options->challenge_reponse_authentication = 1;
if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0;
if (options->use_login == -1)
options->use_login = 0;
if (options->allow_tcp_forwarding == -1)
options->allow_tcp_forwarding = 1;
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->max_startups == -1)
@ -172,6 +201,12 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_rate = 100; /* 100% */
if (options->max_startups_begin == -1)
options->max_startups_begin = options->max_startups;
if (options->reverse_mapping_check == -1)
options->reverse_mapping_check = 0;
if (options->client_alive_interval == -1)
options->client_alive_interval = 0;
if (options->client_alive_count_max == -1)
options->client_alive_count_max = 3;
}
/* Keyword tokens. */
@ -186,16 +221,18 @@ typedef enum {
#ifdef AFS
sKerberosTgtPassing, sAFSTokenPassing,
#endif
#ifdef SKEY
sSkeyAuthentication,
#endif
sChallengeResponseAuthentication,
sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset,
sStrictModes, sEmptyPasswd, sKeepAlives, sCheckMail,
sUseLogin, sAllowTcpForwarding,
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
sBanner, sReverseMappingCheck, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
sClientAliveCountMax
} ServerOpCodes;
/* Textual representation of the tokens. */
@ -205,8 +242,8 @@ static struct {
} keywords[] = {
{ "port", sPort },
{ "hostkey", sHostKeyFile },
{ "hostdsakey", sHostDSAKeyFile },
{ "pidfile", sPidFile },
{ "hostdsakey", sHostKeyFile }, /* alias */
{ "pidfile", sPidFile },
{ "serverkeybits", sServerKeyBits },
{ "logingracetime", sLoginGraceTime },
{ "keyregenerationinterval", sKeyRegenerationTime },
@ -215,8 +252,11 @@ static struct {
{ "loglevel", sLogLevel },
{ "rhostsauthentication", sRhostsAuthentication },
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
{ "hostbasedauthentication", sHostbasedAuthentication },
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
{ "rsaauthentication", sRSAAuthentication },
{ "dsaauthentication", sDSAAuthentication },
{ "pubkeyauthentication", sPubkeyAuthentication },
{ "dsaauthentication", sPubkeyAuthentication }, /* alias */
#ifdef KRB4
{ "kerberosauthentication", sKerberosAuthentication },
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
@ -228,12 +268,12 @@ static struct {
#endif
{ "passwordauthentication", sPasswordAuthentication },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
#ifdef SKEY
{ "skeyauthentication", sSkeyAuthentication },
#endif
{ "challengeresponseauthentication", sChallengeResponseAuthentication },
{ "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
{ "checkmail", sCheckMail },
{ "listenaddress", sListenAddress },
{ "printmotd", sPrintMotd },
{ "printlastlog", sPrintLastLog },
{ "ignorerhosts", sIgnoreRhosts },
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
{ "x11forwarding", sX11Forwarding },
@ -242,7 +282,6 @@ static struct {
{ "strictmodes", sStrictModes },
{ "permitemptypasswords", sEmptyPasswd },
{ "uselogin", sUseLogin },
{ "randomseed", sRandomSeedFile },
{ "keepalive", sKeepAlives },
{ "allowtcpforwarding", sAllowTcpForwarding },
{ "allowusers", sAllowUsers },
@ -250,62 +289,71 @@ static struct {
{ "allowgroups", sAllowGroups },
{ "denygroups", sDenyGroups },
{ "ciphers", sCiphers },
{ "macs", sMacs },
{ "protocol", sProtocol },
{ "gatewayports", sGatewayPorts },
{ "subsystem", sSubsystem },
{ "maxstartups", sMaxStartups },
{ "banner", sBanner },
{ "reversemappingcheck", sReverseMappingCheck },
{ "clientaliveinterval", sClientAliveInterval },
{ "clientalivecountmax", sClientAliveCountMax },
{ NULL, 0 }
};
/*
* Returns the number of the token pointed to by cp of length len. Never
* returns if the token is not known.
* Returns the number of the token pointed to by cp or sBadOption.
*/
static ServerOpCodes
parse_token(const char *cp, const char *filename,
int linenum)
{
unsigned int i;
u_int i;
for (i = 0; keywords[i].name; i++)
if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
filename, linenum, cp);
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
return sBadOption;
}
/*
* add listen address
*/
void
add_listen_addr(ServerOptions *options, char *addr)
add_listen_addr(ServerOptions *options, char *addr, u_short port)
{
extern int IPv4or6;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
int i;
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
for (i = 0; i < options->num_ports; i++) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
snprintf(strport, sizeof strport, "%d", options->ports[i]);
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
fatal("bad addr or host: %s (%s)\n",
addr ? addr : "<NULL>",
gai_strerror(gaierr));
for (ai = aitop; ai->ai_next; ai = ai->ai_next)
;
ai->ai_next = options->listen_addrs;
options->listen_addrs = aitop;
}
if (port == 0)
for (i = 0; i < options->num_ports; i++)
add_one_listen_addr(options, addr, options->ports[i]);
else
add_one_listen_addr(options, addr, port);
}
void
add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
{
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
fatal("bad addr or host: %s (%s)",
addr ? addr : "<NULL>",
gai_strerror(gaierr));
for (ai = aitop; ai->ai_next; ai = ai->ai_next)
;
ai->ai_next = options->listen_addrs;
options->listen_addrs = aitop;
}
/* Reads the server configuration file. */
@ -315,7 +363,7 @@ read_server_config(ServerOptions *options, const char *filename)
{
FILE *f;
char line[1024];
char *cp, **charptr, *arg;
char *cp, **charptr, *arg, *p;
int linenum, *intptr, value;
int bad_options = 0;
ServerOpCodes opcode;
@ -334,8 +382,10 @@ read_server_config(ServerOptions *options, const char *filename)
/* Ignore leading whitespace */
if (*arg == '\0')
arg = strdelim(&cp);
if (!*arg || *arg == '#')
if (!arg || !*arg || *arg == '#')
continue;
intptr = NULL;
charptr = NULL;
opcode = parse_token(arg, filename, linenum);
switch (opcode) {
case sBadOption:
@ -349,24 +399,25 @@ read_server_config(ServerOptions *options, const char *filename)
fatal("%s line %d: ports must be specified before "
"ListenAdress.\n", filename, linenum);
if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.\n",
fatal("%s line %d: too many ports.",
filename, linenum);
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing port number.\n",
fatal("%s line %d: missing port number.",
filename, linenum);
options->ports[options->num_ports++] = a2port(arg);
if (options->ports[options->num_ports-1] == 0)
fatal("%s line %d: Badly formatted port number.",
filename, linenum);
options->ports[options->num_ports++] = atoi(arg);
break;
case sServerKeyBits:
intptr = &options->server_key_bits;
parse_int:
arg = strdelim(&cp);
if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing integer value.\n",
filename, linenum);
exit(1);
}
if (!arg || *arg == '\0')
fatal("%s line %d: missing integer value.",
filename, linenum);
value = atoi(arg);
if (*intptr == -1)
*intptr = value;
@ -382,56 +433,84 @@ parse_int:
case sListenAddress:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing inet addr.\n",
if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
fatal("%s line %d: missing inet addr.",
filename, linenum);
if (*arg == '[') {
if ((p = strchr(arg, ']')) == NULL)
fatal("%s line %d: bad ipv6 inet addr usage.",
filename, linenum);
arg++;
memmove(p, p+1, strlen(p+1)+1);
} else if (((p = strchr(arg, ':')) == NULL) ||
(strchr(p+1, ':') != NULL)) {
add_listen_addr(options, arg, 0);
break;
}
if (*p == ':') {
u_short port;
p++;
if (*p == '\0')
fatal("%s line %d: bad inet addr:port usage.",
filename, linenum);
else {
*(p-1) = '\0';
if ((port = a2port(p)) == 0)
fatal("%s line %d: bad port number.",
filename, linenum);
add_listen_addr(options, arg, port);
}
} else if (*p == '\0')
add_listen_addr(options, arg, 0);
else
fatal("%s line %d: bad inet addr usage.",
filename, linenum);
add_listen_addr(options, arg);
break;
case sHostKeyFile:
case sHostDSAKeyFile:
charptr = (opcode == sHostKeyFile ) ?
&options->host_key_file : &options->host_dsa_key_file;
intptr = &options->num_host_key_files;
if (*intptr >= MAX_HOSTKEYS)
fatal("%s line %d: too many host keys specified (max %d).",
filename, linenum, MAX_HOSTKEYS);
charptr = &options->host_key_files[*intptr];
parse_filename:
arg = strdelim(&cp);
if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing file name.\n",
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
exit(1);
}
if (*charptr == NULL)
if (*charptr == NULL) {
*charptr = tilde_expand_filename(arg, getuid());
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break;
case sPidFile:
charptr = &options->pid_file;
goto parse_filename;
case sRandomSeedFile:
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
filename, linenum);
arg = strdelim(&cp);
break;
case sPermitRootLogin:
intptr = &options->permit_root_login;
arg = strdelim(&cp);
if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
filename, linenum);
exit(1);
}
if (!arg || *arg == '\0')
fatal("%s line %d: missing yes/"
"without-password/forced-commands-only/no "
"argument.", filename, linenum);
value = 0; /* silence compiler */
if (strcmp(arg, "without-password") == 0)
value = 2;
value = PERMIT_NO_PASSWD;
else if (strcmp(arg, "forced-commands-only") == 0)
value = PERMIT_FORCED_ONLY;
else if (strcmp(arg, "yes") == 0)
value = 1;
value = PERMIT_YES;
else if (strcmp(arg, "no") == 0)
value = 0;
else {
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
filename, linenum, arg);
exit(1);
}
value = PERMIT_NO;
else
fatal("%s line %d: Bad yes/"
"without-password/forced-commands-only/no "
"argument: %s", filename, linenum, arg);
if (*intptr == -1)
*intptr = value;
break;
@ -440,20 +519,17 @@ parse_filename:
intptr = &options->ignore_rhosts;
parse_flag:
arg = strdelim(&cp);
if (!arg || *arg == '\0') {
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
filename, linenum);
exit(1);
}
if (!arg || *arg == '\0')
fatal("%s line %d: missing yes/no argument.",
filename, linenum);
value = 0; /* silence compiler */
if (strcmp(arg, "yes") == 0)
value = 1;
else if (strcmp(arg, "no") == 0)
value = 0;
else {
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
else
fatal("%s line %d: Bad yes/no argument: %s",
filename, linenum, arg);
exit(1);
}
if (*intptr == -1)
*intptr = value;
break;
@ -470,12 +546,20 @@ parse_flag:
intptr = &options->rhosts_rsa_authentication;
goto parse_flag;
case sHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
case sHostbasedUsesNameFromPacketOnly:
intptr = &options->hostbased_uses_name_from_packet_only;
goto parse_flag;
case sRSAAuthentication:
intptr = &options->rsa_authentication;
goto parse_flag;
case sDSAAuthentication:
intptr = &options->dsa_authentication;
case sPubkeyAuthentication:
intptr = &options->pubkey_authentication;
goto parse_flag;
#ifdef KRB4
@ -514,16 +598,18 @@ parse_flag:
intptr = &options->check_mail;
goto parse_flag;
#ifdef SKEY
case sSkeyAuthentication:
intptr = &options->skey_authentication;
case sChallengeResponseAuthentication:
intptr = &options->challenge_reponse_authentication;
goto parse_flag;
#endif
case sPrintMotd:
intptr = &options->print_motd;
goto parse_flag;
case sPrintLastLog:
intptr = &options->print_lastlog;
goto parse_flag;
case sX11Forwarding:
intptr = &options->x11_forwarding;
goto parse_flag;
@ -535,7 +621,7 @@ parse_flag:
case sXAuthLocation:
charptr = &options->xauth_location;
goto parse_filename;
case sStrictModes:
intptr = &options->strict_modes;
goto parse_flag;
@ -556,12 +642,16 @@ parse_flag:
intptr = &options->gateway_ports;
goto parse_flag;
case sReverseMappingCheck:
intptr = &options->reverse_mapping_check;
goto parse_flag;
case sLogFacility:
intptr = (int *) &options->log_facility;
arg = strdelim(&cp);
value = log_facility_number(arg);
if (value == (SyslogFacility) - 1)
fatal("%.200s line %d: unsupported log facility '%s'\n",
fatal("%.200s line %d: unsupported log facility '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1)
*intptr = (SyslogFacility) value;
@ -572,7 +662,7 @@ parse_flag:
arg = strdelim(&cp);
value = log_level_number(arg);
if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n",
fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1)
*intptr = (LogLevel) value;
@ -585,7 +675,7 @@ parse_flag:
case sAllowUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_users >= MAX_ALLOW_USERS)
fatal("%s line %d: too many allow users.\n",
fatal("%s line %d: too many allow users.",
filename, linenum);
options->allow_users[options->num_allow_users++] = xstrdup(arg);
}
@ -594,7 +684,7 @@ parse_flag:
case sDenyUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_users >= MAX_DENY_USERS)
fatal( "%s line %d: too many deny users.\n",
fatal( "%s line %d: too many deny users.",
filename, linenum);
options->deny_users[options->num_deny_users++] = xstrdup(arg);
}
@ -603,7 +693,7 @@ parse_flag:
case sAllowGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
fatal("%s line %d: too many allow groups.\n",
fatal("%s line %d: too many allow groups.",
filename, linenum);
options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
}
@ -612,7 +702,7 @@ parse_flag:
case sDenyGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_groups >= MAX_DENY_GROUPS)
fatal("%s line %d: too many deny groups.\n",
fatal("%s line %d: too many deny groups.",
filename, linenum);
options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
}
@ -629,6 +719,17 @@ parse_flag:
options->ciphers = xstrdup(arg);
break;
case sMacs:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%s line %d: Bad SSH2 mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (options->macs == NULL)
options->macs = xstrdup(arg);
break;
case sProtocol:
intptr = &options->protocol;
arg = strdelim(&cp);
@ -684,22 +785,25 @@ parse_flag:
intptr = &options->max_startups;
goto parse_int;
case sBanner:
charptr = &options->banner;
goto parse_filename;
case sClientAliveInterval:
intptr = &options->client_alive_interval;
goto parse_int;
case sClientAliveCountMax:
intptr = &options->client_alive_count_max;
goto parse_int;
default:
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, arg, opcode);
exit(1);
}
if ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
fprintf(stderr,
"%s line %d: garbage at end of line; \"%.200s\".\n",
filename, linenum, arg);
exit(1);
fatal("%s line %d: Missing handler for opcode %s (%d)",
filename, linenum, arg, opcode);
}
if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
fatal("%s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
}
fclose(f);
if (bad_options > 0) {
fprintf(stderr, "%s: terminating, %d bad configuration options\n",
filename, bad_options);
exit(1);
}
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
}

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: servconf.h,v 1.30 2000/10/14 12:12:09 markus Exp $"); */
/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@ -23,25 +23,35 @@
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
#define MAX_HOSTKEYS 256 /* Max # hostkeys. */
/* permit_root_login */
#define PERMIT_NOT_SET -1
#define PERMIT_NO 0
#define PERMIT_FORCED_ONLY 1
#define PERMIT_NO_PASSWD 2
#define PERMIT_YES 3
typedef struct {
unsigned int num_ports;
unsigned int ports_from_cmdline;
u_int num_ports;
u_int ports_from_cmdline;
u_short ports[MAX_PORTS]; /* Port number to listen on. */
char *listen_addr; /* Address on which the server listens. */
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
char *host_key_file; /* File containing host key. */
char *host_dsa_key_file; /* File containing dsa host key. */
char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */
int num_host_key_files; /* Number of files for host keys. */
char *pid_file; /* Where to put our pid */
int server_key_bits;/* Size of the server key. */
int login_grace_time; /* Disconnect if no auth in this time
* (sec). */
int key_regeneration_time; /* Server key lifetime (seconds). */
int permit_root_login; /* If true, permit root login. */
int permit_root_login; /* PERMIT_*, see above */
int ignore_rhosts; /* Ignore .rhosts and .shosts. */
int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts
* 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
@ -49,8 +59,9 @@ typedef struct {
char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */
char *ciphers; /* Ciphers in order of preference. */
int protocol; /* Protocol in order of preference. */
char *ciphers; /* Supported SSH2 ciphers. */
char *macs; /* Supported SSH2 macs. */
int protocol; /* Supported protocol versions. */
int gateway_ports; /* If true, allow remote connects to forwarded ports. */
SyslogFacility log_facility; /* Facility for system logging. */
LogLevel log_level; /* Level for system logging. */
@ -58,8 +69,10 @@ typedef struct {
* authentication. */
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
* authentication. */
int hostbased_authentication; /* If true, permit ssh2 hostbased auth */
int hostbased_uses_name_from_packet_only; /* experimental */
int rsa_authentication; /* If true, permit RSA authentication. */
int dsa_authentication; /* If true, permit DSA authentication. */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
#ifdef KRB4
int kerberos_authentication; /* If true, permit Kerberos
* authentication. */
@ -79,30 +92,38 @@ typedef struct {
int password_authentication; /* If true, permit password
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
#ifdef SKEY
int skey_authentication; /* If true, permit s/key
* authentication. */
#endif
int challenge_reponse_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int use_login; /* If true, login(1) is used */
int allow_tcp_forwarding;
unsigned int num_allow_users;
u_int num_allow_users;
char *allow_users[MAX_ALLOW_USERS];
unsigned int num_deny_users;
u_int num_deny_users;
char *deny_users[MAX_DENY_USERS];
unsigned int num_allow_groups;
u_int num_allow_groups;
char *allow_groups[MAX_ALLOW_GROUPS];
unsigned int num_deny_groups;
u_int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS];
unsigned int num_subsystems;
u_int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
int max_startups_begin;
int max_startups_rate;
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
int client_alive_interval; /*
* 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
*/
} ServerOptions;
/*

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000 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,24 +35,31 @@
*/
#include "includes.h"
RCSID("$OpenBSD: serverloop.c,v 1.34 2000/10/27 07:32:18 markus Exp $");
RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "packet.h"
#include "buffer.h"
#include "log.h"
#include "servconf.h"
#include "pty.h"
#include "sshpty.h"
#include "channels.h"
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
#include "auth.h"
#include "session.h"
#include "dispatch.h"
#include "auth-options.h"
#include "serverloop.h"
#include "misc.h"
#include "kex.h"
extern ServerOptions options;
/* XXX */
extern Kex *xxx_kex;
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
static Buffer stderr_buffer; /* Buffer for stderr data. */
@ -67,10 +74,11 @@ static long fdout_bytes = 0; /* Number of stdout bytes read from program. */
static int stdin_eof = 0; /* EOF message received from client. */
static int fdout_eof = 0; /* EOF encountered reading from fdout. */
static int fderr_eof = 0; /* EOF encountered readung from fderr. */
static int fdin_is_tty = 0; /* fdin points to a tty. */
static int connection_in; /* Connection to client (input). */
static int connection_out; /* Connection to client (output). */
static unsigned int buffer_high;/* "Soft" max buffer size. */
static int max_fd; /* Max file descriptor number for select(). */
static int connection_closed = 0; /* Connection to client closed. */
static u_int buffer_high; /* "Soft" max buffer size. */
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
@ -83,6 +91,8 @@ static volatile int child_wait_status; /* Status from wait(). */
void server_init_dispatch(void);
int client_alive_timeouts = 0;
void
sigchld_handler(int sig)
{
@ -117,7 +127,7 @@ sigchld_handler2(int sig)
* to the client.
*/
void
make_packets_from_stderr_data()
make_packets_from_stderr_data(void)
{
int len;
@ -146,7 +156,7 @@ make_packets_from_stderr_data()
* client.
*/
void
make_packets_from_stdout_data()
make_packets_from_stdout_data(void)
{
int len;
@ -160,7 +170,7 @@ make_packets_from_stdout_data()
} else {
/* Keep the packets at reasonable size. */
if (len > packet_get_maxsize())
len = packet_get_maxsize();
len = packet_get_maxsize();
}
packet_start(SSH_SMSG_STDOUT_DATA);
packet_put_string(buffer_ptr(&stdout_buffer), len);
@ -177,23 +187,37 @@ make_packets_from_stdout_data()
* for the duration of the wait (0 = infinite).
*/
void
wait_until_can_do_something(fd_set * readset, fd_set * writeset,
unsigned int max_time_milliseconds)
wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
u_int max_time_milliseconds)
{
struct timeval tv, *tvp;
int ret;
int client_alive_scheduled = 0;
/*
* if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
* alive by setting the client_alive_scheduled flag.
*
* this could be randomized somewhat to make traffic
* analysis more difficult, but we're not doing it yet.
*/
if (max_time_milliseconds == 0 && options.client_alive_interval) {
client_alive_scheduled = 1;
max_time_milliseconds = options.client_alive_interval * 1000;
} else
client_alive_scheduled = 0;
/* When select fails we restart from here. */
retry_select:
/* Initialize select() masks. */
FD_ZERO(readset);
FD_ZERO(writeset);
/* Allocate and update select() masks for channel descriptors. */
channel_prepare_select(readsetp, writesetp, maxfdp, 0);
if (compat20) {
/* wrong: bad condition XXX */
if (channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
} else {
/*
* Read packets from the client unless we have too much
@ -201,44 +225,38 @@ retry_select:
*/
if (buffer_len(&stdin_buffer) < buffer_high &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
/*
* If there is not too much data already buffered going to
* the client, try to get some more data from the program.
*/
if (packet_not_very_much_data_to_write()) {
if (!fdout_eof)
FD_SET(fdout, readset);
FD_SET(fdout, *readsetp);
if (!fderr_eof)
FD_SET(fderr, readset);
FD_SET(fderr, *readsetp);
}
/*
* If we have buffered data, try to write some of that data
* to the program.
*/
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
FD_SET(fdin, writeset);
FD_SET(fdin, *writesetp);
}
/* Set masks for channel descriptors. */
channel_prepare_select(readset, writeset);
/*
* If we have buffered packet data going to the client, mark that
* descriptor.
*/
if (packet_have_data_to_write())
FD_SET(connection_out, writeset);
/* Update the maximum descriptor number if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
FD_SET(connection_out, *writesetp);
/*
* If child has terminated and there is enough buffer space to read
* from it, then read as much as is available and exit.
*/
if (child_terminated && packet_not_very_much_data_to_write())
if (max_time_milliseconds == 0)
if (max_time_milliseconds == 0 || client_alive_scheduled)
max_time_milliseconds = 100;
if (max_time_milliseconds == 0)
@ -249,17 +267,41 @@ retry_select:
tvp = &tv;
}
if (tvp!=NULL)
debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
debug3("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
/* Wait for something to happen, or the timeout to expire. */
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret < 0) {
if (ret == -1) {
if (errno != EINTR)
error("select: %.100s", strerror(errno));
else
goto retry_select;
}
if (ret == 0 && client_alive_scheduled) {
/* timeout, check to see how many we have had */
client_alive_timeouts++;
if (client_alive_timeouts > options.client_alive_count_max ) {
packet_disconnect(
"Timeout, your session not responding.");
} else {
/*
* send a bogus channel request with "wantreply"
* we should get back a failure
*/
int id;
id = channel_find_open();
if (id != -1) {
channel_request_start(id,
"keepalive@openssh.com", 1);
packet_send();
} else
packet_disconnect(
"No open channels after timeout!");
}
}
}
/*
@ -277,6 +319,9 @@ process_input(fd_set * readset)
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
verbose("Connection closed by remote host.");
connection_closed = 1;
if (compat20)
return;
fatal_cleanup();
} else if (len < 0) {
if (errno != EINTR && errno != EAGAIN) {
@ -322,6 +367,7 @@ process_input(fd_set * readset)
void
process_output(fd_set * writeset)
{
struct termios tio;
int len;
/* Write buffered data to program stdin. */
@ -341,7 +387,17 @@ process_output(fd_set * writeset)
#endif
fdin = -1;
} else {
/* Successful write. Consume the data from the buffer. */
/* Successful write. */
if (fdin_is_tty && tcgetattr(fdin, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
* Simulate echo to reduce the impact of
* traffic analysis
*/
packet_send_ignore(len);
packet_send();
}
/* Consume the data from the buffer. */
buffer_consume(&stdin_buffer, len);
/* Update the count of bytes written to the program. */
stdin_bytes += len;
@ -357,7 +413,7 @@ process_output(fd_set * writeset)
* This is used when the program terminates.
*/
void
drain_output()
drain_output(void)
{
/* Send any buffered stdout data to the client. */
if (buffer_len(&stdout_buffer) > 0) {
@ -382,9 +438,9 @@ drain_output()
}
void
process_buffered_input_packets()
process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, NULL, NULL);
dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
}
/*
@ -397,13 +453,14 @@ process_buffered_input_packets()
void
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
{
fd_set readset, writeset;
fd_set *readset = NULL, *writeset = NULL;
int max_fd;
int wait_status; /* Status returned by wait(). */
pid_t wait_pid; /* pid returned by wait(). */
int waiting_termination = 0; /* Have displayed waiting close message. */
unsigned int max_time_milliseconds;
unsigned int previous_stdout_buffer_bytes;
unsigned int stdout_buffer_bytes;
u_int max_time_milliseconds;
u_int previous_stdout_buffer_bytes;
u_int stdout_buffer_bytes;
int type;
debug("Entering interactive session.");
@ -425,6 +482,9 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
if (fderr != -1)
set_nonblock(fderr);
if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
fdin_is_tty = 1;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
@ -437,15 +497,11 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
buffer_high = 64 * 1024;
/* Initialize max_fd to the maximum of the known file descriptors. */
max_fd = fdin;
if (fdout > max_fd)
max_fd = fdout;
if (fderr != -1 && fderr > max_fd)
max_fd = fderr;
if (connection_in > max_fd)
max_fd = connection_in;
if (connection_out > max_fd)
max_fd = connection_out;
max_fd = MAX(fdin, fdout);
if (fderr != -1)
max_fd = MAX(max_fd, fderr);
max_fd = MAX(max_fd, connection_in);
max_fd = MAX(max_fd, connection_out);
/* Initialize Initialize buffers. */
buffer_init(&stdin_buffer);
@ -532,18 +588,22 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
}
}
/* Sleep in select() until we can do something. */
wait_until_can_do_something(&readset, &writeset,
max_time_milliseconds);
wait_until_can_do_something(&readset, &writeset, &max_fd,
max_time_milliseconds);
/* Process any channel events. */
channel_after_select(&readset, &writeset);
channel_after_select(readset, writeset);
/* Process input from the client and from program stdout/stderr. */
process_input(&readset);
process_input(readset);
/* Process output to the client and to program stdin. */
process_output(&writeset);
process_output(writeset);
}
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
/* Cleanup and termination code. */
@ -576,7 +636,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* Wait for the child to exit. Get its exit status. */
wait_pid = wait(&wait_status);
if (wait_pid < 0) {
if (wait_pid == -1) {
/*
* It is possible that the wait was handled by SIGCHLD
* handler. This may result in either: this call
@ -634,9 +694,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
void
server_loop2(void)
{
fd_set readset, writeset;
int had_channel = 0;
int status;
fd_set *readset = NULL, *writeset = NULL;
int rekeying = 0, max_fd, status;
pid_t pid;
debug("Entering interactive session for SSH2.");
@ -645,42 +704,61 @@ server_loop2(void)
child_terminated = 0;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
max_fd = connection_in;
if (connection_out > max_fd)
max_fd = connection_out;
max_fd = MAX(connection_in, connection_out);
server_init_dispatch();
for (;;) {
process_buffered_input_packets();
if (!had_channel && channel_still_open())
had_channel = 1;
if (had_channel && !channel_still_open()) {
debug("!channel_still_open.");
break;
}
if (packet_not_very_much_data_to_write())
rekeying = (xxx_kex != NULL && !xxx_kex->done);
if (!rekeying && packet_not_very_much_data_to_write())
channel_output_poll();
wait_until_can_do_something(&readset, &writeset, 0);
wait_until_can_do_something(&readset, &writeset, &max_fd,
rekeying);
if (child_terminated) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status);
child_terminated = 0;
}
channel_after_select(&readset, &writeset);
process_input(&readset);
process_output(&writeset);
if (!rekeying)
channel_after_select(readset, writeset);
process_input(readset);
if (connection_closed)
break;
process_output(writeset);
}
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
signal(SIGCHLD, SIG_DFL);
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status);
channel_stop_listening();
}
void
server_input_channel_failure(int type, int plen, void *ctxt)
{
debug("Got CHANNEL_FAILURE for keepalive");
/*
* reset timeout, since we got a sane answer from the client.
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
client_alive_timeouts = 0;
}
void
server_input_stdin_data(int type, int plen, void *ctxt)
{
char *data;
unsigned int data_len;
u_int data_len;
/* Stdin data from the client. Append it to the buffer. */
/* Ignore any data if the client has closed stdin. */
@ -720,10 +798,10 @@ server_input_window_size(int type, int plen, void *ctxt)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
}
int
input_direct_tcpip(void)
Channel *
server_request_direct_tcpip(char *ctype)
{
int sock;
int sock, newch;
char *target, *originator;
int target_port, originator_port;
@ -733,23 +811,47 @@ input_direct_tcpip(void)
originator_port = packet_get_int();
packet_done();
debug("open direct-tcpip: from %s port %d to %s port %d",
debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
originator, originator_port, target, target_port);
/* XXX check permission */
if (no_port_forwarding_flag || !options.allow_tcp_forwarding) {
xfree(target);
xfree(originator);
return -1;
}
sock = channel_connect_to(target, target_port);
xfree(target);
xfree(originator);
if (sock < 0)
return -1;
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
return NULL;
newch = channel_new(ctype, SSH_CHANNEL_CONNECTING,
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
return (newch >= 0) ? channel_lookup(newch) : NULL;
}
Channel *
server_request_session(char *ctype)
{
int newch;
debug("input_session_request");
packet_done();
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
newch = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
if (session_open(newch) == 1) {
channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST,
session_input_channel_req, (void *)0);
channel_register_cleanup(newch, session_close_by_channel);
return channel_lookup(newch);
} else {
debug("session open failed, free channel %d", newch);
channel_free(newch);
}
return NULL;
}
void
@ -757,8 +859,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
{
Channel *c = NULL;
char *ctype;
int id;
unsigned int len;
u_int len;
int rchan;
int rmaxpack;
int rwindow;
@ -772,34 +873,12 @@ server_input_channel_open(int type, int plen, void *ctxt)
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) {
debug("open session");
packet_done();
/*
* A server session has no fd to read or write
* until a CHANNEL_REQUEST for a shell is made,
* so we set the type to SSH_CHANNEL_LARVAL.
* Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
if (session_open(id) == 1) {
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
session_input_channel_req, (void *)0);
channel_register_cleanup(id, session_close_by_channel);
c = channel_lookup(id);
} else {
debug("session open failed, free channel %d", id);
channel_free(id);
}
c = server_request_session(ctype);
} else if (strcmp(ctype, "direct-tcpip") == 0) {
id = input_direct_tcpip();
if (id >= 0)
c = channel_lookup(id);
c = server_request_direct_tcpip(ctype);
}
if (c != NULL) {
debug("confirm %s", ctype);
debug("server_input_channel_open: confirm %s", ctype);
c->remote_id = rchan;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
@ -811,7 +890,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
packet_put_int(c->local_maxpacket);
packet_send();
} else {
debug("failure %s", ctype);
debug("server_input_channel_open: failure %s", ctype);
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan);
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
@ -823,7 +902,57 @@ server_input_channel_open(int type, int plen, void *ctxt)
}
void
server_init_dispatch_20()
server_input_global_request(int type, int plen, void *ctxt)
{
char *rtype;
int want_reply;
int success = 0;
rtype = packet_get_string(NULL);
want_reply = packet_get_char();
debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
/* -R style forwarding */
if (strcmp(rtype, "tcpip-forward") == 0) {
struct passwd *pw;
char *listen_address;
u_short listen_port;
pw = auth_get_user();
if (pw == NULL)
fatal("server_input_global_request: no user");
listen_address = packet_get_string(NULL); /* XXX currently ignored */
listen_port = (u_short)packet_get_int();
debug("server_input_global_request: tcpip-forward listen %s port %d",
listen_address, listen_port);
/* check permissions */
if (!options.allow_tcp_forwarding ||
no_port_forwarding_flag ||
(listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) {
success = 0;
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_request_forwarding(
listen_address, listen_port,
/*unspec host_to_connect*/ "<unspec host>",
/*unspec port_to_connect*/ 0,
options.gateway_ports, /*remote*/ 1);
}
xfree(listen_address);
}
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
packet_send();
packet_write_wait();
}
xfree(rtype);
}
void
server_init_dispatch_20(void)
{
debug("server_init_dispatch_20");
dispatch_init(&dispatch_protocol_error);
@ -836,9 +965,14 @@ server_init_dispatch_20()
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
/* client_alive */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
server_init_dispatch_13()
server_init_dispatch_13(void)
{
debug("server_init_dispatch_13");
dispatch_init(NULL);
@ -853,7 +987,7 @@ server_init_dispatch_13()
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
}
void
server_init_dispatch_15()
server_init_dispatch_15(void)
{
server_init_dispatch_13();
debug("server_init_dispatch_15");
@ -861,7 +995,7 @@ server_init_dispatch_15()
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
}
void
server_init_dispatch()
server_init_dispatch(void)
{
if (compat20)
server_init_dispatch_20();
@ -870,3 +1004,4 @@ server_init_dispatch()
else
server_init_dispatch_15();
}

View file

@ -0,0 +1,22 @@
/* $OpenBSD: serverloop.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Performs the interactive session. This handles data transmission between
* the client and the program. Note that the notion of stdin, stdout, and
* stderr in this function is sort of reversed: this function writes to stdin
* (of the child program), and reads from stdout and stderr (of the child
* program).
*/
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
void server_loop2(void);

View file

@ -9,7 +9,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -33,28 +33,30 @@
*/
#include "includes.h"
RCSID("$OpenBSD: session.c,v 1.42 2000/10/27 07:32:18 markus Exp $");
RCSID("$OpenBSD: session.c,v 1.74 2001/04/17 19:34:25 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "pty.h"
#include "ssh1.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "sshpty.h"
#include "packet.h"
#include "buffer.h"
#include "mpaux.h"
#include "servconf.h"
#include "uidswap.h"
#include "compat.h"
#include "channels.h"
#include "nchan.h"
#include "bufaux.h"
#include "ssh2.h"
#include "auth.h"
#include "auth-options.h"
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
#endif
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
#include "sshlogin.h"
#include "serverloop.h"
#include "canohost.h"
#include "session.h"
/* types */
@ -63,7 +65,6 @@ typedef struct Session Session;
struct Session {
int used;
int self;
int extended;
struct passwd *pw;
pid_t pid;
/* tty */
@ -79,6 +80,7 @@ struct Session {
int single_connection;
/* proto 2 */
int chanid;
int is_subsystem;
};
/* func */
@ -87,29 +89,30 @@ Session *session_new(void);
void session_set_fds(Session *s, int fdin, int fdout, int fderr);
void session_pty_cleanup(Session *s);
void session_proctitle(Session *s);
void do_exec_pty(Session *s, const char *command, struct passwd * pw);
void do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
void do_exec_pty(Session *s, const char *command);
void do_exec_no_pty(Session *s, const char *command);
void do_login(Session *s, const char *command);
void do_child(Session *s, const char *command);
void do_motd(void);
int check_quietlogin(Session *s, const char *command);
void
do_child(const char *command, struct passwd * pw, const char *term,
const char *display, const char *auth_proto,
const char *auth_data, const char *ttyname);
void do_authenticated1(Authctxt *authctxt);
void do_authenticated2(Authctxt *authctxt);
/* import */
extern ServerOptions options;
extern char *__progname;
extern int log_stderr;
extern int debug_flag;
extern unsigned int utmp_len;
extern u_int utmp_len;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
/* Local Xauthority file. */
static char *xauthfile;
/* original command from peer. */
char *original_command = NULL;
char *original_command = NULL;
/* data */
#define MAX_SESSIONS 10
@ -119,6 +122,40 @@ Session sessions[MAX_SESSIONS];
static login_cap_t *lc;
#endif
void
do_authenticated(Authctxt *authctxt)
{
/*
* Cancel the alarm we set to limit the time taken for
* authentication.
*/
alarm(0);
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
#ifdef HAVE_LOGIN_CAP
if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {
error("unable to get login class");
return;
}
#ifdef BSD_AUTH
if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) {
packet_disconnect("Approval failure for %s",
authctxt->pw->pw_name);
}
#endif
#endif
/* setup the channel layer */
if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
channel_permit_all_opens();
if (compat20)
do_authenticated2(authctxt);
else
do_authenticated1(authctxt);
}
/*
* Remove local Xauthority file.
*/
@ -168,53 +205,23 @@ pty_cleanup_proc(void *session)
* are requested, etc.
*/
void
do_authenticated(struct passwd * pw)
do_authenticated1(Authctxt *authctxt)
{
Session *s;
int type, fd;
int compression_level = 0, enable_compression_after_reply = 0;
int have_pty = 0;
char *command;
int n_bytes;
int plen;
unsigned int proto_len, data_len, dlen;
/*
* Cancel the alarm we set to limit the time taken for
* authentication.
*/
alarm(0);
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
/*
* Inform the channel mechanism that we are the server side and that
* the client may request to connect to any port at all. (The user
* could do it anyway, and we wouldn\'t know what is permitted except
* by the client telling us, so we can equally well trust the client
* not to request anything bogus.)
*/
if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
channel_permit_all_opens();
int success, type, fd, n_bytes, plen, screen_flag, have_pty = 0;
int compression_level = 0, enable_compression_after_reply = 0;
u_int proto_len, data_len, dlen;
s = session_new();
s->pw = pw;
#ifdef HAVE_LOGIN_CAP
if ((lc = login_getclass(pw->pw_class)) == NULL) {
error("unable to get login class");
return;
}
#endif
s->pw = authctxt->pw;
/*
* We stay in this loop until the client requests to execute a shell
* or a command.
*/
for (;;) {
int success = 0;
success = 0;
/* Get a packet from the client. */
type = packet_read(&plen);
@ -251,7 +258,7 @@ do_authenticated(struct passwd * pw)
break;
}
fatal_add_cleanup(pty_cleanup_proc, (void *)s);
pty_setowner(pw, s->tty);
pty_setowner(s->pw, s->tty);
/* Get TERM from the packet. Note that the value may be of arbitrary length. */
s->term = packet_get_string(&dlen);
@ -301,12 +308,23 @@ do_authenticated(struct passwd * pw)
s->auth_proto = packet_get_string(&proto_len);
s->auth_data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
screen_flag = packet_get_protocol_flags() &
SSH_PROTOFLAG_SCREEN_NUMBER;
debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
if (packet_remaining() == 4) {
if (!screen_flag)
debug2("Buggy client: "
"X11 screen flag missing");
packet_integrity_check(plen,
4 + proto_len + 4 + data_len + 4, type);
s->screen = packet_get_int();
else
} else {
packet_integrity_check(plen,
4 + proto_len + 4 + data_len, type);
s->screen = 0;
}
s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
if (s->display == NULL)
@ -315,7 +333,7 @@ do_authenticated(struct passwd * pw)
/* Setup to always have a local .Xauthority. */
xauthfile = xmalloc(MAXPATHLEN);
strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(s->pw);
if (mkdtemp(xauthfile) == NULL) {
restore_uid();
error("private X11 dir: mkdtemp %s failed: %s",
@ -340,7 +358,7 @@ do_authenticated(struct passwd * pw)
break;
}
debug("Received authentication agent forwarding request.");
success = auth_input_request_forwarding(pw);
success = auth_input_request_forwarding(s->pw);
break;
case SSH_CMSG_PORT_FORWARD_REQUEST:
@ -353,7 +371,7 @@ do_authenticated(struct passwd * pw)
break;
}
debug("Received TCP/IP port forwarding request.");
channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);
channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
success = 1;
break;
@ -364,10 +382,6 @@ do_authenticated(struct passwd * pw)
case SSH_CMSG_EXEC_SHELL:
case SSH_CMSG_EXEC_CMD:
/* Set interactive/non-interactive mode. */
packet_set_interactive(have_pty || s->display != NULL,
options.keepalives);
if (type == SSH_CMSG_EXEC_CMD) {
command = packet_get_string(&dlen);
debug("Exec command '%.500s'", command);
@ -382,9 +396,9 @@ do_authenticated(struct passwd * pw)
debug("Forced command '%.500s'", forced_command);
}
if (have_pty)
do_exec_pty(s, command, pw);
do_exec_pty(s, command);
else
do_exec_no_pty(s, command, pw);
do_exec_no_pty(s, command);
if (command != NULL)
xfree(command);
@ -418,7 +432,7 @@ do_authenticated(struct passwd * pw)
* setting up file descriptors and such.
*/
void
do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
do_exec_no_pty(Session *s, const char *command)
{
int pid;
@ -491,12 +505,14 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
#endif /* USE_PIPES */
/* Do processing for the child (exec command etc). */
do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);
do_child(s, command);
/* NOTREACHED */
}
if (pid < 0)
packet_disconnect("fork failed: %.100s", strerror(errno));
s->pid = pid;
/* Set interactive/non-interactive mode. */
packet_set_interactive(s->display != NULL);
#ifdef USE_PIPES
/* We are the parent. Close the child sides of the pipes. */
close(pin[0]);
@ -504,11 +520,11 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
close(perr[1]);
if (compat20) {
session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);
session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
} else {
/* Enter the interactive session. */
server_loop(pid, pin[1], pout[0], perr[0]);
/* server_loop has closed pin[1], pout[1], and perr[1]. */
/* server_loop has closed pin[1], pout[0], and perr[0]. */
}
#else /* USE_PIPES */
/* We are the parent. Close the child sides of the socket pairs. */
@ -520,7 +536,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
* handle the case that fdin and fdout are the same.
*/
if (compat20) {
session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);
session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
} else {
server_loop(pid, inout[1], inout[1], err[1]);
/* server_loop has closed inout[1] and err[1]. */
@ -535,7 +551,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
* lastlog, and other such operations.
*/
void
do_exec_pty(Session *s, const char *command, struct passwd * pw)
do_exec_pty(Session *s, const char *command)
{
int fdout, ptyfd, ttyfd, ptymaster;
pid_t pid;
@ -576,8 +592,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
do_login(s, command);
/* Do common processing for the child, such as execing the command. */
do_child(command, pw, s->term, s->display, s->auth_proto,
s->auth_data, s->tty);
do_child(s, command);
/* NOTREACHED */
}
if (pid < 0)
@ -603,6 +618,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
s->ptymaster = ptymaster;
/* Enter interactive session. */
packet_set_interactive(1);
if (compat20) {
session_set_fds(s, ptyfd, fdout, -1);
} else {
@ -612,28 +628,14 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
}
}
const char *
get_remote_name_or_ip(void)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname();
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
}
/* administrative, login(1)-like work */
void
do_login(Session *s, const char *command)
{
FILE *f;
char *time_string;
char buf[256];
char hostname[MAXHOSTNAMELEN];
socklen_t fromlen;
struct sockaddr_storage from;
struct stat st;
time_t last_login_time;
struct passwd * pw = s->pw;
pid_t pid = getpid();
@ -653,25 +655,21 @@ do_login(Session *s, const char *command)
}
/* Get the time and hostname when the user last logged in. */
hostname[0] = '\0';
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
hostname, sizeof(hostname));
if (options.print_lastlog) {
hostname[0] = '\0';
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
hostname, sizeof(hostname));
}
/* Record that there was a login on that tty from the remote host. */
record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
get_remote_name_or_ip(), (struct sockaddr *)&from);
get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
(struct sockaddr *)&from);
/* Done if .hushlogin exists or a command given. */
if (command != NULL)
if (check_quietlogin(s, command))
return;
snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
#else
if (stat(buf, &st) >= 0)
#endif
return;
if (last_login_time != 0) {
if (options.print_lastlog && last_login_time != 0) {
time_string = ctime(&last_login_time);
if (strchr(time_string, '\n'))
*strchr(time_string, '\n') = 0;
@ -680,6 +678,19 @@ do_login(Session *s, const char *command)
else
printf("Last login: %s from %s\r\n", time_string, hostname);
}
do_motd();
}
/*
* Display the message of the day.
*/
void
do_motd(void)
{
FILE *f;
char buf[256];
if (options.print_motd) {
#ifdef HAVE_LOGIN_CAP
f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
@ -695,15 +706,40 @@ do_login(Session *s, const char *command)
}
}
/*
* Check for quiet login, either .hushlogin or command given.
*/
int
check_quietlogin(Session *s, const char *command)
{
char buf[256];
struct passwd * pw = s->pw;
struct stat st;
/* Return 1 if .hushlogin exists or a command given. */
if (command != NULL)
return 1;
snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
return 1;
#else
if (stat(buf, &st) >= 0)
return 1;
#endif
return 0;
}
/*
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden.
*/
void
child_set_env(char ***envp, unsigned int *envsizep, const char *name,
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
unsigned int i, namelen;
u_int i, namelen;
char **env;
/*
@ -741,7 +777,7 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name,
* and assignments of the form name=value. No other forms are allowed.
*/
void
read_environment_file(char ***env, unsigned int *envsize,
read_environment_file(char ***env, u_int *envsize,
const char *filename)
{
FILE *f;
@ -781,19 +817,22 @@ read_environment_file(char ***env, unsigned int *envsize,
* ids, and executing the command or shell.
*/
void
do_child(const char *command, struct passwd * pw, const char *term,
const char *display, const char *auth_proto,
const char *auth_data, const char *ttyname)
do_child(Session *s, const char *command)
{
const char *shell, *hostname = NULL, *cp = NULL;
struct passwd * pw = s->pw;
char buf[256];
char cmd[1024];
FILE *f = NULL;
unsigned int envsize, i;
u_int envsize, i;
char **env;
extern char **environ;
struct stat st;
char *argv[10];
int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;
/* remove hostkey from the child's memory */
destroy_sensitive_data();
/* login(1) is only called if we execute the login shell */
if (options.use_login && command != NULL)
@ -826,7 +865,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
(LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
perror("unable to set user context");
exit(1);
}
#else
if (setlogin(pw->pw_name) < 0)
@ -843,7 +881,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
endgrent();
/* Permanently switch to the desired uid. */
permanently_set_uid(pw->pw_uid);
permanently_set_uid(pw);
#endif
}
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
@ -916,12 +954,12 @@ do_child(const char *command, struct passwd * pw, const char *term,
get_remote_ipaddr(), get_remote_port(), get_local_port());
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
if (ttyname)
child_set_env(&env, &envsize, "SSH_TTY", ttyname);
if (term)
child_set_env(&env, &envsize, "TERM", term);
if (display)
child_set_env(&env, &envsize, "DISPLAY", display);
if (s->ttyfd != -1)
child_set_env(&env, &envsize, "SSH_TTY", s->tty);
if (s->term)
child_set_env(&env, &envsize, "TERM", s->term);
if (s->display)
child_set_env(&env, &envsize, "DISPLAY", s->display);
if (original_command)
child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
original_command);
@ -955,7 +993,8 @@ do_child(const char *command, struct passwd * pw, const char *term,
}
/* we have to stash the hostname before we close our socket. */
if (options.use_login)
hostname = get_remote_name_or_ip();
hostname = get_remote_name_or_ip(utmp_len,
options.reverse_mapping_check);
/*
* Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important
@ -1012,58 +1051,66 @@ do_child(const char *command, struct passwd * pw, const char *term,
* in this order).
*/
if (!options.use_login) {
if (stat(SSH_USER_RC, &st) >= 0) {
/* ignore _PATH_SSH_USER_RC for subsystems */
if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
if (debug_flag)
fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
f = popen("/bin/sh " SSH_USER_RC, "w");
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
_PATH_SSH_USER_RC);
f = popen(_PATH_BSHELL " " _PATH_SSH_USER_RC, "w");
if (f) {
if (auth_proto != NULL && auth_data != NULL)
fprintf(f, "%s %s\n", auth_proto, auth_data);
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
} else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
fprintf(stderr, "Could not run %s\n",
_PATH_SSH_USER_RC);
} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
if (debug_flag)
fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
_PATH_SSH_SYSTEM_RC);
f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
if (f) {
if (auth_proto != NULL && auth_data != NULL)
fprintf(f, "%s %s\n", auth_proto, auth_data);
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
} else if (options.xauth_location != NULL) {
fprintf(stderr, "Could not run %s\n",
_PATH_SSH_SYSTEM_RC);
} else if (do_xauth && options.xauth_location != NULL) {
/* Add authority data to .Xauthority if appropriate. */
if (auth_proto != NULL && auth_data != NULL) {
char *screen = strchr(display, ':');
if (debug_flag) {
char *screen = strchr(s->display, ':');
if (debug_flag) {
fprintf(stderr,
"Running %.100s add "
"%.100s %.100s %.100s\n",
options.xauth_location, s->display,
s->auth_proto, s->auth_data);
if (screen != NULL)
fprintf(stderr,
"Running %.100s add %.100s %.100s %.100s\n",
options.xauth_location, display,
auth_proto, auth_data);
if (screen != NULL)
fprintf(stderr,
"Adding %.*s/unix%s %s %s\n",
(int)(screen-display), display,
screen, auth_proto, auth_data);
}
snprintf(cmd, sizeof cmd, "%s -q -",
options.xauth_location);
f = popen(cmd, "w");
if (f) {
fprintf(f, "add %s %s %s\n", display,
auth_proto, auth_data);
if (screen != NULL)
fprintf(f, "add %.*s/unix%s %s %s\n",
(int)(screen-display), display,
screen, auth_proto, auth_data);
pclose(f);
} else {
fprintf(stderr, "Could not run %s\n",
cmd);
}
"Adding %.*s/unix%s %s %s\n",
(int)(screen - s->display),
s->display, screen,
s->auth_proto, s->auth_data);
}
snprintf(cmd, sizeof cmd, "%s -q -",
options.xauth_location);
f = popen(cmd, "w");
if (f) {
fprintf(f, "add %s %s %s\n", s->display,
s->auth_proto, s->auth_data);
if (screen != NULL)
fprintf(f, "add %.*s/unix%s %s %s\n",
(int)(screen - s->display),
s->display, screen,
s->auth_proto,
s->auth_data);
pclose(f);
} else {
fprintf(stderr, "Could not run %s\n",
cmd);
}
}
/* Get the last component of the shell name. */
@ -1073,6 +1120,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
else
cp = shell;
}
/* restore SIGPIPE for child */
signal(SIGPIPE, SIG_DFL);
/*
* If we have no command, execute the shell. In this case, the shell
* name to be passed in argv[0] is preceded by '-' to indicate that
@ -1086,9 +1137,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
* Check for mail if we have a tty and it was enabled
* in server options.
*/
if (ttyname && options.check_mail) {
if (s->ttyfd != -1 && options.check_mail) {
char *mailbox;
struct stat mailstat;
mailbox = getenv("MAIL");
if (mailbox != NULL) {
if (stat(mailbox, &mailstat) != 0 ||
@ -1155,19 +1207,11 @@ session_new(void)
for(i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
if (! s->used) {
s->pid = 0;
s->extended = 0;
memset(s, 0, sizeof(*s));
s->chanid = -1;
s->ptyfd = -1;
s->ttyfd = -1;
s->term = NULL;
s->pw = NULL;
s->display = NULL;
s->screen = 0;
s->auth_data = NULL;
s->auth_proto = NULL;
s->used = 1;
s->pw = NULL;
debug("session_new: session %d", i);
return s;
}
@ -1201,7 +1245,7 @@ session_open(int chanid)
}
s->pw = auth_get_user();
if (s->pw == NULL)
fatal("no user for session %i", s->self);
fatal("no user for session %d", s->self);
debug("session_open: session %d: link with channel %d", s->self, chanid);
s->chanid = chanid;
return 1;
@ -1253,8 +1297,8 @@ session_window_change_req(Session *s)
int
session_pty_req(Session *s)
{
unsigned int len;
char *term_modes; /* encoded terminal modes */
u_int len;
int n_bytes;
if (no_pty_flag)
return 0;
@ -1265,8 +1309,6 @@ session_pty_req(Session *s)
s->row = packet_get_int();
s->xpixel = packet_get_int();
s->ypixel = packet_get_int();
term_modes = packet_get_string(&len);
packet_done();
if (strcmp(s->term, "") == 0) {
xfree(s->term);
@ -1279,7 +1321,6 @@ session_pty_req(Session *s)
s->ptyfd = -1;
s->ttyfd = -1;
error("session_pty_req: session %d alloc failed", s->self);
xfree(term_modes);
return 0;
}
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
@ -1292,17 +1333,19 @@ session_pty_req(Session *s)
/* Get window size from the packet. */
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
/* Get tty modes from the packet. */
tty_parse_modes(s->ttyfd, &n_bytes);
packet_done();
session_proctitle(s);
/* XXX parse and set terminal modes */
xfree(term_modes);
return 1;
}
int
session_subsystem_req(Session *s)
{
unsigned int len;
u_int len;
int success = 0;
char *subsys = packet_get_string(&len);
int i;
@ -1313,7 +1356,8 @@ session_subsystem_req(Session *s)
for (i = 0; i < options.num_subsystems; i++) {
if(strcmp(subsys, options.subsystem_name[i]) == 0) {
debug("subsystem: exec() %s", options.subsystem_command[i]);
do_exec_no_pty(s, options.subsystem_command[i], s->pw);
s->is_subsystem = 1;
do_exec_no_pty(s, options.subsystem_command[i]);
success = 1;
}
}
@ -1360,7 +1404,7 @@ session_x11_req(Session *s)
}
xauthfile = xmalloc(MAXPATHLEN);
strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
temporarily_use_uid(s->pw->pw_uid);
temporarily_use_uid(s->pw);
if (mkdtemp(xauthfile) == NULL) {
restore_uid();
error("private X11 dir: mkdtemp %s failed: %s",
@ -1387,18 +1431,17 @@ session_shell_req(Session *s)
/* if forced_command == NULL, the shell is execed */
char *shell = forced_command;
packet_done();
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, shell, s->pw);
do_exec_no_pty(s, shell);
else
do_exec_pty(s, shell, s->pw);
do_exec_pty(s, shell);
return 1;
}
int
session_exec_req(Session *s)
{
unsigned int len;
u_int len;
char *command = packet_get_string(&len);
packet_done();
if (forced_command) {
@ -1406,20 +1449,36 @@ session_exec_req(Session *s)
command = forced_command;
debug("Forced command '%.500s'", forced_command);
}
s->extended = 1;
if (s->ttyfd == -1)
do_exec_no_pty(s, command, s->pw);
do_exec_no_pty(s, command);
else
do_exec_pty(s, command, s->pw);
do_exec_pty(s, command);
if (forced_command == NULL)
xfree(command);
return 1;
}
int
session_auth_agent_req(Session *s)
{
static int called = 0;
packet_done();
if (no_agent_forwarding_flag) {
debug("session_auth_agent_req: no_agent_forwarding_flag");
return 0;
}
if (called) {
return 0;
} else {
called = 1;
return auth_input_request_forwarding(s->pw);
}
}
void
session_input_channel_req(int id, void *arg)
{
unsigned int len;
u_int len;
int reply;
int success = 0;
char *rtype;
@ -1440,8 +1499,8 @@ session_input_channel_req(int id, void *arg)
s->self, id, rtype, reply);
/*
* a session is in LARVAL state until a shell
* or programm is executed
* a session is in LARVAL state until a shell, a command
* or a subsystem is executed
*/
if (c->type == SSH_CHANNEL_LARVAL) {
if (strcmp(rtype, "shell") == 0) {
@ -1452,6 +1511,8 @@ session_input_channel_req(int id, void *arg)
success = session_pty_req(s);
} else if (strcmp(rtype, "x11-req") == 0) {
success = session_x11_req(s);
} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
success = session_auth_agent_req(s);
} else if (strcmp(rtype, "subsystem") == 0) {
success = session_subsystem_req(s);
}
@ -1492,7 +1553,7 @@ session_pty_cleanup(Session *s)
if (s == NULL || s->ttyfd == -1)
return;
debug("session_pty_cleanup: session %i release %s", s->self, s->tty);
debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
/* Cancel the cleanup function. */
fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
@ -1650,26 +1711,9 @@ session_proctitle(Session *s)
}
void
do_authenticated2(void)
do_authenticated2(Authctxt *authctxt)
{
struct passwd *pw;
/*
* Cancel the alarm we set to limit the time taken for
* authentication.
*/
alarm(0);
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
#ifdef HAVE_LOGIN_CAP
pw = auth_get_user();
if ((lc = login_getclass(pw->pw_class)) == NULL) {
error("unable to get login class");
return;
}
#endif
server_loop2();
if (xauthfile)
xauthfile_cleanup_proc(NULL);

View file

@ -1,3 +1,5 @@
/* $OpenBSD: session.h,v 1.6 2001/03/21 11:43:45 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,11 +26,8 @@
#ifndef SESSION_H
#define SESSION_H
/* SSH1 */
void do_authenticated(struct passwd * pw);
void do_authenticated(Authctxt *ac);
/* SSH2 */
void do_authenticated2(void);
int session_open(int id);
void session_input_channel_req(int id, void *arg);
void session_close_by_pid(pid_t pid, int status);

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