This commit was generated by cvs2svn to compensate for changes in r57429,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
commit
8e3e42fe07
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=57430
70
crypto/openssh/COPYING.Ylonen
Normal file
70
crypto/openssh/COPYING.Ylonen
Normal file
@ -0,0 +1,70 @@
|
||||
This file is part of the ssh software, Copyright (c) 1995 Tatu Ylonen, Finland
|
||||
|
||||
|
||||
COPYING POLICY AND OTHER LEGAL ISSUES
|
||||
|
||||
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".
|
||||
|
||||
However, I am not implying to give any licenses to any patents or
|
||||
copyrights held by third parties, and the software includes parts that
|
||||
are not under my direct control. As far as I know, all included
|
||||
source code is used in accordance with the relevant license agreements
|
||||
and can be used freely for any purpose (the GNU license being the most
|
||||
restrictive); see below for details.
|
||||
|
||||
[ RSA is no longer included. ]
|
||||
[ IDEA is no longer included. ]
|
||||
[ DES is now external. ]
|
||||
[ GMP is now external. No more GNU licence. ]
|
||||
[ Zlib is now external. ]
|
||||
[ The make-ssh-known-hosts script is no longer included. ]
|
||||
[ TSS has been removed. ]
|
||||
[ MD5 is now external. ]
|
||||
[ RC4 support has been removed. ]
|
||||
[ Blowfish is now external. ]
|
||||
|
||||
The 32-bit CRC implementation in crc32.c is due to Gary S. Brown.
|
||||
Comments in the file indicate it may be used for any purpose without
|
||||
restrictions.
|
||||
|
||||
The 32-bit CRC compensation attack detector in deattack.c was
|
||||
contributed by CORE SDI S.A. under a BSD-style license. See
|
||||
http://www.core-sdi.com/english/ssh/ for details.
|
||||
|
||||
Note that any information and cryptographic algorithms used in this
|
||||
software are publicly available on the Internet and at any major
|
||||
bookstore, scientific library, and patent office worldwide. More
|
||||
information can be found e.g. at "http://www.cs.hut.fi/crypto".
|
||||
|
||||
The legal status of this program is some combination of all these
|
||||
permissions and restrictions. Use only at your own responsibility.
|
||||
You will be responsible for any legal consequences yourself; I am not
|
||||
making any claims whether possessing or using this is legal or not in
|
||||
your country, and I am not taking any responsibility on your behalf.
|
||||
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
13
crypto/openssh/Makefile
Normal file
13
crypto/openssh/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
# $OpenBSD: Makefile,v 1.5 1999/10/25 20:27:26 markus Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp
|
||||
|
||||
distribution:
|
||||
install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \
|
||||
${DESTDIR}/etc/ssh_config
|
||||
install -C -o root -g wheel -m 0644 ${.CURDIR}/sshd_config \
|
||||
${DESTDIR}/etc/sshd_config
|
||||
|
||||
.include <bsd.subdir.mk>
|
11
crypto/openssh/Makefile.inc
Normal file
11
crypto/openssh/Makefile.inc
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS+= -I${.CURDIR}/..
|
||||
|
||||
.include <bsd.obj.mk>
|
||||
|
||||
.if exists(${.CURDIR}/../lib/${__objdir})
|
||||
LDADD+= -L${.CURDIR}/../lib/${__objdir} -lssh
|
||||
DPADD+= ${.CURDIR}/../lib/${__objdir}/libssh.a
|
||||
.else
|
||||
LDADD+= -L${.CURDIR}/../lib -lssh
|
||||
DPADD+= ${.CURDIR}/../lib/libssh.a
|
||||
.endif
|
164
crypto/openssh/OVERVIEW
Normal file
164
crypto/openssh/OVERVIEW
Normal file
@ -0,0 +1,164 @@
|
||||
This document is intended for those who wish to read the ssh source
|
||||
code. This tries to give an overview of the structure of the code.
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>
|
||||
Updated 17 Nov 1995.
|
||||
Updated 19 Oct 1999 for OpenSSH-1.2
|
||||
|
||||
The software consists of ssh (client), sshd (server), scp, sdist, and
|
||||
the auxiliary programs ssh-keygen, ssh-agent, ssh-add, and
|
||||
make-ssh-known-hosts. The main program for each of these is in a .c
|
||||
file with the same name.
|
||||
|
||||
There are some subsystems/abstractions that are used by a number of
|
||||
these programs.
|
||||
|
||||
Buffer manipulation routines
|
||||
|
||||
- These provide an arbitrary size buffer, where data can be appended.
|
||||
Data can be consumed from either end. The code is used heavily
|
||||
throughout ssh. The basic buffer manipulation functions are in
|
||||
buffer.c (header buffer.h), and additional code to manipulate specific
|
||||
data types is in bufaux.c.
|
||||
|
||||
Compression Library
|
||||
|
||||
- Ssh uses the GNU GZIP compression library (ZLIB).
|
||||
|
||||
Encryption/Decryption
|
||||
|
||||
- Ssh contains several encryption algorithms. These are all
|
||||
accessed through the cipher.h interface. The interface code is
|
||||
in cipher.c, and the implementations are in libc.
|
||||
|
||||
Multiple Precision Integer Library
|
||||
|
||||
- Uses the SSLeay BIGNUM sublibrary.
|
||||
- Some auxiliary functions for mp-int manipulation are in mpaux.c.
|
||||
|
||||
Random Numbers
|
||||
|
||||
- Uses arc4random() and such.
|
||||
|
||||
RSA key generation, encryption, decryption
|
||||
|
||||
- Ssh uses the RSA routines in libssl.
|
||||
|
||||
RSA key files
|
||||
|
||||
- RSA keys are stored in files with a special format. The code to
|
||||
read/write these files is in authfile.c. The files are normally
|
||||
encrypted with a passphrase. The functions to read passphrases
|
||||
are in readpass.c (the same code is used to read passwords).
|
||||
|
||||
Binary packet protocol
|
||||
|
||||
- The ssh binary packet protocol is implemented in packet.c. The
|
||||
code in packet.c does not concern itself with packet types or their
|
||||
execution; it contains code to build packets, to receive them and
|
||||
extract data from them, and the code to compress and/or encrypt
|
||||
packets. CRC code comes from crc32.c.
|
||||
|
||||
- The code in packet.c calls the buffer manipulation routines
|
||||
(buffer.c, bufaux.c), compression routines (compress.c, zlib),
|
||||
and the encryption routines.
|
||||
|
||||
X11, TCP/IP, and Agent forwarding
|
||||
|
||||
- Code for various types of channel forwarding is in channels.c.
|
||||
The file defines a generic framework for arbitrary communication
|
||||
channels inside the secure channel, and uses this framework to
|
||||
implement X11 forwarding, TCP/IP forwarding, and authentication
|
||||
agent forwarding.
|
||||
The new, Protocol 1.5, channel close implementation is in nchan.c
|
||||
|
||||
Authentication agent
|
||||
|
||||
- Code to communicate with the authentication agent is in authfd.c.
|
||||
|
||||
Authentication methods
|
||||
|
||||
- Code for various authentication methods resides in auth-*.c
|
||||
(auth-passwd.c, auth-rh-rsa.c, auth-rhosts.c, auth-rsa.c). This
|
||||
code is linked into the server. The routines also manipulate
|
||||
known hosts files using code in hostfile.c. Code in canohost.c
|
||||
is used to retrieve the canonical host name of the remote host.
|
||||
Code in match.c is used to match host names.
|
||||
|
||||
- In the client end, authentication code is in sshconnect.c. It
|
||||
reads Passwords/passphrases using code in readpass.c. It reads
|
||||
RSA key files with authfile.c. It communicates the
|
||||
authentication agent using authfd.c.
|
||||
|
||||
The ssh client
|
||||
|
||||
- The client main program is in ssh.c. It first parses arguments
|
||||
and reads configuration (readconf.c), then calls ssh_connect (in
|
||||
sshconnect.c) to open a connection to the server (possibly via a
|
||||
proxy), and performs authentication (ssh_login in sshconnect.c).
|
||||
It then makes any pty, forwarding, etc. requests. It may call
|
||||
code in ttymodes.c to encode current tty modes. Finally it
|
||||
calls client_loop in clientloop.c. This does the real work for
|
||||
the session.
|
||||
|
||||
- The client is suid root. It tries to temporarily give up this
|
||||
rights while reading the configuration data. The root
|
||||
privileges are only used to make the connection (from a
|
||||
privileged socket). Any extra privileges are dropped before
|
||||
calling ssh_login.
|
||||
|
||||
Pseudo-tty manipulation and tty modes
|
||||
|
||||
- Code to allocate and use a pseudo tty is in pty.c. Code to
|
||||
encode and set terminal modes is in ttymodes.c.
|
||||
|
||||
Logging in (updating utmp, lastlog, etc.)
|
||||
|
||||
- The code to do things that are done when a user logs in are in
|
||||
login.c. This includes things such as updating the utmp, wtmp,
|
||||
and lastlog files. Some of the code is in sshd.c.
|
||||
|
||||
Writing to the system log and terminal
|
||||
|
||||
- The programs use the functions fatal(), log(), debug(), error()
|
||||
in many places to write messages to system log or user's
|
||||
terminal. The implementation that logs to system log is in
|
||||
log-server.c; it is used in the server program. The other
|
||||
programs use an implementation that sends output to stderr; it
|
||||
is in log-client.c. The definitions are in ssh.h.
|
||||
|
||||
The sshd server (daemon)
|
||||
|
||||
- The sshd daemon starts by processing arguments and reading the
|
||||
configuration file (servconf.c). It then reads the host key,
|
||||
starts listening for connections, and generates the server key.
|
||||
The server key will be regenerated every hour by an alarm.
|
||||
|
||||
- When the server receives a connection, it forks, disables the
|
||||
regeneration alarm, and starts communicating with the client.
|
||||
They first perform identification string exchange, then
|
||||
negotiate encryption, then perform authentication, preparatory
|
||||
operations, and finally the server enters the normal session
|
||||
mode by calling server_loop in serverloop.c. This does the real
|
||||
work, calling functions in other modules.
|
||||
|
||||
- The code for the server is in sshd.c. It contains a lot of
|
||||
stuff, including:
|
||||
- server main program
|
||||
- waiting for connections
|
||||
- processing new connection
|
||||
- authentication
|
||||
- preparatory operations
|
||||
- building up the execution environment for the user program
|
||||
- starting the user program.
|
||||
|
||||
Auxiliary files
|
||||
|
||||
- There are several other files in the distribution that contain
|
||||
various auxiliary routines:
|
||||
ssh.h the main header file for ssh (various definitions)
|
||||
getput.h byte-order independent storage of integers
|
||||
includes.h includes most system headers. Lots of #ifdefs.
|
||||
tildexpand.c expand tilde in file names
|
||||
uidswap.c uid-swapping
|
||||
xmalloc.c "safe" malloc routines
|
563
crypto/openssh/README
Normal file
563
crypto/openssh/README
Normal file
@ -0,0 +1,563 @@
|
||||
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.
|
1780
crypto/openssh/RFC.nroff
Normal file
1780
crypto/openssh/RFC.nroff
Normal file
File diff suppressed because it is too large
Load Diff
57
crypto/openssh/atomicio.c
Normal file
57
crypto/openssh/atomicio.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Theo de Raadt
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: atomicio.c,v 1.2 2000/02/01 22:32:53 d Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* ensure all of data on socket comes through. f==read || f==write
|
||||
*/
|
||||
ssize_t
|
||||
atomicio(f, fd, s, n)
|
||||
ssize_t (*f) ();
|
||||
int fd;
|
||||
void *s;
|
||||
size_t n;
|
||||
{
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = (f) (fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (res);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
}
|
348
crypto/openssh/auth-krb4.c
Normal file
348
crypto/openssh/auth-krb4.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
* Kerberos v4 authentication and ticket-passing routines.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#ifdef KRB4
|
||||
char *ticket = NULL;
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
/*
|
||||
* try krb4 authentication,
|
||||
* return 1 on success, 0 on failure, -1 if krb4 is not available
|
||||
*/
|
||||
|
||||
int
|
||||
auth_krb4_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
AUTH_DAT adata;
|
||||
KTEXT_ST tkt;
|
||||
struct hostent *hp;
|
||||
unsigned long faddr;
|
||||
char localhost[MAXHOSTNAMELEN];
|
||||
char phost[INST_SZ];
|
||||
char realm[REALM_SZ];
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Try Kerberos password authentication only for non-root
|
||||
* users and only if Kerberos is installed.
|
||||
*/
|
||||
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
|
||||
|
||||
/* Set up our ticket file. */
|
||||
if (!krb4_init(pw->pw_uid)) {
|
||||
log("Couldn't initialize Kerberos ticket file for %s!",
|
||||
pw->pw_name);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
/* Try to get TGT using our password. */
|
||||
r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
|
||||
realm, "krbtgt", realm,
|
||||
DEFAULT_TKT_LIFE, (char *) password);
|
||||
if (r != INTK_OK) {
|
||||
packet_send_debug("Kerberos V4 password "
|
||||
"authentication for %s failed: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
/* Successful authentication. */
|
||||
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/*
|
||||
* Now that we have a TGT, try to get a local
|
||||
* "rcmd" ticket to ensure that we are not talking
|
||||
* to a bogus Kerberos server.
|
||||
*/
|
||||
(void) gethostname(localhost, sizeof(localhost));
|
||||
(void) strlcpy(phost, (char *) krb_get_phost(localhost),
|
||||
INST_SZ);
|
||||
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
|
||||
|
||||
if (r == KSUCCESS) {
|
||||
if (!(hp = gethostbyname(localhost))) {
|
||||
log("Couldn't get local host address!");
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
memmove((void *) &faddr, (void *) hp->h_addr,
|
||||
sizeof(faddr));
|
||||
|
||||
/* Verify our "rcmd" ticket. */
|
||||
r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
|
||||
faddr, &adata, "");
|
||||
if (r == RD_AP_UNDEC) {
|
||||
/*
|
||||
* Probably didn't have a srvtab on
|
||||
* localhost. Allow login.
|
||||
*/
|
||||
log("Kerberos V4 TGT for %s unverifiable, "
|
||||
"no srvtab installed? krb_rd_req: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
} else if (r != KSUCCESS) {
|
||||
log("Kerberos V4 %s ticket unverifiable: %s",
|
||||
KRB4_SERVICE_NAME, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
} else if (r == KDC_PR_UNKNOWN) {
|
||||
/*
|
||||
* Allow login if no rcmd service exists, but
|
||||
* log the error.
|
||||
*/
|
||||
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
|
||||
"not registered, or srvtab is wrong?", pw->pw_name,
|
||||
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
|
||||
} else {
|
||||
/*
|
||||
* TGT is bad, forget it. Possibly spoofed!
|
||||
*/
|
||||
packet_send_debug("WARNING: Kerberos V4 TGT "
|
||||
"possibly spoofed for %s: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
|
||||
kerberos_auth_failure:
|
||||
krb4_cleanup_proc(NULL);
|
||||
|
||||
if (!options.kerberos_or_local_passwd)
|
||||
return 0;
|
||||
} else {
|
||||
/* Logging in as root or no local Kerberos realm. */
|
||||
packet_send_debug("Unable to authenticate to Kerberos.");
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
krb4_cleanup_proc(void *ignore)
|
||||
{
|
||||
debug("krb4_cleanup_proc called");
|
||||
if (ticket) {
|
||||
(void) dest_tkt();
|
||||
xfree(ticket);
|
||||
ticket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
krb4_init(uid_t uid)
|
||||
{
|
||||
static int cleanup_registered = 0;
|
||||
char *tkt_root = TKT_ROOT;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
if (!ticket) {
|
||||
/* Set unique ticket string manually since we're still root. */
|
||||
ticket = xmalloc(MAXPATHLEN);
|
||||
#ifdef AFS
|
||||
if (lstat("/ticket", &st) != -1)
|
||||
tkt_root = "/ticket/";
|
||||
#endif /* AFS */
|
||||
snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid());
|
||||
(void) krb_set_tkt_string(ticket);
|
||||
}
|
||||
/* Register ticket cleanup in case of fatal error. */
|
||||
if (!cleanup_registered) {
|
||||
fatal_add_cleanup(krb4_cleanup_proc, NULL);
|
||||
cleanup_registered = 1;
|
||||
}
|
||||
/* Try to create our ticket file. */
|
||||
if ((fd = mkstemp(ticket)) != -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
/* Ticket file exists - make sure user owns it (just passed ticket). */
|
||||
if (lstat(ticket, &st) != -1) {
|
||||
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
|
||||
st.st_uid == uid)
|
||||
return 1;
|
||||
}
|
||||
/* Failure - cancel cleanup function, leaving bad ticket for inspection. */
|
||||
log("WARNING: bad ticket file %s", ticket);
|
||||
fatal_remove_cleanup(krb4_cleanup_proc, NULL);
|
||||
cleanup_registered = 0;
|
||||
xfree(ticket);
|
||||
ticket = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
auth_krb4(const char *server_user, KTEXT auth, char **client)
|
||||
{
|
||||
AUTH_DAT adat = {0};
|
||||
KTEXT_ST reply;
|
||||
char instance[INST_SZ];
|
||||
int r, s;
|
||||
u_int cksum;
|
||||
Key_schedule schedule;
|
||||
struct sockaddr_in local, foreign;
|
||||
|
||||
s = packet_get_connection_in();
|
||||
|
||||
r = sizeof(local);
|
||||
memset(&local, 0, sizeof(local));
|
||||
if (getsockname(s, (struct sockaddr *) & local, &r) < 0)
|
||||
debug("getsockname failed: %.100s", strerror(errno));
|
||||
r = sizeof(foreign);
|
||||
memset(&foreign, 0, sizeof(foreign));
|
||||
if (getpeername(s, (struct sockaddr *) & foreign, &r) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
instance[0] = '*';
|
||||
instance[1] = 0;
|
||||
|
||||
/* Get the encrypted request, challenge, and session key. */
|
||||
if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
|
||||
packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
|
||||
return 0;
|
||||
}
|
||||
des_key_sched((des_cblock *) adat.session, schedule);
|
||||
|
||||
*client = xmalloc(MAX_K_NAME_SZ);
|
||||
(void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
|
||||
*adat.pinst ? "." : "", adat.pinst, adat.prealm);
|
||||
|
||||
/* Check ~/.klogin authorization now. */
|
||||
if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
|
||||
packet_send_debug("Kerberos V4 .klogin authorization failed!");
|
||||
log("Kerberos V4 .klogin authorization failed for %s to account %s",
|
||||
*client, server_user);
|
||||
xfree(*client);
|
||||
return 0;
|
||||
}
|
||||
/* Increment the checksum, and return it encrypted with the
|
||||
session key. */
|
||||
cksum = adat.checksum + 1;
|
||||
cksum = htonl(cksum);
|
||||
|
||||
/* If we can't successfully encrypt the checksum, we send back an
|
||||
empty message, admitting our failure. */
|
||||
if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
|
||||
schedule, &adat.session, &local, &foreign)) < 0) {
|
||||
packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
|
||||
reply.dat[0] = 0;
|
||||
reply.length = 0;
|
||||
} else
|
||||
reply.length = r;
|
||||
|
||||
/* Clear session key. */
|
||||
memset(&adat.session, 0, sizeof(&adat.session));
|
||||
|
||||
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
|
||||
packet_put_string((char *) reply.dat, reply.length);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef AFS
|
||||
int
|
||||
auth_kerberos_tgt(struct passwd *pw, const char *string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
|
||||
if (!radix_to_creds(string, &creds)) {
|
||||
log("Protocol error decoding Kerberos V4 tgt");
|
||||
packet_send_debug("Protocol error decoding Kerberos V4 tgt");
|
||||
goto auth_kerberos_tgt_failure;
|
||||
}
|
||||
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
|
||||
strlcpy(creds.service, "krbtgt", sizeof creds.service);
|
||||
|
||||
if (strcmp(creds.service, "krbtgt")) {
|
||||
log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
|
||||
creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
|
||||
pw->pw_name);
|
||||
packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
|
||||
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
|
||||
creds.realm, pw->pw_name);
|
||||
goto auth_kerberos_tgt_failure;
|
||||
}
|
||||
if (!krb4_init(pw->pw_uid))
|
||||
goto auth_kerberos_tgt_failure;
|
||||
|
||||
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
|
||||
goto auth_kerberos_tgt_failure;
|
||||
|
||||
if (save_credentials(creds.service, creds.instance, creds.realm,
|
||||
creds.session, creds.lifetime, creds.kvno,
|
||||
&creds.ticket_st, creds.issue_date) != KSUCCESS) {
|
||||
packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
|
||||
goto auth_kerberos_tgt_failure;
|
||||
}
|
||||
/* Successful authentication, passed all checks. */
|
||||
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
|
||||
|
||||
packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
|
||||
creds.service, creds.instance, creds.realm, creds.pname,
|
||||
creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
|
||||
auth_kerberos_tgt_failure:
|
||||
krb4_cleanup_proc(NULL);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
auth_afs_token(struct passwd *pw, const char *token_string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
uid_t uid = pw->pw_uid;
|
||||
|
||||
if (!radix_to_creds(token_string, &creds)) {
|
||||
log("Protocol error decoding AFS token");
|
||||
packet_send_debug("Protocol error decoding AFS token");
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
|
||||
strlcpy(creds.service, "afs", sizeof creds.service);
|
||||
|
||||
if (strncmp(creds.pname, "AFS ID ", 7) == 0)
|
||||
uid = atoi(creds.pname + 7);
|
||||
|
||||
if (kafs_settoken(creds.realm, uid, &creds)) {
|
||||
log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
|
||||
pw->pw_name);
|
||||
packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
|
||||
creds.realm, pw->pw_name);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
|
||||
creds.realm, creds.pname, creds.realm);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
#endif /* AFS */
|
62
crypto/openssh/auth-passwd.c
Normal file
62
crypto/openssh/auth-passwd.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sat Mar 18 05:11:38 1995 ylo
|
||||
* Password authentication. This file contains the functions to check whether
|
||||
* the password is valid for the user.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-passwd.c,v 1.14 1999/12/29 12:47:46 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/*
|
||||
* Tries to authenticate the user using password. Returns true if
|
||||
* authentication succeeds.
|
||||
*/
|
||||
int
|
||||
auth_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char *encrypted_password;
|
||||
|
||||
/* deny if no user. */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
if (pw->pw_uid == 0 && options.permit_root_login == 2)
|
||||
return 0;
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef SKEY
|
||||
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. */
|
||||
}
|
||||
#endif
|
||||
#ifdef KRB4
|
||||
if (options.kerberos_authentication == 1) {
|
||||
int ret = auth_krb4_password(pw, password);
|
||||
if (ret == 1 || ret == 0)
|
||||
return ret;
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for users with no password. */
|
||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
|
||||
return 1;
|
||||
/* Encrypt the candidate password using the proper salt. */
|
||||
encrypted_password = crypt(password,
|
||||
(pw->pw_passwd[0] && pw->pw_passwd[1]) ? pw->pw_passwd : "xx");
|
||||
|
||||
/* Authentication is accepted if the encrypted passwords are identical. */
|
||||
return (strcmp(encrypted_password, pw->pw_passwd) == 0);
|
||||
}
|
107
crypto/openssh/auth-rh-rsa.c
Normal file
107
crypto/openssh/auth-rh-rsa.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
*
|
||||
* auth-rh-rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun May 7 03:08:06 1995 ylo
|
||||
*
|
||||
* Rhosts or /etc/hosts.equiv authentication combined with RSA host
|
||||
* authentication.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rh-rsa.c,v 1.10 1999/11/24 19:53:43 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "uidswap.h"
|
||||
#include "servconf.h"
|
||||
|
||||
/*
|
||||
* 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,
|
||||
BIGNUM *client_host_key_e, BIGNUM *client_host_key_n)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
const char *canonical_hostname;
|
||||
HostStatus host_status;
|
||||
BIGNUM *ke, *kn;
|
||||
|
||||
debug("Trying rhosts with RSA host authentication for %.100s", client_user);
|
||||
|
||||
/* Check if we would accept it using rhosts authentication. */
|
||||
if (!auth_rhosts(pw, client_user))
|
||||
return 0;
|
||||
|
||||
canonical_hostname = get_canonical_hostname();
|
||||
|
||||
debug("Rhosts RSA authentication: canonical host %.900s",
|
||||
canonical_hostname);
|
||||
|
||||
/* Check if we know the host and its host key. */
|
||||
ke = BN_new();
|
||||
kn = BN_new();
|
||||
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n,
|
||||
ke, kn);
|
||||
|
||||
/* 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);
|
||||
/*
|
||||
* Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
|
||||
* did already check pw->pw_dir, but there is a race XXX
|
||||
*/
|
||||
if (options.strict_modes &&
|
||||
(stat(user_hostfile, &st) == 0) &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
|
||||
pw->pw_name, user_hostfile);
|
||||
} else {
|
||||
/* XXX race between stat and the following open() */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n,
|
||||
ke, kn);
|
||||
restore_uid();
|
||||
}
|
||||
xfree(user_hostfile);
|
||||
}
|
||||
BN_free(ke);
|
||||
BN_free(kn);
|
||||
|
||||
if (host_status != HOST_OK) {
|
||||
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
|
||||
packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
|
||||
return 0;
|
||||
}
|
||||
/* A matching host key was found and is known. */
|
||||
|
||||
/* Perform the challenge-response dialog with the client for the host key. */
|
||||
if (!auth_rsa_challenge_dialog(client_host_key_e, client_host_key_n)) {
|
||||
log("Client on %.800s failed to respond correctly to host authentication.",
|
||||
canonical_hostname);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* We have authenticated the user using .rhosts or /etc/hosts.equiv,
|
||||
* and the host using RSA. We accept the authentication.
|
||||
*/
|
||||
|
||||
verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
|
||||
pw->pw_name, client_user, canonical_hostname);
|
||||
packet_send_debug("Rhosts with RSA host authentication accepted.");
|
||||
return 1;
|
||||
}
|
266
crypto/openssh/auth-rhosts.c
Normal file
266
crypto/openssh/auth-rhosts.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
*
|
||||
* auth-rhosts.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 05:12:18 1995 ylo
|
||||
*
|
||||
* Rhosts authentication. This file contains code to check whether to admit
|
||||
* the login based on rhosts authentication. This file also processes
|
||||
* /etc/hosts.equiv.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rhosts.c,v 1.12 1999/12/27 10:46:11 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "uidswap.h"
|
||||
#include "servconf.h"
|
||||
|
||||
/*
|
||||
* This function processes an rhosts-style file (.rhosts, .shosts, or
|
||||
* /etc/hosts.equiv). This returns true if authentication can be granted
|
||||
* based on the file, and returns zero otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
check_rhosts_file(const char *filename, const char *hostname,
|
||||
const char *ipaddr, const char *client_user,
|
||||
const char *server_user)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[1024]; /* Must not be larger than host, user, dummy below. */
|
||||
|
||||
/* Open the .rhosts file, deny if unreadable */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
/* All three must be at least as big as buf to avoid overflows. */
|
||||
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
|
||||
int negated;
|
||||
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (*cp == '#' || *cp == '\n' || !*cp)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* NO_PLUS is supported at least on OSF/1. We skip it (we
|
||||
* don't ever support the plus syntax).
|
||||
*/
|
||||
if (strncmp(cp, "NO_PLUS", 7) == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* This should be safe because each buffer is as big as the
|
||||
* whole string, and thus cannot be overwritten.
|
||||
*/
|
||||
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
|
||||
case 0:
|
||||
packet_send_debug("Found empty line in %.100s.", filename);
|
||||
continue;
|
||||
case 1:
|
||||
/* Host name only. */
|
||||
strlcpy(userbuf, server_user, sizeof(userbuf));
|
||||
break;
|
||||
case 2:
|
||||
/* Got both host and user name. */
|
||||
break;
|
||||
case 3:
|
||||
packet_send_debug("Found garbage in %.100s.", filename);
|
||||
continue;
|
||||
default:
|
||||
/* Weird... */
|
||||
continue;
|
||||
}
|
||||
|
||||
host = hostbuf;
|
||||
user = userbuf;
|
||||
negated = 0;
|
||||
|
||||
/* Process negated host names, or positive netgroups. */
|
||||
if (host[0] == '-') {
|
||||
negated = 1;
|
||||
host++;
|
||||
} else if (host[0] == '+')
|
||||
host++;
|
||||
|
||||
if (user[0] == '-') {
|
||||
negated = 1;
|
||||
user++;
|
||||
} else if (user[0] == '+')
|
||||
user++;
|
||||
|
||||
/* Check for empty host/user names (particularly '+'). */
|
||||
if (!host[0] || !user[0]) {
|
||||
/* We come here if either was '+' or '-'. */
|
||||
packet_send_debug("Ignoring wild host/user names in %.100s.",
|
||||
filename);
|
||||
continue;
|
||||
}
|
||||
/* Verify that host name matches. */
|
||||
if (host[0] == '@') {
|
||||
if (!innetgr(host + 1, hostname, NULL, NULL) &&
|
||||
!innetgr(host + 1, ipaddr, NULL, NULL))
|
||||
continue;
|
||||
} else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
|
||||
continue; /* Different hostname. */
|
||||
|
||||
/* Verify that user name matches. */
|
||||
if (user[0] == '@') {
|
||||
if (!innetgr(user + 1, NULL, client_user, NULL))
|
||||
continue;
|
||||
} else if (strcmp(user, client_user) != 0)
|
||||
continue; /* Different username. */
|
||||
|
||||
/* Found the user and host. */
|
||||
fclose(f);
|
||||
|
||||
/* If the entry was negated, deny access. */
|
||||
if (negated) {
|
||||
packet_send_debug("Matched negative entry in %.100s.",
|
||||
filename);
|
||||
return 0;
|
||||
}
|
||||
/* Accept authentication. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Authentication using this file denied. */
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to authenticate the user using the .shosts or .rhosts file. Returns
|
||||
* true if authentication succeeds. If ignore_rhosts is true, only
|
||||
* /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
|
||||
*/
|
||||
|
||||
int
|
||||
auth_rhosts(struct passwd *pw, const char *client_user)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char buf[1024];
|
||||
const char *hostname, *ipaddr;
|
||||
struct stat st;
|
||||
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
|
||||
unsigned int rhosts_file_index;
|
||||
|
||||
/* Switch to the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
/*
|
||||
* Quick check: if the user has no .shosts or .rhosts files, return
|
||||
* failure immediately without doing costly lookups from name
|
||||
* servers.
|
||||
*/
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++) {
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) >= 0)
|
||||
break;
|
||||
}
|
||||
/* Switch back to privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
/* 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)
|
||||
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,
|
||||
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,
|
||||
pw->pw_name)) {
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
|
||||
hostname, ipaddr, SSH_HOSTS_EQUIV);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check that the home directory is owned by root or the user, and is
|
||||
* not group or world writable.
|
||||
*/
|
||||
if (stat(pw->pw_dir, &st) < 0) {
|
||||
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
packet_send_debug("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
return 0;
|
||||
}
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* Check all .rhosts files (currently .shosts and .rhosts). */
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++) {
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make sure that the file is either owned by the user or by
|
||||
* root, and make sure it is not writable by anyone but the
|
||||
* owner. This is to help avoid novices accidentally
|
||||
* allowing access to their account by anyone.
|
||||
*/
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts authentication refused for %.100s: bad modes for %.200s",
|
||||
pw->pw_name, buf);
|
||||
packet_send_debug("Bad file modes for %.200s", buf);
|
||||
continue;
|
||||
}
|
||||
/* Check if we have been configured to ignore .rhosts and .shosts files. */
|
||||
if (options.ignore_rhosts) {
|
||||
packet_send_debug("Server has been configured to ignore %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
continue;
|
||||
}
|
||||
/* Check if authentication is permitted by the file. */
|
||||
if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
|
||||
packet_send_debug("Accepted by %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
477
crypto/openssh/auth-rsa.c
Normal file
477
crypto/openssh/auth-rsa.c
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
*
|
||||
* auth-rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 27 01:46:52 1995 ylo
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rsa.c,v 1.18 2000/02/11 10:59:11 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "mpaux.h"
|
||||
#include "uidswap.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#include <ssl/rsa.h>
|
||||
#include <ssl/md5.h>
|
||||
|
||||
/* Flags that may be set in authorized_keys options. */
|
||||
extern int no_port_forwarding_flag;
|
||||
extern int no_agent_forwarding_flag;
|
||||
extern int no_x11_forwarding_flag;
|
||||
extern int no_pty_flag;
|
||||
extern char *forced_command;
|
||||
extern struct envstring *custom_environment;
|
||||
|
||||
/*
|
||||
* Session identifier that is used to bind key exchange and authentication
|
||||
* responses to a particular session.
|
||||
*/
|
||||
extern unsigned char session_id[16];
|
||||
|
||||
/*
|
||||
* The .ssh/authorized_keys file contains public keys, one per line, in the
|
||||
* following format:
|
||||
* options bits e n comment
|
||||
* where bits, e and n are decimal numbers,
|
||||
* and comment is any string of characters up to newline. The maximum
|
||||
* length of a line is 8000 characters. See the documentation for a
|
||||
* description of the options.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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(BIGNUM *e, BIGNUM *n)
|
||||
{
|
||||
BIGNUM *challenge, *encrypted_challenge;
|
||||
RSA *pk;
|
||||
BN_CTX *ctx;
|
||||
unsigned char buf[32], mdbuf[16], response[16];
|
||||
MD5_CTX md;
|
||||
unsigned int i;
|
||||
int plen, len;
|
||||
|
||||
encrypted_challenge = BN_new();
|
||||
challenge = BN_new();
|
||||
|
||||
/* Generate a random challenge. */
|
||||
BN_rand(challenge, 256, 0, 0);
|
||||
ctx = BN_CTX_new();
|
||||
BN_mod(challenge, challenge, n, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
/* Create the public key data structure. */
|
||||
pk = RSA_new();
|
||||
pk->e = BN_new();
|
||||
BN_copy(pk->e, e);
|
||||
pk->n = BN_new();
|
||||
BN_copy(pk->n, n);
|
||||
|
||||
/* Encrypt the challenge with the public key. */
|
||||
rsa_public_encrypt(encrypted_challenge, challenge, pk);
|
||||
RSA_free(pk);
|
||||
|
||||
/* Send the encrypted challenge to the client. */
|
||||
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
|
||||
packet_put_bignum(encrypted_challenge);
|
||||
packet_send();
|
||||
BN_clear_free(encrypted_challenge);
|
||||
packet_write_wait();
|
||||
|
||||
/* Wait for a response. */
|
||||
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = packet_get_char();
|
||||
|
||||
/* The response is MD5 of decrypted challenge plus session id. */
|
||||
len = BN_num_bytes(challenge);
|
||||
if (len <= 0 || len > 32)
|
||||
fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
|
||||
memset(buf, 0, 32);
|
||||
BN_bn2bin(challenge, buf + 32 - len);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, 32);
|
||||
MD5_Update(&md, session_id, 16);
|
||||
MD5_Final(mdbuf, &md);
|
||||
BN_clear_free(challenge);
|
||||
|
||||
/* Verify that the response is the original challenge. */
|
||||
if (memcmp(response, mdbuf, 16) != 0) {
|
||||
/* Wrong answer. */
|
||||
return 0;
|
||||
}
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char line[8192], file[1024];
|
||||
int authenticated;
|
||||
unsigned int bits;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
struct stat st;
|
||||
BIGNUM *e, *n;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
SSH_USER_PERMITTED_KEYS);
|
||||
|
||||
/* Fail quietly if file does not exist */
|
||||
if (stat(file, &st) < 0) {
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
/* Open the file containing the authorized keys. */
|
||||
f = fopen(file, "r");
|
||||
if (!f) {
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
packet_send_debug("Could not open %.900s for reading.", file);
|
||||
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes) {
|
||||
int fail = 0;
|
||||
char buf[1024];
|
||||
/* Check open file in order to avoid open/stat races */
|
||||
if (fstat(fileno(f), &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.", pw->pw_name, file);
|
||||
fail = 1;
|
||||
} else {
|
||||
/* Check path to SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; i++) {
|
||||
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
|
||||
if (stat(line, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.", pw->pw_name, line);
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
log(buf);
|
||||
packet_send_debug(buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Flag indicating whether authentication has succeeded. */
|
||||
authenticated = 0;
|
||||
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
|
||||
/*
|
||||
* Go though the accepted keys, looking for the current key. If
|
||||
* found, perform a challenge-response dialog to verify that the
|
||||
* user really has the corresponding private key.
|
||||
*/
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *cp;
|
||||
char *options;
|
||||
|
||||
linenum++;
|
||||
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check if there are options for this key, and if so,
|
||||
* save their starting address and skip the option part
|
||||
* for now. If there are no options, set the starting
|
||||
* address to NULL.
|
||||
*/
|
||||
if (*cp < '0' || *cp > '9') {
|
||||
int quoted = 0;
|
||||
options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
} else
|
||||
options = NULL;
|
||||
|
||||
/* Parse the key from the line. */
|
||||
if (!auth_rsa_read_key(&cp, &bits, e, n)) {
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
/* cp now points to the comment part. */
|
||||
|
||||
/* Check if the we have found the desired key (identified by its modulus). */
|
||||
if (BN_cmp(n, client_n) != 0)
|
||||
continue;
|
||||
|
||||
/* check the real bits */
|
||||
if (bits != BN_num_bits(n))
|
||||
log("Warning: %s, line %ld: keysize mismatch: "
|
||||
"actual %d vs. announced %d.",
|
||||
file, linenum, BN_num_bits(n), bits);
|
||||
|
||||
/* We have found the desired key. */
|
||||
|
||||
/* Perform the challenge-response dialog for this key. */
|
||||
if (!auth_rsa_challenge_dialog(e, n)) {
|
||||
/* Wrong response. */
|
||||
verbose("Wrong response to RSA authentication challenge.");
|
||||
packet_send_debug("Wrong response to RSA authentication challenge.");
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Correct response. The client has been successfully
|
||||
* authenticated. Note that we have not yet processed the
|
||||
* options; this will be reset if the options cause the
|
||||
* authentication to be rejected.
|
||||
*/
|
||||
authenticated = 1;
|
||||
|
||||
/* RSA part of authentication was accepted. Now process the options. */
|
||||
if (options) {
|
||||
while (*options && *options != ' ' && *options != '\t') {
|
||||
cp = "no-port-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Port forwarding disabled.");
|
||||
no_port_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-agent-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Agent forwarding disabled.");
|
||||
no_agent_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-X11-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("X11 forwarding disabled.");
|
||||
no_x11_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-pty";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Pty allocation disabled.");
|
||||
no_pty_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "command=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
forced_command = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
forced_command[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
forced_command[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
forced_command[i] = 0;
|
||||
packet_send_debug("Forced command: %.900s", forced_command);
|
||||
options++;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "environment=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
int i;
|
||||
char *s;
|
||||
struct envstring *new_envstring;
|
||||
options += strlen(cp);
|
||||
s = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
s[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
s[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
s[i] = 0;
|
||||
packet_send_debug("Adding to environment: %.900s", s);
|
||||
debug("Adding to environment: %.900s", s);
|
||||
options++;
|
||||
new_envstring = xmalloc(sizeof(struct envstring));
|
||||
new_envstring->s = s;
|
||||
new_envstring->next = custom_environment;
|
||||
custom_environment = new_envstring;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "from=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
char *patterns = xmalloc(strlen(options) + 1);
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
patterns[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
patterns[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
patterns[i] = 0;
|
||||
options++;
|
||||
if (!match_hostname(get_canonical_hostname(), patterns,
|
||||
strlen(patterns)) &&
|
||||
!match_hostname(get_remote_ipaddr(), patterns,
|
||||
strlen(patterns))) {
|
||||
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
|
||||
pw->pw_name, get_canonical_hostname(),
|
||||
get_remote_ipaddr());
|
||||
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
|
||||
get_canonical_hostname());
|
||||
xfree(patterns);
|
||||
/* key invalid for this host, reset flags */
|
||||
authenticated = 0;
|
||||
no_agent_forwarding_flag = 0;
|
||||
no_port_forwarding_flag = 0;
|
||||
no_pty_flag = 0;
|
||||
no_x11_forwarding_flag = 0;
|
||||
while (custom_environment) {
|
||||
struct envstring *ce = custom_environment;
|
||||
custom_environment = ce->next;
|
||||
xfree(ce->s);
|
||||
xfree(ce);
|
||||
}
|
||||
if (forced_command) {
|
||||
xfree(forced_command);
|
||||
forced_command = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
xfree(patterns);
|
||||
/* Host name matches. */
|
||||
goto next_option;
|
||||
}
|
||||
bad_option:
|
||||
log("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
authenticated = 0;
|
||||
break;
|
||||
|
||||
next_option:
|
||||
/*
|
||||
* Skip the comma, and move to the next option
|
||||
* (or break out if there are no more).
|
||||
*/
|
||||
if (!*options)
|
||||
fatal("Bugs in auth-rsa.c option processing.");
|
||||
if (*options == ' ' || *options == '\t')
|
||||
break; /* End of options. */
|
||||
if (*options != ',')
|
||||
goto bad_option;
|
||||
options++;
|
||||
/* Process the next option. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Break out of the loop if authentication was successful;
|
||||
* otherwise continue searching.
|
||||
*/
|
||||
if (authenticated)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
|
||||
BN_clear_free(n);
|
||||
BN_clear_free(e);
|
||||
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
}
|
181
crypto/openssh/auth-skey.c
Normal file
181
crypto/openssh/auth-skey.c
Normal file
@ -0,0 +1,181 @@
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-skey.c,v 1.5 1999/12/06 19:04:57 deraadt Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include <sha1.h>
|
||||
|
||||
/*
|
||||
* try skey authentication,
|
||||
* return 1 on success, 0 on failure, -1 if skey is not available
|
||||
*/
|
||||
|
||||
int
|
||||
auth_skey_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
if (strncasecmp(password, "s/key", 5) == 0) {
|
||||
char *skeyinfo = skey_keyinfo(pw->pw_name);
|
||||
if (skeyinfo == NULL) {
|
||||
debug("generating fake skeyinfo for %.100s.",
|
||||
pw->pw_name);
|
||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
}
|
||||
if (skeyinfo != NULL)
|
||||
packet_send_debug(skeyinfo);
|
||||
/* Try again. */
|
||||
return 0;
|
||||
} else if (skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, (char *) password) != -1) {
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
|
||||
|
||||
#define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \
|
||||
((x)[3]))
|
||||
|
||||
/*
|
||||
* hash_collapse()
|
||||
*/
|
||||
static u_int32_t
|
||||
hash_collapse(s)
|
||||
u_char *s;
|
||||
{
|
||||
int len, target;
|
||||
u_int32_t i;
|
||||
|
||||
if ((strlen(s) % sizeof(u_int32_t)) == 0)
|
||||
target = strlen(s); /* Multiple of 4 */
|
||||
else
|
||||
target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
|
||||
|
||||
for (i = 0, len = 0; len < target; len += 4)
|
||||
i ^= ROUND(s + len);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
char *
|
||||
skey_fake_keyinfo(char *username)
|
||||
{
|
||||
int i;
|
||||
u_int ptr;
|
||||
u_char hseed[SKEY_MAX_SEED_LEN], flg = 1, *up;
|
||||
char pbuf[SKEY_MAX_PW_LEN+1];
|
||||
static char skeyprompt[SKEY_MAX_CHALLENGE+1];
|
||||
char *secret = NULL;
|
||||
size_t secretlen = 0;
|
||||
SHA1_CTX ctx;
|
||||
char *p, *u;
|
||||
|
||||
/*
|
||||
* Base first 4 chars of seed on hostname.
|
||||
* Add some filler for short hostnames if necessary.
|
||||
*/
|
||||
if (gethostname(pbuf, sizeof(pbuf)) == -1)
|
||||
*(p = pbuf) = '.';
|
||||
else
|
||||
for (p = pbuf; *p && isalnum(*p); p++)
|
||||
if (isalpha(*p) && isupper(*p))
|
||||
*p = tolower(*p);
|
||||
if (*p && pbuf - p < 4)
|
||||
(void)strncpy(p, "asjd", 4 - (pbuf - p));
|
||||
pbuf[4] = '\0';
|
||||
|
||||
/* Hash the username if possible */
|
||||
if ((up = SHA1Data(username, strlen(username), NULL)) != NULL) {
|
||||
struct stat sb;
|
||||
time_t t;
|
||||
int fd;
|
||||
|
||||
/* Collapse the hash */
|
||||
ptr = hash_collapse(up);
|
||||
memset(up, 0, strlen(up));
|
||||
|
||||
/* See if the random file's there, else use ctime */
|
||||
if ((fd = open(_SKEY_RAND_FILE_PATH_, O_RDONLY)) != -1
|
||||
&& fstat(fd, &sb) == 0 &&
|
||||
sb.st_size > (off_t)SKEY_MAX_SEED_LEN &&
|
||||
lseek(fd, ptr % (sb.st_size - SKEY_MAX_SEED_LEN),
|
||||
SEEK_SET) != -1 && read(fd, hseed,
|
||||
SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
secret = hseed;
|
||||
secretlen = SKEY_MAX_SEED_LEN;
|
||||
flg = 0;
|
||||
} else if (!stat(_PATH_MEM, &sb) || !stat("/", &sb)) {
|
||||
t = sb.st_ctime;
|
||||
secret = ctime(&t);
|
||||
secretlen = strlen(secret);
|
||||
flg = 0;
|
||||
}
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Put that in your pipe and smoke it */
|
||||
if (flg == 0) {
|
||||
/* Hash secret value with username */
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, secret, secretlen);
|
||||
SHA1Update(&ctx, username, strlen(username));
|
||||
SHA1End(&ctx, up);
|
||||
|
||||
/* Zero out */
|
||||
memset(secret, 0, secretlen);
|
||||
|
||||
/* Now hash the hash */
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, up, strlen(up));
|
||||
SHA1End(&ctx, up);
|
||||
|
||||
ptr = hash_collapse(up + 4);
|
||||
|
||||
for (i = 4; i < 9; i++) {
|
||||
pbuf[i] = (ptr % 10) + '0';
|
||||
ptr /= 10;
|
||||
}
|
||||
pbuf[i] = '\0';
|
||||
|
||||
/* Sequence number */
|
||||
ptr = ((up[2] + up[3]) % 99) + 1;
|
||||
|
||||
memset(up, 0, 20); /* SHA1 specific */
|
||||
free(up);
|
||||
|
||||
(void)snprintf(skeyprompt, sizeof skeyprompt,
|
||||
"otp-%.*s %d %.*s",
|
||||
SKEY_MAX_HASHNAME_LEN,
|
||||
skey_get_algorithm(),
|
||||
ptr, SKEY_MAX_SEED_LEN,
|
||||
pbuf);
|
||||
} else {
|
||||
/* Base last 8 chars of seed on username */
|
||||
u = username;
|
||||
i = 8;
|
||||
p = &pbuf[4];
|
||||
do {
|
||||
if (*u == 0) {
|
||||
/* Pad remainder with zeros */
|
||||
while (--i >= 0)
|
||||
*p++ = '0';
|
||||
break;
|
||||
}
|
||||
|
||||
*p++ = (*u++ % 10) + '0';
|
||||
} while (--i != 0);
|
||||
pbuf[12] = '\0';
|
||||
|
||||
(void)snprintf(skeyprompt, sizeof skeyprompt,
|
||||
"otp-%.*s %d %.*s",
|
||||
SKEY_MAX_HASHNAME_LEN,
|
||||
skey_get_algorithm(),
|
||||
99, SKEY_MAX_SEED_LEN, pbuf);
|
||||
}
|
||||
return skeyprompt;
|
||||
}
|
578
crypto/openssh/authfd.c
Normal file
578
crypto/openssh/authfd.c
Normal file
@ -0,0 +1,578 @@
|
||||
/*
|
||||
*
|
||||
* authfd.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 01:30:28 1995 ylo
|
||||
*
|
||||
* Functions for connecting the local authentication agent.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "authfd.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <ssl/rsa.h>
|
||||
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
|
||||
int
|
||||
ssh_get_authentication_socket()
|
||||
{
|
||||
const char *authsocket;
|
||||
int sock;
|
||||
struct sockaddr_un sunaddr;
|
||||
|
||||
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
|
||||
if (!authsocket)
|
||||
return -1;
|
||||
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
/* close on exec */
|
||||
if (fcntl(sock, F_SETFD, 1) == -1) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the agent socket if it should be closed (depends on how it was
|
||||
* obtained). The argument must have been returned by
|
||||
* ssh_get_authentication_socket().
|
||||
*/
|
||||
|
||||
void
|
||||
ssh_close_authentication_socket(int sock)
|
||||
{
|
||||
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
|
||||
close(sock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens and connects a private socket for communication with the
|
||||
* authentication agent. Returns the file descriptor (which must be
|
||||
* shut down and closed by the caller when no longer needed).
|
||||
* Returns NULL if an error occurred and the connection could not be
|
||||
* opened.
|
||||
*/
|
||||
|
||||
AuthenticationConnection *
|
||||
ssh_get_authentication_connection()
|
||||
{
|
||||
AuthenticationConnection *auth;
|
||||
int sock;
|
||||
|
||||
sock = ssh_get_authentication_socket();
|
||||
|
||||
/*
|
||||
* Fail if we couldn't obtain a connection. This happens if we
|
||||
* exited due to a timeout.
|
||||
*/
|
||||
if (sock < 0)
|
||||
return NULL;
|
||||
|
||||
auth = xmalloc(sizeof(*auth));
|
||||
auth->fd = sock;
|
||||
buffer_init(&auth->packet);
|
||||
buffer_init(&auth->identities);
|
||||
auth->howmany = 0;
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the connection to the authentication agent and frees any associated
|
||||
* memory.
|
||||
*/
|
||||
|
||||
void
|
||||
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||
{
|
||||
buffer_free(&ac->packet);
|
||||
buffer_free(&ac->identities);
|
||||
close(ac->fd);
|
||||
xfree(ac);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent.
|
||||
* Returns true if an identity is available, 0 otherwise.
|
||||
* The caller must initialize the integers before the call, and free the
|
||||
* comment after a successful call (before calling ssh_get_next_identity).
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, char **comment)
|
||||
{
|
||||
unsigned char msg[8192];
|
||||
int len, l;
|
||||
|
||||
/*
|
||||
* Send a message to the agent requesting for a list of the
|
||||
* identities it can represent.
|
||||
*/
|
||||
msg[0] = 0;
|
||||
msg[1] = 0;
|
||||
msg[2] = 0;
|
||||
msg[3] = 1;
|
||||
msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
if (atomicio(write, auth->fd, msg, 5) != 5) {
|
||||
error("write auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
/* Read the length of the response. XXX implement timeouts here. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, msg + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("read auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the length, and check it for sanity. (We cannot trust
|
||||
* authentication agents).
|
||||
*/
|
||||
len = GET_32BIT(msg);
|
||||
if (len < 1 || len > 256 * 1024)
|
||||
fatal("Authentication reply message too long: %d\n", len);
|
||||
|
||||
/* Read the packet itself. */
|
||||
buffer_clear(&auth->identities);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(msg))
|
||||
l = sizeof(msg);
|
||||
l = read(auth->fd, msg, l);
|
||||
if (l <= 0)
|
||||
fatal("Incomplete authentication reply.");
|
||||
buffer_append(&auth->identities, (char *) msg, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
buffer_get(&auth->identities, (char *) msg, 1);
|
||||
if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
|
||||
fatal("Bad authentication reply message type: %d", msg[0]);
|
||||
|
||||
/* 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", auth->howmany);
|
||||
|
||||
/* Return the first entry (if any). */
|
||||
return ssh_get_next_identity(auth, e, n, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the next authentication identity for the agent. Other functions
|
||||
* can be called between this and ssh_get_first_identity or two calls of this
|
||||
* function. This returns 0 if there are no more identities. The caller
|
||||
* must free comment after a successful return.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, char **comment)
|
||||
{
|
||||
unsigned int bits;
|
||||
|
||||
/* Return failure if no more entries. */
|
||||
if (auth->howmany <= 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Get the next entry from the packet. These will abort with a fatal
|
||||
* error if the packet is too short or contains corrupt data.
|
||||
*/
|
||||
bits = buffer_get_int(&auth->identities);
|
||||
buffer_get_bignum(&auth->identities, e);
|
||||
buffer_get_bignum(&auth->identities, n);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: identity keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(n), bits);
|
||||
|
||||
/* Decrement the number of remaining entries. */
|
||||
auth->howmany--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a random challenge, sends it to the agent, and waits for
|
||||
* response from the agent. Returns true (non-zero) if the agent gave the
|
||||
* correct answer, zero otherwise. Response type selects the style of
|
||||
* response desired, with 0 corresponding to protocol version 1.0 (no longer
|
||||
* supported) and 1 corresponding to protocol version 1.1.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16])
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, i;
|
||||
|
||||
/* Response type 0 is no longer supported. */
|
||||
if (response_type == 0)
|
||||
fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buf[0] = SSH_AGENTC_RSA_CHALLENGE;
|
||||
buffer_init(&buffer);
|
||||
buffer_append(&buffer, (char *) buf, 1);
|
||||
buffer_put_int(&buffer, BN_num_bits(n));
|
||||
buffer_put_bignum(&buffer, e);
|
||||
buffer_put_bignum(&buffer, n);
|
||||
buffer_put_bignum(&buffer, challenge);
|
||||
buffer_append(&buffer, (char *) session_id, 16);
|
||||
buffer_put_int(&buffer, response_type);
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (atomicio(write, auth->fd, buf, 4) != 4 ||
|
||||
atomicio(write, auth->fd, buffer_ptr(&buffer),
|
||||
buffer_len(&buffer)) != buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Wait for response from the agent. First read the length of the
|
||||
* response packet.
|
||||
*/
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Authentication response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
buffer_get(&buffer, (char *) buf, 1);
|
||||
|
||||
/* Check for agent failure message. */
|
||||
if (buf[0] == SSH_AGENT_FAILURE) {
|
||||
log("Agent admitted failure to authenticate using the key.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
/* Now it must be an authentication response packet. */
|
||||
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
||||
fatal("Bad authentication response: %d", buf[0]);
|
||||
|
||||
/*
|
||||
* Get the response from the packet. This will abort with a fatal
|
||||
* error if the packet is corrupt.
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = buffer_get_char(&buffer);
|
||||
|
||||
/* The buffer containing the packet is no longer needed. */
|
||||
buffer_free(&buffer);
|
||||
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an identity to the authentication server. This call is not meant to
|
||||
* be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection *auth,
|
||||
RSA * key, const char *comment)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
/* To keep within the protocol: p < q for ssh. in SSL p > q */
|
||||
buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
|
||||
buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
|
||||
buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
|
||||
buffer_put_string(&buffer, comment, strlen(comment));
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (atomicio(write, auth->fd, buf, 4) != 4 ||
|
||||
atomicio(write, auth->fd, buffer_ptr(&buffer),
|
||||
buffer_len(&buffer)) != buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Add identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to add identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an identity from the authentication server. This call is not
|
||||
* meant to be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (atomicio(write, auth->fd, buf, 4) != 4 ||
|
||||
atomicio(write, auth->fd, buffer_ptr(&buffer),
|
||||
buffer_len(&buffer)) != buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Wait for response from the agent. First read the length of the
|
||||
* response packet.
|
||||
*/
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes all identities from the agent. This call is not meant to be used
|
||||
* by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
PUT_32BIT(buf, 1);
|
||||
buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (atomicio(write, auth->fd, buf, 5) != 5) {
|
||||
error("Error writing to authentication socket.");
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Wait for response from the agent. First read the length of the
|
||||
* response packet.
|
||||
*/
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response into the buffer. */
|
||||
buffer_init(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
119
crypto/openssh/authfd.h
Normal file
119
crypto/openssh/authfd.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
*
|
||||
* authfd.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 01:17:41 1995 ylo
|
||||
*
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: authfd.h,v 1.6 1999/11/24 19:53:44 markus Exp $"); */
|
||||
|
||||
#ifndef AUTHFD_H
|
||||
#define AUTHFD_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
/* Messages for the authentication agent connection. */
|
||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||
#define SSH_AGENTC_RSA_CHALLENGE 3
|
||||
#define SSH_AGENT_RSA_RESPONSE 4
|
||||
#define SSH_AGENT_FAILURE 5
|
||||
#define SSH_AGENT_SUCCESS 6
|
||||
#define SSH_AGENTC_ADD_RSA_IDENTITY 7
|
||||
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||
#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
Buffer packet;
|
||||
Buffer identities;
|
||||
int howmany;
|
||||
} AuthenticationConnection;
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
int ssh_get_authentication_socket();
|
||||
|
||||
/*
|
||||
* This should be called for any descriptor returned by
|
||||
* ssh_get_authentication_socket(). Depending on the way the descriptor was
|
||||
* obtained, this may close the descriptor.
|
||||
*/
|
||||
void ssh_close_authentication_socket(int authfd);
|
||||
|
||||
/*
|
||||
* Opens and connects a private socket for communication with the
|
||||
* authentication agent. Returns NULL if an error occurred and the
|
||||
* connection could not be opened. The connection should be closed by the
|
||||
* caller by calling ssh_close_authentication_connection().
|
||||
*/
|
||||
AuthenticationConnection *ssh_get_authentication_connection();
|
||||
|
||||
/*
|
||||
* Closes the connection to the authentication agent and frees any associated
|
||||
* memory.
|
||||
*/
|
||||
void ssh_close_authentication_connection(AuthenticationConnection * ac);
|
||||
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent. Returns true
|
||||
* if an identity is available, 0 otherwise. The caller must initialize the
|
||||
* integers before the call, and free the comment after a successful call
|
||||
* (before calling ssh_get_next_identity).
|
||||
*/
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
/*
|
||||
* Returns the next authentication identity for the agent. Other functions
|
||||
* can be called between this and ssh_get_first_identity or two calls of this
|
||||
* function. This returns 0 if there are no more identities. The caller
|
||||
* must free comment after a successful return.
|
||||
*/
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
/* Requests the agent to decrypt the given challenge. Returns true if
|
||||
the agent claims it was able to decrypt it. */
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection * auth,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16]);
|
||||
|
||||
/*
|
||||
* Adds an identity to the authentication server. This call is not meant to
|
||||
* be used by normal applications. This returns true if the identity was
|
||||
* successfully added.
|
||||
*/
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection * connection, RSA * key,
|
||||
const char *comment);
|
||||
|
||||
/*
|
||||
* Removes the identity from the authentication server. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* identity was successfully added.
|
||||
*/
|
||||
int ssh_remove_identity(AuthenticationConnection * connection, RSA * key);
|
||||
|
||||
/*
|
||||
* Removes all identities from the authentication agent. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* operation was successful.
|
||||
*/
|
||||
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
||||
|
||||
/* Closes the connection to the authentication agent. */
|
||||
void ssh_close_authentication(AuthenticationConnection * connection);
|
||||
|
||||
#endif /* AUTHFD_H */
|
345
crypto/openssh/authfile.c
Normal file
345
crypto/openssh/authfile.c
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
*
|
||||
* authfile.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 27 03:52:05 1995 ylo
|
||||
*
|
||||
* This file contains functions for reading and writing identity files, and
|
||||
* for reading the passphrase from the user.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $");
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Version identification string for identity files. */
|
||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. 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,
|
||||
RSA *key, const char *comment)
|
||||
{
|
||||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
int fd, i;
|
||||
CipherContext cipher;
|
||||
int cipher_type;
|
||||
u_int32_t rand;
|
||||
|
||||
/*
|
||||
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
|
||||
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
|
||||
*/
|
||||
if (strcmp(passphrase, "") == 0)
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
else
|
||||
cipher_type = SSH_AUTHFILE_CIPHER;
|
||||
|
||||
/* This buffer is used to built the secret part of the private key. */
|
||||
buffer_init(&buffer);
|
||||
|
||||
/* Put checkbytes for checking passphrase validity. */
|
||||
rand = arc4random();
|
||||
buf[0] = rand & 0xff;
|
||||
buf[1] = (rand >> 8) & 0xff;
|
||||
buf[2] = buf[0];
|
||||
buf[3] = buf[1];
|
||||
buffer_append(&buffer, buf, 4);
|
||||
|
||||
/*
|
||||
* Store the private key (n and e will not be stored because they
|
||||
* 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 */
|
||||
|
||||
/* Pad the part to be encrypted until its size is a multiple of 8. */
|
||||
while (buffer_len(&buffer) % 8 != 0)
|
||||
buffer_put_char(&buffer, 0);
|
||||
|
||||
/* This buffer will be used to contain the data in the file. */
|
||||
buffer_init(&encrypted);
|
||||
|
||||
/* First store keyfile id string. */
|
||||
cp = AUTHFILE_ID_STRING;
|
||||
for (i = 0; cp[i]; i++)
|
||||
buffer_put_char(&encrypted, cp[i]);
|
||||
buffer_put_char(&encrypted, 0);
|
||||
|
||||
/* Store cipher type. */
|
||||
buffer_put_char(&encrypted, cipher_type);
|
||||
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_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(&cipher, cipher_type, passphrase, 1);
|
||||
cipher_encrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
memset(&cipher, 0, sizeof(cipher));
|
||||
|
||||
/* Destroy temporary data. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buffer_free(&buffer);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
||||
buffer_len(&encrypted)) {
|
||||
debug("Write to key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&encrypted);
|
||||
close(fd);
|
||||
remove(filename);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
buffer_free(&encrypted);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return)
|
||||
{
|
||||
int fd, i;
|
||||
off_t len;
|
||||
Buffer buffer;
|
||||
char *cp;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(const char *filename, const char *passphrase,
|
||||
RSA * prv, char **comment_return)
|
||||
{
|
||||
int fd, i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
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_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);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* 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);
|
||||
else
|
||||
xfree(buffer_get_string(&buffer, NULL));
|
||||
|
||||
/* Check that it is a supported cipher. */
|
||||
if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
(1 << cipher_type)) == 0) {
|
||||
debug("Unsupported cipher %.100s used in key file %.200s.",
|
||||
cipher_name(cipher_type), filename);
|
||||
buffer_free(&buffer);
|
||||
goto fail;
|
||||
}
|
||||
/* Initialize space for decrypted data. */
|
||||
buffer_init(&decrypted);
|
||||
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
|
||||
cipher_decrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
|
||||
buffer_free(&buffer);
|
||||
|
||||
check1 = buffer_get_char(&decrypted);
|
||||
check2 = buffer_get_char(&decrypted);
|
||||
if (check1 != buffer_get_char(&decrypted) ||
|
||||
check2 != buffer_get_char(&decrypted)) {
|
||||
if (strcmp(passphrase, "") != 0)
|
||||
debug("Bad passphrase supplied for key file %.200s.", filename);
|
||||
/* Bad passphrase. */
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
BN_clear_free(prv->e);
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
}
|
||||
/* 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 */
|
||||
|
||||
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->p, BN_value_one());
|
||||
prv->dmp1 = BN_new();
|
||||
BN_mod(prv->dmp1, prv->d, aux, ctx);
|
||||
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
buffer_free(&decrypted);
|
||||
|
||||
return 1;
|
||||
}
|
158
crypto/openssh/bufaux.c
Normal file
158
crypto/openssh/bufaux.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
*
|
||||
* bufaux.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 02:24:47 1995 ylo
|
||||
*
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: bufaux.c,v 1.7 1999/11/24 19:53:44 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include <ssl/bn.h>
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
* by (bits+7)/8 bytes of binary data, msb first.
|
||||
*/
|
||||
void
|
||||
buffer_put_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bits = BN_num_bits(value);
|
||||
int bin_size = (bits + 7) / 8;
|
||||
char *buf = xmalloc(bin_size);
|
||||
int oi;
|
||||
char msg[2];
|
||||
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf);
|
||||
if (oi != bin_size)
|
||||
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bin_size);
|
||||
|
||||
/* Store the number of bits in the buffer in two bytes, msb first. */
|
||||
PUT_16BIT(msg, bits);
|
||||
buffer_append(buffer, msg, 2);
|
||||
/* Store the binary data. */
|
||||
buffer_append(buffer, buf, oi);
|
||||
|
||||
memset(buf, 0, bin_size);
|
||||
xfree(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves an BIGNUM from the buffer.
|
||||
*/
|
||||
int
|
||||
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bits, bytes;
|
||||
unsigned char buf[2], *bin;
|
||||
|
||||
/* Get the number for bits. */
|
||||
buffer_get(buffer, (char *) buf, 2);
|
||||
bits = GET_16BIT(buf);
|
||||
/* Compute the number of binary bytes that follow. */
|
||||
bytes = (bits + 7) / 8;
|
||||
if (buffer_len(buffer) < bytes)
|
||||
fatal("buffer_get_bignum: input buffer too small");
|
||||
bin = buffer_ptr(buffer);
|
||||
BN_bin2bn(bin, bytes, value);
|
||||
buffer_consume(buffer, bytes);
|
||||
|
||||
return 2 + bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an integer from the buffer (4 bytes, msb first).
|
||||
*/
|
||||
unsigned int
|
||||
buffer_get_int(Buffer *buffer)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
buffer_get(buffer, (char *) buf, 4);
|
||||
return GET_32BIT(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores an integer in the buffer in 4 bytes, msb first.
|
||||
*/
|
||||
void
|
||||
buffer_put_int(Buffer *buffer, unsigned int value)
|
||||
{
|
||||
char buf[4];
|
||||
PUT_32BIT(buf, value);
|
||||
buffer_append(buffer, buf, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an arbitrary binary string from the buffer. The string cannot
|
||||
* be longer than 256k. The returned value points to memory allocated
|
||||
* with xmalloc; it is the responsibility of the calling function to free
|
||||
* the data. If length_ptr is non-NULL, the length of the returned data
|
||||
* will be stored there. A null character will be automatically appended
|
||||
* to the returned string, and is not counted in length.
|
||||
*/
|
||||
char *
|
||||
buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
|
||||
{
|
||||
unsigned int len;
|
||||
char *value;
|
||||
/* Get the length. */
|
||||
len = buffer_get_int(buffer);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Received packet with bad string length %d", len);
|
||||
/* Allocate space for the string. Add one byte for a null character. */
|
||||
value = xmalloc(len + 1);
|
||||
/* Get the string. */
|
||||
buffer_get(buffer, value, len);
|
||||
/* Append a null character to make processing easier. */
|
||||
value[len] = 0;
|
||||
/* Optionally return the length of the string. */
|
||||
if (length_ptr)
|
||||
*length_ptr = len;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores and arbitrary binary string in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
|
||||
{
|
||||
buffer_put_int(buffer, len);
|
||||
buffer_append(buffer, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a character from the buffer (0 - 255).
|
||||
*/
|
||||
int
|
||||
buffer_get_char(Buffer *buffer)
|
||||
{
|
||||
char ch;
|
||||
buffer_get(buffer, &ch, 1);
|
||||
return (unsigned char) ch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores a character in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_char(Buffer *buffer, int value)
|
||||
{
|
||||
char ch = value;
|
||||
buffer_append(buffer, &ch, 1);
|
||||
}
|
55
crypto/openssh/bufaux.h
Normal file
55
crypto/openssh/bufaux.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
*
|
||||
* bufaux.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 02:18:23 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: bufaux.h,v 1.4 1999/11/24 19:53:44 markus Exp $"); */
|
||||
|
||||
#ifndef BUFAUX_H
|
||||
#define BUFAUX_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
* by (bits+7)/8 bytes of binary data, msb first.
|
||||
*/
|
||||
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Returns an integer from the buffer (4 bytes, msb first). */
|
||||
unsigned int buffer_get_int(Buffer * buffer);
|
||||
|
||||
/* Stores an integer in the buffer in 4 bytes, msb first. */
|
||||
void buffer_put_int(Buffer * buffer, unsigned int value);
|
||||
|
||||
/* Returns a character from the buffer (0 - 255). */
|
||||
int buffer_get_char(Buffer * buffer);
|
||||
|
||||
/* Stores a character in the buffer. */
|
||||
void buffer_put_char(Buffer * buffer, int value);
|
||||
|
||||
/*
|
||||
* Returns an arbitrary binary string from the buffer. The string cannot be
|
||||
* longer than 256k. The returned value points to memory allocated with
|
||||
* xmalloc; it is the responsibility of the calling function to free the
|
||||
* data. If length_ptr is non-NULL, the length of the returned data will be
|
||||
* stored there. A null character will be automatically appended to the
|
||||
* returned string, and is not counted in length.
|
||||
*/
|
||||
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
|
||||
|
||||
/* Stores and arbitrary binary string in the buffer. */
|
||||
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
|
||||
|
||||
#endif /* BUFAUX_H */
|
161
crypto/openssh/buffer.c
Normal file
161
crypto/openssh/buffer.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
*
|
||||
* buffer.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 04:15:33 1995 ylo
|
||||
*
|
||||
* Functions for manipulating fifo buffers (that can grow if needed).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Initializes the buffer structure. */
|
||||
|
||||
void
|
||||
buffer_init(Buffer *buffer)
|
||||
{
|
||||
buffer->alloc = 4096;
|
||||
buffer->buf = xmalloc(buffer->alloc);
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
|
||||
void
|
||||
buffer_free(Buffer *buffer)
|
||||
{
|
||||
memset(buffer->buf, 0, buffer->alloc);
|
||||
xfree(buffer->buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears any data from the buffer, making it empty. This does not actually
|
||||
* zero the memory.
|
||||
*/
|
||||
|
||||
void
|
||||
buffer_clear(Buffer *buffer)
|
||||
{
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
|
||||
void
|
||||
buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
||||
{
|
||||
char *cp;
|
||||
buffer_append_space(buffer, &cp, len);
|
||||
memcpy(cp, data, 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)
|
||||
{
|
||||
/* If the buffer is empty, start using it from the beginning. */
|
||||
if (buffer->offset == buffer->end) {
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
restart:
|
||||
/* If there is enough space to store all data, store it now. */
|
||||
if (buffer->end + len < buffer->alloc) {
|
||||
*datap = buffer->buf + buffer->end;
|
||||
buffer->end += len;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If the buffer is quite empty, but all data is at the end, move the
|
||||
* data to the beginning and retry.
|
||||
*/
|
||||
if (buffer->offset > buffer->alloc / 2) {
|
||||
memmove(buffer->buf, buffer->buf + buffer->offset,
|
||||
buffer->end - buffer->offset);
|
||||
buffer->end -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
goto restart;
|
||||
}
|
||||
/* Increase the size of the buffer and retry. */
|
||||
buffer->alloc += len + 32768;
|
||||
buffer->buf = xrealloc(buffer->buf, buffer->alloc);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
|
||||
unsigned int
|
||||
buffer_len(Buffer *buffer)
|
||||
{
|
||||
return buffer->end - buffer->offset;
|
||||
}
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
|
||||
void
|
||||
buffer_get(Buffer *buffer, char *buf, unsigned int len)
|
||||
{
|
||||
if (len > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
memcpy(buf, buffer->buf + buffer->offset, len);
|
||||
buffer->offset += len;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the beginning of the buffer. */
|
||||
|
||||
void
|
||||
buffer_consume(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->offset += bytes;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
|
||||
void
|
||||
buffer_consume_end(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->end -= bytes;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the first used byte in the buffer. */
|
||||
|
||||
char *
|
||||
buffer_ptr(Buffer *buffer)
|
||||
{
|
||||
return buffer->buf + buffer->offset;
|
||||
}
|
||||
|
||||
/* Dumps the contents of the buffer to stderr. */
|
||||
|
||||
void
|
||||
buffer_dump(Buffer *buffer)
|
||||
{
|
||||
int i;
|
||||
unsigned char *ucp = (unsigned char *) buffer->buf;
|
||||
|
||||
for (i = buffer->offset; i < buffer->end; i++)
|
||||
fprintf(stderr, " %02x", ucp[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
68
crypto/openssh/buffer.h
Normal file
68
crypto/openssh/buffer.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
*
|
||||
* buffer.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 04:12:25 1995 ylo
|
||||
*
|
||||
* Code for manipulating FIFO buffers.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: buffer.h,v 1.3 1999/11/24 19:53:44 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. */
|
||||
} Buffer;
|
||||
/* Initializes the buffer structure. */
|
||||
void buffer_init(Buffer * buffer);
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
void buffer_free(Buffer * buffer);
|
||||
|
||||
/* Clears any data from the buffer, making it empty. This does not actually
|
||||
zero the memory. */
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
unsigned int buffer_len(Buffer * buffer);
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
void 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);
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
void buffer_consume_end(Buffer * buffer, unsigned int bytes);
|
||||
|
||||
/* Returns a pointer to the first used byte in the buffer. */
|
||||
char *buffer_ptr(Buffer * buffer);
|
||||
|
||||
/*
|
||||
* Dumps the contents of the buffer to stderr in hex. This intended for
|
||||
* debugging purposes only.
|
||||
*/
|
||||
void buffer_dump(Buffer * buffer);
|
||||
|
||||
#endif /* BUFFER_H */
|
274
crypto/openssh/canohost.c
Normal file
274
crypto/openssh/canohost.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
*
|
||||
* canohost.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 2 17:52:22 1995 ylo
|
||||
*
|
||||
* Functions for returning the canonical host name of the remote site.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: canohost.c,v 1.11 2000/01/04 13:41:32 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Return the canonical name of the host at the other end of the socket. The
|
||||
* caller should free the returned string with xfree.
|
||||
*/
|
||||
|
||||
char *
|
||||
get_remote_hostname(int socket)
|
||||
{
|
||||
struct sockaddr_storage from;
|
||||
int i;
|
||||
socklen_t fromlen;
|
||||
struct addrinfo hints, *ai, *aitop;
|
||||
char name[MAXHOSTNAMELEN];
|
||||
char 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) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
|
||||
NULL, 0, NI_NUMERICHOST) != 0)
|
||||
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
check_ip_options:
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* 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;
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
option_size = sizeof(options);
|
||||
if (getsockopt(0, 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);
|
||||
}
|
||||
}
|
||||
|
||||
return xstrdup(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* several times.
|
||||
*/
|
||||
|
||||
const char *
|
||||
get_canonical_hostname()
|
||||
{
|
||||
static char *canonical_host_name = NULL;
|
||||
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_name != NULL)
|
||||
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());
|
||||
else
|
||||
canonical_host_name = xstrdup("UNKNOWN");
|
||||
|
||||
return canonical_host_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the IP-address of the remote host as a string. The returned
|
||||
* string must not be freed.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Returns the local/remote port for the socket. */
|
||||
|
||||
int
|
||||
get_sock_port(int sock, int local)
|
||||
{
|
||||
struct sockaddr_storage from;
|
||||
socklen_t fromlen;
|
||||
char strport[NI_MAXSERV];
|
||||
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (local) {
|
||||
if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
|
||||
error("getsockname failed: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
}
|
||||
/* Return port number. */
|
||||
if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
|
||||
strport, sizeof(strport), NI_NUMERICSERV) != 0)
|
||||
fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
|
||||
return atoi(strport);
|
||||
}
|
||||
|
||||
/* Returns remote/local port number for the current connection. */
|
||||
|
||||
int
|
||||
get_port(int local)
|
||||
{
|
||||
/*
|
||||
* If the connection is not a socket, return 65535. This is
|
||||
* intentionally chosen to be an unprivileged port number.
|
||||
*/
|
||||
if (!packet_connection_is_on_socket())
|
||||
return 65535;
|
||||
|
||||
/* Get socket and return the port number. */
|
||||
return get_sock_port(packet_get_connection_in(), local);
|
||||
}
|
||||
|
||||
int
|
||||
get_peer_port(int sock)
|
||||
{
|
||||
return get_sock_port(sock, 0);
|
||||
}
|
||||
|
||||
int
|
||||
get_remote_port()
|
||||
{
|
||||
return get_port(0);
|
||||
}
|
||||
|
||||
int
|
||||
get_local_port()
|
||||
{
|
||||
return get_port(1);
|
||||
}
|
1614
crypto/openssh/channels.c
Normal file
1614
crypto/openssh/channels.c
Normal file
File diff suppressed because it is too large
Load Diff
43
crypto/openssh/channels.h
Normal file
43
crypto/openssh/channels.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* RCSID("$Id: channels.h,v 1.6 1999/11/24 19:53:45 markus Exp $"); */
|
||||
|
||||
#ifndef CHANNELS_H
|
||||
#define CHANNELS_H
|
||||
|
||||
/* Definitions for channel types. */
|
||||
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
|
||||
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
|
||||
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
|
||||
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
|
||||
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
|
||||
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
||||
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
|
||||
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
|
||||
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
|
||||
|
||||
/*
|
||||
* Data structure for channel data. This is iniailized in channel_allocate
|
||||
* and cleared in channel_free.
|
||||
*/
|
||||
|
||||
typedef struct Channel {
|
||||
int type; /* channel type/state */
|
||||
int self; /* my own channel identifier */
|
||||
int remote_id; /* channel identifier for remote peer */
|
||||
/* peer can be reached over encrypted connection, via packet-sent */
|
||||
int istate; /* input from channel (state of receive half) */
|
||||
int ostate; /* output to channel (state of transmit half) */
|
||||
int sock; /* data socket, linked to this channel */
|
||||
Buffer input; /* data read from socket, to be sent over
|
||||
* encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for
|
||||
* send on socket */
|
||||
char path[200]; /* path for unix domain sockets, or host name
|
||||
* for forwards */
|
||||
int listening_port; /* port being listened for forwards */
|
||||
int host_port; /* remote port to connect for forwards */
|
||||
char *remote_name; /* remote hostname */
|
||||
} Channel;
|
||||
#endif
|
320
crypto/openssh/cipher.c
Normal file
320
crypto/openssh/cipher.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
*
|
||||
* cipher.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Apr 19 17:41:39 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: cipher.c,v 1.19 2000/02/22 15:19:29 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
|
||||
/*
|
||||
* What kind of tripple DES are these 2 routines?
|
||||
*
|
||||
* Why is there a redundant initialization vector?
|
||||
*
|
||||
* If only iv3 was used, then, this would till effect have been
|
||||
* outer-cbc. However, there is also a private iv1 == iv2 which
|
||||
* perhaps makes differential analysis easier. On the other hand, the
|
||||
* private iv1 probably makes the CRC-32 attack ineffective. This is a
|
||||
* result of that there is no longer any known iv1 to use when
|
||||
* choosing the X block.
|
||||
*/
|
||||
void
|
||||
SSH_3CBC_ENCRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
unsigned char *dest, unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
|
||||
memcpy(&iv1, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
|
||||
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
|
||||
memcpy(iv3, dest + len - 8, 8);
|
||||
}
|
||||
|
||||
void
|
||||
SSH_3CBC_DECRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
unsigned char *dest, unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
|
||||
memcpy(iv3, src + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
|
||||
memcpy(iv2, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
|
||||
/* memcpy(&iv1, iv2, 8); */
|
||||
/* Note how iv1 == iv2 on entry and exit. */
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
*/
|
||||
static void
|
||||
swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
|
||||
{
|
||||
/* dst must be properly aligned. */
|
||||
u_int32_t *dst = (u_int32_t *) dst_;
|
||||
union {
|
||||
u_int32_t i;
|
||||
char c[4];
|
||||
} t;
|
||||
|
||||
/* Process 8 bytes every lap. */
|
||||
for (n = n / 8; n > 0; n--) {
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
}
|
||||
}
|
||||
|
||||
void (*cipher_attack_detected) (const char *fmt,...) = fatal;
|
||||
|
||||
static inline void
|
||||
detect_cbc_attack(const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
return;
|
||||
|
||||
log("CRC-32 CBC insertion attack detected");
|
||||
cipher_attack_detected("CRC-32 CBC insertion attack detected");
|
||||
}
|
||||
|
||||
/*
|
||||
* Names of all encryption algorithms.
|
||||
* These must match the numbers defined in cipher.h.
|
||||
*/
|
||||
static char *cipher_names[] =
|
||||
{
|
||||
"none",
|
||||
"idea",
|
||||
"des",
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4",
|
||||
"blowfish"
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
|
||||
const char *
|
||||
cipher_name(int cipher)
|
||||
{
|
||||
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
|
||||
cipher_names[cipher] == NULL)
|
||||
fatal("cipher_name: bad cipher number: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the name of the cipher. Returns the number of the corresponding
|
||||
* cipher, or -1 on error.
|
||||
*/
|
||||
|
||||
int
|
||||
cipher_number(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
|
||||
if (strcmp(cipher_names[i], name) == 0 &&
|
||||
(cipher_mask() & (1 << i)))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects the cipher, and keys if by computing the MD5 checksum of the
|
||||
* passphrase and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
|
||||
void
|
||||
cipher_set_key_string(CipherContext *context, int cipher,
|
||||
const char *passphrase, int for_encryption)
|
||||
{
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
|
||||
MD5_Final(digest, &md);
|
||||
|
||||
cipher_set_key(context, cipher, digest, 16, for_encryption);
|
||||
|
||||
memset(digest, 0, sizeof(digest));
|
||||
memset(&md, 0, sizeof(md));
|
||||
}
|
||||
|
||||
/* Selects the cipher to use and sets the key. */
|
||||
|
||||
void
|
||||
cipher_set_key(CipherContext *context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption)
|
||||
{
|
||||
unsigned char padded[32];
|
||||
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Get 32 bytes of key data. Pad if necessary. (So that code
|
||||
below does not need to worry about key size). */
|
||||
memset(padded, 0, sizeof(padded));
|
||||
memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
/*
|
||||
* Has to stay for authfile saving of private key with no
|
||||
* passphrase
|
||||
*/
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/*
|
||||
* Note: the least significant bit of each byte of key is
|
||||
* parity, and must be ignored by the implementation. 16
|
||||
* bytes of key are used (first and last keys are the same).
|
||||
*/
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for 3DES.", keylen);
|
||||
des_set_key((void *) padded, context->u.des3.key1);
|
||||
des_set_key((void *) (padded + 8), context->u.des3.key2);
|
||||
if (keylen <= 16)
|
||||
des_set_key((void *) padded, context->u.des3.key3);
|
||||
else
|
||||
des_set_key((void *) (padded + 16), context->u.des3.key3);
|
||||
memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
|
||||
memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
}
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
|
||||
void
|
||||
cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_encrypt: bad plaintext length %d", len);
|
||||
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
SSH_3CBC_ENCRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (unsigned char *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt(dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
|
||||
void
|
||||
cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_decrypt: bad ciphertext length %d", len);
|
||||
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/* CRC-32 attack? */
|
||||
SSH_3CBC_DECRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (unsigned char *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
detect_cbc_attack(src, len);
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void *) dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
97
crypto/openssh/cipher.h
Normal file
97
crypto/openssh/cipher.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
*
|
||||
* cipher.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Apr 19 16:50:42 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: cipher.h,v 1.10 1999/11/24 19:53:46 markus Exp $"); */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
||||
#include <ssl/des.h>
|
||||
#include <ssl/blowfish.h>
|
||||
|
||||
/* Cipher types. New types can be added, but old types should not be removed
|
||||
for compatibility. The maximum allowed value is 31. */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
|
||||
#define SSH_CIPHER_DES 2 /* DES CBC */
|
||||
#define SSH_CIPHER_3DES 3 /* 3DES CBC */
|
||||
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
|
||||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
typedef struct {
|
||||
unsigned int type;
|
||||
union {
|
||||
struct {
|
||||
des_key_schedule key1;
|
||||
des_key_schedule key2;
|
||||
des_cblock iv2;
|
||||
des_key_schedule key3;
|
||||
des_cblock iv3;
|
||||
} des3;
|
||||
struct {
|
||||
struct bf_key_st key;
|
||||
unsigned char iv[8];
|
||||
} bf;
|
||||
} u;
|
||||
} CipherContext;
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
unsigned int cipher_mask();
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
const char *cipher_name(int cipher);
|
||||
|
||||
/*
|
||||
* Parses the name of the cipher. Returns the number of the corresponding
|
||||
* cipher, or -1 on error.
|
||||
*/
|
||||
int cipher_number(const char *name);
|
||||
|
||||
/*
|
||||
* Selects the cipher to use and sets the key. If for_encryption is true,
|
||||
* the key is setup for encryption; otherwise it is setup for decryption.
|
||||
*/
|
||||
void
|
||||
cipher_set_key(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption);
|
||||
|
||||
/*
|
||||
* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
||||
* and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
void
|
||||
cipher_set_key_string(CipherContext * context, int cipher,
|
||||
const char *passphrase, int for_encryption);
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
void
|
||||
cipher_encrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
void
|
||||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/*
|
||||
* If and CRC-32 attack is detected this function is called. Defaults to
|
||||
* fatal, changed to packet_disconnect in sshd and ssh.
|
||||
*/
|
||||
extern void (*cipher_attack_detected) (const char *fmt, ...);
|
||||
|
||||
#endif /* CIPHER_H */
|
952
crypto/openssh/clientloop.c
Normal file
952
crypto/openssh/clientloop.c
Normal file
@ -0,0 +1,952 @@
|
||||
/*
|
||||
*
|
||||
* clientloop.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Sep 23 12:23:57 1995 ylo
|
||||
*
|
||||
* The main loop for the interactive session (client side).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "authfd.h"
|
||||
#include "readconf.h"
|
||||
|
||||
/* Flag indicating that stdin should be redirected from /dev/null. */
|
||||
extern int stdin_null_flag;
|
||||
|
||||
/*
|
||||
* Name of the host we are connecting to. This is the name given on the
|
||||
* command line, or the HostName specified for the user-supplied name in a
|
||||
* configuration file.
|
||||
*/
|
||||
extern char *host;
|
||||
|
||||
/*
|
||||
* Flag to indicate that we have received a window change signal which has
|
||||
* not yet been processed. This will cause a message indicating the new
|
||||
* window size to be sent to the server a little later. This is volatile
|
||||
* because this is updated in a signal handler.
|
||||
*/
|
||||
static volatile int received_window_change_signal = 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Common data for the client loop code. */
|
||||
static int escape_pending; /* Last character was the escape character */
|
||||
static int last_was_cr; /* Last character was a newline. */
|
||||
static int exit_status; /* Used to store the exit status of the command. */
|
||||
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 int buffer_high;/* Soft max buffer size. */
|
||||
static int max_fd; /* Maximum file descriptor number in select(). */
|
||||
static int connection_in; /* Connection to server (input). */
|
||||
static int connection_out; /* Connection to server (output). */
|
||||
static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
|
||||
static int quit_pending; /* Set to non-zero to quit the client loop. */
|
||||
static int escape_char; /* Escape character. */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Restores stdin to blocking mode. */
|
||||
|
||||
void
|
||||
leave_non_blocking()
|
||||
{
|
||||
if (in_non_blocking_mode) {
|
||||
(void) fcntl(fileno(stdin), F_SETFL, 0);
|
||||
in_non_blocking_mode = 0;
|
||||
fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Puts stdin terminal in non-blocking mode. */
|
||||
|
||||
void
|
||||
enter_non_blocking()
|
||||
{
|
||||
in_non_blocking_mode = 1;
|
||||
(void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
|
||||
fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for the window change signal (SIGWINCH). This just sets a
|
||||
* flag indicating that the window has changed.
|
||||
*/
|
||||
|
||||
void
|
||||
window_change_handler(int sig)
|
||||
{
|
||||
received_window_change_signal = 1;
|
||||
signal(SIGWINCH, window_change_handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for signals that cause the program to terminate. These
|
||||
* signals must be trapped to restore terminal modes.
|
||||
*/
|
||||
|
||||
void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
if (in_raw_mode)
|
||||
leave_raw_mode();
|
||||
if (in_non_blocking_mode)
|
||||
leave_non_blocking();
|
||||
channel_stop_listening();
|
||||
packet_close();
|
||||
fatal("Killed by signal %d.", sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns current time in seconds from Jan 1, 1970 with the maximum
|
||||
* available resolution.
|
||||
*/
|
||||
|
||||
double
|
||||
get_current_time()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when the interactive is entered. This checks if there is
|
||||
* an EOF coming on stdin. We must check this explicitly, as select() does
|
||||
* not appear to wake up when redirecting from /dev/null.
|
||||
*/
|
||||
|
||||
void
|
||||
client_check_initial_eof_on_stdin()
|
||||
{
|
||||
int len;
|
||||
char buf[1];
|
||||
|
||||
/*
|
||||
* If standard input is to be "redirected from /dev/null", we simply
|
||||
* mark that we have seen an EOF and send an EOF message to the
|
||||
* server. Otherwise, we try to read a single character; it appears
|
||||
* that for some files, such /dev/null, select() never wakes up for
|
||||
* read for this descriptor, which means that we never get EOF. This
|
||||
* way we will get the EOF if stdin comes from /dev/null or similar.
|
||||
*/
|
||||
if (stdin_null_flag) {
|
||||
/* Fake EOF on stdin. */
|
||||
debug("Sending eof.");
|
||||
stdin_eof = 1;
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else {
|
||||
enter_non_blocking();
|
||||
|
||||
/* Check for immediate EOF on stdin. */
|
||||
len = read(fileno(stdin), buf, 1);
|
||||
if (len == 0) {
|
||||
/* EOF. Record that we have seen it and send EOF to server. */
|
||||
debug("Sending eof.");
|
||||
stdin_eof = 1;
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else if (len > 0) {
|
||||
/*
|
||||
* Got data. We must store the data in the buffer,
|
||||
* and also process it as an escape character if
|
||||
* appropriate.
|
||||
*/
|
||||
if ((unsigned char) buf[0] == escape_char)
|
||||
escape_pending = 1;
|
||||
else {
|
||||
buffer_append(&stdin_buffer, buf, 1);
|
||||
stdin_bytes += 1;
|
||||
}
|
||||
}
|
||||
leave_non_blocking();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get packets from the connection input buffer, and process them as long as
|
||||
* there are packets available.
|
||||
*/
|
||||
|
||||
void
|
||||
client_process_buffered_input_packets()
|
||||
{
|
||||
int type;
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
int payload_len;
|
||||
|
||||
/* Process any buffered packets from the server. */
|
||||
while (!quit_pending &&
|
||||
(type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
|
||||
switch (type) {
|
||||
|
||||
case SSH_SMSG_STDOUT_DATA:
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, 4 + data_len, type);
|
||||
buffer_append(&stdout_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_STDERR_DATA:
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, 4 + data_len, type);
|
||||
buffer_append(&stderr_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_EXITSTATUS:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
exit_status = packet_get_int();
|
||||
/* Acknowledge the exit. */
|
||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||
packet_send();
|
||||
/*
|
||||
* Must wait for packet to be sent since we are
|
||||
* exiting the loop.
|
||||
*/
|
||||
packet_write_wait();
|
||||
/* Flag that we want to exit. */
|
||||
quit_pending = 1;
|
||||
break;
|
||||
|
||||
case SSH_SMSG_X11_OPEN:
|
||||
x11_input_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_PORT_OPEN:
|
||||
channel_input_port_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_AGENT_OPEN:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
auth_input_open_request();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
packet_integrity_check(payload_len, 4 + 4, type);
|
||||
channel_input_open_confirmation();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_open_failure();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
channel_input_data(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close_confirmation();
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Any unknown packets received during the actual
|
||||
* session cause the session to terminate. This is
|
||||
* intended to make debugging easier since no
|
||||
* confirmations are sent. Any compatible protocol
|
||||
* extensions must be negotiated during the
|
||||
* preparatory phase.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stdin data, and buffer them for sending to the
|
||||
* connection.
|
||||
*/
|
||||
|
||||
void
|
||||
client_make_packets_from_stdin_data()
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
/* Send buffered stdin data to the server. */
|
||||
while (buffer_len(&stdin_buffer) > 0 &&
|
||||
packet_not_very_much_data_to_write()) {
|
||||
len = buffer_len(&stdin_buffer);
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize())
|
||||
len = packet_get_maxsize();
|
||||
packet_start(SSH_CMSG_STDIN_DATA);
|
||||
packet_put_string(buffer_ptr(&stdin_buffer), len);
|
||||
packet_send();
|
||||
buffer_consume(&stdin_buffer, len);
|
||||
/* If we have a pending EOF, send it now. */
|
||||
if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the client window has changed, and sends a packet about it to
|
||||
* the server if so. The actual change is detected elsewhere (by a software
|
||||
* interrupt on Unix); this just checks the flag and sends a message if
|
||||
* appropriate.
|
||||
*/
|
||||
|
||||
void
|
||||
client_check_window_change()
|
||||
{
|
||||
/* Send possible window change message to the server. */
|
||||
if (received_window_change_signal) {
|
||||
struct winsize ws;
|
||||
|
||||
/* Clear the window change indicator. */
|
||||
received_window_change_signal = 0;
|
||||
|
||||
/* Read new window size. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
|
||||
/* Successful, send the packet now. */
|
||||
packet_start(SSH_CMSG_WINDOW_SIZE);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits until the client can do something (some data becomes available on
|
||||
* one of the file descriptors).
|
||||
*/
|
||||
|
||||
void
|
||||
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
||||
{
|
||||
/* Initialize select masks. */
|
||||
FD_ZERO(readset);
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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_ZERO(writeset);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Select stdout if have data in buffer. */
|
||||
if (buffer_len(&stdout_buffer) > 0)
|
||||
FD_SET(fileno(stdout), writeset);
|
||||
|
||||
/* Select stderr if have data in buffer. */
|
||||
if (buffer_len(&stderr_buffer) > 0)
|
||||
FD_SET(fileno(stderr), writeset);
|
||||
|
||||
/* Update maximum file descriptor number, if appropriate. */
|
||||
if (channel_max_fd() > max_fd)
|
||||
max_fd = channel_max_fd();
|
||||
|
||||
/*
|
||||
* Wait for something to happen. This will suspend the process until
|
||||
* some selected descriptor can be read, written, or has some other
|
||||
* event pending. Note: if you want to implement SSH_MSG_IGNORE
|
||||
* messages to fool traffic analysis, this might be the place to do
|
||||
* it: just have a random timeout for the select, and send a random
|
||||
* SSH_MSG_IGNORE packet when the timeout expires.
|
||||
*/
|
||||
|
||||
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
|
||||
char buf[100];
|
||||
/* Some systems fail to clear these automatically. */
|
||||
FD_ZERO(readset);
|
||||
FD_ZERO(writeset);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
client_suspend_self()
|
||||
{
|
||||
struct winsize oldws, newws;
|
||||
|
||||
/* Flush stdout and stderr buffers. */
|
||||
if (buffer_len(&stdout_buffer) > 0)
|
||||
atomicio(write, fileno(stdout), buffer_ptr(&stdout_buffer),
|
||||
buffer_len(&stdout_buffer));
|
||||
if (buffer_len(&stderr_buffer) > 0)
|
||||
atomicio(write, fileno(stderr), buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
|
||||
leave_raw_mode();
|
||||
|
||||
/*
|
||||
* Free (and clear) the buffer to reduce the amount of data that gets
|
||||
* written to swap.
|
||||
*/
|
||||
buffer_free(&stdin_buffer);
|
||||
buffer_free(&stdout_buffer);
|
||||
buffer_free(&stderr_buffer);
|
||||
|
||||
/* Save old window size. */
|
||||
ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
|
||||
|
||||
/* Send the suspend signal to the program itself. */
|
||||
kill(getpid(), SIGTSTP);
|
||||
|
||||
/* Check if the window size has changed. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
|
||||
(oldws.ws_row != newws.ws_row ||
|
||||
oldws.ws_col != newws.ws_col ||
|
||||
oldws.ws_xpixel != newws.ws_xpixel ||
|
||||
oldws.ws_ypixel != newws.ws_ypixel))
|
||||
received_window_change_signal = 1;
|
||||
|
||||
/* OK, we have been continued by the user. Reinitialize buffers. */
|
||||
buffer_init(&stdin_buffer);
|
||||
buffer_init(&stdout_buffer);
|
||||
buffer_init(&stderr_buffer);
|
||||
|
||||
enter_raw_mode();
|
||||
}
|
||||
|
||||
void
|
||||
client_process_input(fd_set * readset)
|
||||
{
|
||||
int len, pid;
|
||||
char buf[8192], *s;
|
||||
|
||||
/*
|
||||
* Read input from the server, and add any such data to the buffer of
|
||||
* the packet subsystem.
|
||||
*/
|
||||
if (FD_ISSET(connection_in, readset)) {
|
||||
/* Read as much as possible. */
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
/* Received EOF. The remote host has closed the connection. */
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* 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)
|
||||
len = 0;
|
||||
|
||||
if (len < 0) {
|
||||
/* An error has encountered. Perhaps there is a network problem. */
|
||||
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;
|
||||
}
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
/* Read input from stdin. */
|
||||
if (FD_ISSET(fileno(stdin), readset)) {
|
||||
/* Read as much as possible. */
|
||||
len = read(fileno(stdin), buf, sizeof(buf));
|
||||
if (len <= 0) {
|
||||
/*
|
||||
* Received EOF or error. They are treated
|
||||
* similarly, except that an error message is printed
|
||||
* if it was an error condition.
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* Send an EOF message to the server unless there is
|
||||
* data in the buffer. If there is data in the
|
||||
* buffer, no message will be sent now. Code
|
||||
* elsewhere will send the EOF when the buffer
|
||||
* becomes empty if stdin_eof is set.
|
||||
*/
|
||||
if (buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
} else if (escape_char == -1) {
|
||||
/*
|
||||
* Normal successful read, and no escape character.
|
||||
* 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.
|
||||
*/
|
||||
unsigned int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
unsigned char ch;
|
||||
/* Get one character at a time. */
|
||||
ch = buf[i];
|
||||
|
||||
if (escape_pending) {
|
||||
/* We have previously seen an escape character. */
|
||||
/* Clear the flag now. */
|
||||
escape_pending = 0;
|
||||
/* Process the escaped character. */
|
||||
switch (ch) {
|
||||
case '.':
|
||||
/* Terminate the connection. */
|
||||
snprintf(buf, sizeof buf, "%c.\r\n", escape_char);
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
stderr_bytes += strlen(buf);
|
||||
quit_pending = 1;
|
||||
return;
|
||||
|
||||
case 'Z' - 64:
|
||||
/* Suspend the program. */
|
||||
/* Print a message to that effect to the user. */
|
||||
snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char);
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
stderr_bytes += strlen(buf);
|
||||
|
||||
/* Restore terminal modes and suspend. */
|
||||
client_suspend_self();
|
||||
|
||||
/* We have been continued. */
|
||||
continue;
|
||||
|
||||
case '&':
|
||||
/*
|
||||
* Detach the program (continue to serve connections,
|
||||
* but put in background and no more new connections).
|
||||
*/
|
||||
if (!stdin_eof) {
|
||||
/*
|
||||
* Sending SSH_CMSG_EOF alone does not always appear
|
||||
* to be enough. So we try to send an EOF character
|
||||
* first.
|
||||
*/
|
||||
packet_start(SSH_CMSG_STDIN_DATA);
|
||||
packet_put_string("\004", 1);
|
||||
packet_send();
|
||||
/* Close stdin. */
|
||||
stdin_eof = 1;
|
||||
if (buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
/* Restore tty modes. */
|
||||
leave_raw_mode();
|
||||
|
||||
/* Stop listening for new connections. */
|
||||
channel_stop_listening();
|
||||
|
||||
printf("%c& [backgrounded]\n", escape_char);
|
||||
|
||||
/* Fork into background. */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
error("fork: %.100s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (pid != 0) { /* This is the parent. */
|
||||
/* The parent just exits. */
|
||||
exit(0);
|
||||
}
|
||||
/* The child continues serving connections. */
|
||||
continue;
|
||||
|
||||
case '?':
|
||||
snprintf(buf, sizeof buf,
|
||||
"%c?\r\n\
|
||||
Supported escape sequences:\r\n\
|
||||
~. - terminate connection\r\n\
|
||||
~^Z - suspend ssh\r\n\
|
||||
~# - list forwarded connections\r\n\
|
||||
~& - background ssh (when waiting for connections to terminate)\r\n\
|
||||
~? - this message\r\n\
|
||||
~~ - send the escape character by typing it twice\r\n\
|
||||
(Note that escapes are only recognized immediately after newline.)\r\n",
|
||||
escape_char);
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
continue;
|
||||
|
||||
case '#':
|
||||
snprintf(buf, sizeof buf, "%c#\r\n", escape_char);
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
s = channel_open_message();
|
||||
buffer_append(&stderr_buffer, s, strlen(s));
|
||||
xfree(s);
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (ch != escape_char) {
|
||||
/*
|
||||
* Escape character followed by non-special character.
|
||||
* Append both to the input buffer.
|
||||
*/
|
||||
buf[0] = escape_char;
|
||||
buf[1] = ch;
|
||||
buffer_append(&stdin_buffer, buf, 2);
|
||||
stdin_bytes += 2;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Note that escape character typed twice
|
||||
* falls through here; the latter gets processed
|
||||
* as a normal character below.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The previous character was not an escape char. Check if this
|
||||
* is an escape.
|
||||
*/
|
||||
if (last_was_cr && ch == escape_char) {
|
||||
/* It is. Set the flag and continue to next character. */
|
||||
escape_pending = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Normal character. Record whether it was a newline,
|
||||
* and append it to the buffer.
|
||||
*/
|
||||
last_was_cr = (ch == '\r' || ch == '\n');
|
||||
buf[0] = ch;
|
||||
buffer_append(&stdin_buffer, buf, 1);
|
||||
stdin_bytes += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
client_process_output(fd_set * writeset)
|
||||
{
|
||||
int len;
|
||||
char buf[100];
|
||||
|
||||
/* Write buffered output to stdout. */
|
||||
if (FD_ISSET(fileno(stdout), writeset)) {
|
||||
/* Write as much data as possible. */
|
||||
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
|
||||
buffer_len(&stdout_buffer));
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
len = 0;
|
||||
else {
|
||||
/*
|
||||
* An error or EOF was encountered. Put an
|
||||
* error message to stderr buffer.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
/* Write buffered output to stderr. */
|
||||
if (FD_ISSET(fileno(stderr), writeset)) {
|
||||
/* Write as much data as possible. */
|
||||
len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
len = 0;
|
||||
else {
|
||||
/* EOF or error, but can't even print error message. */
|
||||
quit_pending = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Consume printed characters from the buffer. */
|
||||
buffer_consume(&stderr_buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements the interactive session with the server. This is called after
|
||||
* the user has been authenticated, and a command has been started on the
|
||||
* remote host. If escape_char != -1, it is the character used as an escape
|
||||
* character for terminating or suspending the session.
|
||||
*/
|
||||
|
||||
int
|
||||
client_loop(int have_pty, int escape_char_arg)
|
||||
{
|
||||
extern Options options;
|
||||
double start_time, total_time;
|
||||
int len;
|
||||
char buf[100];
|
||||
|
||||
debug("Entering interactive session.");
|
||||
|
||||
start_time = get_current_time();
|
||||
|
||||
/* Initialize variables. */
|
||||
escape_pending = 0;
|
||||
last_was_cr = 1;
|
||||
exit_status = -1;
|
||||
stdin_eof = 0;
|
||||
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;
|
||||
stdin_bytes = 0;
|
||||
stdout_bytes = 0;
|
||||
stderr_bytes = 0;
|
||||
quit_pending = 0;
|
||||
escape_char = escape_char_arg;
|
||||
|
||||
/* Initialize buffers. */
|
||||
buffer_init(&stdin_buffer);
|
||||
buffer_init(&stdout_buffer);
|
||||
buffer_init(&stderr_buffer);
|
||||
|
||||
/* Set signal handlers to restore non-blocking mode. */
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if (have_pty)
|
||||
signal(SIGWINCH, window_change_handler);
|
||||
|
||||
if (have_pty)
|
||||
enter_raw_mode();
|
||||
|
||||
/* Check if we should immediately send of on stdin. */
|
||||
client_check_initial_eof_on_stdin();
|
||||
|
||||
/* 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();
|
||||
|
||||
/*
|
||||
* Make packets of buffered stdin data, and buffer them for
|
||||
* sending to the server.
|
||||
*/
|
||||
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);
|
||||
|
||||
if (quit_pending)
|
||||
break;
|
||||
|
||||
/* Do channel operations. */
|
||||
channel_after_select(&readset, &writeset);
|
||||
|
||||
/*
|
||||
* Process input from the connection and from stdin. Buffer
|
||||
* any data that is available.
|
||||
*/
|
||||
client_process_input(&readset);
|
||||
|
||||
/*
|
||||
* Process output to stdout and stderr. Output to the
|
||||
* connection is processed elsewhere (above).
|
||||
*/
|
||||
client_process_output(&writeset);
|
||||
|
||||
/* Send as much buffered packet data as possible to the sender. */
|
||||
if (FD_ISSET(connection_out, &writeset))
|
||||
packet_write_poll();
|
||||
}
|
||||
|
||||
/* Terminate the session. */
|
||||
|
||||
/* Stop watching for window change. */
|
||||
if (have_pty)
|
||||
signal(SIGWINCH, SIG_DFL);
|
||||
|
||||
/* Stop listening for connections. */
|
||||
channel_stop_listening();
|
||||
|
||||
/*
|
||||
* In interactive mode (with pseudo tty) display a message indicating
|
||||
* that the connection has been closed.
|
||||
*/
|
||||
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) {
|
||||
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
|
||||
buffer_len(&stdout_buffer));
|
||||
if (len <= 0) {
|
||||
error("Write failed flushing stdout buffer.");
|
||||
break;
|
||||
}
|
||||
buffer_consume(&stdout_buffer, len);
|
||||
}
|
||||
|
||||
/* Output any buffered data for stderr. */
|
||||
while (buffer_len(&stderr_buffer) > 0) {
|
||||
len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
if (len <= 0) {
|
||||
error("Write failed flushing stderr buffer.");
|
||||
break;
|
||||
}
|
||||
buffer_consume(&stderr_buffer, len);
|
||||
}
|
||||
|
||||
if (have_pty)
|
||||
leave_raw_mode();
|
||||
|
||||
/* Clear and free any buffers. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buffer_free(&stdin_buffer);
|
||||
buffer_free(&stdout_buffer);
|
||||
buffer_free(&stderr_buffer);
|
||||
|
||||
/* Report bytes transferred, and transfer rates. */
|
||||
total_time = get_current_time() - start_time;
|
||||
debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
|
||||
stdin_bytes, stdout_bytes, stderr_bytes, total_time);
|
||||
if (total_time > 0)
|
||||
debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
|
||||
stdin_bytes / total_time, stdout_bytes / total_time,
|
||||
stderr_bytes / total_time);
|
||||
|
||||
/* Return the exit status of the program. */
|
||||
debug("Exit status %d", exit_status);
|
||||
return exit_status;
|
||||
}
|
42
crypto/openssh/compat.c
Normal file
42
crypto/openssh/compat.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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("$Id: compat.c,v 1.5 1999/11/24 16:15:24 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
int compat13 = 0;
|
||||
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
35
crypto/openssh/compat.h
Normal file
35
crypto/openssh/compat.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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.
|
||||
*/
|
||||
/* RCSID("$Id: compat.h,v 1.4 1999/11/24 16:15:24 markus Exp $"); */
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
void enable_compat13(void);
|
||||
extern int compat13;
|
||||
#endif
|
165
crypto/openssh/compress.c
Normal file
165
crypto/openssh/compress.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
*
|
||||
* compress.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: compress.c,v 1.4 1999/11/24 19:53:46 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "zlib.h"
|
||||
|
||||
static z_stream incoming_stream;
|
||||
static z_stream outgoing_stream;
|
||||
|
||||
/*
|
||||
* Initializes compression; level is compression level from 1 to 9
|
||||
* (as in gzip).
|
||||
*/
|
||||
|
||||
void
|
||||
buffer_compress_init(int level)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* Frees any data structures allocated for compression. */
|
||||
|
||||
void
|
||||
buffer_compress_uninit()
|
||||
{
|
||||
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
|
||||
outgoing_stream.total_in, outgoing_stream.total_out,
|
||||
outgoing_stream.total_in == 0 ? 0.0 :
|
||||
(double) outgoing_stream.total_out / outgoing_stream.total_in);
|
||||
debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
|
||||
incoming_stream.total_out, incoming_stream.total_in,
|
||||
incoming_stream.total_out == 0 ? 0.0 :
|
||||
(double) incoming_stream.total_in / incoming_stream.total_out);
|
||||
inflateEnd(&incoming_stream);
|
||||
deflateEnd(&outgoing_stream);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||
* compressed using this function will form a single compressed data stream;
|
||||
* however, data will be flushed at the end of every call so that each
|
||||
* output_buffer can be decompressed independently (but in the appropriate
|
||||
* order since they together form a single compression stream) by the
|
||||
* receiver. This appends the compressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
int status;
|
||||
|
||||
/* This case is not handled below. */
|
||||
if (buffer_len(input_buffer) == 0)
|
||||
return;
|
||||
|
||||
/* Input is the contents of the input buffer. */
|
||||
outgoing_stream.next_in = buffer_ptr(input_buffer);
|
||||
outgoing_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
/* Loop compressing until deflate() returns with avail_out != 0. */
|
||||
do {
|
||||
/* Set up fixed-size output buffer. */
|
||||
outgoing_stream.next_out = buf;
|
||||
outgoing_stream.avail_out = sizeof(buf);
|
||||
|
||||
/* Compress as much data into the buffer as possible. */
|
||||
status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
/* Append compressed data to output_buffer. */
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - outgoing_stream.avail_out);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_BUF_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_compress: deflate returned %d", status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
while (outgoing_stream.avail_out == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||
* uncompressed using this function will form a single compressed data
|
||||
* stream; however, data will be flushed at the end of every call so that
|
||||
* each output_buffer. This must be called for the same size units that the
|
||||
* buffer_compress was called, and in the same order that buffers compressed
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
int status;
|
||||
|
||||
incoming_stream.next_in = buffer_ptr(input_buffer);
|
||||
incoming_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
|
||||
for (;;) {
|
||||
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_DATA_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
/*
|
||||
* Comments in zlib.h say that we should keep calling
|
||||
* inflate() until we get an error. This appears to
|
||||
* be the error that we get.
|
||||
*/
|
||||
return;
|
||||
case Z_MEM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_uncompress: inflate returned %d", status);
|
||||
}
|
||||
}
|
||||
}
|
50
crypto/openssh/compress.h
Normal file
50
crypto/openssh/compress.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* compress.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: compress.h,v 1.3 1999/11/24 19:53:46 markus Exp $"); */
|
||||
|
||||
#ifndef COMPRESS_H
|
||||
#define COMPRESS_H
|
||||
|
||||
/*
|
||||
* Initializes compression; level is compression level from 1 to 9 (as in
|
||||
* gzip).
|
||||
*/
|
||||
void buffer_compress_init(int level);
|
||||
|
||||
/* Frees any data structures allocated by buffer_compress_init. */
|
||||
void buffer_compress_uninit();
|
||||
|
||||
/*
|
||||
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||
* compressed using this function will form a single compressed data stream;
|
||||
* however, data will be flushed at the end of every call so that each
|
||||
* output_buffer can be decompressed independently (but in the appropriate
|
||||
* order since they together form a single compression stream) by the
|
||||
* receiver. This appends the compressed data to the output buffer.
|
||||
*/
|
||||
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
/*
|
||||
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||
* uncompressed using this function will form a single compressed data
|
||||
* stream; however, data will be flushed at the end of every call so that
|
||||
* each output_buffer. This must be called for the same size units that the
|
||||
* buffer_compress was called, and in the same order that buffers compressed
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
#endif /* COMPRESS_H */
|
121
crypto/openssh/crc32.c
Normal file
121
crypto/openssh/crc32.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* The implementation here was originally done by Gary S. Brown.
|
||||
* I have borrowed the tables directly, and made some minor changes
|
||||
* to the crc32-function (including changing the interface).
|
||||
* //ylo
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: crc32.c,v 1.4 1999/11/24 00:26:01 deraadt Exp $");
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
/* ============================================================= */
|
||||
/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
|
||||
/* code or tables extracted from it, as desired without restriction. */
|
||||
/* */
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
/* */
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
/* */
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* 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 */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
/* polynomial $edb88320 */
|
||||
/* */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static unsigned int crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
/* Return a 32-bit CRC of the contents of the buffer. */
|
||||
|
||||
unsigned int
|
||||
crc32(const unsigned char *s, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int crc32val;
|
||||
|
||||
crc32val = 0;
|
||||
for (i = 0; i < len; i ++) {
|
||||
crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
|
||||
}
|
||||
return crc32val;
|
||||
}
|
27
crypto/openssh/crc32.h
Normal file
27
crypto/openssh/crc32.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
*
|
||||
* crc32.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Tue Feb 11 14:37:27 1992 ylo
|
||||
*
|
||||
* Functions for computing 32-bit CRC.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: crc32.h,v 1.4 1999/11/24 19:53:46 markus Exp $"); */
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
||||
/*
|
||||
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
|
||||
* The polynomial used is 0xedb88320.
|
||||
*/
|
||||
unsigned int crc32(const unsigned char *buf, unsigned int len);
|
||||
|
||||
#endif /* CRC32_H */
|
155
crypto/openssh/deattack.c
Normal file
155
crypto/openssh/deattack.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* $Id: deattack.c,v 1.6 1999/11/24 00:26:01 deraadt Exp $
|
||||
* Cryptographic attack detector for ssh - source code
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "deattack.h"
|
||||
#include "ssh.h"
|
||||
#include "crc32.h"
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* SSH Constants */
|
||||
#define SSH_MAXBLOCKS (32 * 1024)
|
||||
#define SSH_BLOCKSIZE (8)
|
||||
|
||||
/* Hashing constants */
|
||||
#define HASH_MINSIZE (8 * 1024)
|
||||
#define HASH_ENTRYSIZE (2)
|
||||
#define HASH_FACTOR(x) ((x)*3/2)
|
||||
#define HASH_UNUSEDCHAR (0xff)
|
||||
#define HASH_UNUSED (0xffff)
|
||||
#define HASH_IV (0xfffe)
|
||||
|
||||
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
||||
|
||||
|
||||
/* Hash function (Input keys are cipher results) */
|
||||
#define HASH(x) GET_32BIT(x)
|
||||
|
||||
#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
|
||||
|
||||
|
||||
void
|
||||
crc_update(u_int32_t *a, u_int32_t b)
|
||||
{
|
||||
b ^= *a;
|
||||
*a = crc32((unsigned 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)
|
||||
{
|
||||
u_int32_t crc;
|
||||
unsigned char *c;
|
||||
|
||||
crc = 0;
|
||||
if (IV && !CMP(S, IV)) {
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (!CMP(S, c)) {
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
} else {
|
||||
crc_update(&crc, 0);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
}
|
||||
return (crc == 0);
|
||||
}
|
||||
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
int
|
||||
detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
|
||||
{
|
||||
static u_int16_t *h = (u_int16_t *) NULL;
|
||||
static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
register u_int32_t i, j;
|
||||
u_int32_t l;
|
||||
register unsigned char *c;
|
||||
unsigned char *d;
|
||||
|
||||
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0) {
|
||||
fatal("detect_attack: bad length %d", len);
|
||||
}
|
||||
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (h == NULL) {
|
||||
debug("Installing crc compensation attack detector.");
|
||||
n = l;
|
||||
h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
|
||||
} else {
|
||||
if (l > n) {
|
||||
n = l;
|
||||
h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= HASH_MINBLOCKS) {
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (IV && (!CMP(c, IV))) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
|
||||
if (!CMP(c, d)) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (DEATTACK_OK);
|
||||
}
|
||||
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
||||
|
||||
if (IV)
|
||||
h[HASH(IV) & (n - 1)] = HASH_IV;
|
||||
|
||||
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
|
||||
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (n - 1)) {
|
||||
if (h[i] == HASH_IV) {
|
||||
if (!CMP(c, IV)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
h[i] = j;
|
||||
}
|
||||
return (DEATTACK_OK);
|
||||
}
|
28
crypto/openssh/deattack.h
Normal file
28
crypto/openssh/deattack.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - Header file
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#ifndef _DEATTACK_H
|
||||
#define _DEATTACK_H
|
||||
|
||||
/* Return codes */
|
||||
#define DEATTACK_OK 0
|
||||
#define DEATTACK_DETECTED 1
|
||||
|
||||
int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]);
|
||||
#endif
|
69
crypto/openssh/fingerprint.c
Normal file
69
crypto/openssh/fingerprint.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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("$Id: fingerprint.c,v 1.4 1999/11/24 16:15:25 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include <ssl/md5.h>
|
||||
|
||||
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
/*
|
||||
* Generate key fingerprint in ascii format.
|
||||
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
|
||||
*/
|
||||
char *
|
||||
fingerprint(BIGNUM *e, BIGNUM *n)
|
||||
{
|
||||
static char retval[80];
|
||||
MD5_CTX md;
|
||||
unsigned char d[16];
|
||||
char *buf;
|
||||
int nlen, elen;
|
||||
|
||||
nlen = BN_num_bytes(n);
|
||||
elen = BN_num_bytes(e);
|
||||
|
||||
buf = xmalloc(nlen + elen);
|
||||
|
||||
BN_bn2bin(n, buf);
|
||||
BN_bn2bin(e, buf + nlen);
|
||||
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, nlen + elen);
|
||||
MD5_Final(d, &md);
|
||||
snprintf(retval, sizeof(retval), FPRINT,
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
memset(buf, 0, nlen + elen);
|
||||
xfree(buf);
|
||||
return retval;
|
||||
}
|
34
crypto/openssh/fingerprint.h
Normal file
34
crypto/openssh/fingerprint.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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.
|
||||
*/
|
||||
/* RCSID("$Id: fingerprint.h,v 1.3 1999/11/24 16:15:25 markus Exp $"); */
|
||||
|
||||
#ifndef FINGERPRINT_H
|
||||
#define FINGERPRINT_H
|
||||
char *fingerprint(BIGNUM * e, BIGNUM * n);
|
||||
#endif
|
63
crypto/openssh/getput.h
Normal file
63
crypto/openssh/getput.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
*
|
||||
* getput.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Jun 28 22:36:30 1995 ylo
|
||||
*
|
||||
* Macros for storing and retrieving data in msb first and lsb first order.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: getput.h,v 1.2 1999/11/24 00:26:02 deraadt 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_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \
|
||||
((unsigned long)(unsigned char)(cp)[1]))
|
||||
|
||||
#define PUT_32BIT(cp, value) do { \
|
||||
(cp)[0] = (value) >> 24; \
|
||||
(cp)[1] = (value) >> 16; \
|
||||
(cp)[2] = (value) >> 8; \
|
||||
(cp)[3] = (value); } while (0)
|
||||
|
||||
#define PUT_16BIT(cp, value) do { \
|
||||
(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 */
|
300
crypto/openssh/hostfile.c
Normal file
300
crypto/openssh/hostfile.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
*
|
||||
* hostfile.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Jun 29 07:10:56 1995 ylo
|
||||
*
|
||||
* Functions for manipulating the known hosts files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: hostfile.c,v 1.13 2000/02/18 10:20:20 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Reads a multiple-precision integer in decimal from the buffer, and advances
|
||||
* the pointer. The integer must already be initialized. This function is
|
||||
* permitted to modify the buffer. This leaves *cpp to point just beyond the
|
||||
* last processed (and maybe modified) character. Note that this may modify
|
||||
* the buffer containing the number.
|
||||
*/
|
||||
|
||||
int
|
||||
auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
||||
{
|
||||
char *cp = *cpp;
|
||||
int old;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Check that it begins with a decimal digit. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0;
|
||||
|
||||
/* Save starting position. */
|
||||
*cpp = cp;
|
||||
|
||||
/* Move forward until all decimal digits skipped. */
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
|
||||
/* Save the old terminating character, and replace it by \0. */
|
||||
old = *cp;
|
||||
*cp = 0;
|
||||
|
||||
/* Parse the number. */
|
||||
if (BN_dec2bn(&value, *cpp) == 0)
|
||||
return 0;
|
||||
|
||||
/* Restore old terminating character. */
|
||||
*cp = old;
|
||||
|
||||
/* Move beyond the number and return success. */
|
||||
*cpp = cp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
||||
{
|
||||
unsigned int bits;
|
||||
char *cp;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
|
||||
/* Get public exponent. */
|
||||
if (!auth_rsa_read_bignum(&cp, e))
|
||||
return 0;
|
||||
|
||||
/* Get public modulus. */
|
||||
if (!auth_rsa_read_bignum(&cp, n))
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
*bitsp = bits;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns true if there is a positive match; zero
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
match_hostname(const char *host, const char *pattern, unsigned int len)
|
||||
{
|
||||
char sub[1024];
|
||||
int negated;
|
||||
int got_positive;
|
||||
unsigned int i, subi;
|
||||
|
||||
got_positive = 0;
|
||||
for (i = 0; i < len;) {
|
||||
/* Check if the subpattern is negated. */
|
||||
if (pattern[i] == '!') {
|
||||
negated = 1;
|
||||
i++;
|
||||
} else
|
||||
negated = 0;
|
||||
|
||||
/*
|
||||
* Extract the subpattern up to a comma or end. Convert the
|
||||
* subpattern to lowercase.
|
||||
*/
|
||||
for (subi = 0;
|
||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||
subi++, i++)
|
||||
sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
|
||||
/* If subpattern too long, return failure (no match). */
|
||||
if (subi >= sizeof(sub) - 1)
|
||||
return 0;
|
||||
|
||||
/* If the subpattern was terminated by a comma, skip the comma. */
|
||||
if (i < len && pattern[i] == ',')
|
||||
i++;
|
||||
|
||||
/* Null-terminate the subpattern. */
|
||||
sub[subi] = '\0';
|
||||
|
||||
/* Try to match the subpattern against the host name. */
|
||||
if (match_pattern(host, sub)) {
|
||||
if (negated)
|
||||
return 0; /* Fail */
|
||||
else
|
||||
got_positive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return success if got a positive match. If there was a negative
|
||||
* match, we have already returned zero and never get here.
|
||||
*/
|
||||
return got_positive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the given host (which must be in all lowercase) is already
|
||||
* in the list of our known hosts. Returns HOST_OK if the host is known and
|
||||
* has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
|
||||
* if the host is known but used to have a different host key.
|
||||
*/
|
||||
|
||||
HostStatus
|
||||
check_host_in_hostfile(const char *filename, const char *host,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn)
|
||||
{
|
||||
FILE *f;
|
||||
char line[8192];
|
||||
int linenum = 0;
|
||||
unsigned int kbits, hostlen;
|
||||
char *cp, *cp2;
|
||||
HostStatus end_return;
|
||||
|
||||
/* Open the file containing the list of known hosts. */
|
||||
f = fopen(filename, "r");
|
||||
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
|
||||
* not found the proper one.
|
||||
*/
|
||||
end_return = HOST_NEW;
|
||||
|
||||
/* Go trough the file. */
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
cp = line;
|
||||
linenum++;
|
||||
|
||||
/* Skip any leading whitespace, comments and empty lines. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '#' || *cp == '\n')
|
||||
continue;
|
||||
|
||||
/* Find the end of the host name portion. */
|
||||
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
|
||||
;
|
||||
|
||||
/* Check if the host name matches. */
|
||||
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
|
||||
continue;
|
||||
|
||||
/* Got a match. Skip host name. */
|
||||
cp = cp2;
|
||||
|
||||
/*
|
||||
* Extract the key from the line. This will skip any leading
|
||||
* whitespace. Ignore badly formatted lines.
|
||||
*/
|
||||
if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
|
||||
continue;
|
||||
|
||||
if (kbits != BN_num_bits(kn)) {
|
||||
error("Warning: %s, line %d: keysize mismatch for host %s: "
|
||||
"actual %d vs. announced %d.",
|
||||
filename, linenum, host, BN_num_bits(kn), kbits);
|
||||
error("Warning: replace %d with %d in %s, line %d.",
|
||||
kbits, BN_num_bits(kn), filename, linenum);
|
||||
}
|
||||
/* Check if the current key is the same as the given key. */
|
||||
if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) {
|
||||
/* Ok, they match. */
|
||||
fclose(f);
|
||||
return HOST_OK;
|
||||
}
|
||||
/*
|
||||
* They do not match. We will continue to go through the
|
||||
* file; however, we note that we will not return that it is
|
||||
* new.
|
||||
*/
|
||||
end_return = HOST_CHANGED;
|
||||
}
|
||||
/* Clear variables and close the file. */
|
||||
fclose(f);
|
||||
|
||||
/*
|
||||
* Return either HOST_NEW or HOST_CHANGED, depending on whether we
|
||||
* saw a different key for the host.
|
||||
*/
|
||||
return end_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends an entry to the host file. Returns false if the entry could not
|
||||
* be appended.
|
||||
*/
|
||||
|
||||
int
|
||||
add_host_to_hostfile(const char *filename, const char *host,
|
||||
BIGNUM * e, BIGNUM * n)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
unsigned int bits;
|
||||
|
||||
/* Open the file for appending. */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(n);
|
||||
|
||||
/* Print the host name and key to the file. */
|
||||
fprintf(f, "%s %u ", host, bits);
|
||||
buf = BN_bn2dec(e);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(e) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s ", buf);
|
||||
free(buf);
|
||||
buf = BN_bn2dec(n);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(n) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s\n", buf);
|
||||
free(buf);
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
69
crypto/openssh/includes.h
Normal file
69
crypto/openssh/includes.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
*
|
||||
* includes.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Mar 23 16:29:37 1995 ylo
|
||||
*
|
||||
* This file includes most of the needed system headers.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
||||
#define RCSID(msg) \
|
||||
static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <netgroup.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <paths.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
/* Define this to be the path of the xauth program. */
|
||||
#define XAUTH_PATH "/usr/X11R6/bin/xauth"
|
||||
|
||||
/*
|
||||
* Define this to use pipes instead of socketpairs for communicating with the
|
||||
* client program. Socketpairs do not seem to work on all systems.
|
||||
*/
|
||||
#define USE_PIPES 1
|
||||
|
||||
#endif /* INCLUDES_H */
|
25
crypto/openssh/lib/Makefile
Normal file
25
crypto/openssh/lib/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
LIB= ssh
|
||||
SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
|
||||
cipher.c compat.c compress.c crc32.c deattack.c fingerprint.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
|
||||
|
||||
NOPROFILE= yes
|
||||
NOPIC= yes
|
||||
|
||||
install:
|
||||
@echo -n
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.if (${KERBEROS} == "yes")
|
||||
CFLAGS+= -DKRB4 -I/usr/include/kerberosIV
|
||||
.if (${AFS} == "yes")
|
||||
CFLAGS+= -DAFS
|
||||
SRCS+= radix.c
|
||||
.endif # AFS
|
||||
.endif # KERBEROS
|
||||
|
||||
.include <bsd.lib.mk>
|
62
crypto/openssh/log-client.c
Normal file
62
crypto/openssh/log-client.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* log-client.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 21:13:40 1995 ylo
|
||||
*
|
||||
* Client-side versions of debug(), log(), etc. These print to stderr.
|
||||
* This is a stripped down version of log-server.c.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-client.c,v 1.6 1999/11/24 00:26:02 deraadt Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
static LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
|
||||
/* Initialize the log.
|
||||
* av0 program name (should be argv[0])
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void
|
||||
log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
|
||||
{
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
/* unchanged */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MSGBUFSIZE 1024
|
||||
|
||||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
|
||||
if (level > log_level)
|
||||
return;
|
||||
if (level == SYSLOG_LEVEL_DEBUG)
|
||||
fprintf(stderr, "debug: ");
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
fprintf(stderr, "%s", msgbuf);
|
||||
fprintf(stderr, "\r\n");
|
||||
}
|
140
crypto/openssh/log-server.c
Normal file
140
crypto/openssh/log-server.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
*
|
||||
* log-server.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 21:19:30 1995 ylo
|
||||
*
|
||||
* Server-side versions of debug(), log(), etc. These normally send the output
|
||||
* to the system log.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-server.c,v 1.11 1999/11/24 00:26:02 deraadt Exp $");
|
||||
|
||||
#include <syslog.h>
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
static LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
static int log_on_stderr = 0;
|
||||
static int log_facility = LOG_AUTH;
|
||||
|
||||
/* Initialize the log.
|
||||
* av0 program name (should be argv[0])
|
||||
* on_stderr print also on stderr
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void
|
||||
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
{
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
|
||||
(int) level);
|
||||
exit(1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
log_on_stderr = on_stderr;
|
||||
}
|
||||
|
||||
#define MSGBUFSIZE 1024
|
||||
|
||||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
char fmtbuf[MSGBUFSIZE];
|
||||
char *txt = NULL;
|
||||
int pri = LOG_INFO;
|
||||
extern char *__progname;
|
||||
|
||||
if (level > log_level)
|
||||
return;
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
txt = "error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
txt = "fatal";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
pri = LOG_INFO;
|
||||
break;
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
txt = "debug";
|
||||
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\n", msgbuf);
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
}
|
184
crypto/openssh/log.c
Normal file
184
crypto/openssh/log.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Shared versions of debug(), log(), etc.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: log.c,v 1.7 2000/01/04 00:07:59 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* Fatal messages. This function never returns. */
|
||||
|
||||
void
|
||||
fatal(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_FATAL, fmt, args);
|
||||
va_end(args);
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Error messages that should be logged. */
|
||||
|
||||
void
|
||||
error(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_ERROR, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Log this message (information that usually should go to the log). */
|
||||
|
||||
void
|
||||
log(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_INFO, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* More detailed messages (information that does not need to go to the log). */
|
||||
|
||||
void
|
||||
verbose(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Debugging messages that should not be logged during normal operation. */
|
||||
|
||||
void
|
||||
debug(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_DEBUG, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Fatal cleanup */
|
||||
|
||||
struct fatal_cleanup {
|
||||
struct fatal_cleanup *next;
|
||||
void (*proc) (void *);
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct fatal_cleanup *fatal_cleanups = NULL;
|
||||
|
||||
/* Registers a cleanup function to be called by fatal() before exiting. */
|
||||
|
||||
void
|
||||
fatal_add_cleanup(void (*proc) (void *), void *context)
|
||||
{
|
||||
struct fatal_cleanup *cu;
|
||||
|
||||
cu = xmalloc(sizeof(*cu));
|
||||
cu->proc = proc;
|
||||
cu->context = context;
|
||||
cu->next = fatal_cleanups;
|
||||
fatal_cleanups = cu;
|
||||
}
|
||||
|
||||
/* Removes a cleanup frunction to be called at fatal(). */
|
||||
|
||||
void
|
||||
fatal_remove_cleanup(void (*proc) (void *context), void *context)
|
||||
{
|
||||
struct fatal_cleanup **cup, *cu;
|
||||
|
||||
for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
|
||||
cu = *cup;
|
||||
if (cu->proc == proc && cu->context == context) {
|
||||
*cup = cu->next;
|
||||
xfree(cu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
|
||||
(unsigned long) proc, (unsigned long) context);
|
||||
}
|
||||
|
||||
/* Cleanup and exit */
|
||||
void
|
||||
fatal_cleanup(void)
|
||||
{
|
||||
struct fatal_cleanup *cu, *next_cu;
|
||||
static int called = 0;
|
||||
|
||||
if (called)
|
||||
exit(255);
|
||||
called = 1;
|
||||
/* Call cleanup functions. */
|
||||
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);
|
||||
(*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 }
|
||||
};
|
||||
|
||||
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_DEBUG },
|
||||
{ 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;
|
||||
}
|
124
crypto/openssh/login.c
Normal file
124
crypto/openssh/login.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
*
|
||||
* login.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 24 14:51:08 1995 ylo
|
||||
*
|
||||
* This file performs some of the things login(1) normally does. We cannot
|
||||
* easily use something like login -p -h host -f user, because there are
|
||||
* several different logins around, and it is hard to determined what kind of
|
||||
* login the current system has. Also, we want to be able to execute commands
|
||||
* on a tty.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: login.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
|
||||
|
||||
#include <util.h>
|
||||
#include <utmp.h>
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Returns the time when the user last logged in. Returns 0 if the
|
||||
* information is not available. This must be called before record_login.
|
||||
* The host the user logged in from will be returned in buf.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Returns the time when the user last logged in (or 0 if no previous login
|
||||
* is found). The name of the host used last time is returned in buf.
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize)
|
||||
{
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
int fd;
|
||||
|
||||
lastlog = _PATH_LASTLOG;
|
||||
buf[0] = '\0';
|
||||
|
||||
fd = open(lastlog, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
|
||||
if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
if (bufsize > sizeof(ll.ll_host) + 1)
|
||||
bufsize = sizeof(ll.ll_host) + 1;
|
||||
strncpy(buf, ll.ll_host, bufsize - 1);
|
||||
buf[bufsize - 1] = 0;
|
||||
return ll.ll_time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Records that the user has logged in. I these parts of operating systems
|
||||
* were more standardized.
|
||||
*/
|
||||
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr * addr)
|
||||
{
|
||||
int fd;
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
struct utmp u;
|
||||
const char *utmp, *wtmp;
|
||||
|
||||
/* Construct an utmp/wtmp entry. */
|
||||
memset(&u, 0, sizeof(u));
|
||||
strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
|
||||
u.ut_time = time(NULL);
|
||||
strncpy(u.ut_name, user, sizeof(u.ut_name));
|
||||
strncpy(u.ut_host, host, sizeof(u.ut_host));
|
||||
|
||||
/* Figure out the file names. */
|
||||
utmp = _PATH_UTMP;
|
||||
wtmp = _PATH_WTMP;
|
||||
|
||||
login(&u);
|
||||
lastlog = _PATH_LASTLOG;
|
||||
|
||||
/* Update lastlog unless actually recording a logout. */
|
||||
if (strcmp(user, "") != 0) {
|
||||
/*
|
||||
* It is safer to bzero the lastlog structure first because
|
||||
* some systems might have some extra fields in it (e.g. SGI)
|
||||
*/
|
||||
memset(&ll, 0, sizeof(ll));
|
||||
|
||||
/* Update lastlog. */
|
||||
ll.ll_time = time(NULL);
|
||||
strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
|
||||
strncpy(ll.ll_host, host, sizeof(ll.ll_host));
|
||||
fd = open(lastlog, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
|
||||
if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
|
||||
log("Could not write %.100s: %.100s", lastlog, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Records that the user has logged out. */
|
||||
|
||||
void
|
||||
record_logout(int pid, const char *ttyname)
|
||||
{
|
||||
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
|
||||
if (logout(line))
|
||||
logwtmp(line, "", "");
|
||||
}
|
82
crypto/openssh/match.c
Normal file
82
crypto/openssh/match.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
*
|
||||
* match.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Jun 22 01:17:50 1995 ylo
|
||||
*
|
||||
* Simple pattern matching, with '*' and '?' as wildcards.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: match.c,v 1.4 1999/11/24 19:53:48 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Returns true if the given string matches the pattern (which may contain ?
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
|
||||
int
|
||||
match_pattern(const char *s, const char *pattern)
|
||||
{
|
||||
for (;;) {
|
||||
/* If at end of pattern, accept if also at end of string. */
|
||||
if (!*pattern)
|
||||
return !*s;
|
||||
|
||||
if (*pattern == '*') {
|
||||
/* Skip the asterisk. */
|
||||
pattern++;
|
||||
|
||||
/* If at end of pattern, accept immediately. */
|
||||
if (!*pattern)
|
||||
return 1;
|
||||
|
||||
/* If next character in pattern is known, optimize. */
|
||||
if (*pattern != '?' && *pattern != '*') {
|
||||
/*
|
||||
* Look instances of the next character in
|
||||
* pattern, and try to match starting from
|
||||
* those.
|
||||
*/
|
||||
for (; *s; s++)
|
||||
if (*s == *pattern &&
|
||||
match_pattern(s + 1, pattern + 1))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Move ahead one character at a time and try to
|
||||
* match at each position.
|
||||
*/
|
||||
for (; *s; s++)
|
||||
if (match_pattern(s, pattern))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* There must be at least one more character in the string.
|
||||
* If we are at the end, fail.
|
||||
*/
|
||||
if (!*s)
|
||||
return 0;
|
||||
|
||||
/* Check if the next character of the string is acceptable. */
|
||||
if (*pattern != '?' && *pattern != *s)
|
||||
return 0;
|
||||
|
||||
/* Move to the next character, both in string and in pattern. */
|
||||
s++;
|
||||
pattern++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
46
crypto/openssh/mpaux.c
Normal file
46
crypto/openssh/mpaux.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
*
|
||||
* mpaux.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: mpaux.c,v 1.9 1999/12/08 22:37:42 markus Exp $");
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned 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);
|
||||
MD5_CTX md;
|
||||
|
||||
BN_bn2bin(host_key_n, buf);
|
||||
BN_bn2bin(session_key_n, buf + host_key_bytes);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, bytes);
|
||||
MD5_Update(&md, cookie, 8);
|
||||
MD5_Final(session_id, &md);
|
||||
memset(buf, 0, bytes);
|
||||
xfree(buf);
|
||||
}
|
32
crypto/openssh/mpaux.h
Normal file
32
crypto/openssh/mpaux.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
*
|
||||
* mpaux.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: mpaux.h,v 1.5 1999/11/24 19:53:48 markus Exp $"); */
|
||||
|
||||
#ifndef MPAUX_H
|
||||
#define MPAUX_H
|
||||
|
||||
/*
|
||||
* Computes a 16-byte session id in the global variable session_id. The
|
||||
* session id is computed by concatenating the linearized, msb first
|
||||
* representations of host_key_n, session_key_n, and the cookie.
|
||||
*/
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM * host_key_n,
|
||||
BIGNUM * session_key_n);
|
||||
|
||||
#endif /* MPAUX_H */
|
238
crypto/openssh/nchan.c
Normal file
238
crypto/openssh/nchan.c
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "channels.h"
|
||||
#include "nchan.h"
|
||||
|
||||
static void chan_send_ieof(Channel *c);
|
||||
static void chan_send_oclose(Channel *c);
|
||||
static void chan_shutdown_write(Channel *c);
|
||||
static void chan_shutdown_read(Channel *c);
|
||||
static void chan_delete_if_full_closed(Channel *c);
|
||||
|
||||
/*
|
||||
* EVENTS update channel input/output states execute ACTIONS
|
||||
*/
|
||||
|
||||
/* events concerning the INPUT from socket for channel (istate) */
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
/* both local read_failed and remote write_failed */
|
||||
log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
chan_send_ieof(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
|
||||
return;
|
||||
}
|
||||
chan_delete_if_full_closed(c);
|
||||
}
|
||||
void
|
||||
chan_read_failed(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
|
||||
chan_shutdown_read(c);
|
||||
c->istate = CHAN_INPUT_WAIT_DRAIN;
|
||||
break;
|
||||
default:
|
||||
error("internal error: we do not read, but chan_read_failed %d for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_ibuf_empty(Channel *c)
|
||||
{
|
||||
if (buffer_len(&c->input)) {
|
||||
error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
|
||||
chan_send_ieof(c);
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* events concerning the OUTPUT from channel for socket (ostate) */
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_write_failed(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_obuf_empty(Channel *c)
|
||||
{
|
||||
if (buffer_len(&c->output)) {
|
||||
debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ACTIONS: should never update the channel states: c->istate or c->ostate
|
||||
*/
|
||||
static void
|
||||
chan_send_ieof(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
buffer_consume(&c->output, buffer_len(&c->output));
|
||||
packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper */
|
||||
static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug("channel %d: shutdown_write", c->self);
|
||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||
debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
}
|
||||
static void
|
||||
chan_shutdown_read(Channel *c)
|
||||
{
|
||||
debug("channel %d: shutdown_read", c->self);
|
||||
if (shutdown(c->sock, SHUT_RD) < 0)
|
||||
error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
|
||||
c->self, c->sock, c->istate, c->ostate, strerror(errno));
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
debug("channel %d: full closed", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_init_iostates(Channel *c)
|
||||
{
|
||||
c->ostate = CHAN_OUTPUT_OPEN;
|
||||
c->istate = CHAN_INPUT_OPEN;
|
||||
}
|
86
crypto/openssh/nchan.h
Normal file
86
crypto/openssh/nchan.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Markus Friedl.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: nchan.h,v 1.5 1999/11/24 16:15:25 markus Exp $"); */
|
||||
|
||||
#ifndef NCHAN_H
|
||||
#define NCHAN_H
|
||||
|
||||
/*
|
||||
* SSH Protocol 1.5 aka New Channel Protocol
|
||||
* Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
|
||||
* Written by Markus Friedl in October 1999
|
||||
*
|
||||
* Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
|
||||
* tear down of channels:
|
||||
*
|
||||
* 1.3: strict request-ack-protocol:
|
||||
* CLOSE ->
|
||||
* <- CLOSE_CONFIRM
|
||||
*
|
||||
* 1.5: uses variations of:
|
||||
* IEOF ->
|
||||
* <- OCLOSE
|
||||
* <- IEOF
|
||||
* OCLOSE ->
|
||||
* i.e. both sides have to close the channel
|
||||
*
|
||||
* See the debugging output from 'ssh -v' and 'sshd -d' of
|
||||
* ssh-1.2.27 as an example.
|
||||
*
|
||||
*/
|
||||
|
||||
/* ssh-proto-1.5 overloads prot-1.3-message-types */
|
||||
#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
|
||||
#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
|
||||
|
||||
/* possible input states */
|
||||
#define CHAN_INPUT_OPEN 0x01
|
||||
#define CHAN_INPUT_WAIT_DRAIN 0x02
|
||||
#define CHAN_INPUT_WAIT_OCLOSE 0x04
|
||||
#define CHAN_INPUT_CLOSED 0x08
|
||||
|
||||
/* possible output states */
|
||||
#define CHAN_OUTPUT_OPEN 0x10
|
||||
#define CHAN_OUTPUT_WAIT_DRAIN 0x20
|
||||
#define CHAN_OUTPUT_WAIT_IEOF 0x40
|
||||
#define CHAN_OUTPUT_CLOSED 0x80
|
||||
|
||||
/* EVENTS for the input state */
|
||||
void chan_rcvd_oclose(Channel * c);
|
||||
void chan_read_failed(Channel * c);
|
||||
void chan_ibuf_empty(Channel * c);
|
||||
|
||||
/* EVENTS for the output state */
|
||||
void chan_rcvd_ieof(Channel * c);
|
||||
void chan_write_failed(Channel * c);
|
||||
void chan_obuf_empty(Channel * c);
|
||||
|
||||
void chan_init_iostates(Channel * c);
|
||||
#endif
|
102
crypto/openssh/nchan.ms
Normal file
102
crypto/openssh/nchan.ms
Normal file
@ -0,0 +1,102 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1999 Markus Friedl. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by Markus Friedl.
|
||||
.\" 4. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.TL
|
||||
OpenSSH Channel Close Protocol 1.5 Implementation
|
||||
.SH
|
||||
Channel Input State Diagram
|
||||
.PS
|
||||
reset
|
||||
l=1
|
||||
s=1.2
|
||||
ellipsewid=s*ellipsewid
|
||||
boxwid=s*boxwid
|
||||
ellipseht=s*ellipseht
|
||||
S1: ellipse "INPUT" "OPEN"
|
||||
move right 2*l from last ellipse.e
|
||||
S4: ellipse "INPUT" "CLOSED"
|
||||
move down l from last ellipse.s
|
||||
S3: ellipse "INPUT" "WAIT" "OCLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "INPUT" "WAIT" "DRAIN"
|
||||
arrow "" "rcvd OCLOSE/" "shutdown_read" "send IEOF" from S1.e to S4.w
|
||||
arrow "ibuf_empty/" "send IEOF" from S2.e to S3.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "read_failed/" "shutdown_read" with .e at last arrow.c
|
||||
arrow from S3.n to S4.s
|
||||
box invis "rcvd OCLOSE/" "-" with .w at last arrow.c
|
||||
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
|
||||
arrow "start" "" from S1.w+(-0.5,0) to S1.w
|
||||
arrow from S2.ne to S4.sw
|
||||
box invis "rcvd OCLOSE/ " with .e at last arrow.c
|
||||
box invis " send IEOF" with .w at last arrow.c
|
||||
.PE
|
||||
.SH
|
||||
Channel Output State Diagram
|
||||
.PS
|
||||
S1: ellipse "OUTPUT" "OPEN"
|
||||
move right 2*l from last ellipse.e
|
||||
S3: ellipse "OUTPUT" "WAIT" "IEOF"
|
||||
move down l from last ellipse.s
|
||||
S4: ellipse "OUTPUT" "CLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "OUTPUT" "WAIT" "DRAIN"
|
||||
arrow "" "write_failed/" "shutdown_write" "send OCLOSE" from S1.e to S3.w
|
||||
arrow "obuf_empty ||" "write_failed/" "shutdown_write" "send OCLOSE" from S2.e to S4.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "rcvd IEOF/" "-" with .e at last arrow.c
|
||||
arrow from S3.s to S4.n
|
||||
box invis "rcvd IEOF/" "-" with .w at last arrow.c
|
||||
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
|
||||
arrow "start" "" from S1.w+(-0.5,0) to S1.w
|
||||
.PE
|
||||
.SH
|
||||
Notes
|
||||
.PP
|
||||
The input buffer is filled with data from the socket
|
||||
(the socket represents the local consumer/producer of the
|
||||
forwarded channel).
|
||||
The data is then sent over the INPUT-end (transmit-end) of the channel to the
|
||||
remote peer.
|
||||
Data sent by the peer is received on the OUTPUT-end (receive-end),
|
||||
saved in the output buffer and written to the socket.
|
||||
.PP
|
||||
If the local protocol instance has forwarded all data on the
|
||||
INPUT-end of the channel, it sends an IEOF message to the peer.
|
||||
If the peer receives the IEOF and has consumed all
|
||||
data he replies with an OCLOSE.
|
||||
When the local instance receives the OCLOSE
|
||||
he considers the INPUT-half of the channel closed.
|
||||
The peer has his OUTOUT-half closed.
|
||||
.PP
|
||||
A channel can be deallocated by a protocol instance
|
||||
if both the INPUT- and the OUTOUT-half on his
|
||||
side of the channel are closed.
|
||||
Note that when an instance is unable to consume the
|
||||
received data, he is permitted to send an OCLOSE
|
||||
before the matching IEOF is received.
|
845
crypto/openssh/packet.c
Normal file
845
crypto/openssh/packet.c
Normal file
@ -0,0 +1,845 @@
|
||||
/*
|
||||
*
|
||||
* packet.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 02:40:40 1995 ylo
|
||||
*
|
||||
* This file contains code implementing the packet protocol and communication
|
||||
* with the other side. This same code is used both on client and server side.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: packet.c,v 1.22 2000/02/05 10:13:11 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh.h"
|
||||
#include "crc32.h"
|
||||
#include "cipher.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include "compress.h"
|
||||
#include "deattack.h"
|
||||
|
||||
/*
|
||||
* This variable contains the file descriptors used for communicating with
|
||||
* the other side. connection_in is used for reading; connection_out for
|
||||
* writing. These can be the same descriptor, in which case it is assumed to
|
||||
* be a socket.
|
||||
*/
|
||||
static int connection_in = -1;
|
||||
static int connection_out = -1;
|
||||
|
||||
/*
|
||||
* Cipher type. This value is only used to determine whether to pad the
|
||||
* packets with zeroes or random data.
|
||||
*/
|
||||
static int cipher_type = SSH_CIPHER_NONE;
|
||||
|
||||
/* Protocol flags for the remote side. */
|
||||
static unsigned int remote_protocol_flags = 0;
|
||||
|
||||
/* Encryption context for receiving data. This is only used for decryption. */
|
||||
static CipherContext receive_context;
|
||||
|
||||
/* Encryption context for sending data. This is only used for encryption. */
|
||||
static CipherContext send_context;
|
||||
|
||||
/* Buffer for raw input data from the socket. */
|
||||
static Buffer input;
|
||||
|
||||
/* Buffer for raw output data going to the socket. */
|
||||
static Buffer output;
|
||||
|
||||
/* Buffer for the partial outgoing packet being constructed. */
|
||||
static Buffer outgoing_packet;
|
||||
|
||||
/* Buffer for the incoming packet currently being processed. */
|
||||
static Buffer incoming_packet;
|
||||
|
||||
/* Scratch buffer for packet compression/decompression. */
|
||||
static Buffer compression_buffer;
|
||||
|
||||
/* Flag indicating whether packet compression/decompression is enabled. */
|
||||
static int packet_compression = 0;
|
||||
|
||||
/* default maximum packet size */
|
||||
int max_packet_size = 32768;
|
||||
|
||||
/* Flag indicating whether this module has been initialized. */
|
||||
static int initialized = 0;
|
||||
|
||||
/* Set to true if the connection is interactive. */
|
||||
static int interactive_mode = 0;
|
||||
|
||||
/*
|
||||
* Sets the descriptors used for communication. Disables encryption until
|
||||
* packet_set_encryption_key is called.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_set_connection(int fd_in, int fd_out)
|
||||
{
|
||||
connection_in = fd_in;
|
||||
connection_out = fd_out;
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 1);
|
||||
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 0);
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
buffer_init(&input);
|
||||
buffer_init(&output);
|
||||
buffer_init(&outgoing_packet);
|
||||
buffer_init(&incoming_packet);
|
||||
}
|
||||
/* Kludge: arrange the close function to be called from fatal(). */
|
||||
fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
|
||||
}
|
||||
|
||||
/* Returns 1 if remote host is connected via socket, 0 if not. */
|
||||
|
||||
int
|
||||
packet_connection_is_on_socket()
|
||||
{
|
||||
struct sockaddr_storage from, to;
|
||||
socklen_t fromlen, tolen;
|
||||
|
||||
/* filedescriptors in and out are the same, so it's a socket */
|
||||
if (connection_in == connection_out)
|
||||
return 1;
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
|
||||
return 0;
|
||||
tolen = sizeof(to);
|
||||
memset(&to, 0, sizeof(to));
|
||||
if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
|
||||
return 0;
|
||||
if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
|
||||
return 0;
|
||||
if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns 1 if connection is via ipv4 */
|
||||
|
||||
int
|
||||
packet_connection_is_ipv4()
|
||||
{
|
||||
struct sockaddr_storage to;
|
||||
socklen_t tolen = sizeof(to);
|
||||
|
||||
memset(&to, 0, sizeof(to));
|
||||
if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
|
||||
return 0;
|
||||
if (to.ss_family != AF_INET)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sets the connection into non-blocking mode. */
|
||||
|
||||
void
|
||||
packet_set_nonblocking()
|
||||
{
|
||||
/* Set the socket into non-blocking mode. */
|
||||
if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
|
||||
error("fcntl O_NONBLOCK: %.100s", strerror(errno));
|
||||
|
||||
if (connection_out != connection_in) {
|
||||
if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
|
||||
error("fcntl O_NONBLOCK: %.100s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the socket used for reading. */
|
||||
|
||||
int
|
||||
packet_get_connection_in()
|
||||
{
|
||||
return connection_in;
|
||||
}
|
||||
|
||||
/* Returns the descriptor used for writing. */
|
||||
|
||||
int
|
||||
packet_get_connection_out()
|
||||
{
|
||||
return connection_out;
|
||||
}
|
||||
|
||||
/* Closes the connection and clears and frees internal data structures. */
|
||||
|
||||
void
|
||||
packet_close()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
initialized = 0;
|
||||
if (connection_in == connection_out) {
|
||||
shutdown(connection_out, SHUT_RDWR);
|
||||
close(connection_out);
|
||||
} else {
|
||||
close(connection_in);
|
||||
close(connection_out);
|
||||
}
|
||||
buffer_free(&input);
|
||||
buffer_free(&output);
|
||||
buffer_free(&outgoing_packet);
|
||||
buffer_free(&incoming_packet);
|
||||
if (packet_compression) {
|
||||
buffer_free(&compression_buffer);
|
||||
buffer_compress_uninit();
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets remote side protocol flags. */
|
||||
|
||||
void
|
||||
packet_set_protocol_flags(unsigned int protocol_flags)
|
||||
{
|
||||
remote_protocol_flags = protocol_flags;
|
||||
channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
|
||||
}
|
||||
|
||||
/* Returns the remote protocol flags set earlier by the above function. */
|
||||
|
||||
unsigned int
|
||||
packet_get_protocol_flags()
|
||||
{
|
||||
return remote_protocol_flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts packet compression from the next packet on in both directions.
|
||||
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_start_compression(int level)
|
||||
{
|
||||
if (packet_compression)
|
||||
fatal("Compression already enabled.");
|
||||
packet_compression = 1;
|
||||
buffer_init(&compression_buffer);
|
||||
buffer_compress_init(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypts the given number of bytes, copying from src to dest. bytes is
|
||||
* known to be a multiple of 8.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_encrypt(CipherContext * cc, void *dest, void *src,
|
||||
unsigned int bytes)
|
||||
{
|
||||
cipher_encrypt(cc, dest, src, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypts the given number of bytes, copying from src to dest. bytes is
|
||||
* known to be a multiple of 8.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
unsigned int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((bytes % 8) != 0)
|
||||
fatal("packet_decrypt: bad ciphertext length %d", bytes);
|
||||
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - Modifications for packet.c
|
||||
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
|
||||
*/
|
||||
|
||||
switch (cc->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
i = DEATTACK_OK;
|
||||
break;
|
||||
default:
|
||||
i = detect_attack(src, bytes, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == DEATTACK_DETECTED)
|
||||
packet_disconnect("crc32 compensation attack: network attack detected");
|
||||
|
||||
cipher_decrypt(cc, dest, src, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Causes any further packets to be encrypted using the given key. The same
|
||||
* key is used for both sending and reception. However, both directions are
|
||||
* encrypted independently of each other.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
int cipher)
|
||||
{
|
||||
/* All other ciphers use the same key in both directions for now. */
|
||||
cipher_set_key(&receive_context, cipher, key, keylen, 0);
|
||||
cipher_set_key(&send_context, cipher, key, keylen, 1);
|
||||
}
|
||||
|
||||
/* Starts constructing a packet to send. */
|
||||
|
||||
void
|
||||
packet_start(int type)
|
||||
{
|
||||
char buf[9];
|
||||
|
||||
buffer_clear(&outgoing_packet);
|
||||
memset(buf, 0, 8);
|
||||
buf[8] = type;
|
||||
buffer_append(&outgoing_packet, buf, 9);
|
||||
}
|
||||
|
||||
/* Appends a character to the packet data. */
|
||||
|
||||
void
|
||||
packet_put_char(int value)
|
||||
{
|
||||
char ch = value;
|
||||
buffer_append(&outgoing_packet, &ch, 1);
|
||||
}
|
||||
|
||||
/* Appends an integer to the packet data. */
|
||||
|
||||
void
|
||||
packet_put_int(unsigned int value)
|
||||
{
|
||||
buffer_put_int(&outgoing_packet, value);
|
||||
}
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
|
||||
void
|
||||
packet_put_string(const char *buf, unsigned int len)
|
||||
{
|
||||
buffer_put_string(&outgoing_packet, buf, len);
|
||||
}
|
||||
|
||||
/* Appends an arbitrary precision integer to packet data. */
|
||||
|
||||
void
|
||||
packet_put_bignum(BIGNUM * value)
|
||||
{
|
||||
buffer_put_bignum(&outgoing_packet, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalizes and sends the packet. If the encryption key has been set,
|
||||
* encrypts the packet before sending.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_send()
|
||||
{
|
||||
char buf[8], *cp;
|
||||
int i, padding, len;
|
||||
unsigned int checksum;
|
||||
u_int32_t rand = 0;
|
||||
|
||||
/*
|
||||
* If using packet compression, compress the payload of the outgoing
|
||||
* packet.
|
||||
*/
|
||||
if (packet_compression) {
|
||||
buffer_clear(&compression_buffer);
|
||||
/* Skip padding. */
|
||||
buffer_consume(&outgoing_packet, 8);
|
||||
/* padding */
|
||||
buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
|
||||
buffer_compress(&outgoing_packet, &compression_buffer);
|
||||
buffer_clear(&outgoing_packet);
|
||||
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
|
||||
buffer_len(&compression_buffer));
|
||||
}
|
||||
/* Compute packet length without padding (add checksum, remove padding). */
|
||||
len = buffer_len(&outgoing_packet) + 4 - 8;
|
||||
|
||||
/* Insert padding. */
|
||||
padding = 8 - len % 8;
|
||||
if (cipher_type != SSH_CIPHER_NONE) {
|
||||
cp = buffer_ptr(&outgoing_packet);
|
||||
for (i = 0; i < padding; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
cp[7 - i] = rand & 0xff;
|
||||
rand >>= 8;
|
||||
}
|
||||
}
|
||||
buffer_consume(&outgoing_packet, 8 - padding);
|
||||
|
||||
/* Add check bytes. */
|
||||
checksum = crc32((unsigned char *) buffer_ptr(&outgoing_packet),
|
||||
buffer_len(&outgoing_packet));
|
||||
PUT_32BIT(buf, checksum);
|
||||
buffer_append(&outgoing_packet, buf, 4);
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "packet_send plain: ");
|
||||
buffer_dump(&outgoing_packet);
|
||||
#endif
|
||||
|
||||
/* Append to output. */
|
||||
PUT_32BIT(buf, len);
|
||||
buffer_append(&output, buf, 4);
|
||||
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
|
||||
packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
|
||||
buffer_len(&outgoing_packet));
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "encrypted: ");
|
||||
buffer_dump(&output);
|
||||
#endif
|
||||
|
||||
buffer_clear(&outgoing_packet);
|
||||
|
||||
/*
|
||||
* Note that the packet is now only buffered in output. It won\'t be
|
||||
* actually sent until packet_write_wait or packet_write_poll is
|
||||
* called.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits until a packet has been received, and returns its type. Note that
|
||||
* no other data is processed until this returns, so this function should not
|
||||
* be used during the interactive session.
|
||||
*/
|
||||
|
||||
int
|
||||
packet_read(int *payload_len_ptr)
|
||||
{
|
||||
int type, len;
|
||||
fd_set set;
|
||||
char buf[8192];
|
||||
|
||||
/* Since we are blocking, ensure that all written packets have been sent. */
|
||||
packet_write_wait();
|
||||
|
||||
/* Stay in the loop until we have received a complete packet. */
|
||||
for (;;) {
|
||||
/* Try to read a packet from the buffer. */
|
||||
type = packet_read_poll(payload_len_ptr);
|
||||
if (type == SSH_SMSG_SUCCESS
|
||||
|| type == SSH_SMSG_FAILURE
|
||||
|| type == SSH_CMSG_EOF
|
||||
|| type == SSH_CMSG_EXIT_CONFIRMATION)
|
||||
packet_integrity_check(*payload_len_ptr, 0, type);
|
||||
/* If we got a packet, return it. */
|
||||
if (type != SSH_MSG_NONE)
|
||||
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);
|
||||
|
||||
/* Wait for some data to arrive. */
|
||||
select(connection_in + 1, &set, NULL, NULL, NULL);
|
||||
|
||||
/* Read data from the socket. */
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
log("Connection closed by %.200s", get_remote_ipaddr());
|
||||
fatal_cleanup();
|
||||
}
|
||||
if (len < 0)
|
||||
fatal("Read from socket failed: %.100s", strerror(errno));
|
||||
/* Append it to the buffer. */
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits until a packet has been received, verifies that its type matches
|
||||
* that given, and gives a fatal error and exits if there is a mismatch.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_read_expect(int *payload_len_ptr, int expected_type)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = packet_read(payload_len_ptr);
|
||||
if (type != expected_type)
|
||||
packet_disconnect("Protocol error: expected packet type %d, got %d",
|
||||
expected_type, type);
|
||||
}
|
||||
|
||||
/* Checks if a full packet is available in the data received so far via
|
||||
* packet_process_incoming. If so, reads the packet; otherwise returns
|
||||
* SSH_MSG_NONE. This does not wait for data from the connection.
|
||||
*
|
||||
* SSH_MSG_DISCONNECT is handled specially here. Also,
|
||||
* SSH_MSG_IGNORE messages are skipped by this function and are never returned
|
||||
* to higher levels.
|
||||
*
|
||||
* The returned payload_len does include space consumed by:
|
||||
* Packet length
|
||||
* Padding
|
||||
* Packet type
|
||||
* Check bytes
|
||||
*/
|
||||
|
||||
int
|
||||
packet_read_poll(int *payload_len_ptr)
|
||||
{
|
||||
unsigned int len, padded_len;
|
||||
unsigned char *ucp;
|
||||
char buf[8], *cp, *msg;
|
||||
unsigned int checksum, stored_checksum;
|
||||
|
||||
restart:
|
||||
|
||||
/* 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);
|
||||
len = GET_32BIT(ucp);
|
||||
if (len < 1 + 2 + 2 || len > 256 * 1024)
|
||||
packet_disconnect("Bad packet length %d.", len);
|
||||
padded_len = (len + 8) & ~7;
|
||||
|
||||
/* Check if the packet has been entirely received. */
|
||||
if (buffer_len(&input) < 4 + padded_len)
|
||||
return SSH_MSG_NONE;
|
||||
|
||||
/* The entire packet is in buffer. */
|
||||
|
||||
/* Consume packet length. */
|
||||
buffer_consume(&input, 4);
|
||||
|
||||
/* Copy data to incoming_packet. */
|
||||
buffer_clear(&incoming_packet);
|
||||
buffer_append_space(&incoming_packet, &cp, padded_len);
|
||||
packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
|
||||
buffer_consume(&input, padded_len);
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "read_poll plain: ");
|
||||
buffer_dump(&incoming_packet);
|
||||
#endif
|
||||
|
||||
/* Compute packet checksum. */
|
||||
checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet),
|
||||
buffer_len(&incoming_packet) - 4);
|
||||
|
||||
/* Skip padding. */
|
||||
buffer_consume(&incoming_packet, 8 - len % 8);
|
||||
|
||||
/* Test check bytes. */
|
||||
|
||||
if (len != buffer_len(&incoming_packet))
|
||||
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
|
||||
len, buffer_len(&incoming_packet));
|
||||
|
||||
ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
|
||||
stored_checksum = GET_32BIT(ucp);
|
||||
if (checksum != stored_checksum)
|
||||
packet_disconnect("Corrupted check bytes on input.");
|
||||
buffer_consume_end(&incoming_packet, 4);
|
||||
|
||||
/* If using packet compression, decompress the packet. */
|
||||
if (packet_compression) {
|
||||
buffer_clear(&compression_buffer);
|
||||
buffer_uncompress(&incoming_packet, &compression_buffer);
|
||||
buffer_clear(&incoming_packet);
|
||||
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
|
||||
buffer_len(&compression_buffer));
|
||||
}
|
||||
/* Get packet type. */
|
||||
buffer_get(&incoming_packet, &buf[0], 1);
|
||||
|
||||
/* Return length of payload (without type field). */
|
||||
*payload_len_ptr = buffer_len(&incoming_packet);
|
||||
|
||||
/* Handle disconnect message. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_DISCONNECT) {
|
||||
msg = packet_get_string(NULL);
|
||||
log("Received disconnect: %.900s", msg);
|
||||
xfree(msg);
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Ignore ignore messages. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_IGNORE)
|
||||
goto restart;
|
||||
|
||||
/* Send debug messages as debugging output. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_DEBUG) {
|
||||
msg = packet_get_string(NULL);
|
||||
debug("Remote: %.900s", msg);
|
||||
xfree(msg);
|
||||
goto restart;
|
||||
}
|
||||
/* Return type. */
|
||||
return (unsigned char) buf[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
buffer_append(&input, buf, len);
|
||||
}
|
||||
|
||||
/* Returns a character from the packet. */
|
||||
|
||||
unsigned int
|
||||
packet_get_char()
|
||||
{
|
||||
char ch;
|
||||
buffer_get(&incoming_packet, &ch, 1);
|
||||
return (unsigned char) ch;
|
||||
}
|
||||
|
||||
/* Returns an integer from the packet data. */
|
||||
|
||||
unsigned int
|
||||
packet_get_int()
|
||||
{
|
||||
return buffer_get_int(&incoming_packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an arbitrary precision integer from the packet data. The integer
|
||||
* must have been initialized before this call.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_get_bignum(BIGNUM * value, int *length_ptr)
|
||||
{
|
||||
*length_ptr = buffer_get_bignum(&incoming_packet, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a string from the packet data. The string is allocated using
|
||||
* xmalloc; it is the responsibility of the calling program to free it when
|
||||
* no longer needed. The length_ptr argument may be NULL, or point to an
|
||||
* integer into which the length of the string is stored.
|
||||
*/
|
||||
|
||||
char *
|
||||
packet_get_string(unsigned int *length_ptr)
|
||||
{
|
||||
return buffer_get_string(&incoming_packet, length_ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a diagnostic message from the server to the client. This message
|
||||
* can be sent at any time (but not while constructing another message). The
|
||||
* message is printed immediately, but only if the client is being executed
|
||||
* in verbose mode. These messages are primarily intended to ease debugging
|
||||
* authentication problems. The length of the formatted message must not
|
||||
* exceed 1024 bytes. This will automatically call packet_write_wait.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_send_debug(const char *fmt,...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
packet_start(SSH_MSG_DEBUG);
|
||||
packet_put_string(buf, strlen(buf));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
/*
|
||||
* Logs the error plus constructs and sends a disconnect packet, closes the
|
||||
* connection, and exits. This function never returns. The error message
|
||||
* should not contain a newline. The length of the formatted message must
|
||||
* not exceed 1024 bytes.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_disconnect(const char *fmt,...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
static int disconnecting = 0;
|
||||
if (disconnecting) /* Guard against recursive invocations. */
|
||||
fatal("packet_disconnect called recursively.");
|
||||
disconnecting = 1;
|
||||
|
||||
/*
|
||||
* Format the message. Note that the caller must make sure the
|
||||
* message is of limited size.
|
||||
*/
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
/* Send the disconnect message to the other side, and wait for it to get sent. */
|
||||
packet_start(SSH_MSG_DISCONNECT);
|
||||
packet_put_string(buf, strlen(buf));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Stop listening for connections. */
|
||||
channel_stop_listening();
|
||||
|
||||
/* Close the connection. */
|
||||
packet_close();
|
||||
|
||||
/* Display the error locally and exit. */
|
||||
log("Disconnecting: %.100s", buf);
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||
|
||||
void
|
||||
packet_write_poll()
|
||||
{
|
||||
int len = buffer_len(&output);
|
||||
if (len > 0) {
|
||||
len = write(connection_out, buffer_ptr(&output), len);
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
return;
|
||||
else
|
||||
fatal("Write failed: %.100s", strerror(errno));
|
||||
}
|
||||
buffer_consume(&output, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls packet_write_poll repeatedly until all pending output data has been
|
||||
* written.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_write_wait()
|
||||
{
|
||||
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);
|
||||
packet_write_poll();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if there is buffered data to write to the connection. */
|
||||
|
||||
int
|
||||
packet_have_data_to_write()
|
||||
{
|
||||
return buffer_len(&output) != 0;
|
||||
}
|
||||
|
||||
/* Returns true if there is not too much data to write to the connection. */
|
||||
|
||||
int
|
||||
packet_not_very_much_data_to_write()
|
||||
{
|
||||
if (interactive_mode)
|
||||
return buffer_len(&output) < 16384;
|
||||
else
|
||||
return buffer_len(&output) < 128 * 1024;
|
||||
}
|
||||
|
||||
/* Informs that the current session is interactive. Sets IP flags for that. */
|
||||
|
||||
void
|
||||
packet_set_interactive(int interactive, int keepalives)
|
||||
{
|
||||
int on = 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
|
||||
*/
|
||||
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 (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
|
||||
sizeof(on)) < 0)
|
||||
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
|
||||
} else {
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if the current connection is interactive. */
|
||||
|
||||
int
|
||||
packet_is_interactive()
|
||||
{
|
||||
return interactive_mode;
|
||||
}
|
||||
|
||||
int
|
||||
packet_set_maxsize(int s)
|
||||
{
|
||||
static int called = 0;
|
||||
if (called) {
|
||||
log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s);
|
||||
return -1;
|
||||
}
|
||||
if (s < 4 * 1024 || s > 1024 * 1024) {
|
||||
log("packet_set_maxsize: bad size %d", s);
|
||||
return -1;
|
||||
}
|
||||
log("packet_set_maxsize: setting to %d", s);
|
||||
max_packet_size = s;
|
||||
return s;
|
||||
}
|
198
crypto/openssh/packet.h
Normal file
198
crypto/openssh/packet.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
*
|
||||
* packet.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 02:02:14 1995 ylo
|
||||
*
|
||||
* Interface for the packet protocol functions.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: packet.h,v 1.9 2000/01/04 16:54:58 markus Exp $"); */
|
||||
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
||||
#include <ssl/bn.h>
|
||||
|
||||
/*
|
||||
* Sets the socket used for communication. Disables encryption until
|
||||
* packet_set_encryption_key is called. It is permissible that fd_in and
|
||||
* fd_out are the same descriptor; in that case it is assumed to be a socket.
|
||||
*/
|
||||
void packet_set_connection(int fd_in, int fd_out);
|
||||
|
||||
/* Puts the connection file descriptors into non-blocking mode. */
|
||||
void packet_set_nonblocking(void);
|
||||
|
||||
/* Returns the file descriptor used for input. */
|
||||
int packet_get_connection_in(void);
|
||||
|
||||
/* Returns the file descriptor used for output. */
|
||||
int packet_get_connection_out(void);
|
||||
|
||||
/*
|
||||
* Closes the connection (both descriptors) and clears and frees internal
|
||||
* data structures.
|
||||
*/
|
||||
void packet_close(void);
|
||||
|
||||
/*
|
||||
* Causes any further packets to be encrypted using the given key. The same
|
||||
* key is used for both sending and reception. However, both directions are
|
||||
* encrypted independently of each other. Cipher types are defined in ssh.h.
|
||||
*/
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned 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);
|
||||
|
||||
/* Returns the remote protocol flags set earlier by the above function. */
|
||||
unsigned int packet_get_protocol_flags(void);
|
||||
|
||||
/* Enables compression in both directions starting from the next packet. */
|
||||
void packet_start_compression(int level);
|
||||
|
||||
/*
|
||||
* Informs that the current session is interactive. Sets IP flags for
|
||||
* optimal performance in interactive use.
|
||||
*/
|
||||
void packet_set_interactive(int interactive, int keepalives);
|
||||
|
||||
/* Returns true if the current connection is interactive. */
|
||||
int packet_is_interactive(void);
|
||||
|
||||
/* Starts constructing a packet to send. */
|
||||
void packet_start(int type);
|
||||
|
||||
/* Appends a character to the packet data. */
|
||||
void packet_put_char(int ch);
|
||||
|
||||
/* Appends an integer to the packet data. */
|
||||
void packet_put_int(unsigned int value);
|
||||
|
||||
/* Appends an arbitrary precision integer to packet data. */
|
||||
void packet_put_bignum(BIGNUM * value);
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
|
||||
/*
|
||||
* Finalizes and sends the packet. If the encryption key has been set,
|
||||
* encrypts the packet before sending.
|
||||
*/
|
||||
void packet_send(void);
|
||||
|
||||
/* Waits until a packet has been received, and returns its type. */
|
||||
int packet_read(int *payload_len_ptr);
|
||||
|
||||
/*
|
||||
* Waits until a packet has been received, verifies that its type matches
|
||||
* that given, and gives a fatal error and exits if there is a mismatch.
|
||||
*/
|
||||
void packet_read_expect(int *payload_len_ptr, int type);
|
||||
|
||||
/*
|
||||
* Checks if a full packet is available in the data received so far via
|
||||
* packet_process_incoming. If so, reads the packet; otherwise returns
|
||||
* SSH_MSG_NONE. This does not wait for data from the connection.
|
||||
* SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
|
||||
* messages are skipped by this function and are never returned to higher
|
||||
* levels.
|
||||
*/
|
||||
int packet_read_poll(int *packet_len_ptr);
|
||||
|
||||
/*
|
||||
* Buffers the given amount of input characters. This is intended to be used
|
||||
* together with packet_read_poll.
|
||||
*/
|
||||
void packet_process_incoming(const char *buf, unsigned int len);
|
||||
|
||||
/* Returns a character (0-255) from the packet data. */
|
||||
unsigned int packet_get_char(void);
|
||||
|
||||
/* Returns an integer from the packet data. */
|
||||
unsigned int packet_get_int(void);
|
||||
|
||||
/*
|
||||
* Returns an arbitrary precision integer from the packet data. The integer
|
||||
* must have been initialized before this call.
|
||||
*/
|
||||
void packet_get_bignum(BIGNUM * value, int *length_ptr);
|
||||
|
||||
/*
|
||||
* Returns a string from the packet data. The string is allocated using
|
||||
* xmalloc; it is the responsibility of the calling program to free it when
|
||||
* no longer needed. The length_ptr argument may be NULL, or point to an
|
||||
* integer into which the length of the string is stored.
|
||||
*/
|
||||
char *packet_get_string(unsigned int *length_ptr);
|
||||
|
||||
/*
|
||||
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
|
||||
* packet, closes the connection, and exits. This function never returns.
|
||||
* The error message should not contain a newline. The total length of the
|
||||
* message must not exceed 1024 bytes.
|
||||
*/
|
||||
void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));;
|
||||
|
||||
/*
|
||||
* Sends a diagnostic message to the other side. This message can be sent at
|
||||
* any time (but not while constructing another message). The message is
|
||||
* printed immediately, but only if the client is being executed in verbose
|
||||
* mode. These messages are primarily intended to ease debugging
|
||||
* authentication problems. The total length of the message must not exceed
|
||||
* 1024 bytes. This will automatically call packet_write_wait. If the
|
||||
* remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
|
||||
* this will do nothing.
|
||||
*/
|
||||
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));;
|
||||
|
||||
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||
void packet_write_poll(void);
|
||||
|
||||
/* Waits until all pending output data has been written. */
|
||||
void packet_write_wait(void);
|
||||
|
||||
/* Returns true if there is buffered data to write to the connection. */
|
||||
int packet_have_data_to_write(void);
|
||||
|
||||
/* Returns true if there is not too much data to write to the connection. */
|
||||
int packet_not_very_much_data_to_write(void);
|
||||
|
||||
/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */
|
||||
extern int max_packet_size;
|
||||
int packet_set_maxsize(int s);
|
||||
#define packet_get_maxsize() max_packet_size
|
||||
|
||||
/* Stores tty modes from the fd into current packet. */
|
||||
void tty_make_modes(int fd);
|
||||
|
||||
/* Parses tty modes for the fd from the current packet. */
|
||||
void tty_parse_modes(int fd, int *n_bytes_ptr);
|
||||
|
||||
#define packet_integrity_check(payload_len, expected_len, type) \
|
||||
do { \
|
||||
int _p = (payload_len), _e = (expected_len); \
|
||||
if (_p != _e) { \
|
||||
log("Packet integrity error (%d != %d) at %s:%d", \
|
||||
_p, _e, __FILE__, __LINE__); \
|
||||
packet_disconnect("Packet integrity error. (%d)", (type)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remote host is connected via a socket/ipv4 */
|
||||
int packet_connection_is_on_socket(void);
|
||||
int packet_connection_is_ipv4(void);
|
||||
|
||||
#endif /* PACKET_H */
|
277
crypto/openssh/pty.c
Normal file
277
crypto/openssh/pty.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
*
|
||||
* pty.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 04:37:25 1995 ylo
|
||||
*
|
||||
* Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: pty.c,v 1.12 2000/02/15 16:52:58 markus Exp $");
|
||||
|
||||
#include <util.h>
|
||||
#include "pty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
|
||||
#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
|
||||
#undef HAVE_DEV_PTMX
|
||||
#endif
|
||||
|
||||
#ifndef O_NOCTTY
|
||||
#define O_NOCTTY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
||||
* nonzero if a pty was successfully allocated. On success, open file
|
||||
* descriptors for the pty and tty sides and the name of the tty side are
|
||||
* returned (the buffer must be able to hold at least 64 characters).
|
||||
*/
|
||||
|
||||
int
|
||||
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
{
|
||||
#if defined(HAVE_OPENPTY) || defined(BSD4_4)
|
||||
/* openpty(3) exists in OSF/1 and some other os'es */
|
||||
char buf[64];
|
||||
int i;
|
||||
|
||||
i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
|
||||
if (i < 0) {
|
||||
error("openpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
strlcpy(namebuf, buf, namebuflen); /* possible truncation */
|
||||
return 1;
|
||||
#else /* HAVE_OPENPTY */
|
||||
#ifdef HAVE__GETPTY
|
||||
/*
|
||||
* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
|
||||
* pty's automagically when needed
|
||||
*/
|
||||
char *slave;
|
||||
|
||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||
if (slave == NULL) {
|
||||
error("_getpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
strlcpy(namebuf, slave, namebuflen);
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.200s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE__GETPTY */
|
||||
#ifdef HAVE_DEV_PTMX
|
||||
/*
|
||||
* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
|
||||
* also has bsd-style ptys, but they simply do not work.)
|
||||
*/
|
||||
int ptm;
|
||||
char *pts;
|
||||
|
||||
ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
|
||||
if (ptm < 0) {
|
||||
error("/dev/ptmx: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (grantpt(ptm) < 0) {
|
||||
error("grantpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (unlockpt(ptm) < 0) {
|
||||
error("unlockpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
pts = ptsname(ptm);
|
||||
if (pts == NULL)
|
||||
error("Slave pty side name could not be obtained.");
|
||||
strlcpy(namebuf, pts, namebuflen);
|
||||
*ptyfd = ptm;
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
/* Push the appropriate streams modules, as described in Solaris pts(7). */
|
||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
||||
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
||||
error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
|
||||
error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
|
||||
return 1;
|
||||
#else /* HAVE_DEV_PTMX */
|
||||
#ifdef HAVE_DEV_PTS_AND_PTC
|
||||
/* AIX-style pty code. */
|
||||
const char *name;
|
||||
|
||||
*ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0) {
|
||||
error("Could not open /dev/ptc: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
name = ttyname(*ptyfd);
|
||||
if (!name)
|
||||
fatal("Open of /dev/ptc returns device for which ttyname fails.");
|
||||
strlcpy(namebuf, name, namebuflen);
|
||||
*ttyfd = open(name, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("Could not open pty slave side %.100s: %.100s",
|
||||
name, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE_DEV_PTS_AND_PTC */
|
||||
/* BSD-style pty code. */
|
||||
char buf[64];
|
||||
int i;
|
||||
const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptyminors = "0123456789abcdef";
|
||||
int num_minors = strlen(ptyminors);
|
||||
int num_ptys = strlen(ptymajors) * num_minors;
|
||||
|
||||
for (i = 0; i < num_ptys; i++) {
|
||||
snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0)
|
||||
continue;
|
||||
snprintf(namebuf, namebuflen, "/dev/tty%c%c",
|
||||
ptymajors[i / num_minors], ptyminors[i % num_minors]);
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif /* HAVE_DEV_PTS_AND_PTC */
|
||||
#endif /* HAVE_DEV_PTMX */
|
||||
#endif /* HAVE__GETPTY */
|
||||
#endif /* HAVE_OPENPTY */
|
||||
}
|
||||
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
|
||||
|
||||
void
|
||||
pty_release(const char *ttyname)
|
||||
{
|
||||
if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
|
||||
error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
|
||||
if (chmod(ttyname, (mode_t) 0666) < 0)
|
||||
error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
|
||||
}
|
||||
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes. */
|
||||
|
||||
void
|
||||
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* First disconnect from the old controlling tty. */
|
||||
#ifdef TIOCNOTTY
|
||||
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
(void) ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif /* TIOCNOTTY */
|
||||
if (setsid() < 0)
|
||||
error("setsid: %.100s", strerror(errno));
|
||||
|
||||
/*
|
||||
* Verify that we are successfully disconnected from the controlling
|
||||
* tty.
|
||||
*/
|
||||
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
error("Failed to disconnect from controlling tty.");
|
||||
close(fd);
|
||||
}
|
||||
/* Make it our controlling tty. */
|
||||
#ifdef TIOCSCTTY
|
||||
debug("Setting controlling tty using TIOCSCTTY.");
|
||||
/*
|
||||
* We ignore errors from this, because HPSUX defines TIOCSCTTY, but
|
||||
* returns EINVAL with these arguments, and there is absolutely no
|
||||
* documentation.
|
||||
*/
|
||||
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
||||
#endif /* TIOCSCTTY */
|
||||
fd = open(ttyname, O_RDWR);
|
||||
if (fd < 0)
|
||||
error("%.100s: %.100s", ttyname, strerror(errno));
|
||||
else
|
||||
close(fd);
|
||||
|
||||
/* Verify that we now have a controlling tty. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0)
|
||||
error("open /dev/tty failed - could not set controlling tty: %.100s",
|
||||
strerror(errno));
|
||||
else {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel)
|
||||
{
|
||||
struct winsize w;
|
||||
w.ws_row = row;
|
||||
w.ws_col = col;
|
||||
w.ws_xpixel = xpixel;
|
||||
w.ws_ypixel = ypixel;
|
||||
(void) ioctl(ptyfd, TIOCSWINSZ, &w);
|
||||
}
|
||||
|
||||
void
|
||||
pty_setowner(struct passwd *pw, const char *ttyname)
|
||||
{
|
||||
struct group *grp;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
|
||||
/* Determine the group to make the owner of the tty. */
|
||||
grp = getgrnam("tty");
|
||||
if (grp) {
|
||||
gid = grp->gr_gid;
|
||||
mode = S_IRUSR | S_IWUSR | S_IWGRP;
|
||||
} else {
|
||||
gid = pw->pw_gid;
|
||||
mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
}
|
||||
|
||||
/* Change ownership of the tty. */
|
||||
if (chown(ttyname, pw->pw_uid, gid) < 0)
|
||||
fatal("chown(%.100s, %d, %d) failed: %.100s",
|
||||
ttyname, pw->pw_uid, gid, strerror(errno));
|
||||
if (chmod(ttyname, mode) < 0)
|
||||
fatal("chmod(%.100s, 0%o) failed: %.100s",
|
||||
ttyname, mode, strerror(errno));
|
||||
}
|
48
crypto/openssh/pty.h
Normal file
48
crypto/openssh/pty.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
*
|
||||
* pty.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 05:03:28 1995 ylo
|
||||
*
|
||||
* Functions for allocating a pseudo-terminal and making it the controlling
|
||||
* tty.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: pty.h,v 1.5 2000/02/15 16:52:58 markus Exp $"); */
|
||||
|
||||
#ifndef PTY_H
|
||||
#define PTY_H
|
||||
|
||||
/*
|
||||
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
||||
* nonzero if a pty was successfully allocated. On success, open file
|
||||
* descriptors for the pty and tty sides and the name of the tty side are
|
||||
* returned (the buffer must be able to hold at least 64 characters).
|
||||
*/
|
||||
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname, int ttynamelen);
|
||||
|
||||
/*
|
||||
* Releases the tty. Its ownership is returned to root, and permissions to
|
||||
* 0666.
|
||||
*/
|
||||
void pty_release(const char *ttyname);
|
||||
|
||||
/*
|
||||
* Makes the tty the processes controlling tty and sets it to sane modes.
|
||||
* This may need to reopen the tty to get rid of possible eavesdroppers.
|
||||
*/
|
||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel);
|
||||
|
||||
void pty_setowner(struct passwd *pw, const char *ttyname);
|
||||
|
||||
#endif /* PTY_H */
|
285
crypto/openssh/radix.c
Normal file
285
crypto/openssh/radix.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* radix.c
|
||||
*
|
||||
* base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
|
||||
* Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
|
||||
* and placed in the public domain.
|
||||
*
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef AFS
|
||||
#include <krb.h>
|
||||
|
||||
char six2pr[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
unsigned char pr2six[256];
|
||||
|
||||
int
|
||||
uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||||
{
|
||||
/* ENC is the basic 1 character encoding function to make a char printing */
|
||||
#define ENC(c) six2pr[c]
|
||||
|
||||
register char *outptr = bufcoded;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nbytes; i += 3) {
|
||||
*(outptr++) = ENC(*bufin >> 2); /* c1 */
|
||||
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
|
||||
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
|
||||
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
|
||||
bufin += 3;
|
||||
}
|
||||
if (i == nbytes + 1) {
|
||||
outptr[-1] = '=';
|
||||
} else if (i == nbytes + 2) {
|
||||
outptr[-1] = '=';
|
||||
outptr[-2] = '=';
|
||||
}
|
||||
*outptr = '\0';
|
||||
return (outptr - bufcoded);
|
||||
}
|
||||
|
||||
int
|
||||
uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
||||
{
|
||||
/* single character decode */
|
||||
#define DEC(c) pr2six[(unsigned char)c]
|
||||
#define MAXVAL 63
|
||||
|
||||
static int first = 1;
|
||||
int nbytesdecoded, j;
|
||||
const char *bufin = bufcoded;
|
||||
register unsigned char *bufout = bufplain;
|
||||
register int nprbytes;
|
||||
|
||||
/* If this is the first call, initialize the mapping table. */
|
||||
if (first) {
|
||||
first = 0;
|
||||
for (j = 0; j < 256; j++)
|
||||
pr2six[j] = MAXVAL + 1;
|
||||
for (j = 0; j < 64; j++)
|
||||
pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
|
||||
}
|
||||
/* Strip leading whitespace. */
|
||||
while (*bufcoded == ' ' || *bufcoded == '\t')
|
||||
bufcoded++;
|
||||
|
||||
/*
|
||||
* Figure out how many characters are in the input buffer. If this
|
||||
* would decode into more bytes than would fit into the output
|
||||
* buffer, adjust the number of input bytes downwards.
|
||||
*/
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
|
||||
if (nbytesdecoded > outbufsize)
|
||||
nprbytes = (outbufsize * 4) / 3;
|
||||
|
||||
bufin = bufcoded;
|
||||
|
||||
while (nprbytes > 0) {
|
||||
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
|
||||
bufin += 4;
|
||||
nprbytes -= 4;
|
||||
}
|
||||
if (nprbytes & 03) {
|
||||
if (DEC(bufin[-2]) > MAXVAL)
|
||||
nbytesdecoded -= 2;
|
||||
else
|
||||
nbytesdecoded -= 1;
|
||||
}
|
||||
return (nbytesdecoded);
|
||||
}
|
||||
|
||||
typedef unsigned char my_u_char;
|
||||
typedef unsigned int my_u_int32_t;
|
||||
typedef unsigned 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); \
|
||||
(s) = (((my_u_short)t_cp[0]) << 8) \
|
||||
| (((my_u_short)t_cp[1])) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define GETLONG(l, 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) \
|
||||
| (((my_u_int32_t)t_cp[3])) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define PUTSHORT(s, cp) { \
|
||||
register my_u_short t_s = (my_u_short)(s); \
|
||||
register my_u_char *t_cp = (my_u_char*)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define PUTLONG(l, cp) { \
|
||||
register my_u_int32_t t_l = (my_u_int32_t)(l); \
|
||||
register my_u_char *t_cp = (my_u_char*)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define GETSTRING(s, p, p_l) { \
|
||||
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++; \
|
||||
} \
|
||||
if (p_c == p_targ) { \
|
||||
return 1; \
|
||||
} \
|
||||
*s_c = *p_c++; \
|
||||
(p_l) = (p_l) - (p_c - (p)); \
|
||||
(p) = p_c; \
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
|
||||
{
|
||||
char *p, *s;
|
||||
int len;
|
||||
char temp[2048];
|
||||
|
||||
p = temp;
|
||||
*p++ = 1; /* version */
|
||||
s = creds->service;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->instance;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->realm;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
|
||||
s = creds->pname;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->pinst;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
/* Null string to repeat the realm. */
|
||||
*p++ = '\0';
|
||||
|
||||
PUTLONG(creds->issue_date, p);
|
||||
{
|
||||
unsigned int endTime;
|
||||
endTime = (unsigned int) krb_life_to_time(creds->issue_date,
|
||||
creds->lifetime);
|
||||
PUTLONG(endTime, p);
|
||||
}
|
||||
|
||||
memcpy(p, &creds->session, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
|
||||
PUTSHORT(creds->kvno, p);
|
||||
PUTLONG(creds->ticket_st.length, p);
|
||||
|
||||
memcpy(p, creds->ticket_st.dat, creds->ticket_st.length);
|
||||
p += creds->ticket_st.length;
|
||||
len = p - temp;
|
||||
|
||||
return (uuencode(temp, len, buf));
|
||||
}
|
||||
|
||||
int
|
||||
radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
{
|
||||
|
||||
char *p;
|
||||
int len, tl;
|
||||
char version;
|
||||
char temp[2048];
|
||||
|
||||
if (!(len = uudecode(buf, temp, sizeof(temp))))
|
||||
return 0;
|
||||
|
||||
p = temp;
|
||||
|
||||
/* check version and length! */
|
||||
if (len < 1)
|
||||
return 0;
|
||||
version = *p;
|
||||
p++;
|
||||
len--;
|
||||
|
||||
GETSTRING(creds->service, p, len);
|
||||
GETSTRING(creds->instance, p, len);
|
||||
GETSTRING(creds->realm, p, len);
|
||||
|
||||
GETSTRING(creds->pname, p, len);
|
||||
GETSTRING(creds->pinst, p, len);
|
||||
/* Ignore possibly different realm. */
|
||||
while (*p && len)
|
||||
p++, len--;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
p++, len--;
|
||||
|
||||
/* Enough space for remaining fixed-length parts? */
|
||||
if (len < (4 + 4 + sizeof(creds->session) + 2 + 4))
|
||||
return 0;
|
||||
|
||||
GETLONG(creds->issue_date, p);
|
||||
len -= 4;
|
||||
{
|
||||
unsigned int endTime;
|
||||
GETLONG(endTime, p);
|
||||
len -= 4;
|
||||
creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
|
||||
}
|
||||
|
||||
memcpy(&creds->session, p, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
len -= sizeof(creds->session);
|
||||
|
||||
GETSHORT(creds->kvno, p);
|
||||
len -= 2;
|
||||
GETLONG(creds->ticket_st.length, p);
|
||||
len -= 4;
|
||||
|
||||
tl = creds->ticket_st.length;
|
||||
if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
|
||||
return 0;
|
||||
|
||||
memcpy(creds->ticket_st.dat, p, tl);
|
||||
p += tl;
|
||||
len -= tl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* AFS */
|
708
crypto/openssh/readconf.c
Normal file
708
crypto/openssh/readconf.c
Normal file
@ -0,0 +1,708 @@
|
||||
/*
|
||||
*
|
||||
* readconf.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Apr 22 00:03:10 1995 ylo
|
||||
*
|
||||
* Functions for reading the configuration files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: readconf.c,v 1.22 1999/12/01 13:59:15 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "readconf.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* Format of the configuration file:
|
||||
|
||||
# Configuration data is parsed as follows:
|
||||
# 1. command line options
|
||||
# 2. user-specific file
|
||||
# 3. system-wide file
|
||||
# Any configuration value is only changed the first time it is set.
|
||||
# Thus, host-specific definitions should be at the beginning of the
|
||||
# configuration file, and defaults at the end.
|
||||
|
||||
# Host-specific declarations. These may override anything above. A single
|
||||
# host may match multiple declarations; these are processed in the order
|
||||
# that they are given in.
|
||||
|
||||
Host *.ngs.fi ngs.fi
|
||||
FallBackToRsh no
|
||||
|
||||
Host fake.com
|
||||
HostName another.host.name.real.org
|
||||
User blaah
|
||||
Port 34289
|
||||
ForwardX11 no
|
||||
ForwardAgent no
|
||||
|
||||
Host books.com
|
||||
RemoteForward 9999 shadows.cs.hut.fi:9999
|
||||
Cipher 3des
|
||||
|
||||
Host fascist.blob.com
|
||||
Port 23123
|
||||
User tylonen
|
||||
RhostsAuthentication no
|
||||
PasswordAuthentication no
|
||||
|
||||
Host puukko.hut.fi
|
||||
User t35124p
|
||||
ProxyCommand ssh-proxy %h %p
|
||||
|
||||
Host *.fr
|
||||
UseRsh yes
|
||||
|
||||
Host *.su
|
||||
Cipher none
|
||||
PasswordAuthentication no
|
||||
|
||||
# Defaults for various options
|
||||
Host *
|
||||
ForwardAgent no
|
||||
ForwardX11 yes
|
||||
RhostsAuthentication yes
|
||||
PasswordAuthentication yes
|
||||
RSAAuthentication yes
|
||||
RhostsRSAAuthentication yes
|
||||
FallBackToRsh no
|
||||
UseRsh no
|
||||
StrictHostKeyChecking yes
|
||||
KeepAlives no
|
||||
IdentityFile ~/.ssh/identity
|
||||
Port 22
|
||||
EscapeChar ~
|
||||
|
||||
*/
|
||||
|
||||
/* Keyword tokens. */
|
||||
|
||||
typedef enum {
|
||||
oBadOption,
|
||||
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
|
||||
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
|
||||
oSkeyAuthentication,
|
||||
#ifdef KRB4
|
||||
oKerberosAuthentication,
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
oKerberosTgtPassing, oAFSTokenPassing,
|
||||
#endif
|
||||
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
|
||||
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
|
||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||
oUsePrivilegedPort, oLogLevel
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
OpCodes opcode;
|
||||
} keywords[] = {
|
||||
{ "forwardagent", oForwardAgent },
|
||||
{ "forwardx11", oForwardX11 },
|
||||
{ "gatewayports", oGatewayPorts },
|
||||
{ "useprivilegedport", oUsePrivilegedPort },
|
||||
{ "rhostsauthentication", oRhostsAuthentication },
|
||||
{ "passwordauthentication", oPasswordAuthentication },
|
||||
{ "rsaauthentication", oRSAAuthentication },
|
||||
{ "skeyauthentication", oSkeyAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", oKerberosAuthentication },
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
{ "kerberostgtpassing", oKerberosTgtPassing },
|
||||
{ "afstokenpassing", oAFSTokenPassing },
|
||||
#endif
|
||||
{ "fallbacktorsh", oFallBackToRsh },
|
||||
{ "usersh", oUseRsh },
|
||||
{ "identityfile", oIdentityFile },
|
||||
{ "hostname", oHostName },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
{ "port", oPort },
|
||||
{ "cipher", oCipher },
|
||||
{ "remoteforward", oRemoteForward },
|
||||
{ "localforward", oLocalForward },
|
||||
{ "user", oUser },
|
||||
{ "host", oHost },
|
||||
{ "escapechar", oEscapeChar },
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "connectionattempts", oConnectionAttempts },
|
||||
{ "batchmode", oBatchMode },
|
||||
{ "checkhostip", oCheckHostIP },
|
||||
{ "stricthostkeychecking", oStrictHostKeyChecking },
|
||||
{ "compression", oCompression },
|
||||
{ "compressionlevel", oCompressionLevel },
|
||||
{ "keepalive", oKeepAlives },
|
||||
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
|
||||
{ "tisauthentication", oTISAuthentication },
|
||||
{ "loglevel", oLogLevel },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* Characters considered whitespace in strtok calls. */
|
||||
#define WHITESPACE " \t\r\n"
|
||||
|
||||
|
||||
/*
|
||||
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||||
* error.
|
||||
*/
|
||||
|
||||
void
|
||||
add_local_forward(Options *options, u_short port, const char *host,
|
||||
u_short host_port)
|
||||
{
|
||||
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");
|
||||
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++];
|
||||
fwd->port = port;
|
||||
fwd->host = xstrdup(host);
|
||||
fwd->host_port = host_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a remote TCP/IP port forward to options. Never returns if there is
|
||||
* an error.
|
||||
*/
|
||||
|
||||
void
|
||||
add_remote_forward(Options *options, u_short port, const char *host,
|
||||
u_short host_port)
|
||||
{
|
||||
Forward *fwd;
|
||||
if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
|
||||
fatal("Too many remote forwards (max %d).",
|
||||
SSH_MAX_FORWARDS_PER_DIRECTION);
|
||||
fwd = &options->remote_forwards[options->num_remote_forwards++];
|
||||
fwd->port = port;
|
||||
fwd->host = xstrdup(host);
|
||||
fwd->host_port = host_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of the token pointed to by cp of length len. Never
|
||||
* returns if the token is not known.
|
||||
*/
|
||||
|
||||
static OpCodes
|
||||
parse_token(const char *cp, const char *filename, int linenum)
|
||||
{
|
||||
unsigned 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);
|
||||
return oBadOption;
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes a single option line as used in the configuration files. This
|
||||
* only sets those values that have not already been set.
|
||||
*/
|
||||
|
||||
int
|
||||
process_config_line(Options *options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep)
|
||||
{
|
||||
char buf[256], *cp, *string, **charptr, *cp2;
|
||||
int opcode, *intptr, value;
|
||||
u_short fwd_port, fwd_host_port;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
cp = line + strspn(line, WHITESPACE);
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
return 0;
|
||||
|
||||
/* Get the keyword. (Each line is supposed to begin with a keyword). */
|
||||
cp = strtok(cp, WHITESPACE);
|
||||
opcode = parse_token(cp, filename, linenum);
|
||||
|
||||
switch (opcode) {
|
||||
case oBadOption:
|
||||
/* don't panic, but count bad options */
|
||||
return -1;
|
||||
/* NOTREACHED */
|
||||
case oForwardAgent:
|
||||
intptr = &options->forward_agent;
|
||||
parse_flag:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
|
||||
value = 0;
|
||||
else
|
||||
fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oForwardX11:
|
||||
intptr = &options->forward_x11;
|
||||
goto parse_flag;
|
||||
|
||||
case oGatewayPorts:
|
||||
intptr = &options->gateway_ports;
|
||||
goto parse_flag;
|
||||
|
||||
case oUsePrivilegedPort:
|
||||
intptr = &options->use_privileged_port;
|
||||
goto parse_flag;
|
||||
|
||||
case oRhostsAuthentication:
|
||||
intptr = &options->rhosts_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oPasswordAuthentication:
|
||||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oRSAAuthentication:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oRhostsRSAAuthentication:
|
||||
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;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef KRB4
|
||||
case oKerberosAuthentication:
|
||||
intptr = &options->kerberos_authentication;
|
||||
goto parse_flag;
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef AFS
|
||||
case oKerberosTgtPassing:
|
||||
intptr = &options->kerberos_tgt_passing;
|
||||
goto parse_flag;
|
||||
|
||||
case oAFSTokenPassing:
|
||||
intptr = &options->afs_token_passing;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case oFallBackToRsh:
|
||||
intptr = &options->fallback_to_rsh;
|
||||
goto parse_flag;
|
||||
|
||||
case oUseRsh:
|
||||
intptr = &options->use_rsh;
|
||||
goto parse_flag;
|
||||
|
||||
case oBatchMode:
|
||||
intptr = &options->batch_mode;
|
||||
goto parse_flag;
|
||||
|
||||
case oCheckHostIP:
|
||||
intptr = &options->check_host_ip;
|
||||
goto parse_flag;
|
||||
|
||||
case oStrictHostKeyChecking:
|
||||
intptr = &options->strict_host_key_checking;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing yes/no argument.",
|
||||
filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
|
||||
value = 0;
|
||||
else if (strcmp(cp, "ask") == 0)
|
||||
value = 2;
|
||||
else
|
||||
fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oCompression:
|
||||
intptr = &options->compression;
|
||||
goto parse_flag;
|
||||
|
||||
case oKeepAlives:
|
||||
intptr = &options->keepalives;
|
||||
goto parse_flag;
|
||||
|
||||
case oNumberOfPasswordPrompts:
|
||||
intptr = &options->number_of_password_prompts;
|
||||
goto parse_int;
|
||||
|
||||
case oCompressionLevel:
|
||||
intptr = &options->compression_level;
|
||||
goto parse_int;
|
||||
|
||||
case oIdentityFile:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep) {
|
||||
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
options->identity_files[options->num_identity_files++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case oUser:
|
||||
charptr = &options->user;
|
||||
parse_string:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep && *charptr == NULL)
|
||||
*charptr = xstrdup(cp);
|
||||
break;
|
||||
|
||||
case oGlobalKnownHostsFile:
|
||||
charptr = &options->system_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oUserKnownHostsFile:
|
||||
charptr = &options->user_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oHostName:
|
||||
charptr = &options->hostname;
|
||||
goto parse_string;
|
||||
|
||||
case oProxyCommand:
|
||||
charptr = &options->proxy_command;
|
||||
string = xstrdup("");
|
||||
while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
|
||||
string = xrealloc(string, strlen(string) + strlen(cp) + 2);
|
||||
strcat(string, " ");
|
||||
strcat(string, cp);
|
||||
}
|
||||
if (*activep && *charptr == NULL)
|
||||
*charptr = string;
|
||||
else
|
||||
xfree(string);
|
||||
return 0;
|
||||
|
||||
case oPort:
|
||||
intptr = &options->port;
|
||||
parse_int:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (cp[0] < '0' || cp[0] > '9')
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
|
||||
/* Octal, decimal, or hex format? */
|
||||
value = strtol(cp, &cp2, 0);
|
||||
if (cp == cp2)
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oConnectionAttempts:
|
||||
intptr = &options->connection_attempts;
|
||||
goto parse_int;
|
||||
|
||||
case oCipher:
|
||||
intptr = &options->cipher;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = cipher_number(cp);
|
||||
if (value == -1)
|
||||
fatal("%.200s line %d: Bad cipher '%s'.",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_level_number(cp);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*activep && (LogLevel) * intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case oRemoteForward:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (cp[0] < '0' || cp[0] > '9')
|
||||
fatal("%.200s line %d: Badly formatted port number.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(cp);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing second argument.",
|
||||
filename, linenum);
|
||||
if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
|
||||
fatal("%.200s line %d: Badly formatted host:port.",
|
||||
filename, linenum);
|
||||
if (*activep)
|
||||
add_remote_forward(options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case oLocalForward:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (cp[0] < '0' || cp[0] > '9')
|
||||
fatal("%.200s line %d: Badly formatted port number.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(cp);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing second argument.",
|
||||
filename, linenum);
|
||||
if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
|
||||
fatal("%.200s line %d: Badly formatted host:port.",
|
||||
filename, linenum);
|
||||
if (*activep)
|
||||
add_local_forward(options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case oHost:
|
||||
*activep = 0;
|
||||
while ((cp = strtok(NULL, WHITESPACE)) != NULL)
|
||||
if (match_pattern(host, cp)) {
|
||||
debug("Applying options for %.100s", cp);
|
||||
*activep = 1;
|
||||
break;
|
||||
}
|
||||
/* Avoid garbage check below, as strtok already returned NULL. */
|
||||
return 0;
|
||||
|
||||
case oEscapeChar:
|
||||
intptr = &options->escape_char;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (cp[0] == '^' && cp[2] == 0 &&
|
||||
(unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
|
||||
value = (unsigned char) cp[1] & 31;
|
||||
else if (strlen(cp) == 1)
|
||||
value = (unsigned char) cp[0];
|
||||
else if (strcmp(cp, "none") == 0)
|
||||
value = -2;
|
||||
else {
|
||||
fatal("%.200s line %d: Bad escape character.",
|
||||
filename, linenum);
|
||||
/* NOTREACHED */
|
||||
value = 0; /* Avoid compiler warning. */
|
||||
}
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("process_config_line: Unimplemented opcode %d", opcode);
|
||||
}
|
||||
|
||||
/* Check that there is no garbage at end of line. */
|
||||
if (strtok(NULL, WHITESPACE) != NULL)
|
||||
fatal("%.200s line %d: garbage at end of line.",
|
||||
filename, linenum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reads the config file and modifies the options accordingly. Options
|
||||
* should already be initialized before this call. This never returns if
|
||||
* there is an error. If the file does not exist, this returns immediately.
|
||||
*/
|
||||
|
||||
void
|
||||
read_config_file(const char *filename, const char *host, Options *options)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
int active, linenum;
|
||||
int bad_options = 0;
|
||||
|
||||
/* Open the file. */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
debug("Reading configuration data %.200s", filename);
|
||||
|
||||
/*
|
||||
* Mark that we are now processing the options. This flag is turned
|
||||
* on/off by Host specifications.
|
||||
*/
|
||||
active = 1;
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
/* Update line number counter. */
|
||||
linenum++;
|
||||
if (process_config_line(options, host, line, filename, linenum, &active) != 0)
|
||||
bad_options++;
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0)
|
||||
fatal("%s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes options to special values that indicate that they have not yet
|
||||
* been set. Read_config_file will only set options with this value. Options
|
||||
* are processed in the following order: command line, user config file,
|
||||
* system config file. Last, fill_default_options is called.
|
||||
*/
|
||||
|
||||
void
|
||||
initialize_options(Options * options)
|
||||
{
|
||||
memset(options, 'X', sizeof(*options));
|
||||
options->forward_agent = -1;
|
||||
options->forward_x11 = -1;
|
||||
options->gateway_ports = -1;
|
||||
options->use_privileged_port = -1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->skey_authentication = -1;
|
||||
#ifdef KRB4
|
||||
options->kerberos_authentication = -1;
|
||||
#endif
|
||||
#ifdef AFS
|
||||
options->kerberos_tgt_passing = -1;
|
||||
options->afs_token_passing = -1;
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->fallback_to_rsh = -1;
|
||||
options->use_rsh = -1;
|
||||
options->batch_mode = -1;
|
||||
options->check_host_ip = -1;
|
||||
options->strict_host_key_checking = -1;
|
||||
options->compression = -1;
|
||||
options->keepalives = -1;
|
||||
options->compression_level = -1;
|
||||
options->port = -1;
|
||||
options->connection_attempts = -1;
|
||||
options->number_of_password_prompts = -1;
|
||||
options->cipher = -1;
|
||||
options->num_identity_files = 0;
|
||||
options->hostname = NULL;
|
||||
options->proxy_command = NULL;
|
||||
options->user = NULL;
|
||||
options->escape_char = -1;
|
||||
options->system_hostfile = NULL;
|
||||
options->user_hostfile = NULL;
|
||||
options->num_local_forwards = 0;
|
||||
options->num_remote_forwards = 0;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after processing other sources of option data, this fills those
|
||||
* options for which no value has been specified with their default values.
|
||||
*/
|
||||
|
||||
void
|
||||
fill_default_options(Options * options)
|
||||
{
|
||||
if (options->forward_agent == -1)
|
||||
options->forward_agent = 1;
|
||||
if (options->forward_x11 == -1)
|
||||
options->forward_x11 = 1;
|
||||
if (options->gateway_ports == -1)
|
||||
options->gateway_ports = 0;
|
||||
if (options->use_privileged_port == -1)
|
||||
options->use_privileged_port = 1;
|
||||
if (options->rhosts_authentication == -1)
|
||||
options->rhosts_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 0;
|
||||
#ifdef KRB4
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = 1;
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
if (options->kerberos_tgt_passing == -1)
|
||||
options->kerberos_tgt_passing = 1;
|
||||
if (options->afs_token_passing == -1)
|
||||
options->afs_token_passing = 1;
|
||||
#endif /* AFS */
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
options->rhosts_rsa_authentication = 1;
|
||||
if (options->fallback_to_rsh == -1)
|
||||
options->fallback_to_rsh = 1;
|
||||
if (options->use_rsh == -1)
|
||||
options->use_rsh = 0;
|
||||
if (options->batch_mode == -1)
|
||||
options->batch_mode = 0;
|
||||
if (options->check_host_ip == -1)
|
||||
options->check_host_ip = 1;
|
||||
if (options->strict_host_key_checking == -1)
|
||||
options->strict_host_key_checking = 2; /* 2 is default */
|
||||
if (options->compression == -1)
|
||||
options->compression = 0;
|
||||
if (options->keepalives == -1)
|
||||
options->keepalives = 1;
|
||||
if (options->compression_level == -1)
|
||||
options->compression_level = 6;
|
||||
if (options->port == -1)
|
||||
options->port = 0; /* Filled in ssh_connect. */
|
||||
if (options->connection_attempts == -1)
|
||||
options->connection_attempts = 4;
|
||||
if (options->number_of_password_prompts == -1)
|
||||
options->number_of_password_prompts = 3;
|
||||
/* Selected in ssh_login(). */
|
||||
if (options->cipher == -1)
|
||||
options->cipher = SSH_CIPHER_NOT_SET;
|
||||
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->escape_char == -1)
|
||||
options->escape_char = '~';
|
||||
if (options->system_hostfile == NULL)
|
||||
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
||||
if (options->user_hostfile == NULL)
|
||||
options->user_hostfile = SSH_USER_HOSTFILE;
|
||||
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 */
|
||||
}
|
137
crypto/openssh/readconf.h
Normal file
137
crypto/openssh/readconf.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
*
|
||||
* readconf.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Apr 22 00:25:29 1995 ylo
|
||||
*
|
||||
* Functions for reading the configuration file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: readconf.h,v 1.13 1999/12/01 13:59:15 markus Exp $"); */
|
||||
|
||||
#ifndef READCONF_H
|
||||
#define READCONF_H
|
||||
|
||||
/* Data structure for representing a forwarding request. */
|
||||
|
||||
typedef struct {
|
||||
u_short port; /* Port to forward. */
|
||||
char *host; /* Host to connect. */
|
||||
u_short host_port; /* Port to connect on host. */
|
||||
} Forward;
|
||||
/* Data structure for representing option data. */
|
||||
|
||||
typedef struct {
|
||||
int forward_agent; /* Forward authentication agent. */
|
||||
int forward_x11; /* Forward X11 display. */
|
||||
int gateway_ports; /* Allow remote connects to forwarded ports. */
|
||||
int use_privileged_port; /* Don't use privileged port if false. */
|
||||
int rhosts_authentication; /* Try rhosts authentication. */
|
||||
int rhosts_rsa_authentication; /* Try rhosts with RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* Try RSA authentication. */
|
||||
int skey_authentication; /* Try S/Key or TIS authentication. */
|
||||
#ifdef KRB4
|
||||
int kerberos_authentication; /* Try Kerberos
|
||||
* authentication. */
|
||||
#endif
|
||||
#ifdef AFS
|
||||
int kerberos_tgt_passing; /* Try Kerberos tgt passing. */
|
||||
int afs_token_passing; /* Try AFS token passing. */
|
||||
#endif
|
||||
int password_authentication; /* Try password
|
||||
* authentication. */
|
||||
int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
|
||||
int use_rsh; /* Always use rsh (don\'t try ssh). */
|
||||
int batch_mode; /* Batch mode: do not ask for passwords. */
|
||||
int check_host_ip; /* Also keep track of keys for IP address */
|
||||
int strict_host_key_checking; /* Strict host key checking. */
|
||||
int compression; /* Compress packets in both directions. */
|
||||
int compression_level; /* Compression level 1 (fast) to 9
|
||||
* (best). */
|
||||
int keepalives; /* Set SO_KEEPALIVE. */
|
||||
LogLevel log_level; /* Level for logging. */
|
||||
|
||||
int port; /* Port to connect. */
|
||||
int connection_attempts; /* Max attempts (seconds) before
|
||||
* giving up */
|
||||
int number_of_password_prompts; /* Max number of password
|
||||
* prompts. */
|
||||
int cipher; /* Cipher to use. */
|
||||
char *hostname; /* Real host to connect. */
|
||||
char *proxy_command; /* Proxy command for connecting the host. */
|
||||
char *user; /* User to log in as. */
|
||||
int escape_char; /* Escape character; -2 = none */
|
||||
|
||||
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
|
||||
/* Remote TCP/IP forward requests. */
|
||||
int num_remote_forwards;
|
||||
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
} Options;
|
||||
|
||||
|
||||
/*
|
||||
* Initializes options to special values that indicate that they have not yet
|
||||
* been set. Read_config_file will only set options with this value. Options
|
||||
* are processed in the following order: command line, user config file,
|
||||
* system config file. Last, fill_default_options is called.
|
||||
*/
|
||||
void initialize_options(Options * options);
|
||||
|
||||
/*
|
||||
* Called after processing other sources of option data, this fills those
|
||||
* options for which no value has been specified with their default values.
|
||||
*/
|
||||
void fill_default_options(Options * options);
|
||||
|
||||
/*
|
||||
* Processes a single option line as used in the configuration files. This
|
||||
* only sets those values that have not already been set. Returns 0 for legal
|
||||
* options
|
||||
*/
|
||||
int
|
||||
process_config_line(Options * options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep);
|
||||
|
||||
/*
|
||||
* Reads the config file and modifies the options accordingly. Options
|
||||
* should already be initialized before this call. This never returns if
|
||||
* there is an error. If the file does not exist, this returns immediately.
|
||||
*/
|
||||
void
|
||||
read_config_file(const char *filename, const char *host,
|
||||
Options * options);
|
||||
|
||||
/*
|
||||
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||||
* error.
|
||||
*/
|
||||
void
|
||||
add_local_forward(Options * options, u_short port, const char *host,
|
||||
u_short host_port);
|
||||
|
||||
/*
|
||||
* Adds a remote TCP/IP port forward to options. Never returns if there is
|
||||
* an error.
|
||||
*/
|
||||
void
|
||||
add_remote_forward(Options * options, u_short port, const char *host,
|
||||
u_short host_port);
|
||||
|
||||
#endif /* READCONF_H */
|
119
crypto/openssh/readpass.c
Normal file
119
crypto/openssh/readpass.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
* 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("$Id: readpass.c,v 1.9 2000/01/21 21:16:00 deraadt Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
volatile int intr;
|
||||
|
||||
void
|
||||
intcatch()
|
||||
{
|
||||
intr = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
* passphrase (allocated with xmalloc), being very careful to ensure that
|
||||
* no other userland buffer is storing the password.
|
||||
*/
|
||||
char *
|
||||
read_passphrase(const char *prompt, int from_stdin)
|
||||
{
|
||||
char buf[1024], *p, ch;
|
||||
struct termios tio, saved_tio;
|
||||
sigset_t oset, nset;
|
||||
struct sigaction sa, osa;
|
||||
int input, output, echo = 0;
|
||||
|
||||
if (from_stdin) {
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
} else
|
||||
input = output = open("/dev/tty", O_RDWR);
|
||||
|
||||
if (input == -1)
|
||||
fatal("You have no controlling tty. Cannot read passphrase.\n");
|
||||
|
||||
/* block signals, get terminal modes and turn off echo */
|
||||
sigemptyset(&nset);
|
||||
sigaddset(&nset, SIGTSTP);
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = intcatch;
|
||||
(void) sigaction(SIGINT, &sa, &osa);
|
||||
|
||||
intr = 0;
|
||||
|
||||
if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
|
||||
echo = 1;
|
||||
tio = saved_tio;
|
||||
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
(void) tcsetattr(input, TCSANOW, &tio);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
(void)write(output, prompt, strlen(prompt));
|
||||
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
|
||||
if (intr)
|
||||
break;
|
||||
if (p < buf + sizeof(buf) - 1)
|
||||
*p++ = ch;
|
||||
}
|
||||
*p = '\0';
|
||||
if (!intr)
|
||||
(void)write(output, "\n", 1);
|
||||
|
||||
/* restore terminal modes and allow signals */
|
||||
if (echo)
|
||||
tcsetattr(input, TCSANOW, &saved_tio);
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
(void) sigaction(SIGINT, &osa, NULL);
|
||||
|
||||
if (intr) {
|
||||
kill(getpid(), SIGINT);
|
||||
sigemptyset(&nset);
|
||||
/* XXX tty has not neccessarily drained by now? */
|
||||
sigsuspend(&nset);
|
||||
}
|
||||
|
||||
if (!from_stdin)
|
||||
(void)close(input);
|
||||
p = xstrdup(buf);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return (p);
|
||||
}
|
169
crypto/openssh/rsa.c
Normal file
169
crypto/openssh/rsa.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
*
|
||||
* rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 3 22:07:06 1995 ylo
|
||||
*
|
||||
* Description of the RSA algorithm can be found e.g. from the following sources:
|
||||
*
|
||||
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
|
||||
*
|
||||
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
|
||||
* Computer Security. Prentice-Hall, 1989.
|
||||
*
|
||||
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
|
||||
* 1994.
|
||||
*
|
||||
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
|
||||
* System and Method. US Patent 4,405,829, 1983.
|
||||
*
|
||||
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
|
||||
* Birkhauser, 1994.
|
||||
*
|
||||
* The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
|
||||
*
|
||||
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
|
||||
* below:
|
||||
*
|
||||
* [gone - had to be deleted - what a pity]
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: rsa.c,v 1.12 2000/02/21 21:47:31 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.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)
|
||||
{
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
|
||||
fatal("rsa_public_encrypt() exponent too small or not odd");
|
||||
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
BN_bn2bin(in, inbuf);
|
||||
|
||||
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
|
||||
RSA_PKCS1_PADDING)) <= 0)
|
||||
fatal("rsa_public_encrypt() failed");
|
||||
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
}
|
||||
|
||||
void
|
||||
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
{
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
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);
|
||||
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
}
|
||||
|
||||
/* Set whether to output verbose messages during key generation. */
|
||||
|
||||
void
|
||||
rsa_set_verbose(int verbose)
|
||||
{
|
||||
rsa_verbose = verbose;
|
||||
}
|
38
crypto/openssh/rsa.h
Normal file
38
crypto/openssh/rsa.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
*
|
||||
* rsa.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 3 22:01:06 1995 ylo
|
||||
*
|
||||
* RSA key generation, encryption and decryption.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 19:53:50 markus Exp $"); */
|
||||
|
||||
#ifndef RSA_H
|
||||
#define RSA_H
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include <ssl/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));
|
||||
|
||||
#endif /* RSA_H */
|
118
crypto/openssh/scp.1
Normal file
118
crypto/openssh/scp.1
Normal file
@ -0,0 +1,118 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" scp.1
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\"
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Created: Sun May 7 00:14:37 1995 ylo
|
||||
.\"
|
||||
.\" $Id: scp.1,v 1.5 2000/01/04 16:57:16 markus Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SCP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm scp
|
||||
.Nd secure copy (remote file copy program)
|
||||
.Sh SYNOPSIS
|
||||
.Nm scp
|
||||
.Op Fl pqrvC46
|
||||
.Op Fl P Ar port
|
||||
.Op Fl c Ar cipher
|
||||
.Op Fl i Ar identity_file
|
||||
.Sm off
|
||||
.Oo
|
||||
.Op Ar user@
|
||||
.Ar host1 No :
|
||||
.Oc Ns Ar file1
|
||||
.Sm on
|
||||
.Op Ar ...
|
||||
.Sm off
|
||||
.Oo
|
||||
.Op Ar user@
|
||||
.Ar host2 No :
|
||||
.Oc Ar file2
|
||||
.Sm on
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
copies files between hosts on a network. It uses
|
||||
.Xr ssh 1
|
||||
for data transfer, and uses the same authentication and provides the
|
||||
same security as
|
||||
.Xr ssh 1 .
|
||||
Unlike
|
||||
.Xr rcp 1 ,
|
||||
.Nm
|
||||
will ask for passwords or passphrases if they are needed for
|
||||
authentication.
|
||||
.Pp
|
||||
Any file name may contain a host and user specification to indicate
|
||||
that the file is to be copied to/from that host. Copies between two
|
||||
remote hosts are permitted.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl c Ar cipher
|
||||
Selects the cipher to use for encrypting the data transfer. This
|
||||
option is directly passed to
|
||||
.Xr ssh 1 .
|
||||
.It Fl i Ar identity_file
|
||||
Selects the file from which the identity (private key) for RSA
|
||||
authentication is read. This option is directly passed to
|
||||
.Xr ssh 1 .
|
||||
.It Fl p
|
||||
Preserves modification times, access times, and modes from the
|
||||
original file.
|
||||
.It Fl r
|
||||
Recursively copy entire directories.
|
||||
.It Fl v
|
||||
Verbose mode. Causes
|
||||
.Nm
|
||||
and
|
||||
.Xr ssh 1
|
||||
to print debugging messages about their progress. This is helpful in
|
||||
debugging connection, authentication, and configuration problems.
|
||||
.It Fl B
|
||||
Selects batch mode (prevents asking for passwords or passphrases).
|
||||
.It Fl q
|
||||
Disables the progress meter.
|
||||
.It Fl C
|
||||
Compression enable. Passes the
|
||||
.Fl C
|
||||
flag to
|
||||
.Xr ssh 1
|
||||
to enable compression.
|
||||
.It Fl P Ar port
|
||||
Specifies the port to connect to on the remote host. Note that this
|
||||
option is written with a capital
|
||||
.Sq P ,
|
||||
because
|
||||
.Fl p
|
||||
is already reserved for preserving the times and modes of the file in
|
||||
.Xr rcp 1 .
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv6 addresses only.
|
||||
.Sh AUTHORS
|
||||
Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
is based on the
|
||||
.Xr rcp 1
|
||||
program in BSD source code from the Regents of the University of
|
||||
California.
|
||||
.Sh SEE ALSO
|
||||
.Xr rcp 1 ,
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8
|
1245
crypto/openssh/scp.c
Normal file
1245
crypto/openssh/scp.c
Normal file
File diff suppressed because it is too large
Load Diff
18
crypto/openssh/scp/Makefile
Normal file
18
crypto/openssh/scp/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= scp
|
||||
BINOWN= root
|
||||
|
||||
.if (${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "powerpc" || \
|
||||
${MACHINE_ARCH} == "hppa")
|
||||
BINMODE=0000
|
||||
.else
|
||||
BINMODE?=555
|
||||
.endif
|
||||
|
||||
BINDIR= /usr/bin
|
||||
MAN= scp.1
|
||||
|
||||
SRCS= scp.c
|
||||
|
||||
.include <bsd.prog.mk>
|
568
crypto/openssh/servconf.c
Normal file
568
crypto/openssh/servconf.c
Normal file
@ -0,0 +1,568 @@
|
||||
/*
|
||||
*
|
||||
* servconf.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Aug 21 15:48:58 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: servconf.c,v 1.29 2000/01/04 00:07:59 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* add listen address */
|
||||
void add_listen_addr(ServerOptions *options, char *addr);
|
||||
|
||||
/* Initializes the server options to their default values. */
|
||||
|
||||
void
|
||||
initialize_server_options(ServerOptions *options)
|
||||
{
|
||||
memset(options, 0, sizeof(*options));
|
||||
options->num_ports = 0;
|
||||
options->ports_from_cmdline = 0;
|
||||
options->listen_addrs = NULL;
|
||||
options->host_key_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_time = -1;
|
||||
options->key_regeneration_time = -1;
|
||||
options->permit_root_login = -1;
|
||||
options->ignore_rhosts = -1;
|
||||
options->ignore_user_known_hosts = -1;
|
||||
options->print_motd = -1;
|
||||
options->check_mail = -1;
|
||||
options->x11_forwarding = -1;
|
||||
options->x11_display_offset = -1;
|
||||
options->strict_modes = -1;
|
||||
options->keepalives = -1;
|
||||
options->log_facility = (SyslogFacility) - 1;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
#ifdef KRB4
|
||||
options->kerberos_authentication = -1;
|
||||
options->kerberos_or_local_passwd = -1;
|
||||
options->kerberos_ticket_cleanup = -1;
|
||||
#endif
|
||||
#ifdef AFS
|
||||
options->kerberos_tgt_passing = -1;
|
||||
options->afs_token_passing = -1;
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
#ifdef SKEY
|
||||
options->skey_authentication = -1;
|
||||
#endif
|
||||
options->permit_empty_passwd = -1;
|
||||
options->use_login = -1;
|
||||
options->num_allow_users = 0;
|
||||
options->num_deny_users = 0;
|
||||
options->num_allow_groups = 0;
|
||||
options->num_deny_groups = 0;
|
||||
}
|
||||
|
||||
void
|
||||
fill_default_server_options(ServerOptions *options)
|
||||
{
|
||||
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->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->ignore_rhosts == -1)
|
||||
options->ignore_rhosts = 0;
|
||||
if (options->ignore_user_known_hosts == -1)
|
||||
options->ignore_user_known_hosts = 0;
|
||||
if (options->check_mail == -1)
|
||||
options->check_mail = 0;
|
||||
if (options->print_motd == -1)
|
||||
options->print_motd = 1;
|
||||
if (options->x11_forwarding == -1)
|
||||
options->x11_forwarding = 1;
|
||||
if (options->x11_display_offset == -1)
|
||||
options->x11_display_offset = 1;
|
||||
if (options->strict_modes == -1)
|
||||
options->strict_modes = 1;
|
||||
if (options->keepalives == -1)
|
||||
options->keepalives = 1;
|
||||
if (options->log_facility == (SyslogFacility) (-1))
|
||||
options->log_facility = SYSLOG_FACILITY_AUTH;
|
||||
if (options->log_level == (LogLevel) (-1))
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
if (options->rhosts_authentication == -1)
|
||||
options->rhosts_authentication = 0;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
options->rhosts_rsa_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
#ifdef KRB4
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
|
||||
if (options->kerberos_or_local_passwd == -1)
|
||||
options->kerberos_or_local_passwd = 1;
|
||||
if (options->kerberos_ticket_cleanup == -1)
|
||||
options->kerberos_ticket_cleanup = 1;
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
if (options->kerberos_tgt_passing == -1)
|
||||
options->kerberos_tgt_passing = 0;
|
||||
if (options->afs_token_passing == -1)
|
||||
options->afs_token_passing = k_hasafs();
|
||||
#endif /* AFS */
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
#ifdef SKEY
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
#endif
|
||||
if (options->permit_empty_passwd == -1)
|
||||
options->permit_empty_passwd = 1;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
}
|
||||
|
||||
#define WHITESPACE " \t\r\n"
|
||||
|
||||
/* Keyword tokens. */
|
||||
typedef enum {
|
||||
sBadOption, /* == unknown option */
|
||||
sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
|
||||
sPermitRootLogin, sLogFacility, sLogLevel,
|
||||
sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
|
||||
#ifdef KRB4
|
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
||||
#endif
|
||||
#ifdef AFS
|
||||
sKerberosTgtPassing, sAFSTokenPassing,
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
sSkeyAuthentication,
|
||||
#endif
|
||||
sPasswordAuthentication, sListenAddress,
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
sIgnoreUserKnownHosts
|
||||
} ServerOpCodes;
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
static struct {
|
||||
const char *name;
|
||||
ServerOpCodes opcode;
|
||||
} keywords[] = {
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
{ "permitrootlogin", sPermitRootLogin },
|
||||
{ "syslogfacility", sLogFacility },
|
||||
{ "loglevel", sLogLevel },
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", sKerberosAuthentication },
|
||||
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
|
||||
{ "kerberosticketcleanup", sKerberosTicketCleanup },
|
||||
#endif
|
||||
#ifdef AFS
|
||||
{ "kerberostgtpassing", sKerberosTgtPassing },
|
||||
{ "afstokenpassing", sAFSTokenPassing },
|
||||
#endif
|
||||
{ "passwordauthentication", sPasswordAuthentication },
|
||||
#ifdef SKEY
|
||||
{ "skeyauthentication", sSkeyAuthentication },
|
||||
#endif
|
||||
{ "checkmail", sCheckMail },
|
||||
{ "listenaddress", sListenAddress },
|
||||
{ "printmotd", sPrintMotd },
|
||||
{ "ignorerhosts", sIgnoreRhosts },
|
||||
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
|
||||
{ "x11forwarding", sX11Forwarding },
|
||||
{ "x11displayoffset", sX11DisplayOffset },
|
||||
{ "strictmodes", sStrictModes },
|
||||
{ "permitemptypasswords", sEmptyPasswd },
|
||||
{ "uselogin", sUseLogin },
|
||||
{ "randomseed", sRandomSeedFile },
|
||||
{ "keepalive", sKeepAlives },
|
||||
{ "allowusers", sAllowUsers },
|
||||
{ "denyusers", sDenyUsers },
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the number of the token pointed to by cp of length len. Never
|
||||
* returns if the token is not known.
|
||||
*/
|
||||
|
||||
static ServerOpCodes
|
||||
parse_token(const char *cp, const char *filename,
|
||||
int linenum)
|
||||
{
|
||||
unsigned 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);
|
||||
return sBadOption;
|
||||
}
|
||||
|
||||
/*
|
||||
* add listen address
|
||||
*/
|
||||
void
|
||||
add_listen_addr(ServerOptions *options, char *addr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reads the server configuration file. */
|
||||
|
||||
void
|
||||
read_server_config(ServerOptions *options, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
char *cp, **charptr;
|
||||
int linenum, *intptr, value;
|
||||
int bad_options = 0;
|
||||
ServerOpCodes opcode;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
linenum++;
|
||||
cp = line + strspn(line, WHITESPACE);
|
||||
if (!*cp || *cp == '#')
|
||||
continue;
|
||||
cp = strtok(cp, WHITESPACE);
|
||||
opcode = parse_token(cp, filename, linenum);
|
||||
switch (opcode) {
|
||||
case sBadOption:
|
||||
bad_options++;
|
||||
continue;
|
||||
case sPort:
|
||||
/* ignore ports from configfile if cmdline specifies ports */
|
||||
if (options->ports_from_cmdline)
|
||||
continue;
|
||||
if (options->listen_addrs != NULL)
|
||||
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",
|
||||
filename, linenum);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%s line %d: missing port number.\n",
|
||||
filename, linenum);
|
||||
options->ports[options->num_ports++] = atoi(cp);
|
||||
break;
|
||||
|
||||
case sServerKeyBits:
|
||||
intptr = &options->server_key_bits;
|
||||
parse_int:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing integer value.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
value = atoi(cp);
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sLoginGraceTime:
|
||||
intptr = &options->login_grace_time;
|
||||
goto parse_int;
|
||||
|
||||
case sKeyRegenerationTime:
|
||||
intptr = &options->key_regeneration_time;
|
||||
goto parse_int;
|
||||
|
||||
case sListenAddress:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%s line %d: missing inet addr.\n",
|
||||
filename, linenum);
|
||||
add_listen_addr(options, cp);
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
charptr = &options->host_key_file;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
*charptr = tilde_expand_filename(cp, getuid());
|
||||
break;
|
||||
|
||||
case sRandomSeedFile:
|
||||
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
|
||||
filename, linenum);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
break;
|
||||
|
||||
case sPermitRootLogin:
|
||||
intptr = &options->permit_root_login;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "without-password") == 0)
|
||||
value = 2;
|
||||
else if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreRhosts:
|
||||
intptr = &options->ignore_rhosts;
|
||||
parse_flag:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreUserKnownHosts:
|
||||
intptr = &options->ignore_user_known_hosts;
|
||||
goto parse_int;
|
||||
|
||||
case sRhostsAuthentication:
|
||||
intptr = &options->rhosts_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRhostsRSAAuthentication:
|
||||
intptr = &options->rhosts_rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRSAAuthentication:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef KRB4
|
||||
case sKerberosAuthentication:
|
||||
intptr = &options->kerberos_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sKerberosOrLocalPasswd:
|
||||
intptr = &options->kerberos_or_local_passwd;
|
||||
goto parse_flag;
|
||||
|
||||
case sKerberosTicketCleanup:
|
||||
intptr = &options->kerberos_ticket_cleanup;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
#ifdef AFS
|
||||
case sKerberosTgtPassing:
|
||||
intptr = &options->kerberos_tgt_passing;
|
||||
goto parse_flag;
|
||||
|
||||
case sAFSTokenPassing:
|
||||
intptr = &options->afs_token_passing;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case sPasswordAuthentication:
|
||||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sCheckMail:
|
||||
intptr = &options->check_mail;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef SKEY
|
||||
case sSkeyAuthentication:
|
||||
intptr = &options->skey_authentication;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case sPrintMotd:
|
||||
intptr = &options->print_motd;
|
||||
goto parse_flag;
|
||||
|
||||
case sX11Forwarding:
|
||||
intptr = &options->x11_forwarding;
|
||||
goto parse_flag;
|
||||
|
||||
case sX11DisplayOffset:
|
||||
intptr = &options->x11_display_offset;
|
||||
goto parse_int;
|
||||
|
||||
case sStrictModes:
|
||||
intptr = &options->strict_modes;
|
||||
goto parse_flag;
|
||||
|
||||
case sKeepAlives:
|
||||
intptr = &options->keepalives;
|
||||
goto parse_flag;
|
||||
|
||||
case sEmptyPasswd:
|
||||
intptr = &options->permit_empty_passwd;
|
||||
goto parse_flag;
|
||||
|
||||
case sUseLogin:
|
||||
intptr = &options->use_login;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogFacility:
|
||||
intptr = (int *) &options->log_facility;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_facility_number(cp);
|
||||
if (value == (SyslogFacility) - 1)
|
||||
fatal("%.200s line %d: unsupported log facility '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility) value;
|
||||
break;
|
||||
|
||||
case sLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_level_number(cp);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case sAllowUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_users >= MAX_DENY_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sAllowGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
|
||||
filename, linenum, cp, opcode);
|
||||
exit(1);
|
||||
}
|
||||
if (strtok(NULL, WHITESPACE) != NULL) {
|
||||
fprintf(stderr, "%s line %d: garbage at end of line.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0) {
|
||||
fprintf(stderr, "%s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
exit(1);
|
||||
}
|
||||
}
|
106
crypto/openssh/servconf.h
Normal file
106
crypto/openssh/servconf.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
*
|
||||
* servconf.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Aug 21 15:35:03 1995 ylo
|
||||
*
|
||||
* Definitions for server configuration data and for the functions reading it.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: servconf.h,v 1.15 2000/01/04 00:08:00 markus Exp $"); */
|
||||
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
|
||||
#define MAX_PORTS 256 /* Max # ports. */
|
||||
|
||||
#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
|
||||
#define MAX_DENY_USERS 256 /* Max # users on deny list. */
|
||||
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
|
||||
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
|
||||
|
||||
typedef struct {
|
||||
unsigned int num_ports;
|
||||
unsigned 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. */
|
||||
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 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 check_mail; /* If true, check for new mail. */
|
||||
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
|
||||
int x11_display_offset; /* What DISPLAY number to start
|
||||
* searching at */
|
||||
int strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
int rhosts_authentication; /* If true, permit rhosts
|
||||
* authentication. */
|
||||
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* If true, permit RSA authentication. */
|
||||
#ifdef KRB4
|
||||
int kerberos_authentication; /* If true, permit Kerberos
|
||||
* authentication. */
|
||||
int kerberos_or_local_passwd; /* If true, permit kerberos
|
||||
* and any other password
|
||||
* authentication mechanism,
|
||||
* such as SecurID or
|
||||
* /etc/passwd */
|
||||
int kerberos_ticket_cleanup; /* If true, destroy ticket
|
||||
* file on logout. */
|
||||
#endif
|
||||
#ifdef AFS
|
||||
int kerberos_tgt_passing; /* If true, permit Kerberos tgt
|
||||
* passing. */
|
||||
int afs_token_passing; /* If true, permit AFS token passing. */
|
||||
#endif
|
||||
int password_authentication; /* If true, permit password
|
||||
* authentication. */
|
||||
#ifdef SKEY
|
||||
int skey_authentication; /* If true, permit s/key
|
||||
* authentication. */
|
||||
#endif
|
||||
int permit_empty_passwd; /* If false, do not permit empty
|
||||
* passwords. */
|
||||
int use_login; /* If true, login(1) is used */
|
||||
unsigned int num_allow_users;
|
||||
char *allow_users[MAX_ALLOW_USERS];
|
||||
unsigned int num_deny_users;
|
||||
char *deny_users[MAX_DENY_USERS];
|
||||
unsigned int num_allow_groups;
|
||||
char *allow_groups[MAX_ALLOW_GROUPS];
|
||||
unsigned int num_deny_groups;
|
||||
char *deny_groups[MAX_DENY_GROUPS];
|
||||
} ServerOptions;
|
||||
/*
|
||||
* Initializes the server options to special values that indicate that they
|
||||
* have not yet been set.
|
||||
*/
|
||||
void initialize_server_options(ServerOptions * options);
|
||||
|
||||
/*
|
||||
* Reads the server configuration file. This only sets the values for those
|
||||
* options that have the special value indicating they have not been set.
|
||||
*/
|
||||
void read_server_config(ServerOptions * options, const char *filename);
|
||||
|
||||
/* Sets values for those values that have not yet been set. */
|
||||
void fill_default_server_options(ServerOptions * options);
|
||||
|
||||
#endif /* SERVCONF_H */
|
651
crypto/openssh/serverloop.c
Normal file
651
crypto/openssh/serverloop.c
Normal file
@ -0,0 +1,651 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sun Sep 10 00:30:37 1995 ylo
|
||||
* Server main loop for handling the interactive session.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "servconf.h"
|
||||
#include "pty.h"
|
||||
|
||||
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 int fdin; /* Descriptor for stdin (for writing) */
|
||||
static int fdout; /* Descriptor for stdout (for reading);
|
||||
May be same number as fdin. */
|
||||
static int fderr; /* Descriptor for stderr. May be -1. */
|
||||
static long stdin_bytes = 0; /* Number of bytes written to stdin. */
|
||||
static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */
|
||||
static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */
|
||||
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 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(). */
|
||||
|
||||
/*
|
||||
* This SIGCHLD kludge is used to detect when the child exits. The server
|
||||
* will exit after that, as soon as forwarded connections have terminated.
|
||||
*/
|
||||
|
||||
static int child_pid; /* Pid of the child. */
|
||||
static volatile int child_terminated; /* The child has terminated. */
|
||||
static volatile int child_wait_status; /* Status from wait(). */
|
||||
|
||||
void
|
||||
sigchld_handler(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int wait_pid;
|
||||
debug("Received SIGCHLD.");
|
||||
wait_pid = wait((int *) &child_wait_status);
|
||||
if (wait_pid != -1) {
|
||||
if (wait_pid != child_pid)
|
||||
error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
|
||||
wait_pid, child_pid);
|
||||
if (WIFEXITED(child_wait_status) ||
|
||||
WIFSIGNALED(child_wait_status))
|
||||
child_terminated = 1;
|
||||
}
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process any buffered packets that have been received from the client.
|
||||
*/
|
||||
void
|
||||
process_buffered_input_packets()
|
||||
{
|
||||
int type;
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
int row, col, xpixel, ypixel;
|
||||
int payload_len;
|
||||
|
||||
/* Process buffered packets from the client. */
|
||||
while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
|
||||
switch (type) {
|
||||
case SSH_CMSG_STDIN_DATA:
|
||||
/* Stdin data from the client. Append it to the buffer. */
|
||||
/* Ignore any data if the client has closed stdin. */
|
||||
if (fdin == -1)
|
||||
break;
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, (4 + data_len), type);
|
||||
buffer_append(&stdin_buffer, data, data_len);
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_EOF:
|
||||
/*
|
||||
* Eof from the client. The stdin descriptor to the
|
||||
* program will be closed when all buffered data has
|
||||
* drained.
|
||||
*/
|
||||
debug("EOF received for stdin.");
|
||||
packet_integrity_check(payload_len, 0, type);
|
||||
stdin_eof = 1;
|
||||
break;
|
||||
|
||||
case SSH_CMSG_WINDOW_SIZE:
|
||||
debug("Window change received.");
|
||||
packet_integrity_check(payload_len, 4 * 4, type);
|
||||
row = packet_get_int();
|
||||
col = packet_get_int();
|
||||
xpixel = packet_get_int();
|
||||
ypixel = packet_get_int();
|
||||
if (fdin != -1)
|
||||
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
||||
break;
|
||||
|
||||
case SSH_MSG_PORT_OPEN:
|
||||
debug("Received port open request.");
|
||||
channel_input_port_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
debug("Received channel open confirmation.");
|
||||
packet_integrity_check(payload_len, 4 + 4, type);
|
||||
channel_input_open_confirmation();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
debug("Received channel open failure.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_open_failure();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
channel_input_data(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
debug("Received channel close.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
debug("Received channel close confirmation.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close_confirmation();
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* In this phase, any unexpected messages cause a
|
||||
* protocol error. This is to ease debugging; also,
|
||||
* since no confirmations are sent messages,
|
||||
* unprocessed unknown messages could cause strange
|
||||
* problems. Any compatible protocol extensions must
|
||||
* be negotiated before entering the interactive
|
||||
* session.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stderr data, and buffer it for sending
|
||||
* to the client.
|
||||
*/
|
||||
void
|
||||
make_packets_from_stderr_data()
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Send buffered stderr data to the client. */
|
||||
while (buffer_len(&stderr_buffer) > 0 &&
|
||||
packet_not_very_much_data_to_write()) {
|
||||
len = buffer_len(&stderr_buffer);
|
||||
if (packet_is_interactive()) {
|
||||
if (len > 512)
|
||||
len = 512;
|
||||
} else {
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize())
|
||||
len = packet_get_maxsize();
|
||||
}
|
||||
packet_start(SSH_SMSG_STDERR_DATA);
|
||||
packet_put_string(buffer_ptr(&stderr_buffer), len);
|
||||
packet_send();
|
||||
buffer_consume(&stderr_buffer, len);
|
||||
stderr_bytes += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stdout data, and buffer it for sending to the
|
||||
* client.
|
||||
*/
|
||||
void
|
||||
make_packets_from_stdout_data()
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Send buffered stdout data to the client. */
|
||||
while (buffer_len(&stdout_buffer) > 0 &&
|
||||
packet_not_very_much_data_to_write()) {
|
||||
len = buffer_len(&stdout_buffer);
|
||||
if (packet_is_interactive()) {
|
||||
if (len > 512)
|
||||
len = 512;
|
||||
} else {
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize())
|
||||
len = packet_get_maxsize();
|
||||
}
|
||||
packet_start(SSH_SMSG_STDOUT_DATA);
|
||||
packet_put_string(buffer_ptr(&stdout_buffer), len);
|
||||
packet_send();
|
||||
buffer_consume(&stdout_buffer, len);
|
||||
stdout_bytes += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sleep in select() until we can do something. This will initialize the
|
||||
* select masks. Upon return, the masks will indicate which descriptors
|
||||
* have data or can accept data. Optionally, a maximum time can be specified
|
||||
* 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)
|
||||
{
|
||||
struct timeval tv, *tvp;
|
||||
int ret;
|
||||
|
||||
/* When select fails we restart from here. */
|
||||
retry_select:
|
||||
|
||||
/* Initialize select() masks. */
|
||||
FD_ZERO(readset);
|
||||
|
||||
/*
|
||||
* Read packets from the client unless we have too much buffered
|
||||
* stdin or channel data.
|
||||
*/
|
||||
if (buffer_len(&stdin_buffer) < 4096 &&
|
||||
channel_not_very_much_buffered_data())
|
||||
FD_SET(connection_in, readset);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (!fderr_eof)
|
||||
FD_SET(fderr, readset);
|
||||
}
|
||||
FD_ZERO(writeset);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Update the maximum descriptor number if appropriate. */
|
||||
if (channel_max_fd() > max_fd)
|
||||
max_fd = channel_max_fd();
|
||||
|
||||
/*
|
||||
* 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)
|
||||
max_time_milliseconds = 100;
|
||||
|
||||
if (max_time_milliseconds == 0)
|
||||
tvp = NULL;
|
||||
else {
|
||||
tv.tv_sec = max_time_milliseconds / 1000;
|
||||
tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
/* Wait for something to happen, or the timeout to expire. */
|
||||
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
error("select: %.100s", strerror(errno));
|
||||
else
|
||||
goto retry_select;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes input from the client and the program. Input data is stored
|
||||
* in buffers and processed later.
|
||||
*/
|
||||
void
|
||||
process_input(fd_set * readset)
|
||||
{
|
||||
int len;
|
||||
char buf[16384];
|
||||
|
||||
/* Read and buffer any input data from the client. */
|
||||
if (FD_ISSET(connection_in, readset)) {
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
verbose("Connection closed by remote host.");
|
||||
fatal_cleanup();
|
||||
}
|
||||
/*
|
||||
* 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)
|
||||
len = 0;
|
||||
|
||||
if (len < 0) {
|
||||
verbose("Read error from remote host: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
/* Buffer any received data. */
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
/* Read and buffer any available stdout data from the program. */
|
||||
if (!fdout_eof && FD_ISSET(fdout, readset)) {
|
||||
len = read(fdout, buf, sizeof(buf));
|
||||
if (len <= 0)
|
||||
fdout_eof = 1;
|
||||
else {
|
||||
buffer_append(&stdout_buffer, buf, len);
|
||||
fdout_bytes += len;
|
||||
}
|
||||
}
|
||||
/* Read and buffer any available stderr data from the program. */
|
||||
if (!fderr_eof && FD_ISSET(fderr, readset)) {
|
||||
len = read(fderr, buf, sizeof(buf));
|
||||
if (len <= 0)
|
||||
fderr_eof = 1;
|
||||
else
|
||||
buffer_append(&stderr_buffer, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends data from internal buffers to client program stdin.
|
||||
*/
|
||||
void
|
||||
process_output(fd_set * writeset)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Write buffered data to program stdin. */
|
||||
if (fdin != -1 && FD_ISSET(fdin, writeset)) {
|
||||
len = write(fdin, buffer_ptr(&stdin_buffer),
|
||||
buffer_len(&stdin_buffer));
|
||||
if (len <= 0) {
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
#else
|
||||
if (fdout == -1)
|
||||
close(fdin);
|
||||
else
|
||||
shutdown(fdin, SHUT_WR); /* We will no longer send. */
|
||||
#endif
|
||||
fdin = -1;
|
||||
} else {
|
||||
/* Successful write. Consume the data from the buffer. */
|
||||
buffer_consume(&stdin_buffer, len);
|
||||
/* Update the count of bytes written to the program. */
|
||||
stdin_bytes += len;
|
||||
}
|
||||
}
|
||||
/* Send any buffered packet data to the client. */
|
||||
if (FD_ISSET(connection_out, writeset))
|
||||
packet_write_poll();
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until all buffered output has been sent to the client.
|
||||
* This is used when the program terminates.
|
||||
*/
|
||||
void
|
||||
drain_output()
|
||||
{
|
||||
/* Send any buffered stdout data to the client. */
|
||||
if (buffer_len(&stdout_buffer) > 0) {
|
||||
packet_start(SSH_SMSG_STDOUT_DATA);
|
||||
packet_put_string(buffer_ptr(&stdout_buffer),
|
||||
buffer_len(&stdout_buffer));
|
||||
packet_send();
|
||||
/* Update the count of sent bytes. */
|
||||
stdout_bytes += buffer_len(&stdout_buffer);
|
||||
}
|
||||
/* Send any buffered stderr data to the client. */
|
||||
if (buffer_len(&stderr_buffer) > 0) {
|
||||
packet_start(SSH_SMSG_STDERR_DATA);
|
||||
packet_put_string(buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
packet_send();
|
||||
/* Update the count of sent bytes. */
|
||||
stderr_bytes += buffer_len(&stderr_buffer);
|
||||
}
|
||||
/* Wait until all buffered data has been written to the client. */
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
{
|
||||
int wait_status, wait_pid; /* Status and 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;
|
||||
int type;
|
||||
|
||||
debug("Entering interactive session.");
|
||||
|
||||
/* Initialize the SIGCHLD kludge. */
|
||||
child_pid = pid;
|
||||
child_terminated = 0;
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
|
||||
/* Initialize our global variables. */
|
||||
fdin = fdin_arg;
|
||||
fdout = fdout_arg;
|
||||
fderr = fderr_arg;
|
||||
connection_in = packet_get_connection_in();
|
||||
connection_out = packet_get_connection_out();
|
||||
|
||||
previous_stdout_buffer_bytes = 0;
|
||||
|
||||
/* Set approximate I/O buffer size. */
|
||||
if (packet_is_interactive())
|
||||
buffer_high = 4096;
|
||||
else
|
||||
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;
|
||||
|
||||
/* Initialize Initialize buffers. */
|
||||
buffer_init(&stdin_buffer);
|
||||
buffer_init(&stdout_buffer);
|
||||
buffer_init(&stderr_buffer);
|
||||
|
||||
/*
|
||||
* If we have no separate fderr (which is the case when we have a pty
|
||||
* - there we cannot make difference between data sent to stdout and
|
||||
* stderr), indicate that we have seen an EOF from stderr. This way
|
||||
* we don\'t need to check the descriptor everywhere.
|
||||
*/
|
||||
if (fderr == -1)
|
||||
fderr_eof = 1;
|
||||
|
||||
/* Main loop of the server for the interactive session mode. */
|
||||
for (;;) {
|
||||
fd_set readset, writeset;
|
||||
|
||||
/* Process buffered packets from the client. */
|
||||
process_buffered_input_packets();
|
||||
|
||||
/*
|
||||
* If we have received eof, and there is no more pending
|
||||
* input data, cause a real eof by closing fdin.
|
||||
*/
|
||||
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
#else
|
||||
if (fdout == -1)
|
||||
close(fdin);
|
||||
else
|
||||
shutdown(fdin, SHUT_WR); /* We will no longer send. */
|
||||
#endif
|
||||
fdin = -1;
|
||||
}
|
||||
/* Make packets from buffered stderr data to send to the client. */
|
||||
make_packets_from_stderr_data();
|
||||
|
||||
/*
|
||||
* Make packets from buffered stdout data to send to the
|
||||
* client. If there is very little to send, this arranges to
|
||||
* not send them now, but to wait a short while to see if we
|
||||
* are getting more data. This is necessary, as some systems
|
||||
* wake up readers from a pty after each separate character.
|
||||
*/
|
||||
max_time_milliseconds = 0;
|
||||
stdout_buffer_bytes = buffer_len(&stdout_buffer);
|
||||
if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
|
||||
stdout_buffer_bytes != previous_stdout_buffer_bytes) {
|
||||
/* try again after a while */
|
||||
max_time_milliseconds = 10;
|
||||
} else {
|
||||
/* Send it now. */
|
||||
make_packets_from_stdout_data();
|
||||
}
|
||||
previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
|
||||
|
||||
/* Send channel data to the client. */
|
||||
if (packet_not_very_much_data_to_write())
|
||||
channel_output_poll();
|
||||
|
||||
/*
|
||||
* Bail out of the loop if the program has closed its output
|
||||
* descriptors, and we have no more data to send to the
|
||||
* client, and there is no pending buffered data.
|
||||
*/
|
||||
if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
|
||||
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
|
||||
if (!channel_still_open())
|
||||
goto quit;
|
||||
if (!waiting_termination) {
|
||||
const char *s = "Waiting for forwarded connections to terminate...\r\n";
|
||||
char *cp;
|
||||
waiting_termination = 1;
|
||||
buffer_append(&stderr_buffer, s, strlen(s));
|
||||
|
||||
/* Display list of open channels. */
|
||||
cp = channel_open_message();
|
||||
buffer_append(&stderr_buffer, cp, strlen(cp));
|
||||
xfree(cp);
|
||||
}
|
||||
}
|
||||
/* Sleep in select() until we can do something. */
|
||||
wait_until_can_do_something(&readset, &writeset,
|
||||
max_time_milliseconds);
|
||||
|
||||
/* Process any channel events. */
|
||||
channel_after_select(&readset, &writeset);
|
||||
|
||||
/* Process input from the client and from program stdout/stderr. */
|
||||
process_input(&readset);
|
||||
|
||||
/* Process output to the client and to program stdin. */
|
||||
process_output(&writeset);
|
||||
}
|
||||
|
||||
quit:
|
||||
/* Cleanup and termination code. */
|
||||
|
||||
/* Wait until all output has been sent to the client. */
|
||||
drain_output();
|
||||
|
||||
debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
|
||||
stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
|
||||
|
||||
/* Free and clear the buffers. */
|
||||
buffer_free(&stdin_buffer);
|
||||
buffer_free(&stdout_buffer);
|
||||
buffer_free(&stderr_buffer);
|
||||
|
||||
/* Close the file descriptors. */
|
||||
if (fdout != -1)
|
||||
close(fdout);
|
||||
fdout = -1;
|
||||
fdout_eof = 1;
|
||||
if (fderr != -1)
|
||||
close(fderr);
|
||||
fderr = -1;
|
||||
fderr_eof = 1;
|
||||
if (fdin != -1)
|
||||
close(fdin);
|
||||
fdin = -1;
|
||||
|
||||
/* Stop listening for channels; this removes unix domain sockets. */
|
||||
channel_stop_listening();
|
||||
|
||||
/* Wait for the child to exit. Get its exit status. */
|
||||
wait_pid = wait(&wait_status);
|
||||
if (wait_pid < 0) {
|
||||
/*
|
||||
* It is possible that the wait was handled by SIGCHLD
|
||||
* handler. This may result in either: this call
|
||||
* returning with EINTR, or: this call returning ECHILD.
|
||||
*/
|
||||
if (child_terminated)
|
||||
wait_status = child_wait_status;
|
||||
else
|
||||
packet_disconnect("wait: %.100s", strerror(errno));
|
||||
} else {
|
||||
/* Check if it matches the process we forked. */
|
||||
if (wait_pid != pid)
|
||||
error("Strange, wait returned pid %d, expected %d",
|
||||
wait_pid, pid);
|
||||
}
|
||||
|
||||
/* We no longer want our SIGCHLD handler to be called. */
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
/* Check if it exited normally. */
|
||||
if (WIFEXITED(wait_status)) {
|
||||
/* Yes, normal exit. Get exit status and send it to the client. */
|
||||
debug("Command exited with status %d.", WEXITSTATUS(wait_status));
|
||||
packet_start(SSH_SMSG_EXITSTATUS);
|
||||
packet_put_int(WEXITSTATUS(wait_status));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/*
|
||||
* Wait for exit confirmation. Note that there might be
|
||||
* other packets coming before it; however, the program has
|
||||
* already died so we just ignore them. The client is
|
||||
* supposed to respond with the confirmation when it receives
|
||||
* the exit status.
|
||||
*/
|
||||
do {
|
||||
int plen;
|
||||
type = packet_read(&plen);
|
||||
}
|
||||
while (type != SSH_CMSG_EXIT_CONFIRMATION);
|
||||
|
||||
debug("Received exit confirmation.");
|
||||
return;
|
||||
}
|
||||
/* Check if the program terminated due to a signal. */
|
||||
if (WIFSIGNALED(wait_status))
|
||||
packet_disconnect("Command terminated on signal %d.",
|
||||
WTERMSIG(wait_status));
|
||||
|
||||
/* Some weird exit cause. Just exit. */
|
||||
packet_disconnect("wait returned status %04x.", wait_status);
|
||||
/* NOTREACHED */
|
||||
}
|
124
crypto/openssh/ssh-add.1
Normal file
124
crypto/openssh/ssh-add.1
Normal file
@ -0,0 +1,124 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" ssh-add.1
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\"
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh-add.1,v 1.10 2000/01/22 02:17:50 aaron Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH-ADD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-add
|
||||
.Nd adds identities for the authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-add
|
||||
.Op Fl lLdD
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
adds identities to the authentication agent,
|
||||
.Xr ssh-agent 1 .
|
||||
When run without arguments, it adds the file
|
||||
.Pa $HOME/.ssh/identity .
|
||||
Alternative file names can be given on the
|
||||
command line. If any file requires a passphrase,
|
||||
.Nm
|
||||
asks for the passphrase from the user.
|
||||
The Passphrase it is read from the user's tty.
|
||||
.Pp
|
||||
The authentication agent must be running and must be an ancestor of
|
||||
the current process for
|
||||
.Nm
|
||||
to work.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl l
|
||||
Lists fingerprints of all identities currently represented by the agent.
|
||||
.It Fl L
|
||||
Lists public key parameters of all identities currently represented by the agent.
|
||||
.It Fl d
|
||||
Instead of adding the identity, removes the identity from the agent.
|
||||
.It Fl D
|
||||
Deletes all identities from the agent.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa $HOME/.ssh/identity
|
||||
Contains the RSA authentication identity of the user. This file
|
||||
should not be readable by anyone but the user.
|
||||
Note that
|
||||
.Nm
|
||||
ignores this file if it is accessible by others.
|
||||
It is possible to
|
||||
specify a passphrase when generating the key; that passphrase will be
|
||||
used to encrypt the private part of this file. This is the
|
||||
default file added by
|
||||
.Nm
|
||||
when no other files have been specified.
|
||||
.Pp
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ds
|
||||
.It Ev "DISPLAY" and "SSH_ASKPASS"
|
||||
If
|
||||
.Nm
|
||||
needs a passphrase, it will read the passphrase from the current
|
||||
terminal if it was run from a terminal. If
|
||||
.Nm
|
||||
does not have a terminal associated with it but
|
||||
.Ev DISPLAY
|
||||
and
|
||||
.Ev SSH_ASKPASS
|
||||
are set, it will execute the program specified by
|
||||
.Ev SSH_ASKPASS
|
||||
and open an X11 window to read the passphrase. This is particularly
|
||||
useful when calling
|
||||
.Nm
|
||||
from a
|
||||
.Pa .Xsession
|
||||
or related script. (Note that on some machines it
|
||||
may be necessary to redirect the input from
|
||||
.Pa /dev/null
|
||||
to make this work.)
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Pp
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
|
||||
removed and newer features re-added. Rapidly after the 1.2.12 release,
|
||||
newer versions bore successively more restrictive licenses. This version
|
||||
of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
has all components of a restrictive nature (i.e., patents, see
|
||||
.Xr ssl 8 )
|
||||
directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
supports one-time password authentication with
|
||||
.Xr skey 1 .
|
||||
.El
|
||||
.Pp
|
||||
The libraries described in
|
||||
.Xr ssl 8
|
||||
are required for proper operation.
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8 ,
|
||||
.Xr ssl 8
|
255
crypto/openssh/ssh-add.c
Normal file
255
crypto/openssh/ssh-add.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Thu Apr 6 00:52:24 1995 ylo
|
||||
* Adds an identity to the authentication server, or removes an identity.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "authfd.h"
|
||||
#include "fingerprint.h"
|
||||
|
||||
void
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
char *comment;
|
||||
|
||||
key = RSA_new();
|
||||
if (!load_public_key(filename, key, &comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ssh_remove_identity(ac, key))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
void
|
||||
delete_all(AuthenticationConnection *ac)
|
||||
{
|
||||
/* Send a request to remove all identities. */
|
||||
if (ssh_remove_all_identities(ac))
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to remove all identitities.\n");
|
||||
}
|
||||
|
||||
char *
|
||||
ssh_askpass(char *askpass, char *msg)
|
||||
{
|
||||
pid_t pid;
|
||||
size_t len;
|
||||
char *nl, *pass;
|
||||
int p[2], status;
|
||||
char buf[1024];
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
char *saved_comment, *comment, *askpass = NULL;
|
||||
char buf[1024], msg[1024];
|
||||
int success;
|
||||
int interactive = isatty(STDIN_FILENO);
|
||||
|
||||
key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(filename, public_key, &saved_comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
RSA_free(public_key);
|
||||
|
||||
if (!interactive && getenv("DISPLAY")) {
|
||||
if (getenv(SSH_ASKPASS_ENV))
|
||||
askpass = getenv(SSH_ASKPASS_ENV);
|
||||
else
|
||||
askpass = SSH_ASKPASS_DEFAULT;
|
||||
}
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %.200s\n", filename);
|
||||
if (!interactive && askpass == NULL) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
|
||||
for (;;) {
|
||||
char *pass;
|
||||
if (interactive) {
|
||||
snprintf(buf, sizeof buf, "%s: ", msg);
|
||||
pass = read_passphrase(buf, 1);
|
||||
} else {
|
||||
pass = ssh_askpass(askpass, msg);
|
||||
}
|
||||
if (strcmp(pass, "") == 0) {
|
||||
xfree(pass);
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, key, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
break;
|
||||
strlcpy(msg, "Bad passphrase, try again", sizeof msg);
|
||||
}
|
||||
}
|
||||
xfree(saved_comment);
|
||||
|
||||
if (ssh_add_identity(ac, key, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
void
|
||||
list_identities(AuthenticationConnection *ac, int fp)
|
||||
{
|
||||
BIGNUM *e, *n;
|
||||
int status;
|
||||
char *comment;
|
||||
int had_identities;
|
||||
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
had_identities = 0;
|
||||
for (status = ssh_get_first_identity(ac, e, n, &comment);
|
||||
status;
|
||||
status = ssh_get_next_identity(ac, e, n, &comment)) {
|
||||
unsigned int bits = BN_num_bits(n);
|
||||
had_identities = 1;
|
||||
if (fp) {
|
||||
printf("%d %s %s\n", bits, fingerprint(e, n), comment);
|
||||
} else {
|
||||
char *ebuf, *nbuf;
|
||||
ebuf = BN_bn2dec(e);
|
||||
if (ebuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(e) failed.");
|
||||
} else {
|
||||
nbuf = BN_bn2dec(n);
|
||||
if (nbuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(n) failed.");
|
||||
} else {
|
||||
printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
|
||||
free(nbuf);
|
||||
}
|
||||
free(ebuf);
|
||||
}
|
||||
}
|
||||
xfree(comment);
|
||||
}
|
||||
BN_clear_free(e);
|
||||
BN_clear_free(n);
|
||||
if (!had_identities)
|
||||
printf("The agent has no identities.\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
AuthenticationConnection *ac = NULL;
|
||||
struct passwd *pw;
|
||||
char buf[1024];
|
||||
int no_files = 1;
|
||||
int i;
|
||||
int deleting = 0;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
extern char *__progname;
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* At first, get a connection to the authentication agent. */
|
||||
ac = ssh_get_authentication_connection();
|
||||
if (ac == NULL) {
|
||||
fprintf(stderr, "Could not open a connection to your authentication agent.\n");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if ((strcmp(argv[i], "-l") == 0) ||
|
||||
(strcmp(argv[i], "-L") == 0)) {
|
||||
list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
|
||||
/* Don't default-add/delete if -l. */
|
||||
no_files = 0;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-d") == 0) {
|
||||
deleting = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-D") == 0) {
|
||||
delete_all(ac);
|
||||
no_files = 0;
|
||||
continue;
|
||||
}
|
||||
no_files = 0;
|
||||
if (deleting)
|
||||
delete_file(ac, argv[i]);
|
||||
else
|
||||
add_file(ac, argv[i]);
|
||||
}
|
||||
if (no_files) {
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
fprintf(stderr, "No user found with uid %d\n", (int) getuid());
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(1);
|
||||
}
|
||||
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
|
||||
if (deleting)
|
||||
delete_file(ac, buf);
|
||||
else
|
||||
add_file(ac, buf);
|
||||
}
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(0);
|
||||
}
|
21
crypto/openssh/ssh-add/Makefile
Normal file
21
crypto/openssh/ssh-add/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= ssh-add
|
||||
BINOWN= root
|
||||
|
||||
.if (${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "powerpc" || \
|
||||
${MACHINE_ARCH} == "hppa")
|
||||
BINMODE=0000
|
||||
.else
|
||||
BINMODE?=555
|
||||
.endif
|
||||
|
||||
BINDIR= /usr/bin
|
||||
MAN= ssh-add.1
|
||||
|
||||
SRCS= ssh-add.c log-client.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
LDADD+= -lcrypto -lutil -lz
|
||||
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
|
163
crypto/openssh/ssh-agent.1
Normal file
163
crypto/openssh/ssh-agent.1
Normal file
@ -0,0 +1,163 @@
|
||||
.\" $OpenBSD: ssh-agent.1,v 1.9 2000/01/22 02:17:50 aaron Exp $
|
||||
.\"
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" ssh-agent.1
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\"
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Created: Sat Apr 23 20:10:43 1995 ylo
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH-AGENT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-agent
|
||||
.Nd authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-agent
|
||||
.Op Fl c Li | Fl s
|
||||
.Op Fl k
|
||||
.Oo
|
||||
.Ar command
|
||||
.Op Ar args ...
|
||||
.Oc
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a program to hold authentication private keys. The
|
||||
idea is that
|
||||
.Nm
|
||||
is started in the beginning of an X-session or a login session, and
|
||||
all other windows or programs are started as clients to the ssh-agent
|
||||
program. Through use of environment variables the agent can be located
|
||||
and automatically used for RSA authentication when logging in to other
|
||||
machines using
|
||||
.Xr ssh 1 .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl c
|
||||
Generate C-shell commands on
|
||||
.Dv stdout .
|
||||
This is the default if
|
||||
.Ev SHELL
|
||||
looks like it's a csh style of shell.
|
||||
.It Fl s
|
||||
Generate Bourne shell commands on
|
||||
.Dv stdout .
|
||||
This is the default if
|
||||
.Ev SHELL
|
||||
does not look like it's a csh style of shell.
|
||||
.It Fl k
|
||||
Kill the current agent (given by the
|
||||
.Ev SSH_AGENT_PID
|
||||
environment variable).
|
||||
.El
|
||||
.Pp
|
||||
If a commandline is given, this is executed as a subprocess of the agent.
|
||||
When the command dies, so does the agent.
|
||||
.Pp
|
||||
The agent initially does not have any private keys. Keys are added
|
||||
using
|
||||
.Xr ssh-add 1 .
|
||||
When executed without arguments,
|
||||
.Xr ssh-add 1
|
||||
adds the
|
||||
.Pa $HOME/.ssh/identity
|
||||
file. If the identity has a passphrase,
|
||||
.Xr ssh-add 1
|
||||
asks for the passphrase (using a small X11 application if running
|
||||
under X11, or from the terminal if running without X). It then sends
|
||||
the identity to the agent. Several identities can be stored in the
|
||||
agent; the agent can automatically use any of these identities.
|
||||
.Ic ssh-add -l
|
||||
displays the identities currently held by the agent.
|
||||
.Pp
|
||||
The idea is that the agent is run in the user's local PC, laptop, or
|
||||
terminal. Authentication data need not be stored on any other
|
||||
machine, and authentication passphrases never go over the network.
|
||||
However, the connection to the agent is forwarded over SSH
|
||||
remote logins, and the user can thus use the privileges given by the
|
||||
identities anywhere in the network in a secure way.
|
||||
.Pp
|
||||
There are two main ways to get an agent setup: Either you let the agent
|
||||
start a new subcommand into which some environment variables are exported, or
|
||||
you let the agent print the needed shell commands (either
|
||||
.Xr sh 1
|
||||
or
|
||||
.Xr csh 1
|
||||
syntax can be generated) which can be evalled in the calling shell.
|
||||
Later
|
||||
.Xr ssh 1
|
||||
look at these variables and use them to establish a connection to the agent.
|
||||
.Pp
|
||||
A unix-domain socket is created
|
||||
.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
|
||||
and the name of this socket is stored in the
|
||||
.Ev SSH_AUTH_SOCK
|
||||
environment
|
||||
variable. The socket is made accessible only to the current user.
|
||||
This method is easily abused by root or another instance of the same
|
||||
user.
|
||||
.Pp
|
||||
The
|
||||
.Ev SSH_AGENT_PID
|
||||
environment variable holds the agent's PID.
|
||||
.Pp
|
||||
The agent exits automatically when the command given on the command
|
||||
line terminates.
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa $HOME/.ssh/identity
|
||||
Contains the RSA authentication identity of the user. This file
|
||||
should not be readable by anyone but the user. It is possible to
|
||||
specify a passphrase when generating the key; that passphrase will be
|
||||
used to encrypt the private part of this file. This file
|
||||
is not used by
|
||||
.Nm
|
||||
but is normally added to the agent using
|
||||
.Xr ssh-add 1
|
||||
at login time.
|
||||
.It Pa /tmp/ssh-XXXX/agent.<pid> ,
|
||||
Unix-domain sockets used to contain the connection to the
|
||||
authentication agent. These sockets should only be readable by the
|
||||
owner. The sockets should get automatically removed when the agent
|
||||
exits.
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Pp
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
|
||||
removed and newer features re-added. Rapidly after the 1.2.12 release,
|
||||
newer versions bore successively more restrictive licenses. This version
|
||||
of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
has all components of a restrictive nature (i.e., patents, see
|
||||
.Xr ssl 8 )
|
||||
directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
supports one-time password authentication with
|
||||
.Xr skey 1 .
|
||||
.El
|
||||
.Pp
|
||||
The libraries described in
|
||||
.Xr ssl 8
|
||||
are required for proper operation.
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8 ,
|
||||
.Xr ssl 8
|
653
crypto/openssh/ssh-agent.c
Normal file
653
crypto/openssh/ssh-agent.c
Normal file
@ -0,0 +1,653 @@
|
||||
/* $OpenBSD: ssh-agent.c,v 1.25 2000/01/02 21:51:03 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Wed Mar 29 03:46:59 1995 ylo
|
||||
* The authentication agent program.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh-agent.c,v 1.25 2000/01/02 21:51:03 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "authfd.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "packet.h"
|
||||
#include "getput.h"
|
||||
#include "mpaux.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
enum {
|
||||
AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
|
||||
} type;
|
||||
Buffer input;
|
||||
Buffer output;
|
||||
} SocketEntry;
|
||||
|
||||
unsigned int sockets_alloc = 0;
|
||||
SocketEntry *sockets = NULL;
|
||||
|
||||
typedef struct {
|
||||
RSA *key;
|
||||
char *comment;
|
||||
} Identity;
|
||||
|
||||
unsigned int num_identities = 0;
|
||||
Identity *identities = NULL;
|
||||
|
||||
int max_fd = 0;
|
||||
|
||||
/* pid of shell == parent of agent */
|
||||
int parent_pid = -1;
|
||||
|
||||
/* pathname and directory for AUTH_SOCKET */
|
||||
char socket_name[1024];
|
||||
char socket_dir[1024];
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
process_request_identity(SocketEntry *e)
|
||||
{
|
||||
Buffer msg;
|
||||
int i;
|
||||
|
||||
buffer_init(&msg);
|
||||
buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
|
||||
buffer_put_int(&msg, num_identities);
|
||||
for (i = 0; i < num_identities; i++) {
|
||||
buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
|
||||
buffer_put_bignum(&msg, identities[i].key->e);
|
||||
buffer_put_bignum(&msg, identities[i].key->n);
|
||||
buffer_put_string(&msg, identities[i].comment,
|
||||
strlen(identities[i].comment));
|
||||
}
|
||||
buffer_put_int(&e->output, buffer_len(&msg));
|
||||
buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
|
||||
buffer_free(&msg);
|
||||
}
|
||||
|
||||
void
|
||||
process_authentication_challenge(SocketEntry *e)
|
||||
{
|
||||
int i, pub_bits, len;
|
||||
BIGNUM *pub_e, *pub_n, *challenge;
|
||||
Buffer msg;
|
||||
MD5_CTX md;
|
||||
unsigned char buf[32], mdbuf[16], session_id[16];
|
||||
unsigned int response_type;
|
||||
|
||||
buffer_init(&msg);
|
||||
pub_e = BN_new();
|
||||
pub_n = BN_new();
|
||||
challenge = BN_new();
|
||||
pub_bits = buffer_get_int(&e->input);
|
||||
buffer_get_bignum(&e->input, pub_e);
|
||||
buffer_get_bignum(&e->input, pub_n);
|
||||
buffer_get_bignum(&e->input, challenge);
|
||||
if (buffer_len(&e->input) == 0) {
|
||||
/* Compatibility code for old servers. */
|
||||
memset(session_id, 0, 16);
|
||||
response_type = 0;
|
||||
} else {
|
||||
/* New code. */
|
||||
buffer_get(&e->input, (char *) session_id, 16);
|
||||
response_type = buffer_get_int(&e->input);
|
||||
}
|
||||
for (i = 0; i < num_identities; i++)
|
||||
if (pub_bits == BN_num_bits(identities[i].key->n) &&
|
||||
BN_cmp(pub_e, identities[i].key->e) == 0 &&
|
||||
BN_cmp(pub_n, identities[i].key->n) == 0) {
|
||||
/* Decrypt the challenge using the private key. */
|
||||
rsa_private_decrypt(challenge, challenge, identities[i].key);
|
||||
|
||||
/* Compute the desired response. */
|
||||
switch (response_type) {
|
||||
case 0:/* As of protocol 1.0 */
|
||||
/* This response type is no longer supported. */
|
||||
log("Compatibility with ssh protocol 1.0 no longer supported.");
|
||||
buffer_put_char(&msg, SSH_AGENT_FAILURE);
|
||||
goto send;
|
||||
|
||||
case 1:/* As of protocol 1.1 */
|
||||
/* The response is MD5 of decrypted challenge plus session id. */
|
||||
len = BN_num_bytes(challenge);
|
||||
|
||||
if (len <= 0 || len > 32) {
|
||||
fatal("process_authentication_challenge: "
|
||||
"bad challenge length %d", len);
|
||||
}
|
||||
memset(buf, 0, 32);
|
||||
BN_bn2bin(challenge, buf + 32 - len);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, 32);
|
||||
MD5_Update(&md, session_id, 16);
|
||||
MD5_Final(mdbuf, &md);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("process_authentication_challenge: bad response_type %d",
|
||||
response_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send the response. */
|
||||
buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
|
||||
for (i = 0; i < 16; i++)
|
||||
buffer_put_char(&msg, mdbuf[i]);
|
||||
|
||||
goto send;
|
||||
}
|
||||
/* Unknown identity. Send failure. */
|
||||
buffer_put_char(&msg, SSH_AGENT_FAILURE);
|
||||
send:
|
||||
buffer_put_int(&e->output, buffer_len(&msg));
|
||||
buffer_append(&e->output, buffer_ptr(&msg),
|
||||
buffer_len(&msg));
|
||||
buffer_free(&msg);
|
||||
BN_clear_free(pub_e);
|
||||
BN_clear_free(pub_n);
|
||||
BN_clear_free(challenge);
|
||||
}
|
||||
|
||||
void
|
||||
process_remove_identity(SocketEntry *e)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int i;
|
||||
BIGNUM *dummy, *n;
|
||||
|
||||
dummy = BN_new();
|
||||
n = BN_new();
|
||||
|
||||
/* Get the key from the packet. */
|
||||
bits = buffer_get_int(&e->input);
|
||||
buffer_get_bignum(&e->input, dummy);
|
||||
buffer_get_bignum(&e->input, n);
|
||||
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: identity keysize mismatch: actual %d, announced %d",
|
||||
BN_num_bits(n), bits);
|
||||
|
||||
/* Check if we have the key. */
|
||||
for (i = 0; i < num_identities; i++)
|
||||
if (BN_cmp(identities[i].key->n, n) == 0) {
|
||||
/*
|
||||
* We have this key. Free the old key. Since we
|
||||
* don\'t want to leave empty slots in the middle of
|
||||
* the array, we actually free the key there and copy
|
||||
* data from the last entry.
|
||||
*/
|
||||
RSA_free(identities[i].key);
|
||||
xfree(identities[i].comment);
|
||||
if (i < num_identities - 1)
|
||||
identities[i] = identities[num_identities - 1];
|
||||
num_identities--;
|
||||
BN_clear_free(dummy);
|
||||
BN_clear_free(n);
|
||||
|
||||
/* Send success. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
/* We did not have the key. */
|
||||
BN_clear(dummy);
|
||||
BN_clear(n);
|
||||
|
||||
/* Send failure. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes all identities from the agent.
|
||||
*/
|
||||
void
|
||||
process_remove_all_identities(SocketEntry *e)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Loop over all identities and clear the keys. */
|
||||
for (i = 0; i < num_identities; i++) {
|
||||
RSA_free(identities[i].key);
|
||||
xfree(identities[i].comment);
|
||||
}
|
||||
|
||||
/* Mark that there are no identities. */
|
||||
num_identities = 0;
|
||||
|
||||
/* Send success. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an identity to the agent.
|
||||
*/
|
||||
void
|
||||
process_add_identity(SocketEntry *e)
|
||||
{
|
||||
RSA *k;
|
||||
int i;
|
||||
BIGNUM *aux;
|
||||
BN_CTX *ctx;
|
||||
|
||||
if (num_identities == 0)
|
||||
identities = xmalloc(sizeof(Identity));
|
||||
else
|
||||
identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
|
||||
|
||||
identities[num_identities].key = RSA_new();
|
||||
k = identities[num_identities].key;
|
||||
buffer_get_int(&e->input); /* bits */
|
||||
k->n = BN_new();
|
||||
buffer_get_bignum(&e->input, k->n);
|
||||
k->e = BN_new();
|
||||
buffer_get_bignum(&e->input, k->e);
|
||||
k->d = BN_new();
|
||||
buffer_get_bignum(&e->input, k->d);
|
||||
k->iqmp = BN_new();
|
||||
buffer_get_bignum(&e->input, k->iqmp);
|
||||
/* SSH and SSL have p and q swapped */
|
||||
k->q = BN_new();
|
||||
buffer_get_bignum(&e->input, k->q); /* p */
|
||||
k->p = BN_new();
|
||||
buffer_get_bignum(&e->input, k->p); /* q */
|
||||
|
||||
/* Generate additional parameters */
|
||||
aux = BN_new();
|
||||
ctx = BN_CTX_new();
|
||||
|
||||
BN_sub(aux, k->q, BN_value_one());
|
||||
k->dmq1 = BN_new();
|
||||
BN_mod(k->dmq1, k->d, aux, ctx);
|
||||
|
||||
BN_sub(aux, k->p, BN_value_one());
|
||||
k->dmp1 = BN_new();
|
||||
BN_mod(k->dmp1, k->d, aux, ctx);
|
||||
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
identities[num_identities].comment = buffer_get_string(&e->input, NULL);
|
||||
|
||||
/* Check if we already have the key. */
|
||||
for (i = 0; i < num_identities; i++)
|
||||
if (BN_cmp(identities[i].key->n, k->n) == 0) {
|
||||
/*
|
||||
* We already have this key. Clear and free the new
|
||||
* data and return success.
|
||||
*/
|
||||
RSA_free(k);
|
||||
xfree(identities[num_identities].comment);
|
||||
|
||||
/* Send success. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
/* Increment the number of identities. */
|
||||
num_identities++;
|
||||
|
||||
/* Send a success message. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
process_message(SocketEntry *e)
|
||||
{
|
||||
unsigned int msg_len;
|
||||
unsigned int type;
|
||||
unsigned char *cp;
|
||||
if (buffer_len(&e->input) < 5)
|
||||
return; /* Incomplete message. */
|
||||
cp = (unsigned char *) buffer_ptr(&e->input);
|
||||
msg_len = GET_32BIT(cp);
|
||||
if (msg_len > 256 * 1024) {
|
||||
shutdown(e->fd, SHUT_RDWR);
|
||||
close(e->fd);
|
||||
e->type = AUTH_UNUSED;
|
||||
return;
|
||||
}
|
||||
if (buffer_len(&e->input) < msg_len + 4)
|
||||
return;
|
||||
buffer_consume(&e->input, 4);
|
||||
type = buffer_get_char(&e->input);
|
||||
|
||||
switch (type) {
|
||||
case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
|
||||
process_request_identity(e);
|
||||
break;
|
||||
case SSH_AGENTC_RSA_CHALLENGE:
|
||||
process_authentication_challenge(e);
|
||||
break;
|
||||
case SSH_AGENTC_ADD_RSA_IDENTITY:
|
||||
process_add_identity(e);
|
||||
break;
|
||||
case SSH_AGENTC_REMOVE_RSA_IDENTITY:
|
||||
process_remove_identity(e);
|
||||
break;
|
||||
case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
|
||||
process_remove_all_identities(e);
|
||||
break;
|
||||
default:
|
||||
/* Unknown message. Respond with failure. */
|
||||
error("Unknown message %d", type);
|
||||
buffer_clear(&e->input);
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
new_socket(int type, int fd)
|
||||
{
|
||||
unsigned int i, old_alloc;
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
error("fcntl O_NONBLOCK: %s", strerror(errno));
|
||||
|
||||
if (fd > max_fd)
|
||||
max_fd = fd;
|
||||
|
||||
for (i = 0; i < sockets_alloc; i++)
|
||||
if (sockets[i].type == AUTH_UNUSED) {
|
||||
sockets[i].fd = fd;
|
||||
sockets[i].type = type;
|
||||
buffer_init(&sockets[i].input);
|
||||
buffer_init(&sockets[i].output);
|
||||
return;
|
||||
}
|
||||
old_alloc = sockets_alloc;
|
||||
sockets_alloc += 10;
|
||||
if (sockets)
|
||||
sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
|
||||
else
|
||||
sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
|
||||
for (i = old_alloc; i < sockets_alloc; i++)
|
||||
sockets[i].type = AUTH_UNUSED;
|
||||
sockets[old_alloc].type = type;
|
||||
sockets[old_alloc].fd = fd;
|
||||
buffer_init(&sockets[old_alloc].input);
|
||||
buffer_init(&sockets[old_alloc].output);
|
||||
}
|
||||
|
||||
void
|
||||
prepare_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sockets_alloc; i++)
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_SOCKET:
|
||||
case AUTH_CONNECTION:
|
||||
FD_SET(sockets[i].fd, readset);
|
||||
if (buffer_len(&sockets[i].output) > 0)
|
||||
FD_SET(sockets[i].fd, writeset);
|
||||
break;
|
||||
case AUTH_UNUSED:
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown socket type %d", sockets[i].type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
after_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
unsigned int i;
|
||||
int len, sock;
|
||||
char buf[1024];
|
||||
struct sockaddr_un sunaddr;
|
||||
|
||||
for (i = 0; i < sockets_alloc; i++)
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_UNUSED:
|
||||
break;
|
||||
case AUTH_SOCKET:
|
||||
if (FD_ISSET(sockets[i].fd, readset)) {
|
||||
len = sizeof(sunaddr);
|
||||
sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &len);
|
||||
if (sock < 0) {
|
||||
perror("accept from AUTH_SOCKET");
|
||||
break;
|
||||
}
|
||||
new_socket(AUTH_CONNECTION, sock);
|
||||
}
|
||||
break;
|
||||
case AUTH_CONNECTION:
|
||||
if (buffer_len(&sockets[i].output) > 0 &&
|
||||
FD_ISSET(sockets[i].fd, writeset)) {
|
||||
len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
|
||||
buffer_len(&sockets[i].output));
|
||||
if (len <= 0) {
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
sockets[i].type = AUTH_UNUSED;
|
||||
break;
|
||||
}
|
||||
buffer_consume(&sockets[i].output, len);
|
||||
}
|
||||
if (FD_ISSET(sockets[i].fd, readset)) {
|
||||
len = read(sockets[i].fd, buf, sizeof(buf));
|
||||
if (len <= 0) {
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
sockets[i].type = AUTH_UNUSED;
|
||||
break;
|
||||
}
|
||||
buffer_append(&sockets[i].input, buf, len);
|
||||
process_message(&sockets[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown type %d", sockets[i].type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
check_parent_exists(int sig)
|
||||
{
|
||||
if (kill(parent_pid, 0) < 0) {
|
||||
/* printf("Parent has died - Authentication agent exiting.\n"); */
|
||||
exit(1);
|
||||
}
|
||||
signal(SIGALRM, check_parent_exists);
|
||||
alarm(10);
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_socket(void)
|
||||
{
|
||||
remove(socket_name);
|
||||
rmdir(socket_dir);
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_exit(int i)
|
||||
{
|
||||
cleanup_socket();
|
||||
exit(i);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
|
||||
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
|
||||
struct sockaddr_un sunaddr;
|
||||
pid_t pid;
|
||||
char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
while ((ch = getopt(ac, av, "cks")) != -1) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
if (s_flag)
|
||||
usage();
|
||||
c_flag++;
|
||||
break;
|
||||
case 'k':
|
||||
k_flag++;
|
||||
break;
|
||||
case 's':
|
||||
if (c_flag)
|
||||
usage();
|
||||
s_flag++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
ac -= optind;
|
||||
av += optind;
|
||||
|
||||
if (ac > 0 && (c_flag || k_flag || s_flag))
|
||||
usage();
|
||||
|
||||
if (ac == 0 && !c_flag && !k_flag && !s_flag) {
|
||||
shell = getenv("SHELL");
|
||||
if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
|
||||
c_flag = 1;
|
||||
}
|
||||
if (k_flag) {
|
||||
pidstr = getenv(SSH_AGENTPID_ENV_NAME);
|
||||
if (pidstr == NULL) {
|
||||
fprintf(stderr, "%s not set, cannot kill agent\n",
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
exit(1);
|
||||
}
|
||||
pid = atoi(pidstr);
|
||||
if (pid < 1) { /* XXX PID_MAX check too */
|
||||
fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
|
||||
SSH_AGENTPID_ENV_NAME, pidstr);
|
||||
exit(1);
|
||||
}
|
||||
if (kill(pid, SIGTERM) == -1) {
|
||||
perror("kill");
|
||||
exit(1);
|
||||
}
|
||||
format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
|
||||
printf(format, SSH_AUTHSOCKET_ENV_NAME);
|
||||
printf(format, SSH_AGENTPID_ENV_NAME);
|
||||
printf("echo Agent pid %d killed;\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
parent_pid = getpid();
|
||||
|
||||
/* Create private directory for agent socket */
|
||||
strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
|
||||
if (mkdtemp(socket_dir) == NULL) {
|
||||
perror("mkdtemp: private socket dir");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
|
||||
parent_pid);
|
||||
|
||||
/*
|
||||
* Create socket early so it will exist before command gets run from
|
||||
* the parent.
|
||||
*/
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("socket");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
memset(&sunaddr, 0, sizeof(sunaddr));
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
|
||||
if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
|
||||
perror("bind");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
if (listen(sock, 5) < 0) {
|
||||
perror("listen");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
/*
|
||||
* Fork, and have the parent execute the command, if any, or present
|
||||
* the socket data. The child continues as the authentication agent.
|
||||
*/
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
if (pid != 0) { /* Parent - execute the given command. */
|
||||
close(sock);
|
||||
snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
|
||||
if (ac == 0) {
|
||||
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
|
||||
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
|
||||
SSH_AUTHSOCKET_ENV_NAME);
|
||||
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
printf("echo Agent pid %d;\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
|
||||
setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
|
||||
execvp(av[0], av);
|
||||
perror(av[0]);
|
||||
exit(1);
|
||||
}
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
if (setsid() == -1) {
|
||||
perror("setsid");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
if (atexit(cleanup_socket) < 0) {
|
||||
perror("atexit");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
new_socket(AUTH_SOCKET, sock);
|
||||
if (ac > 0) {
|
||||
signal(SIGALRM, check_parent_exists);
|
||||
alarm(10);
|
||||
}
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, cleanup_exit);
|
||||
signal(SIGTERM, cleanup_exit);
|
||||
while (1) {
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&writeset);
|
||||
prepare_select(&readset, &writeset);
|
||||
if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
exit(1);
|
||||
}
|
||||
after_select(&readset, &writeset);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
21
crypto/openssh/ssh-agent/Makefile
Normal file
21
crypto/openssh/ssh-agent/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= ssh-agent
|
||||
BINOWN= root
|
||||
|
||||
.if (${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "powerpc" || \
|
||||
${MACHINE_ARCH} == "hppa")
|
||||
BINMODE=0000
|
||||
.else
|
||||
BINMODE?=555
|
||||
.endif
|
||||
|
||||
BINDIR= /usr/bin
|
||||
MAN= ssh-agent.1
|
||||
|
||||
SRCS= ssh-agent.c log-client.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
LDADD+= -lcrypto -lutil -lz
|
||||
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
|
161
crypto/openssh/ssh-keygen.1
Normal file
161
crypto/openssh/ssh-keygen.1
Normal file
@ -0,0 +1,161 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" ssh-keygen.1
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\"
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh-keygen.1,v 1.11 2000/01/22 02:17:50 aaron Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH-KEYGEN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-keygen
|
||||
.Nd authentication key generation
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-keygen
|
||||
.Op Fl q
|
||||
.Op Fl b Ar bits
|
||||
.Op Fl N Ar new_passphrase
|
||||
.Op Fl C Ar comment
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl p
|
||||
.Op Fl P Ar old_passphrase
|
||||
.Op Fl N Ar new_passphrase
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl c
|
||||
.Op Fl P Ar passphrase
|
||||
.Op Fl C Ar comment
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl l
|
||||
.Op Fl f Ar keyfile
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
generates and manages authentication keys for
|
||||
.Xr ssh 1 .
|
||||
Normally each user wishing to use SSH
|
||||
with RSA authentication runs this once to create the authentication
|
||||
key in
|
||||
.Pa $HOME/.ssh/identity .
|
||||
Additionally, the system administrator may use this to generate host keys.
|
||||
.Pp
|
||||
Normally this program generates the key and asks for a file in which
|
||||
to store the private key. The public key is stored in a file with the
|
||||
same name but
|
||||
.Dq .pub
|
||||
appended. The program also asks for a
|
||||
passphrase. The passphrase may be empty to indicate no passphrase
|
||||
(host keys must have empty passphrase), or it may be a string of
|
||||
arbitrary length. Good passphrases are 10-30 characters long and are
|
||||
not simple sentences or otherwise easily guessable (English
|
||||
prose has only 1-2 bits of entropy per word, and provides very bad
|
||||
passphrases). The passphrase can be changed later by using the
|
||||
.Fl p
|
||||
option.
|
||||
.Pp
|
||||
There is no way to recover a lost passphrase. If the passphrase is
|
||||
lost or forgotten, you will have to generate a new key and copy the
|
||||
corresponding public key to other machines.
|
||||
.Pp
|
||||
There is also a comment field in the key file that is only for
|
||||
convenience to the user to help identify the key. The comment can
|
||||
tell what the key is for, or whatever is useful. The comment is
|
||||
initialized to
|
||||
.Dq user@host
|
||||
when the key is created, but can be changed using the
|
||||
.Fl c
|
||||
option.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b Ar bits
|
||||
Specifies the number of bits in the key to create. Minimum is 512
|
||||
bits. Generally 1024 bits is considered sufficient, and key sizes
|
||||
above that no longer improve security but make things slower. The
|
||||
default is 1024 bits.
|
||||
.It Fl c
|
||||
Requests changing the comment in the private and public key files.
|
||||
The program will prompt for the file containing the private keys, for
|
||||
passphrase if the key has one, and for the new comment.
|
||||
.It Fl f
|
||||
Specifies the filename of the key file.
|
||||
.It Fl l
|
||||
Show fingerprint of specified private or public key file.
|
||||
.It Fl p
|
||||
Requests changing the passphrase of a private key file instead of
|
||||
creating a new private key. The program will prompt for the file
|
||||
containing the private key, for the old passphrase, and twice for the
|
||||
new passphrase.
|
||||
.It Fl q
|
||||
Silence
|
||||
.Nm ssh-keygen .
|
||||
Used by
|
||||
.Pa /etc/rc
|
||||
when creating a new key.
|
||||
.It Fl C Ar comment
|
||||
Provides the new comment.
|
||||
.It Fl N Ar new_passphrase
|
||||
Provides the new passphrase.
|
||||
.It Fl P Ar passphrase
|
||||
Provides the (old) passphrase.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa $HOME/.ssh/identity
|
||||
Contains the RSA authentication identity of the user. This file
|
||||
should not be readable by anyone but the user. It is possible to
|
||||
specify a passphrase when generating the key; that passphrase will be
|
||||
used to encrypt the private part of this file using 3DES. This file
|
||||
is not automatically accessed by
|
||||
.Nm
|
||||
but it is offered as the default file for the private key.
|
||||
.It Pa $HOME/.ssh/identity.pub
|
||||
Contains the public key for authentication. The contents of this file
|
||||
should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
on all machines
|
||||
where you wish to log in using RSA authentication. There is no
|
||||
need to keep the contents of this file secret.
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Pp
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
|
||||
removed and newer features re-added. Rapidly after the 1.2.12 release,
|
||||
newer versions bore successively more restrictive licenses. This version
|
||||
of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
has all components of a restrictive nature (i.e., patents, see
|
||||
.Xr ssl 8 )
|
||||
directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
supports one-time password authentication with
|
||||
.Xr skey 1 .
|
||||
.El
|
||||
.Pp
|
||||
The libraries described in
|
||||
.Xr ssl 8
|
||||
are required for proper operation.
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr sshd 8 ,
|
||||
.Xr ssl 8
|
556
crypto/openssh/ssh-keygen.c
Normal file
556
crypto/openssh/ssh-keygen.c
Normal file
@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Mon Mar 27 02:26:40 1995 ylo
|
||||
* Identity and host key generation and maintenance.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh-keygen.c,v 1.16 2000/02/04 14:34:09 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "fingerprint.h"
|
||||
|
||||
/* Generated private key. */
|
||||
RSA *private_key;
|
||||
|
||||
/* Generated public key. */
|
||||
RSA *public_key;
|
||||
|
||||
/* Number of bits in the RSA key. This value can be changed on the command line. */
|
||||
int bits = 1024;
|
||||
|
||||
/*
|
||||
* Flag indicating that we just want to change the passphrase. This can be
|
||||
* set on the command line.
|
||||
*/
|
||||
int change_passphrase = 0;
|
||||
|
||||
/*
|
||||
* Flag indicating that we just want to change the comment. This can be set
|
||||
* on the command line.
|
||||
*/
|
||||
int change_comment = 0;
|
||||
|
||||
int quiet = 0;
|
||||
|
||||
/* Flag indicating that we just want to see the key fingerprint */
|
||||
int print_fingerprint = 0;
|
||||
|
||||
/* The identity file name, given on the command line or entered by the user. */
|
||||
char identity_file[1024];
|
||||
int have_identity = 0;
|
||||
|
||||
/* This is set to the passphrase if given on the command line. */
|
||||
char *identity_passphrase = NULL;
|
||||
|
||||
/* This is set to the new passphrase if given on the command line. */
|
||||
char *identity_new_passphrase = NULL;
|
||||
|
||||
/* This is set to the new comment if given on the command line. */
|
||||
char *identity_comment = NULL;
|
||||
|
||||
/* argv0 */
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
ask_filename(struct passwd *pw, const char *prompt)
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(identity_file, sizeof(identity_file), "%s/%s",
|
||||
pw->pw_dir, SSH_CLIENT_IDENTITY);
|
||||
printf("%s (%s): ", prompt, identity_file);
|
||||
fflush(stdout);
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
||||
exit(1);
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
if (strcmp(buf, "") != 0)
|
||||
strlcpy(identity_file, buf, sizeof(identity_file));
|
||||
have_identity = 1;
|
||||
}
|
||||
|
||||
void
|
||||
do_fingerprint(struct passwd *pw)
|
||||
{
|
||||
FILE *f;
|
||||
BIGNUM *e, *n;
|
||||
RSA *public_key;
|
||||
char *comment = NULL, *cp, *ep, line[16*1024];
|
||||
int i, skip = 0, num = 1, invalid = 1;
|
||||
struct stat st;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public_key = RSA_new();
|
||||
if (load_public_key(identity_file, public_key, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
RSA_free(public_key);
|
||||
exit(0);
|
||||
}
|
||||
RSA_free(public_key);
|
||||
|
||||
f = fopen(identity_file, "r");
|
||||
if (f != NULL) {
|
||||
n = BN_new();
|
||||
e = BN_new();
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
i = strlen(line) - 1;
|
||||
if (line[i] != '\n') {
|
||||
error("line %d too long: %.40s...", num, line);
|
||||
skip = 1;
|
||||
continue;
|
||||
}
|
||||
num++;
|
||||
if (skip) {
|
||||
skip = 0;
|
||||
continue;
|
||||
}
|
||||
line[i] = '\0';
|
||||
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue ;
|
||||
i = strtol(cp, &ep, 10);
|
||||
if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
|
||||
int quoted = 0;
|
||||
comment = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
if (!*cp)
|
||||
continue;
|
||||
*cp++ = '\0';
|
||||
}
|
||||
ep = cp;
|
||||
if (auth_rsa_read_key(&cp, &i, e, n)) {
|
||||
invalid = 0;
|
||||
comment = *cp ? cp : comment;
|
||||
printf("%d %s %s\n", BN_num_bits(n),
|
||||
fingerprint(e, n),
|
||||
comment ? comment : "no comment");
|
||||
}
|
||||
}
|
||||
BN_free(e);
|
||||
BN_free(n);
|
||||
fclose(f);
|
||||
}
|
||||
if (invalid) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform changing a passphrase. The argument is the passwd structure
|
||||
* for the current user.
|
||||
*/
|
||||
void
|
||||
do_change_passphrase(struct passwd *pw)
|
||||
{
|
||||
char *comment;
|
||||
char *old_passphrase, *passphrase1, *passphrase2;
|
||||
struct stat st;
|
||||
RSA *private_key;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
/* Clear the public key since we are just about to load the whole file. */
|
||||
RSA_free(public_key);
|
||||
|
||||
/* Try to load the file with empty passphrase. */
|
||||
private_key = RSA_new();
|
||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
||||
if (identity_passphrase)
|
||||
old_passphrase = xstrdup(identity_passphrase);
|
||||
else
|
||||
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
||||
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
}
|
||||
printf("Key has comment '%s'\n", comment);
|
||||
|
||||
/* Ask the new passphrase (twice). */
|
||||
if (identity_new_passphrase) {
|
||||
passphrase1 = xstrdup(identity_new_passphrase);
|
||||
passphrase2 = NULL;
|
||||
} else {
|
||||
passphrase1 =
|
||||
read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
|
||||
passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
|
||||
|
||||
/* Verify that they are the same. */
|
||||
if (strcmp(passphrase1, passphrase2) != 0) {
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
memset(passphrase2, 0, strlen(passphrase2));
|
||||
xfree(passphrase1);
|
||||
xfree(passphrase2);
|
||||
printf("Pass phrases do not match. Try again.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the other copy. */
|
||||
memset(passphrase2, 0, strlen(passphrase2));
|
||||
xfree(passphrase2);
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase and the copy of the key in memory. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key); /* Destroys contents */
|
||||
xfree(comment);
|
||||
|
||||
printf("Your identification has been saved with the new passphrase.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the comment of a private key file.
|
||||
*/
|
||||
void
|
||||
do_change_comment(struct passwd *pw)
|
||||
{
|
||||
char new_comment[1024], *comment;
|
||||
RSA *private_key;
|
||||
char *passphrase;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char *tmpbuf;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* Try to load the public key from the file the verify that it is
|
||||
* readable and of the proper format.
|
||||
*/
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
private_key = RSA_new();
|
||||
|
||||
if (load_private_key(identity_file, "", private_key, &comment))
|
||||
passphrase = xstrdup("");
|
||||
else {
|
||||
if (identity_passphrase)
|
||||
passphrase = xstrdup(identity_passphrase);
|
||||
else if (identity_new_passphrase)
|
||||
passphrase = xstrdup(identity_new_passphrase);
|
||||
else
|
||||
passphrase = read_passphrase("Enter passphrase: ", 1);
|
||||
/* Try to load using the passphrase. */
|
||||
if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
printf("Key now has comment '%s'\n", comment);
|
||||
|
||||
if (identity_comment) {
|
||||
strlcpy(new_comment, identity_comment, sizeof(new_comment));
|
||||
} else {
|
||||
printf("Enter new comment: ");
|
||||
fflush(stdout);
|
||||
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
RSA_free(private_key);
|
||||
exit(1);
|
||||
}
|
||||
if (strchr(new_comment, '\n'))
|
||||
*strchr(new_comment, '\n') = 0;
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
|
||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||
f = fopen(identity_file, "w");
|
||||
if (!f) {
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, new_comment);
|
||||
free(tmpbuf);
|
||||
fclose(f);
|
||||
|
||||
xfree(comment);
|
||||
|
||||
printf("The comment in your key file has been changed.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
printf("ssh-keygen version %s\n", SSH_VERSION);
|
||||
printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main program for key management.
|
||||
*/
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
|
||||
struct passwd *pw;
|
||||
char *tmpbuf;
|
||||
int opt;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* we need this for the home * directory. */
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
printf("You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bits = atoi(optarg);
|
||||
if (bits < 512 || bits > 32768) {
|
||||
printf("Bits has bad value.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
print_fingerprint = 1;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
change_passphrase = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
change_comment = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
strlcpy(identity_file, optarg, sizeof(identity_file));
|
||||
have_identity = 1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
identity_passphrase = optarg;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
identity_new_passphrase = optarg;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
identity_comment = optarg;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (optind < ac) {
|
||||
printf("Too many arguments.\n");
|
||||
usage();
|
||||
}
|
||||
if (change_passphrase && change_comment) {
|
||||
printf("Can only have one of -p and -c.\n");
|
||||
usage();
|
||||
}
|
||||
if (print_fingerprint)
|
||||
do_fingerprint(pw);
|
||||
if (change_passphrase)
|
||||
do_change_passphrase(pw);
|
||||
if (change_comment)
|
||||
do_change_comment(pw);
|
||||
|
||||
arc4random_stir();
|
||||
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
|
||||
/* Generate the rsa key pair. */
|
||||
private_key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
rsa_generate_key(private_key, public_key, bits);
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which to save the key");
|
||||
|
||||
/* Create ~/.ssh directory if it doesn\'t already exist. */
|
||||
snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
|
||||
if (strstr(identity_file, dotsshdir) != NULL &&
|
||||
stat(dotsshdir, &st) < 0) {
|
||||
if (mkdir(dotsshdir, 0755) < 0)
|
||||
error("Could not create directory '%s'.", dotsshdir);
|
||||
else if (!quiet)
|
||||
printf("Created directory '%s'.\n", dotsshdir);
|
||||
}
|
||||
/* If the file already exists, ask the user to confirm. */
|
||||
if (stat(identity_file, &st) >= 0) {
|
||||
char yesno[3];
|
||||
printf("%s already exists.\n", identity_file);
|
||||
printf("Overwrite (y/n)? ");
|
||||
fflush(stdout);
|
||||
if (fgets(yesno, sizeof(yesno), stdin) == NULL)
|
||||
exit(1);
|
||||
if (yesno[0] != 'y' && yesno[0] != 'Y')
|
||||
exit(1);
|
||||
}
|
||||
/* Ask for a passphrase (twice). */
|
||||
if (identity_passphrase)
|
||||
passphrase1 = xstrdup(identity_passphrase);
|
||||
else if (identity_new_passphrase)
|
||||
passphrase1 = xstrdup(identity_new_passphrase);
|
||||
else {
|
||||
passphrase_again:
|
||||
passphrase1 =
|
||||
read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
|
||||
passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
|
||||
if (strcmp(passphrase1, passphrase2) != 0) {
|
||||
/* The passphrases do not match. Clear them and retry. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
memset(passphrase2, 0, strlen(passphrase2));
|
||||
xfree(passphrase1);
|
||||
xfree(passphrase2);
|
||||
printf("Passphrases do not match. Try again.\n");
|
||||
goto passphrase_again;
|
||||
}
|
||||
/* Clear the other copy of the passphrase. */
|
||||
memset(passphrase2, 0, strlen(passphrase2));
|
||||
xfree(passphrase2);
|
||||
}
|
||||
|
||||
if (identity_comment) {
|
||||
strlcpy(comment, identity_comment, sizeof(comment));
|
||||
} else {
|
||||
/* Create default commend field for the passphrase. */
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
perror("gethostname");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
|
||||
}
|
||||
|
||||
/* Save the key with the given passphrase and comment. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
exit(1);
|
||||
}
|
||||
/* Clear the passphrase. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
|
||||
/* Clear the private key and the random number generator. */
|
||||
RSA_free(private_key);
|
||||
arc4random_stir();
|
||||
|
||||
if (!quiet)
|
||||
printf("Your identification has been saved in %s.\n", identity_file);
|
||||
|
||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||
f = fopen(identity_file, "w");
|
||||
if (!f) {
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, comment);
|
||||
free(tmpbuf);
|
||||
fclose(f);
|
||||
|
||||
if (!quiet) {
|
||||
printf("Your public key has been saved in %s.\n", identity_file);
|
||||
printf("The key fingerprint is:\n");
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
}
|
||||
exit(0);
|
||||
}
|
21
crypto/openssh/ssh-keygen/Makefile
Normal file
21
crypto/openssh/ssh-keygen/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= ssh-keygen
|
||||
BINOWN= root
|
||||
|
||||
.if (${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "powerpc" || \
|
||||
${MACHINE_ARCH} == "hppa")
|
||||
BINMODE=0000
|
||||
.else
|
||||
BINMODE?=555
|
||||
.endif
|
||||
|
||||
BINDIR= /usr/bin
|
||||
MAN= ssh-keygen.1
|
||||
|
||||
SRCS= ssh-keygen.c log-client.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
LDADD+= -lcrypto -lutil -lz
|
||||
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
|
1001
crypto/openssh/ssh.1
Normal file
1001
crypto/openssh/ssh.1
Normal file
File diff suppressed because it is too large
Load Diff
803
crypto/openssh/ssh.c
Normal file
803
crypto/openssh/ssh.c
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sat Mar 18 16:36:11 1995 ylo
|
||||
* Ssh client program. This program can be used to log into a remote machine.
|
||||
* The software supports strong authentication, encryption, and forwarding
|
||||
* of X11, TCP/IP, and authentication connections.
|
||||
*
|
||||
* Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh.c,v 1.40 2000/02/20 20:05:19 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "authfd.h"
|
||||
#include "readconf.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
|
||||
Default value is AF_UNSPEC means both IPv4 and IPv6. */
|
||||
int IPv4or6 = AF_UNSPEC;
|
||||
|
||||
/* Flag indicating whether debug mode is on. This can be set on the command line. */
|
||||
int debug_flag = 0;
|
||||
|
||||
int tty_flag = 0;
|
||||
|
||||
/*
|
||||
* Flag indicating that nothing should be read from stdin. This can be set
|
||||
* on the command line.
|
||||
*/
|
||||
int stdin_null_flag = 0;
|
||||
|
||||
/*
|
||||
* Flag indicating that ssh should fork after authentication. This is useful
|
||||
* so that the pasphrase can be entered manually, and then ssh goes to the
|
||||
* background.
|
||||
*/
|
||||
int fork_after_authentication_flag = 0;
|
||||
|
||||
/*
|
||||
* General data structure for command line options and options configurable
|
||||
* in configuration files. See readconf.h.
|
||||
*/
|
||||
Options options;
|
||||
|
||||
/*
|
||||
* Name of the host we are connecting to. This is the name given on the
|
||||
* command line, or the HostName specified for the user-supplied name in a
|
||||
* configuration file.
|
||||
*/
|
||||
char *host;
|
||||
|
||||
/* socket address the host resolves to */
|
||||
struct sockaddr_storage hostaddr;
|
||||
|
||||
/*
|
||||
* Flag to indicate that we have received a window change signal which has
|
||||
* not yet been processed. This will cause a message indicating the new
|
||||
* window size to be sent to the server a little later. This is volatile
|
||||
* because this is updated in a signal handler.
|
||||
*/
|
||||
volatile int received_window_change_signal = 0;
|
||||
|
||||
/* Value of argv[0] (set in the main program). */
|
||||
char *av0;
|
||||
|
||||
/* Flag indicating whether we have a valid host private key loaded. */
|
||||
int host_private_key_loaded = 0;
|
||||
|
||||
/* Host private key. */
|
||||
RSA *host_private_key = NULL;
|
||||
|
||||
/* Original real UID. */
|
||||
uid_t original_real_uid;
|
||||
|
||||
/* Prints a help message to the user. This function never returns. */
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -l user Log in using this user name.\n");
|
||||
fprintf(stderr, " -n Redirect input from /dev/null.\n");
|
||||
fprintf(stderr, " -a Disable authentication agent forwarding.\n");
|
||||
#ifdef AFS
|
||||
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
|
||||
#endif /* AFS */
|
||||
fprintf(stderr, " -x Disable X11 connection forwarding.\n");
|
||||
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
|
||||
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
|
||||
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
|
||||
fprintf(stderr, " -V Display version number only.\n");
|
||||
fprintf(stderr, " -P Don't allocate a privileged port.\n");
|
||||
fprintf(stderr, " -q Quiet; don't display any warning messages.\n");
|
||||
fprintf(stderr, " -f Fork into background after authentication.\n");
|
||||
fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
|
||||
|
||||
fprintf(stderr, " -c cipher Select encryption algorithm: "
|
||||
"``3des'', "
|
||||
"``blowfish''\n");
|
||||
fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
|
||||
fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
|
||||
fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
|
||||
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
|
||||
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
|
||||
fprintf(stderr, " -C Enable compression.\n");
|
||||
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
|
||||
fprintf(stderr, " -4 Use IPv4 only.\n");
|
||||
fprintf(stderr, " -6 Use IPv6 only.\n");
|
||||
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Connects to the given host using rsh (or prints an error message and exits
|
||||
* if rsh is not available). This function never returns.
|
||||
*/
|
||||
void
|
||||
rsh_connect(char *host, char *user, Buffer * command)
|
||||
{
|
||||
char *args[10];
|
||||
int i;
|
||||
|
||||
log("Using rsh. WARNING: Connection will not be encrypted.");
|
||||
/* Build argument list for rsh. */
|
||||
i = 0;
|
||||
args[i++] = _PATH_RSH;
|
||||
/* host may have to come after user on some systems */
|
||||
args[i++] = host;
|
||||
if (user) {
|
||||
args[i++] = "-l";
|
||||
args[i++] = user;
|
||||
}
|
||||
if (buffer_len(command) > 0) {
|
||||
buffer_append(command, "\0", 1);
|
||||
args[i++] = buffer_ptr(command);
|
||||
}
|
||||
args[i++] = NULL;
|
||||
if (debug_flag) {
|
||||
for (i = 0; args[i]; i++) {
|
||||
if (i != 0)
|
||||
fprintf(stderr, " ");
|
||||
fprintf(stderr, "%s", args[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
execv(_PATH_RSH, args);
|
||||
perror(_PATH_RSH);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
*/
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
int i, opt, optind, type, exit_status, ok, authfd;
|
||||
u_short fwd_port, fwd_host_port;
|
||||
char *optarg, *cp, buf[256];
|
||||
Buffer command;
|
||||
struct winsize ws;
|
||||
struct stat st;
|
||||
struct passwd *pw, pwcopy;
|
||||
int interactive = 0, dummy;
|
||||
uid_t original_effective_uid;
|
||||
int plen;
|
||||
|
||||
/*
|
||||
* Save the original real uid. It will be needed later (uid-swapping
|
||||
* may clobber the real uid).
|
||||
*/
|
||||
original_real_uid = getuid();
|
||||
original_effective_uid = geteuid();
|
||||
|
||||
/* If we are installed setuid root be careful to not drop core. */
|
||||
if (original_real_uid != original_effective_uid) {
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = rlim.rlim_max = 0;
|
||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
fatal("setrlimit failed: %.100s", strerror(errno));
|
||||
}
|
||||
/*
|
||||
* Use uid-swapping to give up root privileges for the duration of
|
||||
* option processing. We will re-instantiate the rights when we are
|
||||
* ready to create the privileged port, and will permanently drop
|
||||
* them when the port has been created (actually, when the connection
|
||||
* has been made, as we may need to create the port several times).
|
||||
*/
|
||||
temporarily_use_uid(original_real_uid);
|
||||
|
||||
/*
|
||||
* Set our umask to something reasonable, as some files are created
|
||||
* with the default umask. This will make them world-readable but
|
||||
* writable only by the owner, which is ok for all files for which we
|
||||
* don't set the modes explicitly.
|
||||
*/
|
||||
umask(022);
|
||||
|
||||
/* Save our own name. */
|
||||
av0 = av[0];
|
||||
|
||||
/* Initialize option structure to indicate that no values have been set. */
|
||||
initialize_options(&options);
|
||||
|
||||
/* Parse command-line arguments. */
|
||||
host = NULL;
|
||||
|
||||
/* If program name is not one of the standard names, use it as host name. */
|
||||
if (strchr(av0, '/'))
|
||||
cp = strrchr(av0, '/') + 1;
|
||||
else
|
||||
cp = av0;
|
||||
if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
|
||||
strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
|
||||
host = cp;
|
||||
|
||||
for (optind = 1; optind < ac; optind++) {
|
||||
if (av[optind][0] != '-') {
|
||||
if (host)
|
||||
break;
|
||||
if ((cp = strchr(av[optind], '@'))) {
|
||||
if(cp == av[optind])
|
||||
usage();
|
||||
options.user = av[optind];
|
||||
*cp = '\0';
|
||||
host = ++cp;
|
||||
} else
|
||||
host = av[optind];
|
||||
continue;
|
||||
}
|
||||
opt = av[optind][1];
|
||||
if (!opt)
|
||||
usage();
|
||||
if (strchr("eilcpLRo", opt)) { /* options with arguments */
|
||||
optarg = av[optind] + 2;
|
||||
if (strcmp(optarg, "") == 0) {
|
||||
if (optind >= ac - 1)
|
||||
usage();
|
||||
optarg = av[++optind];
|
||||
}
|
||||
} else {
|
||||
if (av[optind][2])
|
||||
usage();
|
||||
optarg = NULL;
|
||||
}
|
||||
switch (opt) {
|
||||
case '4':
|
||||
IPv4or6 = AF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
IPv4or6 = AF_INET6;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
stdin_null_flag = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fork_after_authentication_flag = 1;
|
||||
stdin_null_flag = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
options.forward_x11 = 0;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
options.forward_x11 = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
options.gateway_ports = 1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
options.use_privileged_port = 0;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
options.forward_agent = 0;
|
||||
break;
|
||||
#ifdef AFS
|
||||
case 'k':
|
||||
options.kerberos_tgt_passing = 0;
|
||||
options.afs_token_passing = 0;
|
||||
break;
|
||||
#endif
|
||||
case 'i':
|
||||
if (stat(optarg, &st) < 0) {
|
||||
fprintf(stderr, "Warning: Identity file %s does not exist.\n",
|
||||
optarg);
|
||||
break;
|
||||
}
|
||||
if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("Too many identity files specified (max %d)",
|
||||
SSH_MAX_IDENTITY_FILES);
|
||||
options.identity_files[options.num_identity_files++] =
|
||||
xstrdup(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tty_flag = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
|
||||
SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
|
||||
fprintf(stderr, "Compiled with SSL.\n");
|
||||
if (opt == 'V')
|
||||
exit(0);
|
||||
debug_flag = 1;
|
||||
options.log_level = SYSLOG_LEVEL_DEBUG;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
options.log_level = SYSLOG_LEVEL_QUIET;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (optarg[0] == '^' && optarg[2] == 0 &&
|
||||
(unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
|
||||
options.escape_char = (unsigned char) optarg[1] & 31;
|
||||
else if (strlen(optarg) == 1)
|
||||
options.escape_char = (unsigned char) optarg[0];
|
||||
else if (strcmp(optarg, "none") == 0)
|
||||
options.escape_char = -2;
|
||||
else {
|
||||
fprintf(stderr, "Bad escape character '%s'.\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
options.port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
options.user = optarg;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3 &&
|
||||
sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3) {
|
||||
fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
add_remote_forward(&options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3 &&
|
||||
sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3) {
|
||||
fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
add_local_forward(&options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
options.compression = 1;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
dummy = 1;
|
||||
if (process_config_line(&options, host ? host : "", optarg,
|
||||
"command-line", 0, &dummy) != 0)
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we got a host name. */
|
||||
if (!host)
|
||||
usage();
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
extern char *__progname;
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* Initialize the command to execute on remote host. */
|
||||
buffer_init(&command);
|
||||
|
||||
/*
|
||||
* Save the command to execute on the remote host in a buffer. There
|
||||
* is no limit on the length of the command, except by the maximum
|
||||
* packet size. Also sets the tty flag if there is no command.
|
||||
*/
|
||||
if (optind == ac) {
|
||||
/* No command specified - execute shell on a tty. */
|
||||
tty_flag = 1;
|
||||
} else {
|
||||
/* A command has been specified. Store it into the
|
||||
buffer. */
|
||||
for (i = optind; i < ac; i++) {
|
||||
if (i > optind)
|
||||
buffer_append(&command, " ", 1);
|
||||
buffer_append(&command, av[i], strlen(av[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Cannot fork to background if no command. */
|
||||
if (fork_after_authentication_flag && buffer_len(&command) == 0)
|
||||
fatal("Cannot fork into background without a command to execute.");
|
||||
|
||||
/* Allocate a tty by default if no command specified. */
|
||||
if (buffer_len(&command) == 0)
|
||||
tty_flag = 1;
|
||||
|
||||
/* Do not allocate a tty if stdin is not a tty. */
|
||||
if (!isatty(fileno(stdin))) {
|
||||
if (tty_flag)
|
||||
fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
|
||||
tty_flag = 0;
|
||||
}
|
||||
/* Get user data. */
|
||||
pw = getpwuid(original_real_uid);
|
||||
if (!pw) {
|
||||
fprintf(stderr, "You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
/* 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_dir = xstrdup(pw->pw_dir);
|
||||
pwcopy.pw_shell = xstrdup(pw->pw_shell);
|
||||
pw = &pwcopy;
|
||||
|
||||
/* Initialize "log" output. Since we are the client all output
|
||||
actually goes to the terminal. */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
|
||||
/* Read per-user configuration file. */
|
||||
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
|
||||
read_config_file(buf, host, &options);
|
||||
|
||||
/* Read systemwide configuration file. */
|
||||
read_config_file(HOST_CONFIG_FILE, host, &options);
|
||||
|
||||
/* Fill configuration defaults. */
|
||||
fill_default_options(&options);
|
||||
|
||||
/* reinit */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
|
||||
if (options.user == NULL)
|
||||
options.user = xstrdup(pw->pw_name);
|
||||
|
||||
if (options.hostname != NULL)
|
||||
host = options.hostname;
|
||||
|
||||
/* Find canonic host name. */
|
||||
if (strchr(host, '.') == 0) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *ai = NULL;
|
||||
int errgai;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = IPv4or6;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
errgai = getaddrinfo(host, NULL, &hints, &ai);
|
||||
if (errgai == 0) {
|
||||
if (ai->ai_canonname != NULL)
|
||||
host = xstrdup(ai->ai_canonname);
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
/* Disable rhosts authentication if not running as root. */
|
||||
if (original_effective_uid != 0 || !options.use_privileged_port) {
|
||||
options.rhosts_authentication = 0;
|
||||
options.rhosts_rsa_authentication = 0;
|
||||
}
|
||||
/*
|
||||
* If using rsh has been selected, exec it now (without trying
|
||||
* anything else). Note that we must release privileges first.
|
||||
*/
|
||||
if (options.use_rsh) {
|
||||
/*
|
||||
* Restore our superuser privileges. This must be done
|
||||
* before permanently setting the uid.
|
||||
*/
|
||||
restore_uid();
|
||||
|
||||
/* Switch to the original uid permanently. */
|
||||
permanently_set_uid(original_real_uid);
|
||||
|
||||
/* Execute rsh. */
|
||||
rsh_connect(host, options.user, &command);
|
||||
fatal("rsh_connect returned");
|
||||
}
|
||||
/* Restore our superuser privileges. */
|
||||
restore_uid();
|
||||
|
||||
/*
|
||||
* Open a connection to the remote host. This needs root privileges
|
||||
* if rhosts_{rsa_}authentication is enabled.
|
||||
*/
|
||||
|
||||
ok = ssh_connect(host, &hostaddr, options.port,
|
||||
options.connection_attempts,
|
||||
!options.rhosts_authentication &&
|
||||
!options.rhosts_rsa_authentication,
|
||||
original_real_uid,
|
||||
options.proxy_command);
|
||||
|
||||
/*
|
||||
* If we successfully made the connection, load the host private key
|
||||
* in case we will need it later for combined rsa-rhosts
|
||||
* authentication. This must be done before releasing extra
|
||||
* privileges, because the file is only readable by root.
|
||||
*/
|
||||
if (ok) {
|
||||
host_private_key = RSA_new();
|
||||
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
||||
host_private_key_loaded = 1;
|
||||
}
|
||||
/*
|
||||
* Get rid of any extra privileges that we may have. We will no
|
||||
* longer need them. Also, extra privileges could make it very hard
|
||||
* to read identity files and other non-world-readable files from the
|
||||
* user's home directory if it happens to be on a NFS volume where
|
||||
* root is mapped to nobody.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that some legacy systems need to postpone the following call
|
||||
* to permanently_set_uid() until the private hostkey is destroyed
|
||||
* with RSA_free(). Otherwise the calling user could ptrace() the
|
||||
* process, read the private hostkey and impersonate the host.
|
||||
* OpenBSD does not allow ptracing of setuid processes.
|
||||
*/
|
||||
permanently_set_uid(original_real_uid);
|
||||
|
||||
/*
|
||||
* Now that we are back to our own permissions, create ~/.ssh
|
||||
* directory if it doesn\'t already exist.
|
||||
*/
|
||||
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
|
||||
if (stat(buf, &st) < 0)
|
||||
if (mkdir(buf, 0755) < 0)
|
||||
error("Could not create directory '%.200s'.", buf);
|
||||
|
||||
/* Check if the connection failed, and try "rsh" if appropriate. */
|
||||
if (!ok) {
|
||||
if (options.port != 0)
|
||||
log("Secure connection to %.100s on port %hu refused%.100s.",
|
||||
host, options.port,
|
||||
options.fallback_to_rsh ? "; reverting to insecure method" : "");
|
||||
else
|
||||
log("Secure connection to %.100s refused%.100s.", host,
|
||||
options.fallback_to_rsh ? "; reverting to insecure method" : "");
|
||||
|
||||
if (options.fallback_to_rsh) {
|
||||
rsh_connect(host, options.user, &command);
|
||||
fatal("rsh_connect returned");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
/* Expand ~ in options.identity_files. */
|
||||
for (i = 0; i < options.num_identity_files; i++)
|
||||
options.identity_files[i] =
|
||||
tilde_expand_filename(options.identity_files[i], original_real_uid);
|
||||
|
||||
/* Expand ~ in known host file names. */
|
||||
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
||||
original_real_uid);
|
||||
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
|
||||
original_real_uid);
|
||||
|
||||
/* Log into the remote system. This never returns if the login fails. */
|
||||
ssh_login(host_private_key_loaded, host_private_key,
|
||||
host, (struct sockaddr *)&hostaddr, original_real_uid);
|
||||
|
||||
/* We no longer need the host private key. Clear it now. */
|
||||
if (host_private_key_loaded)
|
||||
RSA_free(host_private_key); /* Destroys contents safely */
|
||||
|
||||
/* Close connection cleanly after attack. */
|
||||
cipher_attack_detected = packet_disconnect;
|
||||
|
||||
/* Enable compression if requested. */
|
||||
if (options.compression) {
|
||||
debug("Requesting compression at level %d.", options.compression_level);
|
||||
|
||||
if (options.compression_level < 1 || options.compression_level > 9)
|
||||
fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
|
||||
|
||||
/* Send the request. */
|
||||
packet_start(SSH_CMSG_REQUEST_COMPRESSION);
|
||||
packet_put_int(options.compression_level);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH_SMSG_SUCCESS)
|
||||
packet_start_compression(options.compression_level);
|
||||
else if (type == SSH_SMSG_FAILURE)
|
||||
log("Warning: Remote host refused compression.");
|
||||
else
|
||||
packet_disconnect("Protocol error waiting for compression response.");
|
||||
}
|
||||
/* Allocate a pseudo tty if appropriate. */
|
||||
if (tty_flag) {
|
||||
debug("Requesting pty.");
|
||||
|
||||
/* Start the packet. */
|
||||
packet_start(SSH_CMSG_REQUEST_PTY);
|
||||
|
||||
/* Store TERM in the packet. There is no limit on the
|
||||
length of the string. */
|
||||
cp = getenv("TERM");
|
||||
if (!cp)
|
||||
cp = "";
|
||||
packet_put_string(cp, strlen(cp));
|
||||
|
||||
/* Store window size in the packet. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
|
||||
/* Store tty modes in the packet. */
|
||||
tty_make_modes(fileno(stdin));
|
||||
|
||||
/* Send the packet, and wait for it to leave. */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH_SMSG_SUCCESS)
|
||||
interactive = 1;
|
||||
else if (type == SSH_SMSG_FAILURE)
|
||||
log("Warning: Remote host failed or refused to allocate a pseudo tty.");
|
||||
else
|
||||
packet_disconnect("Protocol error waiting for pty request response.");
|
||||
}
|
||||
/* Request X11 forwarding if enabled and DISPLAY is set. */
|
||||
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
|
||||
char line[512], proto[512], data[512];
|
||||
FILE *f;
|
||||
int forwarded = 0, got_data = 0, i;
|
||||
|
||||
#ifdef XAUTH_PATH
|
||||
/* Try to get Xauthority information for the display. */
|
||||
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
|
||||
XAUTH_PATH, getenv("DISPLAY"));
|
||||
f = popen(line, "r");
|
||||
if (f && fgets(line, sizeof(line), f) &&
|
||||
sscanf(line, "%*s %s %s", proto, data) == 2)
|
||||
got_data = 1;
|
||||
if (f)
|
||||
pclose(f);
|
||||
#endif /* XAUTH_PATH */
|
||||
/*
|
||||
* If we didn't get authentication data, just make up some
|
||||
* data. The forwarding code will check the validity of the
|
||||
* response anyway, and substitute this data. The X11
|
||||
* server, however, will ignore this fake data and use
|
||||
* whatever authentication mechanisms it was using otherwise
|
||||
* for the local connection.
|
||||
*/
|
||||
if (!got_data) {
|
||||
u_int32_t rand = 0;
|
||||
|
||||
strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
|
||||
rand >>= 8;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Got local authentication reasonable information. Request
|
||||
* forwarding with authentication spoofing.
|
||||
*/
|
||||
debug("Requesting X11 forwarding with authentication spoofing.");
|
||||
x11_request_forwarding_with_spoofing(proto, data);
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
forwarded = 1;
|
||||
interactive = 1;
|
||||
} else if (type == SSH_SMSG_FAILURE)
|
||||
log("Warning: Remote host denied X11 forwarding.");
|
||||
else
|
||||
packet_disconnect("Protocol error waiting for X11 forwarding");
|
||||
}
|
||||
/* Tell the packet module whether this is an interactive session. */
|
||||
packet_set_interactive(interactive, options.keepalives);
|
||||
|
||||
/* Clear agent forwarding if we don\'t have an agent. */
|
||||
authfd = ssh_get_authentication_socket();
|
||||
if (authfd < 0)
|
||||
options.forward_agent = 0;
|
||||
else
|
||||
ssh_close_authentication_socket(authfd);
|
||||
|
||||
/* Request authentication agent forwarding if appropriate. */
|
||||
if (options.forward_agent) {
|
||||
debug("Requesting authentication agent forwarding.");
|
||||
auth_request_forwarding();
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read(&plen);
|
||||
packet_integrity_check(plen, 0, type);
|
||||
if (type != SSH_SMSG_SUCCESS)
|
||||
log("Warning: Remote host denied authentication agent forwarding.");
|
||||
}
|
||||
/* Initiate local TCP/IP port forwardings. */
|
||||
for (i = 0; i < options.num_local_forwards; i++) {
|
||||
debug("Connections to local port %d forwarded to remote address %.200s:%d",
|
||||
options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port);
|
||||
channel_request_local_forwarding(options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port,
|
||||
options.gateway_ports);
|
||||
}
|
||||
|
||||
/* Initiate remote TCP/IP port forwardings. */
|
||||
for (i = 0; i < options.num_remote_forwards; i++) {
|
||||
debug("Connections to remote port %d forwarded to local address %.200s:%d",
|
||||
options.remote_forwards[i].port,
|
||||
options.remote_forwards[i].host,
|
||||
options.remote_forwards[i].host_port);
|
||||
channel_request_remote_forwarding(options.remote_forwards[i].port,
|
||||
options.remote_forwards[i].host,
|
||||
options.remote_forwards[i].host_port);
|
||||
}
|
||||
|
||||
/* If requested, let ssh continue in the background. */
|
||||
if (fork_after_authentication_flag)
|
||||
if (daemon(1, 1) < 0)
|
||||
fatal("daemon() failed: %.200s", strerror(errno));
|
||||
|
||||
/*
|
||||
* If a command was specified on the command line, execute the
|
||||
* command now. Otherwise request the server to start a shell.
|
||||
*/
|
||||
if (buffer_len(&command) > 0) {
|
||||
int len = buffer_len(&command);
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
debug("Sending command: %.*s", len, buffer_ptr(&command));
|
||||
packet_start(SSH_CMSG_EXEC_CMD);
|
||||
packet_put_string(buffer_ptr(&command), buffer_len(&command));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
} else {
|
||||
debug("Requesting shell.");
|
||||
packet_start(SSH_CMSG_EXEC_SHELL);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
/* Enter the interactive session. */
|
||||
exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
|
||||
|
||||
/* Close the connection to the remote host. */
|
||||
packet_close();
|
||||
|
||||
/* Exit with the status returned by the program on the remote side. */
|
||||
exit(exit_status);
|
||||
}
|
726
crypto/openssh/ssh.h
Normal file
726
crypto/openssh/ssh.h
Normal file
@ -0,0 +1,726 @@
|
||||
/*
|
||||
*
|
||||
* ssh.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 17:09:37 1995 ylo
|
||||
*
|
||||
* Generic header file for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ssh.h,v 1.33 2000/02/01 22:32:53 d Exp $"); */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
||||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/*
|
||||
* The default cipher used if IDEA is not supported by the remote host. It is
|
||||
* recommended that this be one of the mandatory ciphers (DES, 3DES), though
|
||||
* that is not required.
|
||||
*/
|
||||
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
/* Cipher used for encrypting authentication files. */
|
||||
#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
/* Default port number. */
|
||||
#define SSH_DEFAULT_PORT 22
|
||||
|
||||
/* Maximum number of TCP/IP ports forwarded per direction. */
|
||||
#define SSH_MAX_FORWARDS_PER_DIRECTION 100
|
||||
|
||||
/*
|
||||
* Maximum number of RSA authentication identity files that can be specified
|
||||
* in configuration files or on the command line.
|
||||
*/
|
||||
#define SSH_MAX_IDENTITY_FILES 100
|
||||
|
||||
/*
|
||||
* Major protocol version. Different version indicates major incompatiblity
|
||||
* that prevents communication.
|
||||
*/
|
||||
#define PROTOCOL_MAJOR 1
|
||||
|
||||
/*
|
||||
* Minor protocol version. Different version indicates minor incompatibility
|
||||
* that does not prevent interoperation.
|
||||
*/
|
||||
#define PROTOCOL_MINOR 5
|
||||
|
||||
/*
|
||||
* Name for the service. The port named by this service overrides the
|
||||
* default port if present.
|
||||
*/
|
||||
#define SSH_SERVICE_NAME "ssh"
|
||||
|
||||
#define ETCDIR "/etc"
|
||||
#define PIDDIR "/var/run"
|
||||
|
||||
/*
|
||||
* System-wide file containing host keys of known hosts. This file should be
|
||||
* world-readable.
|
||||
*/
|
||||
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
||||
|
||||
/*
|
||||
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||
* should be world-readable.
|
||||
*/
|
||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||
|
||||
#define 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 SSH_DAEMON_PID_FILE 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 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 SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
||||
|
||||
/*
|
||||
* Name of the default file containing client-side authentication key. This
|
||||
* file should only be readable by the user him/herself.
|
||||
*/
|
||||
#define SSH_CLIENT_IDENTITY ".ssh/identity"
|
||||
|
||||
/*
|
||||
* 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 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 SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
||||
|
||||
/*
|
||||
* 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 SSH_USER_RC ".ssh/rc"
|
||||
#define 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 SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
|
||||
|
||||
/*
|
||||
* Name of the environment variable containing the pathname of the
|
||||
* authentication socket.
|
||||
*/
|
||||
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
|
||||
|
||||
/*
|
||||
* Name of the environment variable containing the pathname of the
|
||||
* authentication socket.
|
||||
*/
|
||||
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
|
||||
|
||||
/*
|
||||
* Default path to ssh-askpass used by ssh-add,
|
||||
* environment variable for overwriting the default location
|
||||
*/
|
||||
#define SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
|
||||
#define SSH_ASKPASS_ENV "SSH_ASKPASS"
|
||||
|
||||
/*
|
||||
* Force host key length and server key length to differ by at least this
|
||||
* many bits. This is to make double encryption with rsaref work.
|
||||
*/
|
||||
#define SSH_KEY_BITS_RESERVED 128
|
||||
|
||||
/*
|
||||
* Length of the session key in bytes. (Specified as 256 bits in the
|
||||
* protocol.)
|
||||
*/
|
||||
#define SSH_SESSION_KEY_LENGTH 32
|
||||
|
||||
/* Name of Kerberos service for SSH to use. */
|
||||
#define KRB4_SERVICE_NAME "rcmd"
|
||||
|
||||
/*
|
||||
* Authentication methods. New types can be added, but old types should not
|
||||
* be removed for compatibility. The maximum allowed value is 31.
|
||||
*/
|
||||
#define SSH_AUTH_RHOSTS 1
|
||||
#define SSH_AUTH_RSA 2
|
||||
#define SSH_AUTH_PASSWORD 3
|
||||
#define SSH_AUTH_RHOSTS_RSA 4
|
||||
#define SSH_AUTH_TIS 5
|
||||
#define SSH_AUTH_KERBEROS 6
|
||||
#define SSH_PASS_KERBEROS_TGT 7
|
||||
/* 8 to 15 are reserved */
|
||||
#define SSH_PASS_AFS_TOKEN 21
|
||||
|
||||
/* Protocol flags. These are bit masks. */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
|
||||
|
||||
/*
|
||||
* Definition of message types. New values can be added, but old values
|
||||
* should not be removed or without careful consideration of the consequences
|
||||
* for compatibility. The maximum value is 254; value 255 is reserved for
|
||||
* future extension.
|
||||
*/
|
||||
/* Message name */ /* msg code */ /* arguments */
|
||||
#define SSH_MSG_NONE 0 /* no message */
|
||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
||||
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
|
||||
#define SSH_CMSG_USER 4 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
|
||||
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
|
||||
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
|
||||
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
|
||||
#define SSH_CMSG_EXEC_SHELL 12 /* */
|
||||
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
|
||||
#define SSH_SMSG_SUCCESS 14 /* */
|
||||
#define SSH_SMSG_FAILURE 15 /* */
|
||||
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
|
||||
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
|
||||
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
|
||||
#define SSH_CMSG_EOF 19 /* */
|
||||
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
|
||||
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
|
||||
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
|
||||
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
|
||||
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
|
||||
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
|
||||
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
|
||||
#define SSH_MSG_IGNORE 32 /* string */
|
||||
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
|
||||
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
|
||||
#define SSH_MSG_DEBUG 36 /* string */
|
||||
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
|
||||
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
|
||||
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
|
||||
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
|
||||
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
|
||||
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
|
||||
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
|
||||
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
|
||||
|
||||
/*------------ definitions for login.c -------------*/
|
||||
|
||||
/*
|
||||
* Returns the time when the user last logged in. Returns 0 if the
|
||||
* information is not available. This must be called before record_login.
|
||||
* The host from which the user logged in is stored in buf.
|
||||
*/
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize);
|
||||
|
||||
/*
|
||||
* Records that the user has logged in. This does many things normally done
|
||||
* by login(1).
|
||||
*/
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr *addr);
|
||||
|
||||
/*
|
||||
* Records that the user has logged out. This does many thigs normally done
|
||||
* by login(1) or init.
|
||||
*/
|
||||
void record_logout(int pid, const char *ttyname);
|
||||
|
||||
/*------------ definitions for sshconnect.c ----------*/
|
||||
|
||||
/*
|
||||
* Opens a TCP/IP connection to the remote server on the given host. If port
|
||||
* is 0, the default port will be used. If anonymous is zero, a privileged
|
||||
* port will be allocated to make the connection. This requires super-user
|
||||
* privileges if anonymous is false. Connection_attempts specifies the
|
||||
* maximum number of tries, one per second. This returns true on success,
|
||||
* and zero on failure. If the connection is successful, this calls
|
||||
* packet_set_connection for the connection.
|
||||
*/
|
||||
int
|
||||
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
u_short port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
const char *proxy_command);
|
||||
|
||||
/*
|
||||
* Starts a dialog with the server, and authenticates the current user on the
|
||||
* server. This does not need any extra privileges. The basic connection to
|
||||
* the server must already have been established before this is called. If
|
||||
* login fails, this function prints an error and never returns. This
|
||||
* initializes the random state, and leaves it initialized (it will also have
|
||||
* references from the packet module).
|
||||
*/
|
||||
|
||||
void
|
||||
ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
||||
struct sockaddr * hostaddr, uid_t original_real_uid);
|
||||
|
||||
/*------------ Definitions for various authentication methods. -------*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
|
||||
|
||||
/*
|
||||
* Tries to authenticate the user using password. Returns true if
|
||||
* authentication succeeds.
|
||||
*/
|
||||
int auth_password(struct passwd * pw, 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, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
|
||||
|
||||
/*
|
||||
* Returns the name of the machine at the other end of the socket. The
|
||||
* returned string should be freed by the caller.
|
||||
*/
|
||||
char *get_remote_hostname(int socket);
|
||||
|
||||
/*
|
||||
* 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(void);
|
||||
|
||||
/*
|
||||
* Returns the remote IP address as an ascii string. The value need not be
|
||||
* freed by the caller.
|
||||
*/
|
||||
const char *get_remote_ipaddr(void);
|
||||
|
||||
/* Returns the port number of the peer of the socket. */
|
||||
int get_peer_port(int sock);
|
||||
|
||||
/* Returns the port number of the remote/local host. */
|
||||
int get_remote_port(void);
|
||||
int get_local_port(void);
|
||||
|
||||
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns true if there is a positive match; zero
|
||||
* otherwise.
|
||||
*/
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/*
|
||||
* Checks whether the given host is already in the list of our known hosts.
|
||||
* Returns HOST_OK if the host is known and has the specified key, HOST_NEW
|
||||
* if the host is not known, and HOST_CHANGED if the host is known but used
|
||||
* to have a different host key. The host must be in all lowercase.
|
||||
*/
|
||||
typedef enum {
|
||||
HOST_OK, HOST_NEW, HOST_CHANGED
|
||||
} HostStatus;
|
||||
HostStatus
|
||||
check_host_in_hostfile(const char *filename, const char *host,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
|
||||
|
||||
/*
|
||||
* Appends an entry to the host file. Returns false if the entry could not
|
||||
* be appended.
|
||||
*/
|
||||
int
|
||||
add_host_to_hostfile(const char *filename, const char *host,
|
||||
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(BIGNUM * e, BIGNUM * n);
|
||||
|
||||
/*
|
||||
* 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(const char *prompt, int from_stdin);
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. 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,
|
||||
RSA * private_key, 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, RSA * pub,
|
||||
char **comment_return);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
RSA * private_key, char **comment_return);
|
||||
|
||||
/*------------ Definitions for logging. -----------------------*/
|
||||
|
||||
/* 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_DEBUG
|
||||
} 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)));
|
||||
|
||||
/* 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);
|
||||
|
||||
/*---------------- definitions for channels ------------------*/
|
||||
|
||||
/* Sets specific protocol options. */
|
||||
void channel_set_options(int hostname_in_open);
|
||||
|
||||
/*
|
||||
* Allocate a new channel object and set its type and socket. Remote_name
|
||||
* must have been allocated with xmalloc; this will free it when the channel
|
||||
* is freed.
|
||||
*/
|
||||
int channel_allocate(int type, int sock, char *remote_name);
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* After select, perform any appropriate operations for channels which have
|
||||
* events pending.
|
||||
*/
|
||||
void channel_after_select(fd_set * readset, fd_set * writeset);
|
||||
|
||||
/* If there is data to send to the connection, send some of it now. */
|
||||
void channel_output_poll(void);
|
||||
|
||||
/*
|
||||
* This is called when a packet of type CHANNEL_DATA has just been received.
|
||||
* The message type has already been consumed, but channel number and data is
|
||||
* still there.
|
||||
*/
|
||||
void channel_input_data(int payload_len);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE. */
|
||||
void channel_input_close(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
|
||||
void channel_input_close_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
|
||||
void channel_input_open_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
|
||||
void channel_input_open_failure(void);
|
||||
|
||||
/* This closes any sockets that are listening for connections; this removes
|
||||
any unix domain sockets. */
|
||||
void channel_stop_listening(void);
|
||||
|
||||
/*
|
||||
* Closes the sockets of all channels. This is used to close extra file
|
||||
* descriptors after a fork.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Returns a string containing a list of all open channels. The list is
|
||||
* suitable for displaying to the user. It uses crlf instead of newlines.
|
||||
* The caller should free the string with xfree.
|
||||
*/
|
||||
char *channel_open_message(void);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
channel_request_local_forwarding(u_short port, const char *host,
|
||||
u_short remote_port, int gateway_ports);
|
||||
|
||||
/*
|
||||
* Initiate forwarding of connections to port "port" on remote host through
|
||||
* the secure channel to host:port from local side. This never returns if
|
||||
* there was an error. This registers that open requests for that port are
|
||||
* permitted.
|
||||
*/
|
||||
void
|
||||
channel_request_remote_forwarding(u_short port, const char *host,
|
||||
u_short remote_port);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void channel_permit_all_opens(void);
|
||||
|
||||
/*
|
||||
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||
* listening for the port, and sends back a success reply (or disconnect
|
||||
* message if there was an error). This never returns if there was an error.
|
||||
*/
|
||||
void channel_input_port_forward_request(int is_root);
|
||||
|
||||
/*
|
||||
* This is called after receiving PORT_OPEN message. This attempts to
|
||||
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||
* or CHANNEL_OPEN_FAILURE.
|
||||
*/
|
||||
void channel_input_port_open(int payload_len);
|
||||
|
||||
/*
|
||||
* Creates a port for X11 connections, and starts listening for it. Returns
|
||||
* the display name, or NULL if an error was encountered.
|
||||
*/
|
||||
char *x11_create_display(int screen);
|
||||
|
||||
/*
|
||||
* Creates an internet domain socket for listening for X11 connections.
|
||||
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||
* occurs.
|
||||
*/
|
||||
char *x11_create_display_inet(int screen, int x11_display_offset);
|
||||
|
||||
/*
|
||||
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
||||
* the remote channel number. We should do whatever we want, and respond
|
||||
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||
*/
|
||||
void x11_input_open(int payload_len);
|
||||
|
||||
/*
|
||||
* Requests forwarding of X11 connections. This should be called on the
|
||||
* client only.
|
||||
*/
|
||||
void x11_request_forwarding(void);
|
||||
|
||||
/*
|
||||
* Requests forwarding for X11 connections, with authentication spoofing.
|
||||
* This should be called in the client only.
|
||||
*/
|
||||
void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
|
||||
|
||||
/* Sends a message to the server to request authentication fd forwarding. */
|
||||
void auth_request_forwarding(void);
|
||||
|
||||
/*
|
||||
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||
* there is no forwarded authentication socket. The returned value points to
|
||||
* a static buffer.
|
||||
*/
|
||||
char *auth_get_socket_name(void);
|
||||
|
||||
/*
|
||||
* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
||||
* This starts forwarding authentication requests.
|
||||
*/
|
||||
void auth_input_request_forwarding(struct passwd * pw);
|
||||
|
||||
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
||||
void auth_input_open_request(void);
|
||||
|
||||
/*
|
||||
* Returns true if the given string matches the pattern (which may contain ?
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
int match_pattern(const char *s, const char *pattern);
|
||||
|
||||
/*
|
||||
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
* Warning: this calls getpw*.
|
||||
*/
|
||||
char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
||||
|
||||
/*
|
||||
* 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(int pid, int fdin, int fdout, int fderr);
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int have_pty, int escape_char);
|
||||
|
||||
/* Linked list of custom environment strings (see auth-rsa.c). */
|
||||
struct envstring {
|
||||
struct envstring *next;
|
||||
char *s;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#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);
|
||||
|
||||
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf);
|
||||
int radix_to_creds(const char *buf, CREDENTIALS * creds);
|
||||
#endif /* AFS */
|
||||
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef SKEY
|
||||
#include <skey.h>
|
||||
char *skey_fake_keyinfo(char *username);
|
||||
int auth_skey_password(struct passwd * pw, const char *password);
|
||||
#endif /* SKEY */
|
||||
|
||||
/* AF_UNSPEC or AF_INET or AF_INET6 */
|
||||
extern int IPv4or6;
|
||||
|
||||
#endif /* SSH_H */
|
36
crypto/openssh/ssh/Makefile
Normal file
36
crypto/openssh/ssh/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= ssh
|
||||
BINOWN= root
|
||||
|
||||
.if (${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "powerpc" || \
|
||||
${MACHINE_ARCH} == "hppa")
|
||||
BINMODE=0000
|
||||
.else
|
||||
BINMODE?=4555
|
||||
.endif
|
||||
|
||||
BINDIR= /usr/bin
|
||||
MAN= ssh.1
|
||||
LINKS= ${BINDIR}/ssh ${BINDIR}/slogin
|
||||
MLINKS= ssh.1 slogin.1
|
||||
|
||||
SRCS= ssh.c sshconnect.c log-client.c readconf.c clientloop.c
|
||||
|
||||
.include <bsd.own.mk> # for AFS
|
||||
|
||||
.if (${KERBEROS} == "yes")
|
||||
CFLAGS+= -DKRB4 -I/usr/include/kerberosIV
|
||||
LDADD+= -lkrb
|
||||
DPADD+= ${LIBKRB}
|
||||
.if (${AFS} == "yes")
|
||||
CFLAGS+= -DAFS
|
||||
LDADD+= -lkafs
|
||||
DPADD+= ${LIBKRBAFS}
|
||||
.endif # AFS
|
||||
.endif # KERBEROS
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
LDADD+= -lutil -lz -lcrypto
|
||||
DPADD+= ${LIBCRYPTO} ${LIBUTIL} ${LIBZ}
|
30
crypto/openssh/ssh_config
Normal file
30
crypto/openssh/ssh_config
Normal file
@ -0,0 +1,30 @@
|
||||
# This is ssh client systemwide configuration file. This file provides
|
||||
# defaults for users, and the values can be changed in per-user configuration
|
||||
# files or on the command line.
|
||||
|
||||
# Configuration data is parsed as follows:
|
||||
# 1. command line options
|
||||
# 2. user-specific file
|
||||
# 3. system-wide file
|
||||
# Any configuration value is only changed the first time it is set.
|
||||
# Thus, host-specific definitions should be at the beginning of the
|
||||
# configuration file, and defaults at the end.
|
||||
|
||||
# Site-wide defaults for various options
|
||||
|
||||
# Host *
|
||||
# ForwardAgent yes
|
||||
# ForwardX11 yes
|
||||
# RhostsAuthentication yes
|
||||
# RhostsRSAAuthentication yes
|
||||
# RSAAuthentication yes
|
||||
# PasswordAuthentication yes
|
||||
# FallBackToRsh yes
|
||||
# UseRsh no
|
||||
# BatchMode no
|
||||
# CheckHostIP yes
|
||||
# StrictHostKeyChecking no
|
||||
# IdentityFile ~/.ssh/identity
|
||||
# Port 22
|
||||
# Cipher blowfish
|
||||
# EscapeChar ~
|
1639
crypto/openssh/sshconnect.c
Normal file
1639
crypto/openssh/sshconnect.c
Normal file
File diff suppressed because it is too large
Load Diff
801
crypto/openssh/sshd.8
Normal file
801
crypto/openssh/sshd.8
Normal file
@ -0,0 +1,801 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" sshd.8.in
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\"
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: sshd.8,v 1.33 2000/02/21 14:19:09 deraadt Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSHD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sshd
|
||||
.Nd secure shell daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm sshd
|
||||
.Op Fl diqQ46
|
||||
.Op Fl b Ar bits
|
||||
.Op Fl f Ar config_file
|
||||
.Op Fl g Ar login_grace_time
|
||||
.Op Fl h Ar host_key_file
|
||||
.Op Fl k Ar key_gen_time
|
||||
.Op Fl p Ar port
|
||||
.Op Fl V Ar client_protocol_id
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(Secure Shell Daemon) is the daemon program for
|
||||
.Xr ssh 1 .
|
||||
Together these programs replace rlogin and rsh programs, and
|
||||
provide secure encrypted communications between two untrusted hosts
|
||||
over an insecure network. The programs are intended to be as easy to
|
||||
install and use as possible.
|
||||
.Pp
|
||||
.Nm
|
||||
is the daemon that listens for connections from clients. It is
|
||||
normally started at boot from
|
||||
.Pa /etc/rc .
|
||||
It forks a new
|
||||
daemon for each incoming connection. The forked daemons handle
|
||||
key exchange, encryption, authentication, command execution,
|
||||
and data exchange.
|
||||
.Pp
|
||||
.Nm
|
||||
works as follows. Each host has a host-specific RSA key
|
||||
(normally 1024 bits) used to identify the host. Additionally, when
|
||||
the daemon starts, it generates a server RSA key (normally 768 bits).
|
||||
This key is normally regenerated every hour if it has been used, and
|
||||
is never stored on disk.
|
||||
.Pp
|
||||
Whenever a client connects the daemon, the daemon sends its host
|
||||
and server public keys to the client. The client compares the
|
||||
host key against its own database to verify that it has not changed.
|
||||
The client then generates a 256 bit random number. It encrypts this
|
||||
random number using both the host key and the server key, and sends
|
||||
the encrypted number to the server. Both sides then start to use this
|
||||
random number as a session key which is used to encrypt all further
|
||||
communications in the session. The rest of the session is encrypted
|
||||
using a conventional cipher, currently Blowfish and 3DES, with 3DES
|
||||
being is used by default. The client selects the encryption algorithm
|
||||
to use from those offered by the server.
|
||||
.Pp
|
||||
Next, the server and the client enter an authentication dialog. The
|
||||
client tries to authenticate itself using
|
||||
.Pa .rhosts
|
||||
authentication,
|
||||
.Pa .rhosts
|
||||
authentication combined with RSA host
|
||||
authentication, RSA challenge-response authentication, or password
|
||||
based authentication.
|
||||
.Pp
|
||||
Rhosts authentication is normally disabled
|
||||
because it is fundamentally insecure, but can be enabled in the server
|
||||
configuration file if desired. System security is not improved unless
|
||||
.Xr rshd 8 ,
|
||||
.Xr rlogind 8 ,
|
||||
.Xr rexecd 8 ,
|
||||
and
|
||||
.Xr rexd 8
|
||||
are disabled (thus completely disabling
|
||||
.Xr rlogin 1
|
||||
and
|
||||
.Xr rsh 1
|
||||
into that machine).
|
||||
.Pp
|
||||
If the client successfully authenticates itself, a dialog for
|
||||
preparing the session is entered. At this time the client may request
|
||||
things like allocating a pseudo-tty, forwarding X11 connections,
|
||||
forwarding TCP/IP connections, or forwarding the authentication agent
|
||||
connection over the secure channel.
|
||||
.Pp
|
||||
Finally, the client either requests a shell or execution of a command.
|
||||
The sides then enter session mode. In this mode, either side may send
|
||||
data at any time, and such data is forwarded to/from the shell or
|
||||
command on the server side, and the user terminal in the client side.
|
||||
.Pp
|
||||
When the user program terminates and all forwarded X11 and other
|
||||
connections have been closed, the server sends command exit status to
|
||||
the client, and both sides exit.
|
||||
.Pp
|
||||
.Nm
|
||||
can be configured using command-line options or a configuration
|
||||
file. Command-line options override values specified in the
|
||||
configuration file.
|
||||
.Pp
|
||||
.Nm
|
||||
rereads its configuration file when it receives a hangup signal,
|
||||
.Dv SIGHUP .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b Ar bits
|
||||
Specifies the number of bits in the server key (default 768).
|
||||
.Pp
|
||||
.It Fl d
|
||||
Debug mode. The server sends verbose debug output to the system
|
||||
log, and does not put itself in the background. The server also will
|
||||
not fork and will only process one connection. This option is only
|
||||
intended for debugging for the server.
|
||||
.It Fl f Ar configuration_file
|
||||
Specifies the name of the configuration file. The default is
|
||||
.Pa /etc/sshd_config .
|
||||
.Nm
|
||||
refuses to start if there is no configuration file.
|
||||
.It Fl g Ar login_grace_time
|
||||
Gives the grace time for clients to authenticate themselves (default
|
||||
300 seconds). If the client fails to authenticate the user within
|
||||
this many seconds, the server disconnects and exits. A value of zero
|
||||
indicates no limit.
|
||||
.It Fl h Ar host_key_file
|
||||
Specifies the file from which the host key is read (default
|
||||
.Pa /etc/ssh_host_key ) .
|
||||
This option must be given if
|
||||
.Nm
|
||||
is not run as root (as the normal
|
||||
host file is normally not readable by anyone but root).
|
||||
.It Fl i
|
||||
Specifies that
|
||||
.Nm
|
||||
is being run from inetd.
|
||||
.Nm
|
||||
is normally not run
|
||||
from inetd because it needs to generate the server key before it can
|
||||
respond to the client, and this may take tens of seconds. Clients
|
||||
would have to wait too long if the key was regenerated every time.
|
||||
However, with small key sizes (e.g. 512) using
|
||||
.Nm
|
||||
from inetd may
|
||||
be feasible.
|
||||
.It Fl k Ar key_gen_time
|
||||
Specifies how often the server key is regenerated (default 3600
|
||||
seconds, or one hour). The motivation for regenerating the key fairly
|
||||
often is that the key is not stored anywhere, and after about an hour,
|
||||
it becomes impossible to recover the key for decrypting intercepted
|
||||
communications even if the machine is cracked into or physically
|
||||
seized. A value of zero indicates that the key will never be regenerated.
|
||||
.It Fl p Ar port
|
||||
Specifies the port on which the server listens for connections
|
||||
(default 22).
|
||||
.It Fl q
|
||||
Quiet mode. Nothing is sent to the system log. Normally the beginning,
|
||||
authentication, and termination of each connection is logged.
|
||||
.It Fl Q
|
||||
Do not print an error message if RSA support is missing.
|
||||
.It Fl V Ar client_protocol_id
|
||||
SSH2 compatibility mode.
|
||||
When this options is specified
|
||||
.Nm
|
||||
assumes the client has sent the given version string
|
||||
and skips the
|
||||
Protocol Version Identification Exchange.
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv6 addresses only.
|
||||
.El
|
||||
.Sh CONFIGURATION FILE
|
||||
.Nm
|
||||
reads configuration data from
|
||||
.Pa /etc/sshd_config
|
||||
(or the file specified with
|
||||
.Fl f
|
||||
on the command line). The file
|
||||
contains keyword-value pairs, one per line. Lines starting with
|
||||
.Ql #
|
||||
and empty lines are interpreted as comments.
|
||||
.Pp
|
||||
The following keywords are possible.
|
||||
.Bl -tag -width Ds
|
||||
.It Cm AFSTokenPassing
|
||||
Specifies whether an AFS token may be forwarded to the server. Default is
|
||||
.Dq yes .
|
||||
.It Cm AllowGroups
|
||||
This keyword can be followed by a number of group names, separated
|
||||
by spaces. If specified, login is allowed only for users whose primary
|
||||
group matches one of the patterns.
|
||||
.Ql \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns. Only group names are valid, a numerical group
|
||||
id isn't recognized. By default login is allowed regardless of
|
||||
the primary group.
|
||||
.Pp
|
||||
.It Cm AllowUsers
|
||||
This keyword can be followed by a number of user names, separated
|
||||
by spaces. If specified, login is allowed only for users names that
|
||||
match one of the patterns.
|
||||
.Ql \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns. Only user names are valid, a numerical user
|
||||
id isn't recognized. By default login is allowed regardless of
|
||||
the user name.
|
||||
.Pp
|
||||
.It Cm CheckMail
|
||||
Specifies whether
|
||||
.Nm
|
||||
should check for new mail for interactive logins.
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm DenyGroups
|
||||
This keyword can be followed by a number of group names, separated
|
||||
by spaces. Users whose primary group matches one of the patterns
|
||||
aren't allowed to log in.
|
||||
.Ql \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns. Only group names are valid, a numerical group
|
||||
id isn't recognized. By default login is allowed regardless of
|
||||
the primary group.
|
||||
.Pp
|
||||
.It Cm DenyUsers
|
||||
This keyword can be followed by a number of user names, separated
|
||||
by spaces. Login is disallowed for user names that match
|
||||
one of the patterns.
|
||||
.Ql \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns. Only user names are valid, a numerical user
|
||||
id isn't recognized. By default login is allowed regardless of
|
||||
the user name.
|
||||
.It Cm HostKey
|
||||
Specifies the file containing the private host key (default
|
||||
.Pa /etc/ssh_host_key ) .
|
||||
Note that
|
||||
.Nm
|
||||
does not start if this file is group/world-accessible.
|
||||
.It Cm IgnoreRhosts
|
||||
Specifies that rhosts and shosts files will not be used in
|
||||
authentication.
|
||||
.Pa /etc/hosts.equiv
|
||||
and
|
||||
.Pa /etc/shosts.equiv
|
||||
are still used. The default is
|
||||
.Dq no .
|
||||
.It Cm IgnoreUserKnownHosts
|
||||
Specifies whether
|
||||
.Nm
|
||||
should ignore the user's
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
during
|
||||
.Cm RhostsRSAAuthentication .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm KeepAlive
|
||||
Specifies whether the system should send keepalive messages to the
|
||||
other side. If they are sent, death of the connection or crash of one
|
||||
of the machines will be properly noticed. However, this means that
|
||||
connections will die if the route is down temporarily, and some people
|
||||
find it annoying. On the other hand, if keepalives are not send,
|
||||
sessions may hang indefinitely on the server, leaving
|
||||
.Dq ghost
|
||||
users and consuming server resources.
|
||||
.Pp
|
||||
The default is
|
||||
.Dq yes
|
||||
(to send keepalives), and the server will notice
|
||||
if the network goes down or the client host reboots. This avoids
|
||||
infinitely hanging sessions.
|
||||
.Pp
|
||||
To disable keepalives, the value should be set to
|
||||
.Dq no
|
||||
in both the server and the client configuration files.
|
||||
.It Cm KerberosAuthentication
|
||||
Specifies whether Kerberos authentication is allowed. This can
|
||||
be in the form of a Kerberos ticket, or if
|
||||
.Cm PasswordAuthentication
|
||||
is yes, the password provided by the user will be validated through
|
||||
the Kerberos KDC. Default is
|
||||
.Dq yes .
|
||||
.It Cm KerberosOrLocalPasswd
|
||||
If set then if password authentication through Kerberos fails then
|
||||
the password will be validated via any additional local mechanism
|
||||
such as
|
||||
.Pa /etc/passwd
|
||||
or SecurID. Default is
|
||||
.Dq yes .
|
||||
.It Cm KerberosTgtPassing
|
||||
Specifies whether a Kerberos TGT may be forwarded to the server.
|
||||
Default is
|
||||
.Dq no ,
|
||||
as this only works when the Kerberos KDC is actually an AFS kaserver.
|
||||
.It Cm KerberosTicketCleanup
|
||||
Specifies whether to automatically destroy the user's ticket cache
|
||||
file on logout. Default is
|
||||
.Dq yes .
|
||||
.It Cm KeyRegenerationInterval
|
||||
The server key is automatically regenerated after this many seconds
|
||||
(if it has been used). The purpose of regeneration is to prevent
|
||||
decrypting captured sessions by later breaking into the machine and
|
||||
stealing the keys. The key is never stored anywhere. If the value is
|
||||
0, the key is never regenerated. The default is 3600
|
||||
(seconds).
|
||||
.It Cm ListenAddress
|
||||
Specifies what local address
|
||||
.Nm
|
||||
should listen on.
|
||||
The default is to listen to all local addresses.
|
||||
Multiple options of this type are permitted.
|
||||
Additionally, the
|
||||
.Cm Ports
|
||||
options must precede this option.
|
||||
.It Cm LoginGraceTime
|
||||
The server disconnects after this time if the user has not
|
||||
successfully logged in. If the value is 0, there is no time limit.
|
||||
The default is 600 (seconds).
|
||||
.It Cm LogLevel
|
||||
Gives the verbosity level that is used when logging messages from
|
||||
.Nm sshd .
|
||||
The possible values are:
|
||||
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
|
||||
The default is INFO.
|
||||
Logging with level DEBUG violates the privacy of users
|
||||
and is not recommended.
|
||||
.It Cm PasswordAuthentication
|
||||
Specifies whether password authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
.It Cm PermitEmptyPasswords
|
||||
When password authentication is allowed, it specifies whether the
|
||||
server allows login to accounts with empty password strings. The default
|
||||
is
|
||||
.Dq yes .
|
||||
.It Cm PermitRootLogin
|
||||
Specifies whether the root can log in using
|
||||
.Xr ssh 1 .
|
||||
The argument must be
|
||||
.Dq yes ,
|
||||
.Dq without-password
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq yes .
|
||||
If this options is set to
|
||||
.Dq without-password
|
||||
only password authentication is disabled for root.
|
||||
.Pp
|
||||
Root login with RSA authentication when the
|
||||
.Ar command
|
||||
option has been
|
||||
specified will be allowed regardless of the value of this setting
|
||||
(which may be useful for taking remote backups even if root login is
|
||||
normally not allowed).
|
||||
.It Cm Port
|
||||
Specifies the port number that
|
||||
.Nm
|
||||
listens on. The default is 22.
|
||||
Multiple options of this type are permitted.
|
||||
.It Cm PrintMotd
|
||||
Specifies whether
|
||||
.Nm
|
||||
should print
|
||||
.Pa /etc/motd
|
||||
when a user logs in interactively. (On some systems it is also
|
||||
printed by the shell,
|
||||
.Pa /etc/profile ,
|
||||
or equivalent.) The default is
|
||||
.Dq yes .
|
||||
.It Cm RandomSeed
|
||||
Obsolete. Random number generation uses other techniques.
|
||||
.It Cm RhostsAuthentication
|
||||
Specifies whether authentication using rhosts or /etc/hosts.equiv
|
||||
files is sufficient. Normally, this method should not be permitted
|
||||
because it is insecure.
|
||||
.Cm RhostsRSAAuthentication
|
||||
should be used
|
||||
instead, because it performs RSA-based host authentication in addition
|
||||
to normal rhosts or /etc/hosts.equiv authentication.
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm RhostsRSAAuthentication
|
||||
Specifies whether rhosts or /etc/hosts.equiv authentication together
|
||||
with successful RSA host authentication is allowed. The default is
|
||||
.Dq yes .
|
||||
.It Cm RSAAuthentication
|
||||
Specifies whether pure RSA authentication is allowed. The default is
|
||||
.Dq yes .
|
||||
.It Cm ServerKeyBits
|
||||
Defines the number of bits in the server key. The minimum value is
|
||||
512, and the default is 768.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether
|
||||
.Xr skey 1
|
||||
authentication is allowed. The default is
|
||||
.Dq yes .
|
||||
Note that s/key authentication is enabled only if
|
||||
.Cm PasswordAuthentication
|
||||
is allowed, too.
|
||||
.It Cm StrictModes
|
||||
Specifies whether
|
||||
.Nm
|
||||
should check file modes and ownership of the
|
||||
user's files and home directory before accepting login. This
|
||||
is normally desirable because novices sometimes accidentally leave their
|
||||
directory or files world-writable. The default is
|
||||
.Dq yes .
|
||||
.It Cm SyslogFacility
|
||||
Gives the facility code that is used when logging messages from
|
||||
.Nm sshd .
|
||||
The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
|
||||
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is AUTH.
|
||||
.It Cm UseLogin
|
||||
Specifies whether
|
||||
.Xr login 1
|
||||
is used. The default is
|
||||
.Dq no .
|
||||
.It Cm X11DisplayOffset
|
||||
Specifies the first display number available for
|
||||
.Nm sshd Ns 's
|
||||
X11 forwarding. This prevents
|
||||
.Nm
|
||||
from interfering with real X11 servers.
|
||||
.It Cm X11Forwarding
|
||||
Specifies whether X11 forwarding is permitted. The default is
|
||||
.Dq yes .
|
||||
Note that disabling X11 forwarding does not improve security in any
|
||||
way, as users can always install their own forwarders.
|
||||
.El
|
||||
.Sh LOGIN PROCESS
|
||||
When a user successfully logs in,
|
||||
.Nm
|
||||
does the following:
|
||||
.Bl -enum -offset indent
|
||||
.It
|
||||
If the login is on a tty, and no command has been specified,
|
||||
prints last login time and
|
||||
.Pa /etc/motd
|
||||
(unless prevented in the configuration file or by
|
||||
.Pa $HOME/.hushlogin ;
|
||||
see the
|
||||
.Sx FILES
|
||||
section).
|
||||
.It
|
||||
If the login is on a tty, records login time.
|
||||
.It
|
||||
Checks
|
||||
.Pa /etc/nologin ;
|
||||
if it exists, prints contents and quits
|
||||
(unless root).
|
||||
.It
|
||||
Changes to run with normal user privileges.
|
||||
.It
|
||||
Sets up basic environment.
|
||||
.It
|
||||
Reads
|
||||
.Pa $HOME/.ssh/environment
|
||||
if it exists.
|
||||
.It
|
||||
Changes to user's home directory.
|
||||
.It
|
||||
If
|
||||
.Pa $HOME/.ssh/rc
|
||||
exists, runs it; else if
|
||||
.Pa /etc/sshrc
|
||||
exists, runs
|
||||
it; otherwise runs xauth. The
|
||||
.Dq rc
|
||||
files are given the X11
|
||||
authentication protocol and cookie in standard input.
|
||||
.It
|
||||
Runs user's shell or command.
|
||||
.El
|
||||
.Sh AUTHORIZED_KEYS FILE FORMAT
|
||||
The
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
file lists the RSA keys that are
|
||||
permitted for RSA authentication. Each line of the file contains one
|
||||
key (empty lines and lines starting with a
|
||||
.Ql #
|
||||
are ignored as
|
||||
comments). Each line consists of the following fields, separated by
|
||||
spaces: options, bits, exponent, modulus, comment. The options field
|
||||
is optional; its presence is determined by whether the line starts
|
||||
with a number or not (the option field never starts with a number).
|
||||
The bits, exponent, modulus and comment fields give the RSA key; the
|
||||
comment field is not used for anything (but may be convenient for the
|
||||
user to identify the key).
|
||||
.Pp
|
||||
Note that lines in this file are usually several hundred bytes long
|
||||
(because of the size of the RSA key modulus). You don't want to type
|
||||
them in; instead, copy the
|
||||
.Pa identity.pub
|
||||
file and edit it.
|
||||
.Pp
|
||||
The options (if present) consists of comma-separated option
|
||||
specifications. No spaces are permitted, except within double quotes.
|
||||
The following option specifications are supported:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm from="pattern-list"
|
||||
Specifies that in addition to RSA authentication, the canonical name
|
||||
of the remote host must be present in the comma-separated list of
|
||||
patterns ('*' and '?' serve as wildcards). The list may also contain
|
||||
patterns negated by prefixing them with '!'; if the canonical host
|
||||
name matches a negated pattern, the key is not accepted. The purpose
|
||||
of this option is to optionally increase security: RSA authentication
|
||||
by itself does not trust the network or name servers or anything (but
|
||||
the key); however, if somebody somehow steals the key, the key
|
||||
permits an intruder to log in from anywhere in the world. This
|
||||
additional option makes using a stolen key more difficult (name
|
||||
servers and/or routers would have to be compromised in addition to
|
||||
just the key).
|
||||
.It Cm command="command"
|
||||
Specifies that the command is executed whenever this key is used for
|
||||
authentication. The command supplied by the user (if any) is ignored.
|
||||
The command is run on a pty if the connection requests a pty;
|
||||
otherwise it is run without a tty. A quote may be included in the
|
||||
command by quoting it with a backslash. This option might be useful
|
||||
to restrict certain RSA keys to perform just a specific operation. An
|
||||
example might be a key that permits remote backups but nothing
|
||||
else. Notice that the client may specify TCP/IP and/or X11
|
||||
forwardings unless they are explicitly prohibited.
|
||||
.It Cm environment="NAME=value"
|
||||
Specifies that the string is to be added to the environment when
|
||||
logging in using this key. Environment variables set this way
|
||||
override other default environment values. Multiple options of this
|
||||
type are permitted.
|
||||
.It Cm no-port-forwarding
|
||||
Forbids TCP/IP forwarding when this key is used for authentication.
|
||||
Any port forward requests by the client will return an error. This
|
||||
might be used, e.g., in connection with the
|
||||
.Cm command
|
||||
option.
|
||||
.It Cm no-X11-forwarding
|
||||
Forbids X11 forwarding when this key is used for authentication.
|
||||
Any X11 forward requests by the client will return an error.
|
||||
.It Cm no-agent-forwarding
|
||||
Forbids authentication agent forwarding when this key is used for
|
||||
authentication.
|
||||
.It Cm no-pty
|
||||
Prevents tty allocation (a request to allocate a pty will fail).
|
||||
.El
|
||||
.Ss Examples
|
||||
1024 33 12121.\|.\|.\|312314325 ylo@foo.bar
|
||||
.Pp
|
||||
from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
|
||||
.Pp
|
||||
command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
|
||||
.Sh SSH_KNOWN_HOSTS FILE FORMAT
|
||||
The
|
||||
.Pa /etc/ssh_known_hosts
|
||||
and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
files contain host public keys for all known hosts. The global file should
|
||||
be prepared by the admistrator (optional), and the per-user file is
|
||||
maintained automatically: whenever the user connects an unknown host
|
||||
its key is added to the per-user file.
|
||||
.Pp
|
||||
Each line in these files contains the following fields: hostnames,
|
||||
bits, exponent, modulus, comment. The fields are separated by spaces.
|
||||
.Pp
|
||||
Hostnames is a comma-separated list of patterns ('*' and '?' act as
|
||||
wildcards); each pattern in turn is matched against the canonical host
|
||||
name (when authenticating a client) or against the user-supplied
|
||||
name (when authenticating a server). A pattern may also be preceded
|
||||
by
|
||||
.Ql !
|
||||
to indicate negation: if the host name matches a negated
|
||||
pattern, it is not accepted (by that line) even if it matched another
|
||||
pattern on the line.
|
||||
.Pp
|
||||
Bits, exponent, and modulus are taken directly from the host key; they
|
||||
can be obtained, e.g., from
|
||||
.Pa /etc/ssh_host_key.pub .
|
||||
The optional comment field continues to the end of the line, and is not used.
|
||||
.Pp
|
||||
Lines starting with
|
||||
.Ql #
|
||||
and empty lines are ignored as comments.
|
||||
.Pp
|
||||
When performing host authentication, authentication is accepted if any
|
||||
matching line has the proper key. It is thus permissible (but not
|
||||
recommended) to have several lines or different host keys for the same
|
||||
names. This will inevitably happen when short forms of host names
|
||||
from different domains are put in the file. It is possible
|
||||
that the files contain conflicting information; authentication is
|
||||
accepted if valid information can be found from either file.
|
||||
.Pp
|
||||
Note that the lines in these files are typically hundreds of characters
|
||||
long, and you definitely don't want to type in the host keys by hand.
|
||||
Rather, generate them by a script
|
||||
or by taking
|
||||
.Pa /etc/ssh_host_key.pub
|
||||
and adding the host names at the front.
|
||||
.Ss Examples
|
||||
closenet,closenet.hut.fi,.\|.\|.\|,130.233.208.41 1024 37 159.\|.\|.93 closenet.hut.fi
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa /etc/sshd_config
|
||||
Contains configuration data for
|
||||
.Nm sshd .
|
||||
This file should be writable by root only, but it is recommended
|
||||
(though not necessary) that it be world-readable.
|
||||
.It Pa /etc/ssh_host_key
|
||||
Contains the private part of the host key.
|
||||
This file should only be owned by root, readable only by root, and not
|
||||
accessible to others.
|
||||
Note that
|
||||
.Nm
|
||||
does not start if this file is group/world-accessible.
|
||||
.It Pa /etc/ssh_host_key.pub
|
||||
Contains the public part of the host key.
|
||||
This file should be world-readable but writable only by
|
||||
root. Its contents should match the private part. This file is not
|
||||
really used for anything; it is only provided for the convenience of
|
||||
the user so its contents can be copied to known hosts files.
|
||||
These two files are created using
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Pa /var/run/sshd.pid
|
||||
Contains the process ID of the
|
||||
.Nm
|
||||
listening for connections (if there are several daemons running
|
||||
concurrently for different ports, this contains the pid of the one
|
||||
started last). The contents of this file are not sensitive; it can be
|
||||
world-readable.
|
||||
.It Pa $HOME/.ssh/authorized_keys
|
||||
Lists the RSA keys that can be used to log into the user's account.
|
||||
This file must be readable by root (which may on some machines imply
|
||||
it being world-readable if the user's home directory resides on an NFS
|
||||
volume). It is recommended that it not be accessible by others. The
|
||||
format of this file is described above.
|
||||
.It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
|
||||
These files are consulted when using rhosts with RSA host
|
||||
authentication to check the public key of the host. The key must be
|
||||
listed in one of these files to be accepted.
|
||||
The client uses the same files
|
||||
to verify that the remote host is the one we intended to
|
||||
connect. These files should be writable only by root/the owner.
|
||||
.Pa /etc/ssh_known_hosts
|
||||
should be world-readable, and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
can but need not be world-readable.
|
||||
.It Pa /etc/nologin
|
||||
If this file exists,
|
||||
.Nm
|
||||
refuses to let anyone except root log in. The contents of the file
|
||||
are displayed to anyone trying to log in, and non-root connections are
|
||||
refused. The file should be world-readable.
|
||||
.It Pa /etc/hosts.allow, /etc/hosts.deny
|
||||
If compiled with
|
||||
.Sy LIBWRAP
|
||||
support, tcp-wrappers access controls may be defined here as described in
|
||||
.Xr hosts_access 5 .
|
||||
.It Pa $HOME/.rhosts
|
||||
This file contains host-username pairs, separated by a space, one per
|
||||
line. The given user on the corresponding host is permitted to log in
|
||||
without password. The same file is used by rlogind and rshd.
|
||||
The file must
|
||||
be writable only by the user; it is recommended that it not be
|
||||
accessible by others.
|
||||
.Pp
|
||||
If is also possible to use netgroups in the file. Either host or user
|
||||
name may be of the form +@groupname to specify all hosts or all users
|
||||
in the group.
|
||||
.It Pa $HOME/.shosts
|
||||
For ssh,
|
||||
this file is exactly the same as for
|
||||
.Pa .rhosts .
|
||||
However, this file is
|
||||
not used by rlogin and rshd, so using this permits access using SSH only.
|
||||
.Pa /etc/hosts.equiv
|
||||
This file is used during
|
||||
.Pa .rhosts
|
||||
authentication. In the
|
||||
simplest form, this file contains host names, one per line. Users on
|
||||
those hosts are permitted to log in without a password, provided they
|
||||
have the same user name on both machines. The host name may also be
|
||||
followed by a user name; such users are permitted to log in as
|
||||
.Em any
|
||||
user on this machine (except root). Additionally, the syntax
|
||||
.Dq +@group
|
||||
can be used to specify netgroups. Negated entries start with
|
||||
.Ql \&- .
|
||||
.Pp
|
||||
If the client host/user is successfully matched in this file, login is
|
||||
automatically permitted provided the client and server user names are the
|
||||
same. Additionally, successful RSA host authentication is normally
|
||||
required. This file must be writable only by root; it is recommended
|
||||
that it be world-readable.
|
||||
.Pp
|
||||
.Sy "Warning: It is almost never a good idea to use user names in"
|
||||
.Pa hosts.equiv .
|
||||
Beware that it really means that the named user(s) can log in as
|
||||
.Em anybody ,
|
||||
which includes bin, daemon, adm, and other accounts that own critical
|
||||
binaries and directories. Using a user name practically grants the
|
||||
user root access. The only valid use for user names that I can think
|
||||
of is in negative entries.
|
||||
.Pp
|
||||
Note that this warning also applies to rsh/rlogin.
|
||||
.It Pa /etc/shosts.equiv
|
||||
This is processed exactly as
|
||||
.Pa /etc/hosts.equiv .
|
||||
However, this file may be useful in environments that want to run both
|
||||
rsh/rlogin and ssh.
|
||||
.It Pa $HOME/.ssh/environment
|
||||
This file is read into the environment at login (if it exists). It
|
||||
can only contain empty lines, comment lines (that start with
|
||||
.Ql # ) ,
|
||||
and assignment lines of the form name=value. The file should be writable
|
||||
only by the user; it need not be readable by anyone else.
|
||||
.It Pa $HOME/.ssh/rc
|
||||
If this file exists, it is run with /bin/sh after reading the
|
||||
environment files but before starting the user's shell or command. If
|
||||
X11 spoofing is in use, this will receive the "proto cookie" pair in
|
||||
standard input (and
|
||||
.Ev DISPLAY
|
||||
in environment). This must call
|
||||
.Xr xauth 1
|
||||
in that case.
|
||||
.Pp
|
||||
The primary purpose of this file is to run any initialization routines
|
||||
which may be needed before the user's home directory becomes
|
||||
accessible; AFS is a particular example of such an environment.
|
||||
.Pp
|
||||
This file will probably contain some initialization code followed by
|
||||
something similar to: "if read proto cookie; then echo add $DISPLAY
|
||||
$proto $cookie | xauth -q -; fi".
|
||||
.Pp
|
||||
If this file does not exist,
|
||||
.Pa /etc/sshrc
|
||||
is run, and if that
|
||||
does not exist either, xauth is used to store the cookie.
|
||||
.Pp
|
||||
This file should be writable only by the user, and need not be
|
||||
readable by anyone else.
|
||||
.It Pa /etc/sshrc
|
||||
Like
|
||||
.Pa $HOME/.ssh/rc .
|
||||
This can be used to specify
|
||||
machine-specific login-time initializations globally. This file
|
||||
should be writable only by root, and should be world-readable.
|
||||
.Sh AUTHOR
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
|
||||
but with bugs removed and newer features re-added. Rapidly after the
|
||||
1.2.12 release, newer versions of the original ssh bore successively
|
||||
more restrictive licenses, and thus demand for a free version was born.
|
||||
This version of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
has all components of a restrictive nature (i.e., patents, see
|
||||
.Xr ssl 8 )
|
||||
directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5, making it compatible with
|
||||
all other ssh protocol 1 clients and servers.
|
||||
.It
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
supports one-time password authentication with
|
||||
.Xr skey 1 .
|
||||
.El
|
||||
.Pp
|
||||
The libraries described in
|
||||
.Xr ssl 8
|
||||
are required for proper operation.
|
||||
.Sh SEE ALSO
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr scp 1 ,
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr ssl 8
|
2541
crypto/openssh/sshd.c
Normal file
2541
crypto/openssh/sshd.c
Normal file
File diff suppressed because it is too large
Load Diff
45
crypto/openssh/sshd/Makefile
Normal file
45
crypto/openssh/sshd/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
PROG= sshd
|
||||
BINOWN= root
|
||||
BINMODE=555
|
||||
BINDIR= /usr/sbin
|
||||
MAN= sshd.8
|
||||
|
||||
SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \
|
||||
pty.c log-server.c login.c servconf.c serverloop.c
|
||||
|
||||
.include <bsd.own.mk> # for KERBEROS and AFS
|
||||
|
||||
.if (${KERBEROS} == "yes")
|
||||
CFLAGS+= -DKRB4 -I/usr/include/kerberosIV
|
||||
SRCS+= auth-krb4.c
|
||||
LDADD+= -lkrb
|
||||
DPADD+= ${LIBKRB}
|
||||
.if (${AFS} == "yes")
|
||||
CFLAGS+= -DAFS
|
||||
LDADD+= -lkafs
|
||||
DPADD+= ${LIBKRBAFS}
|
||||
.endif # AFS
|
||||
.endif # KERBEROS
|
||||
|
||||
.if (${SKEY} == "yes")
|
||||
SRCS+= auth-skey.c
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
LDADD+= -lcrypto -lutil -lz
|
||||
DPADD+= ${LIBCRYPTO} ${LIBUTIL} ${LIBZ}
|
||||
|
||||
.if (${TCP_WRAPPERS} == "yes")
|
||||
CFLAGS+= -DLIBWRAP
|
||||
LDADD+= -lwrap
|
||||
DPADD+= ${LIBWRAP}
|
||||
.endif
|
||||
|
||||
.if (${SKEY} == "yes")
|
||||
CFLAGS+= -DSKEY
|
||||
LDADD+= -lskey
|
||||
DPADD+= ${SKEY}
|
||||
.endif
|
50
crypto/openssh/sshd_config
Normal file
50
crypto/openssh/sshd_config
Normal file
@ -0,0 +1,50 @@
|
||||
# This is ssh server systemwide configuration file.
|
||||
|
||||
Port 22
|
||||
#ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
HostKey /etc/ssh_host_key
|
||||
ServerKeyBits 768
|
||||
LoginGraceTime 600
|
||||
KeyRegenerationInterval 3600
|
||||
PermitRootLogin yes
|
||||
#
|
||||
# Don't read ~/.rhosts and ~/.shosts files
|
||||
IgnoreRhosts yes
|
||||
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
|
||||
#IgnoreUserKnownHosts yes
|
||||
StrictModes yes
|
||||
X11Forwarding no
|
||||
X11DisplayOffset 10
|
||||
PrintMotd yes
|
||||
KeepAlive yes
|
||||
|
||||
# Logging
|
||||
SyslogFacility AUTH
|
||||
LogLevel INFO
|
||||
#obsoletes QuietMode and FascistLogging
|
||||
|
||||
RhostsAuthentication no
|
||||
#
|
||||
# For this to work you will also need host keys in /etc/ssh_known_hosts
|
||||
RhostsRSAAuthentication no
|
||||
#
|
||||
RSAAuthentication yes
|
||||
|
||||
# To disable tunneled clear text passwords, change to no here!
|
||||
PasswordAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
# Uncomment to disable s/key passwords
|
||||
#SkeyAuthentication no
|
||||
|
||||
# To change Kerberos options
|
||||
#KerberosAuthentication no
|
||||
#KerberosOrLocalPasswd yes
|
||||
#AFSTokenPassing no
|
||||
#KerberosTicketCleanup no
|
||||
|
||||
# Kerberos TGT Passing does only work with the AFS kaserver
|
||||
#KerberosTgtPassing yes
|
||||
|
||||
#CheckMail yes
|
||||
#UseLogin no
|
66
crypto/openssh/tildexpand.c
Normal file
66
crypto/openssh/tildexpand.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Wed Jul 12 01:07:36 1995 ylo
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: tildexpand.c,v 1.6 1999/12/06 19:10:38 deraadt Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
* Warning: this calls getpw*.
|
||||
*/
|
||||
char *
|
||||
tilde_expand_filename(const char *filename, uid_t my_uid)
|
||||
{
|
||||
const char *cp;
|
||||
unsigned int userlen;
|
||||
char *expanded;
|
||||
struct passwd *pw;
|
||||
char user[100];
|
||||
int len;
|
||||
|
||||
/* Return immediately if no tilde. */
|
||||
if (filename[0] != '~')
|
||||
return xstrdup(filename);
|
||||
|
||||
/* Skip the tilde. */
|
||||
filename++;
|
||||
|
||||
/* Find where the username ends. */
|
||||
cp = strchr(filename, '/');
|
||||
if (cp)
|
||||
userlen = cp - filename; /* Something after username. */
|
||||
else
|
||||
userlen = strlen(filename); /* Nothing after username. */
|
||||
if (userlen == 0)
|
||||
pw = getpwuid(my_uid); /* Own home directory. */
|
||||
else {
|
||||
/* Tilde refers to someone elses home directory. */
|
||||
if (userlen > sizeof(user) - 1)
|
||||
fatal("User name after tilde too long.");
|
||||
memcpy(user, filename, userlen);
|
||||
user[userlen] = 0;
|
||||
pw = getpwnam(user);
|
||||
}
|
||||
if (!pw)
|
||||
fatal("Unknown user %100s.", user);
|
||||
|
||||
/* If referring to someones home directory, return it now. */
|
||||
if (!cp) {
|
||||
/* Only home directory specified */
|
||||
return xstrdup(pw->pw_dir);
|
||||
}
|
||||
/* Build a path combining the specified directory and path. */
|
||||
len = strlen(pw->pw_dir) + strlen(cp + 1) + 2;
|
||||
if (len > MAXPATHLEN)
|
||||
fatal("Home directory too long (%d > %d", len-1, MAXPATHLEN-1);
|
||||
expanded = xmalloc(len);
|
||||
snprintf(expanded, len, "%s/%s", pw->pw_dir, cp + 1);
|
||||
return expanded;
|
||||
}
|
359
crypto/openssh/ttymodes.c
Normal file
359
crypto/openssh/ttymodes.c
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Tue Mar 21 15:59:15 1995 ylo
|
||||
* Encoding and decoding of terminal modes in a portable way.
|
||||
* Much of the format is defined in ttymodes.h; it is included multiple times
|
||||
* into this file with the appropriate macro definitions to generate the
|
||||
* suitable code.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#define TTY_OP_END 0
|
||||
#define TTY_OP_ISPEED 192 /* int follows */
|
||||
#define TTY_OP_OSPEED 193 /* int follows */
|
||||
|
||||
/*
|
||||
* Converts POSIX speed_t to a baud rate. The values of the
|
||||
* constants for speed_t are not themselves portable.
|
||||
*/
|
||||
static int
|
||||
speed_to_baud(speed_t speed)
|
||||
{
|
||||
switch (speed) {
|
||||
case B0:
|
||||
return 0;
|
||||
case B50:
|
||||
return 50;
|
||||
case B75:
|
||||
return 75;
|
||||
case B110:
|
||||
return 110;
|
||||
case B134:
|
||||
return 134;
|
||||
case B150:
|
||||
return 150;
|
||||
case B200:
|
||||
return 200;
|
||||
case B300:
|
||||
return 300;
|
||||
case B600:
|
||||
return 600;
|
||||
case B1200:
|
||||
return 1200;
|
||||
case B1800:
|
||||
return 1800;
|
||||
case B2400:
|
||||
return 2400;
|
||||
case B4800:
|
||||
return 4800;
|
||||
case B9600:
|
||||
return 9600;
|
||||
|
||||
#ifdef B19200
|
||||
case B19200:
|
||||
return 19200;
|
||||
#else /* B19200 */
|
||||
#ifdef EXTA
|
||||
case EXTA:
|
||||
return 19200;
|
||||
#endif /* EXTA */
|
||||
#endif /* B19200 */
|
||||
|
||||
#ifdef B38400
|
||||
case B38400:
|
||||
return 38400;
|
||||
#else /* B38400 */
|
||||
#ifdef EXTB
|
||||
case EXTB:
|
||||
return 38400;
|
||||
#endif /* EXTB */
|
||||
#endif /* B38400 */
|
||||
|
||||
#ifdef B7200
|
||||
case B7200:
|
||||
return 7200;
|
||||
#endif /* B7200 */
|
||||
#ifdef B14400
|
||||
case B14400:
|
||||
return 14400;
|
||||
#endif /* B14400 */
|
||||
#ifdef B28800
|
||||
case B28800:
|
||||
return 28800;
|
||||
#endif /* B28800 */
|
||||
#ifdef B57600
|
||||
case B57600:
|
||||
return 57600;
|
||||
#endif /* B57600 */
|
||||
#ifdef B76800
|
||||
case B76800:
|
||||
return 76800;
|
||||
#endif /* B76800 */
|
||||
#ifdef B115200
|
||||
case B115200:
|
||||
return 115200;
|
||||
#endif /* B115200 */
|
||||
#ifdef B230400
|
||||
case B230400:
|
||||
return 230400;
|
||||
#endif /* B230400 */
|
||||
default:
|
||||
return 9600;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a numeric baud rate to a POSIX speed_t.
|
||||
*/
|
||||
static speed_t
|
||||
baud_to_speed(int baud)
|
||||
{
|
||||
switch (baud) {
|
||||
case 0:
|
||||
return B0;
|
||||
case 50:
|
||||
return B50;
|
||||
case 75:
|
||||
return B75;
|
||||
case 110:
|
||||
return B110;
|
||||
case 134:
|
||||
return B134;
|
||||
case 150:
|
||||
return B150;
|
||||
case 200:
|
||||
return B200;
|
||||
case 300:
|
||||
return B300;
|
||||
case 600:
|
||||
return B600;
|
||||
case 1200:
|
||||
return B1200;
|
||||
case 1800:
|
||||
return B1800;
|
||||
case 2400:
|
||||
return B2400;
|
||||
case 4800:
|
||||
return B4800;
|
||||
case 9600:
|
||||
return B9600;
|
||||
|
||||
#ifdef B19200
|
||||
case 19200:
|
||||
return B19200;
|
||||
#else /* B19200 */
|
||||
#ifdef EXTA
|
||||
case 19200:
|
||||
return EXTA;
|
||||
#endif /* EXTA */
|
||||
#endif /* B19200 */
|
||||
|
||||
#ifdef B38400
|
||||
case 38400:
|
||||
return B38400;
|
||||
#else /* B38400 */
|
||||
#ifdef EXTB
|
||||
case 38400:
|
||||
return EXTB;
|
||||
#endif /* EXTB */
|
||||
#endif /* B38400 */
|
||||
|
||||
#ifdef B7200
|
||||
case 7200:
|
||||
return B7200;
|
||||
#endif /* B7200 */
|
||||
#ifdef B14400
|
||||
case 14400:
|
||||
return B14400;
|
||||
#endif /* B14400 */
|
||||
#ifdef B28800
|
||||
case 28800:
|
||||
return B28800;
|
||||
#endif /* B28800 */
|
||||
#ifdef B57600
|
||||
case 57600:
|
||||
return B57600;
|
||||
#endif /* B57600 */
|
||||
#ifdef B76800
|
||||
case 76800:
|
||||
return B76800;
|
||||
#endif /* B76800 */
|
||||
#ifdef B115200
|
||||
case 115200:
|
||||
return B115200;
|
||||
#endif /* B115200 */
|
||||
#ifdef B230400
|
||||
case 230400:
|
||||
return B230400;
|
||||
#endif /* B230400 */
|
||||
default:
|
||||
return B9600;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encodes terminal modes for the terminal referenced by fd
|
||||
* in a portable manner, and appends the modes to a packet
|
||||
* being constructed.
|
||||
*/
|
||||
void
|
||||
tty_make_modes(int fd)
|
||||
{
|
||||
struct termios tio;
|
||||
int baud;
|
||||
|
||||
if (tcgetattr(fd, &tio) < 0) {
|
||||
packet_put_char(TTY_OP_END);
|
||||
log("tcgetattr: %.100s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
/* Store input and output baud rates. */
|
||||
baud = speed_to_baud(cfgetospeed(&tio));
|
||||
packet_put_char(TTY_OP_OSPEED);
|
||||
packet_put_int(baud);
|
||||
baud = speed_to_baud(cfgetispeed(&tio));
|
||||
packet_put_char(TTY_OP_ISPEED);
|
||||
packet_put_int(baud);
|
||||
|
||||
/* Store values of mode flags. */
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
|
||||
#define TTYMODE(NAME, FIELD, OP) \
|
||||
packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
|
||||
#define SGTTYCHAR(NAME, OP)
|
||||
#define SGTTYMODE(NAME, FIELD, OP)
|
||||
#define SGTTYMODEN(NAME, FIELD, OP)
|
||||
|
||||
#include "ttymodes.h"
|
||||
|
||||
#undef TTYCHAR
|
||||
#undef TTYMODE
|
||||
#undef SGTTYCHAR
|
||||
#undef SGTTYMODE
|
||||
#undef SGTTYMODEN
|
||||
|
||||
/* Mark end of mode data. */
|
||||
packet_put_char(TTY_OP_END);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes terminal modes for the terminal referenced by fd in a portable
|
||||
* manner from a packet being read.
|
||||
*/
|
||||
void
|
||||
tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
{
|
||||
struct termios tio;
|
||||
int opcode, baud;
|
||||
int n_bytes = 0;
|
||||
int failure = 0;
|
||||
|
||||
/*
|
||||
* Get old attributes for the terminal. We will modify these
|
||||
* flags. I am hoping that if there are any machine-specific
|
||||
* modes, they will initially have reasonable values.
|
||||
*/
|
||||
if (tcgetattr(fd, &tio) < 0)
|
||||
failure = -1;
|
||||
|
||||
for (;;) {
|
||||
n_bytes += 1;
|
||||
opcode = packet_get_char();
|
||||
switch (opcode) {
|
||||
case TTY_OP_END:
|
||||
goto set;
|
||||
|
||||
case TTY_OP_ISPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetispeed failed for %d", baud);
|
||||
break;
|
||||
|
||||
case TTY_OP_OSPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetospeed failed for %d", baud);
|
||||
break;
|
||||
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
case OP: \
|
||||
n_bytes += 1; \
|
||||
tio.c_cc[NAME] = packet_get_char(); \
|
||||
break;
|
||||
#define TTYMODE(NAME, FIELD, OP) \
|
||||
case OP: \
|
||||
n_bytes += 1; \
|
||||
if (packet_get_char()) \
|
||||
tio.FIELD |= NAME; \
|
||||
else \
|
||||
tio.FIELD &= ~NAME; \
|
||||
break;
|
||||
#define SGTTYCHAR(NAME, OP)
|
||||
#define SGTTYMODE(NAME, FIELD, OP)
|
||||
#define SGTTYMODEN(NAME, FIELD, OP)
|
||||
|
||||
#include "ttymodes.h"
|
||||
|
||||
#undef TTYCHAR
|
||||
#undef TTYMODE
|
||||
#undef SGTTYCHAR
|
||||
#undef SGTTYMODE
|
||||
#undef SGTTYMODEN
|
||||
|
||||
default:
|
||||
debug("Ignoring unsupported tty mode opcode %d (0x%x)",
|
||||
opcode, opcode);
|
||||
/*
|
||||
* Opcodes 0 to 127 are defined to have
|
||||
* a one-byte argument.
|
||||
*/
|
||||
if (opcode >= 0 && opcode < 128) {
|
||||
n_bytes += 1;
|
||||
(void) packet_get_char();
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Opcodes 128 to 159 are defined to have
|
||||
* an integer argument.
|
||||
*/
|
||||
if (opcode >= 128 && opcode < 160) {
|
||||
n_bytes += 4;
|
||||
(void) packet_get_int();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It is a truly undefined opcode (160 to 255).
|
||||
* We have no idea about its arguments. So we
|
||||
* must stop parsing. Note that some data may be
|
||||
* left in the packet; hopefully there is nothing
|
||||
* more coming after the mode data.
|
||||
*/
|
||||
log("parse_tty_modes: unknown opcode %d", opcode);
|
||||
packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
|
||||
goto set;
|
||||
}
|
||||
}
|
||||
|
||||
set:
|
||||
if (*n_bytes_ptr != n_bytes) {
|
||||
*n_bytes_ptr = n_bytes;
|
||||
return; /* Don't process bytes passed */
|
||||
}
|
||||
if (failure == -1)
|
||||
return; /* Packet parsed ok but tty stuff failed */
|
||||
|
||||
/* Set the new modes for the terminal. */
|
||||
if (tcsetattr(fd, TCSANOW, &tio) < 0)
|
||||
log("Setting tty modes failed: %.100s", strerror(errno));
|
||||
return;
|
||||
}
|
141
crypto/openssh/ttymodes.h
Normal file
141
crypto/openssh/ttymodes.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
*
|
||||
* ttymodes.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Tue Mar 21 15:42:09 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ttymodes.h,v 1.6 1999/11/24 19:53:54 markus Exp $"); */
|
||||
|
||||
/* The tty mode description is a stream of bytes. The stream consists of
|
||||
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
||||
* Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer
|
||||
* arguments. Opcodes 160-255 are not yet defined, and cause parsing to
|
||||
* stop (they should only be used after any other data).
|
||||
*
|
||||
* The client puts in the stream any modes it knows about, and the
|
||||
* server ignores any modes it does not know about. This allows some degree
|
||||
* of machine-independence, at least between systems that use a posix-like
|
||||
* tty interface. The protocol can support other systems as well, but might
|
||||
* require reimplementing as mode names would likely be different.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some constants and prototypes are defined in packet.h; this file
|
||||
* is only intended for including from ttymodes.c.
|
||||
*/
|
||||
|
||||
/* termios macro */ /* sgtty macro */
|
||||
/* name, op */
|
||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||
TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
|
||||
#if defined(VKILL)
|
||||
TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
|
||||
#endif /* VKILL */
|
||||
TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
|
||||
#if defined(VEOL)
|
||||
TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
|
||||
#endif /* VEOL */
|
||||
#ifdef VEOL2 /* n/a */
|
||||
TTYCHAR(VEOL2, 7)
|
||||
#endif /* VEOL2 */
|
||||
TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
|
||||
TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
|
||||
#if defined(VSUSP)
|
||||
TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
|
||||
#endif /* VSUSP */
|
||||
#if defined(VDSUSP)
|
||||
TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
|
||||
#endif /* VDSUSP */
|
||||
#if defined(VREPRINT)
|
||||
TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
|
||||
#endif /* VREPRINT */
|
||||
#if defined(VWERASE)
|
||||
TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
|
||||
#endif /* VWERASE */
|
||||
#if defined(VLNEXT)
|
||||
TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
|
||||
#endif /* VLNEXT */
|
||||
#if defined(VFLUSH)
|
||||
TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
|
||||
#endif /* VFLUSH */
|
||||
#ifdef VSWTCH
|
||||
TTYCHAR(VSWTCH, 16) /* n/a */
|
||||
#endif /* VSWTCH */
|
||||
#if defined(VSTATUS)
|
||||
TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
|
||||
#endif /* VSTATUS */
|
||||
#ifdef VDISCARD
|
||||
TTYCHAR(VDISCARD, 18) /* n/a */
|
||||
#endif /* VDISCARD */
|
||||
|
||||
/* name, field, op */
|
||||
TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
|
||||
TTYMODE(PARMRK, c_iflag, 31) /* n/a */
|
||||
TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
|
||||
TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
|
||||
TTYMODE(INLCR, c_iflag, 34) /* n/a */
|
||||
TTYMODE(IGNCR, c_iflag, 35) /* n/a */
|
||||
TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
|
||||
#if defined(IUCLC)
|
||||
TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
|
||||
#endif
|
||||
TTYMODE(IXON, c_iflag, 38) /* n/a */
|
||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||
#ifdef IMAXBEL
|
||||
TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */
|
||||
#endif /* IMAXBEL */
|
||||
|
||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||
TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
|
||||
#ifdef XCASE
|
||||
TTYMODE(XCASE, c_lflag, 52) /* n/a */
|
||||
#endif
|
||||
TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
|
||||
TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
|
||||
TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
|
||||
TTYMODE(ECHONL, c_lflag, 56) /* n/a */
|
||||
TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
|
||||
TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
||||
#ifdef IEXTEN
|
||||
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
|
||||
#endif /* IEXTEN */
|
||||
#if defined(ECHOCTL)
|
||||
TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||
#endif /* ECHOCTL */
|
||||
#ifdef ECHOKE
|
||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||
#endif /* ECHOKE */
|
||||
#if defined(PENDIN)
|
||||
TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
|
||||
#endif /* PENDIN */
|
||||
|
||||
TTYMODE(OPOST, c_oflag, 70) /* n/a */
|
||||
#if defined(OLCUC)
|
||||
TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
|
||||
#endif
|
||||
TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
|
||||
#ifdef OCRNL
|
||||
TTYMODE(OCRNL, c_oflag, 73) /* n/a */
|
||||
#endif
|
||||
#ifdef ONOCR
|
||||
TTYMODE(ONOCR, c_oflag, 74) /* n/a */
|
||||
#endif
|
||||
#ifdef ONLRET
|
||||
TTYMODE(ONLRET, c_oflag, 75) /* n/a */
|
||||
#endif
|
||||
|
||||
TTYMODE(CS7, c_cflag, 90) /* n/a */
|
||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||
|
87
crypto/openssh/uidswap.c
Normal file
87
crypto/openssh/uidswap.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sat Sep 9 01:56:14 1995 ylo
|
||||
* Code for uid-swapping.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: uidswap.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
/*
|
||||
* Note: all these functions must work in all of the following cases:
|
||||
* 1. euid=0, ruid=0
|
||||
* 2. euid=0, ruid!=0
|
||||
* 3. euid!=0, ruid!=0
|
||||
* Additionally, they must work regardless of whether the system has
|
||||
* POSIX saved uids or not.
|
||||
*/
|
||||
|
||||
#ifdef _POSIX_SAVED_IDS
|
||||
/* Lets assume that posix saved ids also work with seteuid, even though that
|
||||
is not part of the posix specification. */
|
||||
#define SAVED_IDS_WORK_WITH_SETEUID
|
||||
#endif /* _POSIX_SAVED_IDS */
|
||||
|
||||
/* Saved effective uid. */
|
||||
static uid_t saved_euid = 0;
|
||||
|
||||
/*
|
||||
* Temporarily changes to the given uid. If the effective user
|
||||
* id is not root, this does nothing. This call cannot be nested.
|
||||
*/
|
||||
void
|
||||
temporarily_use_uid(uid_t uid)
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
/* Save the current euid. */
|
||||
saved_euid = geteuid();
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int) uid, strerror(errno));
|
||||
#else /* SAVED_IDS_WORK_WITH_SETUID */
|
||||
/* Propagate the privileged uid to all of our uids. */
|
||||
if (setuid(geteuid()) < 0)
|
||||
debug("setuid %d: %.100s", (int) geteuid(), strerror(errno));
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int) uid, strerror(errno));
|
||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
}
|
||||
|
||||
/*
|
||||
* Restores to the original uid.
|
||||
*/
|
||||
void
|
||||
restore_uid()
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
/* Set the effective uid back to the saved uid. */
|
||||
if (seteuid(saved_euid) < 0)
|
||||
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
|
||||
#else /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
/*
|
||||
* We are unable to restore the real uid to its unprivileged value.
|
||||
* Propagate the real uid (usually more privileged) to effective uid
|
||||
* as well.
|
||||
*/
|
||||
setuid(getuid());
|
||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
}
|
||||
|
||||
/*
|
||||
* Permanently sets all uids to the given uid. This cannot be
|
||||
* called while temporarily_use_uid is effective.
|
||||
*/
|
||||
void
|
||||
permanently_set_uid(uid_t uid)
|
||||
{
|
||||
if (setuid(uid) < 0)
|
||||
debug("setuid %d: %.100s", (int) uid, strerror(errno));
|
||||
}
|
36
crypto/openssh/uidswap.h
Normal file
36
crypto/openssh/uidswap.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
*
|
||||
* uidswap.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Sep 9 01:43:15 1995 ylo
|
||||
* Last modified: Sat Sep 9 02:34:04 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UIDSWAP_H
|
||||
#define UIDSWAP_H
|
||||
|
||||
/*
|
||||
* Temporarily changes to the given uid. If the effective user id is not
|
||||
* root, this does nothing. This call cannot be nested.
|
||||
*/
|
||||
void temporarily_use_uid(uid_t uid);
|
||||
|
||||
/*
|
||||
* Restores the original effective user id after temporarily_use_uid().
|
||||
* This should only be called while temporarily_use_uid is effective.
|
||||
*/
|
||||
void restore_uid();
|
||||
|
||||
/*
|
||||
* Permanently sets all uids to the given uid. This cannot be called while
|
||||
* temporarily_use_uid is effective. This must also clear any saved uids.
|
||||
*/
|
||||
void permanently_set_uid(uid_t uid);
|
||||
|
||||
#endif /* UIDSWAP_H */
|
1
crypto/openssh/version.h
Normal file
1
crypto/openssh/version.h
Normal file
@ -0,0 +1 @@
|
||||
#define SSH_VERSION "OpenSSH-1.2.2"
|
53
crypto/openssh/xmalloc.c
Normal file
53
crypto/openssh/xmalloc.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Mon Mar 20 21:23:10 1995 ylo
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: xmalloc.c,v 1.5 1999/11/24 00:26:04 deraadt Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
fatal("xmalloc: out of memory (allocating %d bytes)", (int) size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *ptr, size_t new_size)
|
||||
{
|
||||
void *new_ptr;
|
||||
|
||||
if (ptr == NULL)
|
||||
fatal("xrealloc: NULL pointer given as argument");
|
||||
new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr == NULL)
|
||||
fatal("xrealloc: out of memory (new_size %d bytes)", (int) new_size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
xfree(void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
fatal("xfree: NULL pointer given as argument");
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
int len = strlen(str) + 1;
|
||||
|
||||
char *cp = xmalloc(len);
|
||||
strlcpy(cp, str, len);
|
||||
return cp;
|
||||
}
|
34
crypto/openssh/xmalloc.h
Normal file
34
crypto/openssh/xmalloc.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
*
|
||||
* xmalloc.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 22:09:17 1995 ylo
|
||||
*
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 00:26:04 deraadt Exp $"); */
|
||||
|
||||
#ifndef XMALLOC_H
|
||||
#define XMALLOC_H
|
||||
|
||||
/* Like malloc, but calls fatal() if out of memory. */
|
||||
void *xmalloc(size_t size);
|
||||
|
||||
/* Like realloc, but calls fatal() if out of memory. */
|
||||
void *xrealloc(void *ptr, size_t new_size);
|
||||
|
||||
/* Frees memory allocated using xmalloc or xrealloc. */
|
||||
void xfree(void *ptr);
|
||||
|
||||
/* Allocates memory using xmalloc, and copies the string into that memory. */
|
||||
char *xstrdup(const char *str);
|
||||
|
||||
#endif /* XMALLOC_H */
|
Loading…
Reference in New Issue
Block a user