Import NetBSD Secure Shell. This is based on OpenSSH, but modified
somewhat.
This commit is contained in:
parent
03aaa05985
commit
49a55a1d58
136
crypto/dist/ssh/LICENCE
vendored
Normal file
136
crypto/dist/ssh/LICENCE
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
This file is part of the ssh software.
|
||||
|
||||
The licences which components of this software falls under are as
|
||||
follows. First, we will summarize and say that that all components
|
||||
are under a BSD licence, or a licence more free than that.
|
||||
|
||||
OpenSSH contains no GPL code.
|
||||
|
||||
1)
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
|
||||
[Tatu continues]
|
||||
* 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.
|
||||
|
||||
[However, none of that term is relevant at this point in time. All of
|
||||
these restrictively licenced software components which he talks about
|
||||
have been removed from OpenSSH, ie.
|
||||
|
||||
- RSA is no longer included, found in the OpenSSL library
|
||||
- IDEA is no longer included, it's use is depricated
|
||||
- DES is now external, in the OpenSSL library
|
||||
- GMP is no longer used, and instead we call BN code from OpenSSL
|
||||
- Zlib is now external, in a library
|
||||
- The make-ssh-known-hosts script is no longer included
|
||||
- TSS has been removed
|
||||
- MD5 is now external, in the OpenSSL library
|
||||
- RC4 support has been replaced with ARC4 support from OpenSSL
|
||||
- Blowfish is now external, in the OpenSSL library
|
||||
|
||||
[The licence continues]
|
||||
|
||||
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.
|
||||
|
||||
2)
|
||||
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:
|
||||
|
||||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
|
||||
3)
|
||||
The 32-bit CRC compensation attack detector in deattack.c was
|
||||
contributed by CORE SDI S.A. under a BSD-style license. See
|
||||
http://www.core-sdi.com/english/ssh/ for details.
|
||||
|
||||
* 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>
|
||||
|
||||
4)
|
||||
Remaining components of the software are provided under a standard
|
||||
2-term BSD licence with the following names as copyright holders:
|
||||
|
||||
Markus Friedl
|
||||
Theo de Raadt
|
||||
Niels Provos
|
||||
Dug Song
|
||||
Aaron Campbell
|
||||
|
||||
* 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.
|
164
crypto/dist/ssh/OVERVIEW
vendored
Normal file
164
crypto/dist/ssh/OVERVIEW
vendored
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
|
567
crypto/dist/ssh/README
vendored
Normal file
567
crypto/dist/ssh/README
vendored
Normal file
@ -0,0 +1,567 @@
|
||||
|
||||
[ Please note that this file has not been updated for OpenSSH and
|
||||
covers the ssh-1.2.12 release from Dec 1995 only. ]
|
||||
|
||||
Ssh (Secure Shell) is a program to log into another computer over a
|
||||
network, to execute commands in a remote machine, and to move files
|
||||
from one machine to another. It provides strong authentication and
|
||||
secure communications over insecure channels. It is intended as a
|
||||
replacement for rlogin, rsh, rcp, and rdist.
|
||||
|
||||
See the file INSTALL for installation instructions. See COPYING for
|
||||
license terms and other legal issues. See RFC for a description of
|
||||
the protocol. There is a WWW page for ssh; see http://www.cs.hut.fi/ssh.
|
||||
|
||||
This file has been updated to match ssh-1.2.12.
|
||||
|
||||
|
||||
FEATURES
|
||||
|
||||
o Strong authentication. Closes several security holes (e.g., IP,
|
||||
routing, and DNS spoofing). New authentication methods: .rhosts
|
||||
together with RSA based host authentication, and pure RSA
|
||||
authentication.
|
||||
|
||||
o Improved privacy. All communications are automatically and
|
||||
transparently encrypted. RSA is used for key exchange, and a
|
||||
conventional cipher (normally IDEA, DES, or triple-DES) for
|
||||
encrypting the session. Encryption is started before
|
||||
authentication, and no passwords or other information is
|
||||
transmitted in the clear. Encryption is also used to protect
|
||||
against spoofed packets.
|
||||
|
||||
o Secure X11 sessions. The program automatically sets DISPLAY on
|
||||
the server machine, and forwards any X11 connections over the
|
||||
secure channel. Fake Xauthority information is automatically
|
||||
generated and forwarded to the remote machine; the local client
|
||||
automatically examines incoming X11 connections and replaces the
|
||||
fake authorization data with the real data (never telling the
|
||||
remote machine the real information).
|
||||
|
||||
o Arbitrary TCP/IP ports can be redirected through the encrypted channel
|
||||
in both directions (e.g., for e-cash transactions).
|
||||
|
||||
o No retraining needed for normal users; everything happens
|
||||
automatically, and old .rhosts files will work with strong
|
||||
authentication if administration installs host key files.
|
||||
|
||||
o Never trusts the network. Minimal trust on the remote side of
|
||||
the connection. Minimal trust on domain name servers. Pure RSA
|
||||
authentication never trusts anything but the private key.
|
||||
|
||||
o Client RSA-authenticates the server machine in the beginning of
|
||||
every connection to prevent trojan horses (by routing or DNS
|
||||
spoofing) and man-in-the-middle attacks, and the server
|
||||
RSA-authenticates the client machine before accepting .rhosts or
|
||||
/etc/hosts.equiv authentication (to prevent DNS, routing, or
|
||||
IP-spoofing).
|
||||
|
||||
o Host authentication key distribution can be centrally by the
|
||||
administration, automatically when the first connection is made
|
||||
to a machine (the key obtained on the first connection will be
|
||||
recorded and used for authentication in the future), or manually
|
||||
by each user for his/her own use. The central and per-user host
|
||||
key repositories are both used and complement each other. Host
|
||||
keys can be generated centrally or automatically when the software
|
||||
is installed. Host authentication keys are typically 1024 bits.
|
||||
|
||||
o Any user can create any number of user authentication RSA keys for
|
||||
his/her own use. Each user has a file which lists the RSA public
|
||||
keys for which proof of possession of the corresponding private
|
||||
key is accepted as authentication. User authentication keys are
|
||||
typically 1024 bits.
|
||||
|
||||
o The server program has its own server RSA key which is
|
||||
automatically regenerated every hour. This key is never saved in
|
||||
any file. Exchanged session keys are encrypted using both the
|
||||
server key and the server host key. The purpose of the separate
|
||||
server key is to make it impossible to decipher a captured session by
|
||||
breaking into the server machine at a later time; one hour from
|
||||
the connection even the server machine cannot decipher the session
|
||||
key. The key regeneration interval is configurable. The server
|
||||
key is normally 768 bits.
|
||||
|
||||
o An authentication agent, running in the user's laptop or local
|
||||
workstation, can be used to hold the user's RSA authentication
|
||||
keys. Ssh automatically forwards the connection to the
|
||||
authentication agent over any connections, and there is no need to
|
||||
store the RSA authentication keys on any machine in the network
|
||||
(except the user's own local machine). The authentication
|
||||
protocols never reveal the keys; they can only be used to verify
|
||||
that the user's agent has a certain key. Eventually the agent
|
||||
could rely on a smart card to perform all authentication
|
||||
computations.
|
||||
|
||||
o The software can be installed and used (with restricted
|
||||
functionality) even without root privileges.
|
||||
|
||||
o The client is customizable in system-wide and per-user
|
||||
configuration files. Most aspects of the client's operation can
|
||||
be configured. Different options can be specified on a per-host basis.
|
||||
|
||||
o Automatically executes conventional rsh (after displaying a
|
||||
warning) if the server machine is not running sshd.
|
||||
|
||||
o Optional compression of all data with gzip (including forwarded X11
|
||||
and TCP/IP port data), which may result in significant speedups on
|
||||
slow connections.
|
||||
|
||||
o Complete replacement for rlogin, rsh, and rcp.
|
||||
|
||||
|
||||
WHY TO USE SECURE SHELL
|
||||
|
||||
Currently, almost all communications in computer networks are done
|
||||
without encryption. As a consequence, anyone who has access to any
|
||||
machine connected to the network can listen in on any communication.
|
||||
This is being done by hackers, curious administrators, employers,
|
||||
criminals, industrial spies, and governments. Some networks leak off
|
||||
enough electromagnetic radiation that data may be captured even from a
|
||||
distance.
|
||||
|
||||
When you log in, your password goes in the network in plain
|
||||
text. Thus, any listener can then use your account to do any evil he
|
||||
likes. Many incidents have been encountered worldwide where crackers
|
||||
have started programs on workstations without the owners knowledge
|
||||
just to listen to the network and collect passwords. Programs for
|
||||
doing this are available on the Internet, or can be built by a
|
||||
competent programmer in a few hours.
|
||||
|
||||
Any information that you type or is printed on your screen can be
|
||||
monitored, recorded, and analyzed. For example, an intruder who has
|
||||
penetrated a host connected to a major network can start a program
|
||||
that listens to all data flowing in the network, and whenever it
|
||||
encounters a 16-digit string, it checks if it is a valid credit card
|
||||
number (using the check digit), and saves the number plus any
|
||||
surrounding text (to catch expiration date and holder) in a file.
|
||||
When the intruder has collected a few thousand credit card numbers, he
|
||||
makes smallish mail-order purchases from a few thousand stores around
|
||||
the world, and disappears when the goods arrive but before anyone
|
||||
suspects anything.
|
||||
|
||||
Businesses have trade secrets, patent applications in preparation,
|
||||
pricing information, subcontractor information, client data, personnel
|
||||
data, financial information, etc. Currently, anyone with access to
|
||||
the network (any machine on the network) can listen to anything that
|
||||
goes in the network, without any regard to normal access restrictions.
|
||||
|
||||
Many companies are not aware that information can so easily be
|
||||
recovered from the network. They trust that their data is safe
|
||||
since nobody is supposed to know that there is sensitive information
|
||||
in the network, or because so much other data is transferred in the
|
||||
network. This is not a safe policy.
|
||||
|
||||
Individual persons also have confidential information, such as
|
||||
diaries, love letters, health care documents, information about their
|
||||
personal interests and habits, professional data, job applications,
|
||||
tax reports, political documents, unpublished manuscripts, etc.
|
||||
|
||||
One should also be aware that economical intelligence and industrial
|
||||
espionage has recently become a major priority of the intelligence
|
||||
agencies of major governments. President Clinton recently assigned
|
||||
economical espionage as the primary task of the CIA, and the French
|
||||
have repeatedly been publicly boasting about their achievements on
|
||||
this field.
|
||||
|
||||
|
||||
There is also another frightening aspect about the poor security of
|
||||
communications. Computer storage and analysis capability has
|
||||
increased so much that it is feasible for governments, major
|
||||
companies, and criminal organizations to automatically analyze,
|
||||
identify, classify, and file information about millions of people over
|
||||
the years. Because most of the work can be automated, the cost of
|
||||
collecting this information is getting very low.
|
||||
|
||||
Government agencies may be able to monitor major communication
|
||||
systems, telephones, fax, computer networks, etc., and passively
|
||||
collect huge amounts of information about all people with any
|
||||
significant position in the society. Most of this information is not
|
||||
sensitive, and many people would say there is no harm in someone
|
||||
getting that information. However, the information starts to get
|
||||
sensitive when someone has enough of it. You may not mind someone
|
||||
knowing what you bought from the shop one random day, but you might
|
||||
not like someone knowing every small thing you have bought in the last
|
||||
ten years.
|
||||
|
||||
If the government some day starts to move into a more totalitarian
|
||||
direction (one should remember that Nazi Germany was created by
|
||||
democratic elections), there is considerable danger of an ultimate
|
||||
totalitarian state. With enough information (the automatically
|
||||
collected records of an individual can be manually analyzed when the
|
||||
person becomes interesting), one can form a very detailed picture of
|
||||
the individual's interests, opinions, beliefs, habits, friends,
|
||||
lovers, weaknesses, etc. This information can be used to 1) locate
|
||||
any persons who might oppose the new system 2) use deception to
|
||||
disturb any organizations which might rise against the government 3)
|
||||
eliminate difficult individuals without anyone understanding what
|
||||
happened. Additionally, if the government can monitor communications
|
||||
too effectively, it becomes too easy to locate and eliminate any
|
||||
persons distributing information contrary to the official truth.
|
||||
|
||||
Fighting crime and terrorism are often used as grounds for domestic
|
||||
surveillance and restricting encryption. These are good goals, but
|
||||
there is considerable danger that the surveillance data starts to get
|
||||
used for questionable purposes. I find that it is better to tolerate
|
||||
a small amount of crime in the society than to let the society become
|
||||
fully controlled. I am in favor of a fairly strong state, but the
|
||||
state must never get so strong that people become unable to spread
|
||||
contra-offical information and unable to overturn the government if it
|
||||
is bad. The danger is that when you notice that the government is
|
||||
too powerful, it is too late. Also, the real power may not be where
|
||||
the official government is.
|
||||
|
||||
For these reasons (privacy, protecting trade secrets, and making it
|
||||
more difficult to create a totalitarian state), I think that strong
|
||||
cryptography should be integrated to the tools we use every day.
|
||||
Using it causes no harm (except for those who wish to monitor
|
||||
everything), but not using it can cause huge problems. If the society
|
||||
changes in undesirable ways, then it will be to late to start
|
||||
encrypting.
|
||||
|
||||
Encryption has had a "military" or "classified" flavor to it. There
|
||||
are no longer any grounds for this. The military can and will use its
|
||||
own encryption; that is no excuse to prevent the civilians from
|
||||
protecting their privacy and secrets. Information on strong
|
||||
encryption is available in every major bookstore, scientific library,
|
||||
and patent office around the world, and strong encryption software is
|
||||
available in every country on the Internet.
|
||||
|
||||
Some people would like to make it illegal to use encryption, or to
|
||||
force people to use encryption that governments can break. This
|
||||
approach offers no protection if the government turns bad. Also, the
|
||||
"bad guys" will be using true strong encryption anyway. Good
|
||||
encryption techniques are too widely known to make them disappear.
|
||||
Thus, any "key escrow encryption" or other restrictions will only help
|
||||
monitor ordinary people and petty criminals. It does not help against
|
||||
powerful criminals, terrorists, or espionage, because they will know
|
||||
how to use strong encryption anyway. (One source for internationally
|
||||
available encryption software is http://www.cs.hut.fi/crypto.)
|
||||
|
||||
|
||||
OVERVIEW OF SECURE SHELL
|
||||
|
||||
The software consists of a number of programs.
|
||||
|
||||
sshd Server program run on the server machine. This
|
||||
listens for connections from client machines, and
|
||||
whenever it receives a connection, it performs
|
||||
authentication and starts serving the client.
|
||||
|
||||
ssh This is the client program used to log into another
|
||||
machine or to execute commands on the other machine.
|
||||
"slogin" is another name for this program.
|
||||
|
||||
scp Securely copies files from one machine to another.
|
||||
|
||||
ssh-keygen Used to create RSA keys (host keys and user
|
||||
authentication keys).
|
||||
|
||||
ssh-agent Authentication agent. This can be used to hold RSA
|
||||
keys for authentication.
|
||||
|
||||
ssh-add Used to register new keys with the agent.
|
||||
|
||||
make-ssh-known-hosts
|
||||
Used to create the /etc/ssh_known_hosts file.
|
||||
|
||||
|
||||
Ssh is the program users normally use. It is started as
|
||||
|
||||
ssh host
|
||||
|
||||
or
|
||||
|
||||
ssh host command
|
||||
|
||||
The first form opens a new shell on the remote machine (after
|
||||
authentication). The latter form executes the command on the remote
|
||||
machine.
|
||||
|
||||
When started, the ssh connects sshd on the server machine, verifies
|
||||
that the server machine really is the machine it wanted to connect,
|
||||
exchanges encryption keys (in a manner which prevents an outside
|
||||
listener from getting the keys), performs authentication using .rhosts
|
||||
and /etc/hosts.equiv, RSA authentication, or conventional password
|
||||
based authentication. The server then (normally) allocates a
|
||||
pseudo-terminal and starts an interactive shell or user program.
|
||||
|
||||
The TERM environment variable (describing the type of the user's
|
||||
terminal) is passed from the client side to the remote side. Also,
|
||||
terminal modes will be copied from the client side to the remote side
|
||||
to preserve user preferences (e.g., the erase character).
|
||||
|
||||
If the DISPLAY variable is set on the client side, the server will
|
||||
create a dummy X server and set DISPLAY accordingly. Any connections
|
||||
to the dummy X server will be forwarded through the secure channel,
|
||||
and will be made to the real X server from the client side. An
|
||||
arbitrary number of X programs can be started during the session, and
|
||||
starting them does not require anything special from the user. (Note
|
||||
that the user must not manually set DISPLAY, because then it would
|
||||
connect directly to the real display instead of going through the
|
||||
encrypted channel). This behavior can be disabled in the
|
||||
configuration file or by giving the -x option to the client.
|
||||
|
||||
Arbitrary IP ports can be forwarded over the secure channel. The
|
||||
program then creates a port on one side, and whenever a connection is
|
||||
opened to this port, it will be passed over the secure channel, and a
|
||||
connection will be made from the other side to a specified host:port
|
||||
pair. Arbitrary IP forwarding must always be explicitly requested,
|
||||
and cannot be used to forward privileged ports (unless the user is
|
||||
root). It is possible to specify automatic forwards in a per-user
|
||||
configuration file, for example to make electronic cash systems work
|
||||
securely.
|
||||
|
||||
If there is an authentication agent on the client side, connection to
|
||||
it will be automatically forwarded to the server side.
|
||||
|
||||
For more infomation, see the manual pages ssh(1), sshd(8), scp(1),
|
||||
ssh-keygen(1), ssh-agent(1), ssh-add(1), and make-ssh-known-hosts(1)
|
||||
included in this distribution.
|
||||
|
||||
|
||||
X11 CONNECTION FORWARDING
|
||||
|
||||
X11 forwarding serves two purposes: it is a convenience to the user
|
||||
because there is no need to set the DISPLAY variable, and it provides
|
||||
encrypted X11 connections. I cannot think of any other easy way to
|
||||
make X11 connections encrypted; modifying the X server, clients or
|
||||
libraries would require special work for each machine, vendor and
|
||||
application. Widely used IP-level encryption does not seem likely for
|
||||
several years. Thus what we have left is faking an X server on the
|
||||
same machine where the clients are run, and forwarding the connections
|
||||
to a real X server over the secure channel.
|
||||
|
||||
X11 forwarding works as follows. The client extracts Xauthority
|
||||
information for the server. It then creates random authorization
|
||||
data, and sends the random data to the server. The server allocates
|
||||
an X11 display number, and stores the (fake) Xauthority data for this
|
||||
display. Whenever an X11 connection is opened, the server forwards
|
||||
the connection over the secure channel to the client, and the client
|
||||
parses the first packet of the X11 protocol, substitutes real
|
||||
authentication data for the fake data (if the fake data matched), and
|
||||
forwards the connection to the real X server.
|
||||
|
||||
If the display does not have Xauthority data, the server will create a
|
||||
unix domain socket in /tmp/.X11-unix, and use the unix domain socket
|
||||
as the display. No authentication information is forwarded in this
|
||||
case. X11 connections are again forwarded over the secure channel.
|
||||
To the X server the connections appear to come from the client
|
||||
machine, and the server must have connections allowed from the local
|
||||
machine. Using authentication data is always recommended because not
|
||||
using it makes the display insecure. If XDM is used, it automatically
|
||||
generates the authentication data.
|
||||
|
||||
One should be careful not to use "xin" or "xstart" or other similar
|
||||
scripts that explicitly set DISPLAY to start X sessions in a remote
|
||||
machine, because the connection will then not go over the secure
|
||||
channel. The recommended way to start a shell in a remote machine is
|
||||
|
||||
xterm -e ssh host &
|
||||
|
||||
and the recommended way to execute an X11 application in a remote
|
||||
machine is
|
||||
|
||||
ssh -n host emacs &
|
||||
|
||||
If you need to type a password/passphrase for the remote machine,
|
||||
|
||||
ssh -f host emacs
|
||||
|
||||
may be useful.
|
||||
|
||||
|
||||
|
||||
RSA AUTHENTICATION
|
||||
|
||||
RSA authentication is based on public key cryptograpy. The idea is
|
||||
that there are two encryption keys, one for encryption and another for
|
||||
decryption. It is not possible (on human timescale) to derive the
|
||||
decryption key from the encryption key. The encryption key is called
|
||||
the public key, because it can be given to anyone and it is not
|
||||
secret. The decryption key, on the other hand, is secret, and is
|
||||
called the private key.
|
||||
|
||||
RSA authentication is based on the impossibility of deriving the
|
||||
private key from the public key. The public key is stored on the
|
||||
server machine in the user's $HOME/.ssh/authorized_keys file. The
|
||||
private key is only kept on the user's local machine, laptop, or other
|
||||
secure storage. Then the user tries to log in, the client tells the
|
||||
server the public key that the user wishes to use for authentication.
|
||||
The server then checks if this public key is admissible. If so, it
|
||||
generates a 256 bit random number, encrypts it with the public key,
|
||||
and sends the value to the client. The client then decrypts the
|
||||
number with its private key, computes a 128 bit MD5 checksum from the
|
||||
resulting data, and sends the checksum back to the server. (Only a
|
||||
checksum is sent to prevent chosen-plaintext attacks against RSA.)
|
||||
The server checks computes a checksum from the correct data,
|
||||
and compares the checksums. Authentication is accepted if the
|
||||
checksums match. (Theoretically this indicates that the client
|
||||
only probably knows the correct key, but for all practical purposes
|
||||
there is no doubt.)
|
||||
|
||||
The RSA private key can be protected with a passphrase. The
|
||||
passphrase can be any string; it is hashed with MD5 to produce an
|
||||
encryption key for IDEA, which is used to encrypt the private part of
|
||||
the key file. With passphrase, authorization requires access to the key
|
||||
file and the passphrase. Without passphrase, authorization only
|
||||
depends on possession of the key file.
|
||||
|
||||
RSA authentication is the most secure form of authentication supported
|
||||
by this software. It does not rely on the network, routers, domain
|
||||
name servers, or the client machine. The only thing that matters is
|
||||
access to the private key.
|
||||
|
||||
All this, of course, depends on the security of the RSA algorithm
|
||||
itself. RSA has been widely known since about 1978, and no effective
|
||||
methods for breaking it are known if it is used properly. Care has
|
||||
been taken to avoid the well-known pitfalls. Breaking RSA is widely
|
||||
believed to be equivalent to factoring, which is a very hard
|
||||
mathematical problem that has received considerable public research.
|
||||
So far, no effective methods are known for numbers bigger than about
|
||||
512 bits. However, as computer speeds and factoring methods are
|
||||
increasing, 512 bits can no longer be considered secure. The
|
||||
factoring work is exponential, and 768 or 1024 bits are widely
|
||||
considered to be secure in the near future.
|
||||
|
||||
|
||||
RHOSTS AUTHENTICATION
|
||||
|
||||
Conventional .rhosts and hosts.equiv based authentication mechanisms
|
||||
are fundamentally insecure due to IP, DNS (domain name server) and
|
||||
routing spoofing attacks. Additionally this authentication method
|
||||
relies on the integrity of the client machine. These weaknesses is
|
||||
tolerable, and been known and exploited for a long time.
|
||||
|
||||
Ssh provides an improved version of these types of authentication,
|
||||
because they are very convenient for the user (and allow easy
|
||||
transition from rsh and rlogin). It permits these types of
|
||||
authentication, but additionally requires that the client host be
|
||||
authenticated using RSA.
|
||||
|
||||
The server has a list of host keys stored in /etc/ssh_known_host, and
|
||||
additionally each user has host keys in $HOME/.ssh/known_hosts. Ssh
|
||||
uses the name servers to obtain the canonical name of the client host,
|
||||
looks for its public key in its known host files, and requires the
|
||||
client to prove that it knows the private host key. This prevents IP
|
||||
and routing spoofing attacks (as long as the client machine private
|
||||
host key has not been compromized), but is still vulnerable to DNS
|
||||
attacks (to a limited extent), and relies on the integrity of the
|
||||
client machine as to who is requesting to log in. This prevents
|
||||
outsiders from attacking, but does not protect against very powerful
|
||||
attackers. If maximal security is desired, only RSA authentication
|
||||
should be used.
|
||||
|
||||
It is possible to enable conventional .rhosts and /etc/hosts.equiv
|
||||
authentication (without host authentication) at compile time by giving
|
||||
the option --with-rhosts to configure. However, this is not
|
||||
recommended, and is not done by default.
|
||||
|
||||
These weaknesses are present in rsh and rlogin. No improvement in
|
||||
security will be obtained unless rlogin and rsh are completely
|
||||
disabled (commented out in /etc/inetd.conf). This is highly
|
||||
recommended.
|
||||
|
||||
|
||||
WEAKEST LINKS IN SECURITY
|
||||
|
||||
One should understand that while this software may provide
|
||||
cryptographically secure communications, it may be easy to
|
||||
monitor the communications at their endpoints.
|
||||
|
||||
Basically, anyone with root access on the local machine on which you
|
||||
are running the software may be able to do anything. Anyone with root
|
||||
access on the server machine may be able to monitor your
|
||||
communications, and a very talented root user might even be able to
|
||||
send his/her own requests to your authentication agent.
|
||||
|
||||
One should also be aware that computers send out electromagnetic
|
||||
radition that can sometimes be picked up hundreds of meters away.
|
||||
Your keyboard is particularly easy to listen to. The image on your
|
||||
monitor might also be seen on another monitor in a van parked behind
|
||||
your house.
|
||||
|
||||
Beware that unwanted visitors might come to your home or office and
|
||||
use your machine while you are away. They might also make
|
||||
modifications or install bugs in your hardware or software.
|
||||
|
||||
Beware that the most effective way for someone to decrypt your data
|
||||
may be with a rubber hose.
|
||||
|
||||
|
||||
LEGAL ISSUES
|
||||
|
||||
As far as I am concerned, anyone is permitted to use this software
|
||||
freely. However, see the file COPYING for detailed copying,
|
||||
licensing, and distribution information.
|
||||
|
||||
In some countries, particularly France, Russia, Iraq, and Pakistan,
|
||||
it may be illegal to use any encryption at all without a special
|
||||
permit, and the rumor has it that you cannot get a permit for any
|
||||
strong encryption.
|
||||
|
||||
This software may be freely imported into the United States; however,
|
||||
the United States Government may consider re-exporting it a criminal
|
||||
offence.
|
||||
|
||||
Note that any information and cryptographic algorithms used in this
|
||||
software are publicly available on the Internet and at any major
|
||||
bookstore, scientific library, or patent office worldwide.
|
||||
|
||||
THERE IS NO WARRANTY FOR THIS PROGRAM. Please consult the file
|
||||
COPYING for more information.
|
||||
|
||||
|
||||
MAILING LISTS AND OTHER INFORMATION
|
||||
|
||||
There is a mailing list for ossh. It is ossh@sics.se. If you would
|
||||
like to join, send a message to majordomo@sics.se with "subscribe
|
||||
ssh" in body.
|
||||
|
||||
The WWW home page for ssh is http://www.cs.hut.fi/ssh. It contains an
|
||||
archive of the mailing list, and detailed information about new
|
||||
releases, mailing lists, and other relevant issues.
|
||||
|
||||
Bug reports should be sent to ossh-bugs@sics.se.
|
||||
|
||||
|
||||
ABOUT THE AUTHOR
|
||||
|
||||
This software was written by Tatu Ylonen <ylo@cs.hut.fi>. I work as a
|
||||
researcher at Helsinki University of Technology, Finland. For more
|
||||
information, see http://www.cs.hut.fi/~ylo/. My PGP public key is
|
||||
available via finger from ylo@cs.hut.fi and from the key servers. I
|
||||
prefer PGP encrypted mail.
|
||||
|
||||
The author can be contacted via ordinary mail at
|
||||
Tatu Ylonen
|
||||
Helsinki University of Technology
|
||||
Otakaari 1
|
||||
FIN-02150 ESPOO
|
||||
Finland
|
||||
|
||||
Fax. +358-0-4513293
|
||||
|
||||
|
||||
ACKNOWLEDGEMENTS
|
||||
|
||||
I thank Tero Kivinen, Timo Rinne, Janne Snabb, and Heikki Suonsivu for
|
||||
their help and comments in the design, implementation and porting of
|
||||
this software. I also thank numerous contributors, including but not
|
||||
limited to Walker Aumann, Jurgen Botz, Hans-Werner Braun, Stephane
|
||||
Bortzmeyer, Adrian Colley, Michael Cooper, David Dombek, Jerome
|
||||
Etienne, Bill Fithen, Mark Fullmer, Bert Gijsbers, Andreas Gustafsson,
|
||||
Michael Henits, Steve Johnson, Thomas Koenig, Felix Leitner, Gunnar
|
||||
Lindberg, Andrew Macpherson, Marc Martinec, Paul Mauvais, Donald
|
||||
McKillican, Leon Mlakar, Robert Muchsel, Mark Treacy, Bryan
|
||||
O'Sullivan, Mikael Suokas, Ollivier Robert, Jakob Schlyter, Tomasz
|
||||
Surmacz, Alvar Vinacua, Petri Virkkula, Michael Warfield, and
|
||||
Cristophe Wolfhugel.
|
||||
|
||||
Thanks also go to Philip Zimmermann, whose PGP software and the
|
||||
associated legal battle provided inspiration, motivation, and many
|
||||
useful techniques, and to Bruce Schneier whose book Applied
|
||||
Cryptography has done a great service in widely distributing knowledge
|
||||
about cryptographic methods.
|
||||
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen, Espoo, Finland.
|
1780
crypto/dist/ssh/RFC.nroff
vendored
Normal file
1780
crypto/dist/ssh/RFC.nroff
vendored
Normal file
File diff suppressed because it is too large
Load Diff
78
crypto/dist/ssh/atomicio.c
vendored
Normal file
78
crypto/dist/ssh/atomicio.c
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/* $NetBSD: atomicio.c,v 1.1.1.1 2000/09/28 22:09:38 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995,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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: atomicio.c,v 1.5 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: atomicio.c,v 1.1.1.1 2000/09/28 22:09:38 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
|
||||
ssize_t
|
||||
atomic_read(int fd, void *v, size_t n)
|
||||
{
|
||||
char *s = v;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (res);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
atomic_write(int fd, const void *v, size_t n)
|
||||
{
|
||||
const char *s = v;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = write(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (res);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
}
|
379
crypto/dist/ssh/auth-krb4.c
vendored
Normal file
379
crypto/dist/ssh/auth-krb4.c
vendored
Normal file
@ -0,0 +1,379 @@
|
||||
/* $NetBSD: auth-krb4.c,v 1.1.1.1 2000/09/28 22:09:38 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Dug Song. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from: OpenBSD: auth-krb4.c,v 1.18 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-krb4.c,v 1.1.1.1 2000/09/28 22:09:38 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#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. Disallow login.
|
||||
*/
|
||||
log("Kerberos V4 TGT for %s unverifiable, "
|
||||
"no srvtab installed? krb_rd_req: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
} 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) {
|
||||
/*
|
||||
* Disallow login if no rcmd service exists, and
|
||||
* 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);
|
||||
goto kerberos_auth_failure;
|
||||
} else {
|
||||
/*
|
||||
* TGT is bad, forget it. Possibly spoofed!
|
||||
*/
|
||||
packet_send_debug("WARNING: Kerberos V4 TGT "
|
||||
"possibly spoofed for %s: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
const char *tkt_root = TKT_ROOT;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
if (!ticket) {
|
||||
/* Set unique ticket string manually since we're still root. */
|
||||
ticket = xmalloc(MAXPATHLEN);
|
||||
#ifdef AFS
|
||||
if (lstat("/ticket", &st) != -1)
|
||||
tkt_root = "/ticket/";
|
||||
#endif /* AFS */
|
||||
snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
|
||||
(void) krb_set_tkt_string(ticket);
|
||||
}
|
||||
/* Register ticket cleanup in case of fatal error. */
|
||||
if (!cleanup_registered) {
|
||||
fatal_add_cleanup(krb4_cleanup_proc, NULL);
|
||||
cleanup_registered = 1;
|
||||
}
|
||||
/* Try to create our ticket file. */
|
||||
if ((fd = mkstemp(ticket)) != -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
/* Ticket file exists - make sure user owns it (just passed ticket). */
|
||||
if (lstat(ticket, &st) != -1) {
|
||||
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
|
||||
st.st_uid == uid)
|
||||
return 1;
|
||||
}
|
||||
/* Failure - cancel cleanup function, leaving bad ticket for inspection. */
|
||||
log("WARNING: bad ticket file %s", ticket);
|
||||
fatal_remove_cleanup(krb4_cleanup_proc, NULL);
|
||||
cleanup_registered = 0;
|
||||
xfree(ticket);
|
||||
ticket = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
auth_krb4(const char *server_user, KTEXT auth, char **client)
|
||||
{
|
||||
AUTH_DAT adat = {0};
|
||||
KTEXT_ST reply;
|
||||
char instance[INST_SZ];
|
||||
int r, s;
|
||||
socklen_t slen;
|
||||
u_int cksum;
|
||||
Key_schedule schedule;
|
||||
struct sockaddr_in local, foreign;
|
||||
|
||||
s = packet_get_connection_in();
|
||||
|
||||
slen = sizeof(local);
|
||||
memset(&local, 0, sizeof(local));
|
||||
if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
|
||||
debug("getsockname failed: %.100s", strerror(errno));
|
||||
slen = sizeof(foreign);
|
||||
memset(&foreign, 0, sizeof(foreign));
|
||||
if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 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 */
|
233
crypto/dist/ssh/auth-options.c
vendored
Normal file
233
crypto/dist/ssh/auth-options.c
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
/* $NetBSD: auth-options.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* RSA-based authentication. This code determines whether to admit a login
|
||||
* based on RSA authentication. This file also contains functions to check
|
||||
* validity of the host key.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-options.c,v 1.4 2000/09/07 21:13:36 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-options.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "pathnames.h"
|
||||
#include "xmalloc.h"
|
||||
#include "match.h"
|
||||
#include "auth-options.h"
|
||||
|
||||
/* Flags set authorized_keys flags */
|
||||
int no_port_forwarding_flag = 0;
|
||||
int no_agent_forwarding_flag = 0;
|
||||
int no_x11_forwarding_flag = 0;
|
||||
int no_pty_flag = 0;
|
||||
|
||||
/* "command=" option. */
|
||||
char *forced_command = NULL;
|
||||
|
||||
/* "environment=" options. */
|
||||
struct envstring *custom_environment = NULL;
|
||||
|
||||
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
|
||||
int
|
||||
auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
||||
{
|
||||
const char *cp;
|
||||
if (!options)
|
||||
return 1;
|
||||
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",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
_PATH_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",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
_PATH_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) {
|
||||
int mname, mip;
|
||||
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",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
patterns[i] = 0;
|
||||
options++;
|
||||
/*
|
||||
* Deny access if we get a negative
|
||||
* match for the hostname or the ip
|
||||
* or if we get not match at all
|
||||
*/
|
||||
mname = match_hostname(get_canonical_hostname(),
|
||||
patterns, strlen(patterns));
|
||||
mip = match_hostname(get_remote_ipaddr(),
|
||||
patterns, strlen(patterns));
|
||||
xfree(patterns);
|
||||
if (mname == -1 || mip == -1 ||
|
||||
(mname != 1 && mip != 1)) {
|
||||
log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
|
||||
pw->pw_name, get_canonical_hostname(),
|
||||
get_remote_ipaddr());
|
||||
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
|
||||
get_canonical_hostname());
|
||||
/* key invalid for this host, reset flags */
|
||||
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;
|
||||
}
|
||||
/* deny access */
|
||||
return 0;
|
||||
}
|
||||
/* Host name matches. */
|
||||
goto next_option;
|
||||
}
|
||||
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-options.c option processing.");
|
||||
if (*options == ' ' || *options == '\t')
|
||||
break; /* End of options. */
|
||||
if (*options != ',')
|
||||
goto bad_option;
|
||||
options++;
|
||||
/* Process the next option. */
|
||||
}
|
||||
/* grant access */
|
||||
return 1;
|
||||
|
||||
bad_option:
|
||||
log("Bad options in %.100s file, line %lu: %.50s",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
/* deny access */
|
||||
return 0;
|
||||
}
|
28
crypto/dist/ssh/auth-options.h
vendored
Normal file
28
crypto/dist/ssh/auth-options.h
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/* $NetBSD: auth-options.h,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef AUTH_OPTIONS_H
|
||||
#define AUTH_OPTIONS_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;
|
||||
|
||||
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
|
||||
int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum);
|
||||
#endif
|
136
crypto/dist/ssh/auth-passwd.c
vendored
Normal file
136
crypto/dist/ssh/auth-passwd.c
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
/* $NetBSD: auth-passwd.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Password authentication. This file contains the functions to check whether
|
||||
* the password is valid for the user.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1999 Dug Song. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-passwd.c,v 1.17 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-passwd.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (options.kerberos_authentication) {
|
||||
#ifdef KRBB4
|
||||
case 4:
|
||||
ret = auth_krb4_password(pw, password);
|
||||
break;
|
||||
#endif
|
||||
#ifdef KRB5
|
||||
case 5:
|
||||
ret = auth_krb5_password(pw, password);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 1 || ret == 0)
|
||||
return ret;
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
#endif /* KRB4 || KRB5 */
|
||||
|
||||
/* 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);
|
||||
}
|
122
crypto/dist/ssh/auth-rh-rsa.c
vendored
Normal file
122
crypto/dist/ssh/auth-rh-rsa.c
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
/* $NetBSD: auth-rh-rsa.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Rhosts or /etc/hosts.equiv authentication combined with RSA host
|
||||
* authentication.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-rh-rsa.c,v 1.16 2000/09/07 21:13:36 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-rh-rsa.c,v 1.1.1.1 2000/09/28 22:09:39 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "packet.h"
|
||||
#include "pathnames.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "uidswap.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.h"
|
||||
#include "hostfile.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, RSA *client_host_key)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
const char *canonical_hostname;
|
||||
HostStatus host_status;
|
||||
Key *client_key, *found;
|
||||
|
||||
debug("Trying rhosts with RSA host authentication for %.100s", client_user);
|
||||
|
||||
if (client_host_key == NULL)
|
||||
return 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* wrap the RSA key into a 'generic' key */
|
||||
client_key = key_new(KEY_RSA);
|
||||
BN_copy(client_key->rsa->e, client_host_key->e);
|
||||
BN_copy(client_key->rsa->n, client_host_key->n);
|
||||
found = key_new(KEY_RSA);
|
||||
|
||||
/* Check if we know the host and its host key. */
|
||||
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_key, found);
|
||||
|
||||
/* Check user host file unless ignored. */
|
||||
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
|
||||
struct stat st;
|
||||
char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
|
||||
/*
|
||||
* Check file permissions of _PATH_SSH_USER_HOSTFILE, auth_rsa()
|
||||
* did already check pw->pw_dir, but there is a race XXX
|
||||
*/
|
||||
if (options.strict_modes &&
|
||||
(stat(user_hostfile, &st) == 0) &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
|
||||
pw->pw_name, user_hostfile);
|
||||
} else {
|
||||
/* XXX race between stat and the following open() */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
|
||||
client_key, found);
|
||||
restore_uid();
|
||||
}
|
||||
xfree(user_hostfile);
|
||||
}
|
||||
key_free(client_key);
|
||||
key_free(found);
|
||||
|
||||
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)) {
|
||||
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;
|
||||
}
|
273
crypto/dist/ssh/auth-rhosts.c
vendored
Normal file
273
crypto/dist/ssh/auth-rhosts.c
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
/* $NetBSD: auth-rhosts.c,v 1.1.1.1 2000/09/28 22:09:40 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Rhosts authentication. This file contains code to check whether to admit
|
||||
* the login based on rhosts authentication. This file also processes
|
||||
* /etc/hosts.equiv.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-rhosts.c,v 1.15 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-rhosts.c,v 1.1.1.1 2000/09/28 22:09:40 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "packet.h"
|
||||
#include "pathnames.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.
|
||||
*/
|
||||
|
||||
static 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(_PATH_HEQUIV, &st) < 0 &&
|
||||
stat(_PATH_SSH_HEQUIV, &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(_PATH_HEQUIV, hostname, ipaddr, client_user,
|
||||
pw->pw_name)) {
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by " _PATH_HEQUIV ".",
|
||||
hostname, ipaddr);
|
||||
return 1;
|
||||
}
|
||||
if (check_rhosts_file(_PATH_SSH_HEQUIV, hostname, ipaddr, client_user,
|
||||
pw->pw_name)) {
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
|
||||
hostname, ipaddr, _PATH_SSH_HEQUIV);
|
||||
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;
|
||||
}
|
292
crypto/dist/ssh/auth-rsa.c
vendored
Normal file
292
crypto/dist/ssh/auth-rsa.c
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
/* $NetBSD: auth-rsa.c,v 1.1.1.1 2000/09/28 22:09:40 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* RSA-based authentication. This code determines whether to admit a login
|
||||
* based on RSA authentication. This file also contains functions to check
|
||||
* validity of the host key.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-rsa.c,v 1.1.1.1 2000/09/28 22:09:40 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "rsa.h"
|
||||
#include "packet.h"
|
||||
#include "pathnames.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "mpaux.h"
|
||||
#include "uidswap.h"
|
||||
#include "match.h"
|
||||
#include "servconf.h"
|
||||
#include "auth-options.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/*
|
||||
* 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(RSA *pk)
|
||||
{
|
||||
BIGNUM *challenge, *encrypted_challenge;
|
||||
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, pk->n, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
/* Encrypt the challenge with the public key. */
|
||||
rsa_public_encrypt(encrypted_challenge, challenge, 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;
|
||||
RSA *pk;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
_PATH_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 _PATH_SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", _PATH_SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; i++) {
|
||||
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
|
||||
if (stat(line, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.", pw->pw_name, line);
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
fclose(f);
|
||||
log("%s",buf);
|
||||
packet_send_debug("%s",buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Flag indicating whether authentication has succeeded. */
|
||||
authenticated = 0;
|
||||
|
||||
pk = RSA_new();
|
||||
pk->e = BN_new();
|
||||
pk->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, pk->e, pk->n)) {
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
_PATH_SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
_PATH_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(pk->n, client_n) != 0)
|
||||
continue;
|
||||
|
||||
/* check the real bits */
|
||||
if (bits != BN_num_bits(pk->n))
|
||||
log("Warning: %s, line %ld: keysize mismatch: "
|
||||
"actual %d vs. announced %d.",
|
||||
file, linenum, BN_num_bits(pk->n), bits);
|
||||
|
||||
/* We have found the desired key. */
|
||||
|
||||
/* Perform the challenge-response dialog for this key. */
|
||||
if (!auth_rsa_challenge_dialog(pk)) {
|
||||
/* 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.
|
||||
* Break out of the loop if authentication was successful;
|
||||
* otherwise continue searching.
|
||||
*/
|
||||
authenticated = auth_parse_options(pw, options, linenum);
|
||||
if (authenticated)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
|
||||
RSA_free(pk);
|
||||
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
}
|
214
crypto/dist/ssh/auth-skey.c
vendored
Normal file
214
crypto/dist/ssh/auth-skey.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* $NetBSD: auth-skey.c,v 1.1.1.1 2000/09/28 22:09:41 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth-skey.c,v 1.8 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth-skey.c,v 1.1.1.1 2000/09/28 22:09:41 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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) {
|
||||
const 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(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(const 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;
|
||||
const char *u;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
282
crypto/dist/ssh/auth.c
vendored
Normal file
282
crypto/dist/ssh/auth.c
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
/* $NetBSD: auth.c,v 1.1.1.1 2000/09/28 22:09:41 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth.c,v 1.1.1.1 2000/09/28 22:09:41 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "match.h"
|
||||
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
|
||||
#include <login_cap.h>
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
|
||||
/*
|
||||
* Check if the user is allowed to log in via ssh. If user is listed in
|
||||
* DenyUsers or user's primary group is listed in DenyGroups, false will
|
||||
* be returned. If AllowUsers isn't empty and user isn't listed there, or
|
||||
* if AllowGroups isn't empty and user isn't listed there, false will be
|
||||
* returned.
|
||||
* If the user's shell is not executable, false will be returned.
|
||||
* Otherwise true is returned.
|
||||
*/
|
||||
int
|
||||
allowed_user(struct passwd *pw)
|
||||
{
|
||||
struct stat st;
|
||||
struct group *grp;
|
||||
const char *shell;
|
||||
int i, match_name, match_ip;
|
||||
login_cap_t *lc;
|
||||
const char *hostname, *ipaddr;
|
||||
char *cap_hlist, *hp;
|
||||
|
||||
hostname = get_canonical_hostname();
|
||||
ipaddr = get_remote_ipaddr();
|
||||
|
||||
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
|
||||
if (pw == NULL)
|
||||
goto denied;
|
||||
|
||||
lc = login_getclass(pw->pw_class);
|
||||
|
||||
/*
|
||||
* Check the deny list.
|
||||
*/
|
||||
cap_hlist = login_getcapstr(lc, "host.deny", NULL, NULL);
|
||||
if (cap_hlist != NULL) {
|
||||
hp = strtok(cap_hlist, ",");
|
||||
while (hp != NULL) {
|
||||
match_name = match_hostname(hostname,
|
||||
hp, strlen(hp));
|
||||
match_ip = match_hostname(ipaddr,
|
||||
hp, strlen(hp));
|
||||
/*
|
||||
* Only a positive match here causes a "deny".
|
||||
*/
|
||||
if (match_name > 0 || match_ip > 0) {
|
||||
free(cap_hlist);
|
||||
login_close(lc);
|
||||
goto denied;
|
||||
}
|
||||
hp = strtok(NULL, ",");
|
||||
}
|
||||
free(cap_hlist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the allow list. If the allow list exists, and the
|
||||
* remote host is not in it, the user is implicitly denied.
|
||||
*/
|
||||
cap_hlist = login_getcapstr(lc, "host.allow", NULL, NULL);
|
||||
if (cap_hlist != NULL) {
|
||||
hp = strtok(cap_hlist, ",");
|
||||
if (hp == NULL) {
|
||||
/* Just in case there's an empty string... */
|
||||
free(cap_hlist);
|
||||
login_close(lc);
|
||||
goto denied;
|
||||
}
|
||||
while (hp != NULL) {
|
||||
match_name = match_hostname(hostname,
|
||||
hp, strlen(hp));
|
||||
match_ip = match_hostname(ipaddr,
|
||||
hp, strlen(hp));
|
||||
/*
|
||||
* Negative match causes an immediate "deny".
|
||||
* Positive match causes us to break out
|
||||
* of the loop (allowing a fallthrough).
|
||||
*/
|
||||
if (match_name < 0 || match_ip < 0) {
|
||||
free(cap_hlist);
|
||||
login_close(lc);
|
||||
goto denied;
|
||||
}
|
||||
if (match_name > 0 || match_ip > 0)
|
||||
break;
|
||||
}
|
||||
free(cap_hlist);
|
||||
if (hp == NULL) {
|
||||
login_close(lc);
|
||||
goto denied;
|
||||
}
|
||||
}
|
||||
|
||||
login_close(lc);
|
||||
|
||||
/*
|
||||
* Get the shell from the password data. An empty shell field is
|
||||
* legal, and means /bin/sh.
|
||||
*/
|
||||
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
|
||||
|
||||
/*
|
||||
* Deny if shell does not exists or is not executable.
|
||||
* XXX Should check to see if it is executable by the
|
||||
* XXX requesting user. --thorpej
|
||||
*/
|
||||
if (stat(shell, &st) != 0)
|
||||
goto denied;
|
||||
if (S_ISREG(st.st_mode) == 0 ||
|
||||
(st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0)
|
||||
goto denied;
|
||||
|
||||
/*
|
||||
* XXX Consider nuking {Allow,Deny}{Users,Groups}. We have the
|
||||
* XXX login_cap(3) mechanism which covers all other types of
|
||||
* XXX logins, too.
|
||||
*/
|
||||
|
||||
/* Return false if user is listed in DenyUsers */
|
||||
if (options.num_deny_users > 0) {
|
||||
if (pw->pw_name == NULL)
|
||||
goto denied;
|
||||
for (i = 0; i < options.num_deny_users; i++)
|
||||
if (match_pattern(pw->pw_name, options.deny_users[i]))
|
||||
goto denied;
|
||||
}
|
||||
/* Return false if AllowUsers isn't empty and user isn't listed there */
|
||||
if (options.num_allow_users > 0) {
|
||||
if (pw->pw_name == NULL)
|
||||
goto denied;
|
||||
for (i = 0; i < options.num_allow_users; i++)
|
||||
if (match_pattern(pw->pw_name, options.allow_users[i]))
|
||||
break;
|
||||
/* i < options.num_allow_users iff we break for loop */
|
||||
if (i >= options.num_allow_users)
|
||||
goto denied;
|
||||
}
|
||||
/* Get the primary group name if we need it. Return false if it fails */
|
||||
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
|
||||
grp = getgrgid(pw->pw_gid);
|
||||
if (grp == NULL)
|
||||
goto denied;
|
||||
|
||||
/* Return false if user's group is listed in DenyGroups */
|
||||
if (options.num_deny_groups > 0) {
|
||||
if (grp->gr_name == NULL)
|
||||
goto denied;
|
||||
for (i = 0; i < options.num_deny_groups; i++)
|
||||
if (match_pattern(grp->gr_name,
|
||||
options.deny_groups[i]))
|
||||
goto denied;
|
||||
}
|
||||
/*
|
||||
* Return false if AllowGroups isn't empty and user's group
|
||||
* isn't listed there
|
||||
*/
|
||||
if (options.num_allow_groups > 0) {
|
||||
if (grp->gr_name == NULL)
|
||||
goto denied;
|
||||
for (i = 0; i < options.num_allow_groups; i++)
|
||||
if (match_pattern(grp->gr_name,
|
||||
options.allow_groups[i]))
|
||||
break;
|
||||
/* i < options.num_allow_groups iff we break for
|
||||
loop */
|
||||
if (i >= options.num_allow_groups)
|
||||
goto denied;
|
||||
}
|
||||
}
|
||||
|
||||
/* We found no reason not to let this user try to log on... */
|
||||
return 1;
|
||||
|
||||
denied:
|
||||
/* XXX Need to add notice() --thorpej */
|
||||
log("Denied connection for %.200s from %.200s [%.200s] port %d.\n",
|
||||
pw == NULL ? "<unknown>" : pw->pw_name, hostname, ipaddr,
|
||||
get_remote_port());
|
||||
return (0);
|
||||
}
|
43
crypto/dist/ssh/auth.h
vendored
Normal file
43
crypto/dist/ssh/auth.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/* $NetBSD: auth.h,v 1.1.1.1 2000/09/28 22:09:41 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
void do_authentication(void);
|
||||
void do_authentication2(void);
|
||||
|
||||
struct passwd *
|
||||
auth_get_user(void);
|
||||
|
||||
int allowed_user(struct passwd *);
|
||||
|
||||
#define AUTH_FAIL_MAX 6
|
||||
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
|
||||
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
|
||||
|
||||
#endif
|
||||
|
516
crypto/dist/ssh/auth1.c
vendored
Normal file
516
crypto/dist/ssh/auth1.c
vendored
Normal file
@ -0,0 +1,516 @@
|
||||
/* $NetBSD: auth1.c,v 1.1.1.1 2000/09/28 22:09:42 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth1.c,v 1.4 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth1.c,v 1.1.1.1 2000/09/28 22:09:42 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern char *forced_command;
|
||||
|
||||
/*
|
||||
* convert ssh auth msg type into description
|
||||
*/
|
||||
static char *
|
||||
get_authname(int type)
|
||||
{
|
||||
static char buf[1024];
|
||||
switch (type) {
|
||||
case SSH_CMSG_AUTH_PASSWORD:
|
||||
return "password";
|
||||
case SSH_CMSG_AUTH_RSA:
|
||||
return "rsa";
|
||||
case SSH_CMSG_AUTH_RHOSTS_RSA:
|
||||
return "rhosts-rsa";
|
||||
case SSH_CMSG_AUTH_RHOSTS:
|
||||
return "rhosts";
|
||||
#ifdef KRB4
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
return "kerberos";
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
return "s/key";
|
||||
#endif
|
||||
}
|
||||
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The user does not exist or access is denied,
|
||||
* but fake indication that authentication is needed.
|
||||
*/
|
||||
static void
|
||||
do_fake_authloop1(char *user)
|
||||
{
|
||||
int attempt = 0;
|
||||
|
||||
/* Indicate that authentication is needed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/*
|
||||
* Keep reading packets, and always respond with a failure. This is
|
||||
* to avoid disclosing whether such a user really exists.
|
||||
*/
|
||||
for (attempt = 1;; attempt++) {
|
||||
/* Read a packet. This will not return if the client disconnects. */
|
||||
int plen;
|
||||
int type = packet_read(&plen);
|
||||
#ifdef SKEY
|
||||
unsigned int dlen;
|
||||
char *password, *skeyinfo;
|
||||
password = NULL;
|
||||
/* Try to send a fake s/key challenge. */
|
||||
if (options.skey_authentication == 1 &&
|
||||
(skeyinfo = skey_fake_keyinfo(user)) != NULL) {
|
||||
if (type == SSH_CMSG_AUTH_TIS) {
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
} else if (type == SSH_CMSG_AUTH_PASSWORD &&
|
||||
options.password_authentication &&
|
||||
(password = packet_get_string(&dlen)) != NULL &&
|
||||
dlen == 5 &&
|
||||
strncasecmp(password, "s/key", 5) == 0 ) {
|
||||
packet_send_debug(skeyinfo);
|
||||
}
|
||||
}
|
||||
if (password != NULL)
|
||||
xfree(password);
|
||||
#endif
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, user);
|
||||
|
||||
/*
|
||||
* Send failure. This should be indistinguishable from a
|
||||
* failed authentication.
|
||||
*/
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* read packets and try to authenticate local user *pw.
|
||||
* return if authentication is successfull
|
||||
*/
|
||||
static void
|
||||
do_authloop(struct passwd * pw)
|
||||
{
|
||||
int attempt = 0;
|
||||
unsigned int bits;
|
||||
RSA *client_host_key;
|
||||
BIGNUM *n;
|
||||
char *client_user, *password;
|
||||
char user[1024];
|
||||
unsigned int dlen;
|
||||
int plen, nlen, elen;
|
||||
unsigned int ulen;
|
||||
int type = 0;
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
|
||||
/* Indicate that authentication is needed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
for (attempt = 1;; attempt++) {
|
||||
int authenticated = 0;
|
||||
strlcpy(user, "", sizeof user);
|
||||
|
||||
/* Get a packet from the client. */
|
||||
type = packet_read(&plen);
|
||||
|
||||
/* Process the packet. */
|
||||
switch (type) {
|
||||
#if defined(AFS) || defined(KRB5)
|
||||
case SSH_CMSG_HAVE_KERBEROS_TGT:
|
||||
if (!options.kerberos_tgt_passing) {
|
||||
/* packet_get_all(); */
|
||||
verbose("Kerberos TGT passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
/* Accept Kerberos tgt. */
|
||||
char *tgt = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
switch (options.kerberos_authentication) {
|
||||
#ifdef AFS
|
||||
case 4:
|
||||
ret = auth_krb4_tgt(pw, tgt);
|
||||
break;
|
||||
#endif
|
||||
#ifdef KRB5
|
||||
case 5:
|
||||
ret = auth_krb5_tgt(pw, tgt);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
verbose("Kerberos TGT REFUSED for %s",
|
||||
pw->pw_name);
|
||||
xfree(tgt);
|
||||
}
|
||||
continue;
|
||||
#endif /* AFS || KRB5 */
|
||||
#if defined(AFS)
|
||||
case SSH_CMSG_HAVE_AFS_TOKEN:
|
||||
if (!options.afs_token_passing || !k_hasafs()) {
|
||||
/* packet_get_all(); */
|
||||
verbose("AFS token passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
/* Accept AFS token. */
|
||||
char *token_string = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_afs_token(pw, token_string))
|
||||
verbose("AFS token REFUSED for %s", pw->pw_name);
|
||||
xfree(token_string);
|
||||
}
|
||||
continue;
|
||||
#endif /* AFS */
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
if (options.kerberos_authentication == 0) {
|
||||
/* packet_get_all(); */
|
||||
verbose("Kerberos authentication disabled.");
|
||||
break;
|
||||
}
|
||||
#if defined(KRB4)
|
||||
else if (options.kerberos_authentication == 4) {
|
||||
/* Try Kerberos v4 authentication. */
|
||||
KTEXT_ST auth;
|
||||
char *tkt_user = NULL;
|
||||
char *kdata = packet_get_string((unsigned int *) &auth.length);
|
||||
packet_integrity_check(plen, 4 + auth.length, type);
|
||||
|
||||
if (auth.length < MAX_KTXT_LEN)
|
||||
memcpy(auth.dat, kdata, auth.length);
|
||||
xfree(kdata);
|
||||
|
||||
authenticated = auth_krb4(pw->pw_name, &auth,
|
||||
&tkt_user);
|
||||
|
||||
if (authenticated) {
|
||||
snprintf(user, sizeof user,
|
||||
" tktuser %s", tkt_user);
|
||||
xfree(tkt_user);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(KRB5)
|
||||
else {
|
||||
verbose("Kerberos v5 not yet supported.");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif /* KRB4 || KRB5 */
|
||||
|
||||
case SSH_CMSG_AUTH_RHOSTS:
|
||||
if (!options.rhosts_authentication) {
|
||||
verbose("Rhosts authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Get client user name. Note that we just have to
|
||||
* trust the client; this is one reason why rhosts
|
||||
* authentication is insecure. (Another is
|
||||
* IP-spoofing on a local network.)
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, 4 + ulen, type);
|
||||
|
||||
/* Try to authenticate using /etc/hosts.equiv and
|
||||
.rhosts. */
|
||||
authenticated = auth_rhosts(pw, client_user);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
xfree(client_user);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_RHOSTS_RSA:
|
||||
if (!options.rhosts_rsa_authentication) {
|
||||
verbose("Rhosts with RSA authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Get client user name. Note that we just have to
|
||||
* trust the client; root on the client machine can
|
||||
* claim to be any user.
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
|
||||
/* Get the client host key. */
|
||||
client_host_key = RSA_new();
|
||||
if (client_host_key == NULL)
|
||||
fatal("RSA_new failed");
|
||||
client_host_key->e = BN_new();
|
||||
client_host_key->n = BN_new();
|
||||
if (client_host_key->e == NULL || client_host_key->n == NULL)
|
||||
fatal("BN_new failed");
|
||||
bits = packet_get_int();
|
||||
packet_get_bignum(client_host_key->e, &elen);
|
||||
packet_get_bignum(client_host_key->n, &nlen);
|
||||
|
||||
if (bits != BN_num_bits(client_host_key->n))
|
||||
log("Warning: keysize mismatch for client_host_key: "
|
||||
"actual %d, announced %d",
|
||||
BN_num_bits(client_host_key->n), bits);
|
||||
packet_integrity_check(plen,
|
||||
(4 + ulen) + 4 + elen + nlen, type);
|
||||
|
||||
authenticated = auth_rhosts_rsa(pw, client_user,
|
||||
client_host_key);
|
||||
RSA_free(client_host_key);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
xfree(client_user);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_RSA:
|
||||
if (!options.rsa_authentication) {
|
||||
verbose("RSA authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/* RSA authentication requested. */
|
||||
n = BN_new();
|
||||
packet_get_bignum(n, &nlen);
|
||||
packet_integrity_check(plen, nlen, type);
|
||||
authenticated = auth_rsa(pw, n);
|
||||
BN_clear_free(n);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_PASSWORD:
|
||||
if (!options.password_authentication) {
|
||||
verbose("Password authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Read user password. It is in plain text, but was
|
||||
* transmitted over the encrypted channel so it is
|
||||
* not visible to an outside observer.
|
||||
*/
|
||||
password = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
|
||||
/* Try authentication with the password. */
|
||||
authenticated = auth_password(pw, password);
|
||||
|
||||
memset(password, 0, strlen(password));
|
||||
xfree(password);
|
||||
break;
|
||||
|
||||
#ifdef SKEY
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS");
|
||||
if (options.skey_authentication == 1) {
|
||||
const char *skeyinfo =
|
||||
skey_keyinfo(pw->pw_name);
|
||||
if (skeyinfo != NULL) {
|
||||
/*
|
||||
* we send our s/key- in tis-challenge
|
||||
* messages
|
||||
*/
|
||||
debug("sending challenge '%s'",
|
||||
skeyinfo);
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo,
|
||||
strlen(skeyinfo));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
|
||||
if (options.skey_authentication == 1) {
|
||||
char *response = packet_get_string(&dlen);
|
||||
debug("skey response == '%s'", response);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
authenticated =
|
||||
(skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name,
|
||||
response) != -1);
|
||||
xfree(response);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
/* TIS Authentication is unsupported */
|
||||
log("TIS authentication unsupported.");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/*
|
||||
* Any unknown messages will be ignored (and failure
|
||||
* returned) during authentication.
|
||||
*/
|
||||
log("Unknown message during authentication: type %d",
|
||||
type);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the user is logging in as root and root logins
|
||||
* are disallowed.
|
||||
* Note that root login is allowed for forced commands.
|
||||
*/
|
||||
if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
if (forced_command) {
|
||||
log("Root login accepted for forced command.");
|
||||
} else {
|
||||
authenticated = 0;
|
||||
log("ROOT LOGIN REFUSED FROM %.200s",
|
||||
get_canonical_hostname());
|
||||
}
|
||||
}
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated ||
|
||||
attempt == AUTH_FAIL_LOG ||
|
||||
type == SSH_CMSG_AUTH_PASSWORD)
|
||||
authlog = log;
|
||||
|
||||
authlog("%s %s for %.200s from %.200s port %d%s",
|
||||
authenticated ? "Accepted" : "Failed",
|
||||
get_authname(type),
|
||||
pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port(),
|
||||
user);
|
||||
|
||||
if (authenticated)
|
||||
return;
|
||||
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
|
||||
|
||||
/* Send a message indicating that the authentication attempt failed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs authentication of an incoming connection. Session key has already
|
||||
* been exchanged and encryption is enabled.
|
||||
*/
|
||||
void
|
||||
do_authentication(void)
|
||||
{
|
||||
struct passwd *pw, pwcopy;
|
||||
int plen;
|
||||
unsigned int ulen;
|
||||
char *user;
|
||||
|
||||
/* Get the name of the user that we wish to log in as. */
|
||||
packet_read_expect(&plen, SSH_CMSG_USER);
|
||||
|
||||
/* Get the user name. */
|
||||
user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
|
||||
|
||||
setproctitle("%s", user);
|
||||
|
||||
#ifdef AFS
|
||||
/* If machine has AFS, set process authentication group. */
|
||||
if (k_hasafs()) {
|
||||
k_setpag();
|
||||
k_unlog();
|
||||
}
|
||||
#endif /* AFS */
|
||||
|
||||
/* Verify that the user is a valid user. */
|
||||
pw = getpwnam(user);
|
||||
if (!pw || !allowed_user(pw))
|
||||
do_fake_authloop1(user);
|
||||
xfree(user);
|
||||
|
||||
/* Take a copy of the returned structure. */
|
||||
memset(&pwcopy, 0, sizeof(pwcopy));
|
||||
pwcopy.pw_name = xstrdup(pw->pw_name);
|
||||
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
|
||||
pwcopy.pw_uid = pw->pw_uid;
|
||||
pwcopy.pw_gid = pw->pw_gid;
|
||||
pwcopy.pw_class = xstrdup(pw->pw_class);
|
||||
pwcopy.pw_dir = xstrdup(pw->pw_dir);
|
||||
pwcopy.pw_shell = xstrdup(pw->pw_shell);
|
||||
pw = &pwcopy;
|
||||
|
||||
/*
|
||||
* If we are not running as root, the user must have the same uid as
|
||||
* the server.
|
||||
*/
|
||||
if (getuid() != 0 && pw->pw_uid != getuid())
|
||||
packet_disconnect("Cannot change user when server not running as root.");
|
||||
|
||||
debug("Attempting authentication for %.100s.", pw->pw_name);
|
||||
|
||||
/* If the user has no password, accept authentication immediately. */
|
||||
if (options.password_authentication &&
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
(!options.kerberos_authentication ||
|
||||
options.kerberos_or_local_passwd) &&
|
||||
#endif /* KRB4 || KRB5 */
|
||||
auth_password(pw, "")) {
|
||||
/* Authentication with empty password succeeded. */
|
||||
log("Login for user %s from %.100s, accepted without authentication.",
|
||||
pw->pw_name, get_remote_ipaddr());
|
||||
} else {
|
||||
/* Loop until the user has been authenticated or the
|
||||
connection is closed, do_authloop() returns only if
|
||||
authentication is successfull */
|
||||
do_authloop(pw);
|
||||
}
|
||||
|
||||
/* The user has been authenticated and accepted. */
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Perform session preparation. */
|
||||
do_authenticated(pw);
|
||||
}
|
500
crypto/dist/ssh/auth2.c
vendored
Normal file
500
crypto/dist/ssh/auth2.c
vendored
Normal file
@ -0,0 +1,500 @@
|
||||
/* $NetBSD: auth2.c,v 1.1.1.1 2000/09/28 22:09:43 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: auth2.c,v 1.1.1.1 2000/09/28 22:09:43 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pathnames.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
#include "auth.h"
|
||||
#include "key.h"
|
||||
#include "kex.h"
|
||||
|
||||
#include "dsa.h"
|
||||
#include "uidswap.h"
|
||||
#include "auth-options.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern unsigned char *session_id2;
|
||||
extern int session_id2_len;
|
||||
|
||||
/* protocol */
|
||||
|
||||
void input_service_request(int type, int plen, void *ctxt);
|
||||
void input_userauth_request(int type, int plen, void *ctxt);
|
||||
void protocol_error(int type, int plen, void *ctxt);
|
||||
|
||||
/* auth */
|
||||
int ssh2_auth_none(struct passwd *pw);
|
||||
int ssh2_auth_password(struct passwd *pw);
|
||||
int ssh2_auth_pubkey(struct passwd *pw, char *service);
|
||||
|
||||
/* helper */
|
||||
struct passwd* auth_set_user(char *u, char *s);
|
||||
int user_dsa_key_allowed(struct passwd *pw, Key *key);
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
struct Authctxt {
|
||||
char *user;
|
||||
char *service;
|
||||
struct passwd pw;
|
||||
int valid;
|
||||
};
|
||||
static Authctxt *authctxt = NULL;
|
||||
static int userauth_success = 0;
|
||||
|
||||
/*
|
||||
* loop until userauth_success == TRUE
|
||||
*/
|
||||
|
||||
void
|
||||
do_authentication2(void)
|
||||
{
|
||||
|
||||
/* turn off skey/kerberos, not supported by SSH2 */
|
||||
#ifdef SKEY
|
||||
options.skey_authentication = 0;
|
||||
#endif
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
options.kerberos_authentication = 0;
|
||||
#endif
|
||||
|
||||
dispatch_init(&protocol_error);
|
||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
dispatch_run(DISPATCH_BLOCK, &userauth_success, NULL);
|
||||
do_authenticated2();
|
||||
}
|
||||
|
||||
void
|
||||
protocol_error(int type, int plen, void *ctxt)
|
||||
{
|
||||
log("auth: protocol error: type %d plen %d", type, plen);
|
||||
packet_start(SSH2_MSG_UNIMPLEMENTED);
|
||||
packet_put_int(0);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
void
|
||||
input_service_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
unsigned int len;
|
||||
int accept = 0;
|
||||
char *service = packet_get_string(&len);
|
||||
packet_done();
|
||||
|
||||
if (strcmp(service, "ssh-userauth") == 0) {
|
||||
if (!userauth_success) {
|
||||
accept = 1;
|
||||
/* now we can handle user-auth requests */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||
}
|
||||
}
|
||||
/* XXX all other service requests are denied */
|
||||
|
||||
if (accept) {
|
||||
packet_start(SSH2_MSG_SERVICE_ACCEPT);
|
||||
packet_put_cstring(service);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
} else {
|
||||
debug("bad service request %s", service);
|
||||
packet_disconnect("bad service request %s", service);
|
||||
}
|
||||
xfree(service);
|
||||
}
|
||||
|
||||
void
|
||||
input_userauth_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
static void (*authlog) (const char *fmt,...) = verbose;
|
||||
static int attempt = 0;
|
||||
unsigned int len;
|
||||
int authenticated = 0;
|
||||
char *user, *service, *method, *authmsg = NULL;
|
||||
struct passwd *pw;
|
||||
|
||||
if (++attempt == AUTH_FAIL_MAX)
|
||||
packet_disconnect("too many failed userauth_requests");
|
||||
|
||||
user = packet_get_string(&len);
|
||||
service = packet_get_string(&len);
|
||||
method = packet_get_string(&len);
|
||||
debug("userauth-request for user %s service %s method %s", user, service, method);
|
||||
|
||||
/* XXX we only allow the ssh-connection service */
|
||||
pw = auth_set_user(user, service);
|
||||
if (pw && strcmp(service, "ssh-connection")==0) {
|
||||
if (strcmp(method, "none") == 0) {
|
||||
authenticated = ssh2_auth_none(pw);
|
||||
} else if (strcmp(method, "password") == 0) {
|
||||
authenticated = ssh2_auth_password(pw);
|
||||
} else if (strcmp(method, "publickey") == 0) {
|
||||
authenticated = ssh2_auth_pubkey(pw, service);
|
||||
}
|
||||
}
|
||||
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
authenticated = 0;
|
||||
log("ROOT LOGIN REFUSED FROM %.200s",
|
||||
get_canonical_hostname());
|
||||
}
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated == 1 ||
|
||||
attempt == AUTH_FAIL_LOG ||
|
||||
strcmp(method, "password") == 0)
|
||||
authlog = log;
|
||||
|
||||
/* Log before sending the reply */
|
||||
if (authenticated == 1) {
|
||||
authmsg = "Accepted";
|
||||
} else if (authenticated == 0) {
|
||||
authmsg = "Failed";
|
||||
} else {
|
||||
authmsg = "Postponed";
|
||||
}
|
||||
authlog("%s %s for %.200s from %.200s port %d ssh2",
|
||||
authmsg,
|
||||
method,
|
||||
pw && pw->pw_uid == 0 ? "ROOT" : user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
|
||||
/* XXX todo: check if multiple auth methods are needed */
|
||||
if (authenticated == 1) {
|
||||
/* turn off userauth */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
|
||||
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
/* now we can break out */
|
||||
userauth_success = 1;
|
||||
} else if (authenticated == 0) {
|
||||
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
||||
packet_put_cstring("publickey,password"); /* XXX dynamic */
|
||||
packet_put_char(0); /* XXX partial success, unused */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
xfree(service);
|
||||
xfree(user);
|
||||
xfree(method);
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_auth_none(struct passwd *pw)
|
||||
{
|
||||
packet_done();
|
||||
return auth_password(pw, "");
|
||||
}
|
||||
int
|
||||
ssh2_auth_password(struct passwd *pw)
|
||||
{
|
||||
char *password;
|
||||
int authenticated = 0;
|
||||
int change;
|
||||
unsigned int len;
|
||||
change = packet_get_char();
|
||||
if (change)
|
||||
log("password change not supported");
|
||||
password = packet_get_string(&len);
|
||||
packet_done();
|
||||
if (options.password_authentication &&
|
||||
auth_password(pw, password) == 1)
|
||||
authenticated = 1;
|
||||
memset(password, 0, len);
|
||||
xfree(password);
|
||||
return authenticated;
|
||||
}
|
||||
int
|
||||
ssh2_auth_pubkey(struct passwd *pw, char *service)
|
||||
{
|
||||
Buffer b;
|
||||
Key *key;
|
||||
char *pkalg, *pkblob, *sig;
|
||||
unsigned int alen, blen, slen;
|
||||
int have_sig;
|
||||
int authenticated = 0;
|
||||
|
||||
if (options.dsa_authentication == 0) {
|
||||
debug("pubkey auth disabled");
|
||||
return 0;
|
||||
}
|
||||
have_sig = packet_get_char();
|
||||
pkalg = packet_get_string(&alen);
|
||||
if (strcmp(pkalg, KEX_DSS) != 0) {
|
||||
xfree(pkalg);
|
||||
log("bad pkalg %s", pkalg); /*XXX*/
|
||||
return 0;
|
||||
}
|
||||
pkblob = packet_get_string(&blen);
|
||||
key = dsa_key_from_blob(pkblob, blen);
|
||||
if (key != NULL) {
|
||||
if (have_sig) {
|
||||
sig = packet_get_string(&slen);
|
||||
packet_done();
|
||||
buffer_init(&b);
|
||||
if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
|
||||
buffer_put_string(&b, session_id2, session_id2_len);
|
||||
} else {
|
||||
buffer_append(&b, session_id2, session_id2_len);
|
||||
}
|
||||
/* reconstruct packet */
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, pw->pw_name);
|
||||
buffer_put_cstring(&b,
|
||||
datafellows & SSH_BUG_PUBKEYAUTH ?
|
||||
"ssh-userauth" :
|
||||
service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, pkblob, blen);
|
||||
#ifdef DEBUG_DSS
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
/* test for correct signature */
|
||||
if (user_dsa_key_allowed(pw, key) &&
|
||||
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
|
||||
authenticated = 1;
|
||||
buffer_clear(&b);
|
||||
xfree(sig);
|
||||
} else {
|
||||
packet_done();
|
||||
debug("test key...");
|
||||
/* test whether pkalg/pkblob are acceptable */
|
||||
/* XXX fake reply and always send PK_OK ? */
|
||||
/*
|
||||
* XXX this allows testing whether a user is allowed
|
||||
* to login: if you happen to have a valid pubkey this
|
||||
* message is sent. the message is NEVER sent at all
|
||||
* if a user is not allowed to login. is this an
|
||||
* issue? -markus
|
||||
*/
|
||||
if (user_dsa_key_allowed(pw, key)) {
|
||||
packet_start(SSH2_MSG_USERAUTH_PK_OK);
|
||||
packet_put_string(pkalg, alen);
|
||||
packet_put_string(pkblob, blen);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
authenticated = -1;
|
||||
}
|
||||
}
|
||||
key_free(key);
|
||||
}
|
||||
xfree(pkalg);
|
||||
xfree(pkblob);
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
/* set and get current user */
|
||||
|
||||
struct passwd*
|
||||
auth_get_user(void)
|
||||
{
|
||||
return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
|
||||
}
|
||||
|
||||
struct passwd*
|
||||
auth_set_user(char *u, char *s)
|
||||
{
|
||||
struct passwd *pw, *copy;
|
||||
|
||||
if (authctxt == NULL) {
|
||||
authctxt = xmalloc(sizeof(*authctxt));
|
||||
authctxt->valid = 0;
|
||||
authctxt->user = xstrdup(u);
|
||||
authctxt->service = xstrdup(s);
|
||||
setproctitle("%s", u);
|
||||
pw = getpwnam(u);
|
||||
if (!pw || !allowed_user(pw)) {
|
||||
log("auth_set_user: illegal user %s", u);
|
||||
return NULL;
|
||||
}
|
||||
copy = &authctxt->pw;
|
||||
memset(copy, 0, sizeof(*copy));
|
||||
copy->pw_name = xstrdup(pw->pw_name);
|
||||
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||
copy->pw_uid = pw->pw_uid;
|
||||
copy->pw_gid = pw->pw_gid;
|
||||
copy->pw_class = xstrdup(pw->pw_class);
|
||||
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||
authctxt->valid = 1;
|
||||
} else {
|
||||
if (strcmp(u, authctxt->user) != 0 ||
|
||||
strcmp(s, authctxt->service) != 0) {
|
||||
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
|
||||
u, s, authctxt->user, authctxt->service);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return auth_get_user();
|
||||
}
|
||||
|
||||
/* return 1 if user allows given key */
|
||||
int
|
||||
user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
{
|
||||
char line[8192], file[1024];
|
||||
int found_key = 0;
|
||||
unsigned int bits = -1;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
struct stat st;
|
||||
Key *found;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
_PATH_SSH_USER_PERMITTED_KEYS2);
|
||||
|
||||
/* 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();
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes) {
|
||||
int fail = 0;
|
||||
char buf[1024];
|
||||
/* Check open file in order to avoid open/stat races */
|
||||
if (fstat(fileno(f), &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf,
|
||||
"%s authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.",
|
||||
key_type(key), pw->pw_name, file);
|
||||
fail = 1;
|
||||
} else {
|
||||
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", _PATH_SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; i++) {
|
||||
snprintf(line, sizeof line, "%.500s/%.100s",
|
||||
pw->pw_dir, check[i]);
|
||||
if (stat(line, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf,
|
||||
"%s authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.",
|
||||
key_type(key), pw->pw_name, line);
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
fclose(f);
|
||||
log("%s",buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
found_key = 0;
|
||||
found = key_new(key->type);
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *cp, *options = NULL;
|
||||
linenum++;
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
bits = key_read(found, &cp);
|
||||
if (bits == 0) {
|
||||
/* no key? check if there are options for this key */
|
||||
int quoted = 0;
|
||||
options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
/* Skip remaining whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
bits = key_read(found, &cp);
|
||||
if (bits == 0) {
|
||||
/* still no key? advance to next line*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (key_equal(found, key) &&
|
||||
auth_parse_options(pw, options, linenum) == 1) {
|
||||
found_key = 1;
|
||||
debug("matching key found: file %s, line %ld",
|
||||
file, linenum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
restore_uid();
|
||||
fclose(f);
|
||||
key_free(found);
|
||||
return found_key;
|
||||
}
|
553
crypto/dist/ssh/authfd.c
vendored
Normal file
553
crypto/dist/ssh/authfd.c
vendored
Normal file
@ -0,0 +1,553 @@
|
||||
/* $NetBSD: authfd.c,v 1.1.1.1 2000/09/28 22:09:44 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for connecting the local authentication agent.
|
||||
*
|
||||
* 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".
|
||||
*
|
||||
* SSH2 implementation,
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: authfd.c,v 1.28 2000/09/21 11:07:50 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: authfd.c,v 1.1.1.1 2000/09/28 22:09:44 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "kex.h"
|
||||
#include "dsa.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* helper */
|
||||
int decode_reply(int type);
|
||||
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
|
||||
int
|
||||
ssh_get_authentication_socket()
|
||||
{
|
||||
const char *authsocket;
|
||||
int sock, len;
|
||||
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));
|
||||
sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1;
|
||||
|
||||
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, len) < 0) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
|
||||
{
|
||||
int l, len;
|
||||
char buf[1024];
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(request);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (atomic_write(auth->fd, buf, 4) != 4 ||
|
||||
atomic_write(auth->fd, buffer_ptr(request),
|
||||
buffer_len(request)) != buffer_len(request)) {
|
||||
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("Authentication response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in to the buffer. */
|
||||
buffer_clear(reply);
|
||||
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.");
|
||||
return 0;
|
||||
}
|
||||
buffer_append(reply, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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->identities);
|
||||
auth->howmany = 0;
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the connection to the authentication agent and frees any associated
|
||||
* memory.
|
||||
*/
|
||||
|
||||
void
|
||||
ssh_close_authentication_connection(AuthenticationConnection *auth)
|
||||
{
|
||||
buffer_free(&auth->identities);
|
||||
close(auth->fd);
|
||||
xfree(auth);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent.
|
||||
*/
|
||||
|
||||
Key *
|
||||
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
|
||||
{
|
||||
int type, code1 = 0, code2 = 0;
|
||||
Buffer request;
|
||||
|
||||
switch(version){
|
||||
case 1:
|
||||
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
|
||||
break;
|
||||
case 2:
|
||||
code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
|
||||
code2 = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to the agent requesting for a list of the
|
||||
* identities it can represent.
|
||||
*/
|
||||
buffer_init(&request);
|
||||
buffer_put_char(&request, code1);
|
||||
|
||||
buffer_clear(&auth->identities);
|
||||
if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
|
||||
buffer_free(&request);
|
||||
return NULL;
|
||||
}
|
||||
buffer_free(&request);
|
||||
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
type = buffer_get_char(&auth->identities);
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
return NULL;
|
||||
} else if (type != code2) {
|
||||
fatal("Bad authentication reply message type: %d", type);
|
||||
}
|
||||
|
||||
/* 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, comment, version);
|
||||
}
|
||||
|
||||
Key *
|
||||
ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
Key *key = NULL;
|
||||
|
||||
/* Return failure if no more entries. */
|
||||
if (auth->howmany <= 0)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Get the next entry from the packet. These will abort with a fatal
|
||||
* error if the packet is too short or contains corrupt data.
|
||||
*/
|
||||
switch(version){
|
||||
case 1:
|
||||
key = key_new(KEY_RSA);
|
||||
bits = buffer_get_int(&auth->identities);
|
||||
buffer_get_bignum(&auth->identities, key->rsa->e);
|
||||
buffer_get_bignum(&auth->identities, key->rsa->n);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
if (bits != BN_num_bits(key->rsa->n))
|
||||
log("Warning: identity keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(key->rsa->n), bits);
|
||||
break;
|
||||
case 2:
|
||||
blob = buffer_get_string(&auth->identities, &blen);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
xfree(blob);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
/* Decrement the number of remaining entries. */
|
||||
auth->howmany--;
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
Key* key, BIGNUM *challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16])
|
||||
{
|
||||
Buffer buffer;
|
||||
int success = 0;
|
||||
int i;
|
||||
int type;
|
||||
|
||||
if (key->type != KEY_RSA)
|
||||
return 0;
|
||||
if (response_type == 0) {
|
||||
log("Compatibility with ssh protocol version 1.0 no longer supported.");
|
||||
return 0;
|
||||
}
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
|
||||
buffer_put_bignum(&buffer, key->rsa->e);
|
||||
buffer_put_bignum(&buffer, key->rsa->n);
|
||||
buffer_put_bignum(&buffer, challenge);
|
||||
buffer_append(&buffer, (char *) session_id, 16);
|
||||
buffer_put_int(&buffer, response_type);
|
||||
|
||||
if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
type = buffer_get_char(&buffer);
|
||||
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
log("Agent admitted failure to authenticate using the key.");
|
||||
} else if (type != SSH_AGENT_RSA_RESPONSE) {
|
||||
fatal("Bad authentication response: %d", type);
|
||||
} else {
|
||||
success = 1;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
buffer_free(&buffer);
|
||||
return success;
|
||||
}
|
||||
|
||||
/* ask agent to sign data, returns -1 on error, 0 on success */
|
||||
int
|
||||
ssh_agent_sign(AuthenticationConnection *auth,
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
extern int datafellows;
|
||||
Buffer msg;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
int type, flags = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (dsa_make_key_blob(key, &blob, &blen) == 0)
|
||||
return -1;
|
||||
|
||||
if (datafellows & SSH_BUG_SIGBLOB)
|
||||
flags = SSH_AGENT_OLD_SIGNATURE;
|
||||
|
||||
buffer_init(&msg);
|
||||
buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
|
||||
buffer_put_string(&msg, blob, blen);
|
||||
buffer_put_string(&msg, data, datalen);
|
||||
buffer_put_int(&msg, flags);
|
||||
xfree(blob);
|
||||
|
||||
if (ssh_request_reply(auth, &msg, &msg) == 0) {
|
||||
buffer_free(&msg);
|
||||
return -1;
|
||||
}
|
||||
type = buffer_get_char(&msg);
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
log("Agent admitted failure to sign using the key.");
|
||||
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
fatal("Bad authentication response: %d", type);
|
||||
} else {
|
||||
ret = 0;
|
||||
*sigp = buffer_get_string(&msg, lenp);
|
||||
}
|
||||
buffer_free(&msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Encode key for a message to the agent. */
|
||||
|
||||
static void
|
||||
ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
|
||||
{
|
||||
buffer_clear(b);
|
||||
buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
|
||||
buffer_put_int(b, BN_num_bits(key->n));
|
||||
buffer_put_bignum(b, key->n);
|
||||
buffer_put_bignum(b, key->e);
|
||||
buffer_put_bignum(b, key->d);
|
||||
/* To keep within the protocol: p < q for ssh. in SSL p > q */
|
||||
buffer_put_bignum(b, key->iqmp); /* ssh key->u */
|
||||
buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
|
||||
buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
|
||||
buffer_put_string(b, comment, strlen(comment));
|
||||
}
|
||||
|
||||
static void
|
||||
ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
|
||||
{
|
||||
buffer_clear(b);
|
||||
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
|
||||
buffer_put_cstring(b, KEX_DSS);
|
||||
buffer_put_bignum2(b, key->p);
|
||||
buffer_put_bignum2(b, key->q);
|
||||
buffer_put_bignum2(b, key->g);
|
||||
buffer_put_bignum2(b, key->pub_key);
|
||||
buffer_put_bignum2(b, key->priv_key);
|
||||
buffer_put_string(b, comment, strlen(comment));
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an identity to the authentication server. This call is not meant to
|
||||
* be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
|
||||
{
|
||||
Buffer msg;
|
||||
int type;
|
||||
|
||||
buffer_init(&msg);
|
||||
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
ssh_encode_identity_rsa(&msg, key->rsa, comment);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
ssh_encode_identity_dsa(&msg, key->dsa, comment);
|
||||
break;
|
||||
default:
|
||||
buffer_free(&msg);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
if (ssh_request_reply(auth, &msg, &msg) == 0) {
|
||||
buffer_free(&msg);
|
||||
return 0;
|
||||
}
|
||||
type = buffer_get_char(&msg);
|
||||
buffer_free(&msg);
|
||||
return decode_reply(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an identity from the authentication server. This call is not
|
||||
* meant to be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_remove_identity(AuthenticationConnection *auth, Key *key)
|
||||
{
|
||||
Buffer msg;
|
||||
int type;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
|
||||
buffer_init(&msg);
|
||||
|
||||
if (key->type == KEY_RSA) {
|
||||
buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
|
||||
buffer_put_int(&msg, BN_num_bits(key->rsa->n));
|
||||
buffer_put_bignum(&msg, key->rsa->e);
|
||||
buffer_put_bignum(&msg, key->rsa->n);
|
||||
} else if (key->type == KEY_DSA) {
|
||||
dsa_make_key_blob(key, &blob, &blen);
|
||||
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
|
||||
buffer_put_string(&msg, blob, blen);
|
||||
xfree(blob);
|
||||
} else {
|
||||
buffer_free(&msg);
|
||||
return 0;
|
||||
}
|
||||
if (ssh_request_reply(auth, &msg, &msg) == 0) {
|
||||
buffer_free(&msg);
|
||||
return 0;
|
||||
}
|
||||
type = buffer_get_char(&msg);
|
||||
buffer_free(&msg);
|
||||
return decode_reply(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes all identities from the agent. This call is not meant to be used
|
||||
* by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_remove_all_identities(AuthenticationConnection *auth, int version)
|
||||
{
|
||||
Buffer msg;
|
||||
int type;
|
||||
int code = (version==1) ?
|
||||
SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
|
||||
SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
|
||||
|
||||
buffer_init(&msg);
|
||||
buffer_put_char(&msg, code);
|
||||
|
||||
if (ssh_request_reply(auth, &msg, &msg) == 0) {
|
||||
buffer_free(&msg);
|
||||
return 0;
|
||||
}
|
||||
type = buffer_get_char(&msg);
|
||||
buffer_free(&msg);
|
||||
return decode_reply(type);
|
||||
}
|
||||
|
||||
int
|
||||
decode_reply(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
log("SSH_AGENT_FAILURE");
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response from authentication agent: %d", type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
131
crypto/dist/ssh/authfd.h
vendored
Normal file
131
crypto/dist/ssh/authfd.h
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
/* $NetBSD: authfd.h,v 1.1.1.1 2000/09/28 22:09:44 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: authfd.h,v 1.12 2000/09/21 11:07:51 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
|
||||
|
||||
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||
#define SSH2_AGENT_SIGN_RESPONSE 14
|
||||
#define SSH2_AGENTC_ADD_IDENTITY 17
|
||||
#define SSH2_AGENTC_REMOVE_IDENTITY 18
|
||||
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
|
||||
|
||||
#define SSH_AGENT_OLD_SIGNATURE 0x01
|
||||
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
Buffer identities;
|
||||
int howmany;
|
||||
} AuthenticationConnection;
|
||||
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
int ssh_get_authentication_socket(void);
|
||||
|
||||
/*
|
||||
* This should be called for any descriptor returned by
|
||||
* ssh_get_authentication_socket(). Depending on the way the descriptor was
|
||||
* obtained, this may close the descriptor.
|
||||
*/
|
||||
void ssh_close_authentication_socket(int authfd);
|
||||
|
||||
/*
|
||||
* Opens and connects a private socket for communication with the
|
||||
* authentication agent. Returns NULL if an error occurred and the
|
||||
* connection could not be opened. The connection should be closed by the
|
||||
* caller by calling ssh_close_authentication_connection().
|
||||
*/
|
||||
AuthenticationConnection *ssh_get_authentication_connection(void);
|
||||
|
||||
/*
|
||||
* Closes the connection to the authentication agent and frees any associated
|
||||
* memory.
|
||||
*/
|
||||
void ssh_close_authentication_connection(AuthenticationConnection *auth);
|
||||
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent or NULL if
|
||||
* no identies are available. Caller must free comment and key.
|
||||
* Note that you cannot mix calls with different versions.
|
||||
*/
|
||||
Key *ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version);
|
||||
|
||||
/*
|
||||
* Returns the next authentication identity for the agent. Other functions
|
||||
* can be called between this and ssh_get_first_identity or two calls of this
|
||||
* function. This returns NULL if there are no more identities. The caller
|
||||
* must free key and comment after a successful return.
|
||||
*/
|
||||
Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version);
|
||||
|
||||
/*
|
||||
* Requests the agent to decrypt the given challenge. Returns true if the
|
||||
* agent claims it was able to decrypt it.
|
||||
*/
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
Key *key, BIGNUM * challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16]);
|
||||
|
||||
/* Requests the agent to sign data using key */
|
||||
int
|
||||
ssh_agent_sign(AuthenticationConnection *auth,
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
/*
|
||||
* Adds an identity to the authentication server. This call is not meant to
|
||||
* be used by normal applications. This returns true if the identity was
|
||||
* successfully added.
|
||||
*/
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection *auth, Key *key,
|
||||
const char *comment);
|
||||
|
||||
/*
|
||||
* Removes the identity from the authentication server. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* identity was successfully added.
|
||||
*/
|
||||
int ssh_remove_identity(AuthenticationConnection *auth, Key *key);
|
||||
|
||||
/*
|
||||
* Removes all identities from the authentication agent. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* operation was successful.
|
||||
*/
|
||||
int ssh_remove_all_identities(AuthenticationConnection *auth, int version);
|
||||
|
||||
#endif /* AUTHFD_H */
|
580
crypto/dist/ssh/authfile.c
vendored
Normal file
580
crypto/dist/ssh/authfile.c
vendored
Normal file
@ -0,0 +1,580 @@
|
||||
/* $NetBSD: authfile.c,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* This file contains functions for reading and writing identity files, and
|
||||
* for reading the passphrase from the user.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: authfile.c,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "ssh.h"
|
||||
#include "key.h"
|
||||
#include "authfile.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.
|
||||
*/
|
||||
|
||||
static int
|
||||
save_private_key_rsa(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. */
|
||||
/* XXXthorpej */
|
||||
RAND_pseudo_bytes((u_char *)&rand, sizeof(rand));
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* save DSA key in OpenSSL PEM format */
|
||||
|
||||
static int
|
||||
save_private_key_dsa(const char *filename, const char *passphrase,
|
||||
DSA *dsa, const char *comment)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int success = 1;
|
||||
int len = strlen(passphrase);
|
||||
|
||||
if (len > 0 && len <= 4) {
|
||||
error("passphrase too short: %d bytes", len);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
debug("open %s failed", filename);
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "w");
|
||||
if (fp == NULL ) {
|
||||
debug("fdopen %s failed", filename);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
|
||||
(char *)passphrase, strlen(passphrase), NULL, NULL))
|
||||
success = 0;
|
||||
} else {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
|
||||
NULL, 0, NULL, NULL))
|
||||
success = 0;
|
||||
}
|
||||
fclose(fp);
|
||||
return success;
|
||||
}
|
||||
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
const char *comment)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return save_private_key_dsa(filename, passphrase, key->dsa, comment);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file. Returns 0 if an error was
|
||||
* encountered (the file does not exist or is not readable), and non-zero
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
static int
|
||||
load_public_key_rsa(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);
|
||||
/* XXX alloc */
|
||||
if (pub->n == NULL)
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
/* XXX alloc */
|
||||
if (pub->e == NULL)
|
||||
pub->e = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
/* The encrypted private part is not parsed by this function. */
|
||||
|
||||
buffer_free(&buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* load public key from private-key file */
|
||||
int
|
||||
load_public_key(const char *filename, Key * key, char **comment_return)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return load_public_key_rsa(filename, key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
* (file does not exist or is not readable, or passphrase is bad). This
|
||||
* initializes the private key.
|
||||
* Assumes we are called under uid of the owner of the file.
|
||||
*/
|
||||
|
||||
static int
|
||||
load_private_key_rsa(int fd, const char *filename,
|
||||
const char *passphrase, RSA * prv, char **comment_return)
|
||||
{
|
||||
int i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
|
||||
len = lseek(fd, (off_t) 0, SEEK_END);
|
||||
lseek(fd, (off_t) 0, SEEK_SET);
|
||||
|
||||
buffer_init(&buffer);
|
||||
buffer_append_space(&buffer, &cp, len);
|
||||
|
||||
if (read(fd, cp, (size_t) len) != (size_t) len) {
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
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_mask1() | 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);
|
||||
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);
|
||||
prv->n = NULL;
|
||||
BN_clear_free(prv->e);
|
||||
prv->e = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
|
||||
{
|
||||
DSA *dsa;
|
||||
BIO *in;
|
||||
FILE *fp;
|
||||
|
||||
in = BIO_new(BIO_s_file());
|
||||
if (in == NULL) {
|
||||
error("BIO_new failed");
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "r");
|
||||
if (fp == NULL) {
|
||||
error("fdopen failed");
|
||||
return 0;
|
||||
}
|
||||
BIO_set_fp(in, fp, BIO_NOCLOSE);
|
||||
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
|
||||
if (dsa == NULL) {
|
||||
debug("PEM_read_bio_DSAPrivateKey failed");
|
||||
} else {
|
||||
/* replace k->dsa with loaded key */
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = dsa;
|
||||
}
|
||||
BIO_free(in);
|
||||
fclose(fp);
|
||||
if (comment_return)
|
||||
*comment_return = xstrdup("dsa w/o comment");
|
||||
debug("read DSA private key done");
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
#endif
|
||||
return dsa != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
char **comment_return)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_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;
|
||||
}
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
if (key->rsa->e != NULL) {
|
||||
BN_clear_free(key->rsa->e);
|
||||
key->rsa->e = NULL;
|
||||
}
|
||||
if (key->rsa->n != NULL) {
|
||||
BN_clear_free(key->rsa->n);
|
||||
key->rsa->n = NULL;
|
||||
}
|
||||
ret = load_private_key_rsa(fd, filename, passphrase,
|
||||
key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_load_public_key(const char *filename, Key *k, char **commentp)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned int bits;
|
||||
char line[1024];
|
||||
char *cp;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f != NULL) {
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
line[sizeof(line)-1] = '\0';
|
||||
cp = line;
|
||||
switch(*cp){
|
||||
case '#':
|
||||
case '\n':
|
||||
case '\0':
|
||||
continue;
|
||||
}
|
||||
/* Skip leading whitespace. */
|
||||
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
|
||||
;
|
||||
if (*cp) {
|
||||
bits = key_read(k, &cp);
|
||||
if (bits != 0) {
|
||||
if (commentp)
|
||||
*commentp=xstrdup(filename);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load public key from pubkey file */
|
||||
int
|
||||
try_load_public_key(const char *filename, Key *k, char **commentp)
|
||||
{
|
||||
char pub[MAXPATHLEN];
|
||||
|
||||
if (do_load_public_key(filename, k, commentp) == 1)
|
||||
return 1;
|
||||
if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN)
|
||||
return 0;
|
||||
if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN)
|
||||
return 0;
|
||||
if (do_load_public_key(pub, k, commentp) == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
50
crypto/dist/ssh/authfile.h
vendored
Normal file
50
crypto/dist/ssh/authfile.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/* $NetBSD: authfile.h,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef AUTHFILE_H
|
||||
#define AUTHFILE_H
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase.
|
||||
* For RSA keys: The identification of the file (lowest 64 bits of n)
|
||||
* will precede the key to provide identification of the key without
|
||||
* needing a passphrase.
|
||||
*/
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
Key * private_key, const char *comment);
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file (public key and comment). Returns 0
|
||||
* if an error occurred; zero if the public key was successfully read. The
|
||||
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||
* caller must free the value with xfree.
|
||||
*/
|
||||
int load_public_key(const char *filename, Key * pub, char **comment_return);
|
||||
int try_load_public_key(const char *filename, Key * pub, char **comment_return);
|
||||
|
||||
/*
|
||||
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
* (file does not exist or is not readable, or passphrase is bad). This
|
||||
* initializes the private key. The comment of the key is returned in
|
||||
* comment_return if it is non-NULL; the caller must free the value with
|
||||
* xfree.
|
||||
*/
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
Key * private_key, char **comment_return);
|
||||
|
||||
#endif
|
237
crypto/dist/ssh/bufaux.c
vendored
Normal file
237
crypto/dist/ssh/bufaux.c
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
/* $NetBSD: bufaux.c,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
*
|
||||
* 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".
|
||||
*
|
||||
*
|
||||
* SSH2 packet format added by Markus Friedl
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: bufaux.c,v 1.13 2000/09/07 20:27:50 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: bufaux.c,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include <openssl/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 unsigned *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, (char *)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 = (unsigned char*) buffer_ptr(buffer);
|
||||
BN_bin2bn(bin, bytes, value);
|
||||
buffer_consume(buffer, bytes);
|
||||
|
||||
return 2 + bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer in SSH2 format.
|
||||
*/
|
||||
void
|
||||
buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bytes = BN_num_bytes(value) + 1;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
int oi;
|
||||
int hasnohigh = 0;
|
||||
buf[0] = '\0';
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf+1);
|
||||
if (oi != bytes-1)
|
||||
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bytes);
|
||||
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
|
||||
if (value->neg) {
|
||||
/**XXX should be two's-complement */
|
||||
int i, carry;
|
||||
unsigned char *uc = buf;
|
||||
log("negativ!");
|
||||
for(i = bytes-1, carry = 1; i>=0; i--) {
|
||||
uc[i] ^= 0xff;
|
||||
if(carry)
|
||||
carry = !++uc[i];
|
||||
}
|
||||
}
|
||||
buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
|
||||
memset(buf, 0, bytes);
|
||||
xfree(buf);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
/**XXX should be two's-complement */
|
||||
int len;
|
||||
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len);
|
||||
BN_bin2bn(bin, len, value);
|
||||
xfree(bin);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
void
|
||||
buffer_put_cstring(Buffer *buffer, const char *s)
|
||||
{
|
||||
buffer_put_string(buffer, s, strlen(s));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
59
crypto/dist/ssh/bufaux.h
vendored
Normal file
59
crypto/dist/ssh/bufaux.h
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/* $NetBSD: bufaux.h,v 1.1.1.1 2000/09/28 22:09:46 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: bufaux.h,v 1.8 2000/09/07 20:27:50 deraadt 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);
|
||||
void buffer_put_bignum2(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
|
||||
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
|
||||
|
||||
/* Returns an integer from the buffer (4 bytes, msb first). */
|
||||
unsigned int buffer_get_int(Buffer * buffer);
|
||||
|
||||
/* 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);
|
||||
void buffer_put_cstring(Buffer *buffer, const char *s);
|
||||
|
||||
#endif /* BUFAUX_H */
|
167
crypto/dist/ssh/buffer.c
vendored
Normal file
167
crypto/dist/ssh/buffer.c
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/* $NetBSD: buffer.c,v 1.1.1.1 2000/09/28 22:09:47 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for manipulating fifo buffers (that can grow if needed).
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: buffer.c,v 1.8 2000/09/07 20:27:50 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: buffer.c,v 1.1.1.1 2000/09/28 22:09:47 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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_consume: 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_consume_end: 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/dist/ssh/buffer.h
vendored
Normal file
68
crypto/dist/ssh/buffer.h
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/* $NetBSD: buffer.h,v 1.1.1.1 2000/09/28 22:09:47 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Code for manipulating FIFO buffers.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: buffer.h,v 1.6 2000/09/07 20:27:50 deraadt 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 */
|
280
crypto/dist/ssh/canohost.c
vendored
Normal file
280
crypto/dist/ssh/canohost.c
vendored
Normal file
@ -0,0 +1,280 @@
|
||||
/* $NetBSD: canohost.c,v 1.1.1.1 2000/09/28 22:09:48 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for returning the canonical host name of the remote site.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: canohost.c,v 1.15 2000/09/07 21:13:37 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: canohost.c,v 1.1.1.1 2000/09/28 22:09:48 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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. */
|
||||
|
||||
static 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. */
|
||||
|
||||
static 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);
|
||||
}
|
2313
crypto/dist/ssh/channels.c
vendored
Normal file
2313
crypto/dist/ssh/channels.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
291
crypto/dist/ssh/channels.h
vendored
Normal file
291
crypto/dist/ssh/channels.h
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
/* $NetBSD: channels.h,v 1.1.1.1 2000/09/28 22:09:53 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: channels.h,v 1.20 2000/09/21 11:25:33 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 */
|
||||
#define SSH_CHANNEL_AUTH_SOCKET 6 /* authentication socket */
|
||||
#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
|
||||
#define SSH_CHANNEL_LARVAL 10 /* larval session */
|
||||
#define SSH_CHANNEL_MAX_TYPE 11
|
||||
|
||||
/*
|
||||
* Data structure for channel data. This is iniailized in channel_allocate
|
||||
* and cleared in channel_free.
|
||||
*/
|
||||
struct Channel;
|
||||
typedef struct Channel Channel;
|
||||
|
||||
typedef void channel_callback_fn(int id, void *arg);
|
||||
typedef int channel_filter_fn(struct Channel *c, char *buf, int len);
|
||||
|
||||
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 flags; /* close sent/rcvd */
|
||||
int rfd; /* read fd */
|
||||
int wfd; /* write fd */
|
||||
int efd; /* extended fd */
|
||||
int sock; /* sock fd */
|
||||
Buffer input; /* data read from socket, to be sent over
|
||||
* encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for
|
||||
* send on socket */
|
||||
Buffer extended;
|
||||
char path[200]; /* path for unix domain sockets, or host name
|
||||
* for forwards */
|
||||
int listening_port; /* port being listened for forwards */
|
||||
int host_port; /* remote port to connect for forwards */
|
||||
char *remote_name; /* remote hostname */
|
||||
|
||||
int remote_window;
|
||||
int remote_maxpacket;
|
||||
int local_window;
|
||||
int local_window_max;
|
||||
int local_consumed;
|
||||
int local_maxpacket;
|
||||
int extended_usage;
|
||||
|
||||
char *ctype; /* type */
|
||||
|
||||
/* callback */
|
||||
channel_callback_fn *cb_fn;
|
||||
void *cb_arg;
|
||||
int cb_event;
|
||||
channel_callback_fn *dettach_user;
|
||||
|
||||
/* filter */
|
||||
channel_filter_fn *input_filter;
|
||||
};
|
||||
|
||||
#define CHAN_EXTENDED_IGNORE 0
|
||||
#define CHAN_EXTENDED_READ 1
|
||||
#define CHAN_EXTENDED_WRITE 2
|
||||
|
||||
/* default window/packet sizes for tcp/x11-fwd-channel */
|
||||
#define CHAN_SES_WINDOW_DEFAULT (32*1024)
|
||||
#define CHAN_SES_PACKET_DEFAULT (CHAN_SES_WINDOW_DEFAULT/2)
|
||||
#define CHAN_TCP_WINDOW_DEFAULT (32*1024)
|
||||
#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2)
|
||||
#define CHAN_X11_WINDOW_DEFAULT (4*1024)
|
||||
#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2)
|
||||
|
||||
|
||||
void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage);
|
||||
void channel_open(int id);
|
||||
void channel_request(int id, char *service, int wantconfirm);
|
||||
void channel_request_start(int id, char *service, int wantconfirm);
|
||||
void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
|
||||
void channel_register_cleanup(int id, channel_callback_fn *fn);
|
||||
void channel_register_filter(int id, channel_filter_fn *fn);
|
||||
void channel_cancel_cleanup(int id);
|
||||
Channel *channel_lookup(int id);
|
||||
|
||||
int
|
||||
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
|
||||
int window, int maxpack, int extended_usage, char *remote_name);
|
||||
|
||||
void channel_input_channel_request(int type, int plen, void *ctxt);
|
||||
void channel_input_close(int type, int plen, void *ctxt);
|
||||
void channel_input_close_confirmation(int type, int plen, void *ctxt);
|
||||
void channel_input_data(int type, int plen, void *ctxt);
|
||||
void channel_input_extended_data(int type, int plen, void *ctxt);
|
||||
void channel_input_ieof(int type, int plen, void *ctxt);
|
||||
void channel_input_oclose(int type, int plen, void *ctxt);
|
||||
void channel_input_open_confirmation(int type, int plen, void *ctxt);
|
||||
void channel_input_open_failure(int type, int plen, void *ctxt);
|
||||
void channel_input_port_open(int type, int plen, void *ctxt);
|
||||
void channel_input_window_adjust(int type, int plen, void *ctxt);
|
||||
void channel_input_open(int type, int plen, void *ctxt);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
int channel_not_very_much_buffered_data(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, int gateway_ports);
|
||||
|
||||
/*
|
||||
* Creates a port for X11 connections, and starts listening for it. Returns
|
||||
* the display name, or NULL if an error was encountered.
|
||||
*/
|
||||
char *x11_create_display(int screen);
|
||||
|
||||
/*
|
||||
* Creates an internet domain socket for listening for X11 connections.
|
||||
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||
* occurs.
|
||||
*/
|
||||
char *x11_create_display_inet(int screen, int x11_display_offset);
|
||||
|
||||
/*
|
||||
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
||||
* the remote channel number. We should do whatever we want, and respond
|
||||
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||
*/
|
||||
void x11_input_open(int type, int plen, void *ctxt);
|
||||
|
||||
/*
|
||||
* Requests forwarding of X11 connections. This should be called on the
|
||||
* client only.
|
||||
*/
|
||||
void x11_request_forwarding(void);
|
||||
|
||||
/*
|
||||
* Requests forwarding for X11 connections, with authentication spoofing.
|
||||
* This should be called in the client only.
|
||||
*/
|
||||
void
|
||||
x11_request_forwarding_with_spoofing(int client_session_id,
|
||||
const char *proto, const char *data);
|
||||
|
||||
/* Sends a message to the server to request authentication fd forwarding. */
|
||||
void auth_request_forwarding(void);
|
||||
|
||||
/*
|
||||
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||
* there is no forwarded authentication socket. The returned value points to
|
||||
* a static buffer.
|
||||
*/
|
||||
char *auth_get_socket_name(void);
|
||||
|
||||
/*
|
||||
* This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
||||
* This starts forwarding authentication requests.
|
||||
*/
|
||||
int auth_input_request_forwarding(struct passwd * pw);
|
||||
|
||||
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
||||
void auth_input_open_request(int type, int plen, void *ctxt);
|
||||
|
||||
/* XXX */
|
||||
int channel_connect_to(const char *host, u_short host_port);
|
||||
int x11_connect_display(void);
|
||||
|
||||
#endif
|
495
crypto/dist/ssh/cipher.c
vendored
Normal file
495
crypto/dist/ssh/cipher.c
vendored
Normal file
@ -0,0 +1,495 @@
|
||||
/* $NetBSD: cipher.c,v 1.1.1.1 2000/09/28 22:09:53 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1999 Niels Provos. All rights reserved.
|
||||
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: cipher.c,v 1.31 2000/09/12 00:38:32 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: cipher.c,v 1.1.1.1 2000/09/28 22:09:53 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/*
|
||||
* This is used by SSH1:
|
||||
*
|
||||
* What kind of triple DES are these 2 routines?
|
||||
*
|
||||
* Why is there a redundant initialization vector?
|
||||
*
|
||||
* If only iv3 was used, then, this would till effect have been
|
||||
* outer-cbc. However, there is also a private iv1 == iv2 which
|
||||
* perhaps makes differential analysis easier. On the other hand, the
|
||||
* private iv1 probably makes the CRC-32 attack ineffective. This is a
|
||||
* result of that there is no longer any known iv1 to use when
|
||||
* choosing the X block.
|
||||
*/
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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. */
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
*/
|
||||
static void
|
||||
swap_bytes(const 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Names of all encryption algorithms.
|
||||
* These must match the numbers defined in cipher.h.
|
||||
*/
|
||||
static char *cipher_names[] =
|
||||
{
|
||||
"none",
|
||||
"idea",
|
||||
"des",
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4", /* Alleged RC4 */
|
||||
"blowfish",
|
||||
"reserved",
|
||||
"blowfish-cbc",
|
||||
"3des-cbc",
|
||||
"arcfour",
|
||||
"cast128-cbc"
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_mask1()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask2()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH_CBC;
|
||||
mask |= 1 << SSH_CIPHER_3DES_CBC;
|
||||
mask |= 1 << SSH_CIPHER_ARCFOUR;
|
||||
mask |= 1 << SSH_CIPHER_CAST128_CBC;
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
{
|
||||
return cipher_mask1() | cipher_mask2();
|
||||
}
|
||||
|
||||
/* 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 name: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
}
|
||||
|
||||
/* Returns 1 if the name of the ciphers are valid. */
|
||||
|
||||
#define CIPHER_SEP ","
|
||||
int
|
||||
ciphers_valid(const char *names)
|
||||
{
|
||||
char *ciphers, *cp;
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
if (names == NULL || strcmp(names, "") == 0)
|
||||
return 0;
|
||||
ciphers = cp = xstrdup(names);
|
||||
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
|
||||
(p = strsep(&cp, CIPHER_SEP))) {
|
||||
i = cipher_number(p);
|
||||
if (i == -1 || !(cipher_mask2() & (1 << i))) {
|
||||
xfree(ciphers);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
xfree(ciphers);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
}
|
||||
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen)
|
||||
{
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
if (keylen < 24)
|
||||
error("Key length %d is insufficient for 3des-cbc.", keylen);
|
||||
des_set_key((void *) key, context->u.des3.key1);
|
||||
des_set_key((void *) (key+8), context->u.des3.key2);
|
||||
des_set_key((void *) (key+16), context->u.des3.key3);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for 3des-cbc.", ivlen);
|
||||
memcpy(context->u.des3.iv3, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for blowfish.", ivlen);
|
||||
BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key);
|
||||
memcpy(context->u.bf.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for arcfour.", keylen);
|
||||
RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for cast128.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for cast128.", ivlen);
|
||||
CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key);
|
||||
memcpy(context->u.cast.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *)src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT);
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *) src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_DECRYPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
116
crypto/dist/ssh/cipher.h
vendored
Normal file
116
crypto/dist/ssh/cipher.h
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
/* $NetBSD: cipher.h,v 1.1.1.1 2000/09/28 22:09:54 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: cipher.h,v 1.19 2000/09/07 20:27:50 deraadt Exp */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <openssl/cast.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_ILLEGAL -2 /* No valid cipher selected. */
|
||||
#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
|
||||
#define SSH_CIPHER_RESERVED 7
|
||||
|
||||
/* these ciphers are used in SSH2: */
|
||||
#define SSH_CIPHER_BLOWFISH_CBC 8
|
||||
#define SSH_CIPHER_3DES_CBC 9
|
||||
#define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_CAST128_CBC 11
|
||||
|
||||
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;
|
||||
struct {
|
||||
CAST_KEY key;
|
||||
unsigned char iv[8];
|
||||
} cast;
|
||||
RC4_KEY rc4;
|
||||
} 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(void);
|
||||
unsigned int cipher_mask1(void);
|
||||
unsigned int cipher_mask2(void);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* returns 1 if all ciphers are supported (ssh2 only) */
|
||||
int ciphers_valid(const char *names);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif /* CIPHER_H */
|
39
crypto/dist/ssh/client.h
vendored
Normal file
39
crypto/dist/ssh/client.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/* $NetBSD: client.h,v 1.1.1.1 2000/09/28 22:09:54 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*/
|
||||
|
||||
void client_set_session_ident(int id);
|
1188
crypto/dist/ssh/clientloop.c
vendored
Normal file
1188
crypto/dist/ssh/clientloop.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
111
crypto/dist/ssh/compat.c
vendored
Normal file
111
crypto/dist/ssh/compat.c
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/* $NetBSD: compat.c,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: compat.c,v 1.23 2000/09/07 21:13:37 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: compat.c,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.h"
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
int datafellows = 0;
|
||||
|
||||
void
|
||||
enable_compat20(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 2.0");
|
||||
compat20 = 1;
|
||||
}
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
||||
/* datafellows bug compatibility */
|
||||
void
|
||||
compat_datafellows(const char *version)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
struct {
|
||||
char *version;
|
||||
int bugs;
|
||||
} check[] = {
|
||||
{"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
|
||||
{"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
|
||||
{"2.", SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
|
||||
{NULL, 0}
|
||||
};
|
||||
/* process table, return first match */
|
||||
for (i = 0; check[i].version; i++) {
|
||||
len = strlen(check[i].version);
|
||||
if (strlen(version) >= len &&
|
||||
(strncmp(version, check[i].version, len) == 0)) {
|
||||
verbose("datafellows: %.200s", version);
|
||||
datafellows = check[i].bugs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SEP ","
|
||||
int
|
||||
proto_spec(const char *spec)
|
||||
{
|
||||
char *s, *p, *q;
|
||||
int ret = SSH_PROTO_UNKNOWN;
|
||||
|
||||
if (spec == NULL)
|
||||
return ret;
|
||||
q = s = xstrdup(spec);
|
||||
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
|
||||
switch(atoi(p)) {
|
||||
case 1:
|
||||
if (ret == SSH_PROTO_UNKNOWN)
|
||||
ret |= SSH_PROTO_1_PREFERRED;
|
||||
ret |= SSH_PROTO_1;
|
||||
break;
|
||||
case 2:
|
||||
ret |= SSH_PROTO_2;
|
||||
break;
|
||||
default:
|
||||
log("ignoring bad proto spec: '%s'.", p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xfree(s);
|
||||
return ret;
|
||||
}
|
50
crypto/dist/ssh/compat.h
vendored
Normal file
50
crypto/dist/ssh/compat.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/* $NetBSD: compat.h,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: compat.h,v 1.10 2000/09/07 20:27:50 deraadt Exp */
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
|
||||
#define SSH_PROTO_UNKNOWN 0x00
|
||||
#define SSH_PROTO_1 0x01
|
||||
#define SSH_PROTO_1_PREFERRED 0x02
|
||||
#define SSH_PROTO_2 0x04
|
||||
|
||||
#define SSH_BUG_SIGBLOB 0x01
|
||||
#define SSH_BUG_PUBKEYAUTH 0x02
|
||||
#define SSH_BUG_HMAC 0x04
|
||||
#define SSH_BUG_X11FWD 0x08
|
||||
#define SSH_COMPAT_SESSIONID_ENCODING 0x10
|
||||
|
||||
void enable_compat13(void);
|
||||
void enable_compat20(void);
|
||||
void compat_datafellows(const char *s);
|
||||
int proto_spec(const char *spec);
|
||||
extern int compat13;
|
||||
extern int compat20;
|
||||
extern int datafellows;
|
||||
#endif
|
150
crypto/dist/ssh/compress.c
vendored
Normal file
150
crypto/dist/ssh/compress.c
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
/* $NetBSD: compress.c,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: compress.c,v 1.9 2000/09/07 20:27:50 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: compress.c,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "compress.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 = (unsigned char *) buffer_ptr(input_buffer);
|
||||
outgoing_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
/* Loop compressing until deflate() returns with avail_out != 0. */
|
||||
do {
|
||||
/* Set up fixed-size output buffer. */
|
||||
outgoing_stream.next_out = (unsigned char *)buf;
|
||||
outgoing_stream.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;
|
||||
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 = (unsigned char *) buffer_ptr(input_buffer);
|
||||
incoming_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
for (;;) {
|
||||
/* Set up fixed-size output buffer. */
|
||||
incoming_stream.next_out = (unsigned char *) buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
|
||||
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
fatal("buffer_uncompress: inflate returned %d", status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
}
|
50
crypto/dist/ssh/compress.h
vendored
Normal file
50
crypto/dist/ssh/compress.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/* $NetBSD: compress.h,v 1.1.1.1 2000/09/28 22:10:00 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: compress.h,v 1.6 2000/09/07 20:27:50 deraadt 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(void);
|
||||
|
||||
/*
|
||||
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||
* compressed using this function will form a single compressed data stream;
|
||||
* however, data will be flushed at the end of every call so that each
|
||||
* output_buffer can be decompressed independently (but in the appropriate
|
||||
* order since they together form a single compression stream) by the
|
||||
* receiver. This appends the compressed data to the output buffer.
|
||||
*/
|
||||
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
/*
|
||||
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||
* uncompressed using this function will form a single compressed data
|
||||
* stream; however, data will be flushed at the end of every call so that
|
||||
* each output_buffer. This must be called for the same size units that the
|
||||
* buffer_compress was called, and in the same order that buffers compressed
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
#endif /* COMPRESS_H */
|
119
crypto/dist/ssh/crc32.c
vendored
Normal file
119
crypto/dist/ssh/crc32.c
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
/* $NetBSD: crc32.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* from OpenBSD: crc32.c,v 1.7 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: crc32.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
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
|
||||
ssh_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/dist/ssh/crc32.h
vendored
Normal file
27
crypto/dist/ssh/crc32.h
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/* $NetBSD: crc32.h,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for computing 32-bit CRC.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: crc32.h,v 1.8 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
||||
/*
|
||||
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
|
||||
* The polynomial used is 0xedb88320.
|
||||
*/
|
||||
unsigned int ssh_crc32(const unsigned char *buf, unsigned int len);
|
||||
|
||||
#endif /* CRC32_H */
|
163
crypto/dist/ssh/deattack.c
vendored
Normal file
163
crypto/dist/ssh/deattack.c
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/* $NetBSD: deattack.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej 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>
|
||||
*/
|
||||
|
||||
/* from OpenBSD: deattack.c,v 1.9 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: deattack.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
static void
|
||||
crc_update(u_int32_t *a, u_int32_t b)
|
||||
{
|
||||
b ^= *a;
|
||||
*a = ssh_crc32((unsigned char *) &b, sizeof(b));
|
||||
}
|
||||
|
||||
/* detect if a block is used in a particular pattern */
|
||||
static 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);
|
||||
}
|
30
crypto/dist/ssh/deattack.h
vendored
Normal file
30
crypto/dist/ssh/deattack.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/* $NetBSD: deattack.h,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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
|
82
crypto/dist/ssh/dispatch.c
vendored
Normal file
82
crypto/dist/ssh/dispatch.c
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/* $NetBSD: dispatch.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: dispatch.c,v 1.5 2000/09/21 11:25:34 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: dispatch.c,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include "dispatch.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define DISPATCH_MIN 0
|
||||
#define DISPATCH_MAX 255
|
||||
|
||||
dispatch_fn *dispatch[DISPATCH_MAX];
|
||||
|
||||
void
|
||||
dispatch_protocol_error(int type, int plen, void *ctxt)
|
||||
{
|
||||
error("Hm, dispatch protocol error: type %d plen %d", type, plen);
|
||||
}
|
||||
void
|
||||
dispatch_init(dispatch_fn *dflt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DISPATCH_MAX; i++)
|
||||
dispatch[i] = dflt;
|
||||
}
|
||||
void
|
||||
dispatch_set(int type, dispatch_fn *fn)
|
||||
{
|
||||
dispatch[type] = fn;
|
||||
}
|
||||
void
|
||||
dispatch_run(int mode, int *done, void *ctxt)
|
||||
{
|
||||
for (;;) {
|
||||
int plen;
|
||||
int type;
|
||||
|
||||
if (mode == DISPATCH_BLOCK) {
|
||||
type = packet_read(&plen);
|
||||
} else {
|
||||
type = packet_read_poll(&plen);
|
||||
if (type == SSH_MSG_NONE)
|
||||
return;
|
||||
}
|
||||
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
|
||||
(*dispatch[type])(type, plen, ctxt);
|
||||
else
|
||||
packet_disconnect("protocol error: rcvd type %d", type);
|
||||
if (done != NULL && *done)
|
||||
return;
|
||||
}
|
||||
}
|
37
crypto/dist/ssh/dispatch.h
vendored
Normal file
37
crypto/dist/ssh/dispatch.h
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/* $NetBSD: dispatch.h,v 1.1.1.1 2000/09/28 22:10:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
enum {
|
||||
DISPATCH_BLOCK,
|
||||
DISPATCH_NONBLOCK
|
||||
};
|
||||
|
||||
typedef void dispatch_fn(int type, int plen, void *ctxt);
|
||||
|
||||
void dispatch_init(dispatch_fn *dflt);
|
||||
void dispatch_set(int type, dispatch_fn *fn);
|
||||
void dispatch_run(int mode, int *done, void *ctxt);
|
||||
void dispatch_protocol_error(int type, int plen, void *ctxt);
|
313
crypto/dist/ssh/dsa.c
vendored
Normal file
313
crypto/dist/ssh/dsa.c
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
/* $NetBSD: dsa.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: dsa.c,v 1.11 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: dsa.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
#include "kex.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define INTBLOB_LEN 20
|
||||
#define SIGBLOB_LEN (2*INTBLOB_LEN)
|
||||
|
||||
Key *
|
||||
dsa_key_from_blob(char *blob, int blen)
|
||||
{
|
||||
Buffer b;
|
||||
char *ktype;
|
||||
int rlen;
|
||||
DSA *dsa;
|
||||
Key *key;
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
dump_base64(stderr, blob, blen);
|
||||
#endif
|
||||
/* fetch & parse DSA/DSS pubkey */
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, blob, blen);
|
||||
ktype = buffer_get_string(&b, NULL);
|
||||
if (strcmp(KEX_DSS, ktype) != 0) {
|
||||
error("dsa_key_from_blob: cannot handle type %s", ktype);
|
||||
buffer_free(&b);
|
||||
xfree(ktype);
|
||||
return NULL;
|
||||
}
|
||||
key = key_new(KEY_DSA);
|
||||
dsa = key->dsa;
|
||||
buffer_get_bignum2(&b, dsa->p);
|
||||
buffer_get_bignum2(&b, dsa->q);
|
||||
buffer_get_bignum2(&b, dsa->g);
|
||||
buffer_get_bignum2(&b, dsa->pub_key);
|
||||
rlen = buffer_len(&b);
|
||||
if(rlen != 0)
|
||||
error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
|
||||
buffer_free(&b);
|
||||
xfree(ktype);
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
#endif
|
||||
return key;
|
||||
}
|
||||
int
|
||||
dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
|
||||
{
|
||||
Buffer b;
|
||||
int len;
|
||||
unsigned char *buf;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA)
|
||||
return 0;
|
||||
buffer_init(&b);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_bignum2(&b, key->dsa->p);
|
||||
buffer_put_bignum2(&b, key->dsa->q);
|
||||
buffer_put_bignum2(&b, key->dsa->g);
|
||||
buffer_put_bignum2(&b, key->dsa->pub_key);
|
||||
len = buffer_len(&b);
|
||||
buf = xmalloc(len);
|
||||
memcpy(buf, buffer_ptr(&b), len);
|
||||
memset(buffer_ptr(&b), 0, len);
|
||||
buffer_free(&b);
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
if (blobp != NULL)
|
||||
*blobp = buf;
|
||||
return len;
|
||||
}
|
||||
int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
unsigned char *digest;
|
||||
unsigned char *ret;
|
||||
DSA_SIG *sig;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
unsigned int rlen;
|
||||
unsigned int slen;
|
||||
unsigned int len;
|
||||
unsigned char sigblob[SIGBLOB_LEN];
|
||||
Buffer b;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
|
||||
error("dsa_sign: no DSA key");
|
||||
return -1;
|
||||
}
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
|
||||
if (sig == NULL) {
|
||||
fatal("dsa_sign: cannot sign");
|
||||
}
|
||||
|
||||
rlen = BN_num_bytes(sig->r);
|
||||
slen = BN_num_bytes(sig->s);
|
||||
if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
|
||||
error("bad sig size %d %d", rlen, slen);
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
debug("sig size %d %d", rlen, slen);
|
||||
|
||||
memset(sigblob, 0, SIGBLOB_LEN);
|
||||
BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
|
||||
BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
if (datafellows & SSH_BUG_SIGBLOB) {
|
||||
debug("datafellows");
|
||||
ret = xmalloc(SIGBLOB_LEN);
|
||||
memcpy(ret, sigblob, SIGBLOB_LEN);
|
||||
if (lenp != NULL)
|
||||
*lenp = SIGBLOB_LEN;
|
||||
if (sigp != NULL)
|
||||
*sigp = ret;
|
||||
} else {
|
||||
/* ietf-drafts */
|
||||
buffer_init(&b);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, sigblob, SIGBLOB_LEN);
|
||||
len = buffer_len(&b);
|
||||
ret = xmalloc(len);
|
||||
memcpy(ret, buffer_ptr(&b), len);
|
||||
buffer_free(&b);
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
if (sigp != NULL)
|
||||
*sigp = ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
Buffer b;
|
||||
unsigned char *digest;
|
||||
DSA_SIG *sig;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
unsigned char *sigblob;
|
||||
char *txt;
|
||||
unsigned int len;
|
||||
int rlen;
|
||||
int ret;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
|
||||
error("dsa_verify: no DSA key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(datafellows & SSH_BUG_SIGBLOB) &&
|
||||
signaturelen == SIGBLOB_LEN) {
|
||||
datafellows |= ~SSH_BUG_SIGBLOB;
|
||||
log("autodetect SSH_BUG_SIGBLOB");
|
||||
} else if ((datafellows & SSH_BUG_SIGBLOB) &&
|
||||
signaturelen != SIGBLOB_LEN) {
|
||||
log("autoremove SSH_BUG_SIGBLOB");
|
||||
datafellows &= ~SSH_BUG_SIGBLOB;
|
||||
}
|
||||
|
||||
debug("len %d datafellows %d", signaturelen, datafellows);
|
||||
|
||||
/* fetch signature */
|
||||
if (datafellows & SSH_BUG_SIGBLOB) {
|
||||
sigblob = signature;
|
||||
len = signaturelen;
|
||||
} else {
|
||||
/* ietf-drafts */
|
||||
char *ktype;
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, (char *) signature, signaturelen);
|
||||
ktype = buffer_get_string(&b, NULL);
|
||||
if (strcmp(KEX_DSS, ktype) != 0) {
|
||||
error("dsa_verify: cannot handle type %s", ktype);
|
||||
buffer_free(&b);
|
||||
return -1;
|
||||
}
|
||||
sigblob = (unsigned char *)buffer_get_string(&b, &len);
|
||||
rlen = buffer_len(&b);
|
||||
if(rlen != 0) {
|
||||
error("remaining bytes in signature %d", rlen);
|
||||
buffer_free(&b);
|
||||
return -1;
|
||||
}
|
||||
buffer_free(&b);
|
||||
xfree(ktype);
|
||||
}
|
||||
|
||||
if (len != SIGBLOB_LEN) {
|
||||
fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
|
||||
}
|
||||
|
||||
/* parse signature */
|
||||
sig = DSA_SIG_new();
|
||||
sig->r = BN_new();
|
||||
sig->s = BN_new();
|
||||
BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
|
||||
BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
|
||||
|
||||
if (!(datafellows & SSH_BUG_SIGBLOB)) {
|
||||
memset(sigblob, 0, len);
|
||||
xfree(sigblob);
|
||||
}
|
||||
|
||||
/* sha1 the data */
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
|
||||
|
||||
memset(digest, 0, evp_md->md_size);
|
||||
xfree(digest);
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
switch (ret) {
|
||||
case 1:
|
||||
txt = "correct";
|
||||
break;
|
||||
case 0:
|
||||
txt = "incorrect";
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
txt = "error";
|
||||
break;
|
||||
}
|
||||
debug("dsa_verify: signature %s", txt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits)
|
||||
{
|
||||
DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
|
||||
Key *k;
|
||||
if (dsa == NULL) {
|
||||
fatal("DSA_generate_parameters failed");
|
||||
}
|
||||
if (!DSA_generate_key(dsa)) {
|
||||
fatal("DSA_generate_keys failed");
|
||||
}
|
||||
|
||||
k = key_new(KEY_EMPTY);
|
||||
k->type = KEY_DSA;
|
||||
k->dsa = dsa;
|
||||
return k;
|
||||
}
|
48
crypto/dist/ssh/dsa.h
vendored
Normal file
48
crypto/dist/ssh/dsa.h
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/* $NetBSD: dsa.h,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DSA_H
|
||||
#define DSA_H
|
||||
|
||||
Key *dsa_key_from_blob(char *blob, int blen);
|
||||
int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
||||
|
||||
int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits);
|
||||
|
||||
#endif
|
63
crypto/dist/ssh/getput.h
vendored
Normal file
63
crypto/dist/ssh/getput.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/* $NetBSD: getput.h,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Macros for storing and retrieving data in msb first and lsb first order.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: getput.h,v 1.5 2000/09/07 20:27:51 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 */
|
64
crypto/dist/ssh/hmac.c
vendored
Normal file
64
crypto/dist/ssh/hmac.c
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/* $NetBSD: hmac.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: hmac.c,v 1.4 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: hmac.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include "hmac.h"
|
||||
|
||||
unsigned char *
|
||||
hmac(
|
||||
EVP_MD *evp_md,
|
||||
unsigned int seqno,
|
||||
unsigned char *data, int datalen,
|
||||
unsigned char *key, int keylen)
|
||||
{
|
||||
HMAC_CTX c;
|
||||
static unsigned char m[EVP_MAX_MD_SIZE];
|
||||
unsigned char b[4];
|
||||
|
||||
if (key == NULL)
|
||||
fatal("hmac: no key");
|
||||
HMAC_Init(&c, key, keylen, evp_md);
|
||||
PUT_32BIT(b, seqno);
|
||||
HMAC_Update(&c, b, sizeof b);
|
||||
HMAC_Update(&c, data, datalen);
|
||||
HMAC_Final(&c, m, NULL);
|
||||
HMAC_cleanup(&c);
|
||||
return(m);
|
||||
}
|
37
crypto/dist/ssh/hmac.h
vendored
Normal file
37
crypto/dist/ssh/hmac.h
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/* $NetBSD: hmac.h,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HMAC_H
|
||||
#define HMAC_H
|
||||
|
||||
unsigned char *
|
||||
hmac(
|
||||
EVP_MD *evp_md,
|
||||
unsigned int seqno,
|
||||
unsigned char *data, int datalen,
|
||||
unsigned char *key, int len);
|
||||
|
||||
#endif
|
224
crypto/dist/ssh/hostfile.c
vendored
Normal file
224
crypto/dist/ssh/hostfile.c
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/* $NetBSD: hostfile.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for manipulating the known hosts files.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 1999 Niels Provos. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: hostfile.c,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "packet.h"
|
||||
#include "match.h"
|
||||
#include "ssh.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
/*
|
||||
* Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
|
||||
* pointer over the key. Skips any whitespace at the beginning and at end.
|
||||
*/
|
||||
|
||||
static int
|
||||
hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
|
||||
{
|
||||
unsigned int bits;
|
||||
char *cp;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
bits = key_read(ret, &cp);
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
*bitsp = bits;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
||||
{
|
||||
Key *k = key_new(KEY_RSA);
|
||||
int ret = hostfile_read_key(cpp, bitsp, k);
|
||||
BN_copy(e, k->rsa->e);
|
||||
BN_copy(n, k->rsa->n);
|
||||
key_free(k);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
|
||||
{
|
||||
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL)
|
||||
return 1;
|
||||
if (bits != BN_num_bits(key->rsa->n)) {
|
||||
log("Warning: %s, line %d: keysize mismatch for host %s: "
|
||||
"actual %d vs. announced %d.",
|
||||
filename, linenum, host, BN_num_bits(key->rsa->n), bits);
|
||||
log("Warning: replace %d with %d in %s, line %d.",
|
||||
bits, BN_num_bits(key->rsa->n), filename, linenum);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, Key *key, Key *found)
|
||||
{
|
||||
FILE *f;
|
||||
char line[8192];
|
||||
int linenum = 0;
|
||||
unsigned int kbits, hostlen;
|
||||
char *cp, *cp2;
|
||||
HostStatus end_return;
|
||||
|
||||
if (key == NULL)
|
||||
fatal("no key to look up");
|
||||
/* 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)) != 1)
|
||||
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 (!hostfile_read_key(&cp, &kbits, found))
|
||||
continue;
|
||||
if (!hostfile_check_key(kbits, found, host, filename, linenum))
|
||||
continue;
|
||||
|
||||
/* Check if the current key is the same as the given key. */
|
||||
if (key_equal(key, found)) {
|
||||
/* 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, Key *key)
|
||||
{
|
||||
FILE *f;
|
||||
int success = 0;
|
||||
if (key == NULL)
|
||||
return 1; /* XXX ? */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
fprintf(f, "%s ", host);
|
||||
if (key_write(key, f)) {
|
||||
success = 1;
|
||||
} else {
|
||||
error("add_host_to_hostfile: saving key in %s failed", filename);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
return success;
|
||||
}
|
36
crypto/dist/ssh/hostfile.h
vendored
Normal file
36
crypto/dist/ssh/hostfile.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/* $NetBSD: hostfile.h,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef HOSTFILE_H
|
||||
#define HOSTFILE_H
|
||||
|
||||
/*
|
||||
* 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, Key *key, Key *found);
|
||||
|
||||
/*
|
||||
* Appends an entry to the host file. Returns false if the entry could not
|
||||
* be appended.
|
||||
*/
|
||||
int add_host_to_hostfile(const char *filename, const char *host, Key *key);
|
||||
|
||||
#endif
|
63
crypto/dist/ssh/includes.h
vendored
Normal file
63
crypto/dist/ssh/includes.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/* $NetBSD: includes.h,v 1.1.1.1 2000/09/28 22:10:02 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* This file includes most of the needed system headers.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
||||
#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 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 */
|
478
crypto/dist/ssh/kex.c
vendored
Normal file
478
crypto/dist/ssh/kex.c
vendored
Normal file
@ -0,0 +1,478 @@
|
||||
/* $NetBSD: kex.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: kex.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "ssh2.h"
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "kex.h"
|
||||
|
||||
#define KEX_COOKIE_LEN 16
|
||||
|
||||
Buffer *
|
||||
kex_init(char *myproposal[PROPOSAL_MAX])
|
||||
{
|
||||
int first_kex_packet_follows = 0;
|
||||
unsigned char cookie[KEX_COOKIE_LEN];
|
||||
u_int32_t rand = 0;
|
||||
int i;
|
||||
Buffer *ki = xmalloc(sizeof(*ki));
|
||||
for (i = 0; i < KEX_COOKIE_LEN; i++) {
|
||||
if (i % 4 == 0) {
|
||||
/* XXXthorpej */
|
||||
RAND_pseudo_bytes((u_char *)&rand, sizeof(rand));
|
||||
}
|
||||
cookie[i] = rand & 0xff;
|
||||
rand >>= 8;
|
||||
}
|
||||
buffer_init(ki);
|
||||
buffer_append(ki, (char *)cookie, sizeof cookie);
|
||||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
buffer_put_cstring(ki, myproposal[i]);
|
||||
buffer_put_char(ki, first_kex_packet_follows);
|
||||
buffer_put_int(ki, 0); /* uint32 reserved */
|
||||
return ki;
|
||||
}
|
||||
|
||||
/* send kexinit, parse and save reply */
|
||||
void
|
||||
kex_exchange_kexinit(
|
||||
Buffer *my_kexinit, Buffer *peer_kexint,
|
||||
char *peer_proposal[PROPOSAL_MAX])
|
||||
{
|
||||
int i;
|
||||
char *ptr;
|
||||
int plen;
|
||||
|
||||
debug("send KEXINIT");
|
||||
packet_start(SSH2_MSG_KEXINIT);
|
||||
packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done");
|
||||
|
||||
/*
|
||||
* read and save raw KEXINIT payload in buffer. this is used during
|
||||
* computation of the session_id and the session keys.
|
||||
*/
|
||||
debug("wait KEXINIT");
|
||||
packet_read_expect(&plen, SSH2_MSG_KEXINIT);
|
||||
ptr = packet_get_raw(&plen);
|
||||
buffer_append(peer_kexint, ptr, plen);
|
||||
|
||||
/* parse packet and save algorithm proposal */
|
||||
/* skip cookie */
|
||||
for (i = 0; i < KEX_COOKIE_LEN; i++)
|
||||
packet_get_char();
|
||||
/* extract kex init proposal strings */
|
||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||
peer_proposal[i] = packet_get_string(NULL);
|
||||
debug("got kexinit: %s", peer_proposal[i]);
|
||||
}
|
||||
/* first kex follow / reserved */
|
||||
i = packet_get_char();
|
||||
debug("first kex follow: %d ", i);
|
||||
i = packet_get_int();
|
||||
debug("reserved: %d ", i);
|
||||
packet_done();
|
||||
debug("done");
|
||||
}
|
||||
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
|
||||
int
|
||||
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
|
||||
{
|
||||
int i;
|
||||
int n = BN_num_bits(dh_pub);
|
||||
int bits_set = 0;
|
||||
|
||||
/* we only accept g==2 */
|
||||
if (!BN_is_word(dh->g, 2)) {
|
||||
log("invalid DH base != 2");
|
||||
return 0;
|
||||
}
|
||||
if (dh_pub->neg) {
|
||||
log("invalid public DH value: negativ");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i <= n; i++)
|
||||
if (BN_is_bit_set(dh_pub, i))
|
||||
bits_set++;
|
||||
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
|
||||
|
||||
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
|
||||
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
|
||||
return 1;
|
||||
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group1()
|
||||
{
|
||||
static char *group1 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
DH *dh;
|
||||
int ret, tries = 0;
|
||||
dh = DH_new();
|
||||
if(dh == NULL)
|
||||
fatal("DH_new");
|
||||
ret = BN_hex2bn(&dh->p, group1);
|
||||
if(ret<0)
|
||||
fatal("BN_hex2bn");
|
||||
dh->g = BN_new();
|
||||
if(dh->g == NULL)
|
||||
fatal("DH_new g");
|
||||
BN_set_word(dh->g, 2);
|
||||
do {
|
||||
if (DH_generate_key(dh) == 0)
|
||||
fatal("DH_generate_key");
|
||||
if (tries++ > 10)
|
||||
fatal("dh_new_group1: too many bad keys: giving up");
|
||||
} while (!dh_pub_is_valid(dh, dh->pub_key));
|
||||
return dh;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
static void
|
||||
dump_digest(unsigned char *digest, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i< len; i++){
|
||||
fprintf(stderr, "%02x", digest[i]);
|
||||
if(i%2!=0)
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char *
|
||||
kex_hash(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret)
|
||||
{
|
||||
Buffer b;
|
||||
static unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_put_string(&b, client_version_string, strlen(client_version_string));
|
||||
buffer_put_string(&b, server_version_string, strlen(server_version_string));
|
||||
|
||||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
|
||||
buffer_put_int(&b, ckexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, ckexinit, ckexinitlen);
|
||||
buffer_put_int(&b, skexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, skexinit, skexinitlen);
|
||||
|
||||
buffer_put_string(&b, serverhostkeyblob, sbloblen);
|
||||
buffer_put_bignum2(&b, client_dh_pub);
|
||||
buffer_put_bignum2(&b, server_dh_pub);
|
||||
buffer_put_bignum2(&b, shared_secret);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
buffer_free(&b);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
dump_digest(digest, evp_md->md_size);
|
||||
#endif
|
||||
return digest;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
|
||||
{
|
||||
Buffer b;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
char c = id;
|
||||
int have;
|
||||
int mdsz = evp_md->md_size;
|
||||
unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_put_bignum2(&b, shared_secret);
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
|
||||
EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
|
||||
EVP_DigestUpdate(&md, &c, 1); /* key id */
|
||||
EVP_DigestUpdate(&md, hash, mdsz); /* session id */
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
/* expand */
|
||||
for (have = mdsz; need > have; have += mdsz) {
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
|
||||
EVP_DigestUpdate(&md, hash, mdsz);
|
||||
EVP_DigestUpdate(&md, digest, have);
|
||||
EVP_DigestFinal(&md, digest + have, NULL);
|
||||
}
|
||||
buffer_free(&b);
|
||||
#ifdef DEBUG_KEX
|
||||
fprintf(stderr, "Digest '%c'== ", c);
|
||||
dump_digest(digest, need);
|
||||
#endif
|
||||
return digest;
|
||||
}
|
||||
|
||||
#define NKEYS 6
|
||||
|
||||
#define MAX_PROP 20
|
||||
#define SEP ","
|
||||
|
||||
static char *
|
||||
get_match(char *client, char *server)
|
||||
{
|
||||
char *sproposals[MAX_PROP];
|
||||
char *c, *s, *p, *ret, *cp, *sp;
|
||||
int i, j, nproposals;
|
||||
|
||||
c = cp = xstrdup(client);
|
||||
s = sp = xstrdup(server);
|
||||
|
||||
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
|
||||
(p = strsep(&sp, SEP)), i++) {
|
||||
if (i < MAX_PROP)
|
||||
sproposals[i] = p;
|
||||
else
|
||||
break;
|
||||
}
|
||||
nproposals = i;
|
||||
|
||||
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
|
||||
(p = strsep(&cp, SEP)), i++) {
|
||||
for (j = 0; j < nproposals; j++) {
|
||||
if (strcmp(p, sproposals[j]) == 0) {
|
||||
ret = xstrdup(p);
|
||||
xfree(c);
|
||||
xfree(s);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree(c);
|
||||
xfree(s);
|
||||
return NULL;
|
||||
}
|
||||
static void
|
||||
choose_enc(Enc *enc, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching cipher found: client %s server %s", client, server);
|
||||
enc->type = cipher_number(name);
|
||||
|
||||
switch (enc->type) {
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
enc->key_len = 24;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 0;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
default:
|
||||
fatal("unsupported cipher %s", name);
|
||||
}
|
||||
enc->name = name;
|
||||
enc->enabled = 0;
|
||||
enc->iv = NULL;
|
||||
enc->key = NULL;
|
||||
}
|
||||
static void
|
||||
choose_mac(Mac *mac, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching mac found: client %s server %s", client, server);
|
||||
if (strcmp(name, "hmac-md5") == 0) {
|
||||
mac->md = EVP_md5();
|
||||
} else if (strcmp(name, "hmac-sha1") == 0) {
|
||||
mac->md = EVP_sha1();
|
||||
} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
|
||||
mac->md = EVP_ripemd160();
|
||||
} else {
|
||||
fatal("unsupported mac %s", name);
|
||||
}
|
||||
mac->name = name;
|
||||
mac->mac_len = mac->md->md_size;
|
||||
mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
|
||||
mac->key = NULL;
|
||||
mac->enabled = 0;
|
||||
}
|
||||
static void
|
||||
choose_comp(Comp *comp, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching comp found: client %s server %s", client, server);
|
||||
if (strcmp(name, "zlib") == 0) {
|
||||
comp->type = 1;
|
||||
} else if (strcmp(name, "none") == 0) {
|
||||
comp->type = 0;
|
||||
} else {
|
||||
fatal("unsupported comp %s", name);
|
||||
}
|
||||
comp->name = name;
|
||||
}
|
||||
static void
|
||||
choose_kex(Kex *k, char *client, char *server)
|
||||
{
|
||||
k->name = get_match(client, server);
|
||||
if (k->name == NULL)
|
||||
fatal("no kex alg");
|
||||
if (strcmp(k->name, KEX_DH1) != 0)
|
||||
fatal("bad kex alg %s", k->name);
|
||||
}
|
||||
static void
|
||||
choose_hostkeyalg(Kex *k, char *client, char *server)
|
||||
{
|
||||
k->hostkeyalg = get_match(client, server);
|
||||
if (k->hostkeyalg == NULL)
|
||||
fatal("no hostkey alg");
|
||||
if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
|
||||
fatal("bad hostkey alg %s", k->hostkeyalg);
|
||||
}
|
||||
|
||||
Kex *
|
||||
kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
|
||||
{
|
||||
int mode;
|
||||
int ctos; /* direction: if true client-to-server */
|
||||
int need;
|
||||
Kex *k;
|
||||
|
||||
k = xmalloc(sizeof(*k));
|
||||
memset(k, 0, sizeof(*k));
|
||||
k->server = server;
|
||||
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
int nenc, nmac, ncomp;
|
||||
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
|
||||
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
|
||||
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
|
||||
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
|
||||
choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
|
||||
choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
|
||||
choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
|
||||
debug("kex: %s %s %s %s",
|
||||
ctos ? "client->server" : "server->client",
|
||||
k->enc[mode].name,
|
||||
k->mac[mode].name,
|
||||
k->comp[mode].name);
|
||||
}
|
||||
choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
|
||||
choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
|
||||
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
|
||||
need = 0;
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
if (need < k->enc[mode].key_len)
|
||||
need = k->enc[mode].key_len;
|
||||
if (need < k->enc[mode].iv_len)
|
||||
need = k->enc[mode].iv_len;
|
||||
if (need < k->mac[mode].key_len)
|
||||
need = k->mac[mode].key_len;
|
||||
}
|
||||
/* XXX need runden? */
|
||||
k->we_need = need;
|
||||
return k;
|
||||
}
|
||||
|
||||
int
|
||||
kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
|
||||
{
|
||||
int i;
|
||||
int mode;
|
||||
int ctos;
|
||||
unsigned char *keys[NKEYS];
|
||||
|
||||
for (i = 0; i < NKEYS; i++)
|
||||
keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
|
||||
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
|
||||
k->enc[mode].iv = keys[ctos ? 0 : 1];
|
||||
k->enc[mode].key = keys[ctos ? 2 : 3];
|
||||
k->mac[mode].key = keys[ctos ? 4 : 5];
|
||||
}
|
||||
return 0;
|
||||
}
|
114
crypto/dist/ssh/kex.h
vendored
Normal file
114
crypto/dist/ssh/kex.h
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/* $NetBSD: kex.h,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef KEX_H
|
||||
#define KEX_H
|
||||
|
||||
#define KEX_DH1 "diffie-hellman-group1-sha1"
|
||||
#define KEX_DSS "ssh-dss"
|
||||
|
||||
enum kex_init_proposals {
|
||||
PROPOSAL_KEX_ALGS,
|
||||
PROPOSAL_SERVER_HOST_KEY_ALGS,
|
||||
PROPOSAL_ENC_ALGS_CTOS,
|
||||
PROPOSAL_ENC_ALGS_STOC,
|
||||
PROPOSAL_MAC_ALGS_CTOS,
|
||||
PROPOSAL_MAC_ALGS_STOC,
|
||||
PROPOSAL_COMP_ALGS_CTOS,
|
||||
PROPOSAL_COMP_ALGS_STOC,
|
||||
PROPOSAL_LANG_CTOS,
|
||||
PROPOSAL_LANG_STOC,
|
||||
PROPOSAL_MAX
|
||||
};
|
||||
|
||||
enum kex_modes {
|
||||
MODE_IN,
|
||||
MODE_OUT,
|
||||
MODE_MAX
|
||||
};
|
||||
|
||||
typedef struct Kex Kex;
|
||||
typedef struct Mac Mac;
|
||||
typedef struct Comp Comp;
|
||||
typedef struct Enc Enc;
|
||||
|
||||
struct Enc {
|
||||
int type;
|
||||
int enabled;
|
||||
int block_size;
|
||||
unsigned char *key;
|
||||
unsigned char *iv;
|
||||
int key_len;
|
||||
int iv_len;
|
||||
char *name;
|
||||
};
|
||||
struct Mac {
|
||||
EVP_MD *md;
|
||||
int enabled;
|
||||
int mac_len;
|
||||
unsigned char *key;
|
||||
int key_len;
|
||||
char *name;
|
||||
};
|
||||
struct Comp {
|
||||
int type;
|
||||
int enabled;
|
||||
char *name;
|
||||
};
|
||||
struct Kex {
|
||||
Enc enc [MODE_MAX];
|
||||
Mac mac [MODE_MAX];
|
||||
Comp comp[MODE_MAX];
|
||||
int we_need;
|
||||
int server;
|
||||
char *name;
|
||||
char *hostkeyalg;
|
||||
};
|
||||
|
||||
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
|
||||
void
|
||||
kex_exchange_kexinit(
|
||||
Buffer *my_kexinit, Buffer *peer_kexint,
|
||||
char *peer_proposal[PROPOSAL_MAX]);
|
||||
Kex *
|
||||
kex_choose_conf(char *cprop[PROPOSAL_MAX],
|
||||
char *sprop[PROPOSAL_MAX], int server);
|
||||
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
|
||||
void packet_set_kex(Kex *k);
|
||||
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
|
||||
DH *dh_new_group1(void);
|
||||
|
||||
unsigned char *
|
||||
kex_hash(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret);
|
||||
|
||||
#endif
|
362
crypto/dist/ssh/key.c
vendored
Normal file
362
crypto/dist/ssh/key.c
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
/* $NetBSD: key.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* read_bignum():
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* read_bignum():
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
*/
|
||||
|
||||
/* from OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: key.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define SSH_DSS "ssh-dss"
|
||||
|
||||
Key *
|
||||
key_new(int type)
|
||||
{
|
||||
Key *k;
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
k = xmalloc(sizeof(*k));
|
||||
k->type = type;
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
rsa = RSA_new();
|
||||
rsa->n = BN_new();
|
||||
rsa->e = BN_new();
|
||||
k->rsa = rsa;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
dsa = DSA_new();
|
||||
dsa->p = BN_new();
|
||||
dsa->q = BN_new();
|
||||
dsa->g = BN_new();
|
||||
dsa->pub_key = BN_new();
|
||||
k->dsa = dsa;
|
||||
break;
|
||||
case KEY_EMPTY:
|
||||
break;
|
||||
default:
|
||||
fatal("key_new: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
void
|
||||
key_free(Key *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
if (k->rsa != NULL)
|
||||
RSA_free(k->rsa);
|
||||
k->rsa = NULL;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
if (k->dsa != NULL)
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = NULL;
|
||||
break;
|
||||
default:
|
||||
fatal("key_free: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
xfree(k);
|
||||
}
|
||||
int
|
||||
key_equal(Key *a, Key *b)
|
||||
{
|
||||
if (a == NULL || b == NULL || a->type != b->type)
|
||||
return 0;
|
||||
switch (a->type) {
|
||||
case KEY_RSA:
|
||||
return a->rsa != NULL && b->rsa != NULL &&
|
||||
BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
|
||||
BN_cmp(a->rsa->n, b->rsa->n) == 0;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return a->dsa != NULL && b->dsa != NULL &&
|
||||
BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
|
||||
BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
|
||||
BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
|
||||
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
|
||||
break;
|
||||
default:
|
||||
fatal("key_equal: bad key type %d", a->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate key fingerprint in ascii format.
|
||||
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
|
||||
*/
|
||||
char *
|
||||
key_fingerprint(Key *k)
|
||||
{
|
||||
static char retval[(EVP_MAX_MD_SIZE+1)*3];
|
||||
unsigned char *blob = NULL;
|
||||
int len = 0;
|
||||
int nlen, elen;
|
||||
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
nlen = BN_num_bytes(k->rsa->n);
|
||||
elen = BN_num_bytes(k->rsa->e);
|
||||
len = nlen + elen;
|
||||
blob = xmalloc(len);
|
||||
BN_bn2bin(k->rsa->n, blob);
|
||||
BN_bn2bin(k->rsa->e, blob + nlen);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
break;
|
||||
default:
|
||||
fatal("key_fingerprint: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
retval[0] = '\0';
|
||||
|
||||
if (blob != NULL) {
|
||||
int i;
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD *md = EVP_md5();
|
||||
EVP_MD_CTX ctx;
|
||||
EVP_DigestInit(&ctx, md);
|
||||
EVP_DigestUpdate(&ctx, blob, len);
|
||||
EVP_DigestFinal(&ctx, digest, NULL);
|
||||
for(i = 0; i < md->md_size; i++) {
|
||||
char hex[4];
|
||||
snprintf(hex, sizeof(hex), "%02x:", digest[i]);
|
||||
strlcat(retval, hex, sizeof(retval));
|
||||
}
|
||||
retval[strlen(retval) - 1] = '\0';
|
||||
memset(blob, 0, len);
|
||||
xfree(blob);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a multiple-precision integer in decimal from the buffer, and advances
|
||||
* the pointer. The integer must already be initialized. This function is
|
||||
* 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.
|
||||
*/
|
||||
static int
|
||||
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;
|
||||
}
|
||||
static int
|
||||
write_bignum(FILE *f, BIGNUM *num)
|
||||
{
|
||||
char *buf = BN_bn2dec(num);
|
||||
if (buf == NULL) {
|
||||
error("write_bignum: BN_bn2dec() failed");
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, " %s", buf);
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
unsigned int
|
||||
key_read(Key *ret, char **cpp)
|
||||
{
|
||||
Key *k;
|
||||
unsigned int bits = 0;
|
||||
char *cp;
|
||||
int len, n;
|
||||
unsigned char *blob;
|
||||
|
||||
cp = *cpp;
|
||||
|
||||
switch(ret->type) {
|
||||
case KEY_RSA:
|
||||
/* 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';
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
*cpp = cp;
|
||||
/* Get public exponent, public modulus. */
|
||||
if (!read_bignum(cpp, ret->rsa->e))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->rsa->n))
|
||||
return 0;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
if (strncmp(cp, SSH_DSS " ", 7) != 0)
|
||||
return 0;
|
||||
cp += 7;
|
||||
len = 2*strlen(cp);
|
||||
blob = xmalloc(len);
|
||||
n = uudecode(cp, blob, len);
|
||||
if (n < 0) {
|
||||
error("key_read: uudecode %s failed", cp);
|
||||
return 0;
|
||||
}
|
||||
k = dsa_key_from_blob(blob, n);
|
||||
if (k == NULL) {
|
||||
error("key_read: dsa_key_from_blob %s failed", cp);
|
||||
return 0;
|
||||
}
|
||||
xfree(blob);
|
||||
if (ret->dsa != NULL)
|
||||
DSA_free(ret->dsa);
|
||||
ret->dsa = k->dsa;
|
||||
k->dsa = NULL;
|
||||
key_free(k);
|
||||
bits = BN_num_bits(ret->dsa->p);
|
||||
/* advance cp: skip whitespace and data */
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
|
||||
cp++;
|
||||
*cpp = cp;
|
||||
break;
|
||||
default:
|
||||
fatal("key_read: bad key type: %d", ret->type);
|
||||
break;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
int
|
||||
key_write(Key *key, FILE *f)
|
||||
{
|
||||
int success = 0;
|
||||
unsigned int bits = 0;
|
||||
|
||||
if (key->type == KEY_RSA && key->rsa != NULL) {
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(key->rsa->n);
|
||||
fprintf(f, "%u", bits);
|
||||
if (write_bignum(f, key->rsa->e) &&
|
||||
write_bignum(f, key->rsa->n)) {
|
||||
success = 1;
|
||||
} else {
|
||||
error("key_write: failed for RSA key");
|
||||
}
|
||||
} else if (key->type == KEY_DSA && key->dsa != NULL) {
|
||||
int len, n;
|
||||
unsigned char *blob, *uu;
|
||||
dsa_make_key_blob(key, &blob, &len);
|
||||
uu = xmalloc(2*len);
|
||||
n = uuencode(blob, len, uu, 2*len);
|
||||
if (n > 0) {
|
||||
fprintf(f, "%s %s", SSH_DSS, uu);
|
||||
success = 1;
|
||||
}
|
||||
xfree(blob);
|
||||
xfree(uu);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
char *
|
||||
key_type(Key *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
return "RSA";
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return "DSA";
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
unsigned int
|
||||
key_size(Key *k){
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
return BN_num_bits(k->rsa->n);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return BN_num_bits(k->dsa->p);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
51
crypto/dist/ssh/key.h
vendored
Normal file
51
crypto/dist/ssh/key.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/* $NetBSD: key.h,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef KEY_H
|
||||
#define KEY_H
|
||||
|
||||
typedef struct Key Key;
|
||||
enum types {
|
||||
KEY_RSA,
|
||||
KEY_DSA,
|
||||
KEY_EMPTY
|
||||
};
|
||||
struct Key {
|
||||
int type;
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
};
|
||||
|
||||
Key *key_new(int type);
|
||||
void key_free(Key *k);
|
||||
int key_equal(Key *a, Key *b);
|
||||
char *key_fingerprint(Key *k);
|
||||
char *key_type(Key *k);
|
||||
int key_write(Key *key, FILE *f);
|
||||
unsigned int key_read(Key *key, char **cpp);
|
||||
unsigned int key_size(Key *k);
|
||||
|
||||
#endif
|
97
crypto/dist/ssh/log-client.c
vendored
Normal file
97
crypto/dist/ssh/log-client.c
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/* $NetBSD: log-client.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Client-side versions of debug(), log(), etc. These print to stderr.
|
||||
* This is a stripped down version of log-server.c.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: log-client.c,v 1.12 2000/09/12 20:53:10 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: log-client.c,v 1.1.1.1 2000/09/28 22:10:03 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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(const char *av0, LogLevel level,
|
||||
SyslogFacility facility, /* ignored */
|
||||
int on_stderr, /* ignored */
|
||||
int quiet_mode, /* ignored */
|
||||
int debug_mode /* ignored */)
|
||||
{
|
||||
|
||||
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_DEBUG1:
|
||||
case SYSLOG_LEVEL_DEBUG2:
|
||||
case SYSLOG_LEVEL_DEBUG3:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
/* unchanged */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MSGBUFSIZ 1024
|
||||
|
||||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZ];
|
||||
|
||||
if (level > log_level)
|
||||
return;
|
||||
if (level >= SYSLOG_LEVEL_DEBUG1)
|
||||
fprintf(stderr, "debug: ");
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
fprintf(stderr, "%s\r\n", msgbuf);
|
||||
}
|
191
crypto/dist/ssh/log-server.c
vendored
Normal file
191
crypto/dist/ssh/log-server.c
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
/* $NetBSD: log-server.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Server-side versions of debug(), log(), etc. These normally send the output
|
||||
* to the system log.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: log-server.c,v 1.17 2000/09/12 20:53:10 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: log-server.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <syslog.h>
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
static LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
static int log_facility = LOG_AUTH;
|
||||
|
||||
static int log_on_stderr = 0;
|
||||
static int log_quiet_mode = 0;
|
||||
static int log_debug_mode = 0;
|
||||
|
||||
/* Initialize the log.
|
||||
* av0 program name (should be argv[0])
|
||||
* on_stderr print also on stderr
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void
|
||||
log_init(const char *av0, LogLevel level, SyslogFacility facility,
|
||||
int on_stderr, int quiet_mode, int debug_mode)
|
||||
{
|
||||
|
||||
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_DEBUG1:
|
||||
case SYSLOG_LEVEL_DEBUG2:
|
||||
case SYSLOG_LEVEL_DEBUG3:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
|
||||
(int) level);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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;
|
||||
log_quiet_mode = quiet_mode;
|
||||
log_debug_mode = debug_mode;
|
||||
}
|
||||
|
||||
#define MSGBUFSIZ 1024
|
||||
|
||||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZ];
|
||||
char fmtbuf[MSGBUFSIZ];
|
||||
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_DEBUG1:
|
||||
txt = "debug1";
|
||||
pri = LOG_DEBUG;
|
||||
break;
|
||||
case SYSLOG_LEVEL_DEBUG2:
|
||||
txt = "debug2";
|
||||
pri = LOG_DEBUG;
|
||||
break;
|
||||
case SYSLOG_LEVEL_DEBUG3:
|
||||
txt = "debug3";
|
||||
pri = LOG_DEBUG;
|
||||
break;
|
||||
default:
|
||||
txt = "internal error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
}
|
||||
if (txt != NULL) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
|
||||
} else {
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
}
|
||||
if (log_on_stderr) {
|
||||
fprintf(stderr, "%s\n", msgbuf);
|
||||
} else {
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
}
|
||||
}
|
247
crypto/dist/ssh/log.c
vendored
Normal file
247
crypto/dist/ssh/log.c
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
/* $NetBSD: log.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
/*
|
||||
* Shared versions of debug(), log(), etc.
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: log.c,v 1.10 2000/09/12 20:53:10 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: log.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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_DEBUG1, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
debug2(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
debug3(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_DEBUG3, 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 },
|
||||
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
|
||||
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
|
||||
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
SyslogFacility
|
||||
log_facility_number(const 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(const 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;
|
||||
}
|
153
crypto/dist/ssh/login.c
vendored
Normal file
153
crypto/dist/ssh/login.c
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
/* $NetBSD: login.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* 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.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: login.c,v 1.15 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: login.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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(pid_t 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(pid_t pid, const char *ttyname)
|
||||
{
|
||||
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
|
||||
if (logout(line))
|
||||
logwtmp(line, "", "");
|
||||
}
|
148
crypto/dist/ssh/match.c
vendored
Normal file
148
crypto/dist/ssh/match.c
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
/* $NetBSD: match.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Simple pattern matching, with '*' and '?' as wildcards.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: match.c,v 1.9 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: match.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "match.h"
|
||||
|
||||
/*
|
||||
* Returns true if the given string matches the pattern (which may contain ?
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
|
||||
int
|
||||
match_pattern(const char *s, const char *pattern)
|
||||
{
|
||||
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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns -1 if negation matches, 1 if there is
|
||||
* a positive match, 0 if there is no match at all.
|
||||
*/
|
||||
|
||||
int
|
||||
match_hostname(const char *host, const char *pattern, 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 -1; /* Negative */
|
||||
else
|
||||
got_positive = 1; /* Positive */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return success if got a positive match. If there was a negative
|
||||
* match, we have already returned -1 and never get here.
|
||||
*/
|
||||
return got_positive;
|
||||
}
|
34
crypto/dist/ssh/match.h
vendored
Normal file
34
crypto/dist/ssh/match.h
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
/* $NetBSD: match.h,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef MATCH_H
|
||||
#define MATCH_H
|
||||
|
||||
/*
|
||||
* Returns true if the given string matches the pattern (which may contain ?
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
int match_pattern(const char *s, const char *pattern);
|
||||
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns -1 if negation matches, 1 if there is
|
||||
* a positive match, 0 if there is no match at all.
|
||||
*/
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
#endif
|
54
crypto/dist/ssh/mpaux.c
vendored
Normal file
54
crypto/dist/ssh/mpaux.c
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/* $NetBSD: mpaux.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: mpaux.c,v 1.14 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mpaux.c,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "mpaux.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);
|
||||
}
|
33
crypto/dist/ssh/mpaux.h
vendored
Normal file
33
crypto/dist/ssh/mpaux.h
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/* $NetBSD: mpaux.h,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: mpaux.h,v 1.8 2000/09/07 20:27:52 deraadt 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 */
|
46
crypto/dist/ssh/myproposal.h
vendored
Normal file
46
crypto/dist/ssh/myproposal.h
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/* $NetBSD: myproposal.h,v 1.1.1.1 2000/09/28 22:10:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1"
|
||||
#define KEX_DEFAULT_PK_ALG "ssh-dss"
|
||||
#define KEX_DEFAULT_ENCRYPT "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
|
||||
#define KEX_DEFAULT_COMP "zlib,none"
|
||||
#define KEX_DEFAULT_LANG ""
|
||||
|
||||
|
||||
static char *myproposal[PROPOSAL_MAX] = {
|
||||
KEX_DEFAULT_KEX,
|
||||
KEX_DEFAULT_PK_ALG,
|
||||
KEX_DEFAULT_ENCRYPT,
|
||||
KEX_DEFAULT_ENCRYPT,
|
||||
KEX_DEFAULT_MAC,
|
||||
KEX_DEFAULT_MAC,
|
||||
KEX_DEFAULT_COMP,
|
||||
KEX_DEFAULT_COMP,
|
||||
KEX_DEFAULT_LANG,
|
||||
KEX_DEFAULT_LANG
|
||||
};
|
498
crypto/dist/ssh/nchan.c
vendored
Normal file
498
crypto/dist/ssh/nchan.c
vendored
Normal file
@ -0,0 +1,498 @@
|
||||
/* $NetBSD: nchan.c,v 1.1.1.1 2000/09/28 22:10:05 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: nchan.c,v 1.19 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: nchan.c,v 1.1.1.1 2000/09/28 22:10:05 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "channels.h"
|
||||
#include "nchan.h"
|
||||
|
||||
#include "ssh2.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* functions manipulating channel states */
|
||||
/*
|
||||
* EVENTS update channel input/output states execute ACTIONS
|
||||
*/
|
||||
/* events concerning the INPUT from socket for channel (istate) */
|
||||
chan_event_fn *chan_rcvd_oclose = NULL;
|
||||
chan_event_fn *chan_read_failed = NULL;
|
||||
chan_event_fn *chan_ibuf_empty = NULL;
|
||||
/* events concerning the OUTPUT from channel for socket (ostate) */
|
||||
chan_event_fn *chan_rcvd_ieof = NULL;
|
||||
chan_event_fn *chan_write_failed = NULL;
|
||||
chan_event_fn *chan_obuf_empty = NULL;
|
||||
/*
|
||||
* ACTIONS: should never update the channel states
|
||||
*/
|
||||
static void chan_send_ieof1(Channel *c);
|
||||
static void chan_send_oclose1(Channel *c);
|
||||
static void chan_send_close2(Channel *c);
|
||||
static void chan_send_eof2(Channel *c);
|
||||
|
||||
/* channel cleanup */
|
||||
chan_event_fn *chan_delete_if_full_closed = NULL;
|
||||
|
||||
/* helper */
|
||||
static void chan_shutdown_write(Channel *c);
|
||||
static void chan_shutdown_read(Channel *c);
|
||||
|
||||
/*
|
||||
* SSH1 specific implementation of event functions
|
||||
*/
|
||||
|
||||
static void
|
||||
chan_rcvd_oclose1(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd oclose", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
debug("channel %d: input wait_oclose -> closed", c->self);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: input open -> closed", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
/* both local read_failed and remote write_failed */
|
||||
log("channel %d: input drain -> closed", c->self);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
|
||||
c->self, c->istate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_read_failed_12(Channel *c)
|
||||
{
|
||||
debug("channel %d: read failed", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: input open -> drain", c->self);
|
||||
chan_shutdown_read(c);
|
||||
c->istate = CHAN_INPUT_WAIT_DRAIN;
|
||||
if (buffer_len(&c->input) == 0) {
|
||||
debug("channel %d: input: no drain shortcut", c->self);
|
||||
chan_ibuf_empty(c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_ibuf_empty1(Channel *c)
|
||||
{
|
||||
debug("channel %d: ibuf empty", c->self);
|
||||
if (buffer_len(&c->input)) {
|
||||
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: input drain -> wait_oclose", c->self);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_ibuf_empty for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_ieof1(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd ieof", c->self);
|
||||
if (c->type != SSH_CHANNEL_OPEN) {
|
||||
debug("channel %d: non-open", c->self);
|
||||
if (c->istate == CHAN_INPUT_OPEN) {
|
||||
debug("channel %d: non-open: input open -> wait_oclose", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
} else {
|
||||
error("channel %d: istate %d != open", c->self, c->istate);
|
||||
}
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN) {
|
||||
debug("channel %d: non-open: output open -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
} else {
|
||||
error("channel %d: ostate %d != open", c->self, c->ostate);
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
debug("channel %d: output wait_ieof -> closed", c->self);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_write_failed1(Channel *c)
|
||||
{
|
||||
debug("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: output open -> wait_ieof", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output wait_drain -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_obuf_empty1(Channel *c)
|
||||
{
|
||||
debug("channel %d: obuf empty", c->self);
|
||||
if (buffer_len(&c->output)) {
|
||||
error("channel %d: internal error: chan_obuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_obuf_empty for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_ieof1(Channel *c)
|
||||
{
|
||||
debug("channel %d: send ieof", c->self);
|
||||
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("channel %d: internal error: cannot send ieof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose1(Channel *c)
|
||||
{
|
||||
debug("channel %d: send oclose", c->self);
|
||||
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("channel %d: internal error: cannot send oclose for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed1(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
debug("channel %d: full closed", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the same for SSH2
|
||||
*/
|
||||
static void
|
||||
chan_rcvd_oclose2(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd close", c->self);
|
||||
if (c->flags & CHAN_CLOSE_RCVD)
|
||||
error("channel %d: protocol error: close rcvd twice", c->self);
|
||||
c->flags |= CHAN_CLOSE_RCVD;
|
||||
if (c->type == SSH_CHANNEL_LARVAL) {
|
||||
/* tear down larval channels immediately */
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
/* wait until a data from the channel is consumed if a CLOSE is received */
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: input open -> closed", c->self);
|
||||
chan_shutdown_read(c);
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: input drain -> closed", c->self);
|
||||
chan_send_eof2(c);
|
||||
break;
|
||||
}
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
}
|
||||
static void
|
||||
chan_ibuf_empty2(Channel *c)
|
||||
{
|
||||
debug("channel %d: ibuf empty", c->self);
|
||||
if (buffer_len(&c->input)) {
|
||||
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: input drain -> closed", c->self);
|
||||
if (!(c->flags & CHAN_CLOSE_SENT))
|
||||
chan_send_eof2(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_ibuf_empty for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_ieof2(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd eof", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN) {
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_write_failed2(Channel *c)
|
||||
{
|
||||
debug("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: output open -> closed", c->self);
|
||||
chan_shutdown_write(c); /* ?? */
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_shutdown_write(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_obuf_empty2(Channel *c)
|
||||
{
|
||||
debug("channel %d: obuf empty", c->self);
|
||||
if (buffer_len(&c->output)) {
|
||||
error("internal error: chan_obuf_empty %d for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_shutdown_write(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_obuf_empty for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eof2(Channel *c)
|
||||
{
|
||||
debug("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH2_MSG_CHANNEL_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_close2(Channel *c)
|
||||
{
|
||||
debug("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: internal error: already sent close", c->self);
|
||||
} else {
|
||||
packet_start(SSH2_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed2(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
if (!(c->flags & CHAN_CLOSE_SENT)) {
|
||||
chan_send_close2(c);
|
||||
}
|
||||
if ((c->flags & CHAN_CLOSE_SENT) &&
|
||||
(c->flags & CHAN_CLOSE_RCVD)) {
|
||||
debug("channel %d: full closed2", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* shared */
|
||||
void
|
||||
chan_init_iostates(Channel *c)
|
||||
{
|
||||
c->ostate = CHAN_OUTPUT_OPEN;
|
||||
c->istate = CHAN_INPUT_OPEN;
|
||||
c->flags = 0;
|
||||
}
|
||||
|
||||
/* init */
|
||||
void
|
||||
chan_init(void)
|
||||
{
|
||||
if (compat20) {
|
||||
chan_rcvd_oclose = chan_rcvd_oclose2;
|
||||
chan_read_failed = chan_read_failed_12;
|
||||
chan_ibuf_empty = chan_ibuf_empty2;
|
||||
|
||||
chan_rcvd_ieof = chan_rcvd_ieof2;
|
||||
chan_write_failed = chan_write_failed2;
|
||||
chan_obuf_empty = chan_obuf_empty2;
|
||||
|
||||
chan_delete_if_full_closed = chan_delete_if_full_closed2;
|
||||
} else {
|
||||
chan_rcvd_oclose = chan_rcvd_oclose1;
|
||||
chan_read_failed = chan_read_failed_12;
|
||||
chan_ibuf_empty = chan_ibuf_empty1;
|
||||
|
||||
chan_rcvd_ieof = chan_rcvd_ieof1;
|
||||
chan_write_failed = chan_write_failed1;
|
||||
chan_obuf_empty = chan_obuf_empty1;
|
||||
|
||||
chan_delete_if_full_closed = chan_delete_if_full_closed1;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper */
|
||||
static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
buffer_consume(&c->output, buffer_len(&c->output));
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug("channel %d: close_write", c->self);
|
||||
if (c->sock != -1) {
|
||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||
debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
} else {
|
||||
if (close(c->wfd) < 0)
|
||||
log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
|
||||
c->self, c->wfd, strerror(errno));
|
||||
c->wfd = -1;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_shutdown_read(Channel *c)
|
||||
{
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
debug("channel %d: close_read", c->self);
|
||||
if (c->sock != -1) {
|
||||
if (shutdown(c->sock, SHUT_RD) < 0)
|
||||
error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
|
||||
c->self, c->sock, c->istate, c->ostate, strerror(errno));
|
||||
} else {
|
||||
if (close(c->rfd) < 0)
|
||||
log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
|
||||
c->self, c->rfd, strerror(errno));
|
||||
c->rfd = -1;
|
||||
}
|
||||
}
|
93
crypto/dist/ssh/nchan.h
vendored
Normal file
93
crypto/dist/ssh/nchan.h
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/* $NetBSD: nchan.h,v 1.1.1.1 2000/09/28 22:10:05 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: nchan.h,v 1.9 2000/09/07 20:27:52 deraadt 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
|
||||
|
||||
#define CHAN_CLOSE_SENT 0x01
|
||||
#define CHAN_CLOSE_RCVD 0x02
|
||||
|
||||
|
||||
/* Channel EVENTS */
|
||||
typedef void chan_event_fn(Channel * c);
|
||||
|
||||
/* for the input state */
|
||||
extern chan_event_fn *chan_rcvd_oclose;
|
||||
extern chan_event_fn *chan_read_failed;
|
||||
extern chan_event_fn *chan_ibuf_empty;
|
||||
|
||||
/* for the output state */
|
||||
extern chan_event_fn *chan_rcvd_ieof;
|
||||
extern chan_event_fn *chan_write_failed;
|
||||
extern chan_event_fn *chan_obuf_empty;
|
||||
|
||||
extern chan_event_fn *chan_delete_if_full_closed;
|
||||
|
||||
void chan_init_iostates(Channel * c);
|
||||
void chan_init(void);
|
||||
#endif
|
98
crypto/dist/ssh/nchan.ms
vendored
Normal file
98
crypto/dist/ssh/nchan.ms
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
.\" $NetBSD: nchan.ms,v 1.1.1.1 2000/09/28 22:10:06 thorpej Exp $
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" 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.
|
66
crypto/dist/ssh/nchan2.ms
vendored
Normal file
66
crypto/dist/ssh/nchan2.ms
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
.\" $NetBSD: nchan2.ms,v 1.1.1.1 2000/09/28 22:10:06 thorpej Exp $
|
||||
.\"
|
||||
.TL
|
||||
OpenSSH Channel Close Protocol 2.0 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
|
||||
S3: ellipse invis
|
||||
move down l from last ellipse.s
|
||||
S4: ellipse "INPUT" "CLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "INPUT" "WAIT" "DRAIN"
|
||||
arrow from S1.e to S4.n
|
||||
box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
|
||||
arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "read_failed/" "shutdown_read" with .e 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
|
||||
Channel Output State Diagram
|
||||
.PS
|
||||
S1: ellipse "OUTPUT" "OPEN"
|
||||
move right 2*l from last ellipse.e
|
||||
S3: ellipse invis
|
||||
move down l from last ellipse.s
|
||||
S4: ellipse "OUTPUT" "CLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "OUTPUT" "WAIT" "DRAIN"
|
||||
arrow from S1.e to S4.n
|
||||
box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
|
||||
arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e 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 EOF message to the peer.
|
||||
.PP
|
||||
A CLOSE message is sent to the peer if
|
||||
both the INPUT- and the OUTOUT-half of the local
|
||||
end of the channel are closed.
|
||||
.PP
|
||||
The channel can be deallocated by a protocol instance
|
||||
if a CLOSE message he been both sent and received.
|
1318
crypto/dist/ssh/packet.c
vendored
Normal file
1318
crypto/dist/ssh/packet.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
219
crypto/dist/ssh/packet.h
vendored
Normal file
219
crypto/dist/ssh/packet.h
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
/* $NetBSD: packet.h,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Interface for the packet protocol functions.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: packet.h,v 1.17 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
/*
|
||||
* Sets the socket used for communication. Disables encryption until
|
||||
* packet_set_encryption_key is called. It is permissible that fd_in and
|
||||
* fd_out are the same descriptor; in that case it is assumed to be a socket.
|
||||
*/
|
||||
void packet_set_connection(int fd_in, int fd_out);
|
||||
|
||||
/* 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);
|
||||
void packet_put_bignum2(BIGNUM * value);
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
void packet_put_cstring(const char *str);
|
||||
void packet_put_raw(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);
|
||||
void packet_get_bignum2(BIGNUM * value, int *length_ptr);
|
||||
char *packet_get_raw(int *length_ptr);
|
||||
|
||||
/*
|
||||
* Returns a string from the packet data. The string is allocated using
|
||||
* xmalloc; it is the responsibility of the calling program to free it when
|
||||
* no longer needed. The length_ptr argument may be NULL, or point to an
|
||||
* integer into which the length of the string is stored.
|
||||
*/
|
||||
char *packet_get_string(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)
|
||||
|
||||
#define packet_done() \
|
||||
do { \
|
||||
int _len = packet_remaining(); \
|
||||
if (_len > 0) { \
|
||||
log("Packet integrity error (%d bytes remaining) at %s:%d", \
|
||||
_len ,__FILE__, __LINE__); \
|
||||
packet_disconnect("Packet integrity error."); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remote host is connected via a socket/ipv4 */
|
||||
int packet_connection_is_on_socket(void);
|
||||
int packet_connection_is_ipv4(void);
|
||||
|
||||
/* enable SSH2 packet format */
|
||||
void packet_set_ssh2_format(void);
|
||||
|
||||
/* returns remaining payload bytes */
|
||||
int packet_remaining(void);
|
||||
|
||||
#endif /* PACKET_H */
|
94
crypto/dist/ssh/pathnames.h
vendored
Normal file
94
crypto/dist/ssh/pathnames.h
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/* $NetBSD: pathnames.h,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
#ifndef _PATHNAMES_H
|
||||
#define _PATHNAMES_H
|
||||
|
||||
/* system utility and file paths */
|
||||
|
||||
#define _PATH_CP "/bin/cp"
|
||||
#define _PATH_MOTD "/etc/motd"
|
||||
#define _PATH_LOGIN "/usr/bin/login"
|
||||
#define _PATH_RSH "/usr/bin/rsh"
|
||||
#define _PATH_URANDOM "/dev/urandom"
|
||||
|
||||
/* X Window utility and file paths */
|
||||
|
||||
#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
|
||||
#define _PATH_XUNIX_DIR "/tmp/.X11-unix/X"
|
||||
#define _PATH_SSH_ASKPASS "/usr/X11R6/bin/ssh-askpass"
|
||||
|
||||
/* paths specific to the Secure Shell */
|
||||
|
||||
/* mk?temp input string for process-specific scratch dir */
|
||||
#define _PATH_SSH_TMPDIR _PATH_TMP "/ssh-XXXXXXXX"
|
||||
|
||||
/* daemon pid file */
|
||||
#define _PATH_SSH_DAEMON_PID_FILE _PATH_VARRUN "sshd.pid"
|
||||
|
||||
/* System-wide files containing host keys of known hosts. */
|
||||
#define _PATH_SSH_SYSTEM_HOSTFILE "/etc/ssh_known_hosts"
|
||||
#define _PATH_SSH_SYSTEM_HOSTFILE2 "/etc/ssh_known_hosts2"
|
||||
|
||||
/* host keys (should be readable only by root) */
|
||||
#define _PATH_HOST_KEY_FILE "/etc/ssh_host_key"
|
||||
#define _PATH_HOST_DSA_KEY_FILE "/etc/ssh_host_dsa_key"
|
||||
|
||||
/* client and server config files */
|
||||
#define _PATH_CLIENT_CONFIG_FILE "/etc/ssh.conf"
|
||||
#define _PATH_SERVER_CONFIG_FILE "/etc/sshd.conf"
|
||||
|
||||
/* the ssh utility itself as called from scp */
|
||||
#define _PATH_SSH "/usr/bin/ssh"
|
||||
|
||||
/* ssh-only version of hosts.equiv */
|
||||
#define _PATH_SSH_HEQUIV "/etc/shosts.equiv"
|
||||
|
||||
/*
|
||||
* name of the directory in each users home directory containing private
|
||||
* configuration and data files. May need to change if this secure shell
|
||||
* implementation becomes incompatible with other implementations.
|
||||
*/
|
||||
#define _PATH_SSH_USER_DIR ".ssh"
|
||||
|
||||
/*
|
||||
* Per-user and system-wide ssh "rc" files. These files are executed with
|
||||
* /bin/sh before starting the shell or command if they exist. They will be
|
||||
* passed "proto cookie" as arguments if X11 forwarding with spoofing is in
|
||||
* use. xauth will be run if neither of these exists.
|
||||
*/
|
||||
#define _PATH_SSH_USER_RC _PATH_SSH_USER_DIR "/rc"
|
||||
#define _PATH_SSH_SYSTEM_RC "/etc/sshrc"
|
||||
|
||||
/* Per-user file containing host keys of known hosts. */
|
||||
#define _PATH_SSH_USER_HOSTFILE "~/" _PATH_SSH_USER_DIR "/known_hosts"
|
||||
#define _PATH_SSH_USER_HOSTFILE2 "~/" _PATH_SSH_USER_DIR "/known_hosts2"
|
||||
|
||||
/*
|
||||
* Name of the default file containing client-side authentication key. This
|
||||
* file should only be readable by the user him/herself.
|
||||
*/
|
||||
#define _PATH_SSH_CLIENT_IDENTITY _PATH_SSH_USER_DIR "/identity"
|
||||
#define _PATH_SSH_CLIENT_ID_DSA _PATH_SSH_USER_DIR "/id_dsa"
|
||||
|
||||
/*
|
||||
* Configuration and environment files in user's home directory. These
|
||||
* need not be readable by anyone but the user him/herself, but do not
|
||||
* contain anything particularly secret. If the user's home directory
|
||||
* resides on an NFS volume where root is mapped to nobody, this may need
|
||||
* to be world-readable.
|
||||
*/
|
||||
#define _PATH_SSH_USER_CONFFILE _PATH_SSH_USER_DIR "/config"
|
||||
#define _PATH_SSH_USER_ENVIRONMENT _PATH_SSH_USER_DIR "/environment"
|
||||
|
||||
/*
|
||||
* File containing a list of those rsa keys that permit logging in as this
|
||||
* user. This file need not be readable by anyone but the user him/herself,
|
||||
* but does not contain anything particularly secret. If the user's home
|
||||
* directory resides on an NFS volume where root is mapped to nobody, this
|
||||
* may need to be world-readable. (This file is read by the daemon which is
|
||||
* running as root.)
|
||||
*/
|
||||
#define _PATH_SSH_USER_PERMITTED_KEYS _PATH_SSH_USER_DIR "/authorized_keys"
|
||||
#define _PATH_SSH_USER_PERMITTED_KEYS2 _PATH_SSH_USER_DIR "/authorized_keys2"
|
||||
|
||||
#endif
|
283
crypto/dist/ssh/pty.c
vendored
Normal file
283
crypto/dist/ssh/pty.c
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
/* $NetBSD: pty.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: pty.c,v 1.16 2000/09/07 21:13:37 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: pty.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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, _PATH_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(_PATH_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(_PATH_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(_PATH_TTY, O_WRONLY);
|
||||
if (fd < 0)
|
||||
error("open " _PATH_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));
|
||||
}
|
49
crypto/dist/ssh/pty.h
vendored
Normal file
49
crypto/dist/ssh/pty.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/* $NetBSD: pty.h,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for allocating a pseudo-terminal and making it the controlling
|
||||
* tty.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: pty.h,v 1.8 2000/09/07 20:27:52 deraadt 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 */
|
220
crypto/dist/ssh/radix.c
vendored
Normal file
220
crypto/dist/ssh/radix.c
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
/* $NetBSD: radix.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Dug Song. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: radix.c,v 1.13 2000/09/07 20:27:52 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: radix.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "uuencode.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#ifdef AFS
|
||||
#include <krb.h>
|
||||
|
||||
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, size_t buflen)
|
||||
{
|
||||
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((unsigned char *)temp, len, (char *)buf, buflen));
|
||||
}
|
||||
|
||||
int
|
||||
radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
{
|
||||
|
||||
char *p;
|
||||
int len, tl;
|
||||
char version;
|
||||
char temp[2048];
|
||||
|
||||
len = uudecode(buf, (unsigned char *)temp, sizeof(temp));
|
||||
if (len < 0)
|
||||
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 */
|
84
crypto/dist/ssh/random.c
vendored
Normal file
84
crypto/dist/ssh/random.c
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
/* $NetBSD: random.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: random.c,v 1.1.1.1 2000/09/28 22:10:08 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for stirring in additional noise into the
|
||||
* cryptographically strong PRNG.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#define BUFSIZE 32
|
||||
|
||||
void
|
||||
ssh_random_stir(void)
|
||||
{
|
||||
u_char buf[BUFSIZE];
|
||||
ssize_t len;
|
||||
int fd;
|
||||
|
||||
fd = open(_PATH_URANDOM, O_RDONLY, 0666);
|
||||
if (fd != -1) {
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
if (len != -1)
|
||||
RAND_seed(buf, len);
|
||||
(void) close(fd);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
} else {
|
||||
/*
|
||||
* XXX We should stir in other environmental
|
||||
* XXX noise, here.
|
||||
*/
|
||||
RAND_pseudo_bytes(buf, sizeof(buf) >> 1);
|
||||
RAND_seed(buf, sizeof(buf) >> 1);
|
||||
}
|
||||
}
|
817
crypto/dist/ssh/readconf.c
vendored
Normal file
817
crypto/dist/ssh/readconf.c
vendored
Normal file
@ -0,0 +1,817 @@
|
||||
/* $NetBSD: readconf.c,v 1.1.1.1 2000/09/28 22:10:10 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for reading the configuration files.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: readconf.c,v 1.1.1.1 2000/09/28 22:10:10 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "pathnames.h"
|
||||
#include "readconf.h"
|
||||
#include "match.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.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, oXAuthLocation,
|
||||
#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, oCiphers, oProtocol, oIdentityFile2,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
OpCodes opcode;
|
||||
} keywords[] = {
|
||||
{ "forwardagent", oForwardAgent },
|
||||
{ "forwardx11", oForwardX11 },
|
||||
{ "xauthlocation", oXAuthLocation },
|
||||
{ "gatewayports", oGatewayPorts },
|
||||
{ "useprivilegedport", oUsePrivilegedPort },
|
||||
{ "rhostsauthentication", oRhostsAuthentication },
|
||||
{ "passwordauthentication", oPasswordAuthentication },
|
||||
{ "rsaauthentication", oRSAAuthentication },
|
||||
{ "dsaauthentication", oDSAAuthentication },
|
||||
{ "skeyauthentication", oSkeyAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", oKerberosAuthentication },
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
{ "kerberostgtpassing", oKerberosTgtPassing },
|
||||
{ "afstokenpassing", oAFSTokenPassing },
|
||||
#endif
|
||||
{ "fallbacktorsh", oFallBackToRsh },
|
||||
{ "usersh", oUseRsh },
|
||||
{ "identityfile", oIdentityFile },
|
||||
{ "identityfile2", oIdentityFile2 },
|
||||
{ "hostname", oHostName },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
{ "port", oPort },
|
||||
{ "cipher", oCipher },
|
||||
{ "ciphers", oCiphers },
|
||||
{ "protocol", oProtocol },
|
||||
{ "remoteforward", oRemoteForward },
|
||||
{ "localforward", oLocalForward },
|
||||
{ "user", oUser },
|
||||
{ "host", oHost },
|
||||
{ "escapechar", oEscapeChar },
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
|
||||
{ "userknownhostsfile2", oUserKnownHostsFile2 },
|
||||
{ "connectionattempts", oConnectionAttempts },
|
||||
{ "batchmode", oBatchMode },
|
||||
{ "checkhostip", oCheckHostIP },
|
||||
{ "stricthostkeychecking", oStrictHostKeyChecking },
|
||||
{ "compression", oCompression },
|
||||
{ "compressionlevel", oCompressionLevel },
|
||||
{ "keepalive", oKeepAlives },
|
||||
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
|
||||
{ "tisauthentication", oTISAuthentication },
|
||||
{ "loglevel", oLogLevel },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* 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], *s, *string, **charptr, *endofnumber, *keyword, *arg;
|
||||
int opcode, *intptr, value;
|
||||
u_short fwd_port, fwd_host_port;
|
||||
|
||||
s = line;
|
||||
/* Get the keyword. (Each line is supposed to begin with a keyword). */
|
||||
keyword = strdelim(&s);
|
||||
/* Ignore leading whitespace. */
|
||||
if (*keyword == '\0')
|
||||
keyword = strdelim(&s);
|
||||
if (!*keyword || *keyword == '\n' || *keyword == '#')
|
||||
return 0;
|
||||
|
||||
opcode = parse_token(keyword, filename, linenum);
|
||||
|
||||
switch (opcode) {
|
||||
case oBadOption:
|
||||
/* don't panic, but count bad options */
|
||||
return -1;
|
||||
/* NOTREACHED */
|
||||
case oForwardAgent:
|
||||
intptr = &options->forward_agent;
|
||||
parse_flag:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(arg, "no") == 0 || strcmp(arg, "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 oDSAAuthentication:
|
||||
intptr = &options->dsa_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;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing v4/v5/no argument.",
|
||||
filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(arg, "v4") == 0)
|
||||
value = 4;
|
||||
else if (strcmp(arg, "v5") == 0)
|
||||
value = 5;
|
||||
else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
|
||||
value = 0;
|
||||
else
|
||||
fatal("%.200s line %d: Bad v4/v5/no argument.",
|
||||
filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
#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;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing yes/no argument.",
|
||||
filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
|
||||
value = 0;
|
||||
else if (strcmp(arg, "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:
|
||||
case oIdentityFile2:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep) {
|
||||
intptr = (opcode == oIdentityFile) ?
|
||||
&options->num_identity_files :
|
||||
&options->num_identity_files2;
|
||||
if (*intptr >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
charptr = (opcode == oIdentityFile) ?
|
||||
&options->identity_files[*intptr] :
|
||||
&options->identity_files2[*intptr];
|
||||
*charptr = xstrdup(arg);
|
||||
*intptr = *intptr + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case oXAuthLocation:
|
||||
charptr=&options->xauth_location;
|
||||
goto parse_string;
|
||||
|
||||
case oUser:
|
||||
charptr = &options->user;
|
||||
parse_string:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep && *charptr == NULL)
|
||||
*charptr = xstrdup(arg);
|
||||
break;
|
||||
|
||||
case oGlobalKnownHostsFile:
|
||||
charptr = &options->system_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oUserKnownHostsFile:
|
||||
charptr = &options->user_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oGlobalKnownHostsFile2:
|
||||
charptr = &options->system_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oUserKnownHostsFile2:
|
||||
charptr = &options->user_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oHostName:
|
||||
charptr = &options->hostname;
|
||||
goto parse_string;
|
||||
|
||||
case oProxyCommand:
|
||||
charptr = &options->proxy_command;
|
||||
string = xstrdup("");
|
||||
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
|
||||
string = xrealloc(string, strlen(string) + strlen(arg) + 2);
|
||||
strcat(string, " ");
|
||||
strcat(string, arg);
|
||||
}
|
||||
if (*activep && *charptr == NULL)
|
||||
*charptr = string;
|
||||
else
|
||||
xfree(string);
|
||||
return 0;
|
||||
|
||||
case oPort:
|
||||
intptr = &options->port;
|
||||
parse_int:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (arg[0] < '0' || arg[0] > '9')
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
|
||||
/* Octal, decimal, or hex format? */
|
||||
value = strtol(arg, &endofnumber, 0);
|
||||
if (arg == endofnumber)
|
||||
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;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
value = cipher_number(arg);
|
||||
if (value == -1)
|
||||
fatal("%.200s line %d: Bad cipher '%s'.",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oCiphers:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (!ciphers_valid(arg))
|
||||
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*activep && options->ciphers == NULL)
|
||||
options->ciphers = xstrdup(arg);
|
||||
break;
|
||||
|
||||
case oProtocol:
|
||||
intptr = &options->protocol;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
value = proto_spec(arg);
|
||||
if (value == SSH_PROTO_UNKNOWN)
|
||||
fatal("%.200s line %d: Bad protocol spec '%s'.",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
arg = strdelim(&s);
|
||||
value = log_level_number(arg);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*activep && (LogLevel) * intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case oRemoteForward:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (arg[0] < '0' || arg[0] > '9')
|
||||
fatal("%.200s line %d: Badly formatted port number.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(arg);
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing second argument.",
|
||||
filename, linenum);
|
||||
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
|
||||
fatal("%.200s line %d: Badly formatted host:port.",
|
||||
filename, linenum);
|
||||
if (*activep)
|
||||
add_remote_forward(options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case oLocalForward:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (arg[0] < '0' || arg[0] > '9')
|
||||
fatal("%.200s line %d: Badly formatted port number.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(arg);
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing second argument.",
|
||||
filename, linenum);
|
||||
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
|
||||
fatal("%.200s line %d: Badly formatted host:port.",
|
||||
filename, linenum);
|
||||
if (*activep)
|
||||
add_local_forward(options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case oHost:
|
||||
*activep = 0;
|
||||
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
|
||||
if (match_pattern(host, arg)) {
|
||||
debug("Applying options for %.100s", arg);
|
||||
*activep = 1;
|
||||
break;
|
||||
}
|
||||
/* Avoid garbage check below, as strdelim is done. */
|
||||
return 0;
|
||||
|
||||
case oEscapeChar:
|
||||
intptr = &options->escape_char;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (arg[0] == '^' && arg[2] == 0 &&
|
||||
(unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
|
||||
value = (unsigned char) arg[1] & 31;
|
||||
else if (strlen(arg) == 1)
|
||||
value = (unsigned char) arg[0];
|
||||
else if (strcmp(arg, "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 ((arg = strdelim(&s)) != NULL && *arg != '\0')
|
||||
{
|
||||
fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
|
||||
filename, linenum, arg);
|
||||
}
|
||||
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->xauth_location = NULL;
|
||||
options->gateway_ports = -1;
|
||||
options->use_privileged_port = -1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->dsa_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->ciphers = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->num_identity_files = 0;
|
||||
options->num_identity_files2 = 0;
|
||||
options->hostname = NULL;
|
||||
options->proxy_command = NULL;
|
||||
options->user = NULL;
|
||||
options->escape_char = -1;
|
||||
options->system_hostfile = NULL;
|
||||
options->user_hostfile = NULL;
|
||||
options->system_hostfile2 = NULL;
|
||||
options->user_hostfile2 = 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 = 0;
|
||||
if (options->forward_x11 == -1)
|
||||
options->forward_x11 = 0;
|
||||
#ifdef _PATH_XAUTH
|
||||
if (options->xauth_location == NULL)
|
||||
options->xauth_location = _PATH_XAUTH;
|
||||
#endif /* _PATH_XAUTH */
|
||||
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->dsa_authentication == -1)
|
||||
options->dsa_authentication = 1;
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
#ifdef KRB4
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = 4;
|
||||
#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 = 0;
|
||||
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 = 0;
|
||||
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;
|
||||
/* options->ciphers, default set in myproposals.h */
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
|
||||
if (options->num_identity_files == 0) {
|
||||
options->identity_files[0] =
|
||||
xmalloc(2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1);
|
||||
sprintf(options->identity_files[0], "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
|
||||
options->num_identity_files = 1;
|
||||
}
|
||||
if (options->num_identity_files2 == 0) {
|
||||
options->identity_files2[0] =
|
||||
xmalloc(2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1);
|
||||
sprintf(options->identity_files2[0], "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
|
||||
options->num_identity_files2 = 1;
|
||||
}
|
||||
if (options->escape_char == -1)
|
||||
options->escape_char = '~';
|
||||
if (options->system_hostfile == NULL)
|
||||
options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
|
||||
if (options->user_hostfile == NULL)
|
||||
options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
|
||||
if (options->system_hostfile2 == NULL)
|
||||
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
|
||||
if (options->user_hostfile2 == NULL)
|
||||
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
|
||||
if (options->log_level == (LogLevel) - 1)
|
||||
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 */
|
||||
}
|
145
crypto/dist/ssh/readconf.h
vendored
Normal file
145
crypto/dist/ssh/readconf.h
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
/* $NetBSD: readconf.h,v 1.1.1.1 2000/09/28 22:10:10 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for reading the configuration file.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: readconf.h,v 1.21 2000/09/07 20:27:53 deraadt 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. */
|
||||
char *xauth_location; /* Location for xauth program */
|
||||
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 dsa_authentication; /* Try DSA 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 *ciphers; /* SSH2 ciphers in order of preference. */
|
||||
int protocol; /* Protocol in order of preference. */
|
||||
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. */
|
||||
char *system_hostfile2;
|
||||
char *user_hostfile2;
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
int num_identity_files2; /* DSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
char *identity_files2[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 */
|
127
crypto/dist/ssh/readpass.c
vendored
Normal file
127
crypto/dist/ssh/readpass.c
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
/* $NetBSD: readpass.c,v 1.1.1.1 2000/09/28 22:10:10 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: readpass.c,v 1.11 2000/06/20 01:39:44 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: readpass.c,v 1.1.1.1 2000/09/28 22:10:10 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
volatile int intr;
|
||||
|
||||
static void
|
||||
intcatch(int signo)
|
||||
{
|
||||
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(_PATH_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);
|
||||
}
|
202
crypto/dist/ssh/rsa.c
vendored
Normal file
202
crypto/dist/ssh/rsa.c
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/* $NetBSD: rsa.c,v 1.1.1.1 2000/09/28 22:10:11 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1999 Niels Provos. 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.
|
||||
*
|
||||
*
|
||||
* 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]
|
||||
*/
|
||||
|
||||
/* from OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: rsa.c,v 1.1.1.1 2000/09/28 22:10:11 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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)
|
||||
{
|
||||
unsigned 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)
|
||||
{
|
||||
unsigned 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/dist/ssh/rsa.h
vendored
Normal file
38
crypto/dist/ssh/rsa.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/* $NetBSD: rsa.h,v 1.1.1.1 2000/09/28 22:10:11 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* RSA key generation, encryption and decryption.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp */
|
||||
|
||||
#ifndef RSA_H
|
||||
#define RSA_H
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
||||
|
||||
/*
|
||||
* Indicates whether the rsa module is permitted to show messages on the
|
||||
* terminal.
|
||||
*/
|
||||
void rsa_set_verbose __P((int verbose));
|
||||
|
||||
int rsa_alive __P((void));
|
||||
|
||||
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
|
||||
void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
|
||||
|
||||
#endif /* RSA_H */
|
132
crypto/dist/ssh/scp.1
vendored
Normal file
132
crypto/dist/ssh/scp.1
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
.\" -*- 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
|
||||
.\"
|
||||
.\" $NetBSD: scp.1,v 1.1.1.1 2000/09/28 22:10:11 thorpej 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 S Ar program
|
||||
.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 S Ar program
|
||||
Name of
|
||||
.Ar program
|
||||
to use for the encrypted connection. The program must understand
|
||||
.Xr ssh 1
|
||||
options.
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Forces
|
||||
.Nm
|
||||
to use IPv6 addresses only.
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>, Theo de Raadt,
|
||||
Aaron Campbell
|
||||
.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
|
1259
crypto/dist/ssh/scp.c
vendored
Normal file
1259
crypto/dist/ssh/scp.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
697
crypto/dist/ssh/servconf.c
vendored
Normal file
697
crypto/dist/ssh/servconf.c
vendored
Normal file
@ -0,0 +1,697 @@
|
||||
/* $NetBSD: servconf.c,v 1.1.1.1 2000/09/28 22:10:15 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: servconf.c,v 1.51 2000/09/07 20:27:53 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: servconf.c,v 1.1.1.1 2000/09/28 22:10:15 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "pathnames.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.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->host_dsa_key_file = NULL;
|
||||
options->pid_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_time = -1;
|
||||
options->key_regeneration_time = -1;
|
||||
options->permit_root_login = -1;
|
||||
options->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->xauth_location = NULL;
|
||||
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;
|
||||
options->dsa_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;
|
||||
options->ciphers = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->gateway_ports = -1;
|
||||
options->num_subsystems = 0;
|
||||
options->max_startups_begin = -1;
|
||||
options->max_startups_rate = -1;
|
||||
options->max_startups = -1;
|
||||
}
|
||||
|
||||
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 = _PATH_HOST_KEY_FILE;
|
||||
if (options->host_dsa_key_file == NULL)
|
||||
options->host_dsa_key_file = _PATH_HOST_DSA_KEY_FILE;
|
||||
if (options->pid_file == NULL)
|
||||
options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
|
||||
if (options->server_key_bits == -1)
|
||||
options->server_key_bits = 768;
|
||||
if (options->login_grace_time == -1)
|
||||
options->login_grace_time = 600;
|
||||
if (options->key_regeneration_time == -1)
|
||||
options->key_regeneration_time = 3600;
|
||||
if (options->permit_root_login == -1)
|
||||
options->permit_root_login = 1; /* yes */
|
||||
if (options->ignore_rhosts == -1)
|
||||
options->ignore_rhosts = 1;
|
||||
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 = 0;
|
||||
if (options->x11_display_offset == -1)
|
||||
options->x11_display_offset = 10;
|
||||
#ifdef _PATH_XAUTH
|
||||
if (options->xauth_location == NULL)
|
||||
options->xauth_location = _PATH_XAUTH;
|
||||
#endif /* _PATH_XAUTH */
|
||||
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 = 0;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->dsa_authentication == -1)
|
||||
options->dsa_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 = 0;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
|
||||
if (options->gateway_ports == -1)
|
||||
options->gateway_ports = 0;
|
||||
if (options->max_startups == -1)
|
||||
options->max_startups = 10;
|
||||
if (options->max_startups_rate == -1)
|
||||
options->max_startups_rate = 100; /* 100% */
|
||||
if (options->max_startups_begin == -1)
|
||||
options->max_startups_begin = options->max_startups;
|
||||
}
|
||||
|
||||
/* 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, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
|
||||
sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
|
||||
} ServerOpCodes;
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
static struct {
|
||||
const char *name;
|
||||
ServerOpCodes opcode;
|
||||
} keywords[] = {
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "hostdsakey", sHostDSAKeyFile },
|
||||
{ "pidfile", sPidFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
{ "permitrootlogin", sPermitRootLogin },
|
||||
{ "syslogfacility", sLogFacility },
|
||||
{ "loglevel", sLogLevel },
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
{ "dsaauthentication", sDSAAuthentication },
|
||||
#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 },
|
||||
{ "xauthlocation", sXAuthLocation },
|
||||
{ "strictmodes", sStrictModes },
|
||||
{ "permitemptypasswords", sEmptyPasswd },
|
||||
{ "uselogin", sUseLogin },
|
||||
{ "randomseed", sRandomSeedFile },
|
||||
{ "keepalive", sKeepAlives },
|
||||
{ "allowusers", sAllowUsers },
|
||||
{ "denyusers", sDenyUsers },
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ "ciphers", sCiphers },
|
||||
{ "protocol", sProtocol },
|
||||
{ "gatewayports", sGatewayPorts },
|
||||
{ "subsystem", sSubsystem },
|
||||
{ "maxstartups", sMaxStartups },
|
||||
{ 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, *arg;
|
||||
int linenum, *intptr, value;
|
||||
int bad_options = 0;
|
||||
ServerOpCodes opcode;
|
||||
int i;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
linenum++;
|
||||
cp = line;
|
||||
arg = strdelim(&cp);
|
||||
/* Ignore leading whitespace */
|
||||
if (*arg == '\0')
|
||||
arg = strdelim(&cp);
|
||||
if (!*arg || *arg == '#')
|
||||
continue;
|
||||
opcode = parse_token(arg, 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);
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing port number.\n",
|
||||
filename, linenum);
|
||||
options->ports[options->num_ports++] = atoi(arg);
|
||||
break;
|
||||
|
||||
case sServerKeyBits:
|
||||
intptr = &options->server_key_bits;
|
||||
parse_int:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing integer value.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
value = atoi(arg);
|
||||
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:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing inet addr.\n",
|
||||
filename, linenum);
|
||||
add_listen_addr(options, arg);
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
case sHostDSAKeyFile:
|
||||
charptr = (opcode == sHostKeyFile ) ?
|
||||
&options->host_key_file : &options->host_dsa_key_file;
|
||||
parse_filename:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
*charptr = tilde_expand_filename(arg, getuid());
|
||||
break;
|
||||
|
||||
case sPidFile:
|
||||
charptr = &options->pid_file;
|
||||
goto parse_filename;
|
||||
|
||||
case sRandomSeedFile:
|
||||
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
|
||||
filename, linenum);
|
||||
arg = strdelim(&cp);
|
||||
break;
|
||||
|
||||
case sPermitRootLogin:
|
||||
intptr = &options->permit_root_login;
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(arg, "without-password") == 0)
|
||||
value = 2;
|
||||
else if (strcmp(arg, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(arg, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
|
||||
filename, linenum, arg);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreRhosts:
|
||||
intptr = &options->ignore_rhosts;
|
||||
parse_flag:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(arg, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(arg, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
|
||||
filename, linenum, arg);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreUserKnownHosts:
|
||||
intptr = &options->ignore_user_known_hosts;
|
||||
goto parse_flag;
|
||||
|
||||
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;
|
||||
|
||||
case sDSAAuthentication:
|
||||
intptr = &options->dsa_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 sXAuthLocation:
|
||||
charptr = &options->xauth_location;
|
||||
goto parse_filename;
|
||||
|
||||
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 sGatewayPorts:
|
||||
intptr = &options->gateway_ports;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogFacility:
|
||||
intptr = (int *) &options->log_facility;
|
||||
arg = strdelim(&cp);
|
||||
value = log_facility_number(arg);
|
||||
if (value == (SyslogFacility) - 1)
|
||||
fatal("%.200s line %d: unsupported log facility '%s'\n",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility) value;
|
||||
break;
|
||||
|
||||
case sLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
arg = strdelim(&cp);
|
||||
value = log_level_number(arg);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case sAllowUsers:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS)
|
||||
fatal("%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyUsers:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
if (options->num_deny_users >= MAX_DENY_USERS)
|
||||
fatal( "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case sAllowGroups:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
|
||||
fatal("%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyGroups:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS)
|
||||
fatal("%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case sCiphers:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: Missing argument.", filename, linenum);
|
||||
if (!ciphers_valid(arg))
|
||||
fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (options->ciphers == NULL)
|
||||
options->ciphers = xstrdup(arg);
|
||||
break;
|
||||
|
||||
case sProtocol:
|
||||
intptr = &options->protocol;
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: Missing argument.", filename, linenum);
|
||||
value = proto_spec(arg);
|
||||
if (value == SSH_PROTO_UNKNOWN)
|
||||
fatal("%s line %d: Bad protocol spec '%s'.",
|
||||
filename, linenum, arg ? arg : "<NONE>");
|
||||
if (*intptr == SSH_PROTO_UNKNOWN)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sSubsystem:
|
||||
if(options->num_subsystems >= MAX_SUBSYSTEMS) {
|
||||
fatal("%s line %d: too many subsystems defined.",
|
||||
filename, linenum);
|
||||
}
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: Missing subsystem name.",
|
||||
filename, linenum);
|
||||
for (i = 0; i < options->num_subsystems; i++)
|
||||
if(strcmp(arg, options->subsystem_name[i]) == 0)
|
||||
fatal("%s line %d: Subsystem '%s' already defined.",
|
||||
filename, linenum, arg);
|
||||
options->subsystem_name[options->num_subsystems] = xstrdup(arg);
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: Missing subsystem command.",
|
||||
filename, linenum);
|
||||
options->subsystem_command[options->num_subsystems] = xstrdup(arg);
|
||||
options->num_subsystems++;
|
||||
break;
|
||||
|
||||
case sMaxStartups:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: Missing MaxStartups spec.",
|
||||
filename, linenum);
|
||||
if (sscanf(arg, "%d:%d:%d",
|
||||
&options->max_startups_begin,
|
||||
&options->max_startups_rate,
|
||||
&options->max_startups) == 3) {
|
||||
if (options->max_startups_begin >
|
||||
options->max_startups ||
|
||||
options->max_startups_rate > 100 ||
|
||||
options->max_startups_rate < 1)
|
||||
fatal("%s line %d: Illegal MaxStartups spec.",
|
||||
filename, linenum);
|
||||
break;
|
||||
}
|
||||
intptr = &options->max_startups;
|
||||
goto parse_int;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
|
||||
filename, linenum, arg, opcode);
|
||||
exit(1);
|
||||
}
|
||||
if ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
|
||||
fprintf(stderr,
|
||||
"%s line %d: garbage at end of line; \"%.200s\".\n",
|
||||
filename, linenum, arg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0) {
|
||||
fprintf(stderr, "%s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
exit(1);
|
||||
}
|
||||
}
|
123
crypto/dist/ssh/servconf.h
vendored
Normal file
123
crypto/dist/ssh/servconf.h
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/* $NetBSD: servconf.h,v 1.1.1.1 2000/09/28 22:10:16 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Definitions for server configuration data and for the functions reading it.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: servconf.h,v 1.28 2000/09/07 20:27:53 deraadt 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. */
|
||||
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
|
||||
|
||||
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. */
|
||||
char *host_dsa_key_file; /* File containing dsa host key. */
|
||||
char *pid_file; /* Where to put our pid */
|
||||
int server_key_bits;/* Size of the server key. */
|
||||
int login_grace_time; /* Disconnect if no auth in this time
|
||||
* (sec). */
|
||||
int key_regeneration_time; /* Server key lifetime (seconds). */
|
||||
int permit_root_login; /* If true, permit root login. */
|
||||
int 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 */
|
||||
char *xauth_location; /* Location of xauth program */
|
||||
int strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
char *ciphers; /* Ciphers in order of preference. */
|
||||
int protocol; /* Protocol in order of preference. */
|
||||
int gateway_ports; /* If true, allow remote connects to forwarded ports. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
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. */
|
||||
int dsa_authentication; /* If true, permit DSA 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];
|
||||
|
||||
unsigned int num_subsystems;
|
||||
char *subsystem_name[MAX_SUBSYSTEMS];
|
||||
char *subsystem_command[MAX_SUBSYSTEMS];
|
||||
|
||||
int max_startups_begin;
|
||||
int max_startups_rate;
|
||||
int max_startups;
|
||||
|
||||
} 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 */
|
875
crypto/dist/ssh/serverloop.c
vendored
Normal file
875
crypto/dist/ssh/serverloop.c
vendored
Normal file
@ -0,0 +1,875 @@
|
||||
/* $NetBSD: serverloop.c,v 1.1.1.1 2000/09/28 22:10:20 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Server main loop for handling the interactive session.
|
||||
*
|
||||
* 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".
|
||||
*
|
||||
* SSH2 support by Markus Friedl.
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: serverloop.c,v 1.1.1.1 2000/09/28 22:10:20 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "servconf.h"
|
||||
#include "pty.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "ssh2.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
#include "auth-options.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 pid_t 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 server_init_dispatch(void);
|
||||
|
||||
static void
|
||||
sigchld_handler(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
pid_t 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;
|
||||
}
|
||||
static void
|
||||
sigchld_handler2(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
debug("Received SIGCHLD.");
|
||||
child_terminated = 1;
|
||||
signal(SIGCHLD, sigchld_handler2);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stderr data, and buffer it for sending
|
||||
* to the client.
|
||||
*/
|
||||
static void
|
||||
make_packets_from_stderr_data(void)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
static void
|
||||
make_packets_from_stdout_data(void)
|
||||
{
|
||||
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).
|
||||
*/
|
||||
static 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);
|
||||
FD_ZERO(writeset);
|
||||
|
||||
if (compat20) {
|
||||
/* wrong: bad condition XXX */
|
||||
if (channel_not_very_much_buffered_data())
|
||||
FD_SET(connection_in, readset);
|
||||
} else {
|
||||
/*
|
||||
* Read packets from the client unless we have too much
|
||||
* buffered stdin or channel data.
|
||||
*/
|
||||
if (buffer_len(&stdin_buffer) < buffer_high &&
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
/* Set masks for channel descriptors. */
|
||||
channel_prepare_select(readset, writeset);
|
||||
|
||||
/*
|
||||
* If we have buffered packet data going to the client, mark that
|
||||
* descriptor.
|
||||
*/
|
||||
if (packet_have_data_to_write())
|
||||
FD_SET(connection_out, writeset);
|
||||
|
||||
/* Update the maximum descriptor number if appropriate. */
|
||||
if (channel_max_fd() > max_fd)
|
||||
max_fd = channel_max_fd();
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
if (tvp!=NULL)
|
||||
debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
|
||||
|
||||
/* Wait for something to happen, or the timeout to expire. */
|
||||
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
|
||||
|
||||
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.
|
||||
*/
|
||||
static 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();
|
||||
} else if (len < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
verbose("Read error from remote host: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
} else {
|
||||
/* Buffer any received data. */
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
}
|
||||
if (compat20)
|
||||
return;
|
||||
|
||||
/* 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 && (errno == EINTR || errno == EAGAIN)) {
|
||||
/* do nothing */
|
||||
} else 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 && (errno == EINTR || errno == EAGAIN)) {
|
||||
/* do nothing */
|
||||
} else if (len <= 0) {
|
||||
fderr_eof = 1;
|
||||
} else {
|
||||
buffer_append(&stderr_buffer, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends data from internal buffers to client program stdin.
|
||||
*/
|
||||
static void
|
||||
process_output(fd_set * writeset)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Write buffered data to program stdin. */
|
||||
if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
|
||||
len = write(fdin, buffer_ptr(&stdin_buffer),
|
||||
buffer_len(&stdin_buffer));
|
||||
if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
|
||||
/* do nothing */
|
||||
} else if (len <= 0) {
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
#else
|
||||
if (fdin != fdout)
|
||||
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.
|
||||
*/
|
||||
static void
|
||||
drain_output(void)
|
||||
{
|
||||
/* 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();
|
||||
}
|
||||
|
||||
static void
|
||||
process_buffered_input_packets(void)
|
||||
{
|
||||
dispatch_run(DISPATCH_NONBLOCK, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs the interactive session. This handles data transmission between
|
||||
* the client and the program. Note that the notion of stdin, stdout, and
|
||||
* stderr in this function is sort of reversed: this function writes to
|
||||
* stdin (of the child program), and reads from stdout and stderr (of the
|
||||
* child program).
|
||||
*/
|
||||
void
|
||||
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int wait_status; /* Status returned by wait(). */
|
||||
pid_t wait_pid; /* pid returned by wait(). */
|
||||
int waiting_termination = 0; /* Have displayed waiting close message. */
|
||||
unsigned int max_time_milliseconds;
|
||||
unsigned int previous_stdout_buffer_bytes;
|
||||
unsigned int stdout_buffer_bytes;
|
||||
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;
|
||||
|
||||
/* nonblocking IO */
|
||||
set_nonblock(fdin);
|
||||
set_nonblock(fdout);
|
||||
/* we don't have stderr for interactive terminal sessions, see below */
|
||||
if (fderr != -1)
|
||||
set_nonblock(fderr);
|
||||
|
||||
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;
|
||||
|
||||
server_init_dispatch();
|
||||
|
||||
/* Main loop of the server for the interactive session mode. */
|
||||
for (;;) {
|
||||
|
||||
/* 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 (fdin != fdout)
|
||||
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())
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
void
|
||||
server_loop2(void)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int had_channel = 0;
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
debug("Entering interactive session for SSH2.");
|
||||
|
||||
signal(SIGCHLD, sigchld_handler2);
|
||||
child_terminated = 0;
|
||||
connection_in = packet_get_connection_in();
|
||||
connection_out = packet_get_connection_out();
|
||||
max_fd = connection_in;
|
||||
if (connection_out > max_fd)
|
||||
max_fd = connection_out;
|
||||
server_init_dispatch();
|
||||
|
||||
for (;;) {
|
||||
process_buffered_input_packets();
|
||||
if (!had_channel && channel_still_open())
|
||||
had_channel = 1;
|
||||
if (had_channel && !channel_still_open()) {
|
||||
debug("!channel_still_open.");
|
||||
break;
|
||||
}
|
||||
if (packet_not_very_much_data_to_write())
|
||||
channel_output_poll();
|
||||
wait_until_can_do_something(&readset, &writeset, 0);
|
||||
if (child_terminated) {
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
child_terminated = 0;
|
||||
}
|
||||
channel_after_select(&readset, &writeset);
|
||||
process_input(&readset);
|
||||
process_output(&writeset);
|
||||
}
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
channel_stop_listening();
|
||||
}
|
||||
|
||||
static void
|
||||
server_input_stdin_data(int type, int plen, void *ctxt)
|
||||
{
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
|
||||
/* Stdin data from the client. Append it to the buffer. */
|
||||
/* Ignore any data if the client has closed stdin. */
|
||||
if (fdin == -1)
|
||||
return;
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(plen, (4 + data_len), type);
|
||||
buffer_append(&stdin_buffer, data, data_len);
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
static void
|
||||
server_input_eof(int type, int plen, void *ctxt)
|
||||
{
|
||||
/*
|
||||
* 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(plen, 0, type);
|
||||
stdin_eof = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
server_input_window_size(int type, int plen, void *ctxt)
|
||||
{
|
||||
int row = packet_get_int();
|
||||
int col = packet_get_int();
|
||||
int xpixel = packet_get_int();
|
||||
int ypixel = packet_get_int();
|
||||
|
||||
debug("Window change received.");
|
||||
packet_integrity_check(plen, 4 * 4, type);
|
||||
if (fdin != -1)
|
||||
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
||||
}
|
||||
|
||||
static int
|
||||
input_direct_tcpip(void)
|
||||
{
|
||||
int sock;
|
||||
char *target, *originator;
|
||||
int target_port, originator_port;
|
||||
|
||||
target = packet_get_string(NULL);
|
||||
target_port = packet_get_int();
|
||||
originator = packet_get_string(NULL);
|
||||
originator_port = packet_get_int();
|
||||
packet_done();
|
||||
|
||||
debug("open direct-tcpip: from %s port %d to %s port %d",
|
||||
originator, originator_port, target, target_port);
|
||||
|
||||
/* XXX check permission */
|
||||
if (no_port_forwarding_flag) {
|
||||
xfree(target);
|
||||
xfree(originator);
|
||||
return -1;
|
||||
}
|
||||
sock = channel_connect_to(target, target_port);
|
||||
xfree(target);
|
||||
xfree(originator);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
|
||||
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
|
||||
CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"));
|
||||
}
|
||||
|
||||
static void
|
||||
server_input_channel_open(int type, int plen, void *ctxt)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
char *ctype;
|
||||
int id;
|
||||
unsigned int len;
|
||||
int rchan;
|
||||
int rmaxpack;
|
||||
int rwindow;
|
||||
|
||||
ctype = packet_get_string(&len);
|
||||
rchan = packet_get_int();
|
||||
rwindow = packet_get_int();
|
||||
rmaxpack = packet_get_int();
|
||||
|
||||
debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
|
||||
ctype, rchan, rwindow, rmaxpack);
|
||||
|
||||
if (strcmp(ctype, "session") == 0) {
|
||||
debug("open session");
|
||||
packet_done();
|
||||
/*
|
||||
* A server session has no fd to read or write
|
||||
* until a CHANNEL_REQUEST for a shell is made,
|
||||
* so we set the type to SSH_CHANNEL_LARVAL.
|
||||
* Additionally, a callback for handling all
|
||||
* CHANNEL_REQUEST messages is registered.
|
||||
*/
|
||||
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
|
||||
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
|
||||
0, xstrdup("server-session"));
|
||||
if (session_open(id) == 1) {
|
||||
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
|
||||
session_input_channel_req, (void *)0);
|
||||
channel_register_cleanup(id, session_close_by_channel);
|
||||
c = channel_lookup(id);
|
||||
} else {
|
||||
debug("session open failed, free channel %d", id);
|
||||
channel_free(id);
|
||||
}
|
||||
} else if (strcmp(ctype, "direct-tcpip") == 0) {
|
||||
id = input_direct_tcpip();
|
||||
if (id >= 0)
|
||||
c = channel_lookup(id);
|
||||
}
|
||||
if (c != NULL) {
|
||||
debug("confirm %s", ctype);
|
||||
c->remote_id = rchan;
|
||||
c->remote_window = rwindow;
|
||||
c->remote_maxpacket = rmaxpack;
|
||||
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
packet_send();
|
||||
} else {
|
||||
debug("failure %s", ctype);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(rchan);
|
||||
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
|
||||
packet_put_cstring("bla bla");
|
||||
packet_put_cstring("");
|
||||
packet_send();
|
||||
}
|
||||
xfree(ctype);
|
||||
}
|
||||
|
||||
static void
|
||||
server_init_dispatch_20(void)
|
||||
{
|
||||
debug("server_init_dispatch_20");
|
||||
dispatch_init(&dispatch_protocol_error);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
|
||||
}
|
||||
static void
|
||||
server_init_dispatch_13(void)
|
||||
{
|
||||
debug("server_init_dispatch_13");
|
||||
dispatch_init(NULL);
|
||||
dispatch_set(SSH_CMSG_EOF, &server_input_eof);
|
||||
dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
|
||||
dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
|
||||
}
|
||||
static void
|
||||
server_init_dispatch_15(void)
|
||||
{
|
||||
server_init_dispatch_13();
|
||||
debug("server_init_dispatch_15");
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
|
||||
}
|
||||
void
|
||||
server_init_dispatch()
|
||||
{
|
||||
if (compat20)
|
||||
server_init_dispatch_20();
|
||||
else if (compat13)
|
||||
server_init_dispatch_13();
|
||||
else
|
||||
server_init_dispatch_15();
|
||||
}
|
1635
crypto/dist/ssh/session.c
vendored
Normal file
1635
crypto/dist/ssh/session.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
crypto/dist/ssh/session.h
vendored
Normal file
40
crypto/dist/ssh/session.h
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/* $NetBSD: session.h,v 1.1.1.1 2000/09/28 22:10:23 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
/* SSH1 */
|
||||
void do_authenticated(struct passwd * pw);
|
||||
|
||||
/* SSH2 */
|
||||
void do_authenticated2(void);
|
||||
int session_open(int id);
|
||||
void session_input_channel_req(int id, void *arg);
|
||||
void session_close_by_pid(pid_t pid, int status);
|
||||
void session_close_by_channel(int id, void *arg);
|
||||
|
||||
#endif
|
59
crypto/dist/ssh/sftp-server.8
vendored
Normal file
59
crypto/dist/ssh/sftp-server.8
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
.\"
|
||||
.\" $NetBSD: sftp-server.8,v 1.1.1.1 2000/09/28 22:10:23 thorpej Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from OpenBSD: sftp-server.8,v 1.2 2000/09/07 20:27:53 deraadt Exp
|
||||
.\"
|
||||
.Dd August 30, 2000
|
||||
.Dt SFTP-SERVER 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sftp-server
|
||||
.Nd SFTP server subsystem
|
||||
.Sh SYNOPSIS
|
||||
.Nm sftp-server
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a program that speaks the server side of SFTP protocol
|
||||
to stdout and expects client requests from stdin.
|
||||
.Nm
|
||||
is not intended to be called directly, but from
|
||||
.Xr sshd 8
|
||||
using the
|
||||
.Cm Subsystem
|
||||
option.
|
||||
See
|
||||
.Xr sshd 8
|
||||
for more information.
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
first appeared in
|
||||
.Nx 1.5 .
|
||||
.Sh AUTHOR
|
||||
Markus Friedl <markus@openbsd.org>
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8
|
1078
crypto/dist/ssh/sftp-server.c
vendored
Normal file
1078
crypto/dist/ssh/sftp-server.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
131
crypto/dist/ssh/ssh-add.1
vendored
Normal file
131
crypto/dist/ssh/ssh-add.1
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" $NetBSD: ssh-add.1,v 1.1.1.1 2000/09/28 22:10:25 thorpej Exp $
|
||||
.\"
|
||||
.\" 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
|
||||
.\"
|
||||
.\" As far as I am concerned, the code I have written for this software
|
||||
.\" can be used freely for any purpose. Any derived versions of this
|
||||
.\" software must be clearly marked as such, and if the derived work is
|
||||
.\" incompatible with the protocol description in the RFC file, it must be
|
||||
.\" called by a name other than "ssh" or "Secure Shell".
|
||||
.\"
|
||||
.\"
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd August 6, 2000
|
||||
.Dt SSH-ADD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-add
|
||||
.Nd add RSA or DSA identities to the Secure Shell authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-add
|
||||
.Op Fl lLdD
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
adds RSA or DSA identities to the Secure Shell 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.
|
||||
If
|
||||
.Nm
|
||||
was invoked from a tty, the Passphrase is read from the tty.
|
||||
If
|
||||
.Nm
|
||||
was not invoked from a tty, the
|
||||
.Ev DISPLAY
|
||||
environment variable is consulted and, if set, an external
|
||||
Passphrase prompting program is run on that display.
|
||||
.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 "SSH_ASKPASS"
|
||||
.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 identity added by
|
||||
.Nm
|
||||
when no other files have been specified.
|
||||
.It Pa $HOME/.ssh/id_dsa
|
||||
Contains the DSA authentication identity of the user.
|
||||
.Pp
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width "SSH_ASKPASS"
|
||||
.It Ev DISPLAY
|
||||
If set, indicates the X11 display associated with a session. This
|
||||
is the display that the external Passphrase prompting program will
|
||||
be run on.
|
||||
.It Ev SSH_ASKPASS
|
||||
If set, indicates the program to use as the external Passphrase
|
||||
prompter. If unset,
|
||||
.Nm
|
||||
will use the default
|
||||
.Pa /usr/X11R6/bin/ssh-askpass .
|
||||
This environment variable is useful for selecting Passphrase prompters
|
||||
that are part of integrated desktop environments, such as
|
||||
.Em GNOME
|
||||
or
|
||||
.Em KDE .
|
||||
.El
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>, Markus Friedl
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8
|
314
crypto/dist/ssh/ssh-add.c
vendored
Normal file
314
crypto/dist/ssh/ssh-add.c
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/* $NetBSD: ssh-add.c,v 1.1.1.1 2000/09/28 22:10:26 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Adds an identity to the authentication server, or removes an identity.
|
||||
*
|
||||
* 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".
|
||||
*
|
||||
* SSH2 implementation,
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: ssh-add.c,v 1.22 2000/09/07 20:27:54 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: ssh-add.c,v 1.1.1.1 2000/09/28 22:10:26 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pathnames.h"
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "authfile.h"
|
||||
|
||||
static void
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
Key *public;
|
||||
char *comment;
|
||||
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &comment)) {
|
||||
key_free(public);
|
||||
public = key_new(KEY_DSA);
|
||||
if (!try_load_public_key(filename, public, &comment)) {
|
||||
printf("Bad key file %s\n", filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ssh_remove_identity(ac, public))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
key_free(public);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
/* Send a request to remove all identities. */
|
||||
static void
|
||||
delete_all(AuthenticationConnection *ac)
|
||||
{
|
||||
int success = 1;
|
||||
|
||||
if (!ssh_remove_all_identities(ac, 1))
|
||||
success = 0;
|
||||
/* ignore error-code for ssh2 */
|
||||
ssh_remove_all_identities(ac, 2);
|
||||
|
||||
if (success)
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to remove all identitities.\n");
|
||||
}
|
||||
|
||||
static char *
|
||||
ssh_askpass(const 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;
|
||||
}
|
||||
|
||||
static void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
Key *public;
|
||||
Key *private;
|
||||
char *saved_comment, *comment;
|
||||
const char *askpass = NULL;
|
||||
char buf[1024], msg[1024];
|
||||
int success;
|
||||
int interactive = isatty(STDIN_FILENO);
|
||||
int type = KEY_RSA;
|
||||
int count;
|
||||
|
||||
if (stat(filename, &st) < 0) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* try to load the public key. right now this only works for RSA,
|
||||
* since DSA keys are fully encrypted
|
||||
*/
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &saved_comment)) {
|
||||
/* ok, so we will asume this is a DSA key */
|
||||
type = KEY_DSA;
|
||||
saved_comment = xstrdup(filename);
|
||||
}
|
||||
key_free(public);
|
||||
|
||||
if (!interactive && getenv("DISPLAY")) {
|
||||
if (getenv(SSH_ASKPASS_ENV))
|
||||
askpass = getenv(SSH_ASKPASS_ENV);
|
||||
else
|
||||
askpass = _PATH_SSH_ASKPASS;
|
||||
}
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
private = key_new(type);
|
||||
success = load_private_key(filename, "", private, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %.200s\n", filename);
|
||||
if (!interactive && askpass == NULL) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
for (count = 0; ; count++) {
|
||||
char *pass;
|
||||
|
||||
snprintf(msg, sizeof msg,
|
||||
"%sEnter passphrase for %.200s",
|
||||
count > 0 ?
|
||||
"You entered the wrong passphrase. " : "",
|
||||
saved_comment);
|
||||
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, private, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
break;
|
||||
}
|
||||
}
|
||||
xfree(comment);
|
||||
if (ssh_add_identity(ac, private, saved_comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, saved_comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
key_free(private);
|
||||
xfree(saved_comment);
|
||||
}
|
||||
|
||||
static void
|
||||
list_identities(AuthenticationConnection *ac, int fp)
|
||||
{
|
||||
Key *key;
|
||||
char *comment;
|
||||
int had_identities = 0;
|
||||
int version;
|
||||
|
||||
for (version = 1; version <= 2; version++) {
|
||||
for (key = ssh_get_first_identity(ac, &comment, version);
|
||||
key != NULL;
|
||||
key = ssh_get_next_identity(ac, &comment, version)) {
|
||||
had_identities = 1;
|
||||
if (fp) {
|
||||
printf("%d %s %s\n",
|
||||
key_size(key), key_fingerprint(key), comment);
|
||||
} else {
|
||||
if (!key_write(key, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
fprintf(stdout, " %s\n", comment);
|
||||
}
|
||||
key_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
SSLeay_add_all_algorithms();
|
||||
|
||||
/* 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 %u\n",
|
||||
(u_int)getuid());
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(1);
|
||||
}
|
||||
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
|
||||
if (deleting)
|
||||
delete_file(ac, buf);
|
||||
else
|
||||
add_file(ac, buf);
|
||||
}
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(0);
|
||||
}
|
208
crypto/dist/ssh/ssh-agent.1
vendored
Normal file
208
crypto/dist/ssh/ssh-agent.1
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
.\"
|
||||
.\" $NetBSD: ssh-agent.1,v 1.1.1.1 2000/09/28 22:10:27 thorpej Exp $
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" As far as I am concerned, the code I have written for this software
|
||||
.\" can be used freely for any purpose. Any derived versions of this
|
||||
.\" software must be clearly marked as such, and if the derived work is
|
||||
.\" incompatible with the protocol description in the RFC file, it must be
|
||||
.\" called by a name other than "ssh" or "Secure Shell".
|
||||
.\"
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" from OpenBSD: ssh-agent.1,v 1.16 2000/09/07 20:27:54 deraadt Exp
|
||||
.\"
|
||||
.Dd August 6, 2000
|
||||
.Dt SSH-AGENT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-agent
|
||||
.Nd authentication agent for the Secure Shell
|
||||
.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 private keys used for public key (RSA or DSA)
|
||||
authentication. It is intended to be started at the beginning of
|
||||
an X Window System or login session.
|
||||
.Nm
|
||||
works by setting certain variables in the user's environment. Through
|
||||
the use of these environment variables, the agent can be located
|
||||
and automatically used for RSA authentication when logging in to
|
||||
other hosts using
|
||||
.Xr ssh 1 .
|
||||
.Pp
|
||||
A user generally one identity per
|
||||
.Dq workstation ,
|
||||
e.g. laptop or desktop computer, handheld device, etc. Use of
|
||||
.Nm
|
||||
on these workstations prevents having to store authentication
|
||||
information on remote hosts, and prevents having to transmit
|
||||
Passphrases over the network.
|
||||
.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 command line is given, it is executed as a sub-process of the agent.
|
||||
When the command dies, so does the agent. If a command line is not given,
|
||||
the agent will not automatically exit, and must be explicitly killed with
|
||||
the
|
||||
.Fl k
|
||||
option when the session ends.
|
||||
.Pp
|
||||
The agent initially does not have any private keys.
|
||||
Keys must added using
|
||||
.Xr ssh-add 1 .
|
||||
.Pp
|
||||
There are two main ways to set up the agent:
|
||||
.Bl -bullet
|
||||
.It
|
||||
Invoke
|
||||
.Nm
|
||||
with a command line. The command will be started with the
|
||||
appropriate environment variables set to use the agent.
|
||||
.It
|
||||
Invoke
|
||||
.Nm
|
||||
without a command line, which causes
|
||||
.Nm
|
||||
to print shell commands which will set up the enviroment if
|
||||
evaluated by the shell.
|
||||
.Nm
|
||||
will attempt to detect if you are running a
|
||||
.Xr csh 1
|
||||
or
|
||||
.Xr sh 1
|
||||
style shell, and generate the appropriate syntax. The
|
||||
syntax can be forced with the
|
||||
.Fl c
|
||||
and
|
||||
.Fl s
|
||||
flags.
|
||||
.El
|
||||
.Pp
|
||||
When the agent is started, a Unix-domain socket is created
|
||||
and the name of this socket 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.
|
||||
.Sh EXAMPLES
|
||||
The following shows using the command line facility of
|
||||
.Nm
|
||||
to associate an agent with an X session started by
|
||||
.Xr xinit 1 :
|
||||
.Bd -literal -offset indent
|
||||
#!/bin/sh -
|
||||
#
|
||||
# $HOME/.xinitrc
|
||||
#
|
||||
|
||||
if [ -r $HOME/.ssh/identity ]; then
|
||||
EXEC="exec ssh-agent"
|
||||
else
|
||||
EXEC="exec"
|
||||
fi
|
||||
|
||||
# .xsession will perform the ssh-add to add the keys.
|
||||
$EXEC $HOME/.xsession
|
||||
.Ed
|
||||
.Pp
|
||||
The following shows using
|
||||
.Nm
|
||||
and
|
||||
.Xr ssh-add 1
|
||||
in an X session startup script:
|
||||
.Bd -literal -offset indent
|
||||
#!/bin/sh -
|
||||
#
|
||||
# $HOME/.xsession
|
||||
#
|
||||
|
||||
if [ -f $HOME/.Xdefaults ]; then
|
||||
xrdb -merge $HOME/.Xdefaults
|
||||
fi
|
||||
|
||||
xsetroot -solid black
|
||||
|
||||
if [ -r $HOME/.ssh/identity ]; then
|
||||
eval `ssh-agent`
|
||||
ssh-add < /dev/null # ensure stdin is not a tty
|
||||
if [ $? != 0 ]; then
|
||||
# Failed to provide a Passphrase, bail out!
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start the window manager.
|
||||
twm
|
||||
|
||||
# Kill the agent we started above.
|
||||
if [ -n "$SSH_AGENT_PID" ]; then
|
||||
ssh-agent -k
|
||||
fi
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa /tmp/ssh-XXXXXXXX/agent.<pid>
|
||||
Unix-domain sockets used to communicate with the
|
||||
authentication agent. These sockets should only be readable by the
|
||||
owner. The sockets should get automatically removed when the agent
|
||||
exits.
|
||||
.El
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>, Markus Friedl
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr sshd 8
|
829
crypto/dist/ssh/ssh-agent.c
vendored
Normal file
829
crypto/dist/ssh/ssh-agent.c
vendored
Normal file
@ -0,0 +1,829 @@
|
||||
/* $NetBSD: ssh-agent.c,v 1.1.1.1 2000/09/28 22:10:29 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* The authentication agent program.
|
||||
*
|
||||
* 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".
|
||||
*
|
||||
* SSH2 implementation,
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* from OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: ssh-agent.c,v 1.1.1.1 2000/09/28 22:10:29 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "packet.h"
|
||||
#include "pathnames.h"
|
||||
#include "getput.h"
|
||||
#include "mpaux.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "dsa.h"
|
||||
#include "kex.h"
|
||||
#include "compat.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 {
|
||||
Key *key;
|
||||
char *comment;
|
||||
} Identity;
|
||||
|
||||
typedef struct {
|
||||
int nentries;
|
||||
Identity *identities;
|
||||
} Idtab;
|
||||
|
||||
/* private key table, one per protocol version */
|
||||
Idtab idtable[3];
|
||||
|
||||
int max_fd = 0;
|
||||
|
||||
/* pid of shell == parent of agent */
|
||||
pid_t parent_pid = -1;
|
||||
|
||||
/* pathname and directory for AUTH_SOCKET */
|
||||
char socket_name[1024];
|
||||
char socket_dir[1024];
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
static void
|
||||
idtab_init(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <=2; i++){
|
||||
idtable[i].identities = NULL;
|
||||
idtable[i].nentries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* return private key table for requested protocol version */
|
||||
static Idtab *
|
||||
idtab_lookup(int version)
|
||||
{
|
||||
if (version < 1 || version > 2)
|
||||
fatal("internal error, bad protocol version %d", version);
|
||||
return &idtable[version];
|
||||
}
|
||||
|
||||
/* return matching private key for given public key */
|
||||
static Key *
|
||||
lookup_private_key(Key *key, int *idx, int version)
|
||||
{
|
||||
int i;
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
for (i = 0; i < tab->nentries; i++) {
|
||||
if (key_equal(key, tab->identities[i].key)) {
|
||||
if (idx != NULL)
|
||||
*idx = i;
|
||||
return tab->identities[i].key;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* send list of supported public keys to 'client' */
|
||||
static void
|
||||
process_request_identities(SocketEntry *e, int version)
|
||||
{
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
Buffer msg;
|
||||
int i;
|
||||
|
||||
buffer_init(&msg);
|
||||
buffer_put_char(&msg, (version == 1) ?
|
||||
SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
|
||||
buffer_put_int(&msg, tab->nentries);
|
||||
for (i = 0; i < tab->nentries; i++) {
|
||||
Identity *id = &tab->identities[i];
|
||||
if (id->key->type == KEY_RSA) {
|
||||
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
|
||||
buffer_put_bignum(&msg, id->key->rsa->e);
|
||||
buffer_put_bignum(&msg, id->key->rsa->n);
|
||||
} else {
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
dsa_make_key_blob(id->key, &blob, &blen);
|
||||
buffer_put_string(&msg, blob, blen);
|
||||
xfree(blob);
|
||||
}
|
||||
buffer_put_cstring(&msg, id->comment);
|
||||
}
|
||||
buffer_put_int(&e->output, buffer_len(&msg));
|
||||
buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
|
||||
buffer_free(&msg);
|
||||
}
|
||||
|
||||
/* ssh1 only */
|
||||
static void
|
||||
process_authentication_challenge1(SocketEntry *e)
|
||||
{
|
||||
Key *key, *private;
|
||||
BIGNUM *challenge;
|
||||
int i, len;
|
||||
Buffer msg;
|
||||
MD5_CTX md;
|
||||
unsigned char buf[32], mdbuf[16], session_id[16];
|
||||
unsigned int response_type;
|
||||
|
||||
buffer_init(&msg);
|
||||
key = key_new(KEY_RSA);
|
||||
challenge = BN_new();
|
||||
|
||||
buffer_get_int(&e->input); /* ignored */
|
||||
buffer_get_bignum(&e->input, key->rsa->e);
|
||||
buffer_get_bignum(&e->input, key->rsa->n);
|
||||
buffer_get_bignum(&e->input, challenge);
|
||||
|
||||
/* Only protocol 1.1 is supported */
|
||||
if (buffer_len(&e->input) == 0)
|
||||
goto failure;
|
||||
buffer_get(&e->input, (char *) session_id, 16);
|
||||
response_type = buffer_get_int(&e->input);
|
||||
if (response_type != 1)
|
||||
goto failure;
|
||||
|
||||
private = lookup_private_key(key, NULL, 1);
|
||||
if (private != NULL) {
|
||||
/* Decrypt the challenge using the private key. */
|
||||
rsa_private_decrypt(challenge, challenge, private->rsa);
|
||||
|
||||
/* The response is MD5 of decrypted challenge plus session id. */
|
||||
len = BN_num_bytes(challenge);
|
||||
if (len <= 0 || len > 32) {
|
||||
log("process_authentication_challenge: bad challenge length %d", len);
|
||||
goto failure;
|
||||
}
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
failure:
|
||||
/* Unknown identity or protocol error. 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));
|
||||
key_free(key);
|
||||
BN_clear_free(challenge);
|
||||
buffer_free(&msg);
|
||||
}
|
||||
|
||||
/* ssh2 only */
|
||||
static void
|
||||
process_sign_request2(SocketEntry *e)
|
||||
{
|
||||
extern int datafellows;
|
||||
Key *key, *private;
|
||||
unsigned char *blob, *data, *signature = NULL;
|
||||
unsigned int blen, dlen, slen = 0;
|
||||
int flags;
|
||||
Buffer msg;
|
||||
int ok = -1;
|
||||
|
||||
datafellows = 0;
|
||||
|
||||
blob = buffer_get_string(&e->input, &blen);
|
||||
data = buffer_get_string(&e->input, &dlen);
|
||||
|
||||
flags = buffer_get_int(&e->input);
|
||||
if (flags & SSH_AGENT_OLD_SIGNATURE)
|
||||
datafellows = SSH_BUG_SIGBLOB;
|
||||
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
if (key != NULL) {
|
||||
private = lookup_private_key(key, NULL, 2);
|
||||
if (private != NULL)
|
||||
ok = dsa_sign(private, &signature, &slen, data, dlen);
|
||||
}
|
||||
key_free(key);
|
||||
buffer_init(&msg);
|
||||
if (ok == 0) {
|
||||
buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
|
||||
buffer_put_string(&msg, signature, slen);
|
||||
} else {
|
||||
buffer_put_char(&msg, SSH_AGENT_FAILURE);
|
||||
}
|
||||
buffer_put_int(&e->output, buffer_len(&msg));
|
||||
buffer_append(&e->output, buffer_ptr(&msg),
|
||||
buffer_len(&msg));
|
||||
buffer_free(&msg);
|
||||
xfree(data);
|
||||
xfree(blob);
|
||||
if (signature != NULL)
|
||||
xfree(signature);
|
||||
}
|
||||
|
||||
/* shared */
|
||||
static void
|
||||
process_remove_identity(SocketEntry *e, int version)
|
||||
{
|
||||
Key *key = NULL, *private;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
unsigned int bits;
|
||||
int success = 0;
|
||||
|
||||
switch(version){
|
||||
case 1:
|
||||
key = key_new(KEY_RSA);
|
||||
bits = buffer_get_int(&e->input);
|
||||
buffer_get_bignum(&e->input, key->rsa->e);
|
||||
buffer_get_bignum(&e->input, key->rsa->n);
|
||||
|
||||
if (bits != key_size(key))
|
||||
log("Warning: identity keysize mismatch: actual %d, announced %d",
|
||||
key_size(key), bits);
|
||||
break;
|
||||
case 2:
|
||||
blob = buffer_get_string(&e->input, &blen);
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
xfree(blob);
|
||||
break;
|
||||
}
|
||||
if (key != NULL) {
|
||||
int idx;
|
||||
private = lookup_private_key(key, &idx, version);
|
||||
if (private != NULL) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
key_free(tab->identities[idx].key);
|
||||
xfree(tab->identities[idx].comment);
|
||||
if (idx != tab->nentries)
|
||||
tab->identities[idx] = tab->identities[tab->nentries];
|
||||
tab->nentries--;
|
||||
success = 1;
|
||||
}
|
||||
key_free(key);
|
||||
}
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output,
|
||||
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
process_remove_all_identities(SocketEntry *e, int version)
|
||||
{
|
||||
unsigned int i;
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
|
||||
/* Loop over all identities and clear the keys. */
|
||||
for (i = 0; i < tab->nentries; i++) {
|
||||
key_free(tab->identities[i].key);
|
||||
xfree(tab->identities[i].comment);
|
||||
}
|
||||
|
||||
/* Mark that there are no identities. */
|
||||
tab->nentries = 0;
|
||||
|
||||
/* Send success. */
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
process_add_identity(SocketEntry *e, int version)
|
||||
{
|
||||
Key *k = NULL;
|
||||
RSA *rsa;
|
||||
BIGNUM *aux;
|
||||
BN_CTX *ctx;
|
||||
char *type;
|
||||
char *comment;
|
||||
int success = 0;
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
k = key_new(KEY_RSA);
|
||||
rsa = k->rsa;
|
||||
|
||||
/* allocate mem for private key */
|
||||
/* XXX rsa->n and rsa->e are already allocated */
|
||||
rsa->d = BN_new();
|
||||
rsa->iqmp = BN_new();
|
||||
rsa->q = BN_new();
|
||||
rsa->p = BN_new();
|
||||
rsa->dmq1 = BN_new();
|
||||
rsa->dmp1 = BN_new();
|
||||
|
||||
buffer_get_int(&e->input); /* ignored */
|
||||
|
||||
buffer_get_bignum(&e->input, rsa->n);
|
||||
buffer_get_bignum(&e->input, rsa->e);
|
||||
buffer_get_bignum(&e->input, rsa->d);
|
||||
buffer_get_bignum(&e->input, rsa->iqmp);
|
||||
|
||||
/* SSH and SSL have p and q swapped */
|
||||
buffer_get_bignum(&e->input, rsa->q); /* p */
|
||||
buffer_get_bignum(&e->input, rsa->p); /* q */
|
||||
|
||||
/* Generate additional parameters */
|
||||
aux = BN_new();
|
||||
ctx = BN_CTX_new();
|
||||
|
||||
BN_sub(aux, rsa->q, BN_value_one());
|
||||
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
|
||||
|
||||
BN_sub(aux, rsa->p, BN_value_one());
|
||||
BN_mod(rsa->dmp1, rsa->d, aux, ctx);
|
||||
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
type = buffer_get_string(&e->input, NULL);
|
||||
if (strcmp(type, KEX_DSS)) {
|
||||
buffer_clear(&e->input);
|
||||
xfree(type);
|
||||
goto send;
|
||||
}
|
||||
xfree(type);
|
||||
|
||||
k = key_new(KEY_DSA);
|
||||
|
||||
/* allocate mem for private key */
|
||||
k->dsa->priv_key = BN_new();
|
||||
|
||||
buffer_get_bignum2(&e->input, k->dsa->p);
|
||||
buffer_get_bignum2(&e->input, k->dsa->q);
|
||||
buffer_get_bignum2(&e->input, k->dsa->g);
|
||||
buffer_get_bignum2(&e->input, k->dsa->pub_key);
|
||||
buffer_get_bignum2(&e->input, k->dsa->priv_key);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
comment = buffer_get_string(&e->input, NULL);
|
||||
if (k == NULL) {
|
||||
xfree(comment);
|
||||
goto send;
|
||||
}
|
||||
success = 1;
|
||||
if (lookup_private_key(k, NULL, version) == NULL) {
|
||||
if (tab->nentries == 0)
|
||||
tab->identities = xmalloc(sizeof(Identity));
|
||||
else
|
||||
tab->identities = xrealloc(tab->identities,
|
||||
(tab->nentries + 1) * sizeof(Identity));
|
||||
tab->identities[tab->nentries].key = k;
|
||||
tab->identities[tab->nentries].comment = comment;
|
||||
/* Increment the number of identities. */
|
||||
tab->nentries++;
|
||||
} else {
|
||||
key_free(k);
|
||||
xfree(comment);
|
||||
}
|
||||
send:
|
||||
buffer_put_int(&e->output, 1);
|
||||
buffer_put_char(&e->output,
|
||||
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
|
||||
}
|
||||
|
||||
/* dispatch incoming messages */
|
||||
|
||||
static 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) {
|
||||
/* ssh1 */
|
||||
case SSH_AGENTC_RSA_CHALLENGE:
|
||||
process_authentication_challenge1(e);
|
||||
break;
|
||||
case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
|
||||
process_request_identities(e, 1);
|
||||
break;
|
||||
case SSH_AGENTC_ADD_RSA_IDENTITY:
|
||||
process_add_identity(e, 1);
|
||||
break;
|
||||
case SSH_AGENTC_REMOVE_RSA_IDENTITY:
|
||||
process_remove_identity(e, 1);
|
||||
break;
|
||||
case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
|
||||
process_remove_all_identities(e, 1);
|
||||
break;
|
||||
/* ssh2 */
|
||||
case SSH2_AGENTC_SIGN_REQUEST:
|
||||
process_sign_request2(e);
|
||||
break;
|
||||
case SSH2_AGENTC_REQUEST_IDENTITIES:
|
||||
process_request_identities(e, 2);
|
||||
break;
|
||||
case SSH2_AGENTC_ADD_IDENTITY:
|
||||
process_add_identity(e, 2);
|
||||
break;
|
||||
case SSH2_AGENTC_REMOVE_IDENTITY:
|
||||
process_remove_identity(e, 2);
|
||||
break;
|
||||
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
|
||||
process_remove_all_identities(e, 2);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
after_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
unsigned int i;
|
||||
int len, sock;
|
||||
socklen_t slen;
|
||||
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)) {
|
||||
slen = sizeof(sunaddr);
|
||||
sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen);
|
||||
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;
|
||||
buffer_free(&sockets[i].input);
|
||||
buffer_free(&sockets[i].output);
|
||||
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;
|
||||
buffer_free(&sockets[i].input);
|
||||
buffer_free(&sockets[i].output);
|
||||
break;
|
||||
}
|
||||
buffer_append(&sockets[i].input, buf, len);
|
||||
process_message(&sockets[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown type %d", sockets[i].type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_parent_exists(int sig)
|
||||
{
|
||||
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
|
||||
/* printf("Parent has died - Authentication agent exiting.\n"); */
|
||||
exit(1);
|
||||
}
|
||||
signal(SIGALRM, check_parent_exists);
|
||||
alarm(10);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_socket(void)
|
||||
{
|
||||
remove(socket_name);
|
||||
rmdir(socket_dir);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_exit(int i)
|
||||
{
|
||||
cleanup_socket();
|
||||
exit(i);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
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 */
|
||||
/* Yes, PID_MAX check please */
|
||||
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, _PATH_SSH_TMPDIR, 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);
|
||||
}
|
||||
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
|
||||
setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
|
||||
perror("setenv");
|
||||
exit(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);
|
||||
}
|
||||
idtab_init();
|
||||
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 */
|
||||
}
|
221
crypto/dist/ssh/ssh-keygen.1
vendored
Normal file
221
crypto/dist/ssh/ssh-keygen.1
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" $NetBSD: ssh-keygen.1,v 1.1.1.1 2000/09/28 22:10:29 thorpej Exp $
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" As far as I am concerned, the code I have written for this software
|
||||
.\" can be used freely for any purpose. Any derived versions of this
|
||||
.\" software must be clearly marked as such, and if the derived work is
|
||||
.\" incompatible with the protocol description in the RFC file, it must be
|
||||
.\" called by a name other than "ssh" or "Secure Shell".
|
||||
.\"
|
||||
.\"
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd August 6, 2000
|
||||
.Dt SSH-KEYGEN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-keygen
|
||||
.Nd generate Secure Shell authentication keys
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-keygen
|
||||
.Op Fl dq
|
||||
.Op Fl b Ar bits
|
||||
.Op Fl N Ar new_passphrase
|
||||
.Op Fl C Ar comment
|
||||
.Op Fl f Ar output_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 x
|
||||
.Op Fl f Ar input_keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl X
|
||||
.Op Fl f Ar input_keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl y
|
||||
.Op Fl f Ar input_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 input_keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl R
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
generates and manages authentication keys for
|
||||
.Xr ssh 1 .
|
||||
.Nm
|
||||
defaults to generating an RSA key for use by protocols 1.3 and 1.5;
|
||||
specifying the
|
||||
.Fl d
|
||||
flag will create a DSA key for use by protocol 2.0.
|
||||
.Pp
|
||||
Normally each user wishing to use Secure Shell
|
||||
with RSA or DSA authentication runs this once to create the
|
||||
authentication key in
|
||||
.Pa $HOME/.ssh/identity
|
||||
or
|
||||
.Pa $HOME/.ssh/id_dsa .
|
||||
Additionally, the system administrator may use this to generate host keys;
|
||||
An example of this can be found in the
|
||||
.Xr sshd 8
|
||||
startup script
|
||||
.Pa /etc/rc.d/sshd .
|
||||
.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 makes 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
|
||||
For RSA, 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
|
||||
After a key is generated, instructions below detail where the keys
|
||||
should be placed to be activated.
|
||||
.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.d/sshd
|
||||
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.
|
||||
.It Fl R
|
||||
If RSA support is functional, immediately exits with code 0. If RSA
|
||||
support is not functional, exits with code 1. This flag will be
|
||||
removed once the RSA patent expires.
|
||||
.It Fl x
|
||||
This option will read a private OpenSSH-compatible DSA format file and
|
||||
print a SSH2-compatible public key to stdout.
|
||||
.It Fl X
|
||||
This option will read a SSH2-compatible public key file and print an
|
||||
OpenSSH-compatible DSA public key to stdout.
|
||||
.It Fl y
|
||||
This option will read a private OpenSSH-compatible DSA format file and
|
||||
print an OpenSSH-compatible DSA public key to stdout.
|
||||
.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.
|
||||
.Xr sshd 8
|
||||
will read this file when a login attempt is made.
|
||||
.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.
|
||||
.It Pa $HOME/.ssh/id_dsa
|
||||
Contains the DSA 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.
|
||||
.Xr sshd 8
|
||||
will read this file when a login attempt is made.
|
||||
.It Pa $HOME/.ssh/id_dsa.pub
|
||||
Contains the public key for authentication. The contents of this
|
||||
file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
on all machines where you wish to log in using DSA authentication.
|
||||
There is no need to keep the contents of this file secret.
|
||||
.El
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Sh SEE ALSO
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr sshd 8
|
755
crypto/dist/ssh/ssh-keygen.c
vendored
Normal file
755
crypto/dist/ssh/ssh-keygen.c
vendored
Normal file
@ -0,0 +1,755 @@
|
||||
/* $NetBSD: ssh-keygen.c,v 1.1.1.1 2000/09/28 22:10:30 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Identity and host key generation and maintenance.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: ssh-keygen.c,v 1.1.1.1 2000/09/28 22:10:30 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "pathnames.h"
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "rsa.h"
|
||||
#include "dsa.h"
|
||||
#include "authfile.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
/* Number of bits in the RSA/DSA 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;
|
||||
|
||||
/* Dump public key file in format used by real and the original SSH 2 */
|
||||
int convert_to_ssh2 = 0;
|
||||
int convert_from_ssh2 = 0;
|
||||
int print_public = 0;
|
||||
int dsa_mode = 0;
|
||||
|
||||
/* argv0 */
|
||||
extern char *__progname;
|
||||
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
static void
|
||||
ask_filename(struct passwd *pw, const char *prompt)
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(identity_file, sizeof(identity_file), "%s/%s",
|
||||
pw->pw_dir,
|
||||
dsa_mode ? _PATH_SSH_CLIENT_ID_DSA: _PATH_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;
|
||||
}
|
||||
|
||||
static int
|
||||
try_load_key(char *filename, Key *k)
|
||||
{
|
||||
int success = 1;
|
||||
if (!load_private_key(filename, "", k, NULL)) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
if (!load_private_key(filename, pass, k, NULL)) {
|
||||
success = 0;
|
||||
}
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
|
||||
|
||||
static void
|
||||
do_convert_to_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int len;
|
||||
unsigned char *blob;
|
||||
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);
|
||||
}
|
||||
k = key_new(KEY_DSA);
|
||||
if (!try_load_key(identity_file, k)) {
|
||||
fprintf(stderr, "load failed\n");
|
||||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN);
|
||||
fprintf(stdout,
|
||||
"Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
|
||||
BN_num_bits(k->dsa->p),
|
||||
pw->pw_name, hostname);
|
||||
dump_base64(stdout, blob, len);
|
||||
fprintf(stdout, "%s\n", SSH_COM_MAGIC_END);
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_convert_from_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int blen;
|
||||
char line[1024], *p;
|
||||
char blob[8096];
|
||||
char encoded[8096];
|
||||
struct stat st;
|
||||
int escaped = 0;
|
||||
FILE *fp;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fp = fopen(identity_file, "r");
|
||||
if (fp == NULL) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
encoded[0] = '\0';
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (!(p = strchr(line, '\n'))) {
|
||||
fprintf(stderr, "input line too long.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (p > line && p[-1] == '\\')
|
||||
escaped++;
|
||||
if (strncmp(line, "----", 4) == 0 ||
|
||||
strstr(line, ": ") != NULL) {
|
||||
fprintf(stderr, "ignore: %s", line);
|
||||
continue;
|
||||
}
|
||||
if (escaped) {
|
||||
escaped--;
|
||||
fprintf(stderr, "escaped: %s", line);
|
||||
continue;
|
||||
}
|
||||
*p = '\0';
|
||||
strlcat(encoded, line, sizeof(encoded));
|
||||
}
|
||||
blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
|
||||
if (blen < 0) {
|
||||
fprintf(stderr, "uudecode failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
k = dsa_key_from_blob(blob, blen);
|
||||
if (!key_write(k, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
key_free(k);
|
||||
fprintf(stdout, "\n");
|
||||
fclose(fp);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_print_public(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int len;
|
||||
unsigned char *blob;
|
||||
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);
|
||||
}
|
||||
k = key_new(KEY_DSA);
|
||||
if (!try_load_key(identity_file, k)) {
|
||||
fprintf(stderr, "load failed\n");
|
||||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
if (!key_write(k, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
fprintf(stdout, "\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_fingerprint(struct passwd *pw)
|
||||
{
|
||||
/* XXX RSA1 only */
|
||||
|
||||
FILE *f;
|
||||
Key *public;
|
||||
char *comment = NULL, *cp, *ep, line[16*1024];
|
||||
int i, skip = 0, num = 1, invalid = 1;
|
||||
unsigned int ignore;
|
||||
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_new(KEY_RSA);
|
||||
if (load_public_key(identity_file, public, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
|
||||
key_fingerprint(public), comment);
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
f = fopen(identity_file, "r");
|
||||
if (f != NULL) {
|
||||
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, &ignore, public->rsa->e, public->rsa->n)) {
|
||||
invalid = 0;
|
||||
comment = *cp ? cp : comment;
|
||||
printf("%d %s %s\n", key_size(public),
|
||||
key_fingerprint(public),
|
||||
comment ? comment : "no comment");
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
key_free(public);
|
||||
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.
|
||||
*/
|
||||
static void
|
||||
do_change_passphrase(struct passwd *pw)
|
||||
{
|
||||
char *comment;
|
||||
char *old_passphrase, *passphrase1, *passphrase2;
|
||||
struct stat st;
|
||||
Key *private;
|
||||
Key *public;
|
||||
int type = dsa_mode ? KEY_DSA : KEY_RSA;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (type == KEY_RSA) {
|
||||
/* XXX this works currently only for RSA */
|
||||
public = key_new(type);
|
||||
if (!load_public_key(identity_file, public, 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. */
|
||||
key_free(public);
|
||||
}
|
||||
|
||||
/* Try to load the file with empty passphrase. */
|
||||
private = key_new(type);
|
||||
if (!load_private_key(identity_file, "", private, &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, &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, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase and the copy of the key in memory. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
key_free(private); /* 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.
|
||||
*/
|
||||
static void
|
||||
do_change_comment(struct passwd *pw)
|
||||
{
|
||||
char new_comment[1024], *comment;
|
||||
Key *private;
|
||||
Key *public;
|
||||
char *passphrase;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
|
||||
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_new(KEY_RSA);
|
||||
if (!load_public_key(identity_file, public, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
private = key_new(KEY_RSA);
|
||||
if (load_private_key(identity_file, "", private, &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, &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));
|
||||
key_free(private);
|
||||
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, new_comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
key_free(private);
|
||||
|
||||
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);
|
||||
}
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
key_free(public);
|
||||
fprintf(f, " %s\n", new_comment);
|
||||
fclose(f);
|
||||
|
||||
xfree(comment);
|
||||
|
||||
printf("The comment in your key file has been changed.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\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;
|
||||
int opt;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
Key *private;
|
||||
Key *public;
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
SSLeay_add_all_algorithms();
|
||||
|
||||
/* we need this for the home * directory. */
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
printf("You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
perror("gethostname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((opt = getopt(ac, av, "dqpclRxXyb: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 'R':
|
||||
if (rsa_alive() == 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
convert_to_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
convert_from_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
print_public = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dsa_mode = 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();
|
||||
}
|
||||
/* check if RSA support is needed and exists */
|
||||
if (dsa_mode == 0 && rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
if (print_fingerprint)
|
||||
do_fingerprint(pw);
|
||||
if (change_passphrase)
|
||||
do_change_passphrase(pw);
|
||||
if (change_comment)
|
||||
do_change_comment(pw);
|
||||
if (convert_to_ssh2)
|
||||
do_convert_to_ssh2(pw);
|
||||
if (convert_from_ssh2)
|
||||
do_convert_from_ssh2(pw);
|
||||
if (print_public)
|
||||
do_print_public(pw);
|
||||
|
||||
ssh_random_stir();
|
||||
|
||||
if (dsa_mode != 0) {
|
||||
if (!quiet)
|
||||
printf("Generating DSA parameter and key.\n");
|
||||
public = private = dsa_generate_key(bits);
|
||||
if (private == NULL) {
|
||||
fprintf(stderr, "dsa_generate_keys failed");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
/* Generate the rsa key pair. */
|
||||
public = key_new(KEY_RSA);
|
||||
private = key_new(KEY_RSA);
|
||||
rsa_generate_key(private->rsa, public->rsa, 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, _PATH_SSH_USER_DIR);
|
||||
if (strstr(identity_file, dotsshdir) != NULL &&
|
||||
stat(dotsshdir, &st) < 0) {
|
||||
if (mkdir(dotsshdir, 0700) < 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. */
|
||||
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, 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. */
|
||||
if (private != public) {
|
||||
key_free(private);
|
||||
}
|
||||
|
||||
ssh_random_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);
|
||||
}
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
fprintf(f, " %s\n", comment);
|
||||
fclose(f);
|
||||
|
||||
if (!quiet) {
|
||||
printf("Your public key has been saved in %s.\n",
|
||||
identity_file);
|
||||
printf("The key fingerprint is:\n");
|
||||
printf("%s %s\n", key_fingerprint(public), comment);
|
||||
}
|
||||
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
1185
crypto/dist/ssh/ssh.1
vendored
Normal file
1185
crypto/dist/ssh/ssh.1
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1029
crypto/dist/ssh/ssh.c
vendored
Normal file
1029
crypto/dist/ssh/ssh.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
33
crypto/dist/ssh/ssh.conf
vendored
Normal file
33
crypto/dist/ssh/ssh.conf
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# $NetBSD: ssh.conf,v 1.1.1.1 2000/09/28 22:10:34 thorpej Exp $
|
||||
#
|
||||
# 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 no
|
||||
# UseRsh no
|
||||
# BatchMode no
|
||||
# CheckHostIP yes
|
||||
# StrictHostKeyChecking no
|
||||
# IdentityFile ~/.ssh/identity
|
||||
# Port 22
|
||||
# Protocol 2,1
|
||||
# Cipher blowfish
|
||||
# EscapeChar ~
|
461
crypto/dist/ssh/ssh.h
vendored
Normal file
461
crypto/dist/ssh/ssh.h
vendored
Normal file
@ -0,0 +1,461 @@
|
||||
/* $NetBSD: ssh.h,v 1.1.1.1 2000/09/28 22:10:34 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Generic header file for ssh.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: ssh.h,v 1.51 2000/09/12 20:53:10 markus Exp */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
||||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* 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.
|
||||
*
|
||||
* Minor protocol version. Different version indicates minor incompatibility
|
||||
* that does not prevent interoperation.
|
||||
*/
|
||||
#define PROTOCOL_MAJOR_1 1
|
||||
#define PROTOCOL_MINOR_1 5
|
||||
|
||||
/* We support both SSH1 and SSH2 */
|
||||
#define PROTOCOL_MAJOR_2 2
|
||||
#define PROTOCOL_MINOR_2 0
|
||||
|
||||
/*
|
||||
* Name for the service. The port named by this service overrides the
|
||||
* default port if present.
|
||||
*/
|
||||
#define SSH_SERVICE_NAME "ssh"
|
||||
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* environment variable for overwriting the default ssh-askpass location
|
||||
*/
|
||||
#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) */
|
||||
|
||||
/*
|
||||
* The protocol defines this message as support for the
|
||||
* TIS authentication server. However, we currently use
|
||||
* it for s/key challenge/response.
|
||||
* XXX We should bring this up on secsh. --thorpej
|
||||
*/
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* */
|
||||
#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) */
|
||||
|
||||
/* Reserved for official extensions. */
|
||||
#define SSH_CMSG_RESERVED_START 45
|
||||
#define SSH_CMSG_RESERVED_END 63
|
||||
|
||||
#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(pid_t 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(pid_t 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, RSA* client_host_key);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
/*
|
||||
* Performs the RSA authentication challenge-response dialog with the client,
|
||||
* and returns true (non-zero) if the client gave the correct answer to our
|
||||
* challenge; returns zero if the client gives a wrong answer.
|
||||
*/
|
||||
int auth_rsa_challenge_dialog(RSA *pk);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
/*------------ 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_DEBUG1,
|
||||
SYSLOG_LEVEL_DEBUG2,
|
||||
SYSLOG_LEVEL_DEBUG3
|
||||
} LogLevel;
|
||||
|
||||
/* Initializes logging. */
|
||||
void log_init(const char *av0, LogLevel level, SyslogFacility facility,
|
||||
int on_stderr, int quiet_mode, int debug_mode);
|
||||
|
||||
/* 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(const char *name);
|
||||
LogLevel log_level_number(const char *name);
|
||||
|
||||
/* Output a message to syslog or stderr */
|
||||
void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/* same as fatal() but w/o logging */
|
||||
void fatal_cleanup(void);
|
||||
|
||||
/*
|
||||
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
|
||||
* before exiting. It is permissible to call fatal_remove_cleanup for the
|
||||
* function itself from the function.
|
||||
*/
|
||||
void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/* Removes a cleanup function to be called at fatal(). */
|
||||
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/* ---- misc */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* remove newline at end of string */
|
||||
char *chop(char *s);
|
||||
|
||||
/* return next token in configuration line */
|
||||
char *strdelim(char **s);
|
||||
|
||||
/* set filedescriptor to non-blocking */
|
||||
void set_nonblock(int fd);
|
||||
|
||||
/*
|
||||
* Performs the interactive session. This handles data transmission between
|
||||
* the client and the program. Note that the notion of stdin, stdout, and
|
||||
* stderr in this function is sort of reversed: this function writes to stdin
|
||||
* (of the child program), and reads from stdout and stderr (of the child
|
||||
* program).
|
||||
*/
|
||||
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
|
||||
void server_loop2(void);
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int have_pty, int escape_char, int id);
|
||||
|
||||
/* Linked list of custom environment strings (see auth-rsa.c). */
|
||||
struct envstring {
|
||||
struct envstring *next;
|
||||
char *s;
|
||||
};
|
||||
|
||||
/*
|
||||
* `Atomic' read and write operations, to ensure that all the
|
||||
* data makes it through a socket (handles signals, etc.).
|
||||
*/
|
||||
ssize_t atomic_read(int, void *, size_t);
|
||||
ssize_t atomic_write(int, const void *, size_t);
|
||||
|
||||
/*
|
||||
* Misc. random functions.
|
||||
*/
|
||||
void ssh_random_stir(void);
|
||||
|
||||
#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, size_t buflen);
|
||||
int radix_to_creds(const char *buf, CREDENTIALS * creds);
|
||||
#endif /* AFS */
|
||||
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef SKEY
|
||||
#include <skey.h>
|
||||
char *skey_fake_keyinfo(const 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 */
|
139
crypto/dist/ssh/ssh2.h
vendored
Normal file
139
crypto/dist/ssh/ssh2.h
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
/* $NetBSD: ssh2.h,v 1.1.1.1 2000/09/28 22:10:34 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* draft-ietf-secsh-architecture-05.txt
|
||||
*
|
||||
* Transport layer protocol:
|
||||
*
|
||||
* 1-19 Transport layer generic (e.g. disconnect, ignore, debug,
|
||||
* etc)
|
||||
* 20-29 Algorithm negotiation
|
||||
* 30-49 Key exchange method specific (numbers can be reused for
|
||||
* different authentication methods)
|
||||
*
|
||||
* User authentication protocol:
|
||||
*
|
||||
* 50-59 User authentication generic
|
||||
* 60-79 User authentication method specific (numbers can be reused
|
||||
* for different authentication methods)
|
||||
*
|
||||
* Connection protocol:
|
||||
*
|
||||
* 80-89 Connection protocol generic
|
||||
* 90-127 Channel related messages
|
||||
*
|
||||
* Reserved for client protocols:
|
||||
*
|
||||
* 128-191 Reserved
|
||||
*
|
||||
* Local extensions:
|
||||
*
|
||||
* 192-255 Local extensions
|
||||
*/
|
||||
|
||||
/* from OpenBSD: ssh2.h,v 1.4 2000/09/07 20:27:54 deraadt Exp */
|
||||
|
||||
/* transport layer: generic */
|
||||
|
||||
#define SSH2_MSG_DISCONNECT 1
|
||||
#define SSH2_MSG_IGNORE 2
|
||||
#define SSH2_MSG_UNIMPLEMENTED 3
|
||||
#define SSH2_MSG_DEBUG 4
|
||||
#define SSH2_MSG_SERVICE_REQUEST 5
|
||||
#define SSH2_MSG_SERVICE_ACCEPT 6
|
||||
|
||||
/* transport layer: alg negotiation */
|
||||
|
||||
#define SSH2_MSG_KEXINIT 20
|
||||
#define SSH2_MSG_NEWKEYS 21
|
||||
|
||||
/* transport layer: kex specific messages, can be reused */
|
||||
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
|
||||
/* user authentication: generic */
|
||||
|
||||
#define SSH2_MSG_USERAUTH_REQUEST 50
|
||||
#define SSH2_MSG_USERAUTH_FAILURE 51
|
||||
#define SSH2_MSG_USERAUTH_SUCCESS 52
|
||||
#define SSH2_MSG_USERAUTH_BANNER 53
|
||||
|
||||
/* user authentication: method specific, can be reused */
|
||||
|
||||
#define SSH2_MSG_USERAUTH_PK_OK 60
|
||||
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
|
||||
/* connection protocol: generic */
|
||||
|
||||
#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||
#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||
#define SSH2_MSG_REQUEST_FAILURE 82
|
||||
|
||||
/* channel related messages */
|
||||
|
||||
#define SSH2_MSG_CHANNEL_OPEN 90
|
||||
#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||
#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
|
||||
#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
|
||||
#define SSH2_MSG_CHANNEL_DATA 94
|
||||
#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
|
||||
#define SSH2_MSG_CHANNEL_EOF 96
|
||||
#define SSH2_MSG_CHANNEL_CLOSE 97
|
||||
#define SSH2_MSG_CHANNEL_REQUEST 98
|
||||
#define SSH2_MSG_CHANNEL_SUCCESS 99
|
||||
#define SSH2_MSG_CHANNEL_FAILURE 100
|
||||
|
||||
/* disconnect reason code */
|
||||
|
||||
#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
|
||||
#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
|
||||
#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
|
||||
#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
|
||||
#define SSH2_DISCONNECT_RESERVED 4
|
||||
#define SSH2_DISCONNECT_MAC_ERROR 5
|
||||
#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
|
||||
#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
|
||||
#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
|
||||
#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
|
||||
#define SSH2_DISCONNECT_CONNECTION_LOST 10
|
||||
#define SSH2_DISCONNECT_BY_APPLICATION 11
|
||||
#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12
|
||||
#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13
|
||||
#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
|
||||
#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15
|
||||
|
||||
/* misc */
|
||||
|
||||
#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH2_OPEN_CONNECT_FAILED 2
|
||||
#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
#define SSH2_OPEN_RESOURCE_SHORTAGE 4
|
||||
|
||||
#define SSH2_EXTENDED_DATA_STDERR 1
|
704
crypto/dist/ssh/sshconnect.c
vendored
Normal file
704
crypto/dist/ssh/sshconnect.c
vendored
Normal file
@ -0,0 +1,704 @@
|
||||
/* $NetBSD: sshconnect.c,v 1.1.1.1 2000/09/28 22:10:36 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Code to connect to a remote host, and to perform the client side of the
|
||||
* login (authentication) dialog.
|
||||
*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
/* from OpenBSD: sshconnect.c,v 1.79 2000/09/17 15:52:51 markus Exp */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: sshconnect.c,v 1.1.1.1 2000/09/28 22:10:36 thorpej Exp $");
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "uidswap.h"
|
||||
#include "compat.h"
|
||||
#include "readconf.h"
|
||||
#include "key.h"
|
||||
#include "sshconnect.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
char *client_version_string = NULL;
|
||||
char *server_version_string = NULL;
|
||||
|
||||
extern Options options;
|
||||
extern char *__progname;
|
||||
|
||||
/*
|
||||
* Connect to the given ssh server using a proxy command.
|
||||
*/
|
||||
static int
|
||||
ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
|
||||
const char *proxy_command)
|
||||
{
|
||||
Buffer command;
|
||||
const char *cp;
|
||||
char *command_string;
|
||||
int pin[2], pout[2];
|
||||
pid_t pid;
|
||||
char strport[NI_MAXSERV];
|
||||
|
||||
/* Convert the port number into a string. */
|
||||
snprintf(strport, sizeof strport, "%hu", port);
|
||||
|
||||
/* Build the final command string in the buffer by making the
|
||||
appropriate substitutions to the given proxy command. */
|
||||
buffer_init(&command);
|
||||
for (cp = proxy_command; *cp; cp++) {
|
||||
if (cp[0] == '%' && cp[1] == '%') {
|
||||
buffer_append(&command, "%", 1);
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
if (cp[0] == '%' && cp[1] == 'h') {
|
||||
buffer_append(&command, host, strlen(host));
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
if (cp[0] == '%' && cp[1] == 'p') {
|
||||
buffer_append(&command, strport, strlen(strport));
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
buffer_append(&command, cp, 1);
|
||||
}
|
||||
buffer_append(&command, "\0", 1);
|
||||
|
||||
/* Get the final command string. */
|
||||
command_string = buffer_ptr(&command);
|
||||
|
||||
/* Create pipes for communicating with the proxy. */
|
||||
if (pipe(pin) < 0 || pipe(pout) < 0)
|
||||
fatal("Could not create pipes to communicate with the proxy: %.100s",
|
||||
strerror(errno));
|
||||
|
||||
debug("Executing proxy command: %.500s", command_string);
|
||||
|
||||
/* Fork and execute the proxy command. */
|
||||
if ((pid = fork()) == 0) {
|
||||
char *argv[10];
|
||||
|
||||
/* Child. Permanently give up superuser privileges. */
|
||||
permanently_set_uid(original_real_uid);
|
||||
|
||||
/* Redirect stdin and stdout. */
|
||||
close(pin[1]);
|
||||
if (pin[0] != 0) {
|
||||
if (dup2(pin[0], 0) < 0)
|
||||
perror("dup2 stdin");
|
||||
close(pin[0]);
|
||||
}
|
||||
close(pout[0]);
|
||||
if (dup2(pout[1], 1) < 0)
|
||||
perror("dup2 stdout");
|
||||
/* Cannot be 1 because pin allocated two descriptors. */
|
||||
close(pout[1]);
|
||||
|
||||
/* Stderr is left as it is so that error messages get
|
||||
printed on the user's terminal. */
|
||||
argv[0] = _PATH_BSHELL;
|
||||
argv[1] = "-c";
|
||||
argv[2] = command_string;
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Execute the proxy command. Note that we gave up any
|
||||
extra privileges above. */
|
||||
execv(_PATH_BSHELL, argv);
|
||||
perror(_PATH_BSHELL);
|
||||
exit(1);
|
||||
}
|
||||
/* Parent. */
|
||||
if (pid < 0)
|
||||
fatal("fork failed: %.100s", strerror(errno));
|
||||
|
||||
/* Close child side of the descriptors. */
|
||||
close(pin[0]);
|
||||
close(pout[1]);
|
||||
|
||||
/* Free the command name. */
|
||||
buffer_free(&command);
|
||||
|
||||
/* Set the connection file descriptors. */
|
||||
packet_set_connection(pout[0], pin[1]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a (possibly privileged) socket for use as the ssh connection.
|
||||
*/
|
||||
static int
|
||||
ssh_create_socket(uid_t original_real_uid, int privileged, int family)
|
||||
{
|
||||
int sock;
|
||||
|
||||
/*
|
||||
* If we are running as root and want to connect to a privileged
|
||||
* port, bind our own socket to a privileged port.
|
||||
*/
|
||||
if (privileged) {
|
||||
int p = IPPORT_RESERVED - 1;
|
||||
sock = rresvport_af(&p, family);
|
||||
if (sock < 0)
|
||||
error("rresvport: af=%d %.100s", family, strerror(errno));
|
||||
else
|
||||
debug("Allocated local port %d.", p);
|
||||
} else {
|
||||
/*
|
||||
* Just create an ordinary socket on arbitrary port. We use
|
||||
* the user's uid to create the socket.
|
||||
*/
|
||||
temporarily_use_uid(original_real_uid);
|
||||
sock = socket(family, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
error("socket: %.100s", strerror(errno));
|
||||
restore_uid();
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a TCP/IP connection to the remote server on the given host.
|
||||
* The address of the remote host will be returned in hostaddr.
|
||||
* 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). If proxy_command is non-NULL, it specifies the command (with %h
|
||||
* and %p substituted for host and port, respectively) to use to contact
|
||||
* the daemon.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int sock = -1, attempt;
|
||||
struct servent *sp;
|
||||
struct addrinfo hints, *ai, *aitop;
|
||||
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
|
||||
int gaierr;
|
||||
struct linger linger;
|
||||
|
||||
debug("ssh_connect: getuid %u geteuid %u anon %d",
|
||||
(u_int) getuid(), (u_int) geteuid(), anonymous);
|
||||
|
||||
/* Get default port if port has not been set. */
|
||||
if (port == 0) {
|
||||
sp = getservbyname(SSH_SERVICE_NAME, "tcp");
|
||||
if (sp)
|
||||
port = ntohs(sp->s_port);
|
||||
else
|
||||
port = SSH_DEFAULT_PORT;
|
||||
}
|
||||
/* If a proxy command is given, connect using it. */
|
||||
if (proxy_command != NULL)
|
||||
return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
|
||||
|
||||
/* No proxy command. */
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = IPv4or6;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
snprintf(strport, sizeof strport, "%d", port);
|
||||
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
|
||||
fatal("%s: %.100s: %s", __progname, host,
|
||||
gai_strerror(gaierr));
|
||||
|
||||
/*
|
||||
* Try to connect several times. On some machines, the first time
|
||||
* will sometimes fail. In general socket code appears to behave
|
||||
* quite magically on many machines.
|
||||
*/
|
||||
for (attempt = 0; attempt < connection_attempts; attempt++) {
|
||||
if (attempt > 0)
|
||||
debug("Trying again...");
|
||||
|
||||
/* Loop through addresses for this host, and try each one in
|
||||
sequence until the connection succeeds. */
|
||||
for (ai = aitop; ai; ai = ai->ai_next) {
|
||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
||||
continue;
|
||||
if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
|
||||
ntop, sizeof(ntop), strport, sizeof(strport),
|
||||
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
|
||||
error("ssh_connect: getnameinfo failed");
|
||||
continue;
|
||||
}
|
||||
debug("Connecting to %.200s [%.100s] port %s.",
|
||||
host, ntop, strport);
|
||||
|
||||
/* Create a socket for connecting. */
|
||||
sock = ssh_create_socket(original_real_uid,
|
||||
!anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
|
||||
ai->ai_family);
|
||||
if (sock < 0)
|
||||
continue;
|
||||
|
||||
/* Connect to the host. We use the user's uid in the
|
||||
* hope that it will help with tcp_wrappers showing
|
||||
* the remote uid as root.
|
||||
*/
|
||||
temporarily_use_uid(original_real_uid);
|
||||
if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
|
||||
/* Successful connection. */
|
||||
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
|
||||
restore_uid();
|
||||
break;
|
||||
} else {
|
||||
debug("connect: %.100s", strerror(errno));
|
||||
restore_uid();
|
||||
/*
|
||||
* Close the failed socket; there appear to
|
||||
* be some problems when reusing a socket for
|
||||
* which connect() has already returned an
|
||||
* error.
|
||||
*/
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
if (ai)
|
||||
break; /* Successful connection. */
|
||||
|
||||
/* Sleep a moment before retrying. */
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
freeaddrinfo(aitop);
|
||||
|
||||
/* Return failure if we didn't get a successful connection. */
|
||||
if (attempt >= connection_attempts)
|
||||
return 0;
|
||||
|
||||
debug("Connection established.");
|
||||
|
||||
/*
|
||||
* Set socket options. We would like the socket to disappear as soon
|
||||
* as it has been closed for whatever reason.
|
||||
*/
|
||||
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
|
||||
|
||||
/* Set the connection. */
|
||||
packet_set_connection(sock, sock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits for the server identification string, and sends our own
|
||||
* identification string.
|
||||
*/
|
||||
static void
|
||||
ssh_exchange_identification(void)
|
||||
{
|
||||
char buf[256], remote_version[256]; /* must be same size! */
|
||||
int remote_major, remote_minor, i, mismatch;
|
||||
int connection_in = packet_get_connection_in();
|
||||
int connection_out = packet_get_connection_out();
|
||||
|
||||
/* Read other side\'s version identification. */
|
||||
for (;;) {
|
||||
for (i = 0; i < sizeof(buf) - 1; i++) {
|
||||
int len = atomic_read(connection_in, &buf[i], 1);
|
||||
if (len < 0)
|
||||
fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
|
||||
if (len != 1)
|
||||
fatal("ssh_exchange_identification: Connection closed by remote host");
|
||||
if (buf[i] == '\r') {
|
||||
buf[i] = '\n';
|
||||
buf[i + 1] = 0;
|
||||
continue; /**XXX wait for \n */
|
||||
}
|
||||
if (buf[i] == '\n') {
|
||||
buf[i + 1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
if (strncmp(buf, "SSH-", 4) == 0)
|
||||
break;
|
||||
debug("ssh_exchange_identification: %s", buf);
|
||||
}
|
||||
server_version_string = xstrdup(buf);
|
||||
|
||||
/*
|
||||
* Check that the versions match. In future this might accept
|
||||
* several versions and set appropriate flags to handle them.
|
||||
*/
|
||||
if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
|
||||
&remote_major, &remote_minor, remote_version) != 3)
|
||||
fatal("Bad remote protocol version identification: '%.100s'", buf);
|
||||
debug("Remote protocol version %d.%d, remote software version %.100s",
|
||||
remote_major, remote_minor, remote_version);
|
||||
|
||||
compat_datafellows(remote_version);
|
||||
mismatch = 0;
|
||||
|
||||
switch(remote_major) {
|
||||
case 1:
|
||||
if (remote_minor == 99 &&
|
||||
(options.protocol & SSH_PROTO_2) &&
|
||||
!(options.protocol & SSH_PROTO_1_PREFERRED)) {
|
||||
enable_compat20();
|
||||
break;
|
||||
}
|
||||
if (!(options.protocol & SSH_PROTO_1)) {
|
||||
mismatch = 1;
|
||||
break;
|
||||
}
|
||||
if (remote_minor < 3) {
|
||||
fatal("Remote machine has too old SSH software version.");
|
||||
} else if (remote_minor == 3) {
|
||||
/* We speak 1.3, too. */
|
||||
enable_compat13();
|
||||
if (options.forward_agent) {
|
||||
log("Agent forwarding disabled for protocol 1.3");
|
||||
options.forward_agent = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (options.protocol & SSH_PROTO_2) {
|
||||
enable_compat20();
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
mismatch = 1;
|
||||
break;
|
||||
}
|
||||
if (mismatch)
|
||||
fatal("Protocol major versions differ: %d vs. %d",
|
||||
(options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
|
||||
remote_major);
|
||||
if (compat20)
|
||||
packet_set_ssh2_format();
|
||||
/* Send our own protocol version identification. */
|
||||
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
|
||||
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
|
||||
compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1,
|
||||
SSH_VERSION);
|
||||
if (atomic_write(connection_out, buf, strlen(buf)) != strlen(buf))
|
||||
fatal("write: %.100s", strerror(errno));
|
||||
client_version_string = xstrdup(buf);
|
||||
chop(client_version_string);
|
||||
chop(server_version_string);
|
||||
debug("Local version string %.100s", client_version_string);
|
||||
}
|
||||
|
||||
static int
|
||||
read_yes_or_no(const char *prompt, int defval)
|
||||
{
|
||||
char buf[1024];
|
||||
FILE *f;
|
||||
int retval = -1;
|
||||
|
||||
if (isatty(0))
|
||||
f = stdin;
|
||||
else
|
||||
f = fopen(_PATH_TTY, "rw");
|
||||
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
while (1) {
|
||||
fprintf(stderr, "%s", prompt);
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
/* Print a newline (the prompt probably didn\'t have one). */
|
||||
fprintf(stderr, "\n");
|
||||
strlcpy(buf, "no", sizeof buf);
|
||||
}
|
||||
/* Remove newline from response. */
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
|
||||
if (buf[0] == 0)
|
||||
retval = defval;
|
||||
if (strcmp(buf, "yes") == 0)
|
||||
retval = 1;
|
||||
else if (strcmp(buf, "no") == 0)
|
||||
retval = 0;
|
||||
else
|
||||
fprintf(stderr, "Please type 'yes' or 'no'.\n");
|
||||
|
||||
if (retval != -1) {
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether the supplied host key is valid, return only if ok.
|
||||
*/
|
||||
|
||||
void
|
||||
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
const char *user_hostfile, const char *system_hostfile)
|
||||
{
|
||||
Key *file_key;
|
||||
char *type = key_type(host_key);
|
||||
char *ip = NULL;
|
||||
char hostline[1000], *hostp;
|
||||
HostStatus host_status;
|
||||
HostStatus ip_status;
|
||||
int local = 0, host_ip_differ = 0;
|
||||
char ntop[NI_MAXHOST];
|
||||
|
||||
/*
|
||||
* Force accepting of the host key for loopback/localhost. The
|
||||
* problem is that if the home directory is NFS-mounted to multiple
|
||||
* machines, localhost will refer to a different machine in each of
|
||||
* them, and the user will get bogus HOST_CHANGED warnings. This
|
||||
* essentially disables host authentication for localhost; however,
|
||||
* this is probably not a real problem.
|
||||
*/
|
||||
/** hostaddr == 0! */
|
||||
switch (hostaddr->sa_family) {
|
||||
case AF_INET:
|
||||
local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
|
||||
break;
|
||||
case AF_INET6:
|
||||
local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
|
||||
break;
|
||||
default:
|
||||
local = 0;
|
||||
break;
|
||||
}
|
||||
if (local) {
|
||||
debug("Forcing accepting of host key for loopback/localhost.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off check_host_ip for proxy connects, since
|
||||
* we don't have the remote ip-address
|
||||
*/
|
||||
if (options.proxy_command != NULL && options.check_host_ip)
|
||||
options.check_host_ip = 0;
|
||||
|
||||
if (options.check_host_ip) {
|
||||
if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop),
|
||||
NULL, 0, NI_NUMERICHOST) != 0)
|
||||
fatal("check_host_key: getnameinfo failed");
|
||||
ip = xstrdup(ntop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the host key from the known host file in here so that we can
|
||||
* compare it with the key for the IP address.
|
||||
*/
|
||||
file_key = key_new(host_key->type);
|
||||
|
||||
/*
|
||||
* Check if the host key is present in the user\'s list of known
|
||||
* hosts or in the systemwide list.
|
||||
*/
|
||||
host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
|
||||
if (host_status == HOST_NEW)
|
||||
host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
|
||||
/*
|
||||
* Also perform check for the ip address, skip the check if we are
|
||||
* localhost or the hostname was an ip address to begin with
|
||||
*/
|
||||
if (options.check_host_ip && !local && strcmp(host, ip)) {
|
||||
Key *ip_key = key_new(host_key->type);
|
||||
ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
|
||||
|
||||
if (ip_status == HOST_NEW)
|
||||
ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
|
||||
if (host_status == HOST_CHANGED &&
|
||||
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
|
||||
host_ip_differ = 1;
|
||||
|
||||
key_free(ip_key);
|
||||
} else
|
||||
ip_status = host_status;
|
||||
|
||||
key_free(file_key);
|
||||
|
||||
switch (host_status) {
|
||||
case HOST_OK:
|
||||
/* The host is known and the key matches. */
|
||||
debug("Host '%.200s' is known and matches the %s host key.",
|
||||
host, type);
|
||||
if (options.check_host_ip) {
|
||||
if (ip_status == HOST_NEW) {
|
||||
if (!add_host_to_hostfile(user_hostfile, ip, host_key))
|
||||
log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).",
|
||||
type, ip, user_hostfile);
|
||||
else
|
||||
log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.",
|
||||
type, ip);
|
||||
} else if (ip_status != HOST_OK)
|
||||
log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'",
|
||||
type, host, ip);
|
||||
}
|
||||
break;
|
||||
case HOST_NEW:
|
||||
/* The host is new. */
|
||||
if (options.strict_host_key_checking == 1) {
|
||||
/* User has requested strict host key checking. We will not add the host key
|
||||
automatically. The only alternative left is to abort. */
|
||||
fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host);
|
||||
} else if (options.strict_host_key_checking == 2) {
|
||||
/* The default */
|
||||
char prompt[1024];
|
||||
char *fp = key_fingerprint(host_key);
|
||||
snprintf(prompt, sizeof(prompt),
|
||||
"The authenticity of host '%.200s' can't be established.\n"
|
||||
"%s key fingerprint is %s.\n"
|
||||
"Are you sure you want to continue connecting (yes/no)? ",
|
||||
host, type, fp);
|
||||
if (!read_yes_or_no(prompt, -1))
|
||||
fatal("Aborted by user!\n");
|
||||
}
|
||||
if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) {
|
||||
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
|
||||
hostp = hostline;
|
||||
} else
|
||||
hostp = host;
|
||||
|
||||
/* If not in strict mode, add the key automatically to the local known_hosts file. */
|
||||
if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
|
||||
log("Failed to add the host to the list of known hosts (%.500s).",
|
||||
user_hostfile);
|
||||
else
|
||||
log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.",
|
||||
hostp, type);
|
||||
break;
|
||||
case HOST_CHANGED:
|
||||
if (options.check_host_ip && host_ip_differ) {
|
||||
char *msg;
|
||||
if (ip_status == HOST_NEW)
|
||||
msg = "is unknown";
|
||||
else if (ip_status == HOST_OK)
|
||||
msg = "is unchanged";
|
||||
else
|
||||
msg = "has a different value";
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("The %s host key for %s has changed,", type, host);
|
||||
error("and the key for the according IP address %s", ip);
|
||||
error("%s. This could either mean that", msg);
|
||||
error("DNS SPOOFING is happening or the IP address for the host");
|
||||
error("and its host key have changed at the same time");
|
||||
}
|
||||
/* The host key has changed. */
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
|
||||
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
|
||||
error("It is also possible that the %s host key has just been changed.", type);
|
||||
error("Please contact your system administrator.");
|
||||
error("Add correct host key in %.100s to get rid of this message.",
|
||||
user_hostfile);
|
||||
|
||||
/*
|
||||
* If strict host key checking is in use, the user will have
|
||||
* to edit the key manually and we can only abort.
|
||||
*/
|
||||
if (options.strict_host_key_checking)
|
||||
fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host);
|
||||
|
||||
/*
|
||||
* If strict host key checking has not been requested, allow
|
||||
* the connection but without password authentication or
|
||||
* agent forwarding.
|
||||
*/
|
||||
if (options.password_authentication) {
|
||||
error("Password authentication is disabled to avoid trojan horses.");
|
||||
options.password_authentication = 0;
|
||||
}
|
||||
if (options.forward_agent) {
|
||||
error("Agent forwarding is disabled to avoid trojan horses.");
|
||||
options.forward_agent = 0;
|
||||
}
|
||||
/*
|
||||
* XXX Should permit the user to change to use the new id.
|
||||
* This could be done by converting the host key to an
|
||||
* identifying sentence, tell that the host identifies itself
|
||||
* by that sentence, and ask the user if he/she whishes to
|
||||
* accept the authentication.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (options.check_host_ip)
|
||||
xfree(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 function does not require super-user privileges.
|
||||
*/
|
||||
void
|
||||
ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
|
||||
struct sockaddr *hostaddr, uid_t original_real_uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *host, *cp;
|
||||
char *server_user, *local_user;
|
||||
|
||||
/* Get local user name. Use it as server user if no user name was given. */
|
||||
pw = getpwuid(original_real_uid);
|
||||
if (!pw)
|
||||
fatal("User id %u not found from user database.", original_real_uid);
|
||||
local_user = xstrdup(pw->pw_name);
|
||||
server_user = options.user ? options.user : local_user;
|
||||
|
||||
/* Convert the user-supplied hostname into all lowercase. */
|
||||
host = xstrdup(orighost);
|
||||
for (cp = host; *cp; cp++)
|
||||
if (isupper(*cp))
|
||||
*cp = tolower(*cp);
|
||||
|
||||
/* Exchange protocol version identification strings with the server. */
|
||||
ssh_exchange_identification();
|
||||
|
||||
/* Put the connection into non-blocking mode. */
|
||||
packet_set_nonblocking();
|
||||
|
||||
/* key exchange */
|
||||
/* authenticate user */
|
||||
if (compat20) {
|
||||
ssh_kex2(host, hostaddr);
|
||||
ssh_userauth2(server_user, host);
|
||||
} else {
|
||||
ssh_kex(host, hostaddr);
|
||||
ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user