mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Say "hi" to the latest in the OpenSSH series, version 2.9!
Happy birthday to: rwatson
This commit is contained in:
parent
5b9b2fafd4
commit
1e8db6e2f6
162 changed files with 16037 additions and 7255 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/..
|
||||
|
||||
CFLAGS+= -Wall
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
31
crypto/openssh/atomicio.h
Normal 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
104
crypto/openssh/auth-chall.c
Normal 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
|
||||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
112
crypto/openssh/auth2-chall.c
Normal file
112
crypto/openssh/auth2-chall.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
38
crypto/openssh/canohost.h
Normal 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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
39
crypto/openssh/clientloop.h
Normal file
39
crypto/openssh/clientloop.h
Normal 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);
|
||||
|
|
@ -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(®, version, 0, NULL, 0);
|
||||
regfree(®);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ++) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
78
crypto/openssh/groupaccess.c
Normal file
78
crypto/openssh/groupaccess.c
Normal 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;
|
||||
}
|
||||
}
|
||||
49
crypto/openssh/groupaccess.h
Normal file
49
crypto/openssh/groupaccess.h
Normal 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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
304
crypto/openssh/kexdh.c
Normal 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
408
crypto/openssh/kexgex.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
75
crypto/openssh/log.h
Normal 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
114
crypto/openssh/mac.c
Normal 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
28
crypto/openssh/mac.h
Normal 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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
130
crypto/openssh/misc.c
Normal 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
30
crypto/openssh/misc.h
Normal 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);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
.\"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
111
crypto/openssh/pathnames.h
Normal 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"
|
||||
|
|
@ -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
28
crypto/openssh/radix.h
Normal 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);
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
20
crypto/openssh/readpass.h
Normal 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);
|
||||
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
98
crypto/openssh/scp-common.c
Normal file
98
crypto/openssh/scp-common.c
Normal 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);
|
||||
}
|
||||
64
crypto/openssh/scp-common.h
Normal file
64
crypto/openssh/scp-common.h
Normal 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);
|
||||
|
|
@ -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 ,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
22
crypto/openssh/serverloop.h
Normal file
22
crypto/openssh/serverloop.h
Normal 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);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue