diff options
author | green <green@FreeBSD.org> | 2001-05-04 03:57:05 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2001-05-04 03:57:05 +0000 |
commit | 08fd06354d1aae8cd1350eb68d9f549e0c4d9037 (patch) | |
tree | 403a00e61ab75754c0654d4f7a0fac3c23f032dd /crypto | |
parent | 5b85c0e3b3967dddea695e33712ddecb60cd454a (diff) | |
parent | 8acd87ac472a182ef2d717212f2c0faba81143a5 (diff) | |
download | FreeBSD-src-08fd06354d1aae8cd1350eb68d9f549e0c4d9037.zip FreeBSD-src-08fd06354d1aae8cd1350eb68d9f549e0c4d9037.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r76259,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'crypto')
118 files changed, 10190 insertions, 2874 deletions
diff --git a/crypto/openssh/LICENCE b/crypto/openssh/LICENCE index 7c2346a..f60f502 100644 --- a/crypto/openssh/LICENCE +++ b/crypto/openssh/LICENCE @@ -1,7 +1,7 @@ -This file is part of the ssh software. +This file is part of the OpenSSH software. -The licences which components of this software falls under are as -follows. First, we will summarize and say that that all components +The licences which components of this software fall under are as +follows. First, we will summarize and say that all components are under a BSD licence, or a licence more free than that. OpenSSH contains no GPL code. @@ -29,7 +29,7 @@ OpenSSH contains no GPL code. have been removed from OpenSSH, ie. - RSA is no longer included, found in the OpenSSL library - - IDEA is no longer included, it's use is depricated + - IDEA is no longer included, its use is deprecated - DES is now external, in the OpenSSL library - GMP is no longer used, and instead we call BN code from OpenSSL - Zlib is now external, in a library diff --git a/crypto/openssh/Makefile b/crypto/openssh/Makefile index 299d349..eea6f14 100644 --- a/crypto/openssh/Makefile +++ b/crypto/openssh/Makefile @@ -1,8 +1,9 @@ -# $OpenBSD: Makefile,v 1.6 2000/08/31 21:52:23 markus Exp $ +# $OpenBSD: Makefile,v 1.8 2001/02/04 11:11:53 djm Exp $ .include <bsd.own.mk> -SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server +SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server \ + ssh-keyscan sftp distribution: install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \ diff --git a/crypto/openssh/Makefile.inc b/crypto/openssh/Makefile.inc index 85e1454..89fdf43 100644 --- a/crypto/openssh/Makefile.inc +++ b/crypto/openssh/Makefile.inc @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $ + CFLAGS+= -I${.CURDIR}/.. CFLAGS+= -Wall diff --git a/crypto/openssh/README b/crypto/openssh/README index 70dd612..4e75d624 100644 --- a/crypto/openssh/README +++ b/crypto/openssh/README @@ -1,567 +1,25 @@ - -[ Please note that this file has not been updated for OpenSSH and - covers the ssh-1.2.12 release from Dec 1995 only. ] - -Ssh (Secure Shell) is a program to log into another computer over a -network, to execute commands in a remote machine, and to move files -from one machine to another. It provides strong authentication and -secure communications over insecure channels. It is intended as a -replacement for rlogin, rsh, rcp, and rdist. - -See the file INSTALL for installation instructions. See COPYING for -license terms and other legal issues. See RFC for a description of -the protocol. There is a WWW page for ssh; see http://www.cs.hut.fi/ssh. - -This file has been updated to match ssh-1.2.12. - - -FEATURES - - o Strong authentication. Closes several security holes (e.g., IP, - routing, and DNS spoofing). New authentication methods: .rhosts - together with RSA based host authentication, and pure RSA - authentication. - - o Improved privacy. All communications are automatically and - transparently encrypted. RSA is used for key exchange, and a - conventional cipher (normally IDEA, DES, or triple-DES) for - encrypting the session. Encryption is started before - authentication, and no passwords or other information is - transmitted in the clear. Encryption is also used to protect - against spoofed packets. - - o Secure X11 sessions. The program automatically sets DISPLAY on - the server machine, and forwards any X11 connections over the - secure channel. Fake Xauthority information is automatically - generated and forwarded to the remote machine; the local client - automatically examines incoming X11 connections and replaces the - fake authorization data with the real data (never telling the - remote machine the real information). - - o Arbitrary TCP/IP ports can be redirected through the encrypted channel - in both directions (e.g., for e-cash transactions). - - o No retraining needed for normal users; everything happens - automatically, and old .rhosts files will work with strong - authentication if administration installs host key files. - - o Never trusts the network. Minimal trust on the remote side of - the connection. Minimal trust on domain name servers. Pure RSA - authentication never trusts anything but the private key. - - o Client RSA-authenticates the server machine in the beginning of - every connection to prevent trojan horses (by routing or DNS - spoofing) and man-in-the-middle attacks, and the server - RSA-authenticates the client machine before accepting .rhosts or - /etc/hosts.equiv authentication (to prevent DNS, routing, or - IP-spoofing). - - o Host authentication key distribution can be centrally by the - administration, automatically when the first connection is made - to a machine (the key obtained on the first connection will be - recorded and used for authentication in the future), or manually - by each user for his/her own use. The central and per-user host - key repositories are both used and complement each other. Host - keys can be generated centrally or automatically when the software - is installed. Host authentication keys are typically 1024 bits. - - o Any user can create any number of user authentication RSA keys for - his/her own use. Each user has a file which lists the RSA public - keys for which proof of possession of the corresponding private - key is accepted as authentication. User authentication keys are - typically 1024 bits. - - o The server program has its own server RSA key which is - automatically regenerated every hour. This key is never saved in - any file. Exchanged session keys are encrypted using both the - server key and the server host key. The purpose of the separate - server key is to make it impossible to decipher a captured session by - breaking into the server machine at a later time; one hour from - the connection even the server machine cannot decipher the session - key. The key regeneration interval is configurable. The server - key is normally 768 bits. - - o An authentication agent, running in the user's laptop or local - workstation, can be used to hold the user's RSA authentication - keys. Ssh automatically forwards the connection to the - authentication agent over any connections, and there is no need to - store the RSA authentication keys on any machine in the network - (except the user's own local machine). The authentication - protocols never reveal the keys; they can only be used to verify - that the user's agent has a certain key. Eventually the agent - could rely on a smart card to perform all authentication - computations. - - o The software can be installed and used (with restricted - functionality) even without root privileges. - - o The client is customizable in system-wide and per-user - configuration files. Most aspects of the client's operation can - be configured. Different options can be specified on a per-host basis. - - o Automatically executes conventional rsh (after displaying a - warning) if the server machine is not running sshd. - - o Optional compression of all data with gzip (including forwarded X11 - and TCP/IP port data), which may result in significant speedups on - slow connections. - - o Complete replacement for rlogin, rsh, and rcp. - - -WHY TO USE SECURE SHELL - -Currently, almost all communications in computer networks are done -without encryption. As a consequence, anyone who has access to any -machine connected to the network can listen in on any communication. -This is being done by hackers, curious administrators, employers, -criminals, industrial spies, and governments. Some networks leak off -enough electromagnetic radiation that data may be captured even from a -distance. - -When you log in, your password goes in the network in plain -text. Thus, any listener can then use your account to do any evil he -likes. Many incidents have been encountered worldwide where crackers -have started programs on workstations without the owners knowledge -just to listen to the network and collect passwords. Programs for -doing this are available on the Internet, or can be built by a -competent programmer in a few hours. - -Any information that you type or is printed on your screen can be -monitored, recorded, and analyzed. For example, an intruder who has -penetrated a host connected to a major network can start a program -that listens to all data flowing in the network, and whenever it -encounters a 16-digit string, it checks if it is a valid credit card -number (using the check digit), and saves the number plus any -surrounding text (to catch expiration date and holder) in a file. -When the intruder has collected a few thousand credit card numbers, he -makes smallish mail-order purchases from a few thousand stores around -the world, and disappears when the goods arrive but before anyone -suspects anything. - -Businesses have trade secrets, patent applications in preparation, -pricing information, subcontractor information, client data, personnel -data, financial information, etc. Currently, anyone with access to -the network (any machine on the network) can listen to anything that -goes in the network, without any regard to normal access restrictions. - -Many companies are not aware that information can so easily be -recovered from the network. They trust that their data is safe -since nobody is supposed to know that there is sensitive information -in the network, or because so much other data is transferred in the -network. This is not a safe policy. - -Individual persons also have confidential information, such as -diaries, love letters, health care documents, information about their -personal interests and habits, professional data, job applications, -tax reports, political documents, unpublished manuscripts, etc. - -One should also be aware that economical intelligence and industrial -espionage has recently become a major priority of the intelligence -agencies of major governments. President Clinton recently assigned -economical espionage as the primary task of the CIA, and the French -have repeatedly been publicly boasting about their achievements on -this field. - - -There is also another frightening aspect about the poor security of -communications. Computer storage and analysis capability has -increased so much that it is feasible for governments, major -companies, and criminal organizations to automatically analyze, -identify, classify, and file information about millions of people over -the years. Because most of the work can be automated, the cost of -collecting this information is getting very low. - -Government agencies may be able to monitor major communication -systems, telephones, fax, computer networks, etc., and passively -collect huge amounts of information about all people with any -significant position in the society. Most of this information is not -sensitive, and many people would say there is no harm in someone -getting that information. However, the information starts to get -sensitive when someone has enough of it. You may not mind someone -knowing what you bought from the shop one random day, but you might -not like someone knowing every small thing you have bought in the last -ten years. - -If the government some day starts to move into a more totalitarian -direction (one should remember that Nazi Germany was created by -democratic elections), there is considerable danger of an ultimate -totalitarian state. With enough information (the automatically -collected records of an individual can be manually analyzed when the -person becomes interesting), one can form a very detailed picture of -the individual's interests, opinions, beliefs, habits, friends, -lovers, weaknesses, etc. This information can be used to 1) locate -any persons who might oppose the new system 2) use deception to -disturb any organizations which might rise against the government 3) -eliminate difficult individuals without anyone understanding what -happened. Additionally, if the government can monitor communications -too effectively, it becomes too easy to locate and eliminate any -persons distributing information contrary to the official truth. - -Fighting crime and terrorism are often used as grounds for domestic -surveillance and restricting encryption. These are good goals, but -there is considerable danger that the surveillance data starts to get -used for questionable purposes. I find that it is better to tolerate -a small amount of crime in the society than to let the society become -fully controlled. I am in favor of a fairly strong state, but the -state must never get so strong that people become unable to spread -contra-offical information and unable to overturn the government if it -is bad. The danger is that when you notice that the government is -too powerful, it is too late. Also, the real power may not be where -the official government is. - -For these reasons (privacy, protecting trade secrets, and making it -more difficult to create a totalitarian state), I think that strong -cryptography should be integrated to the tools we use every day. -Using it causes no harm (except for those who wish to monitor -everything), but not using it can cause huge problems. If the society -changes in undesirable ways, then it will be to late to start -encrypting. - -Encryption has had a "military" or "classified" flavor to it. There -are no longer any grounds for this. The military can and will use its -own encryption; that is no excuse to prevent the civilians from -protecting their privacy and secrets. Information on strong -encryption is available in every major bookstore, scientific library, -and patent office around the world, and strong encryption software is -available in every country on the Internet. - -Some people would like to make it illegal to use encryption, or to -force people to use encryption that governments can break. This -approach offers no protection if the government turns bad. Also, the -"bad guys" will be using true strong encryption anyway. Good -encryption techniques are too widely known to make them disappear. -Thus, any "key escrow encryption" or other restrictions will only help -monitor ordinary people and petty criminals. It does not help against -powerful criminals, terrorists, or espionage, because they will know -how to use strong encryption anyway. (One source for internationally -available encryption software is http://www.cs.hut.fi/crypto.) - - -OVERVIEW OF SECURE SHELL - -The software consists of a number of programs. - - sshd Server program run on the server machine. This - listens for connections from client machines, and - whenever it receives a connection, it performs - authentication and starts serving the client. - - ssh This is the client program used to log into another - machine or to execute commands on the other machine. - "slogin" is another name for this program. - - scp Securely copies files from one machine to another. - - ssh-keygen Used to create RSA keys (host keys and user - authentication keys). - - ssh-agent Authentication agent. This can be used to hold RSA - keys for authentication. - - ssh-add Used to register new keys with the agent. - - make-ssh-known-hosts - Used to create the /etc/ssh_known_hosts file. - - -Ssh is the program users normally use. It is started as - - ssh host - -or - - ssh host command - -The first form opens a new shell on the remote machine (after -authentication). The latter form executes the command on the remote -machine. - -When started, the ssh connects sshd on the server machine, verifies -that the server machine really is the machine it wanted to connect, -exchanges encryption keys (in a manner which prevents an outside -listener from getting the keys), performs authentication using .rhosts -and /etc/hosts.equiv, RSA authentication, or conventional password -based authentication. The server then (normally) allocates a -pseudo-terminal and starts an interactive shell or user program. - -The TERM environment variable (describing the type of the user's -terminal) is passed from the client side to the remote side. Also, -terminal modes will be copied from the client side to the remote side -to preserve user preferences (e.g., the erase character). - -If the DISPLAY variable is set on the client side, the server will -create a dummy X server and set DISPLAY accordingly. Any connections -to the dummy X server will be forwarded through the secure channel, -and will be made to the real X server from the client side. An -arbitrary number of X programs can be started during the session, and -starting them does not require anything special from the user. (Note -that the user must not manually set DISPLAY, because then it would -connect directly to the real display instead of going through the -encrypted channel). This behavior can be disabled in the -configuration file or by giving the -x option to the client. - -Arbitrary IP ports can be forwarded over the secure channel. The -program then creates a port on one side, and whenever a connection is -opened to this port, it will be passed over the secure channel, and a -connection will be made from the other side to a specified host:port -pair. Arbitrary IP forwarding must always be explicitly requested, -and cannot be used to forward privileged ports (unless the user is -root). It is possible to specify automatic forwards in a per-user -configuration file, for example to make electronic cash systems work -securely. - -If there is an authentication agent on the client side, connection to -it will be automatically forwarded to the server side. - -For more infomation, see the manual pages ssh(1), sshd(8), scp(1), -ssh-keygen(1), ssh-agent(1), ssh-add(1), and make-ssh-known-hosts(1) -included in this distribution. - - -X11 CONNECTION FORWARDING - -X11 forwarding serves two purposes: it is a convenience to the user -because there is no need to set the DISPLAY variable, and it provides -encrypted X11 connections. I cannot think of any other easy way to -make X11 connections encrypted; modifying the X server, clients or -libraries would require special work for each machine, vendor and -application. Widely used IP-level encryption does not seem likely for -several years. Thus what we have left is faking an X server on the -same machine where the clients are run, and forwarding the connections -to a real X server over the secure channel. - -X11 forwarding works as follows. The client extracts Xauthority -information for the server. It then creates random authorization -data, and sends the random data to the server. The server allocates -an X11 display number, and stores the (fake) Xauthority data for this -display. Whenever an X11 connection is opened, the server forwards -the connection over the secure channel to the client, and the client -parses the first packet of the X11 protocol, substitutes real -authentication data for the fake data (if the fake data matched), and -forwards the connection to the real X server. - -If the display does not have Xauthority data, the server will create a -unix domain socket in /tmp/.X11-unix, and use the unix domain socket -as the display. No authentication information is forwarded in this -case. X11 connections are again forwarded over the secure channel. -To the X server the connections appear to come from the client -machine, and the server must have connections allowed from the local -machine. Using authentication data is always recommended because not -using it makes the display insecure. If XDM is used, it automatically -generates the authentication data. - -One should be careful not to use "xin" or "xstart" or other similar -scripts that explicitly set DISPLAY to start X sessions in a remote -machine, because the connection will then not go over the secure -channel. The recommended way to start a shell in a remote machine is - - xterm -e ssh host & - -and the recommended way to execute an X11 application in a remote -machine is - - ssh -n host emacs & - -If you need to type a password/passphrase for the remote machine, - - ssh -f host emacs - -may be useful. - - - -RSA AUTHENTICATION - -RSA authentication is based on public key cryptograpy. The idea is -that there are two encryption keys, one for encryption and another for -decryption. It is not possible (on human timescale) to derive the -decryption key from the encryption key. The encryption key is called -the public key, because it can be given to anyone and it is not -secret. The decryption key, on the other hand, is secret, and is -called the private key. - -RSA authentication is based on the impossibility of deriving the -private key from the public key. The public key is stored on the -server machine in the user's $HOME/.ssh/authorized_keys file. The -private key is only kept on the user's local machine, laptop, or other -secure storage. Then the user tries to log in, the client tells the -server the public key that the user wishes to use for authentication. -The server then checks if this public key is admissible. If so, it -generates a 256 bit random number, encrypts it with the public key, -and sends the value to the client. The client then decrypts the -number with its private key, computes a 128 bit MD5 checksum from the -resulting data, and sends the checksum back to the server. (Only a -checksum is sent to prevent chosen-plaintext attacks against RSA.) -The server checks computes a checksum from the correct data, -and compares the checksums. Authentication is accepted if the -checksums match. (Theoretically this indicates that the client -only probably knows the correct key, but for all practical purposes -there is no doubt.) - -The RSA private key can be protected with a passphrase. The -passphrase can be any string; it is hashed with MD5 to produce an -encryption key for IDEA, which is used to encrypt the private part of -the key file. With passphrase, authorization requires access to the key -file and the passphrase. Without passphrase, authorization only -depends on possession of the key file. - -RSA authentication is the most secure form of authentication supported -by this software. It does not rely on the network, routers, domain -name servers, or the client machine. The only thing that matters is -access to the private key. - -All this, of course, depends on the security of the RSA algorithm -itself. RSA has been widely known since about 1978, and no effective -methods for breaking it are known if it is used properly. Care has -been taken to avoid the well-known pitfalls. Breaking RSA is widely -believed to be equivalent to factoring, which is a very hard -mathematical problem that has received considerable public research. -So far, no effective methods are known for numbers bigger than about -512 bits. However, as computer speeds and factoring methods are -increasing, 512 bits can no longer be considered secure. The -factoring work is exponential, and 768 or 1024 bits are widely -considered to be secure in the near future. - - -RHOSTS AUTHENTICATION - -Conventional .rhosts and hosts.equiv based authentication mechanisms -are fundamentally insecure due to IP, DNS (domain name server) and -routing spoofing attacks. Additionally this authentication method -relies on the integrity of the client machine. These weaknesses is -tolerable, and been known and exploited for a long time. - -Ssh provides an improved version of these types of authentication, -because they are very convenient for the user (and allow easy -transition from rsh and rlogin). It permits these types of -authentication, but additionally requires that the client host be -authenticated using RSA. - -The server has a list of host keys stored in /etc/ssh_known_host, and -additionally each user has host keys in $HOME/.ssh/known_hosts. Ssh -uses the name servers to obtain the canonical name of the client host, -looks for its public key in its known host files, and requires the -client to prove that it knows the private host key. This prevents IP -and routing spoofing attacks (as long as the client machine private -host key has not been compromized), but is still vulnerable to DNS -attacks (to a limited extent), and relies on the integrity of the -client machine as to who is requesting to log in. This prevents -outsiders from attacking, but does not protect against very powerful -attackers. If maximal security is desired, only RSA authentication -should be used. - -It is possible to enable conventional .rhosts and /etc/hosts.equiv -authentication (without host authentication) at compile time by giving -the option --with-rhosts to configure. However, this is not -recommended, and is not done by default. - -These weaknesses are present in rsh and rlogin. No improvement in -security will be obtained unless rlogin and rsh are completely -disabled (commented out in /etc/inetd.conf). This is highly -recommended. - - -WEAKEST LINKS IN SECURITY - -One should understand that while this software may provide -cryptographically secure communications, it may be easy to -monitor the communications at their endpoints. - -Basically, anyone with root access on the local machine on which you -are running the software may be able to do anything. Anyone with root -access on the server machine may be able to monitor your -communications, and a very talented root user might even be able to -send his/her own requests to your authentication agent. - -One should also be aware that computers send out electromagnetic -radition that can sometimes be picked up hundreds of meters away. -Your keyboard is particularly easy to listen to. The image on your -monitor might also be seen on another monitor in a van parked behind -your house. - -Beware that unwanted visitors might come to your home or office and -use your machine while you are away. They might also make -modifications or install bugs in your hardware or software. - -Beware that the most effective way for someone to decrypt your data -may be with a rubber hose. - - -LEGAL ISSUES - -As far as I am concerned, anyone is permitted to use this software -freely. However, see the file COPYING for detailed copying, -licensing, and distribution information. - -In some countries, particularly France, Russia, Iraq, and Pakistan, -it may be illegal to use any encryption at all without a special -permit, and the rumor has it that you cannot get a permit for any -strong encryption. - -This software may be freely imported into the United States; however, -the United States Government may consider re-exporting it a criminal -offence. - -Note that any information and cryptographic algorithms used in this -software are publicly available on the Internet and at any major -bookstore, scientific library, or patent office worldwide. - -THERE IS NO WARRANTY FOR THIS PROGRAM. Please consult the file -COPYING for more information. - - -MAILING LISTS AND OTHER INFORMATION - -There is a mailing list for ossh. It is ossh@sics.se. If you would -like to join, send a message to majordomo@sics.se with "subscribe -ssh" in body. - -The WWW home page for ssh is http://www.cs.hut.fi/ssh. It contains an -archive of the mailing list, and detailed information about new -releases, mailing lists, and other relevant issues. - -Bug reports should be sent to ossh-bugs@sics.se. - - -ABOUT THE AUTHOR - -This software was written by Tatu Ylonen <ylo@cs.hut.fi>. I work as a -researcher at Helsinki University of Technology, Finland. For more -information, see http://www.cs.hut.fi/~ylo/. My PGP public key is -available via finger from ylo@cs.hut.fi and from the key servers. I -prefer PGP encrypted mail. - -The author can be contacted via ordinary mail at - Tatu Ylonen - Helsinki University of Technology - Otakaari 1 - FIN-02150 ESPOO - Finland - - Fax. +358-0-4513293 - - -ACKNOWLEDGEMENTS - -I thank Tero Kivinen, Timo Rinne, Janne Snabb, and Heikki Suonsivu for -their help and comments in the design, implementation and porting of -this software. I also thank numerous contributors, including but not -limited to Walker Aumann, Jurgen Botz, Hans-Werner Braun, Stephane -Bortzmeyer, Adrian Colley, Michael Cooper, David Dombek, Jerome -Etienne, Bill Fithen, Mark Fullmer, Bert Gijsbers, Andreas Gustafsson, -Michael Henits, Steve Johnson, Thomas Koenig, Felix Leitner, Gunnar -Lindberg, Andrew Macpherson, Marc Martinec, Paul Mauvais, Donald -McKillican, Leon Mlakar, Robert Muchsel, Mark Treacy, Bryan -O'Sullivan, Mikael Suokas, Ollivier Robert, Jakob Schlyter, Tomasz -Surmacz, Alvar Vinacua, Petri Virkkula, Michael Warfield, and -Cristophe Wolfhugel. - -Thanks also go to Philip Zimmermann, whose PGP software and the -associated legal battle provided inspiration, motivation, and many -useful techniques, and to Bruce Schneier whose book Applied -Cryptography has done a great service in widely distributing knowledge -about cryptographic methods. - - -Copyright (c) 1995 Tatu Ylonen, Espoo, Finland. +This release of OpenSSH is for OpenBSD systems only. + +Please read + http://www.openssh.com/portable.html +if you want to install OpenSSH on other operating systems. + +To extract and install this release on your OpenBSD system use: + + # cd /usr/src/usr.bin + # tar xvfz .../openssh-x.y.tgz + # cd ssh + # make obj + # make cleandir + # make depend + # make + # make install + # cp ssh_config sshd_config /etc + +OpenSSH is a derivative of the original and free ssh 1.2.12 release +by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels +Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer +features and created OpenSSH. Markus Friedl contributed the support +for SSH protocol versions 1.5 and 2.0. + +See http://www.openssh.com/ for more information. diff --git a/crypto/openssh/atomicio.c b/crypto/openssh/atomicio.c index 744ccc7..8e17b58 100644 --- a/crypto/openssh/atomicio.c +++ b/crypto/openssh/atomicio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995,1999 Theo de Raadt + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,10 +24,10 @@ */ #include "includes.h" -RCSID("$OpenBSD: atomicio.c,v 1.7 2000/10/18 18:04:02 markus Exp $"); +RCSID("$OpenBSD: atomicio.c,v 1.9 2001/03/02 18:54:30 deraadt Exp $"); #include "xmalloc.h" -#include "ssh.h" +#include "atomicio.h" /* * ensure all of data on socket comes through. f==read || f==write diff --git a/crypto/openssh/atomicio.h b/crypto/openssh/atomicio.h new file mode 100644 index 0000000..d878687 --- /dev/null +++ b/crypto/openssh/atomicio.h @@ -0,0 +1,31 @@ +/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */ + +/* + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Ensure all of data on socket comes through. f==read || f==write + */ +ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n); diff --git a/crypto/openssh/auth-chall.c b/crypto/openssh/auth-chall.c new file mode 100644 index 0000000..f3502f4 --- /dev/null +++ b/crypto/openssh/auth-chall.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $"); + +#include "auth.h" +#include "log.h" + +#ifdef BSD_AUTH +char * +get_challenge(Authctxt *authctxt, char *devs) +{ + char *challenge; + + if (authctxt->as != NULL) { + debug2("try reuse session"); + challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE); + if (challenge != NULL) { + debug2("reuse bsd auth session"); + return challenge; + } + auth_close(authctxt->as); + authctxt->as = NULL; + } + debug2("new bsd auth session"); + if (devs == NULL || strlen(devs) == 0) + devs = authctxt->style; + debug3("bsd auth: devs %s", devs ? devs : "<default>"); + authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh", + &challenge); + if (authctxt->as == NULL) + return NULL; + debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY"); + return challenge; +} +int +verify_response(Authctxt *authctxt, char *response) +{ + int authok; + + if (authctxt->as == 0) + error("verify_response: no bsd auth session"); + authok = auth_userresponse(authctxt->as, response, 0); + authctxt->as = NULL; + debug("verify_response: <%s> = <%d>", response, authok); + return authok != 0; +} +#else +#ifdef SKEY +#include <skey.h> + +char * +get_challenge(Authctxt *authctxt, char *devs) +{ + static char challenge[1024]; + struct skey skey; + if (skeychallenge(&skey, authctxt->user, challenge) == -1) + return NULL; + strlcat(challenge, "\nS/Key Password: ", sizeof challenge); + return challenge; +} +int +verify_response(Authctxt *authctxt, char *response) +{ + return (authctxt->valid && + skey_haskey(authctxt->pw->pw_name) == 0 && + skey_passcheck(authctxt->pw->pw_name, response) != -1); +} +#else +/* not available */ +char * +get_challenge(Authctxt *authctxt, char *devs) +{ + return NULL; +} +int +verify_response(Authctxt *authctxt, char *response) +{ + return 0; +} +#endif +#endif diff --git a/crypto/openssh/auth-options.c b/crypto/openssh/auth-options.c index c9c149d..443f541 100644 --- a/crypto/openssh/auth-options.c +++ b/crypto/openssh/auth-options.c @@ -2,10 +2,6 @@ * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved - * RSA-based authentication. This code determines whether to admit a login - * based on RSA authentication. This file also contains functions to check - * validity of the host key. - * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is @@ -14,12 +10,16 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-options.c,v 1.5 2000/10/09 21:32:34 markus Exp $"); +RCSID("$OpenBSD: auth-options.c,v 1.16 2001/03/18 12:07:52 markus Exp $"); -#include "ssh.h" #include "packet.h" #include "xmalloc.h" #include "match.h" +#include "log.h" +#include "canohost.h" +#include "channels.h" +#include "auth-options.h" +#include "servconf.h" /* Flags set authorized_keys flags */ int no_port_forwarding_flag = 0; @@ -33,6 +33,8 @@ char *forced_command = NULL; /* "environment=" options. */ struct envstring *custom_environment = NULL; +extern ServerOptions options; + void auth_clear_options(void) { @@ -50,105 +52,113 @@ auth_clear_options(void) xfree(forced_command); forced_command = NULL; } + channel_clear_permitted_opens(); } -/* return 1 if access is granted, 0 if not. side effect: sets key option flags */ +/* + * return 1 if access is granted, 0 if not. + * side effect: sets key option flags + */ int -auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) +auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { const char *cp; - if (!options) - return 1; + int i; /* reset options */ auth_clear_options(); - while (*options && *options != ' ' && *options != '\t') { + if (!opts) + return 1; + + while (*opts && *opts != ' ' && *opts != '\t') { cp = "no-port-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { packet_send_debug("Port forwarding disabled."); no_port_forwarding_flag = 1; - options += strlen(cp); + opts += strlen(cp); goto next_option; } cp = "no-agent-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { packet_send_debug("Agent forwarding disabled."); no_agent_forwarding_flag = 1; - options += strlen(cp); + opts += strlen(cp); goto next_option; } cp = "no-X11-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { packet_send_debug("X11 forwarding disabled."); no_x11_forwarding_flag = 1; - options += strlen(cp); + opts += strlen(cp); goto next_option; } cp = "no-pty"; - if (strncmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { packet_send_debug("Pty allocation disabled."); no_pty_flag = 1; - options += strlen(cp); + opts += strlen(cp); goto next_option; } cp = "command=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { - int i; - options += strlen(cp); - forced_command = xmalloc(strlen(options) + 1); + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + opts += strlen(cp); + forced_command = xmalloc(strlen(opts) + 1); i = 0; - while (*options) { - if (*options == '"') + while (*opts) { + if (*opts == '"') break; - if (*options == '\\' && options[1] == '"') { - options += 2; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; forced_command[i++] = '"'; continue; } - forced_command[i++] = *options++; + forced_command[i++] = *opts++; } - if (!*options) { + if (!*opts) { debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; + file, linenum); + xfree(forced_command); + forced_command = NULL; + goto bad_option; } forced_command[i] = 0; packet_send_debug("Forced command: %.900s", forced_command); - options++; + opts++; goto next_option; } cp = "environment=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { - int i; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *s; struct envstring *new_envstring; - options += strlen(cp); - s = xmalloc(strlen(options) + 1); + + opts += strlen(cp); + s = xmalloc(strlen(opts) + 1); i = 0; - while (*options) { - if (*options == '"') + while (*opts) { + if (*opts == '"') break; - if (*options == '\\' && options[1] == '"') { - options += 2; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; s[i++] = '"'; continue; } - s[i++] = *options++; + s[i++] = *opts++; } - if (!*options) { + if (!*opts) { debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; + file, linenum); + xfree(s); + goto bad_option; } s[i] = 0; packet_send_debug("Adding to environment: %.900s", s); debug("Adding to environment: %.900s", s); - options++; + opts++; new_envstring = xmalloc(sizeof(struct envstring)); new_envstring->s = s; new_envstring->next = custom_environment; @@ -156,66 +166,125 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) goto next_option; } cp = "from=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { int mname, mip; - char *patterns = xmalloc(strlen(options) + 1); - int i; - options += strlen(cp); + const char *remote_ip = get_remote_ipaddr(); + const char *remote_host = get_canonical_hostname( + options.reverse_mapping_check); + char *patterns = xmalloc(strlen(opts) + 1); + + opts += strlen(cp); i = 0; - while (*options) { - if (*options == '"') + while (*opts) { + if (*opts == '"') break; - if (*options == '\\' && options[1] == '"') { - options += 2; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; patterns[i++] = '"'; continue; } - patterns[i++] = *options++; + patterns[i++] = *opts++; } - if (!*options) { + if (!*opts) { debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); + file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; + file, linenum); + xfree(patterns); + goto bad_option; } patterns[i] = 0; - options++; + opts++; /* * Deny access if we get a negative * match for the hostname or the ip * or if we get not match at all */ - mname = match_hostname(get_canonical_hostname(), - patterns, strlen(patterns)); - mip = match_hostname(get_remote_ipaddr(), - patterns, strlen(patterns)); + mname = match_hostname(remote_host, patterns, + strlen(patterns)); + mip = match_hostname(remote_ip, patterns, + strlen(patterns)); xfree(patterns); if (mname == -1 || mip == -1 || (mname != 1 && mip != 1)) { - log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", - pw->pw_name, get_canonical_hostname(), - get_remote_ipaddr()); - packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", - get_canonical_hostname()); + log("Authentication tried for %.100s with " + "correct key but not from a permitted " + "host (host=%.200s, ip=%.200s).", + pw->pw_name, remote_host, remote_ip); + packet_send_debug("Your host '%.200s' is not " + "permitted to use this key for login.", + remote_host); /* deny access */ return 0; } /* Host name matches. */ goto next_option; } + cp = "permitopen=\""; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + u_short port; + char *c, *ep; + char *patterns = xmalloc(strlen(opts) + 1); + + opts += strlen(cp); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + file, linenum); + xfree(patterns); + goto bad_option; + } + patterns[i] = 0; + opts++; + c = strchr(patterns, ':'); + if (c == NULL) { + debug("%.100s, line %lu: permitopen: missing colon <%.100s>", + file, linenum, patterns); + packet_send_debug("%.100s, line %lu: missing colon", + file, linenum); + xfree(patterns); + goto bad_option; + } + *c = 0; + c++; + port = strtol(c, &ep, 0); + if (c == ep) { + debug("%.100s, line %lu: permitopen: missing port <%.100s>", + file, linenum, patterns); + packet_send_debug("%.100s, line %lu: missing port", + file, linenum); + xfree(patterns); + goto bad_option; + } + if (options.allow_tcp_forwarding) + channel_add_permitted_opens(patterns, port); + xfree(patterns); + goto next_option; + } next_option: /* * Skip the comma, and move to the next option * (or break out if there are no more). */ - if (!*options) + if (!*opts) fatal("Bugs in auth-options.c option processing."); - if (*options == ' ' || *options == '\t') + if (*opts == ' ' || *opts == '\t') break; /* End of options. */ - if (*options != ',') + if (*opts != ',') goto bad_option; - options++; + opts++; /* Process the next option. */ } /* grant access */ @@ -223,9 +292,9 @@ next_option: bad_option: log("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); + file, linenum, opts); packet_send_debug("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); + file, linenum, opts); /* deny access */ return 0; } diff --git a/crypto/openssh/auth-options.h b/crypto/openssh/auth-options.h index 00fae22..8ee2694 100644 --- a/crypto/openssh/auth-options.h +++ b/crypto/openssh/auth-options.h @@ -11,10 +11,17 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* $OpenBSD: auth-options.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */ +/* $OpenBSD: auth-options.h,v 1.8 2001/01/21 19:05:42 markus Exp $ */ #ifndef AUTH_OPTIONS_H #define AUTH_OPTIONS_H + +/* Linked list of custom environment strings */ +struct envstring { + struct envstring *next; + char *s; +}; + /* Flags that may be set in authorized_keys options. */ extern int no_port_forwarding_flag; extern int no_agent_forwarding_flag; @@ -23,8 +30,14 @@ extern int no_pty_flag; extern char *forced_command; extern struct envstring *custom_environment; -/* return 1 if access is granted, 0 if not. side effect: sets key option flags */ -int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum); +/* + * return 1 if access is granted, 0 if not. + * side effect: sets key option flags + */ +int +auth_parse_options(struct passwd *pw, char *options, char *file, + u_long linenum); + /* reset options flags */ void auth_clear_options(void); diff --git a/crypto/openssh/auth-rhosts.c b/crypto/openssh/auth-rhosts.c index 8314e23..324a0f9 100644 --- a/crypto/openssh/auth-rhosts.c +++ b/crypto/openssh/auth-rhosts.c @@ -14,13 +14,19 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rhosts.c,v 1.16 2000/10/03 18:03:03 markus Exp $"); +RCSID("$OpenBSD: auth-rhosts.c,v 1.23 2001/04/12 19:15:24 markus Exp $"); #include "packet.h" -#include "ssh.h" #include "xmalloc.h" #include "uidswap.h" +#include "pathnames.h" +#include "log.h" #include "servconf.h" +#include "canohost.h" +#include "auth.h" + +/* import */ +extern ServerOptions options; /* * This function processes an rhosts-style file (.rhosts, .shosts, or @@ -147,18 +153,33 @@ check_rhosts_file(const char *filename, const char *hostname, int auth_rhosts(struct passwd *pw, const char *client_user) { - extern ServerOptions options; - char buf[1024]; const char *hostname, *ipaddr; + int ret; + + hostname = get_canonical_hostname(options.reverse_mapping_check); + ipaddr = get_remote_ipaddr(); + ret = auth_rhosts2(pw, client_user, hostname, ipaddr); + return ret; +} + +int +auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr) +{ + char buf[1024]; struct stat st; static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; - unsigned int rhosts_file_index; + u_int rhosts_file_index; + + debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s", + client_user, hostname, ipaddr); /* no user given */ if (pw == NULL) return 0; + /* Switch to the user's uid. */ - temporarily_use_uid(pw->pw_uid); + temporarily_use_uid(pw); /* * Quick check: if the user has no .shosts or .rhosts files, return * failure immediately without doing costly lookups from name @@ -177,25 +198,22 @@ auth_rhosts(struct passwd *pw, const char *client_user) /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */ if (!rhosts_files[rhosts_file_index] && - stat("/etc/hosts.equiv", &st) < 0 && - stat(SSH_HOSTS_EQUIV, &st) < 0) + stat(_PATH_RHOSTS_EQUIV, &st) < 0 && + stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) return 0; - hostname = get_canonical_hostname(); - ipaddr = get_remote_ipaddr(); - /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ if (pw->pw_uid != 0) { - if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user, + if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user, pw->pw_name)) { packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.", hostname, ipaddr); return 1; } - if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, + if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, pw->pw_name)) { packet_send_debug("Accepted for %.100s [%.100s] by %.100s.", - hostname, ipaddr, SSH_HOSTS_EQUIV); + hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV); return 1; } } @@ -220,7 +238,7 @@ auth_rhosts(struct passwd *pw, const char *client_user) return 0; } /* Temporarily use the user's uid. */ - temporarily_use_uid(pw->pw_uid); + temporarily_use_uid(pw); /* Check all .rhosts files (currently .shosts and .rhosts). */ for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index 721d763..500b73a 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -21,30 +21,118 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $OpenBSD: auth.h,v 1.7 2000/10/16 09:38:44 djm Exp $ + * $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $ */ #ifndef AUTH_H #define AUTH_H +#include <openssl/rsa.h> + +#ifdef HAVE_LOGIN_CAP +#include <login_cap.h> +#endif +#ifdef BSD_AUTH +#include <bsd_auth.h> +#endif + typedef struct Authctxt Authctxt; struct Authctxt { int success; + int postponed; int valid; int attempt; + int failures; char *user; char *service; struct passwd *pw; + char *style; +#ifdef BSD_AUTH + auth_session_t *as; +#endif }; +/* + * Tries to authenticate the user using the .rhosts file. Returns true if + * authentication succeeds. If ignore_rhosts is non-zero, this will not + * consider .rhosts and .shosts (/etc/hosts.equiv will still be used). + */ +int auth_rhosts(struct passwd * pw, const char *client_user); + +/* extended interface similar to auth_rhosts() */ +int +auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr); + +/* + * Tries to authenticate the user using the .rhosts file and the host using + * its host key. Returns true if authentication succeeds. + */ +int +auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key); + +/* + * Tries to authenticate the user using password. Returns true if + * authentication succeeds. + */ +int auth_password(Authctxt *authctxt, const char *password); + +/* + * Performs the RSA authentication dialog with the client. This returns 0 if + * the client could not be authenticated, and 1 if authentication was + * successful. This may exit if there is a serious protocol violation. + */ +int auth_rsa(struct passwd * pw, BIGNUM * client_n); + +/* + * Parses an RSA key (number of bits, e, n) from a string. Moves the pointer + * over the key. Skips any whitespace at the beginning and at end. + */ +int auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n); + +/* + * Performs the RSA authentication challenge-response dialog with the client, + * and returns true (non-zero) if the client gave the correct answer to our + * challenge; returns zero if the client gives a wrong answer. + */ +int auth_rsa_challenge_dialog(RSA *pk); + +#ifdef KRB4 +#include <krb.h> +/* + * Performs Kerberos v4 mutual authentication with the client. This returns 0 + * if the client could not be authenticated, and 1 if authentication was + * successful. This may exit if there is a serious protocol violation. + */ +int auth_krb4(const char *server_user, KTEXT auth, char **client); +int krb4_init(uid_t uid); +void krb4_cleanup_proc(void *ignore); +int auth_krb4_password(struct passwd * pw, const char *password); + +#ifdef AFS +#include <kafs.h> + +/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */ +int auth_kerberos_tgt(struct passwd * pw, const char *string); +int auth_afs_token(struct passwd * pw, const char *token_string); +#endif /* AFS */ + +#endif /* KRB4 */ + void do_authentication(void); void do_authentication2(void); -void userauth_log(Authctxt *authctxt, int authenticated, char *method); -void userauth_reply(Authctxt *authctxt, int authenticated); +Authctxt *authctxt_new(void); +void auth_log(Authctxt *authctxt, int authenticated, char *method, char *info); +void userauth_finish(Authctxt *authctxt, int authenticated, char *method); +int auth_root_allowed(char *method); -int auth2_skey(Authctxt *authctxt); +int auth2_challenge(Authctxt *authctxt, char *devs); int allowed_user(struct passwd * pw); + +char *get_challenge(Authctxt *authctxt, char *devs); +int verify_response(Authctxt *authctxt, char *response); + struct passwd * auth_get_user(void); #define AUTH_FAIL_MAX 6 diff --git a/crypto/openssh/auth2-chall.c b/crypto/openssh/auth2-chall.c new file mode 100644 index 0000000..5af60e4 --- /dev/null +++ b/crypto/openssh/auth2-chall.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $"); + +#include "ssh2.h" +#include "auth.h" +#include "packet.h" +#include "xmalloc.h" +#include "dispatch.h" +#include "log.h" + +void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo); +void input_userauth_info_response(int type, int plen, void *ctxt); + +/* + * try challenge-reponse, return -1 (= postponed) if we have to + * wait for the response. + */ +int +auth2_challenge(Authctxt *authctxt, char *devs) +{ + char *challenge; + + if (!authctxt->valid || authctxt->user == NULL) + return 0; + if ((challenge = get_challenge(authctxt, devs)) == NULL) + return 0; + send_userauth_into_request(authctxt, challenge, 0); + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, + &input_userauth_info_response); + authctxt->postponed = 1; + return 0; +} + +void +send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo) +{ + int nprompts = 1; + + packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); + /* name, instruction and language are unused */ + packet_put_cstring(""); + packet_put_cstring(""); + packet_put_cstring(""); + packet_put_int(nprompts); + packet_put_cstring(challenge); + packet_put_char(echo); + packet_send(); + packet_write_wait(); +} + +void +input_userauth_info_response(int type, int plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + int authenticated = 0; + u_int nresp, rlen; + char *response, *method = "challenge-reponse"; + + if (authctxt == NULL) + fatal("input_userauth_info_response: no authctxt"); + + authctxt->postponed = 0; /* reset */ + nresp = packet_get_int(); + if (nresp == 1) { + response = packet_get_string(&rlen); + packet_done(); + if (strlen(response) == 0) { + /* + * if we received an empty response, resend challenge + * with echo enabled + */ + char *challenge = get_challenge(authctxt, NULL); + if (challenge != NULL) { + send_userauth_into_request(authctxt, + challenge, 1); + authctxt->postponed = 1; + } + } else if (authctxt->valid) { + authenticated = verify_response(authctxt, response); + memset(response, 'r', rlen); + } + xfree(response); + } + /* unregister callback */ + if (!authctxt->postponed) + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); + + userauth_finish(authctxt, authenticated, method); +} diff --git a/crypto/openssh/authfd.h b/crypto/openssh/authfd.h index 2d24652..29d1847 100644 --- a/crypto/openssh/authfd.h +++ b/crypto/openssh/authfd.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */ +/* RCSID("$OpenBSD: authfd.h,v 1.16 2000/12/20 19:37:21 markus Exp $"); */ #ifndef AUTHFD_H #define AUTHFD_H @@ -51,7 +51,7 @@ typedef struct { } AuthenticationConnection; /* Returns the number of the authentication fd, or -1 if there is none. */ -int ssh_get_authentication_socket(); +int ssh_get_authentication_socket(void); /* * This should be called for any descriptor returned by @@ -66,7 +66,7 @@ void ssh_close_authentication_socket(int authfd); * connection could not be opened. The connection should be closed by the * caller by calling ssh_close_authentication_connection(). */ -AuthenticationConnection *ssh_get_authentication_connection(); +AuthenticationConnection *ssh_get_authentication_connection(void); /* * Closes the connection to the authentication agent and frees any associated @@ -75,6 +75,11 @@ AuthenticationConnection *ssh_get_authentication_connection(); void ssh_close_authentication_connection(AuthenticationConnection *auth); /* + * Returns the number authentication identity held by the agent. + */ +int ssh_get_num_identities(AuthenticationConnection *auth, int version); + +/* * Returns the first authentication identity held by the agent or NULL if * no identies are available. Caller must free comment and key. * Note that you cannot mix calls with different versions. @@ -96,16 +101,16 @@ Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int v int ssh_decrypt_challenge(AuthenticationConnection *auth, Key *key, BIGNUM * challenge, - unsigned char session_id[16], - unsigned int response_type, - unsigned char response[16]); + u_char session_id[16], + u_int response_type, + u_char response[16]); /* Requests the agent to sign data using key */ int ssh_agent_sign(AuthenticationConnection *auth, Key *key, - unsigned char **sigp, int *lenp, - unsigned char *data, int datalen); + u_char **sigp, int *lenp, + u_char *data, int datalen); /* * Adds an identity to the authentication server. This call is not meant to diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h index 525b4aa..da90cd9 100644 --- a/crypto/openssh/authfile.h +++ b/crypto/openssh/authfile.h @@ -2,7 +2,6 @@ * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved - * Functions to interface with the SSH_AUTHENTICATION_FD socket. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this @@ -11,41 +10,27 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* $OpenBSD: authfile.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */ +/* $OpenBSD: authfile.h,v 1.6 2001/03/26 08:07:08 markus Exp $ */ #ifndef AUTHFILE_H #define AUTHFILE_H - -/* - * Saves the authentication (private) key in a file, encrypting it with - * passphrase. - * For RSA keys: The identification of the file (lowest 64 bits of n) - * will precede the key to provide identification of the key without - * needing a passphrase. - */ int -save_private_key(const char *filename, const char *passphrase, - Key * private_key, const char *comment); +key_save_private(Key *key, const char *filename, const char *passphrase, + const char *comment); -/* - * Loads the public part of the key file (public key and comment). Returns 0 - * if an error occurred; zero if the public key was successfully read. The - * comment of the key is returned in comment_return if it is non-NULL; the - * caller must free the value with xfree. - */ -int load_public_key(const char *filename, Key * pub, char **comment_return); -int try_load_public_key(const char *filename, Key * pub, char **comment_return); +Key * +key_load_public(const char *filename, char **commentp); -/* - * Loads the private key from the file. Returns 0 if an error is encountered - * (file does not exist or is not readable, or passphrase is bad). This - * initializes the private key. The comment of the key is returned in - * comment_return if it is non-NULL; the caller must free the value with - * xfree. - */ -int -load_private_key(const char *filename, const char *passphrase, - Key * private_key, char **comment_return); +Key * +key_load_public_type(int type, const char *filename, char **commentp); + +Key * +key_load_private(const char *filename, const char *passphrase, + char **commentp); + +Key * +key_load_private_type(int type, const char *filename, const char *passphrase, + char **commentp); #endif diff --git a/crypto/openssh/bufaux.h b/crypto/openssh/bufaux.h index 4f53858..8902ec2 100644 --- a/crypto/openssh/bufaux.h +++ b/crypto/openssh/bufaux.h @@ -10,12 +10,13 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: bufaux.h,v 1.8 2000/09/07 20:27:50 deraadt Exp $"); */ +/* RCSID("$OpenBSD: bufaux.h,v 1.11 2001/01/21 19:05:45 markus Exp $"); */ #ifndef BUFAUX_H #define BUFAUX_H #include "buffer.h" +#include <openssl/bn.h> /* * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed @@ -29,10 +30,12 @@ int buffer_get_bignum(Buffer * buffer, BIGNUM * value); int buffer_get_bignum2(Buffer *buffer, BIGNUM * value); /* Returns an integer from the buffer (4 bytes, msb first). */ -unsigned int buffer_get_int(Buffer * buffer); +u_int buffer_get_int(Buffer * buffer); +u_int64_t buffer_get_int64(Buffer *buffer); /* Stores an integer in the buffer in 4 bytes, msb first. */ -void buffer_put_int(Buffer * buffer, unsigned int value); +void buffer_put_int(Buffer * buffer, u_int value); +void buffer_put_int64(Buffer *buffer, u_int64_t value); /* Returns a character from the buffer (0 - 255). */ int buffer_get_char(Buffer * buffer); @@ -48,10 +51,10 @@ void buffer_put_char(Buffer * buffer, int value); * stored there. A null character will be automatically appended to the * returned string, and is not counted in length. */ -char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr); +char *buffer_get_string(Buffer * buffer, u_int *length_ptr); /* Stores and arbitrary binary string in the buffer. */ -void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len); +void buffer_put_string(Buffer * buffer, const void *buf, u_int len); void buffer_put_cstring(Buffer *buffer, const char *s); #endif /* BUFAUX_H */ diff --git a/crypto/openssh/buffer.c b/crypto/openssh/buffer.c index d993c8b..044caaf 100644 --- a/crypto/openssh/buffer.c +++ b/crypto/openssh/buffer.c @@ -12,11 +12,11 @@ */ #include "includes.h" -RCSID("$OpenBSD: buffer.c,v 1.8 2000/09/07 20:27:50 deraadt Exp $"); +RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $"); #include "xmalloc.h" #include "buffer.h" -#include "ssh.h" +#include "log.h" /* Initializes the buffer structure. */ @@ -53,7 +53,7 @@ buffer_clear(Buffer *buffer) /* Appends data to the buffer, expanding it if necessary. */ void -buffer_append(Buffer *buffer, const char *data, unsigned int len) +buffer_append(Buffer *buffer, const char *data, u_int len) { char *cp; buffer_append_space(buffer, &cp, len); @@ -67,7 +67,7 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len) */ void -buffer_append_space(Buffer *buffer, char **datap, unsigned int len) +buffer_append_space(Buffer *buffer, char **datap, u_int len) { /* If the buffer is empty, start using it from the beginning. */ if (buffer->offset == buffer->end) { @@ -100,7 +100,7 @@ restart: /* Returns the number of bytes of data in the buffer. */ -unsigned int +u_int buffer_len(Buffer *buffer) { return buffer->end - buffer->offset; @@ -109,10 +109,11 @@ buffer_len(Buffer *buffer) /* Gets data from the beginning of the buffer. */ void -buffer_get(Buffer *buffer, char *buf, unsigned int len) +buffer_get(Buffer *buffer, char *buf, u_int len) { if (len > buffer->end - buffer->offset) - fatal("buffer_get: trying to get more bytes than in buffer"); + fatal("buffer_get: trying to get more bytes %d than in buffer %d", + len, buffer->end - buffer->offset); memcpy(buf, buffer->buf + buffer->offset, len); buffer->offset += len; } @@ -120,7 +121,7 @@ buffer_get(Buffer *buffer, char *buf, unsigned int len) /* Consumes the given number of bytes from the beginning of the buffer. */ void -buffer_consume(Buffer *buffer, unsigned int bytes) +buffer_consume(Buffer *buffer, u_int bytes) { if (bytes > buffer->end - buffer->offset) fatal("buffer_consume: trying to get more bytes than in buffer"); @@ -130,7 +131,7 @@ buffer_consume(Buffer *buffer, unsigned int bytes) /* Consumes the given number of bytes from the end of the buffer. */ void -buffer_consume_end(Buffer *buffer, unsigned int bytes) +buffer_consume_end(Buffer *buffer, u_int bytes) { if (bytes > buffer->end - buffer->offset) fatal("buffer_consume_end: trying to get more bytes than in buffer"); @@ -151,9 +152,14 @@ void buffer_dump(Buffer *buffer) { int i; - unsigned char *ucp = (unsigned char *) buffer->buf; - - for (i = buffer->offset; i < buffer->end; i++) - fprintf(stderr, " %02x", ucp[i]); - fprintf(stderr, "\n"); + u_char *ucp = (u_char *) buffer->buf; + + for (i = buffer->offset; i < buffer->end; i++) { + fprintf(stderr, "%02x", ucp[i]); + if ((i-buffer->offset)%16==15) + fprintf(stderr, "\r\n"); + else if ((i-buffer->offset)%2==1) + fprintf(stderr, " "); + } + fprintf(stderr, "\r\n"); } diff --git a/crypto/openssh/buffer.h b/crypto/openssh/buffer.h index 522036a..f3c509d 100644 --- a/crypto/openssh/buffer.h +++ b/crypto/openssh/buffer.h @@ -11,16 +11,16 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: buffer.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */ +/* RCSID("$OpenBSD: buffer.h,v 1.7 2000/12/19 23:17:55 markus Exp $"); */ #ifndef BUFFER_H #define BUFFER_H typedef struct { char *buf; /* Buffer for data. */ - unsigned int alloc; /* Number of bytes allocated for data. */ - unsigned int offset; /* Offset of first byte containing data. */ - unsigned int end; /* Offset of last byte containing data. */ + u_int alloc; /* Number of bytes allocated for data. */ + u_int offset; /* Offset of first byte containing data. */ + u_int end; /* Offset of last byte containing data. */ } Buffer; /* Initializes the buffer structure. */ void buffer_init(Buffer * buffer); @@ -33,26 +33,26 @@ void buffer_free(Buffer * buffer); void buffer_clear(Buffer * buffer); /* Appends data to the buffer, expanding it if necessary. */ -void buffer_append(Buffer * buffer, const char *data, unsigned int len); +void buffer_append(Buffer * buffer, const char *data, u_int len); /* * Appends space to the buffer, expanding the buffer if necessary. This does * not actually copy the data into the buffer, but instead returns a pointer * to the allocated region. */ -void buffer_append_space(Buffer * buffer, char **datap, unsigned int len); +void buffer_append_space(Buffer * buffer, char **datap, u_int len); /* Returns the number of bytes of data in the buffer. */ -unsigned int buffer_len(Buffer * buffer); +u_int buffer_len(Buffer * buffer); /* Gets data from the beginning of the buffer. */ -void buffer_get(Buffer * buffer, char *buf, unsigned int len); +void buffer_get(Buffer * buffer, char *buf, u_int len); /* Consumes the given number of bytes from the beginning of the buffer. */ -void buffer_consume(Buffer * buffer, unsigned int bytes); +void buffer_consume(Buffer * buffer, u_int bytes); /* Consumes the given number of bytes from the end of the buffer. */ -void buffer_consume_end(Buffer * buffer, unsigned int bytes); +void buffer_consume_end(Buffer * buffer, u_int bytes); /* Returns a pointer to the first used byte in the buffer. */ char *buffer_ptr(Buffer * buffer); diff --git a/crypto/openssh/canohost.h b/crypto/openssh/canohost.h new file mode 100644 index 0000000..36fb345 --- /dev/null +++ b/crypto/openssh/canohost.h @@ -0,0 +1,38 @@ +/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +/* + * Return the canonical name of the host in the other side of the current + * connection (as returned by packet_get_connection). The host name is + * cached, so it is efficient to call this several times. + */ +const char *get_canonical_hostname(int reverse_mapping_check); + +/* + * Returns the IP-address of the remote host as a string. The returned + * string is cached and must not be freed. + */ +const char *get_remote_ipaddr(void); + +const char *get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check); + +/* Returns the ipaddr/port number of the peer of the socket. */ +char * get_peer_ipaddr(int socket); +int get_peer_port(int sock); +char * get_local_ipaddr(int socket); +char * get_local_name(int socket); + +/* Returns the port number of the remote/local host. */ +int get_remote_port(void); +int get_local_port(void); diff --git a/crypto/openssh/cli.c b/crypto/openssh/cli.c index ab9a7dc..8f0b2b8 100644 --- a/crypto/openssh/cli.c +++ b/crypto/openssh/cli.c @@ -1,8 +1,36 @@ +/* $OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "includes.h" -RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $"); +RCSID("$OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt Exp $"); #include "xmalloc.h" -#include "ssh.h" +#include "log.h" +#include "cli.h" + #include <vis.h> static int cli_input = -1; @@ -32,7 +60,7 @@ cli_open(int from_stdin) cli_input = STDIN_FILENO; cli_output = STDERR_FILENO; } else { - cli_input = cli_output = open("/dev/tty", O_RDWR); + cli_input = cli_output = open(_PATH_TTY, O_RDWR); if (cli_input < 0) fatal("You have no controlling tty. Cannot read passphrase."); } @@ -43,7 +71,7 @@ cli_open(int from_stdin) } static void -cli_close() +cli_close(void) { if (!cli_from_stdin && cli_input >= 0) close(cli_input); @@ -54,13 +82,13 @@ cli_close() } void -intrcatch() +intrcatch(int sig) { intr = 1; } static void -cli_echo_disable() +cli_echo_disable(void) { sigemptyset(&nset); sigaddset(&nset, SIGTSTP); @@ -83,7 +111,7 @@ cli_echo_disable() } static void -cli_echo_restore() +cli_echo_restore(void) { if (echo_modified != 0) { tcsetattr(cli_input, TCSANOW, &otio); @@ -108,12 +136,16 @@ cli_read(char* buf, int size, int echo) { char ch = 0; int i = 0; + int n; if (!echo) cli_echo_disable(); while (ch != '\n') { - if (read(cli_input, &ch, 1) != 1) + n = read(cli_input, &ch, 1); + if (n == -1 && (errno == EAGAIN || errno == EINTR)) + continue; + if (n != 1) break; if (ch == '\n' || intr != 0) break; @@ -137,18 +169,21 @@ cli_write(char* buf, int size) output = xmalloc(4*size); for (p = output, i = 0; i < size; i++) { - if (buf[i] == '\n') - *p++ = buf[i]; - else - p = vis(p, buf[i], 0, 0); - } + if (buf[i] == '\n' || buf[i] == '\r') + *p++ = buf[i]; + else + p = vis(p, buf[i], 0, 0); + } len = p - output; for (pos = 0; pos < len; pos += ret) { ret = write(cli_output, output + pos, len - pos); - if (ret == -1) + if (ret == -1) { + xfree(output); return -1; + } } + xfree(output); return 0; } diff --git a/crypto/openssh/cli.h b/crypto/openssh/cli.h index c419404..6f57c9b 100644 --- a/crypto/openssh/cli.h +++ b/crypto/openssh/cli.h @@ -1,4 +1,30 @@ -/* $OpenBSD: cli.h,v 1.2 2000/10/16 09:38:44 djm Exp $ */ +/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt Exp $ */ #ifndef CLI_H #define CLI_H @@ -9,8 +35,8 @@ * of response depending on arg. Tries to ensure that no other userland * buffer is storing the response. */ -char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable); -char* cli_prompt(char* prompt, int echo_enable); -void cli_mesg(char* mesg); +char * cli_read_passphrase(char * prompt, int from_stdin, int echo_enable); +char * cli_prompt(char * prompt, int echo_enable); +void cli_mesg(char * mesg); #endif /* CLI_H */ diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index bccb9be..369ffe4 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -59,22 +59,28 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.65 2001/04/20 07:17:51 djm Exp $"); -#include "xmalloc.h" #include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" #include "packet.h" #include "buffer.h" -#include "readconf.h" - -#include "ssh2.h" #include "compat.h" #include "channels.h" #include "dispatch.h" - #include "buffer.h" #include "bufaux.h" - +#include "key.h" +#include "kex.h" +#include "log.h" +#include "readconf.h" +#include "clientloop.h" +#include "authfd.h" +#include "atomicio.h" +#include "sshtty.h" +#include "misc.h" /* import options */ extern Options options; @@ -97,15 +103,6 @@ extern char *host; */ static volatile int received_window_change_signal = 0; -/* Terminal modes, as saved by enter_raw_mode. */ -static struct termios saved_tio; - -/* - * Flag indicating whether we are in raw mode. This is used by - * enter_raw_mode and leave_raw_mode. - */ -static int in_raw_mode = 0; - /* Flag indicating whether the user\'s terminal is in non-blocking mode. */ static int in_non_blocking_mode = 0; @@ -119,60 +116,23 @@ static int stdin_eof; /* EOF has been encountered on standard error. */ static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ static Buffer stderr_buffer; /* Buffer for stderr data. */ -static unsigned long stdin_bytes, stdout_bytes, stderr_bytes; -static unsigned int buffer_high;/* Soft max buffer size. */ -static int max_fd; /* Maximum file descriptor number in select(). */ +static u_long stdin_bytes, stdout_bytes, stderr_bytes; +static u_int buffer_high;/* Soft max buffer size. */ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ - +static int need_rekeying; /* Set to non-zero if rekeying is requested. */ +static int session_closed = 0; /* In SSH2: login session closed. */ void client_init_dispatch(void); int session_ident = -1; -/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */ - -void -leave_raw_mode() -{ - if (!in_raw_mode) - return; - in_raw_mode = 0; - if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0) - perror("tcsetattr"); - - fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL); -} - -/* Puts the user\'s terminal in raw mode. */ - -void -enter_raw_mode() -{ - struct termios tio; - - if (tcgetattr(fileno(stdin), &tio) < 0) - perror("tcgetattr"); - saved_tio = tio; - tio.c_iflag |= IGNPAR; - tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); - tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); -#ifdef IEXTEN - tio.c_lflag &= ~IEXTEN; -#endif /* IEXTEN */ - tio.c_oflag &= ~OPOST; - tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; - if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) - perror("tcsetattr"); - in_raw_mode = 1; - - fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL); -} +/*XXX*/ +extern Kex *xxx_kex; /* Restores stdin to blocking mode. */ void -leave_non_blocking() +leave_non_blocking(void) { if (in_non_blocking_mode) { (void) fcntl(fileno(stdin), F_SETFL, 0); @@ -184,7 +144,7 @@ leave_non_blocking() /* Puts stdin terminal in non-blocking mode. */ void -enter_non_blocking() +enter_non_blocking(void) { in_non_blocking_mode = 1; (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); @@ -211,7 +171,7 @@ window_change_handler(int sig) void signal_handler(int sig) { - if (in_raw_mode) + if (in_raw_mode()) leave_raw_mode(); if (in_non_blocking_mode) leave_non_blocking(); @@ -226,7 +186,7 @@ signal_handler(int sig) */ double -get_current_time() +get_current_time(void) { struct timeval tv; gettimeofday(&tv, NULL); @@ -240,7 +200,7 @@ get_current_time() */ void -client_check_initial_eof_on_stdin() +client_check_initial_eof_on_stdin(void) { int len; char buf[1]; @@ -276,12 +236,10 @@ client_check_initial_eof_on_stdin() * and also process it as an escape character if * appropriate. */ - if ((unsigned char) buf[0] == escape_char) + if ((u_char) buf[0] == escape_char) escape_pending = 1; - else { + else buffer_append(&stdin_buffer, buf, 1); - stdin_bytes += 1; - } } leave_non_blocking(); } @@ -294,9 +252,9 @@ client_check_initial_eof_on_stdin() */ void -client_make_packets_from_stdin_data() +client_make_packets_from_stdin_data(void) { - unsigned int len; + u_int len; /* Send buffered stdin data to the server. */ while (buffer_len(&stdin_buffer) > 0 && @@ -309,6 +267,7 @@ client_make_packets_from_stdin_data() packet_put_string(buffer_ptr(&stdin_buffer), len); packet_send(); buffer_consume(&stdin_buffer, len); + stdin_bytes += len; /* If we have a pending EOF, send it now. */ if (stdin_eof && buffer_len(&stdin_buffer) == 0) { packet_start(SSH_CMSG_EOF); @@ -325,7 +284,7 @@ client_make_packets_from_stdin_data() */ void -client_check_window_change() +client_check_window_change(void) { struct winsize ws; @@ -362,45 +321,37 @@ client_check_window_change() */ void -client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) +client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, + int *maxfdp, int rekeying) { - /* Initialize select masks. */ - FD_ZERO(readset); - FD_ZERO(writeset); + /* Add any selections by the channel mechanism. */ + channel_prepare_select(readsetp, writesetp, maxfdp, rekeying); if (!compat20) { /* Read from the connection, unless our buffers are full. */ if (buffer_len(&stdout_buffer) < buffer_high && buffer_len(&stderr_buffer) < buffer_high && channel_not_very_much_buffered_data()) - FD_SET(connection_in, readset); + FD_SET(connection_in, *readsetp); /* * Read from stdin, unless we have seen EOF or have very much * buffered data to send to the server. */ if (!stdin_eof && packet_not_very_much_data_to_write()) - FD_SET(fileno(stdin), readset); + FD_SET(fileno(stdin), *readsetp); /* Select stdout/stderr if have data in buffer. */ if (buffer_len(&stdout_buffer) > 0) - FD_SET(fileno(stdout), writeset); + FD_SET(fileno(stdout), *writesetp); if (buffer_len(&stderr_buffer) > 0) - FD_SET(fileno(stderr), writeset); + FD_SET(fileno(stderr), *writesetp); } else { - FD_SET(connection_in, readset); + FD_SET(connection_in, *readsetp); } - /* Add any selections by the channel mechanism. */ - channel_prepare_select(readset, writeset); - /* Select server connection if have data to write to the server. */ if (packet_have_data_to_write()) - FD_SET(connection_out, writeset); - -/* move UP XXX */ - /* Update maximum file descriptor number, if appropriate. */ - if (channel_max_fd() > max_fd) - max_fd = channel_max_fd(); + FD_SET(connection_out, *writesetp); /* * Wait for something to happen. This will suspend the process until @@ -411,17 +362,22 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) * SSH_MSG_IGNORE packet when the timeout expires. */ - if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) { + if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { char buf[100]; - /* Some systems fail to clear these automatically. */ - FD_ZERO(readset); - FD_ZERO(writeset); + + /* + * We have to clear the select masks, because we return. + * We have to return, because the mainloop checks for the flags + * set by the signal handlers. + */ + memset(*readsetp, 0, *maxfdp); + memset(*writesetp, 0, *maxfdp); + if (errno == EINTR) return; /* Note: we might still have data in the buffers. */ snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); quit_pending = 1; } } @@ -487,7 +443,6 @@ client_process_net_input(fd_set * readset) snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", host); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); quit_pending = 1; return; } @@ -495,7 +450,7 @@ client_process_net_input(fd_set * readset) * There is a kernel bug on Solaris that causes select to * sometimes wake up even though there is no data available. */ - if (len < 0 && errno == EAGAIN) + if (len < 0 && (errno == EAGAIN || errno == EINTR)) len = 0; if (len < 0) { @@ -503,7 +458,6 @@ client_process_net_input(fd_set * readset) snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", host, strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); quit_pending = 1; return; } @@ -518,8 +472,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) char string[1024]; pid_t pid; int bytes = 0; - unsigned int i; - unsigned char ch; + u_int i; + u_char ch; char *s; for (i = 0; i < len; i++) { @@ -537,7 +491,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) /* Terminate the connection. */ snprintf(string, sizeof string, "%c.\r\n", escape_char); buffer_append(berr, string, strlen(string)); - /*stderr_bytes += strlen(string); XXX*/ quit_pending = 1; return -1; @@ -547,7 +500,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) /* Print a message to that effect to the user. */ snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); buffer_append(berr, string, strlen(string)); - /*stderr_bytes += strlen(string); XXX*/ /* Restore terminal modes and suspend. */ client_suspend_self(bin, bout, berr); @@ -555,6 +507,15 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) /* We have been continued. */ continue; + case 'R': + if (compat20) { + if (datafellows & SSH_BUG_NOREKEY) + log("Server does not support re-keying"); + else + need_rekeying = 1; + } + continue; + case '&': /* XXX does not work yet with proto 2 */ if (compat20) @@ -605,6 +566,7 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) "%c?\r\n\ Supported escape sequences:\r\n\ ~. - terminate connection\r\n\ +~R - Request rekey (SSH protocol 2 only)\r\n\ ~^Z - suspend ssh\r\n\ ~# - list forwarded connections\r\n\ ~& - background ssh (when waiting for connections to terminate)\r\n\ @@ -657,7 +619,6 @@ Supported escape sequences:\r\n\ void client_process_input(fd_set * readset) { - int ret; int len; char buf[8192]; @@ -665,6 +626,8 @@ client_process_input(fd_set * readset) if (FD_ISSET(fileno(stdin), readset)) { /* Read as much as possible. */ len = read(fileno(stdin), buf, sizeof(buf)); + if (len < 0 && (errno == EAGAIN || errno == EINTR)) + return; /* we'll try again later */ if (len <= 0) { /* * Received EOF or error. They are treated @@ -674,7 +637,6 @@ client_process_input(fd_set * readset) if (len < 0) { snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); } /* Mark that we have seen EOF. */ stdin_eof = 1; @@ -695,16 +657,14 @@ client_process_input(fd_set * readset) * Just append the data to buffer. */ buffer_append(&stdin_buffer, buf, len); - stdin_bytes += len; } else { /* * Normal, successful read. But we have an escape character * and have to process the characters one by one. */ - ret = process_escapes(&stdin_buffer, &stdout_buffer, &stderr_buffer, buf, len); - if (ret == -1) + if (process_escapes(&stdin_buffer, &stdout_buffer, + &stderr_buffer, buf, len) == -1) return; - stdout_bytes += ret; } } } @@ -721,7 +681,7 @@ client_process_output(fd_set * writeset) len = write(fileno(stdout), buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer)); if (len <= 0) { - if (errno == EAGAIN) + if (errno == EINTR || errno == EAGAIN) len = 0; else { /* @@ -730,13 +690,13 @@ client_process_output(fd_set * writeset) */ snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); quit_pending = 1; return; } } /* Consume printed data from the buffer. */ buffer_consume(&stdout_buffer, len); + stdout_bytes += len; } /* Write buffered output to stderr. */ if (FD_ISSET(fileno(stderr), writeset)) { @@ -744,7 +704,7 @@ client_process_output(fd_set * writeset) len = write(fileno(stderr), buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer)); if (len <= 0) { - if (errno == EAGAIN) + if (errno == EINTR || errno == EAGAIN) len = 0; else { /* EOF or error, but can't even print error message. */ @@ -754,6 +714,7 @@ client_process_output(fd_set * writeset) } /* Consume printed characters from the buffer. */ buffer_consume(&stderr_buffer, len); + stderr_bytes += len; } } @@ -770,9 +731,9 @@ client_process_output(fd_set * writeset) */ void -client_process_buffered_input_packets() +client_process_buffered_input_packets(void) { - dispatch_run(DISPATCH_NONBLOCK, &quit_pending, NULL); + dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); } /* scan buf[] for '~' before sending data to the peer */ @@ -784,6 +745,17 @@ simple_escape_filter(Channel *c, char *buf, int len) return process_escapes(&c->input, &c->output, &c->extended, buf, len); } +void +client_channel_closed(int id, void *arg) +{ + if (id != session_ident) + error("client_channel_closed: id %d != session_ident %d", + id, session_ident); + session_closed = 1; + if (in_raw_mode()) + leave_raw_mode(); +} + /* * Implements the interactive session with the server. This is called after * the user has been authenticated, and a command has been started on the @@ -794,8 +766,9 @@ simple_escape_filter(Channel *c, char *buf, int len) int client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) { + fd_set *readset = NULL, *writeset = NULL; double start_time, total_time; - int len; + int max_fd = 0, len, rekeying = 0; char buf[100]; debug("Entering interactive session."); @@ -810,9 +783,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) buffer_high = 64 * 1024; connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); - max_fd = connection_in; - if (connection_out > max_fd) - max_fd = connection_out; + max_fd = MAX(connection_in, connection_out); + + if (!compat20) { + /* enable nonblocking unless tty */ + if (!isatty(fileno(stdin))) + set_nonblock(fileno(stdin)); + if (!isatty(fileno(stdout))) + set_nonblock(fileno(stdout)); + if (!isatty(fileno(stderr))) + set_nonblock(fileno(stderr)); + max_fd = MAX(max_fd, fileno(stdin)); + max_fd = MAX(max_fd, fileno(stdout)); + max_fd = MAX(max_fd, fileno(stderr)); + } stdin_bytes = 0; stdout_bytes = 0; stderr_bytes = 0; @@ -837,80 +821,102 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) if (have_pty) enter_raw_mode(); - /* Check if we should immediately send eof on stdin. */ - if (!compat20) + if (compat20) { + session_ident = ssh2_chan_id; + if (escape_char != -1) + channel_register_filter(session_ident, + simple_escape_filter); + if (session_ident != -1) + channel_register_cleanup(session_ident, + client_channel_closed); + } else { + /* Check if we should immediately send eof on stdin. */ client_check_initial_eof_on_stdin(); - - if (compat20 && escape_char != -1) - channel_register_filter(ssh2_chan_id, simple_escape_filter); + } /* Main loop of the client for the interactive session mode. */ while (!quit_pending) { - fd_set readset, writeset; /* Process buffered packets sent by the server. */ client_process_buffered_input_packets(); - if (compat20 && !channel_still_open()) { - debug2("!channel_still_open."); + if (compat20 && session_closed && !channel_still_open()) break; - } - /* - * Make packets of buffered stdin data, and buffer them for - * sending to the server. - */ - if (!compat20) - client_make_packets_from_stdin_data(); + rekeying = (xxx_kex != NULL && !xxx_kex->done); - /* - * Make packets from buffered channel data, and buffer them - * for sending to the server. - */ - if (packet_not_very_much_data_to_write()) - channel_output_poll(); + if (rekeying) { + debug("rekeying in progress"); + } else { + /* + * Make packets of buffered stdin data, and buffer + * them for sending to the server. + */ + if (!compat20) + client_make_packets_from_stdin_data(); - /* - * Check if the window size has changed, and buffer a message - * about it to the server if so. - */ - client_check_window_change(); + /* + * Make packets from buffered channel data, and + * enqueue them for sending to the server. + */ + if (packet_not_very_much_data_to_write()) + channel_output_poll(); - if (quit_pending) - break; + /* + * Check if the window size has changed, and buffer a + * message about it to the server if so. + */ + client_check_window_change(); + if (quit_pending) + break; + } /* * Wait until we have something to do (something becomes * available on one of the descriptors). */ - client_wait_until_can_do_something(&readset, &writeset); + client_wait_until_can_do_something(&readset, &writeset, + &max_fd, rekeying); if (quit_pending) break; - /* Do channel operations. */ - channel_after_select(&readset, &writeset); + /* Do channel operations unless rekeying in progress. */ + if (!rekeying) { + channel_after_select(readset, writeset); + + if (need_rekeying) { + debug("user requests rekeying"); + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + need_rekeying = 0; + } + } /* Buffer input from the connection. */ - client_process_net_input(&readset); + client_process_net_input(readset); if (quit_pending) break; if (!compat20) { /* Buffer data from stdin */ - client_process_input(&readset); + client_process_input(readset); /* * Process output to stdout and stderr. Output to * the connection is processed elsewhere (above). */ - client_process_output(&writeset); + client_process_output(writeset); } /* Send as much buffered packet data as possible to the sender. */ - if (FD_ISSET(connection_out, &writeset)) + if (FD_ISSET(connection_out, writeset)) packet_write_poll(); } + if (readset) + xfree(readset); + if (writeset) + xfree(writeset); /* Terminate the session. */ @@ -928,7 +934,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); } /* Output any buffered data for stdout. */ while (buffer_len(&stdout_buffer) > 0) { @@ -939,6 +944,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) break; } buffer_consume(&stdout_buffer, len); + stdout_bytes += len; } /* Output any buffered data for stderr. */ @@ -950,6 +956,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) break; } buffer_consume(&stderr_buffer, len); + stderr_bytes += len; } if (have_pty) @@ -980,22 +987,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) void client_input_stdout_data(int type, int plen, void *ctxt) { - unsigned int data_len; + u_int data_len; char *data = packet_get_string(&data_len); packet_integrity_check(plen, 4 + data_len, type); buffer_append(&stdout_buffer, data, data_len); - stdout_bytes += data_len; memset(data, 0, data_len); xfree(data); } void client_input_stderr_data(int type, int plen, void *ctxt) { - unsigned int data_len; + u_int data_len; char *data = packet_get_string(&data_len); packet_integrity_check(plen, 4 + data_len, type); buffer_append(&stderr_buffer, data, data_len); - stdout_bytes += data_len; memset(data, 0, data_len); xfree(data); } @@ -1016,14 +1021,102 @@ client_input_exit_status(int type, int plen, void *ctxt) quit_pending = 1; } +Channel * +client_request_forwarded_tcpip(const char *request_type, int rchan) +{ + Channel* c = NULL; + char *listen_address, *originator_address; + int listen_port, originator_port; + int sock, newch; + + /* Get rest of the packet */ + listen_address = packet_get_string(NULL); + listen_port = packet_get_int(); + originator_address = packet_get_string(NULL); + originator_port = packet_get_int(); + packet_done(); + + debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", + listen_address, listen_port, originator_address, originator_port); + + sock = channel_connect_by_listen_adress(listen_port); + if (sock >= 0) { + newch = channel_new("forwarded-tcpip", + SSH_CHANNEL_CONNECTING, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + xstrdup(originator_address), 1); + c = channel_lookup(newch); + } + xfree(originator_address); + xfree(listen_address); + return c; +} + +Channel* +client_request_x11(const char *request_type, int rchan) +{ + Channel *c = NULL; + char *originator; + int originator_port; + int sock, newch; + + if (!options.forward_x11) { + error("Warning: ssh server tried X11 forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + originator = packet_get_string(NULL); + if (datafellows & SSH_BUG_X11FWD) { + debug2("buggy server: x11 request w/o originator_port"); + originator_port = 0; + } else { + originator_port = packet_get_int(); + } + packet_done(); + /* XXX check permission */ + debug("client_request_x11: request from %s %d", originator, + originator_port); + sock = x11_connect_display(); + if (sock >= 0) { + newch = channel_new("x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, + xstrdup("x11"), 1); + c = channel_lookup(newch); + } + xfree(originator); + return c; +} + +Channel* +client_request_agent(const char *request_type, int rchan) +{ + Channel *c = NULL; + int sock, newch; + + if (!options.forward_agent) { + error("Warning: ssh server tried agent forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + sock = ssh_get_authentication_socket(); + if (sock >= 0) { + newch = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + xstrdup("authentication agent connection"), 1); + c = channel_lookup(newch); + } + return c; +} + /* XXXX move to generic input handler */ void client_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; - int id; - unsigned int len; + u_int len; int rchan; int rmaxpack; int rwindow; @@ -1036,28 +1129,12 @@ client_input_channel_open(int type, int plen, void *ctxt) debug("client_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); - if (strcmp(ctype, "x11") == 0 && options.forward_x11) { - int sock; - char *originator; - int originator_port; - originator = packet_get_string(NULL); - if (datafellows & SSH_BUG_X11FWD) { - debug2("buggy server: x11 request w/o originator_port"); - originator_port = 0; - } else { - originator_port = packet_get_int(); - } - packet_done(); - /* XXX check permission */ - xfree(originator); - /* XXX move to channels.c */ - sock = x11_connect_display(); - if (sock >= 0) { - id = channel_new("x11", SSH_CHANNEL_X11_OPEN, - sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, - CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1); - c = channel_lookup(id); - } + if (strcmp(ctype, "forwarded-tcpip") == 0) { + c = client_request_forwarded_tcpip(ctype, rchan); + } else if (strcmp(ctype, "x11") == 0) { + c = client_request_x11(ctype, rchan); + } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { + c = client_request_agent(ctype, rchan); } /* XXX duplicate : */ if (c != NULL) { @@ -1083,9 +1160,45 @@ client_input_channel_open(int type, int plen, void *ctxt) } xfree(ctype); } +void +client_input_channel_req(int type, int plen, void *ctxt) +{ + Channel *c = NULL; + int id, reply, success = 0; + char *rtype; + + id = packet_get_int(); + rtype = packet_get_string(NULL); + reply = packet_get_char(); + + debug("client_input_channel_req: channel %d rtype %s reply %d", + id, rtype, reply); + + if (session_ident == -1) { + error("client_input_channel_req: no channel %d", session_ident); + } else if (id != session_ident) { + error("client_input_channel_req: channel %d: wrong channel: %d", + session_ident, id); + } + c = channel_lookup(id); + if (c == NULL) { + error("client_input_channel_req: channel %d: unknown channel", id); + } else if (strcmp(rtype, "exit-status") == 0) { + success = 1; + exit_status = packet_get_int(); + packet_done(); + } + if (reply) { + packet_start(success ? + SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); + packet_put_int(c->remote_id); + packet_send(); + } + xfree(rtype); +} void -client_init_dispatch_20() +client_init_dispatch_20(void) { dispatch_init(&dispatch_protocol_error); dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); @@ -1095,11 +1208,14 @@ client_init_dispatch_20() dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open); dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); - dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); + dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); + + /* rekeying */ + dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); } void -client_init_dispatch_13() +client_init_dispatch_13(void) { dispatch_init(NULL); dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); @@ -1118,14 +1234,14 @@ client_init_dispatch_13() &x11_input_open : &deny_input_open); } void -client_init_dispatch_15() +client_init_dispatch_15(void) { client_init_dispatch_13(); dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); } void -client_init_dispatch() +client_init_dispatch(void) { if (compat20) client_init_dispatch_20(); @@ -1134,49 +1250,3 @@ client_init_dispatch() else client_init_dispatch_15(); } - -void -client_input_channel_req(int id, void *arg) -{ - Channel *c = NULL; - unsigned int len; - int success = 0; - int reply; - char *rtype; - - rtype = packet_get_string(&len); - reply = packet_get_char(); - - debug("client_input_channel_req: rtype %s reply %d", rtype, reply); - - c = channel_lookup(id); - if (c == NULL) - fatal("client_input_channel_req: channel %d: bad channel", id); - - if (session_ident == -1) { - error("client_input_channel_req: no channel %d", id); - } else if (id != session_ident) { - error("client_input_channel_req: bad channel %d != %d", - id, session_ident); - } else if (strcmp(rtype, "exit-status") == 0) { - success = 1; - exit_status = packet_get_int(); - packet_done(); - } - if (reply) { - packet_start(success ? - SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); - packet_put_int(c->remote_id); - packet_send(); - } - xfree(rtype); -} - -void -client_set_session_ident(int id) -{ - debug2("client_set_session_ident: id %d", id); - session_ident = id; - channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, - client_input_channel_req, (void *)0); -} diff --git a/crypto/openssh/clientloop.h b/crypto/openssh/clientloop.h new file mode 100644 index 0000000..ee40d87 --- /dev/null +++ b/crypto/openssh/clientloop.h @@ -0,0 +1,39 @@ +/* $OpenBSD: clientloop.h,v 1.4 2001/02/06 22:43:02 markus Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Client side main loop for the interactive session. */ +int client_loop(int have_pty, int escape_char, int id); diff --git a/crypto/openssh/compress.c b/crypto/openssh/compress.c index 93266ed..3e41b3d 100644 --- a/crypto/openssh/compress.c +++ b/crypto/openssh/compress.c @@ -12,14 +12,17 @@ */ #include "includes.h" -RCSID("$OpenBSD: compress.c,v 1.9 2000/09/07 20:27:50 deraadt Exp $"); +RCSID("$OpenBSD: compress.c,v 1.14 2001/04/05 10:39:01 markus Exp $"); -#include "ssh.h" +#include "log.h" #include "buffer.h" #include "zlib.h" +#include "compress.h" static z_stream incoming_stream; static z_stream outgoing_stream; +static int compress_init_send_called = 0; +static int compress_init_recv_called = 0; /* * Initializes compression; level is compression level from 1 to 9 @@ -27,19 +30,29 @@ static z_stream outgoing_stream; */ void -buffer_compress_init(int level) +buffer_compress_init_send(int level) { + if (compress_init_send_called == 1) + deflateEnd(&incoming_stream); + compress_init_send_called = 1; debug("Enabling compression at level %d.", level); if (level < 1 || level > 9) fatal("Bad compression level %d.", level); - inflateInit(&incoming_stream); deflateInit(&outgoing_stream, level); } +void +buffer_compress_init_recv(void) +{ + if (compress_init_recv_called == 1) + inflateEnd(&incoming_stream); + compress_init_recv_called = 1; + inflateInit(&incoming_stream); +} /* Frees any data structures allocated for compression. */ void -buffer_compress_uninit() +buffer_compress_uninit(void) { debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f", outgoing_stream.total_in, outgoing_stream.total_out, @@ -49,8 +62,10 @@ buffer_compress_uninit() incoming_stream.total_out, incoming_stream.total_in, incoming_stream.total_out == 0 ? 0.0 : (double) incoming_stream.total_in / incoming_stream.total_out); - inflateEnd(&incoming_stream); - deflateEnd(&outgoing_stream); + if (compress_init_recv_called == 1) + inflateEnd(&incoming_stream); + if (compress_init_send_called == 1) + deflateEnd(&outgoing_stream); } /* @@ -73,13 +88,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer) return; /* Input is the contents of the input buffer. */ - outgoing_stream.next_in = (unsigned char *) buffer_ptr(input_buffer); + outgoing_stream.next_in = (u_char *) buffer_ptr(input_buffer); outgoing_stream.avail_in = buffer_len(input_buffer); /* Loop compressing until deflate() returns with avail_out != 0. */ do { /* Set up fixed-size output buffer. */ - outgoing_stream.next_out = (unsigned char *)buf; + outgoing_stream.next_out = (u_char *)buf; outgoing_stream.avail_out = sizeof(buf); /* Compress as much data into the buffer as possible. */ @@ -112,12 +127,12 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer) char buf[4096]; int status; - incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer); + incoming_stream.next_in = (u_char *) buffer_ptr(input_buffer); incoming_stream.avail_in = buffer_len(input_buffer); for (;;) { /* Set up fixed-size output buffer. */ - incoming_stream.next_out = (unsigned char *) buf; + incoming_stream.next_out = (u_char *) buf; incoming_stream.avail_out = sizeof(buf); status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); diff --git a/crypto/openssh/compress.h b/crypto/openssh/compress.h index 5757164..f90932a 100644 --- a/crypto/openssh/compress.h +++ b/crypto/openssh/compress.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: compress.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */ +/* RCSID("$OpenBSD: compress.h,v 1.8 2001/04/05 10:39:02 markus Exp $"); */ #ifndef COMPRESS_H #define COMPRESS_H @@ -20,10 +20,11 @@ * Initializes compression; level is compression level from 1 to 9 (as in * gzip). */ -void buffer_compress_init(int level); +void buffer_compress_init_send(int level); +void buffer_compress_init_recv(void); /* Frees any data structures allocated by buffer_compress_init. */ -void buffer_compress_uninit(); +void buffer_compress_uninit(void); /* * Compresses the contents of input_buffer into output_buffer. All packets diff --git a/crypto/openssh/crc32.c b/crypto/openssh/crc32.c index a4e1f27..4774c8b 100644 --- a/crypto/openssh/crc32.c +++ b/crypto/openssh/crc32.c @@ -31,7 +31,7 @@ * tions for all combinations of data and CRC register values * * The values must be right-shifted by eight bits by the "updcrc - * logic; the shift must be unsigned (bring in zeroes). On some + * logic; the shift must be u_(bring in zeroes). On some * hardware you could probably optimize the shift in assembler by * using byte-swap instructions * polynomial $edb88320 @@ -39,11 +39,11 @@ #include "includes.h" -RCSID("$OpenBSD: crc32.c,v 1.7 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: crc32.c,v 1.8 2000/12/19 23:17:56 markus Exp $"); #include "crc32.h" -static unsigned int crc32_tab[] = { +static u_int crc32_tab[] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, @@ -100,11 +100,11 @@ static unsigned int crc32_tab[] = { /* Return a 32-bit CRC of the contents of the buffer. */ -unsigned int -ssh_crc32(const unsigned char *s, unsigned int len) +u_int +ssh_crc32(const u_char *s, u_int len) { - unsigned int i; - unsigned int crc32val; + u_int i; + u_int crc32val; crc32val = 0; for (i = 0; i < len; i ++) { diff --git a/crypto/openssh/crc32.h b/crypto/openssh/crc32.h index 58c4fba..c469a90 100644 --- a/crypto/openssh/crc32.h +++ b/crypto/openssh/crc32.h @@ -1,6 +1,6 @@ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> - * Copyright (c) 1992 Tatu Ylonen, Espoo, Finland + * Copyright (c) 1992 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved * Functions for computing 32-bit CRC. * @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: crc32.h,v 1.8 2000/09/07 20:27:51 deraadt Exp $"); */ +/* RCSID("$OpenBSD: crc32.h,v 1.10 2001/03/02 18:54:31 deraadt Exp $"); */ #ifndef CRC32_H #define CRC32_H @@ -20,6 +20,6 @@ * This computes a 32 bit CRC of the data in the buffer, and returns the CRC. * The polynomial used is 0xedb88320. */ -unsigned int ssh_crc32(const unsigned char *buf, unsigned int len); +u_int ssh_crc32(const u_char *buf, u_int len); #endif /* CRC32_H */ diff --git a/crypto/openssh/deattack.c b/crypto/openssh/deattack.c index df1d224..36023e0 100644 --- a/crypto/openssh/deattack.c +++ b/crypto/openssh/deattack.c @@ -1,4 +1,4 @@ -/* $OpenBSD: deattack.c,v 1.10 2000/10/31 13:18:53 markus Exp $ */ +/* $OpenBSD: deattack.c,v 1.13 2001/03/01 02:45:10 deraadt Exp $ */ /* * Cryptographic attack detector for ssh - source code @@ -21,7 +21,7 @@ #include "includes.h" #include "deattack.h" -#include "ssh.h" +#include "log.h" #include "crc32.h" #include "getput.h" #include "xmalloc.h" @@ -44,23 +44,23 @@ /* Hash function (Input keys are cipher results) */ #define HASH(x) GET_32BIT(x) -#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE)) +#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) void crc_update(u_int32_t *a, u_int32_t b) { b ^= *a; - *a = ssh_crc32((unsigned char *) &b, sizeof(b)); + *a = ssh_crc32((u_char *) &b, sizeof(b)); } /* detect if a block is used in a particular pattern */ int -check_crc(unsigned char *S, unsigned char *buf, u_int32_t len, - unsigned char *IV) +check_crc(u_char *S, u_char *buf, u_int32_t len, + u_char *IV) { u_int32_t crc; - unsigned char *c; + u_char *c; crc = 0; if (IV && !CMP(S, IV)) { @@ -82,14 +82,14 @@ check_crc(unsigned char *S, unsigned char *buf, u_int32_t len, /* Detect a crc32 compensation attack on a packet */ int -detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV) +detect_attack(u_char *buf, u_int32_t len, u_char *IV) { static u_int16_t *h = (u_int16_t *) NULL; static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; register u_int32_t i, j; u_int32_t l; - register unsigned char *c; - unsigned char *d; + register u_char *c; + u_char *d; if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || len % SSH_BLOCKSIZE != 0) { diff --git a/crypto/openssh/deattack.h b/crypto/openssh/deattack.h index 6ce54de..3907159 100644 --- a/crypto/openssh/deattack.h +++ b/crypto/openssh/deattack.h @@ -1,3 +1,5 @@ +/* $OpenBSD: deattack.h,v 1.5 2001/01/29 01:58:15 niklas Exp $ */ + /* * Cryptographic attack detector for ssh - Header file * @@ -24,5 +26,5 @@ #define DEATTACK_OK 0 #define DEATTACK_DETECTED 1 -int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]); +int detect_attack(u_char *buf, u_int32_t len, u_char IV[8]); #endif diff --git a/crypto/openssh/dh.c b/crypto/openssh/dh.c index ff84619..575522d 100644 --- a/crypto/openssh/dh.c +++ b/crypto/openssh/dh.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $"); +RCSID("$OpenBSD: dh.c,v 1.14 2001/04/15 08:43:45 markus Exp $"); #include "xmalloc.h" @@ -31,10 +31,13 @@ RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $"); #include <openssl/dh.h> #include <openssl/evp.h> -#include "ssh.h" #include "buffer.h" +#include "cipher.h" #include "kex.h" #include "dh.h" +#include "pathnames.h" +#include "log.h" +#include "misc.h" int parse_prime(int linenum, char *line, struct dhgroup *dhg) @@ -66,6 +69,8 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) if (cp == NULL || *strsize == '\0' || (dhg->size = atoi(strsize)) == 0) goto fail; + /* The whole group is one bit larger */ + dhg->size++; gen = strsep(&cp, " "); /* gen */ if (cp == NULL || *gen == '\0') goto fail; @@ -74,25 +79,28 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) goto fail; dhg->g = BN_new(); - if (BN_hex2bn(&dhg->g, gen) < 0) { - BN_free(dhg->g); - goto fail; - } dhg->p = BN_new(); - if (BN_hex2bn(&dhg->p, prime) < 0) { - BN_free(dhg->g); - BN_free(dhg->p); - goto fail; - } + if (BN_hex2bn(&dhg->g, gen) == 0) + goto failclean; + + if (BN_hex2bn(&dhg->p, prime) == 0) + goto failclean; + + if (BN_num_bits(dhg->p) != dhg->size) + goto failclean; return (1); + + failclean: + BN_free(dhg->g); + BN_free(dhg->p); fail: - fprintf(stderr, "Bad prime description in line %d\n", linenum); + error("Bad prime description in line %d", linenum); return (0); } DH * -choose_dh(int minbits) +choose_dh(int min, int wantbits, int max) { FILE *f; char line[1024]; @@ -100,10 +108,9 @@ choose_dh(int minbits) int linenum; struct dhgroup dhg; - f = fopen(DH_PRIMES, "r"); + f = fopen(_PATH_DH_PRIMES, "r"); if (!f) { - perror(DH_PRIMES); - log("WARNING: %s does not exist, using old prime", DH_PRIMES); + log("WARNING: %s does not exist, using old prime", _PATH_DH_PRIMES); return (dh_new_group1()); } @@ -116,8 +123,11 @@ choose_dh(int minbits) BN_free(dhg.g); BN_free(dhg.p); - if ((dhg.size > minbits && dhg.size < best) || - (dhg.size > best && best < minbits)) { + if (dhg.size > max || dhg.size < min) + continue; + + if ((dhg.size > wantbits && dhg.size < best) || + (dhg.size > best && best < wantbits)) { best = dhg.size; bestcount = 0; } @@ -127,14 +137,13 @@ choose_dh(int minbits) fclose (f); if (bestcount == 0) { - log("WARNING: no primes in %s, using old prime", DH_PRIMES); - return (dh_new_group1()); + log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES); + return (NULL); } - f = fopen(DH_PRIMES, "r"); + f = fopen(_PATH_DH_PRIMES, "r"); if (!f) { - perror(DH_PRIMES); - exit(1); + fatal("WARNING: %s disappeared, giving up", _PATH_DH_PRIMES); } linenum = 0; @@ -142,9 +151,9 @@ choose_dh(int minbits) while (fgets(line, sizeof(line), f)) { if (!parse_prime(linenum, line, &dhg)) continue; - if (dhg.size != best) - continue; - if (linenum++ != which) { + if ((dhg.size > max || dhg.size < min) || + dhg.size != best || + linenum++ != which) { BN_free(dhg.g); BN_free(dhg.p); continue; @@ -152,6 +161,134 @@ choose_dh(int minbits) break; } fclose(f); + if (linenum != which+1) + fatal("WARNING: line %d disappeared in %s, giving up", + which, _PATH_DH_PRIMES); return (dh_new_group(dhg.g, dhg.p)); } + +/* diffie-hellman-group1-sha1 */ + +int +dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) +{ + int i; + int n = BN_num_bits(dh_pub); + int bits_set = 0; + + if (dh_pub->neg) { + log("invalid public DH value: negativ"); + return 0; + } + for (i = 0; i <= n; i++) + if (BN_is_bit_set(dh_pub, i)) + bits_set++; + debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); + + /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ + if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) + return 1; + log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); + return 0; +} + +void +dh_gen_key(DH *dh, int need) +{ + int i, bits_set = 0, tries = 0; + + if (dh->p == NULL) + fatal("dh_gen_key: dh->p == NULL"); + if (2*need >= BN_num_bits(dh->p)) + fatal("dh_gen_key: group too small: %d (2*need %d)", + BN_num_bits(dh->p), 2*need); + do { + if (dh->priv_key != NULL) + BN_free(dh->priv_key); + dh->priv_key = BN_new(); + if (dh->priv_key == NULL) + fatal("dh_gen_key: BN_new failed"); + /* generate a 2*need bits random private exponent */ + if (!BN_rand(dh->priv_key, 2*need, 0, 0)) + fatal("dh_gen_key: BN_rand failed"); + if (DH_generate_key(dh) == 0) + fatal("DH_generate_key"); + for (i = 0; i <= BN_num_bits(dh->priv_key); i++) + if (BN_is_bit_set(dh->priv_key, i)) + bits_set++; + debug("dh_gen_key: priv key bits set: %d/%d", + bits_set, BN_num_bits(dh->priv_key)); + if (tries++ > 10) + fatal("dh_gen_key: too many bad keys: giving up"); + } while (!dh_pub_is_valid(dh, dh->pub_key)); +} + +DH * +dh_new_group_asc(const char *gen, const char *modulus) +{ + DH *dh; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + + if (BN_hex2bn(&dh->p, modulus) == 0) + fatal("BN_hex2bn p"); + if (BN_hex2bn(&dh->g, gen) == 0) + fatal("BN_hex2bn g"); + + return (dh); +} + +/* + * This just returns the group, we still need to generate the exchange + * value. + */ + +DH * +dh_new_group(BIGNUM *gen, BIGNUM *modulus) +{ + DH *dh; + + dh = DH_new(); + if (dh == NULL) + fatal("DH_new"); + dh->p = modulus; + dh->g = gen; + + return (dh); +} + +DH * +dh_new_group1(void) +{ + static char *gen = "2", *group1 = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + + return (dh_new_group_asc(gen, group1)); +} + +/* + * Estimates the group order for a Diffie-Hellman group that has an + * attack complexity approximately the same as O(2**bits). Estimate + * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) + */ + +int +dh_estimate(int bits) +{ + + if (bits < 64) + return (512); /* O(2**63) */ + if (bits < 128) + return (1024); /* O(2**86) */ + if (bits < 192) + return (2048); /* O(2**116) */ + return (4096); /* O(2**156) */ +} diff --git a/crypto/openssh/dh.h b/crypto/openssh/dh.h index 09b11fd..e8b2944 100644 --- a/crypto/openssh/dh.h +++ b/crypto/openssh/dh.h @@ -1,3 +1,5 @@ +/* $OpenBSD: dh.h,v 1.5 2001/04/03 19:53:29 markus Exp $ */ + /* * Copyright (c) 2000 Niels Provos. All rights reserved. * @@ -30,6 +32,17 @@ struct dhgroup { BIGNUM *p; }; -DH *choose_dh(int minbits); +DH *choose_dh(int min, int nbits, int max); +DH *dh_new_group_asc(const char *, const char *); +DH *dh_new_group(BIGNUM *, BIGNUM *); +DH *dh_new_group1(void); + +void dh_gen_key(DH *, int); +int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub); + +int dh_estimate(int bits); + +#define DH_GRP_MIN 1024 +#define DH_GRP_MAX 8192 #endif diff --git a/crypto/openssh/dispatch.c b/crypto/openssh/dispatch.c index db8951c..7168d1c 100644 --- a/crypto/openssh/dispatch.c +++ b/crypto/openssh/dispatch.c @@ -22,10 +22,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: dispatch.c,v 1.5 2000/09/21 11:25:34 markus Exp $"); -#include "ssh.h" +RCSID("$OpenBSD: dispatch.c,v 1.10 2001/02/18 18:33:53 markus Exp $"); + +#include "ssh1.h" +#include "ssh2.h" +#include "log.h" #include "dispatch.h" #include "packet.h" +#include "compat.h" #define DISPATCH_MIN 0 #define DISPATCH_MAX 255 @@ -36,6 +40,8 @@ void dispatch_protocol_error(int type, int plen, void *ctxt) { error("Hm, dispatch protocol error: type %d plen %d", type, plen); + if (compat20 && type == SSH2_MSG_KEXINIT) + fatal("dispatch_protocol_error: rekeying is not supported"); } void dispatch_init(dispatch_fn *dflt) @@ -66,7 +72,7 @@ dispatch_run(int mode, int *done, void *ctxt) if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) (*dispatch[type])(type, plen, ctxt); else - packet_disconnect("protocol error: rcvd type %d", type); + packet_disconnect("protocol error: rcvd type %d", type); if (done != NULL && *done) return; } diff --git a/crypto/openssh/dispatch.h b/crypto/openssh/dispatch.h index e60174c..0bee03b 100644 --- a/crypto/openssh/dispatch.h +++ b/crypto/openssh/dispatch.h @@ -1,3 +1,5 @@ +/* $OpenBSD: dispatch.h,v 1.4 2001/01/29 01:58:15 niklas Exp $ */ + /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * diff --git a/crypto/openssh/getput.h b/crypto/openssh/getput.h index 19ff5e1..1a19d22 100644 --- a/crypto/openssh/getput.h +++ b/crypto/openssh/getput.h @@ -11,20 +11,39 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: getput.h,v 1.5 2000/09/07 20:27:51 deraadt Exp $"); */ +/* RCSID("$OpenBSD: getput.h,v 1.7 2001/01/10 22:56:22 markus Exp $"); */ #ifndef GETPUT_H #define GETPUT_H /*------------ macros for storing/extracting msb first words -------------*/ -#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[3])) - -#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \ - ((unsigned long)(unsigned char)(cp)[1])) +#define GET_64BIT(cp) (((u_int64_t)(u_char)(cp)[0] << 56) | \ + ((u_int64_t)(u_char)(cp)[1] << 48) | \ + ((u_int64_t)(u_char)(cp)[2] << 40) | \ + ((u_int64_t)(u_char)(cp)[3] << 32) | \ + ((u_int64_t)(u_char)(cp)[4] << 24) | \ + ((u_int64_t)(u_char)(cp)[5] << 16) | \ + ((u_int64_t)(u_char)(cp)[6] << 8) | \ + ((u_int64_t)(u_char)(cp)[7])) + +#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \ + ((u_long)(u_char)(cp)[1] << 16) | \ + ((u_long)(u_char)(cp)[2] << 8) | \ + ((u_long)(u_char)(cp)[3])) + +#define GET_16BIT(cp) (((u_long)(u_char)(cp)[0] << 8) | \ + ((u_long)(u_char)(cp)[1])) + +#define PUT_64BIT(cp, value) do { \ + (cp)[0] = (value) >> 56; \ + (cp)[1] = (value) >> 48; \ + (cp)[2] = (value) >> 40; \ + (cp)[3] = (value) >> 32; \ + (cp)[4] = (value) >> 24; \ + (cp)[5] = (value) >> 16; \ + (cp)[6] = (value) >> 8; \ + (cp)[7] = (value); } while (0) #define PUT_32BIT(cp, value) do { \ (cp)[0] = (value) >> 24; \ @@ -36,26 +55,4 @@ (cp)[0] = (value) >> 8; \ (cp)[1] = (value); } while (0) -/*------------ macros for storing/extracting lsb first words -------------*/ - -#define GET_32BIT_LSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0]) | \ - ((unsigned long)(unsigned char)(cp)[1] << 8) | \ - ((unsigned long)(unsigned char)(cp)[2] << 16) | \ - ((unsigned long)(unsigned char)(cp)[3] << 24)) - -#define GET_16BIT_LSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0]) | \ - ((unsigned long)(unsigned char)(cp)[1] << 8)) - -#define PUT_32BIT_LSB_FIRST(cp, value) do { \ - (cp)[0] = (value); \ - (cp)[1] = (value) >> 8; \ - (cp)[2] = (value) >> 16; \ - (cp)[3] = (value) >> 24; } while (0) - -#define PUT_16BIT_LSB_FIRST(cp, value) do { \ - (cp)[0] = (value); \ - (cp)[1] = (value) >> 8; } while (0) - #endif /* GETPUT_H */ diff --git a/crypto/openssh/groupaccess.c b/crypto/openssh/groupaccess.c new file mode 100644 index 0000000..ac9e00ac --- /dev/null +++ b/crypto/openssh/groupaccess.c @@ -0,0 +1,78 @@ +/* $OpenBSD: groupaccess.c,v 1.3 2001/01/29 01:58:15 niklas Exp $ */ + +/* + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include "groupaccess.h" +#include "xmalloc.h" +#include "match.h" +#include "log.h" + +static int ngroups; +static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */ + +int +ga_init(const char *user, gid_t base) +{ + gid_t groups_bygid[NGROUPS_MAX + 1]; + int i, j; + struct group *gr; + + if (ngroups > 0) + ga_free(); + + ngroups = sizeof(groups_bygid) / sizeof(gid_t); + if (getgrouplist(user, base, groups_bygid, &ngroups) == -1) + log("getgrouplist: groups list too small"); + for (i = 0, j = 0; i < ngroups; i++) + if ((gr = getgrgid(groups_bygid[i])) != NULL) + groups_byname[j++] = xstrdup(gr->gr_name); + return (ngroups = j); +} + +int +ga_match(char * const *groups, int n) +{ + int i, j; + + for (i = 0; i < ngroups; i++) + for (j = 0; j < n; j++) + if (match_pattern(groups_byname[i], groups[j])) + return 1; + return 0; +} + +void +ga_free(void) +{ + int i; + + if (ngroups > 0) { + for (i = 0; i < ngroups; i++) + xfree(groups_byname[i]); + ngroups = 0; + } +} diff --git a/crypto/openssh/groupaccess.h b/crypto/openssh/groupaccess.h new file mode 100644 index 0000000..b4e5e42 --- /dev/null +++ b/crypto/openssh/groupaccess.h @@ -0,0 +1,49 @@ +/* $OpenBSD: groupaccess.h,v 1.2 2001/01/29 01:58:15 niklas Exp $ */ + +/* + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GROUPACCESS_H +#define GROUPACCESS_H + +#include <grp.h> + +/* + * Initialize group access list for user with primary (base) and + * supplementary groups. Return the number of groups in the list. + */ +int ga_init(const char *user, gid_t base); + +/* + * Return 1 if one of user's groups is contained in groups. + * Return 0 otherwise. Use match_pattern() for string comparison. + */ +int ga_match(char * const *groups, int ngroups); + +/* + * Free memory allocated for group access list. + */ +void ga_free(void); + +#endif diff --git a/crypto/openssh/hostfile.h b/crypto/openssh/hostfile.h index 9c2353b..346bcd9 100644 --- a/crypto/openssh/hostfile.h +++ b/crypto/openssh/hostfile.h @@ -1,3 +1,5 @@ +/* $OpenBSD: hostfile.h,v 1.7 2001/02/08 19:30:51 itojun Exp $ */ + /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -12,6 +14,9 @@ #ifndef HOSTFILE_H #define HOSTFILE_H +int +auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n); + /* * Checks whether the given host is already in the list of our known hosts. * Returns HOST_OK if the host is known and has the specified key, HOST_NEW @@ -21,8 +26,10 @@ typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus; + HostStatus -check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found); +check_host_in_hostfile(const char *filename, const char *host, Key *key, + Key *found, int *line); /* * Appends an entry to the host file. Returns false if the entry could not diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c index 68b9e52..69ba102 100644 --- a/crypto/openssh/kex.c +++ b/crypto/openssh/kex.c @@ -23,375 +23,217 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 markus Exp $"); + +#include <openssl/crypto.h> -#include "ssh.h" #include "ssh2.h" #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" #include "packet.h" #include "compat.h" - -#include <openssl/bn.h> -#include <openssl/dh.h> - -#include <openssl/crypto.h> -#include <openssl/bio.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/pem.h> - +#include "cipher.h" #include "kex.h" +#include "key.h" +#include "log.h" +#include "mac.h" +#include "match.h" +#include "dispatch.h" #define KEX_COOKIE_LEN 16 -Buffer * -kex_init(char *myproposal[PROPOSAL_MAX]) +void kex_kexinit_finish(Kex *kex); +void kex_choose_conf(Kex *k); + +/* put algorithm proposal into buffer */ +void +kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) { - int first_kex_packet_follows = 0; - unsigned char cookie[KEX_COOKIE_LEN]; u_int32_t rand = 0; int i; - Buffer *ki = xmalloc(sizeof(*ki)); + + buffer_clear(b); for (i = 0; i < KEX_COOKIE_LEN; i++) { if (i % 4 == 0) rand = arc4random(); - cookie[i] = rand & 0xff; + buffer_put_char(b, rand & 0xff); rand >>= 8; } - buffer_init(ki); - buffer_append(ki, (char *)cookie, sizeof cookie); for (i = 0; i < PROPOSAL_MAX; i++) - buffer_put_cstring(ki, myproposal[i]); - buffer_put_char(ki, first_kex_packet_follows); - buffer_put_int(ki, 0); /* uint32 reserved */ - return ki; + buffer_put_cstring(b, proposal[i]); + buffer_put_char(b, 0); /* first_kex_packet_follows */ + buffer_put_int(b, 0); /* uint32 reserved */ } -/* send kexinit, parse and save reply */ -void -kex_exchange_kexinit( - Buffer *my_kexinit, Buffer *peer_kexint, - char *peer_proposal[PROPOSAL_MAX]) +/* parse buffer and return algorithm proposal */ +char ** +kex_buf2prop(Buffer *raw) { + Buffer b; int i; - char *ptr; - int plen; + char **proposal; - debug("send KEXINIT"); - packet_start(SSH2_MSG_KEXINIT); - packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); - packet_send(); - packet_write_wait(); - debug("done"); + proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); - /* - * read and save raw KEXINIT payload in buffer. this is used during - * computation of the session_id and the session keys. - */ - debug("wait KEXINIT"); - packet_read_expect(&plen, SSH2_MSG_KEXINIT); - ptr = packet_get_raw(&plen); - buffer_append(peer_kexint, ptr, plen); - - /* parse packet and save algorithm proposal */ + buffer_init(&b); + buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); /* skip cookie */ for (i = 0; i < KEX_COOKIE_LEN; i++) - packet_get_char(); + buffer_get_char(&b); /* extract kex init proposal strings */ for (i = 0; i < PROPOSAL_MAX; i++) { - peer_proposal[i] = packet_get_string(NULL); - debug("got kexinit: %s", peer_proposal[i]); + proposal[i] = buffer_get_string(&b,NULL); + debug2("kex_parse_kexinit: %s", proposal[i]); } - /* first kex follow / reserved */ - i = packet_get_char(); - debug("first kex follow: %d ", i); - i = packet_get_int(); - debug("reserved: %d ", i); - packet_done(); - debug("done"); + /* first kex follows / reserved */ + i = buffer_get_char(&b); + debug2("kex_parse_kexinit: first_kex_follows %d ", i); + i = buffer_get_int(&b); + debug2("kex_parse_kexinit: reserved %d ", i); + buffer_free(&b); + return proposal; } -/* diffie-hellman-group1-sha1 */ - -int -dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) +void +kex_prop_free(char **proposal) { int i; - int n = BN_num_bits(dh_pub); - int bits_set = 0; - if (dh_pub->neg) { - log("invalid public DH value: negativ"); - return 0; - } - for (i = 0; i <= n; i++) - if (BN_is_bit_set(dh_pub, i)) - bits_set++; - debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); - - /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ - if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) - return 1; - log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); - return 0; + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(proposal[i]); + xfree(proposal); } -DH * -dh_gen_key(DH *dh) +void +kex_protocol_error(int type, int plen, void *ctxt) { - int tries = 0; - - do { - if (DH_generate_key(dh) == 0) - fatal("DH_generate_key"); - if (tries++ > 10) - fatal("dh_new_group1: too many bad keys: giving up"); - } while (!dh_pub_is_valid(dh, dh->pub_key)); - return dh; + error("Hm, kex protocol error: type %d plen %d", type, plen); } -DH * -dh_new_group_asc(const char *gen, const char *modulus) +void +kex_clear_dispatch(void) { - DH *dh; - int ret; - - dh = DH_new(); - if (dh == NULL) - fatal("DH_new"); - - if ((ret = BN_hex2bn(&dh->p, modulus)) < 0) - fatal("BN_hex2bn p"); - if ((ret = BN_hex2bn(&dh->g, gen)) < 0) - fatal("BN_hex2bn g"); + int i; - return (dh_gen_key(dh)); + /* Numbers 30-49 are used for kex packets */ + for (i = 30; i <= 49; i++) + dispatch_set(i, &kex_protocol_error); } -DH * -dh_new_group(BIGNUM *gen, BIGNUM *modulus) +void +kex_finish(Kex *kex) { - DH *dh; - - dh = DH_new(); - if (dh == NULL) - fatal("DH_new"); - dh->p = modulus; - dh->g = gen; + int plen; - return (dh_gen_key(dh)); -} + kex_clear_dispatch(); -DH * -dh_new_group1() -{ - static char *gen = "2", *group1 = - "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" - "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" - "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" - "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" - "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" - "FFFFFFFF" "FFFFFFFF"; - - return (dh_new_group_asc(gen, group1)); + packet_start(SSH2_MSG_NEWKEYS); + packet_send(); + /* packet_write_wait(); */ + debug("SSH2_MSG_NEWKEYS sent"); + + debug("waiting for SSH2_MSG_NEWKEYS"); + packet_read_expect(&plen, SSH2_MSG_NEWKEYS); + debug("SSH2_MSG_NEWKEYS received"); + + kex->done = 1; + buffer_clear(&kex->peer); + /* buffer_clear(&kex->my); */ + kex->flags &= ~KEX_INIT_SENT; + xfree(kex->name); + kex->name = NULL; } void -dump_digest(unsigned char *digest, int len) +kex_send_kexinit(Kex *kex) { - int i; - for (i = 0; i< len; i++){ - fprintf(stderr, "%02x", digest[i]); - if(i%2!=0) - fprintf(stderr, " "); + if (kex == NULL) { + error("kex_send_kexinit: no kex, cannot rekey"); + return; } - fprintf(stderr, "\n"); + if (kex->flags & KEX_INIT_SENT) { + debug("KEX_INIT_SENT"); + return; + } + kex->done = 0; + packet_start(SSH2_MSG_KEXINIT); + packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); + packet_send(); + debug("SSH2_MSG_KEXINIT sent"); + kex->flags |= KEX_INIT_SENT; } -unsigned char * -kex_hash( - char *client_version_string, - char *server_version_string, - char *ckexinit, int ckexinitlen, - char *skexinit, int skexinitlen, - char *serverhostkeyblob, int sbloblen, - BIGNUM *client_dh_pub, - BIGNUM *server_dh_pub, - BIGNUM *shared_secret) +void +kex_input_kexinit(int type, int plen, void *ctxt) { - Buffer b; - static unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; + char *ptr; + int dlen; + int i; + Kex *kex = (Kex *)ctxt; - 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 + debug("SSH2_MSG_KEXINIT received"); + if (kex == NULL) + fatal("kex_input_kexinit: no kex, cannot rekey"); - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + ptr = packet_get_raw(&dlen); + buffer_append(&kex->peer, ptr, dlen); - buffer_free(&b); + /* discard packet */ + for (i = 0; i < KEX_COOKIE_LEN; i++) + packet_get_char(); + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(packet_get_string(NULL)); + packet_get_char(); + packet_get_int(); + packet_done(); -#ifdef DEBUG_KEX - dump_digest(digest, evp_md->md_size); -#endif - return digest; + kex_kexinit_finish(kex); } -unsigned char * -kex_hash_gex( - char *client_version_string, - char *server_version_string, - char *ckexinit, int ckexinitlen, - char *skexinit, int skexinitlen, - char *serverhostkeyblob, int sbloblen, - int minbits, BIGNUM *prime, BIGNUM *gen, - BIGNUM *client_dh_pub, - BIGNUM *server_dh_pub, - BIGNUM *shared_secret) +Kex * +kex_setup(char *proposal[PROPOSAL_MAX]) { - Buffer b; - static unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; + Kex *kex; - buffer_init(&b); - buffer_put_string(&b, client_version_string, strlen(client_version_string)); - buffer_put_string(&b, server_version_string, strlen(server_version_string)); - - /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ - buffer_put_int(&b, ckexinitlen+1); - buffer_put_char(&b, SSH2_MSG_KEXINIT); - buffer_append(&b, ckexinit, ckexinitlen); - buffer_put_int(&b, skexinitlen+1); - buffer_put_char(&b, SSH2_MSG_KEXINIT); - buffer_append(&b, skexinit, skexinitlen); - - buffer_put_string(&b, serverhostkeyblob, sbloblen); - buffer_put_int(&b, minbits); - buffer_put_bignum2(&b, prime); - buffer_put_bignum2(&b, gen); - buffer_put_bignum2(&b, client_dh_pub); - buffer_put_bignum2(&b, server_dh_pub); - buffer_put_bignum2(&b, shared_secret); - -#ifdef DEBUG_KEX - buffer_dump(&b); -#endif + kex = xmalloc(sizeof(*kex)); + memset(kex, 0, sizeof(*kex)); + buffer_init(&kex->peer); + buffer_init(&kex->my); + kex_prop2buf(&kex->my, proposal); + kex->done = 0; - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); - - buffer_free(&b); + kex_send_kexinit(kex); /* we start */ + kex_clear_dispatch(); + dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); -#ifdef DEBUG_KEX - dump_digest(digest, evp_md->md_size); -#endif - return digest; + return kex; } -unsigned char * -derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) +void +kex_kexinit_finish(Kex *kex) { - Buffer b; - EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; - char c = id; - int have; - int mdsz = evp_md->md_size; - unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); - - 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); + if (!(kex->flags & KEX_INIT_SENT)) + kex_send_kexinit(kex); + + kex_choose_conf(kex); + + switch(kex->kex_type) { + case DH_GRP1_SHA1: + kexdh(kex); + break; + case DH_GEX_SHA1: + kexgex(kex); + break; + default: + fatal("Unsupported key exchange %d", kex->kex_type); } - 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 "," - -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; -} void choose_enc(Enc *enc, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); enc->cipher = cipher_by_name(name); @@ -405,28 +247,22 @@ choose_enc(Enc *enc, char *client, char *server) void choose_mac(Mac *mac, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching mac found: client %s server %s", client, server); - if (strcmp(name, "hmac-md5") == 0) { - mac->md = EVP_md5(); - } else if (strcmp(name, "hmac-sha1") == 0) { - mac->md = EVP_sha1(); - } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { - mac->md = EVP_ripemd160(); - } else { + if (mac_init(mac, name) < 0) fatal("unsupported mac %s", name); - } + /* truncate the key */ + if (datafellows & SSH_BUG_HMAC) + mac->key_len = 16; mac->name = name; - mac->mac_len = mac->md->md_size; - mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; mac->key = NULL; mac->enabled = 0; } void choose_comp(Comp *comp, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching comp found: client %s server %s", client, server); if (strcmp(name, "zlib") == 0) { @@ -441,7 +277,7 @@ choose_comp(Comp *comp, char *client, char *server) void choose_kex(Kex *k, char *client, char *server) { - k->name = get_match(client, server); + k->name = match_list(client, server, NULL); if (k->name == NULL) fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { @@ -454,73 +290,164 @@ choose_kex(Kex *k, char *client, char *server) void choose_hostkeyalg(Kex *k, char *client, char *server) { - k->hostkeyalg = get_match(client, server); - if (k->hostkeyalg == NULL) + char *hostkeyalg = match_list(client, server, NULL); + if (hostkeyalg == NULL) fatal("no hostkey alg"); - if (strcmp(k->hostkeyalg, KEX_DSS) != 0) - fatal("bad hostkey alg %s", k->hostkeyalg); + k->hostkey_type = key_type_from_name(hostkeyalg); + if (k->hostkey_type == KEY_UNSPEC) + fatal("bad hostkey alg '%s'", hostkeyalg); + xfree(hostkeyalg); } -Kex * -kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) +void +kex_choose_conf(Kex *kex) { + Newkeys *newkeys; + char **my, **peer; + char **cprop, **sprop; + int nenc, nmac, ncomp; int mode; int ctos; /* direction: if true client-to-server */ int need; - Kex *k; - k = xmalloc(sizeof(*k)); - memset(k, 0, sizeof(*k)); - k->server = server; + my = kex_buf2prop(&kex->my); + peer = kex_buf2prop(&kex->peer); + if (kex->server) { + cprop=peer; + sprop=my; + } else { + cprop=my; + sprop=peer; + } + + /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { - int nenc, nmac, ncomp; - ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); + newkeys = xmalloc(sizeof(*newkeys)); + memset(newkeys, 0, sizeof(*newkeys)); + kex->newkeys[mode] = newkeys; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; - choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); - choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); - choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); + choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); + choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); + choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", - k->enc[mode].name, - k->mac[mode].name, - k->comp[mode].name); + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); } - choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { - if (need < k->enc[mode].cipher->key_len) - need = k->enc[mode].cipher->key_len; - if (need < k->enc[mode].cipher->block_size) - need = k->enc[mode].cipher->block_size; - if (need < k->mac[mode].key_len) - need = k->mac[mode].key_len; + newkeys = kex->newkeys[mode]; + if (need < newkeys->enc.cipher->key_len) + need = newkeys->enc.cipher->key_len; + if (need < newkeys->enc.cipher->block_size) + need = newkeys->enc.cipher->block_size; + if (need < newkeys->mac.key_len) + need = newkeys->mac.key_len; } /* XXX need runden? */ - k->we_need = need; - return k; + kex->we_need = need; + + kex_prop_free(my); + kex_prop_free(peer); } -int -kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) +u_char * +derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) { - int i; - int mode; - int ctos; - unsigned char *keys[NKEYS]; + Buffer b; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + char c = id; + int have; + int mdsz = evp_md->md_size; + u_char *digest = xmalloc(roundup(need, mdsz)); + + buffer_init(&b); + buffer_put_bignum2(&b, shared_secret); + + /* K1 = HASH(K || H || "A" || session_id) */ + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, &c, 1); + EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); + EVP_DigestFinal(&md, digest, NULL); + + /* + * expand key: + * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) + * Key = K1 || K2 || ... || Kn + */ + for (have = mdsz; need > have; have += mdsz) { + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, digest, have); + EVP_DigestFinal(&md, digest + have, NULL); + } + buffer_free(&b); +#ifdef DEBUG_KEX + fprintf(stderr, "key '%c'== ", c); + dump_digest("key", digest, need); +#endif + return digest; +} + +Newkeys *current_keys[MODE_MAX]; + +#define NKEYS 6 +void +kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) +{ + u_char *keys[NKEYS]; + int i, mode, ctos; for (i = 0; i < NKEYS; i++) - keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); + keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); + debug("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { - ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); - k->enc[mode].iv = keys[ctos ? 0 : 1]; - k->enc[mode].key = keys[ctos ? 2 : 3]; - k->mac[mode].key = keys[ctos ? 4 : 5]; + current_keys[mode] = kex->newkeys[mode]; + kex->newkeys[mode] = NULL; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; + current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; + current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; } - return 0; } + +Newkeys * +kex_get_newkeys(int mode) +{ + Newkeys *ret; + + ret = current_keys[mode]; + current_keys[mode] = NULL; + return ret; +} + +#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) +void +dump_digest(char *msg, u_char *digest, int len) +{ + int i; + + fprintf(stderr, "%s\n", msg); + for (i = 0; i< len; i++){ + fprintf(stderr, "%02x", digest[i]); + if (i%32 == 31) + fprintf(stderr, "\n"); + else if (i%8 == 7) + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); +} +#endif diff --git a/crypto/openssh/kex.h b/crypto/openssh/kex.h index 2129581..8758804 100644 --- a/crypto/openssh/kex.h +++ b/crypto/openssh/kex.h @@ -1,3 +1,5 @@ +/* $OpenBSD: kex.h,v 1.22 2001/04/04 20:25:37 markus Exp $ */ + /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -24,9 +26,13 @@ #ifndef KEX_H #define KEX_H +#include <openssl/evp.h> +#include "buffer.h" +#include "cipher.h" +#include "key.h" + #define KEX_DH1 "diffie-hellman-group1-sha1" #define KEX_DHGEX "diffie-hellman-group-exchange-sha1" -#define KEX_DSS "ssh-dss" enum kex_init_proposals { PROPOSAL_KEX_ALGS, @@ -52,78 +58,73 @@ enum kex_exchange { DH_GRP1_SHA1, DH_GEX_SHA1 }; - + +#define KEX_INIT_SENT 0x0001 + typedef struct Kex Kex; typedef struct Mac Mac; typedef struct Comp Comp; typedef struct Enc Enc; +typedef struct Newkeys Newkeys; struct Enc { - char *name; - Cipher *cipher; - int enabled; - unsigned char *key; - unsigned char *iv; + char *name; + Cipher *cipher; + int enabled; + u_char *key; + u_char *iv; }; struct Mac { - char *name; - int enabled; - EVP_MD *md; - int mac_len; - unsigned char *key; - int key_len; + char *name; + int enabled; + EVP_MD *md; + int mac_len; + u_char *key; + int key_len; }; struct Comp { - int type; - int enabled; - char *name; + int type; + int enabled; + char *name; +}; +struct Newkeys { + Enc enc; + Mac mac; + Comp comp; }; struct Kex { - Enc enc [MODE_MAX]; - Mac mac [MODE_MAX]; - Comp comp[MODE_MAX]; - int we_need; - int server; - char *name; - char *hostkeyalg; - int kex_type; + u_char *session_id; + int session_id_len; + Newkeys *newkeys[MODE_MAX]; + int we_need; + int server; + char *name; + int hostkey_type; + int kex_type; + Buffer my; + Buffer peer; + int done; + int flags; + char *client_version_string; + char *server_version_string; + int (*check_host_key)(Key *hostkey); + Key *(*load_host_key)(int type); }; -Buffer *kex_init(char *myproposal[PROPOSAL_MAX]); -void -kex_exchange_kexinit( - Buffer *my_kexinit, Buffer *peer_kexint, - char *peer_proposal[PROPOSAL_MAX]); -Kex * -kex_choose_conf(char *cprop[PROPOSAL_MAX], - char *sprop[PROPOSAL_MAX], int server); -int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret); -void packet_set_kex(Kex *k); -int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub); -DH *dh_new_group_asc(const char *, const char *); -DH *dh_new_group(BIGNUM *, BIGNUM *); -DH *dh_new_group1(); +Kex *kex_setup(char *proposal[PROPOSAL_MAX]); +void kex_finish(Kex *kex); -unsigned char * -kex_hash( - char *client_version_string, - char *server_version_string, - char *ckexinit, int ckexinitlen, - char *skexinit, int skexinitlen, - char *serverhostkeyblob, int sbloblen, - BIGNUM *client_dh_pub, - BIGNUM *server_dh_pub, - BIGNUM *shared_secret); +void kex_send_kexinit(Kex *kex); +void kex_input_kexinit(int type, int plen, void *ctxt); +void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret); + +void kexdh(Kex *); +void kexgex(Kex *); + +Newkeys *kex_get_newkeys(int mode); + +#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) +void dump_digest(char *msg, u_char *digest, int len); +#endif -unsigned char * -kex_hash_gex( - char *client_version_string, - char *server_version_string, - char *ckexinit, int ckexinitlen, - char *skexinit, int skexinitlen, - char *serverhostkeyblob, int sbloblen, - int minbits, BIGNUM *prime, BIGNUM *gen, - BIGNUM *client_dh_pub, - BIGNUM *server_dh_pub, - BIGNUM *shared_secret); #endif diff --git a/crypto/openssh/kexdh.c b/crypto/openssh/kexdh.c new file mode 100644 index 0000000..7b6a220 --- /dev/null +++ b/crypto/openssh/kexdh.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $"); + +#include <openssl/crypto.h> +#include <openssl/bn.h> + +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" + +u_char * +kex_dh_hash( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static u_char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest("hash", digest, evp_md->md_size); +#endif + return digest; +} + +/* client */ + +void +kexdh_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + DH *dh; + Key *server_host_key; + char *server_host_key_blob = NULL, *signature = NULL; + u_char *kbuf, *hash; + u_int klen, kout, slen, sbloblen; + int dlen, plen; + + /* generate and send 'e', client DH public key */ + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); + packet_start(SSH2_MSG_KEXDH_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("sending SSH2_MSG_KEXDH_INIT"); +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("expecting SSH2_MSG_KEXDH_REPLY"); + packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + + if (kex->check_host_key == NULL) + fatal("cannot check server_host_key"); + kex->check_host_key(server_host_key); + + /* DH paramter f, server public DH key */ + dh_server_pub = BN_new(); + if (dh_server_pub == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_done(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + shared_secret = BN_new(); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + /* calc and verify H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + dh->pub_key, + dh_server_pub, + shared_secret + ); + xfree(server_host_key_blob); + BN_free(dh_server_pub); + DH_free(dh); + + if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} + +/* server */ + +void +kexdh_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + DH *dh; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout; + int dlen, slen, plen; + + /* generate server DH public key */ + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEXDH_INIT"); + packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT); + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + /* key, cert */ + dh_client_pub = BN_new(); + if (dh_client_pub == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + shared_secret = BN_new(); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + /* calc H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + (char *)server_host_key_blob, sbloblen, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + key_sign(server_host_key, &signature, &slen, hash, 20); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + packet_start(SSH2_MSG_KEXDH_REPLY); + packet_put_string((char *)server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string((char *)signature, slen); + packet_send(); + + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} + +void +kexdh(Kex *kex) +{ + if (kex->server) + kexdh_server(kex); + else + kexdh_client(kex); +} diff --git a/crypto/openssh/kexgex.c b/crypto/openssh/kexgex.c new file mode 100644 index 0000000..44f2f5c --- /dev/null +++ b/crypto/openssh/kexgex.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $"); + +#include <openssl/bn.h> + +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "compat.h" + +u_char * +kexgex_hash( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + char *serverhostkeyblob, int sbloblen, + int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static u_char digest[EVP_MAX_MD_SIZE]; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_string(&b, client_version_string, strlen(client_version_string)); + buffer_put_string(&b, server_version_string, strlen(server_version_string)); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + if (min == -1 || max == -1) + buffer_put_int(&b, wantbits); + else { + buffer_put_int(&b, min); + buffer_put_int(&b, wantbits); + buffer_put_int(&b, max); + } + buffer_put_bignum2(&b, prime); + buffer_put_bignum2(&b, gen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEXDH + buffer_dump(&b); +#endif + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEXDH + dump_digest("hash", digest, evp_md->md_size); +#endif + return digest; +} + +/* client */ + +void +kexgex_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + BIGNUM *p = NULL, *g = NULL; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int klen, kout, slen, sbloblen; + int dlen, plen, min, max, nbits; + DH *dh; + + nbits = dh_estimate(kex->we_need * 8); + + if (datafellows & SSH_OLD_DHGEX) { + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent"); + + /* Old GEX request */ + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + packet_put_int(nbits); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + } else { + debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent"); + + /* New GEX request */ + min = DH_GRP_MIN; + max = DH_GRP_MAX; + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); + packet_put_int(min); + packet_put_int(nbits); + packet_put_int(max); + } +#ifdef DEBUG_KEXDH + fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", + min, nbits, max); +#endif + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); + + if ((p = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(p, &dlen); + if ((g = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(g, &dlen); + packet_done(); + + if (BN_num_bits(p) < min || BN_num_bits(p) > max) + fatal("DH_GEX group out of range: %d !< %d !< %d", + min, BN_num_bits(p), max); + + dh = dh_new_group(g, p); + dh_gen_key(dh, kex->we_need * 8); + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); + /* generate and send 'e', client DH public key */ + packet_start(SSH2_MSG_KEX_DH_GEX_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + + if (kex->check_host_key == NULL) + fatal("cannot check server_host_key"); + kex->check_host_key(server_host_key); + + /* DH paramter f, server public DH key */ + dh_server_pub = BN_new(); + if (dh_server_pub == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_done(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + shared_secret = BN_new(); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + if (datafellows & SSH_OLD_DHGEX) + min = max = -1; + + /* calc and verify H */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret + ); + /* have keys, free DH */ + DH_free(dh); + xfree(server_host_key_blob); + BN_free(dh_server_pub); + + if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} + +/* server */ + +void +kexgex_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + Key *server_host_key; + DH *dh = dh; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout; + int min = -1, max = -1, nbits = -1, type, plen, dlen, slen; + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + type = packet_read(&plen); + switch(type){ + case SSH2_MSG_KEX_DH_GEX_REQUEST: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); + min = packet_get_int(); + nbits = packet_get_int(); + max = packet_get_int(); + min = MAX(DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); + nbits = packet_get_int(); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + /* unused for old GEX */ + break; + default: + fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); + } + packet_done(); + + if (max < min || nbits < min || max < nbits) + fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", + min, nbits, max); + + dh = choose_dh(min, nbits, max); + if (dh == NULL) + packet_disconnect("Protocol error: no matching DH grp found"); + + debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); + packet_put_bignum2(dh->p); + packet_put_bignum2(dh->g); + packet_send(); + + /* flush */ + packet_write_wait(); + + /* Compute our exchange value in parallel with the client */ + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); + packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT); + + /* key, cert */ + dh_client_pub = BN_new(); + if (dh_client_pub == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub, &dlen); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + shared_secret = BN_new(); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) + min = max = -1; + + /* calc H */ /* XXX depends on 'kex' */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + (char *)server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + key_sign(server_host_key, &signature, &slen, hash, 20); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); + packet_put_string((char *)server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string((char *)signature, slen); + packet_send(); + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} + +void +kexgex(Kex *kex) +{ + if (kex->server) + kexgex_server(kex); + else + kexgex_client(kex); +} diff --git a/crypto/openssh/key.h b/crypto/openssh/key.h index 8e1e0a9..cee31c3 100644 --- a/crypto/openssh/key.h +++ b/crypto/openssh/key.h @@ -1,3 +1,5 @@ +/* $OpenBSD: key.h,v 1.12 2001/04/17 10:53:24 markus Exp $ */ + /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -24,11 +26,23 @@ #ifndef KEY_H #define KEY_H +#include <openssl/rsa.h> +#include <openssl/dsa.h> + typedef struct Key Key; enum types { + KEY_RSA1, KEY_RSA, KEY_DSA, - KEY_EMPTY + KEY_UNSPEC +}; +enum fp_type { + SSH_FP_SHA1, + SSH_FP_MD5 +}; +enum fp_rep { + SSH_FP_HEX, + SSH_FP_BUBBLEBABBLE }; struct Key { int type; @@ -37,12 +51,34 @@ struct Key { }; Key *key_new(int type); +Key *key_new_private(int type); void key_free(Key *k); int key_equal(Key *a, Key *b); -char *key_fingerprint(Key *k); +char *key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep); char *key_type(Key *k); int key_write(Key *key, FILE *f); -unsigned int key_read(Key *key, char **cpp); -unsigned int key_size(Key *k); +int key_read(Key *key, char **cpp); +u_int key_size(Key *k); + +Key *key_generate(int type, u_int bits); +Key *key_from_private(Key *k); +int key_type_from_name(char *name); + +Key *key_from_blob(char *blob, int blen); +int key_to_blob(Key *key, u_char **blobp, u_int *lenp); +char *key_ssh_name(Key *k); +int key_names_valid2(const char *names); + +int +key_sign( + Key *key, + u_char **sigp, int *lenp, + u_char *data, int datalen); + +int +key_verify( + Key *key, + u_char *signature, int signaturelen, + u_char *data, int datalen); #endif diff --git a/crypto/openssh/lib/Makefile b/crypto/openssh/lib/Makefile index 396186b..fbcd66f 100644 --- a/crypto/openssh/lib/Makefile +++ b/crypto/openssh/lib/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.22 2001/04/03 19:53:30 markus Exp $ + .PATH: ${.CURDIR}/.. LIB= ssh @@ -5,8 +7,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \ cipher.c compat.c compress.c crc32.c deattack.c \ hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \ rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \ - key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c \ - cli.c rijndael.c + key.c dispatch.c kex.c mac.c uuencode.c misc.c \ + cli.c rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c NOPROFILE= yes NOPIC= yes diff --git a/crypto/openssh/log.c b/crypto/openssh/log.c index ce89c59..34b4eb9 100644 --- a/crypto/openssh/log.c +++ b/crypto/openssh/log.c @@ -10,8 +10,6 @@ * called by a name other than "ssh" or "Secure Shell". */ /* - * Shared versions of debug(), log(), etc. - * * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,11 +34,78 @@ */ #include "includes.h" -RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $"); +RCSID("$OpenBSD: log.c,v 1.17 2001/03/04 17:42:28 millert Exp $"); -#include "ssh.h" +#include "log.h" #include "xmalloc.h" +#include <syslog.h> + +static LogLevel log_level = SYSLOG_LEVEL_INFO; +static int log_on_stderr = 1; +static int log_facility = LOG_AUTH; +static char *argv0; + +extern char *__progname; + +/* textual representation of log-facilities/levels */ + +static struct { + const char *name; + SyslogFacility val; +} log_facilities[] = { + { "DAEMON", SYSLOG_FACILITY_DAEMON }, + { "USER", SYSLOG_FACILITY_USER }, + { "AUTH", SYSLOG_FACILITY_AUTH }, + { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, + { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, + { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, + { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, + { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, + { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, + { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, + { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, + { NULL, 0 } +}; + +static struct { + const char *name; + LogLevel val; +} log_levels[] = +{ + { "QUIET", SYSLOG_LEVEL_QUIET }, + { "FATAL", SYSLOG_LEVEL_FATAL }, + { "ERROR", SYSLOG_LEVEL_ERROR }, + { "INFO", SYSLOG_LEVEL_INFO }, + { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, + { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, + { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, + { NULL, 0 } +}; + +SyslogFacility +log_facility_number(char *name) +{ + int i; + if (name != NULL) + for (i = 0; log_facilities[i].name; i++) + if (strcasecmp(log_facilities[i].name, name) == 0) + return log_facilities[i].val; + return (SyslogFacility) - 1; +} + +LogLevel +log_level_number(char *name) +{ + int i; + if (name != NULL) + for (i = 0; log_levels[i].name; i++) + if (strcasecmp(log_levels[i].name, name) == 0) + return log_levels[i].val; + return (LogLevel) - 1; +} /* Fatal messages. This function never returns. */ void @@ -154,8 +219,8 @@ fatal_remove_cleanup(void (*proc) (void *context), void *context) return; } } - fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n", - (unsigned long) proc, (unsigned long) context); + fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", + (u_long) proc, (u_long) context); } /* Cleanup and exit */ @@ -172,67 +237,143 @@ fatal_cleanup(void) for (cu = fatal_cleanups; cu; cu = next_cu) { next_cu = cu->next; debug("Calling cleanup 0x%lx(0x%lx)", - (unsigned long) cu->proc, (unsigned long) cu->context); + (u_long) cu->proc, (u_long) cu->context); (*cu->proc) (cu->context); } exit(255); } -/* textual representation of log-facilities/levels */ -static struct { - const char *name; - SyslogFacility val; -} log_facilities[] = { - { "DAEMON", SYSLOG_FACILITY_DAEMON }, - { "USER", SYSLOG_FACILITY_USER }, - { "AUTH", SYSLOG_FACILITY_AUTH }, - { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, - { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, - { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, - { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, - { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, - { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, - { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, - { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, - { NULL, 0 } -}; +/* + * Initialize the log. + */ -static struct { - const char *name; - LogLevel val; -} log_levels[] = +void +log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) { - { "QUIET", SYSLOG_LEVEL_QUIET }, - { "FATAL", SYSLOG_LEVEL_FATAL }, - { "ERROR", SYSLOG_LEVEL_ERROR }, - { "INFO", SYSLOG_LEVEL_INFO }, - { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, - { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, - { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, - { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, - { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, - { NULL, 0 } -}; + argv0 = av0; -SyslogFacility -log_facility_number(char *name) -{ - int i; - if (name != NULL) - for (i = 0; log_facilities[i].name; i++) - if (strcasecmp(log_facilities[i].name, name) == 0) - return log_facilities[i].val; - return (SyslogFacility) - 1; + switch (level) { + case SYSLOG_LEVEL_QUIET: + case SYSLOG_LEVEL_FATAL: + case SYSLOG_LEVEL_ERROR: + case SYSLOG_LEVEL_INFO: + case SYSLOG_LEVEL_VERBOSE: + case SYSLOG_LEVEL_DEBUG1: + case SYSLOG_LEVEL_DEBUG2: + case SYSLOG_LEVEL_DEBUG3: + log_level = level; + break; + default: + fprintf(stderr, "Unrecognized internal syslog level code %d\n", + (int) level); + exit(1); + } + + log_on_stderr = on_stderr; + if (on_stderr) + return; + + switch (facility) { + case SYSLOG_FACILITY_DAEMON: + log_facility = LOG_DAEMON; + break; + case SYSLOG_FACILITY_USER: + log_facility = LOG_USER; + break; + case SYSLOG_FACILITY_AUTH: + log_facility = LOG_AUTH; + break; + case SYSLOG_FACILITY_LOCAL0: + log_facility = LOG_LOCAL0; + break; + case SYSLOG_FACILITY_LOCAL1: + log_facility = LOG_LOCAL1; + break; + case SYSLOG_FACILITY_LOCAL2: + log_facility = LOG_LOCAL2; + break; + case SYSLOG_FACILITY_LOCAL3: + log_facility = LOG_LOCAL3; + break; + case SYSLOG_FACILITY_LOCAL4: + log_facility = LOG_LOCAL4; + break; + case SYSLOG_FACILITY_LOCAL5: + log_facility = LOG_LOCAL5; + break; + case SYSLOG_FACILITY_LOCAL6: + log_facility = LOG_LOCAL6; + break; + case SYSLOG_FACILITY_LOCAL7: + log_facility = LOG_LOCAL7; + break; + default: + fprintf(stderr, + "Unrecognized internal syslog facility code %d\n", + (int) facility); + exit(1); + } } -LogLevel -log_level_number(char *name) +#define MSGBUFSIZ 1024 + +void +do_log(LogLevel level, const char *fmt, va_list args) { - int i; - if (name != NULL) - for (i = 0; log_levels[i].name; i++) - if (strcasecmp(log_levels[i].name, name) == 0) - return log_levels[i].val; - return (LogLevel) - 1; + char msgbuf[MSGBUFSIZ]; + char fmtbuf[MSGBUFSIZ]; + char *txt = NULL; + int pri = LOG_INFO; + + if (level > log_level) + return; + + switch (level) { + case SYSLOG_LEVEL_FATAL: + if (!log_on_stderr) + txt = "fatal"; + pri = LOG_CRIT; + break; + case SYSLOG_LEVEL_ERROR: + if (!log_on_stderr) + txt = "error"; + pri = LOG_ERR; + break; + case SYSLOG_LEVEL_INFO: + pri = LOG_INFO; + break; + case SYSLOG_LEVEL_VERBOSE: + pri = LOG_INFO; + break; + case SYSLOG_LEVEL_DEBUG1: + txt = "debug1"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG2: + txt = "debug2"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG3: + txt = "debug3"; + pri = LOG_DEBUG; + break; + default: + txt = "internal error"; + pri = LOG_ERR; + break; + } + if (txt != NULL) { + snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); + } else { + vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + } + if (log_on_stderr) { + fprintf(stderr, "%s\r\n", msgbuf); + } else { + openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); + syslog(pri, "%.500s", msgbuf); + closelog(); + } } diff --git a/crypto/openssh/log.h b/crypto/openssh/log.h new file mode 100644 index 0000000..ad9fa3f --- /dev/null +++ b/crypto/openssh/log.h @@ -0,0 +1,75 @@ +/* $OpenBSD: log.h,v 1.2 2001/01/29 01:58:16 niklas Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#ifndef SSH_LOG_H +#define SSH_LOG_H + +/* Supported syslog facilities and levels. */ +typedef enum { + SYSLOG_FACILITY_DAEMON, + SYSLOG_FACILITY_USER, + SYSLOG_FACILITY_AUTH, + SYSLOG_FACILITY_LOCAL0, + SYSLOG_FACILITY_LOCAL1, + SYSLOG_FACILITY_LOCAL2, + SYSLOG_FACILITY_LOCAL3, + SYSLOG_FACILITY_LOCAL4, + SYSLOG_FACILITY_LOCAL5, + SYSLOG_FACILITY_LOCAL6, + SYSLOG_FACILITY_LOCAL7 +} SyslogFacility; + +typedef enum { + SYSLOG_LEVEL_QUIET, + SYSLOG_LEVEL_FATAL, + SYSLOG_LEVEL_ERROR, + SYSLOG_LEVEL_INFO, + SYSLOG_LEVEL_VERBOSE, + SYSLOG_LEVEL_DEBUG1, + SYSLOG_LEVEL_DEBUG2, + SYSLOG_LEVEL_DEBUG3 +} LogLevel; +/* Initializes logging. */ +void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr); + +/* Logging implementation, depending on server or client */ +void do_log(LogLevel level, const char *fmt, va_list args); + +/* name to facility/level */ +SyslogFacility log_facility_number(char *name); +LogLevel log_level_number(char *name); + +/* Output a message to syslog or stderr */ +void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void error(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void log(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2))); + +/* same as fatal() but w/o logging */ +void fatal_cleanup(void); + +/* + * Registers a cleanup function to be called by fatal()/fatal_cleanup() + * before exiting. It is permissible to call fatal_remove_cleanup for the + * function itself from the function. + */ +void fatal_add_cleanup(void (*proc) (void *context), void *context); + +/* Removes a cleanup function to be called at fatal(). */ +void fatal_remove_cleanup(void (*proc) (void *context), void *context); + +#endif diff --git a/crypto/openssh/mac.c b/crypto/openssh/mac.c new file mode 100644 index 0000000..e8b4267 --- /dev/null +++ b/crypto/openssh/mac.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $"); + +#include <openssl/hmac.h> + +#include "xmalloc.h" +#include "getput.h" +#include "log.h" +#include "cipher.h" +#include "kex.h" +#include "mac.h" + +struct { + char *name; + EVP_MD * (*mdfunc)(void); + int truncatebits; /* truncate digest if != 0 */ +} macs[] = { + { "hmac-sha1", EVP_sha1, 0, }, + { "hmac-sha1-96", EVP_sha1, 96 }, + { "hmac-md5", EVP_md5, 0 }, + { "hmac-md5-96", EVP_md5, 96 }, + { "hmac-ripemd160", EVP_ripemd160, 0 }, + { "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 }, + { NULL, NULL, 0 } +}; + +int +mac_init(Mac *mac, char *name) +{ + int i; + for (i = 0; macs[i].name; i++) { + if (strcmp(name, macs[i].name) == 0) { + if (mac != NULL) { + mac->md = (*macs[i].mdfunc)(); + mac->key_len = mac->mac_len = mac->md->md_size; + if (macs[i].truncatebits != 0) + mac->mac_len = macs[i].truncatebits/8; + } + debug2("mac_init: found %s", name); + return (0); + } + } + debug2("mac_init: unknown %s", name); + return (-1); +} + +u_char * +mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) +{ + HMAC_CTX c; + static u_char m[EVP_MAX_MD_SIZE]; + u_char b[4]; + + if (mac->key == NULL) + fatal("mac_compute: no key"); + if (mac->mac_len > sizeof(m)) + fatal("mac_compute: mac too long"); + HMAC_Init(&c, mac->key, mac->key_len, mac->md); + PUT_32BIT(b, seqno); + HMAC_Update(&c, b, sizeof(b)); + HMAC_Update(&c, data, datalen); + HMAC_Final(&c, m, NULL); + HMAC_cleanup(&c); + return (m); +} + +/* XXX copied from ciphers_valid */ +#define MAC_SEP "," +int +mac_valid(const char *names) +{ + char *maclist, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) + return (0); + maclist = cp = xstrdup(names); + for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; + (p = strsep(&cp, MAC_SEP))) { + if (mac_init(NULL, p) < 0) { + debug("bad mac %s [%s]", p, names); + xfree(maclist); + return (0); + } else { + debug3("mac ok: %s [%s]", p, names); + } + } + debug3("macs ok: [%s]", names); + xfree(maclist); + return (1); +} diff --git a/crypto/openssh/mac.h b/crypto/openssh/mac.h new file mode 100644 index 0000000..6173eaa --- /dev/null +++ b/crypto/openssh/mac.h @@ -0,0 +1,28 @@ +/* $OpenBSD: mac.h,v 1.1 2001/02/11 12:59:24 markus Exp $ */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int mac_valid(const char *names); +int mac_init(Mac *mac, char *name); +u_char *mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen); diff --git a/crypto/openssh/match.c b/crypto/openssh/match.c index c373129..ebb562a 100644 --- a/crypto/openssh/match.c +++ b/crypto/openssh/match.c @@ -10,11 +10,35 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include "includes.h" -RCSID("$OpenBSD: match.c,v 1.9 2000/09/07 20:27:52 deraadt Exp $"); +RCSID("$OpenBSD: match.c,v 1.12 2001/03/10 17:51:04 markus Exp $"); -#include "ssh.h" +#include "match.h" +#include "xmalloc.h" /* * Returns true if the given string matches the pattern (which may contain ? @@ -87,12 +111,12 @@ match_pattern(const char *s, const char *pattern) */ int -match_hostname(const char *host, const char *pattern, unsigned int len) +match_hostname(const char *host, const char *pattern, u_int len) { char sub[1024]; int negated; int got_positive; - unsigned int i, subi; + u_int i, subi; got_positive = 0; for (i = 0; i < len;) { @@ -137,3 +161,46 @@ match_hostname(const char *host, const char *pattern, unsigned int len) */ return got_positive; } + + +#define MAX_PROP 20 +#define SEP "," +char * +match_list(const char *client, const char *server, u_int *next) +{ + char *sproposals[MAX_PROP]; + char *c, *s, *p, *ret, *cp, *sp; + int i, j, nproposals; + + c = cp = xstrdup(client); + s = sp = xstrdup(server); + + for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&sp, SEP)), i++) { + if (i < MAX_PROP) + sproposals[i] = p; + else + break; + } + nproposals = i; + + for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&cp, SEP)), i++) { + for (j = 0; j < nproposals; j++) { + if (strcmp(p, sproposals[j]) == 0) { + ret = xstrdup(p); + if (next != NULL) + *next = (cp == NULL) ? + strlen(c) : cp - c; + xfree(c); + xfree(s); + return ret; + } + } + } + if (next != NULL) + *next = strlen(c); + xfree(c); + xfree(s); + return NULL; +} diff --git a/crypto/openssh/match.h b/crypto/openssh/match.h index 564f5ab..09c9311 100644 --- a/crypto/openssh/match.h +++ b/crypto/openssh/match.h @@ -1,3 +1,5 @@ +/* $OpenBSD: match.h,v 1.7 2001/03/10 17:51:04 markus Exp $ */ + /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -26,6 +28,12 @@ int match_pattern(const char *s, const char *pattern); * indicate negation). Returns -1 if negation matches, 1 if there is * a positive match, 0 if there is no match at all. */ -int match_hostname(const char *host, const char *pattern, unsigned int len); +int match_hostname(const char *host, const char *pattern, u_int len); + +/* + * Returns first item from client-list that is also supported by server-list, + * caller must xfree() returned string. + */ +char *match_list(const char *client, const char *server, u_int *next); #endif diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c new file mode 100644 index 0000000..b5c0fd1 --- /dev/null +++ b/crypto/openssh/misc.c @@ -0,0 +1,130 @@ +/* $OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $"); + +#include "misc.h" +#include "log.h" +#include "xmalloc.h" + +char * +chop(char *s) +{ + char *t = s; + while (*t) { + if(*t == '\n' || *t == '\r') { + *t = '\0'; + return s; + } + t++; + } + return s; + +} + +void +set_nonblock(int fd) +{ + int val; + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); + return; + } + if (val & O_NONBLOCK) { + debug("fd %d IS O_NONBLOCK", fd); + return; + } + debug("fd %d setting O_NONBLOCK", fd); + val |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, val) == -1) + if (errno != ENODEV) + error("fcntl(%d, F_SETFL, O_NONBLOCK): %s", + fd, strerror(errno)); +} + +/* Characters considered whitespace in strsep calls. */ +#define WHITESPACE " \t\r\n" + +char * +strdelim(char **s) +{ + char *old; + int wspace = 0; + + if (*s == NULL) + return NULL; + + old = *s; + + *s = strpbrk(*s, WHITESPACE "="); + if (*s == NULL) + return (old); + + /* Allow only one '=' to be skipped */ + if (*s[0] == '=') + wspace = 1; + *s[0] = '\0'; + + *s += strspn(*s + 1, WHITESPACE) + 1; + if (*s[0] == '=' && !wspace) + *s += strspn(*s + 1, WHITESPACE) + 1; + + return (old); +} + +struct passwd * +pwcopy(struct passwd *pw) +{ + struct passwd *copy = xmalloc(sizeof(*copy)); + + memset(copy, 0, sizeof(*copy)); + copy->pw_name = xstrdup(pw->pw_name); + copy->pw_passwd = xstrdup(pw->pw_passwd); + copy->pw_gecos = xstrdup(pw->pw_gecos); + copy->pw_uid = pw->pw_uid; + copy->pw_gid = pw->pw_gid; + copy->pw_class = xstrdup(pw->pw_class); + copy->pw_dir = xstrdup(pw->pw_dir); + copy->pw_shell = xstrdup(pw->pw_shell); + return copy; +} + +int a2port(const char *s) +{ + long port; + char *endp; + + errno = 0; + port = strtol(s, &endp, 0); + if (s == endp || *endp != '\0' || + (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || + port <= 0 || port > 65535) + return 0; + + return port; +} diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h new file mode 100644 index 0000000..9cd4ac1 --- /dev/null +++ b/crypto/openssh/misc.h @@ -0,0 +1,30 @@ +/* $OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* remove newline at end of string */ +char *chop(char *s); + +/* return next token in configuration line */ +char *strdelim(char **s); + +/* set filedescriptor to non-blocking */ +void set_nonblock(int fd); + +struct passwd * pwcopy(struct passwd *pw); + +/* + * Convert ASCII string to TCP/IP port number. + * Port must be >0 and <=65535. + * Return 0 if invalid. + */ +int a2port(const char *s); diff --git a/crypto/openssh/mpaux.h b/crypto/openssh/mpaux.h index 9de1727..b3f15e4 100644 --- a/crypto/openssh/mpaux.h +++ b/crypto/openssh/mpaux.h @@ -12,7 +12,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: mpaux.h,v 1.8 2000/09/07 20:27:52 deraadt Exp $"); */ +/* RCSID("$OpenBSD: mpaux.h,v 1.9 2000/12/19 23:17:57 markus Exp $"); */ #ifndef MPAUX_H #define MPAUX_H @@ -23,8 +23,8 @@ * representations of host_key_n, session_key_n, and the cookie. */ void -compute_session_id(unsigned char session_id[16], - unsigned char cookie[8], +compute_session_id(u_char session_id[16], + u_char cookie[8], BIGNUM * host_key_n, BIGNUM * session_key_n); diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index 98060dc..4a9a363 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,3 +1,5 @@ +/* $OpenBSD: myproposal.h,v 1.12 2001/03/05 15:56:16 deraadt Exp $ */ + /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -22,13 +24,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1" -#define KEX_DEFAULT_PK_ALG "ssh-dss" +#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ - "3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ - "aes128-cbc,aes192-cbc,aes256-cbc," \ + "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ + "aes192-cbc,aes256-cbc," \ "rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \ "rijndael-cbc@lysator.liu.se" -#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com" +#define KEX_DEFAULT_MAC \ + "hmac-md5,hmac-sha1,hmac-ripemd160," \ + "hmac-ripemd160@openssh.com," \ + "hmac-sha1-96,hmac-md5-96" #define KEX_DEFAULT_COMP "none,zlib" #define KEX_DEFAULT_LANG "" diff --git a/crypto/openssh/nchan.c b/crypto/openssh/nchan.c index 30c90b3..eb96501 100644 --- a/crypto/openssh/nchan.c +++ b/crypto/openssh/nchan.c @@ -23,17 +23,16 @@ */ #include "includes.h" -RCSID("$OpenBSD: nchan.c,v 1.19 2000/09/07 20:27:52 deraadt Exp $"); - -#include "ssh.h" +RCSID("$OpenBSD: nchan.c,v 1.23 2001/02/28 08:54:55 markus Exp $"); +#include "ssh1.h" +#include "ssh2.h" #include "buffer.h" #include "packet.h" #include "channels.h" #include "nchan.h" - -#include "ssh2.h" #include "compat.h" +#include "log.h" /* functions manipulating channel states */ /* @@ -55,9 +54,6 @@ static void chan_send_oclose1(Channel *c); static void chan_send_close2(Channel *c); static void chan_send_eof2(Channel *c); -/* channel cleanup */ -chan_event_fn *chan_delete_if_full_closed = NULL; - /* helper */ static void chan_shutdown_write(Channel *c); static void chan_shutdown_read(Channel *c); @@ -250,14 +246,6 @@ chan_send_oclose1(Channel *c) break; } } -static void -chan_delete_if_full_closed1(Channel *c) -{ - if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { - debug("channel %d: full closed", c->self); - channel_free(c->self); - } -} /* * the same for SSH2 @@ -400,22 +388,46 @@ chan_send_close2(Channel *c) c->flags |= CHAN_CLOSE_SENT; } } -static void -chan_delete_if_full_closed2(Channel *c) + +/* shared */ + +int +chan_is_dead(Channel *c) { - if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { + if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) + return 0; + if (!compat20) { + debug("channel %d: is dead", c->self); + return 1; + } + /* + * we have to delay the close message if the efd (for stderr) is + * still active + */ + if (((c->extended_usage != CHAN_EXTENDED_IGNORE) && + buffer_len(&c->extended) > 0) +#if 0 + || ((c->extended_usage == CHAN_EXTENDED_READ) && + c->efd != -1) +#endif + ) { + debug2("channel %d: active efd: %d len %d type %s", + c->self, c->efd, buffer_len(&c->extended), + c->extended_usage==CHAN_EXTENDED_READ ? + "read": "write"); + } else { if (!(c->flags & CHAN_CLOSE_SENT)) { chan_send_close2(c); } if ((c->flags & CHAN_CLOSE_SENT) && (c->flags & CHAN_CLOSE_RCVD)) { - debug("channel %d: full closed2", c->self); - channel_free(c->self); + debug("channel %d: is dead", c->self); + return 1; } } + return 0; } -/* shared */ void chan_init_iostates(Channel *c) { @@ -436,8 +448,6 @@ chan_init(void) chan_rcvd_ieof = chan_rcvd_ieof2; chan_write_failed = chan_write_failed2; chan_obuf_empty = chan_obuf_empty2; - - chan_delete_if_full_closed = chan_delete_if_full_closed2; } else { chan_rcvd_oclose = chan_rcvd_oclose1; chan_read_failed = chan_read_failed_12; @@ -446,8 +456,6 @@ chan_init(void) chan_rcvd_ieof = chan_rcvd_ieof1; chan_write_failed = chan_write_failed1; chan_obuf_empty = chan_obuf_empty1; - - chan_delete_if_full_closed = chan_delete_if_full_closed1; } } diff --git a/crypto/openssh/nchan.h b/crypto/openssh/nchan.h index 366b894..623eccc 100644 --- a/crypto/openssh/nchan.h +++ b/crypto/openssh/nchan.h @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$OpenBSD: nchan.h,v 1.9 2000/09/07 20:27:52 deraadt Exp $"); */ +/* RCSID("$OpenBSD: nchan.h,v 1.10 2001/02/28 08:54:55 markus Exp $"); */ #ifndef NCHAN_H #define NCHAN_H @@ -84,7 +84,7 @@ extern chan_event_fn *chan_rcvd_ieof; extern chan_event_fn *chan_write_failed; extern chan_event_fn *chan_obuf_empty; -extern chan_event_fn *chan_delete_if_full_closed; +int chan_is_dead(Channel * c); void chan_init_iostates(Channel * c); void chan_init(void); diff --git a/crypto/openssh/nchan.ms b/crypto/openssh/nchan.ms index 1679d39..2d08022 100644 --- a/crypto/openssh/nchan.ms +++ b/crypto/openssh/nchan.ms @@ -1,3 +1,5 @@ +.\" $OpenBSD: nchan.ms,v 1.7 2001/01/29 01:58:17 niklas Exp $ +.\" .\" .\" Copyright (c) 1999 Markus Friedl. All rights reserved. .\" diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index 3216fda..00109ea 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -37,13 +37,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $"); +RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $"); #include "xmalloc.h" #include "buffer.h" #include "packet.h" #include "bufaux.h" -#include "ssh.h" #include "crc32.h" #include "getput.h" @@ -52,15 +51,14 @@ RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $"); #include "channels.h" #include "compat.h" +#include "ssh1.h" #include "ssh2.h" -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/hmac.h> -#include "buffer.h" #include "cipher.h" #include "kex.h" -#include "hmac.h" +#include "mac.h" +#include "log.h" +#include "canohost.h" #ifdef PACKET_DEBUG #define DBG(x) x @@ -84,7 +82,7 @@ static int connection_out = -1; static int cipher_type = SSH_CIPHER_NONE; /* Protocol flags for the remote side. */ -static unsigned int remote_protocol_flags = 0; +static u_int remote_protocol_flags = 0; /* Encryption context for receiving data. This is only used for decryption. */ static CipherContext receive_context; @@ -106,6 +104,7 @@ static Buffer incoming_packet; /* Scratch buffer for packet compression/decompression. */ static Buffer compression_buffer; +static int compression_buffer_ready = 0; /* Flag indicating whether packet compression/decompression is enabled. */ static int packet_compression = 0; @@ -123,35 +122,14 @@ static int interactive_mode = 0; int use_ssh2_packet_format = 0; /* Session key information for Encryption and MAC */ -Kex *kex = NULL; +Newkeys *newkeys[MODE_MAX]; void -packet_set_kex(Kex *k) -{ - if( k->mac[MODE_IN ].key == NULL || - k->enc[MODE_IN ].key == NULL || - k->enc[MODE_IN ].iv == NULL || - k->mac[MODE_OUT].key == NULL || - k->enc[MODE_OUT].key == NULL || - k->enc[MODE_OUT].iv == NULL) - fatal("bad KEX"); - kex = k; -} -void -clear_enc_keys(Enc *enc, int len) -{ - memset(enc->iv, 0, len); - memset(enc->key, 0, len); - xfree(enc->iv); - xfree(enc->key); - enc->iv = NULL; - enc->key = NULL; -} -void packet_set_ssh2_format(void) { DBG(debug("use_ssh2_packet_format")); use_ssh2_packet_format = 1; + newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; } /* @@ -167,8 +145,8 @@ packet_set_connection(int fd_in, int fd_out) connection_in = fd_in; connection_out = fd_out; cipher_type = SSH_CIPHER_NONE; - cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0); - cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0); + cipher_init(&send_context, none, (u_char *) "", 0, NULL, 0); + cipher_init(&receive_context, none, (u_char *) "", 0, NULL, 0); if (!initialized) { initialized = 1; buffer_init(&input); @@ -272,7 +250,7 @@ packet_close() buffer_free(&output); buffer_free(&outgoing_packet); buffer_free(&incoming_packet); - if (packet_compression) { + if (compression_buffer_ready) { buffer_free(&compression_buffer); buffer_compress_uninit(); } @@ -281,7 +259,7 @@ packet_close() /* Sets remote side protocol flags. */ void -packet_set_protocol_flags(unsigned int protocol_flags) +packet_set_protocol_flags(u_int protocol_flags) { remote_protocol_flags = protocol_flags; channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); @@ -289,7 +267,7 @@ packet_set_protocol_flags(unsigned int protocol_flags) /* Returns the remote protocol flags set earlier by the above function. */ -unsigned int +u_int packet_get_protocol_flags() { return remote_protocol_flags; @@ -300,15 +278,24 @@ packet_get_protocol_flags() * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ -/*** XXXXX todo: kex means re-init */ +void +packet_init_compression() +{ + if (compression_buffer_ready == 1) + return; + compression_buffer_ready = 1; + buffer_init(&compression_buffer); +} + void packet_start_compression(int level) { - if (packet_compression) + if (packet_compression && !use_ssh2_packet_format) fatal("Compression already enabled."); packet_compression = 1; - buffer_init(&compression_buffer); - buffer_compress_init(level); + packet_init_compression(); + buffer_compress_init_send(level); + buffer_compress_init_recv(); } /* @@ -318,7 +305,7 @@ packet_start_compression(int level) void packet_encrypt(CipherContext * cc, void *dest, void *src, - unsigned int bytes) + u_int bytes) { cipher_encrypt(cc, dest, src, bytes); } @@ -329,7 +316,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src, */ void -packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes) +packet_decrypt(CipherContext *context, void *dest, void *src, u_int bytes) { /* * Cryptographic attack detector for ssh - Modifications for packet.c @@ -350,7 +337,7 @@ packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes */ void -packet_set_encryption_key(const unsigned char *key, unsigned int keylen, +packet_set_encryption_key(const u_char *key, u_int keylen, int number) { Cipher *cipher = cipher_by_number(number); @@ -391,7 +378,7 @@ packet_start2(int type) void packet_start(int type) { - DBG(debug("packet_start[%d]",type)); + DBG(debug("packet_start[%d]", type)); if (use_ssh2_packet_format) packet_start2(type); else @@ -410,7 +397,7 @@ packet_put_char(int value) /* Appends an integer to the packet data. */ void -packet_put_int(unsigned int value) +packet_put_int(u_int value) { buffer_put_int(&outgoing_packet, value); } @@ -418,7 +405,7 @@ packet_put_int(unsigned int value) /* Appends a string to packet data. */ void -packet_put_string(const char *buf, unsigned int len) +packet_put_string(const char *buf, u_int len) { buffer_put_string(&outgoing_packet, buf, len); } @@ -429,7 +416,7 @@ packet_put_cstring(const char *str) } void -packet_put_raw(const char *buf, unsigned int len) +packet_put_raw(const char *buf, u_int len) { buffer_append(&outgoing_packet, buf, len); } @@ -454,11 +441,11 @@ packet_put_bignum2(BIGNUM * value) */ void -packet_send1() +packet_send1(void) { char buf[8], *cp; int i, padding, len; - unsigned int checksum; + u_int checksum; u_int32_t rand = 0; /* @@ -493,7 +480,7 @@ packet_send1() buffer_consume(&outgoing_packet, 8 - padding); /* Add check bytes. */ - checksum = ssh_crc32((unsigned char *) buffer_ptr(&outgoing_packet), + checksum = ssh_crc32((u_char *) buffer_ptr(&outgoing_packet), buffer_len(&outgoing_packet)); PUT_32BIT(buf, checksum); buffer_append(&outgoing_packet, buf, 4); @@ -524,28 +511,78 @@ packet_send1() */ } +void +set_newkeys(int mode) +{ + Enc *enc; + Mac *mac; + Comp *comp; + CipherContext *cc; + + debug("newkeys: mode %d", mode); + + cc = (mode == MODE_OUT) ? &send_context : &receive_context; + if (newkeys[mode] != NULL) { + debug("newkeys: rekeying"); + /* todo: free old keys, reset compression/cipher-ctxt; */ + memset(cc, 0, sizeof(*cc)); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + memset(mac->key, 0, mac->key_len); + xfree(enc->name); + xfree(enc->iv); + xfree(enc->key); + xfree(mac->name); + xfree(mac->key); + xfree(comp->name); + xfree(newkeys[mode]); + } + newkeys[mode] = kex_get_newkeys(mode); + if (newkeys[mode] == NULL) + fatal("newkeys: no keys for mode %d", mode); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + if (mac->md != NULL) + mac->enabled = 1; + DBG(debug("cipher_init_context: %d", mode)); + cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len, + enc->iv, enc->cipher->block_size); + memset(enc->iv, 0, enc->cipher->block_size); + memset(enc->key, 0, enc->cipher->key_len); + if (comp->type != 0 && comp->enabled == 0) { + packet_init_compression(); + if (mode == MODE_OUT) + buffer_compress_init_send(6); + else + buffer_compress_init_recv(); + comp->enabled = 1; + } +} + /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ void -packet_send2() +packet_send2(void) { - unsigned char *macbuf = NULL; + static u_int32_t seqnr = 0; + u_char *macbuf = NULL; char *cp; - unsigned int packet_length = 0; - unsigned int i, padlen, len; + u_int packet_length = 0; + u_int i, padlen, len; u_int32_t rand = 0; - static unsigned int seqnr = 0; int type; Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; int block_size; - if (kex != NULL) { - enc = &kex->enc[MODE_OUT]; - mac = &kex->mac[MODE_OUT]; - comp = &kex->comp[MODE_OUT]; + if (newkeys[MODE_OUT] != NULL) { + enc = &newkeys[MODE_OUT]->enc; + mac = &newkeys[MODE_OUT]->mac; + comp = &newkeys[MODE_OUT]->comp; } block_size = enc ? enc->cipher->block_size : 8; @@ -588,7 +625,7 @@ packet_send2() if (i % 4 == 0) rand = arc4random(); cp[i] = rand & 0xff; - rand <<= 8; + rand >>= 8; } } else { /* clear padding */ @@ -603,11 +640,9 @@ packet_send2() /* compute MAC over seqnr and packet(length fields, payload, padding) */ if (mac && mac->enabled) { - macbuf = hmac( mac->md, seqnr, - (unsigned char *) buffer_ptr(&outgoing_packet), - buffer_len(&outgoing_packet), - mac->key, mac->key_len - ); + macbuf = mac_compute(mac, seqnr, + (u_char *) buffer_ptr(&outgoing_packet), + buffer_len(&outgoing_packet)); DBG(debug("done calc MAC out #%d", seqnr)); } /* encrypt packet and append to output buffer. */ @@ -626,22 +661,8 @@ packet_send2() log("outgoing seqnr wraps around"); buffer_clear(&outgoing_packet); - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_send2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init send_context")); - cipher_init(&send_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_OUT); } void @@ -664,10 +685,13 @@ int packet_read(int *payload_len_ptr) { int type, len; - fd_set set; + fd_set *setp; char buf[8192]; DBG(debug("packet_read()")); + setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) * + sizeof(fd_mask)); + /* Since we are blocking, ensure that all written packets have been sent. */ packet_write_wait(); @@ -682,17 +706,22 @@ packet_read(int *payload_len_ptr) || type == SSH_CMSG_EXIT_CONFIRMATION)) packet_integrity_check(*payload_len_ptr, 0, type); /* If we got a packet, return it. */ - if (type != SSH_MSG_NONE) + if (type != SSH_MSG_NONE) { + xfree(setp); return type; + } /* * Otherwise, wait for some data to arrive, add it to the * buffer, and try again. */ - FD_ZERO(&set); - FD_SET(connection_in, &set); + memset(setp, 0, howmany(connection_in + 1, NFDBITS) * + sizeof(fd_mask)); + FD_SET(connection_in, setp); /* Wait for some data to arrive. */ - select(connection_in + 1, &set, NULL, NULL, NULL); + while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; /* Read data from the socket. */ len = read(connection_in, buf, sizeof(buf)); @@ -742,16 +771,16 @@ packet_read_expect(int *payload_len_ptr, int expected_type) int packet_read_poll1(int *payload_len_ptr) { - unsigned int len, padded_len; - unsigned char *ucp; + u_int len, padded_len; + u_char *ucp; char buf[8], *cp; - unsigned int checksum, stored_checksum; + u_int checksum, stored_checksum; /* Check if input size is less than minimum packet size. */ if (buffer_len(&input) < 4 + 8) return SSH_MSG_NONE; /* Get length of incoming packet. */ - ucp = (unsigned char *) buffer_ptr(&input); + ucp = (u_char *) buffer_ptr(&input); len = GET_32BIT(ucp); if (len < 1 + 2 + 2 || len > 256 * 1024) packet_disconnect("Bad packet length %d.", len); @@ -778,7 +807,7 @@ packet_read_poll1(int *payload_len_ptr) #endif /* Compute packet checksum. */ - checksum = ssh_crc32((unsigned char *) buffer_ptr(&incoming_packet), + checksum = ssh_crc32((u_char *) buffer_ptr(&incoming_packet), buffer_len(&incoming_packet) - 4); /* Skip padding. */ @@ -790,7 +819,7 @@ packet_read_poll1(int *payload_len_ptr) packet_disconnect("packet_read_poll: len %d != buffer_len %d.", len, buffer_len(&incoming_packet)); - ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4; + ucp = (u_char *) buffer_ptr(&incoming_packet) + len - 4; stored_checksum = GET_32BIT(ucp); if (checksum != stored_checksum) packet_disconnect("Corrupted check bytes on input."); @@ -811,28 +840,28 @@ packet_read_poll1(int *payload_len_ptr) *payload_len_ptr = buffer_len(&incoming_packet); /* Return type. */ - return (unsigned char) buf[0]; + return (u_char) buf[0]; } int packet_read_poll2(int *payload_len_ptr) { - unsigned int padlen, need; - unsigned char buf[8], *macbuf; - unsigned char *ucp; + static u_int32_t seqnr = 0; + static u_int packet_length = 0; + u_int padlen, need; + u_char buf[8], *macbuf; + u_char *ucp; char *cp; - static unsigned int packet_length = 0; - static unsigned int seqnr = 0; int type; int maclen, block_size; Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; - if (kex != NULL) { - enc = &kex->enc[MODE_IN]; - mac = &kex->mac[MODE_IN]; - comp = &kex->comp[MODE_IN]; + if (newkeys[MODE_IN] != NULL) { + enc = &newkeys[MODE_IN]->enc; + mac = &newkeys[MODE_IN]->mac; + comp = &newkeys[MODE_IN]->comp; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->cipher->block_size : 8; @@ -848,7 +877,7 @@ packet_read_poll2(int *payload_len_ptr) buffer_append_space(&incoming_packet, &cp, block_size); packet_decrypt(&receive_context, cp, buffer_ptr(&input), block_size); - ucp = (unsigned char *) buffer_ptr(&incoming_packet); + ucp = (u_char *) buffer_ptr(&incoming_packet); packet_length = GET_32BIT(ucp); if (packet_length < 1 + 4 || packet_length > 256 * 1024) { buffer_dump(&incoming_packet); @@ -882,11 +911,9 @@ packet_read_poll2(int *payload_len_ptr) * increment sequence number for incoming packet */ if (mac && mac->enabled) { - macbuf = hmac( mac->md, seqnr, - (unsigned char *) buffer_ptr(&incoming_packet), - buffer_len(&incoming_packet), - mac->key, mac->key_len - ); + macbuf = mac_compute(mac, seqnr, + (u_char *) buffer_ptr(&incoming_packet), + buffer_len(&incoming_packet)); if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) packet_disconnect("Corrupted MAC on input."); DBG(debug("MAC #%d ok", seqnr)); @@ -926,30 +953,16 @@ packet_read_poll2(int *payload_len_ptr) packet_length = 0; /* extract packet type */ - type = (unsigned char)buf[0]; - - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_read_poll2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init receive_context")); - cipher_init(&receive_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + type = (u_char)buf[0]; + + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_IN); #ifdef PACKET_DEBUG - fprintf(stderr, "read/plain[%d]:\r\n",type); + fprintf(stderr, "read/plain[%d]:\r\n", type); buffer_dump(&incoming_packet); #endif - return (unsigned char)type; + return (u_char)type; } int @@ -979,14 +992,15 @@ packet_read_poll(int *payload_len_ptr) case SSH2_MSG_DISCONNECT: reason = packet_get_int(); msg = packet_get_string(NULL); - log("Received disconnect: %d: %.900s", reason, msg); + log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(), + reason, msg); xfree(msg); fatal_cleanup(); break; default: return type; break; - } + } } else { switch(type) { case SSH_MSG_IGNORE: @@ -998,7 +1012,8 @@ packet_read_poll(int *payload_len_ptr) break; case SSH_MSG_DISCONNECT: msg = packet_get_string(NULL); - log("Received disconnect: %.900s", msg); + log("Received disconnect from %s: %.400s", get_remote_ipaddr(), + msg); fatal_cleanup(); xfree(msg); break; @@ -1007,7 +1022,7 @@ packet_read_poll(int *payload_len_ptr) DBG(debug("received packet type %d", type)); return type; break; - } + } } } } @@ -1018,24 +1033,24 @@ packet_read_poll(int *payload_len_ptr) */ void -packet_process_incoming(const char *buf, unsigned int len) +packet_process_incoming(const char *buf, u_int len) { buffer_append(&input, buf, len); } /* Returns a character from the packet. */ -unsigned int +u_int packet_get_char() { char ch; buffer_get(&incoming_packet, &ch, 1); - return (unsigned char) ch; + return (u_char) ch; } /* Returns an integer from the packet data. */ -unsigned int +u_int packet_get_int() { return buffer_get_int(&incoming_packet); @@ -1081,7 +1096,7 @@ packet_remaining(void) */ char * -packet_get_string(unsigned int *length_ptr) +packet_get_string(u_int *length_ptr) { return buffer_get_string(&incoming_packet, length_ptr); } @@ -1101,6 +1116,9 @@ packet_send_debug(const char *fmt,...) char buf[1024]; va_list args; + if (compat20 && (datafellows & SSH_BUG_DEBUG)) + return; + va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); @@ -1193,14 +1211,21 @@ packet_write_poll() void packet_write_wait() { + fd_set *setp; + + setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * + sizeof(fd_mask)); packet_write_poll(); while (packet_have_data_to_write()) { - fd_set set; - FD_ZERO(&set); - FD_SET(connection_out, &set); - select(connection_out + 1, NULL, &set, NULL, NULL); + memset(setp, 0, howmany(connection_out + 1, NFDBITS) * + sizeof(fd_mask)); + FD_SET(connection_out, setp); + while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; packet_write_poll(); } + xfree(setp); } /* Returns true if there is buffered data to write to the connection. */ @@ -1225,45 +1250,45 @@ packet_not_very_much_data_to_write() /* Informs that the current session is interactive. Sets IP flags for that. */ void -packet_set_interactive(int interactive, int keepalives) +packet_set_interactive(int interactive) { + static int called = 0; + int lowdelay = IPTOS_LOWDELAY; + int throughput = IPTOS_THROUGHPUT; int on = 1; + if (called) + return; + called = 1; + /* Record that we are in interactive mode. */ interactive_mode = interactive; /* Only set socket options if using a socket. */ if (!packet_connection_is_on_socket()) return; - if (keepalives) { - /* Set keepalives if requested. */ - if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, - sizeof(on)) < 0) - error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); - } /* - * IPTOS_LOWDELAY, TCP_NODELAY and IPTOS_THROUGHPUT are IPv4 only + * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only */ - if (!packet_connection_is_ipv4()) - return; if (interactive) { /* * Set IP options for an interactive connection. Use * IPTOS_LOWDELAY and TCP_NODELAY. */ - int lowdelay = IPTOS_LOWDELAY; - if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay, - sizeof(lowdelay)) < 0) - error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); + if (packet_connection_is_ipv4()) { + if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, + (void *) &lowdelay, sizeof(lowdelay)) < 0) + error("setsockopt IPTOS_LOWDELAY: %.100s", + strerror(errno)); + } if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)) < 0) error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); - } else { + } else if (packet_connection_is_ipv4()) { /* * Set IP options for a non-interactive connection. Use * IPTOS_THROUGHPUT. */ - int throughput = IPTOS_THROUGHPUT; if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput, sizeof(throughput)) < 0) error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); @@ -1295,3 +1320,65 @@ packet_set_maxsize(int s) max_packet_size = s; return s; } + +/* + * 9.2. Ignored Data Message + * + * byte SSH_MSG_IGNORE + * string data + * + * All implementations MUST understand (and ignore) this message at any + * time (after receiving the protocol version). No implementation is + * required to send them. This message can be used as an additional + * protection measure against advanced traffic analysis techniques. + */ +/* size of current + ignore message should be n*sumlen bytes (w/o mac) */ +void +packet_inject_ignore(int sumlen) +{ + int blocksize, padlen, have, need, nb, mini, nbytes; + Enc *enc = NULL; + + if (use_ssh2_packet_format == 0) + return; + + have = buffer_len(&outgoing_packet); + debug2("packet_inject_ignore: current %d", have); + if (newkeys[MODE_OUT] != NULL) + enc = &newkeys[MODE_OUT]->enc; + blocksize = enc ? enc->cipher->block_size : 8; + padlen = blocksize - (have % blocksize); + if (padlen < 4) + padlen += blocksize; + have += padlen; + have /= blocksize; /* # of blocks for current message */ + + nb = roundup(sumlen, blocksize) / blocksize; /* blocks for both */ + mini = roundup(5+1+4+4, blocksize) / blocksize; /* minsize ignore msg */ + need = nb - (have % nb); /* blocks for ignore */ + if (need <= mini) + need += nb; + nbytes = (need - mini) * blocksize; /* size of ignore payload */ + debug2("packet_inject_ignore: block %d have %d nb %d mini %d need %d", + blocksize, have, nb, mini, need); + + /* enqueue current message and append a ignore message */ + packet_send(); + packet_send_ignore(nbytes); +} + +void +packet_send_ignore(int nbytes) +{ + u_int32_t rand = 0; + int i; + + packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE); + packet_put_int(nbytes); + for(i = 0; i < nbytes; i++) { + if (i % 4 == 0) + rand = arc4random(); + packet_put_char(rand & 0xff); + rand >>= 8; + } +} diff --git a/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h new file mode 100644 index 0000000..2f109b3 --- /dev/null +++ b/crypto/openssh/pathnames.h @@ -0,0 +1,111 @@ +/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#define ETCDIR "/etc" +#define _PATH_SSH_PIDDIR "/var/run" + +/* + * System-wide file containing host keys of known hosts. This file should be + * world-readable. + */ +#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts" +#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2" + +/* + * Of these, ssh_host_key must be readable only by root, whereas ssh_config + * should be world-readable. + */ +#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config" +#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config" +#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key" +#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key" +#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key" +#define _PATH_DH_PRIMES ETCDIR "/primes" + +#define _PATH_SSH_PROGRAM "/usr/bin/ssh" + +/* + * The process id of the daemon listening for connections is saved here to + * make it easier to kill the correct daemon when necessary. + */ +#define _PATH_SSH_DAEMON_PID_FILE _PATH_SSH_PIDDIR "/sshd.pid" + +/* + * The directory in user\'s home directory in which the files reside. The + * directory should be world-readable (though not all files are). + */ +#define _PATH_SSH_USER_DIR ".ssh" + +/* + * Per-user file containing host keys of known hosts. This file need not be + * readable by anyone except the user him/herself, though this does not + * contain anything particularly secret. + */ +#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts" +#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2" + +/* + * Name of the default file containing client-side authentication key. This + * file should only be readable by the user him/herself. + */ +#define _PATH_SSH_CLIENT_IDENTITY ".ssh/identity" +#define _PATH_SSH_CLIENT_ID_DSA ".ssh/id_dsa" +#define _PATH_SSH_CLIENT_ID_RSA ".ssh/id_rsa" + +/* + * Configuration file in user\'s home directory. This file need not be + * readable by anyone but the user him/herself, but does not contain anything + * particularly secret. If the user\'s home directory resides on an NFS + * volume where root is mapped to nobody, this may need to be world-readable. + */ +#define _PATH_SSH_USER_CONFFILE ".ssh/config" + +/* + * File containing a list of those rsa keys that permit logging in as this + * user. This file need not be readable by anyone but the user him/herself, + * but does not contain anything particularly secret. If the user\'s home + * directory resides on an NFS volume where root is mapped to nobody, this + * may need to be world-readable. (This file is read by the daemon which is + * running as root.) + */ +#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" +#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2" + +/* + * Per-user and system-wide ssh "rc" files. These files are executed with + * /bin/sh before starting the shell or command if they exist. They will be + * passed "proto cookie" as arguments if X11 forwarding with spoofing is in + * use. xauth will be run if neither of these exists. + */ +#define _PATH_SSH_USER_RC ".ssh/rc" +#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc" + +/* + * Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use + * ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled. + */ +#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv" +#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv" + +/* + * Default location of askpass + */ +#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass" + +/* for scp */ +#define _PATH_CP "cp" + +/* for sftp */ +#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server" +#define _PATH_LS "ls" diff --git a/crypto/openssh/radix.c b/crypto/openssh/radix.c index 8429204..3b149a8 100644 --- a/crypto/openssh/radix.c +++ b/crypto/openssh/radix.c @@ -25,19 +25,19 @@ #include "includes.h" #include "uuencode.h" -RCSID("$OpenBSD: radix.c,v 1.13 2000/09/07 20:27:52 deraadt Exp $"); +RCSID("$OpenBSD: radix.c,v 1.15 2001/01/16 23:58:09 deraadt Exp $"); #ifdef AFS #include <krb.h> -typedef unsigned char my_u_char; -typedef unsigned int my_u_int32_t; -typedef unsigned short my_u_short; +typedef u_char my_u_char; +typedef u_int my_u_int32_t; +typedef u_short my_u_short; /* Nasty macros from BIND-4.9.2 */ #define GETSHORT(s, cp) { \ - register my_u_char *t_cp = (my_u_char*)(cp); \ + register my_u_char *t_cp = (my_u_char *)(cp); \ (s) = (((my_u_short)t_cp[0]) << 8) \ | (((my_u_short)t_cp[1])) \ ; \ @@ -45,7 +45,7 @@ typedef unsigned short my_u_short; } #define GETLONG(l, cp) { \ - register my_u_char *t_cp = (my_u_char*)(cp); \ + register my_u_char *t_cp = (my_u_char *)(cp); \ (l) = (((my_u_int32_t)t_cp[0]) << 24) \ | (((my_u_int32_t)t_cp[1]) << 16) \ | (((my_u_int32_t)t_cp[2]) << 8) \ @@ -56,7 +56,7 @@ typedef unsigned short my_u_short; #define PUTSHORT(s, cp) { \ register my_u_short t_s = (my_u_short)(s); \ - register my_u_char *t_cp = (my_u_char*)(cp); \ + register my_u_char *t_cp = (my_u_char *)(cp); \ *t_cp++ = t_s >> 8; \ *t_cp = t_s; \ (cp) += 2; \ @@ -64,7 +64,7 @@ typedef unsigned short my_u_short; #define PUTLONG(l, cp) { \ register my_u_int32_t t_l = (my_u_int32_t)(l); \ - register my_u_char *t_cp = (my_u_char*)(cp); \ + register my_u_char *t_cp = (my_u_char *)(cp); \ *t_cp++ = t_l >> 24; \ *t_cp++ = t_l >> 16; \ *t_cp++ = t_l >> 8; \ @@ -73,9 +73,9 @@ typedef unsigned short my_u_short; } #define GETSTRING(s, p, p_l) { \ - register char* p_targ = (p) + p_l; \ - register char* s_c = (s); \ - register char* p_c = (p); \ + register char *p_targ = (p) + p_l; \ + register char *s_c = (s); \ + register char *p_c = (p); \ while (*p_c && (p_c < p_targ)) { \ *s_c++ = *p_c++; \ } \ @@ -89,7 +89,7 @@ typedef unsigned short my_u_short; int -creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen) +creds_to_radix(CREDENTIALS *creds, u_char *buf, size_t buflen) { char *p, *s; int len; @@ -123,8 +123,8 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen) PUTLONG(creds->issue_date, p); { - unsigned int endTime; - endTime = (unsigned int) krb_life_to_time(creds->issue_date, + u_int endTime; + endTime = (u_int) krb_life_to_time(creds->issue_date, creds->lifetime); PUTLONG(endTime, p); } @@ -139,7 +139,7 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen) p += creds->ticket_st.length; len = p - temp; - return (uuencode((unsigned char *)temp, len, (char *)buf, buflen)); + return (uuencode((u_char *)temp, len, (char *)buf, buflen)); } int @@ -151,7 +151,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds) char version; char temp[2048]; - len = uudecode(buf, (unsigned char *)temp, sizeof(temp)); + len = uudecode(buf, (u_char *)temp, sizeof(temp)); if (len < 0) return 0; @@ -184,7 +184,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds) GETLONG(creds->issue_date, p); len -= 4; { - unsigned int endTime; + u_int endTime; GETLONG(endTime, p); len -= 4; creds->lifetime = krb_time_to_life(creds->issue_date, endTime); diff --git a/crypto/openssh/radix.h b/crypto/openssh/radix.h new file mode 100644 index 0000000..57592d8 --- /dev/null +++ b/crypto/openssh/radix.h @@ -0,0 +1,28 @@ +/* $OpenBSD: radix.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */ + +/* + * Copyright (c) 1999 Dug Song. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int creds_to_radix(CREDENTIALS * creds, u_char *buf, size_t buflen); +int radix_to_creds(const char *buf, CREDENTIALS * creds); diff --git a/crypto/openssh/readpass.c b/crypto/openssh/readpass.c index f3a7dcb..b5f5971 100644 --- a/crypto/openssh/readpass.c +++ b/crypto/openssh/readpass.c @@ -32,11 +32,58 @@ */ #include "includes.h" -RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $"); +RCSID("$OpenBSD: readpass.c,v 1.15 2001/04/18 21:57:41 markus Exp $"); #include "xmalloc.h" -#include "ssh.h" #include "cli.h" +#include "readpass.h" +#include "pathnames.h" +#include "log.h" +#include "atomicio.h" +#include "ssh.h" + +char * +ssh_askpass(char *askpass, char *msg) +{ + pid_t pid; + size_t len; + char *nl, *pass; + int p[2], status; + char buf[1024]; + + if (fflush(stdout) != 0) + error("ssh_askpass: fflush: %s", strerror(errno)); + if (askpass == NULL) + fatal("internal error: askpass undefined"); + if (pipe(p) < 0) + fatal("ssh_askpass: pipe: %s", strerror(errno)); + if ((pid = fork()) < 0) + fatal("ssh_askpass: fork: %s", strerror(errno)); + if (pid == 0) { + seteuid(getuid()); + setuid(getuid()); + close(p[0]); + if (dup2(p[1], STDOUT_FILENO) < 0) + fatal("ssh_askpass: dup2: %s", strerror(errno)); + execlp(askpass, askpass, msg, (char *) 0); + fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); + } + close(p[1]); + len = read(p[0], buf, sizeof buf); + close(p[0]); + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + if (len <= 1) + return xstrdup(""); + nl = strchr(buf, '\n'); + if (nl) + *nl = '\0'; + pass = xstrdup(buf); + memset(buf, 0, sizeof(buf)); + return pass; +} + /* * Reads a passphrase from /dev/tty with echo turned off. Returns the @@ -51,5 +98,27 @@ RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $"); char * read_passphrase(char *prompt, int from_stdin) { + char *askpass = NULL; + int use_askpass = 0, ttyfd; + + if (from_stdin) { + if (!isatty(STDIN_FILENO)) + use_askpass = 1; + } else { + ttyfd = open("/dev/tty", O_RDWR); + if (ttyfd >= 0) + close(ttyfd); + else + use_askpass = 1; + } + + if (use_askpass && getenv("DISPLAY")) { + if (getenv(SSH_ASKPASS_ENV)) + askpass = getenv(SSH_ASKPASS_ENV); + else + askpass = _PATH_SSH_ASKPASS_DEFAULT; + return ssh_askpass(askpass, prompt); + } + return cli_read_passphrase(prompt, from_stdin, 0); } diff --git a/crypto/openssh/readpass.h b/crypto/openssh/readpass.h new file mode 100644 index 0000000..d8da448 --- /dev/null +++ b/crypto/openssh/readpass.h @@ -0,0 +1,20 @@ +/* $OpenBSD: readpass.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +/* + * Reads a passphrase from /dev/tty with echo turned off. Returns the + * passphrase (allocated with xmalloc). Exits if EOF is encountered. If + * from_stdin is true, the passphrase will be read from stdin instead. + */ +char *read_passphrase(char *prompt, int from_stdin); diff --git a/crypto/openssh/rijndael.c b/crypto/openssh/rijndael.c index 0eb313d..98ecb55 100644 --- a/crypto/openssh/rijndael.c +++ b/crypto/openssh/rijndael.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rijndael.c,v 1.2 2000/10/15 14:14:01 markus Exp $ */ +/* $OpenBSD: rijndael.c,v 1.7 2001/02/04 15:32:24 stevesk Exp $ */ /* This is an independent implementation of the encryption algorithm: */ /* */ @@ -52,21 +52,14 @@ void gen_tabs __P((void)); /* Invert byte order in a 32 bit variable */ -#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00) +#define bswap(x) ((rotl(x, 8) & 0x00ff00ff) | (rotr(x, 8) & 0xff00ff00)) -/* Extract byte from a 32 bit quantity (little endian notation) */ +/* Extract byte from a 32 bit quantity (little endian notation) */ #define byte(x,n) ((u1byte)((x) >> (8 * n))) #if BYTE_ORDER != LITTLE_ENDIAN -#define BLOCK_SWAP -#endif - -/* For inverting byte order in input/output 32 bit words if needed */ - -#ifdef BLOCK_SWAP #define BYTE_SWAP -#define WORD_SWAP #endif #ifdef BYTE_SWAP @@ -75,84 +68,6 @@ void gen_tabs __P((void)); #define io_swap(x) (x) #endif -/* For inverting the byte order of input/output blocks if needed */ - -#ifdef WORD_SWAP - -#define get_block(x) \ - ((u4byte*)(x))[0] = io_swap(in_blk[3]); \ - ((u4byte*)(x))[1] = io_swap(in_blk[2]); \ - ((u4byte*)(x))[2] = io_swap(in_blk[1]); \ - ((u4byte*)(x))[3] = io_swap(in_blk[0]) - -#define put_block(x) \ - out_blk[3] = io_swap(((u4byte*)(x))[0]); \ - out_blk[2] = io_swap(((u4byte*)(x))[1]); \ - out_blk[1] = io_swap(((u4byte*)(x))[2]); \ - out_blk[0] = io_swap(((u4byte*)(x))[3]) - -#define get_key(x,len) \ - ((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \ - ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \ - switch((((len) + 63) / 64)) { \ - case 2: \ - ((u4byte*)(x))[0] = io_swap(in_key[3]); \ - ((u4byte*)(x))[1] = io_swap(in_key[2]); \ - ((u4byte*)(x))[2] = io_swap(in_key[1]); \ - ((u4byte*)(x))[3] = io_swap(in_key[0]); \ - break; \ - case 3: \ - ((u4byte*)(x))[0] = io_swap(in_key[5]); \ - ((u4byte*)(x))[1] = io_swap(in_key[4]); \ - ((u4byte*)(x))[2] = io_swap(in_key[3]); \ - ((u4byte*)(x))[3] = io_swap(in_key[2]); \ - ((u4byte*)(x))[4] = io_swap(in_key[1]); \ - ((u4byte*)(x))[5] = io_swap(in_key[0]); \ - break; \ - case 4: \ - ((u4byte*)(x))[0] = io_swap(in_key[7]); \ - ((u4byte*)(x))[1] = io_swap(in_key[6]); \ - ((u4byte*)(x))[2] = io_swap(in_key[5]); \ - ((u4byte*)(x))[3] = io_swap(in_key[4]); \ - ((u4byte*)(x))[4] = io_swap(in_key[3]); \ - ((u4byte*)(x))[5] = io_swap(in_key[2]); \ - ((u4byte*)(x))[6] = io_swap(in_key[1]); \ - ((u4byte*)(x))[7] = io_swap(in_key[0]); \ - } - -#else - -#define get_block(x) \ - ((u4byte*)(x))[0] = io_swap(in_blk[0]); \ - ((u4byte*)(x))[1] = io_swap(in_blk[1]); \ - ((u4byte*)(x))[2] = io_swap(in_blk[2]); \ - ((u4byte*)(x))[3] = io_swap(in_blk[3]) - -#define put_block(x) \ - out_blk[0] = io_swap(((u4byte*)(x))[0]); \ - out_blk[1] = io_swap(((u4byte*)(x))[1]); \ - out_blk[2] = io_swap(((u4byte*)(x))[2]); \ - out_blk[3] = io_swap(((u4byte*)(x))[3]) - -#define get_key(x,len) \ - ((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \ - ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \ - switch((((len) + 63) / 64)) { \ - case 4: \ - ((u4byte*)(x))[6] = io_swap(in_key[6]); \ - ((u4byte*)(x))[7] = io_swap(in_key[7]); \ - case 3: \ - ((u4byte*)(x))[4] = io_swap(in_key[4]); \ - ((u4byte*)(x))[5] = io_swap(in_key[5]); \ - case 2: \ - ((u4byte*)(x))[0] = io_swap(in_key[0]); \ - ((u4byte*)(x))[1] = io_swap(in_key[1]); \ - ((u4byte*)(x))[2] = io_swap(in_key[2]); \ - ((u4byte*)(x))[3] = io_swap(in_key[3]); \ - } - -#endif - #define LARGE_TABLES u1byte pow_tab[256]; @@ -174,15 +89,15 @@ u4byte tab_gen = 0; #define f_rn(bo, bi, n, k) \ bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ - ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) #define i_rn(bo, bi, n, k) \ bo[n] = it_tab[0][byte(bi[n],0)] ^ \ - it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) #ifdef LARGE_TABLES @@ -194,15 +109,15 @@ u4byte tab_gen = 0; #define f_rl(bo, bi, n, k) \ bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ - fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) #define i_rl(bo, bi, n, k) \ bo[n] = il_tab[0][byte(bi[n],0)] ^ \ - il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) #else @@ -214,15 +129,15 @@ u4byte tab_gen = 0; #define f_rl(bo, bi, n, k) \ bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \ - rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \ - rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ - rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n) + rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \ + rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ + rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n) #define i_rl(bo, bi, n, k) \ bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \ - rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \ - rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ - rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n) + rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \ + rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ + rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n) #endif @@ -245,7 +160,7 @@ gen_tabs(void) log_tab[1] = 0; p = 1; for(i = 0; i < 10; ++i) { - rco_tab[i] = p; + rco_tab[i] = p; p = (p << 1) ^ (p & 0x80 ? 0x1b : 0); } @@ -257,19 +172,19 @@ gen_tabs(void) /* least significant end of a byte. */ for(i = 0; i < 256; ++i) { - p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p; - q = (q >> 7) | (q << 1); p ^= q; - q = (q >> 7) | (q << 1); p ^= q; - q = (q >> 7) | (q << 1); p ^= q; - q = (q >> 7) | (q << 1); p ^= q ^ 0x63; + p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q; + q = (q >> 7) | (q << 1); p ^= q ^ 0x63; sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i; } for(i = 0; i < 256; ++i) { - p = sbx_tab[i]; + p = sbx_tab[i]; + +#ifdef LARGE_TABLES -#ifdef LARGE_TABLES - t = p; fl_tab[0][i] = t; fl_tab[1][i] = rotl(t, 8); fl_tab[2][i] = rotl(t, 16); @@ -279,30 +194,30 @@ gen_tabs(void) ((u4byte)p << 8) | ((u4byte)p << 16) | ((u4byte)ff_mult(3, p) << 24); - + ft_tab[0][i] = t; ft_tab[1][i] = rotl(t, 8); ft_tab[2][i] = rotl(t, 16); ft_tab[3][i] = rotl(t, 24); - p = isb_tab[i]; + p = isb_tab[i]; -#ifdef LARGE_TABLES - - t = p; il_tab[0][i] = t; - il_tab[1][i] = rotl(t, 8); - il_tab[2][i] = rotl(t, 16); +#ifdef LARGE_TABLES + + t = p; il_tab[0][i] = t; + il_tab[1][i] = rotl(t, 8); + il_tab[2][i] = rotl(t, 16); il_tab[3][i] = rotl(t, 24); -#endif +#endif t = ((u4byte)ff_mult(14, p)) | ((u4byte)ff_mult( 9, p) << 8) | ((u4byte)ff_mult(13, p) << 16) | ((u4byte)ff_mult(11, p) << 24); - - it_tab[0][i] = t; - it_tab[1][i] = rotl(t, 8); - it_tab[2][i] = rotl(t, 16); - it_tab[3][i] = rotl(t, 24); + + it_tab[0][i] = t; + it_tab[1][i] = rotl(t, 8); + it_tab[2][i] = rotl(t, 16); + it_tab[3][i] = rotl(t, 24); } tab_gen = 1; @@ -317,8 +232,8 @@ gen_tabs(void) t = w ^ (x); \ (y) = u ^ v ^ w; \ (y) ^= rotr(u ^ t, 8) ^ \ - rotr(v ^ t, 16) ^ \ - rotr(t,24) + rotr(v ^ t, 16) ^ \ + rotr(t,24) /* initialise the key schedule from the user supplied key */ @@ -356,7 +271,7 @@ gen_tabs(void) rijndael_ctx * rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len, int encrypt) -{ +{ u4byte i, t, u, v, w; u4byte *e_key = ctx->e_key; u4byte *d_key = ctx->d_key; @@ -368,25 +283,25 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len, ctx->k_len = (key_len + 31) / 32; - e_key[0] = in_key[0]; e_key[1] = in_key[1]; - e_key[2] = in_key[2]; e_key[3] = in_key[3]; - + e_key[0] = io_swap(in_key[0]); e_key[1] = io_swap(in_key[1]); + e_key[2] = io_swap(in_key[2]); e_key[3] = io_swap(in_key[3]); + switch(ctx->k_len) { - case 4: t = e_key[3]; - for(i = 0; i < 10; ++i) + case 4: t = e_key[3]; + for(i = 0; i < 10; ++i) loop4(i); - break; + break; - case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5]; - for(i = 0; i < 8; ++i) + case 6: e_key[4] = io_swap(in_key[4]); t = e_key[5] = io_swap(in_key[5]); + for(i = 0; i < 8; ++i) loop6(i); - break; + break; - case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5]; - e_key[6] = in_key[6]; t = e_key[7] = in_key[7]; - for(i = 0; i < 7; ++i) + case 8: e_key[4] = io_swap(in_key[4]); e_key[5] = io_swap(in_key[5]); + e_key[6] = io_swap(in_key[6]); t = e_key[7] = io_swap(in_key[7]); + for(i = 0; i < 7; ++i) loop8(i); - break; + break; } if (!encrypt) { @@ -418,13 +333,15 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len, void rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) -{ +{ u4byte k_len = ctx->k_len; u4byte *e_key = ctx->e_key; u4byte b0[4], b1[4], *kp; - b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1]; - b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3]; + b0[0] = io_swap(in_blk[0]) ^ e_key[0]; + b0[1] = io_swap(in_blk[1]) ^ e_key[1]; + b0[2] = io_swap(in_blk[2]) ^ e_key[2]; + b0[3] = io_swap(in_blk[3]) ^ e_key[3]; kp = e_key + 4; @@ -442,8 +359,8 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) f_nround(b1, b0, kp); f_nround(b0, b1, kp); f_nround(b1, b0, kp); f_lround(b0, b1, kp); - out_blk[0] = b0[0]; out_blk[1] = b0[1]; - out_blk[2] = b0[2]; out_blk[3] = b0[3]; + out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]); + out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]); } /* decrypt a block of text */ @@ -463,14 +380,16 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) void rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) -{ +{ u4byte b0[4], b1[4], *kp; u4byte k_len = ctx->k_len; u4byte *e_key = ctx->e_key; u4byte *d_key = ctx->d_key; - b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25]; - b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27]; + b0[0] = io_swap(in_blk[0]) ^ e_key[4 * k_len + 24]; + b0[1] = io_swap(in_blk[1]) ^ e_key[4 * k_len + 25]; + b0[2] = io_swap(in_blk[2]) ^ e_key[4 * k_len + 26]; + b0[3] = io_swap(in_blk[3]) ^ e_key[4 * k_len + 27]; kp = d_key + 4 * (k_len + 5); @@ -488,6 +407,6 @@ rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk) i_nround(b1, b0, kp); i_nround(b0, b1, kp); i_nround(b1, b0, kp); i_lround(b0, b1, kp); - out_blk[0] = b0[0]; out_blk[1] = b0[1]; - out_blk[2] = b0[2]; out_blk[3] = b0[3]; + out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]); + out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]); } diff --git a/crypto/openssh/rijndael.h b/crypto/openssh/rijndael.h index c13f18c..66e0bbe 100644 --- a/crypto/openssh/rijndael.h +++ b/crypto/openssh/rijndael.h @@ -1,3 +1,19 @@ +/* $OpenBSD: rijndael.h,v 1.7 2001/03/01 03:38:33 deraadt Exp $ */ + +/* This is an independent implementation of the encryption algorithm: */ +/* */ +/* RIJNDAEL by Joan Daemen and Vincent Rijmen */ +/* */ +/* which is a candidate algorithm in the Advanced Encryption Standard */ +/* programme of the US National Institute of Standards and Technology. */ +/* */ +/* Copyright in this implementation is held by Dr B R Gladman but I */ +/* hereby give permission for its free direct or derivative use subject */ +/* to acknowledgment of its origin and compliance with any conditions */ +/* that the originators of the algorithm place on its exploitation. */ +/* */ +/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */ + #ifndef _RIJNDAEL_H_ #define _RIJNDAEL_H_ diff --git a/crypto/openssh/scp-common.c b/crypto/openssh/scp-common.c new file mode 100644 index 0000000..7e5f09c --- /dev/null +++ b/crypto/openssh/scp-common.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Parts from: + * + * Copyright (c) 1983, 1990, 1992, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "includes.h" +RCSID("$OpenBSD: scp-common.c,v 1.1 2001/04/16 02:31:43 mouring Exp $"); + +char * +cleanhostname(host) + char *host; +{ + if (*host == '[' && host[strlen(host) - 1] == ']') { + host[strlen(host) - 1] = '\0'; + return (host + 1); + } else + return host; +} + +char * +colon(cp) + char *cp; +{ + int flag = 0; + + if (*cp == ':') /* Leading colon is part of file name. */ + return (0); + if (*cp == '[') + flag = 1; + + for (; *cp; ++cp) { + if (*cp == '@' && *(cp+1) == '[') + flag = 1; + if (*cp == ']' && *(cp+1) == ':' && flag) + return (cp+1); + if (*cp == ':' && !flag) + return (cp); + if (*cp == '/') + return (0); + } + return (0); +} diff --git a/crypto/openssh/scp-common.h b/crypto/openssh/scp-common.h new file mode 100644 index 0000000..e0ab6ec --- /dev/null +++ b/crypto/openssh/scp-common.h @@ -0,0 +1,64 @@ +/* $OpenBSD: scp-common.h,v 1.1 2001/04/16 02:31:43 mouring Exp $ */ +/* + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Parts from: + * + * Copyright (c) 1983, 1990, 1992, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +char *cleanhostname(char *host); +char *colon(char *cp); diff --git a/crypto/openssh/scp.1 b/crypto/openssh/scp.1 index 0a2ca1a..10e67aa3 100644 --- a/crypto/openssh/scp.1 +++ b/crypto/openssh/scp.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.13 2000/10/16 09:38:44 djm Exp $ +.\" $OpenBSD: scp.1,v 1.14 2001/02/04 11:11:53 djm Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -129,6 +129,7 @@ program in BSD source code from the Regents of the University of California. .Sh SEE ALSO .Xr rcp 1 , +.Xr sftp 1 , .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c index a412b8d..81d3b55 100644 --- a/crypto/openssh/scp.c +++ b/crypto/openssh/scp.c @@ -14,8 +14,8 @@ * called by a name other than "ssh" or "Secure Shell". */ /* - * Copyright (c) 1999 Theo de Raadt. All rights reserved. - * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -75,12 +75,13 @@ */ #include "includes.h" -RCSID("$OpenBSD: scp.c,v 1.43 2000/10/18 18:23:02 markus Exp $"); +RCSID("$OpenBSD: scp.c,v 1.68 2001/04/22 12:34:05 markus Exp $"); -#include "ssh.h" #include "xmalloc.h" - -#define _PATH_CP "cp" +#include "atomicio.h" +#include "pathnames.h" +#include "log.h" +#include "scp-common.h" /* For progressmeter() -- number of seconds before xfer considered "stalled" */ #define STALLTIME 5 @@ -99,7 +100,7 @@ void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2))); static struct timeval start; /* Number of bytes of current file transferred so far. */ -volatile unsigned long statbytes; +volatile off_t statbytes; /* Total size of current file. */ off_t totalbytes = 0; @@ -110,14 +111,11 @@ char *curfile; /* This is set to non-zero to enable verbose mode. */ int verbose_mode = 0; -/* This is set to non-zero if compression is desired. */ -int compress = 0; - /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; /* This is the program to execute for the secured connection. ("ssh" or -S) */ -char *ssh_program = SSH_PROGRAM; +char *ssh_program = _PATH_SSH_PROGRAM; /* This is the list of arguments that scp passes to ssh */ struct { @@ -185,28 +183,12 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) return 0; } -void -fatal(const char *fmt,...) -{ - va_list ap; - char buf[1024]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - fprintf(stderr, "%s\n", buf); - exit(255); -} - typedef struct { int cnt; char *buf; } BUF; -extern int iamremote; - BUF *allocbuf(BUF *, int, int); -char *colon(char *); void lostconn(int); void nospace(void); int okname(char *); @@ -245,7 +227,7 @@ main(argc, argv) addargs("-oFallBackToRsh no"); fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF) + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1) switch (ch) { /* User-visible flags. */ case '4': @@ -292,7 +274,6 @@ main(argc, argv) iamremote = 1; tflag = 1; break; - case '?': default: usage(); } @@ -308,7 +289,7 @@ main(argc, argv) remin = STDIN_FILENO; remout = STDOUT_FILENO; - if (fflag) { + if (fflag) { /* Follow "protocol", send data. */ (void) response(); source(argc, argv); @@ -326,7 +307,8 @@ main(argc, argv) remin = remout = -1; /* Command to be executed on remote system using "ssh". */ - (void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "", + (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", + verbose_mode ? " -v" : "", iamrecursive ? " -r" : "", pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); @@ -342,17 +324,6 @@ main(argc, argv) exit(errs != 0); } -char * -cleanhostname(host) - char *host; -{ - if (*host == '[' && host[strlen(host) - 1] == ']') { - host[strlen(host) - 1] = '\0'; - return (host + 1); - } else - return host; -} - void toremote(targ, argc, argv) char *targ, *argv[]; @@ -397,20 +368,22 @@ toremote(targ, argc, argv) suser = pwd->pw_name; else if (!okname(suser)) continue; - (void) sprintf(bp, - "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - suser, host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); + snprintf(bp, len, + "%s%s -x -o'FallBackToRsh no' -n " + "-l %s %s %s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + suser, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); } else { host = cleanhostname(argv[i]); - (void) sprintf(bp, - "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); + snprintf(bp, len, + "exec %s%s -x -o'FallBackToRsh no' -n %s " + "%s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); } if (verbose_mode) fprintf(stderr, "Executing: %s\n", bp); @@ -420,7 +393,7 @@ toremote(targ, argc, argv) if (remin == -1) { len = strlen(targ) + CMDNEEDS + 20; bp = xmalloc(len); - (void) sprintf(bp, "%s -t %s", cmd, targ); + (void) snprintf(bp, len, "%s -t %s", cmd, targ); host = cleanhostname(thost); if (do_cmd(host, tuser, bp, &remin, &remout, argc) < 0) @@ -447,7 +420,7 @@ tolocal(argc, argv) len = strlen(_PATH_CP) + strlen(argv[i]) + strlen(argv[argc - 1]) + 20; bp = xmalloc(len); - (void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP, + (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, iamrecursive ? " -r" : "", pflag ? " -p" : "", argv[i], argv[argc - 1]); if (verbose_mode) @@ -474,7 +447,7 @@ tolocal(argc, argv) host = cleanhostname(host); len = strlen(src) + CMDNEEDS + 20; bp = xmalloc(len); - (void) sprintf(bp, "%s -f %s", cmd, src); + (void) snprintf(bp, len, "%s -f %s", cmd, src); if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { (void) xfree(bp); ++errs; @@ -495,13 +468,17 @@ source(argc, argv) struct stat stb; static BUF buffer; BUF *bp; - off_t i; - int amt, fd, haderr, indx, result; + off_t i, amt, result; + int fd, haderr, indx; char *last, *name, buf[2048]; + int len; for (indx = 0; indx < argc; ++indx) { name = argv[indx]; statbytes = 0; + len = strlen(name); + while (len > 1 && name[len-1] == '/') + name[--len] = '\0'; if ((fd = open(name, O_RDONLY, 0)) < 0) goto syserr; if (fstat(fd, &stb) < 0) { @@ -531,18 +508,17 @@ syserr: run_err("%s: %s", name, strerror(errno)); * Make it compatible with possible future * versions expecting microseconds. */ - (void) sprintf(buf, "T%lu 0 %lu 0\n", - (unsigned long) stb.st_mtime, - (unsigned long) stb.st_atime); + (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", + (u_long) stb.st_mtime, + (u_long) stb.st_atime); (void) atomicio(write, remout, buf, strlen(buf)); if (response() < 0) goto next; } #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) - (void) sprintf(buf, "C%04o %lu %s\n", - (unsigned int) (stb.st_mode & FILEMODEMASK), - (unsigned long) stb.st_size, - last); + snprintf(buf, sizeof buf, "C%04o %lld %s\n", + (u_int) (stb.st_mode & FILEMODEMASK), + (long long)stb.st_size, last); if (verbose_mode) { fprintf(stderr, "Sending file modes: %s", buf); fflush(stderr); @@ -609,17 +585,17 @@ rsource(name, statp) else last++; if (pflag) { - (void) sprintf(path, "T%lu 0 %lu 0\n", - (unsigned long) statp->st_mtime, - (unsigned long) statp->st_atime); + (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n", + (u_long) statp->st_mtime, + (u_long) statp->st_atime); (void) atomicio(write, remout, path, strlen(path)); if (response() < 0) { closedir(dirp); return; } } - (void) sprintf(path, "D%04o %d %.1024s\n", - (unsigned int) (statp->st_mode & FILEMODEMASK), 0, last); + (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", + (u_int) (statp->st_mode & FILEMODEMASK), 0, last); if (verbose_mode) fprintf(stderr, "Entering directory: %s", path); (void) atomicio(write, remout, path, strlen(path)); @@ -627,7 +603,7 @@ rsource(name, statp) closedir(dirp); return; } - while ((dp = readdir(dirp))) { + while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0) continue; if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) @@ -636,7 +612,7 @@ rsource(name, statp) run_err("%s/%s: name too long", name, dp->d_name); continue; } - (void) sprintf(path, "%s/%s", name, dp->d_name); + (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); vect[0] = path; source(1, vect); } @@ -661,9 +637,10 @@ sink(argc, argv) off_t size; int setimes, targisdir, wrerrno = 0; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; - int dummy_usec; struct timeval tv[2]; +#define atime tv[0] +#define mtime tv[1] #define SCREWUP(str) { why = str; goto screwup; } setimes = targisdir = 0; @@ -697,7 +674,7 @@ sink(argc, argv) if (buf[0] == '\01' || buf[0] == '\02') { if (iamremote == 0) (void) atomicio(write, STDERR_FILENO, - buf + 1, strlen(buf + 1)); + buf + 1, strlen(buf + 1)); if (buf[0] == '\02') exit(1); ++errs; @@ -710,25 +687,21 @@ sink(argc, argv) if (ch == '\n') *--cp = 0; -#define getnum(t) (t) = 0; \ - while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0'); cp = buf; if (*cp == 'T') { setimes++; cp++; - getnum(tv[1].tv_sec); - if (*cp++ != ' ') + mtime.tv_sec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') SCREWUP("mtime.sec not delimited"); - getnum(dummy_usec); - tv[1].tv_usec = 0; - if (*cp++ != ' ') + mtime.tv_usec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') SCREWUP("mtime.usec not delimited"); - getnum(tv[0].tv_sec); - if (*cp++ != ' ') + atime.tv_sec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') SCREWUP("atime.sec not delimited"); - getnum(dummy_usec); - tv[0].tv_usec = 0; - if (*cp++ != '\0') + atime.tv_usec = strtol(cp, &cp, 10); + if (!cp || *cp++ != '\0') SCREWUP("atime.usec not delimited"); (void) atomicio(write, remout, "", 1); continue; @@ -756,7 +729,7 @@ sink(argc, argv) if (*cp++ != ' ') SCREWUP("mode not delimited"); - for (size = 0; *cp >= '0' && *cp <= '9';) + for (size = 0; isdigit(*cp);) size = size * 10 + (*cp++ - '0'); if (*cp++ != ' ') SCREWUP("size not delimited"); @@ -766,9 +739,13 @@ sink(argc, argv) size_t need; need = strlen(targ) + strlen(cp) + 250; - if (need > cursize) + if (need > cursize) { + if (namebuf) + xfree(namebuf); namebuf = xmalloc(need); - (void) sprintf(namebuf, "%s%s%s", targ, + cursize = need; + } + (void) snprintf(namebuf, need, "%s%s%s", targ, *targ ? "/" : "", cp); np = namebuf; } else @@ -791,16 +768,18 @@ sink(argc, argv) if (mkdir(np, mode | S_IRWXU) < 0) goto bad; } - vect[0] = np; + vect[0] = xstrdup(np); sink(1, vect); if (setimes) { setimes = 0; - if (utimes(np, tv) < 0) + if (utimes(vect[0], tv) < 0) run_err("%s: set times: %s", - np, strerror(errno)); + vect[0], strerror(errno)); } if (mod_flag) - (void) chmod(np, mode); + (void) chmod(vect[0], mode); + if (vect[0]) + xfree(vect[0]); continue; } omode = mode; @@ -833,7 +812,7 @@ bad: run_err("%s: %s", np, strerror(errno)); continue; } else if (j <= 0) { run_err("%s", j ? strerror(errno) : - "dropped connection"); + "dropped connection"); exit(1); } amt -= j; @@ -870,12 +849,12 @@ bad: run_err("%s: %s", np, strerror(errno)); if (exists || omode != mode) if (fchmod(ofd, omode)) run_err("%s: set mode: %s", - np, strerror(errno)); + np, strerror(errno)); } else { if (!exists && omode != mode) if (fchmod(ofd, omode & ~mask)) run_err("%s: set mode: %s", - np, strerror(errno)); + np, strerror(errno)); } if (close(ofd) == -1) { wrerr = YES; @@ -886,7 +865,7 @@ bad: run_err("%s: %s", np, strerror(errno)); setimes = 0; if (utimes(np, tv) < 0) { run_err("%s: set times: %s", - np, strerror(errno)); + np, strerror(errno)); wrerr = DISPLAYED; } } @@ -943,8 +922,8 @@ void usage() { (void) fprintf(stderr, "usage: scp " - "[-pqrvC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2; or:\n" - " scp [options] f1 ... fn directory\n"); + "[-pqrvBC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2\n" + " or: scp [options] f1 ... fn directory\n"); exit(1); } @@ -971,30 +950,6 @@ run_err(const char *fmt,...) va_end(ap); } -char * -colon(cp) - char *cp; -{ - int flag = 0; - - if (*cp == ':') /* Leading colon is part of file name. */ - return (0); - if (*cp == '[') - flag = 1; - - for (; *cp; ++cp) { - if (*cp == '@' && *(cp+1) == '[') - flag = 1; - if (*cp == ']' && *(cp+1) == ':' && flag) - return (cp+1); - if (*cp == ':' && !flag) - return (cp); - if (*cp == '/') - return (0); - } - return (0); -} - void verifydir(cp) char *cp; @@ -1022,7 +977,8 @@ okname(cp0) c = *cp; if (c & 0200) goto bad; - if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-' && c != '.') + if (!isalpha(c) && !isdigit(c) && + c != '_' && c != '-' && c != '.' && c != '+') goto bad; } while (*++cp); return (1); @@ -1089,7 +1045,7 @@ updateprogressmeter(int ignore) } int -foregroundproc() +foregroundproc(void) { static pid_t pgrp = -1; int ctty_pgrp; @@ -1147,9 +1103,9 @@ progressmeter(int flag) i++; abbrevsize >>= 10; } - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5qd %c%c ", - (quad_t) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : - 'B'); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5llu %c%c ", + (unsigned long long) abbrevsize, prefixes[i], + prefixes[i] == ' ' ? ' ' : 'B'); timersub(&now, &lastupdate, &wait); if (cursize > lastsize) { @@ -1164,16 +1120,17 @@ progressmeter(int flag) timersub(&now, &start, &td); elapsed = td.tv_sec + (td.tv_usec / 1000000.0); - if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) { + if (flag != 1 && + (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " --:-- ETA"); + " --:-- ETA"); } else if (wait.tv_sec >= STALLTIME) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " - stalled -"); + " - stalled -"); } else { if (flag != 1) - remaining = - (int)(totalbytes / (statbytes / elapsed) - elapsed); + remaining = (int)(totalbytes / (statbytes / elapsed) - + elapsed); else remaining = elapsed; diff --git a/crypto/openssh/scp/Makefile b/crypto/openssh/scp/Makefile index fc45dfd..454682a 100644 --- a/crypto/openssh/scp/Makefile +++ b/crypto/openssh/scp/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.12 2001/04/16 02:31:48 mouring Exp $ + .PATH: ${.CURDIR}/.. PROG= scp @@ -8,6 +10,6 @@ BINMODE?=555 BINDIR= /usr/bin MAN= scp.1 -SRCS= scp.c +SRCS= scp.c scp-common.c .include <bsd.prog.mk> diff --git a/crypto/openssh/serverloop.h b/crypto/openssh/serverloop.h new file mode 100644 index 0000000..652c1d9 --- /dev/null +++ b/crypto/openssh/serverloop.h @@ -0,0 +1,22 @@ +/* $OpenBSD: serverloop.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* + * Performs the interactive session. This handles data transmission between + * the client and the program. Note that the notion of stdin, stdout, and + * stderr in this function is sort of reversed: this function writes to stdin + * (of the child program), and reads from stdout and stderr (of the child + * program). + */ +void server_loop(pid_t pid, int fdin, int fdout, int fderr); +void server_loop2(void); diff --git a/crypto/openssh/session.h b/crypto/openssh/session.h index bce99f7..842e941 100644 --- a/crypto/openssh/session.h +++ b/crypto/openssh/session.h @@ -1,3 +1,5 @@ +/* $OpenBSD: session.h,v 1.6 2001/03/21 11:43:45 markus Exp $ */ + /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -24,11 +26,8 @@ #ifndef SESSION_H #define SESSION_H -/* SSH1 */ -void do_authenticated(struct passwd * pw); +void do_authenticated(Authctxt *ac); -/* SSH2 */ -void do_authenticated2(void); int session_open(int id); void session_input_channel_req(int id, void *arg); void session_close_by_pid(pid_t pid, int status); diff --git a/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c new file mode 100644 index 0000000..b5d2fd3 --- /dev/null +++ b/crypto/openssh/sftp-client.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2001 Damien Miller. 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. + */ + +/* XXX: memleaks */ +/* XXX: signed vs unsigned */ +/* XXX: redesign to allow concurrent overlapped operations */ +/* XXX: we use fatal too much, error may be more appropriate in places */ +/* XXX: copy between two remote sites */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-client.c,v 1.16 2001/04/05 10:42:52 markus Exp $"); + +#include "ssh.h" +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "xmalloc.h" +#include "log.h" +#include "atomicio.h" +#include "pathnames.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" + +/* How much data to read/write at at time during copies */ +/* XXX: what should this be? */ +#define COPY_SIZE 8192 + +/* Message ID */ +static u_int msg_id = 1; + +void +send_msg(int fd, Buffer *m) +{ + int mlen = buffer_len(m); + int len; + Buffer oqueue; + + buffer_init(&oqueue); + buffer_put_int(&oqueue, mlen); + buffer_append(&oqueue, buffer_ptr(m), mlen); + buffer_consume(m, mlen); + + len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue)); + if (len <= 0) + fatal("Couldn't send packet: %s", strerror(errno)); + + buffer_free(&oqueue); +} + +void +get_msg(int fd, Buffer *m) +{ + u_int len, msg_len; + unsigned char buf[4096]; + + len = atomicio(read, fd, buf, 4); + if (len == 0) + fatal("Connection closed"); + else if (len == -1) + fatal("Couldn't read packet: %s", strerror(errno)); + + msg_len = GET_32BIT(buf); + if (msg_len > 256 * 1024) + fatal("Received message too long %d", msg_len); + + while (msg_len) { + len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); + if (len == 0) + fatal("Connection closed"); + else if (len == -1) + fatal("Couldn't read packet: %s", strerror(errno)); + + msg_len -= len; + buffer_append(m, buf, len); + } +} + +void +send_string_request(int fd, u_int id, u_int code, char *s, + u_int len) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, code); + buffer_put_int(&msg, id); + buffer_put_string(&msg, s, len); + send_msg(fd, &msg); + debug3("Sent message fd %d T:%d I:%d", fd, code, id); + buffer_free(&msg); +} + +void +send_string_attrs_request(int fd, u_int id, u_int code, char *s, + u_int len, Attrib *a) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, code); + buffer_put_int(&msg, id); + buffer_put_string(&msg, s, len); + encode_attrib(&msg, a); + send_msg(fd, &msg); + debug3("Sent message fd %d T:%d I:%d", fd, code, id); + buffer_free(&msg); +} + +u_int +get_status(int fd, int expected_id) +{ + Buffer msg; + u_int type, id, status; + + buffer_init(&msg); + get_msg(fd, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + if (type != SSH2_FXP_STATUS) + fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d", + SSH2_FXP_STATUS, type); + + status = buffer_get_int(&msg); + buffer_free(&msg); + + debug3("SSH2_FXP_STATUS %d", status); + + return(status); +} + +char * +get_handle(int fd, u_int expected_id, u_int *len) +{ + Buffer msg; + u_int type, id; + char *handle; + + buffer_init(&msg); + get_msg(fd, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + error("Couldn't get handle: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_HANDLE) + fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d", + SSH2_FXP_HANDLE, type); + + handle = buffer_get_string(&msg, len); + buffer_free(&msg); + + return(handle); +} + +Attrib * +get_decode_stat(int fd, u_int expected_id, int quiet) +{ + Buffer msg; + u_int type, id; + Attrib *a; + + buffer_init(&msg); + get_msg(fd, &msg); + + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + debug3("Received stat reply T:%d I:%d", type, id); + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + if (quiet) + debug("Couldn't stat remote file: %s", fx2txt(status)); + else + error("Couldn't stat remote file: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_ATTRS) { + fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d", + SSH2_FXP_ATTRS, type); + } + a = decode_attrib(&msg); + buffer_free(&msg); + + return(a); +} + +int +do_init(int fd_in, int fd_out) +{ + int type, version; + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_INIT); + buffer_put_int(&msg, SSH2_FILEXFER_VERSION); + send_msg(fd_out, &msg); + + buffer_clear(&msg); + + get_msg(fd_in, &msg); + + /* Expecting a VERSION reply */ + if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { + error("Invalid packet back from SSH2_FXP_INIT (type %d)", + type); + buffer_free(&msg); + return(-1); + } + version = buffer_get_int(&msg); + + debug2("Remote version: %d", version); + + /* Check for extensions */ + while (buffer_len(&msg) > 0) { + char *name = buffer_get_string(&msg, NULL); + char *value = buffer_get_string(&msg, NULL); + + debug2("Init extension: \"%s\"", name); + xfree(name); + xfree(value); + } + + buffer_free(&msg); + + return(version); +} + +int +do_close(int fd_in, int fd_out, char *handle, u_int handle_len) +{ + u_int id, status; + Buffer msg; + + buffer_init(&msg); + + id = msg_id++; + buffer_put_char(&msg, SSH2_FXP_CLOSE); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_CLOSE I:%d", id); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't close file: %s", fx2txt(status)); + + buffer_free(&msg); + + return(status); +} + + +int +do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, + SFTP_DIRENT ***dir) +{ + Buffer msg; + u_int type, id, handle_len, i, expected_id, ents = 0; + char *handle; + + id = msg_id++; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_OPENDIR); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, path); + send_msg(fd_out, &msg); + + buffer_clear(&msg); + + handle = get_handle(fd_in, id, &handle_len); + if (handle == NULL) + return(-1); + + if (dir) { + ents = 0; + *dir = xmalloc(sizeof(**dir)); + (*dir)[0] = NULL; + } + + + for(;;) { + int count; + + id = expected_id = msg_id++; + + debug3("Sending SSH2_FXP_READDIR I:%d", id); + + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_READDIR); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + send_msg(fd_out, &msg); + + buffer_clear(&msg); + + get_msg(fd_in, &msg); + + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + debug3("Received reply T:%d I:%d", type, id); + + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + debug3("Received SSH2_FXP_STATUS %d", status); + + if (status == SSH2_FX_EOF) { + break; + } else { + error("Couldn't read directory: %s", + fx2txt(status)); + do_close(fd_in, fd_out, handle, handle_len); + return(status); + } + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count == 0) + break; + debug3("Received %d SSH2_FXP_NAME responses", count); + for(i = 0; i < count; i++) { + char *filename, *longname; + Attrib *a; + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + if (printflag) + printf("%s\n", longname); + + if (dir) { + *dir = xrealloc(*dir, sizeof(**dir) * + (ents + 2)); + (*dir)[ents] = xmalloc(sizeof(***dir)); + (*dir)[ents]->filename = xstrdup(filename); + (*dir)[ents]->longname = xstrdup(longname); + memcpy(&(*dir)[ents]->a, a, sizeof(*a)); + (*dir)[++ents] = NULL; + } + + xfree(filename); + xfree(longname); + } + } + + buffer_free(&msg); + do_close(fd_in, fd_out, handle, handle_len); + xfree(handle); + + return(0); +} + +int +do_ls(int fd_in, int fd_out, char *path) +{ + return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); +} + +int +do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) +{ + return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); +} + +void free_sftp_dirents(SFTP_DIRENT **s) +{ + int i; + + for(i = 0; s[i]; i++) { + xfree(s[i]->filename); + xfree(s[i]->longname); + xfree(s[i]); + } + xfree(s); +} + +int +do_rm(int fd_in, int fd_out, char *path) +{ + u_int status, id; + + debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); + + id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't delete file: %s", fx2txt(status)); + return(status); +} + +int +do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) +{ + u_int status, id; + + id = msg_id++; + send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path, + strlen(path), a); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't create directory: %s", fx2txt(status)); + + return(status); +} + +int +do_rmdir(int fd_in, int fd_out, char *path) +{ + u_int status, id; + + id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't remove directory: %s", fx2txt(status)); + + return(status); +} + +Attrib * +do_stat(int fd_in, int fd_out, char *path, int quiet) +{ + u_int id; + + id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); + return(get_decode_stat(fd_in, id, quiet)); +} + +Attrib * +do_lstat(int fd_in, int fd_out, char *path, int quiet) +{ + u_int id; + + id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); + return(get_decode_stat(fd_in, id, quiet)); +} + +Attrib * +do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet) +{ + u_int id; + + id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); + return(get_decode_stat(fd_in, id, quiet)); +} + +int +do_setstat(int fd_in, int fd_out, char *path, Attrib *a) +{ + u_int status, id; + + id = msg_id++; + send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path, + strlen(path), a); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't setstat on \"%s\": %s", path, + fx2txt(status)); + + return(status); +} + +int +do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, + Attrib *a) +{ + u_int status, id; + + id = msg_id++; + send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle, + handle_len, a); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't fsetstat: %s", fx2txt(status)); + + return(status); +} + +char * +do_realpath(int fd_in, int fd_out, char *path) +{ + Buffer msg; + u_int type, expected_id, count, id; + char *filename, *longname; + Attrib *a; + + expected_id = id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); + + buffer_init(&msg); + + get_msg(fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + u_int status = buffer_get_int(&msg); + + error("Couldn't canonicalise: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count != 1) + fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + debug3("SSH_FXP_REALPATH %s -> %s", path, filename); + + xfree(longname); + + buffer_free(&msg); + + return(filename); +} + +int +do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) +{ + Buffer msg; + u_int status, id; + + buffer_init(&msg); + + /* Send rename request */ + id = msg_id++; + buffer_put_char(&msg, SSH2_FXP_RENAME); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, oldpath); + buffer_put_cstring(&msg, newpath); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, + newpath); + buffer_free(&msg); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, + fx2txt(status)); + + return(status); +} + +int +do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath) +{ + Buffer msg; + u_int status, id; + + buffer_init(&msg); + + /* Send rename request */ + id = msg_id++; + buffer_put_char(&msg, SSH2_FXP_SYMLINK); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, oldpath); + buffer_put_cstring(&msg, newpath); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, + newpath); + buffer_free(&msg); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, + fx2txt(status)); + + return(status); +} + +char * +do_readlink(int fd_in, int fd_out, char *path) +{ + Buffer msg; + u_int type, expected_id, count, id; + char *filename, *longname; + Attrib *a; + + expected_id = id = msg_id++; + send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); + + buffer_init(&msg); + + get_msg(fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + u_int status = buffer_get_int(&msg); + + error("Couldn't readlink: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count != 1) + fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + debug3("SSH_FXP_READLINK %s -> %s", path, filename); + + xfree(longname); + + buffer_free(&msg); + + return(filename); +} + +int +do_download(int fd_in, int fd_out, char *remote_path, char *local_path, + int pflag) +{ + int local_fd; + u_int expected_id, handle_len, mode, type, id; + u_int64_t offset; + char *handle; + Buffer msg; + Attrib junk, *a; + int status; + + a = do_stat(fd_in, fd_out, remote_path, 0); + if (a == NULL) + return(-1); + + /* XXX: should we preserve set[ug]id? */ + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + mode = S_IWRITE | (a->perm & 0777); + else + mode = 0666; + + if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + (a->perm & S_IFDIR)) { + error("Cannot download a directory: %s", remote_path); + return(-1); + } + + local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (local_fd == -1) { + error("Couldn't open local file \"%s\" for writing: %s", + local_path, strerror(errno)); + return(-1); + } + + buffer_init(&msg); + + /* Send open request */ + id = msg_id++; + buffer_put_char(&msg, SSH2_FXP_OPEN); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, remote_path); + buffer_put_int(&msg, SSH2_FXF_READ); + attrib_clear(&junk); /* Send empty attributes */ + encode_attrib(&msg, &junk); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); + + handle = get_handle(fd_in, id, &handle_len); + if (handle == NULL) { + buffer_free(&msg); + close(local_fd); + return(-1); + } + + /* Read from remote and write to local */ + offset = 0; + for(;;) { + u_int len; + char *data; + + id = expected_id = msg_id++; + + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_READ); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + buffer_put_int64(&msg, offset); + buffer_put_int(&msg, COPY_SIZE); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u", + id, (unsigned long long)offset, COPY_SIZE); + + buffer_clear(&msg); + + get_msg(fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + debug3("Received reply T:%d I:%d", type, id); + if (id != expected_id) + fatal("ID mismatch (%d != %d)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + status = buffer_get_int(&msg); + + if (status == SSH2_FX_EOF) + break; + else { + error("Couldn't read from remote " + "file \"%s\" : %s", remote_path, + fx2txt(status)); + do_close(fd_in, fd_out, handle, handle_len); + goto done; + } + } else if (type != SSH2_FXP_DATA) { + fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", + SSH2_FXP_DATA, type); + } + + data = buffer_get_string(&msg, &len); + if (len > COPY_SIZE) + fatal("Received more data than asked for %d > %d", + len, COPY_SIZE); + + debug3("In read loop, got %d offset %llu", len, + (unsigned long long)offset); + if (atomicio(write, local_fd, data, len) != len) { + error("Couldn't write to \"%s\": %s", local_path, + strerror(errno)); + do_close(fd_in, fd_out, handle, handle_len); + status = -1; + xfree(data); + goto done; + } + + offset += len; + xfree(data); + } + status = do_close(fd_in, fd_out, handle, handle_len); + + /* Override umask and utimes if asked */ + if (pflag && fchmod(local_fd, mode) == -1) + error("Couldn't set mode on \"%s\": %s", local_path, + strerror(errno)); + if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { + struct timeval tv[2]; + tv[0].tv_sec = a->atime; + tv[1].tv_sec = a->mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(local_path, tv) == -1) + error("Can't set times on \"%s\": %s", local_path, + strerror(errno)); + } + +done: + close(local_fd); + buffer_free(&msg); + xfree(handle); + return status; +} + +int +do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, + int pflag) +{ + int local_fd; + u_int handle_len, id; + u_int64_t offset; + char *handle; + Buffer msg; + struct stat sb; + Attrib a; + int status; + + if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { + error("Couldn't open local file \"%s\" for reading: %s", + local_path, strerror(errno)); + return(-1); + } + if (fstat(local_fd, &sb) == -1) { + error("Couldn't fstat local file \"%s\": %s", + local_path, strerror(errno)); + close(local_fd); + return(-1); + } + stat_to_attrib(&sb, &a); + + a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; + a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; + a.perm &= 0777; + if (!pflag) + a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; + + buffer_init(&msg); + + /* Send open request */ + id = msg_id++; + buffer_put_char(&msg, SSH2_FXP_OPEN); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, remote_path); + buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); + encode_attrib(&msg, &a); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); + + buffer_clear(&msg); + + handle = get_handle(fd_in, id, &handle_len); + if (handle == NULL) { + close(local_fd); + buffer_free(&msg); + return(-1); + } + + /* Read from local and write to remote */ + offset = 0; + for(;;) { + int len; + char data[COPY_SIZE]; + + /* + * Can't use atomicio here because it returns 0 on EOF, thus losing + * the last block of the file + */ + do + len = read(local_fd, data, COPY_SIZE); + while ((len == -1) && (errno == EINTR || errno == EAGAIN)); + + if (len == -1) + fatal("Couldn't read from \"%s\": %s", local_path, + strerror(errno)); + if (len == 0) + break; + + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_WRITE); + buffer_put_int(&msg, ++id); + buffer_put_string(&msg, handle, handle_len); + buffer_put_int64(&msg, offset); + buffer_put_string(&msg, data, len); + send_msg(fd_out, &msg); + debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", + id, (unsigned long long)offset, len); + + status = get_status(fd_in, id); + if (status != SSH2_FX_OK) { + error("Couldn't write to remote file \"%s\": %s", + remote_path, fx2txt(status)); + do_close(fd_in, fd_out, handle, handle_len); + close(local_fd); + goto done; + } + debug3("In write loop, got %d offset %llu", len, + (unsigned long long)offset); + + offset += len; + } + + if (close(local_fd) == -1) { + error("Couldn't close local file \"%s\": %s", local_path, + strerror(errno)); + do_close(fd_in, fd_out, handle, handle_len); + status = -1; + goto done; + } + + /* Override umask and utimes if asked */ + if (pflag) + do_fsetstat(fd_in, fd_out, handle, handle_len, &a); + + status = do_close(fd_in, fd_out, handle, handle_len); + +done: + xfree(handle); + buffer_free(&msg); + return status; +} + diff --git a/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h new file mode 100644 index 0000000..09ffcc0 --- /dev/null +++ b/crypto/openssh/sftp-client.h @@ -0,0 +1,107 @@ +/* $OpenBSD: sftp-client.h,v 1.5 2001/04/05 10:42:52 markus Exp $ */ + +/* + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Client side of SSH2 filexfer protocol */ + +typedef struct SFTP_DIRENT SFTP_DIRENT; + +struct SFTP_DIRENT { + char *filename; + char *longname; + Attrib a; +}; + +/* + * Initialiase a SSH filexfer connection. Returns -1 on error or + * protocol version on success. + */ +int do_init(int fd_in, int fd_out); + +/* Close file referred to by 'handle' */ +int do_close(int fd_in, int fd_out, char *handle, u_int handle_len); + +/* List contents of directory 'path' to stdout */ +int do_ls(int fd_in, int fd_out, char *path); + +/* Read contents of 'path' to NULL-terminated array 'dir' */ +int do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir); + +/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ +void free_sftp_dirents(SFTP_DIRENT **s); + +/* Delete file 'path' */ +int do_rm(int fd_in, int fd_out, char *path); + +/* Create directory 'path' */ +int do_mkdir(int fd_in, int fd_out, char *path, Attrib *a); + +/* Remove directory 'path' */ +int do_rmdir(int fd_in, int fd_out, char *path); + +/* Get file attributes of 'path' (follows symlinks) */ +Attrib *do_stat(int fd_in, int fd_out, char *path, int quiet); + +/* Get file attributes of 'path' (does not follow symlinks) */ +Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet); + +/* Get file attributes of open file 'handle' */ +Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, + int quiet); + +/* Set file attributes of 'path' */ +int do_setstat(int fd_in, int fd_out, char *path, Attrib *a); + +/* Set file attributes of open file 'handle' */ +int do_fsetstat(int fd_in, int fd_out, char *handle, + u_int handle_len, Attrib *a); + +/* Canonicalise 'path' - caller must free result */ +char *do_realpath(int fd_in, int fd_out, char *path); + +/* Rename 'oldpath' to 'newpath' */ +int do_rename(int fd_in, int fd_out, char *oldpath, char *newpath); + +/* Rename 'oldpath' to 'newpath' */ +int do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath); + +/* Return target of symlink 'path' - caller must free result */ +char *do_readlink(int fd_in, int fd_out, char *path); + +/* XXX: add callbacks to do_download/do_upload so we can do progress meter */ + +/* + * Download 'remote_path' to 'local_path'. Preserve permissions and times + * if 'pflag' is set + */ +int do_download(int fd_in, int fd_out, char *remote_path, char *local_path, + int pflag); + +/* + * Upload 'local_path' to 'remote_path'. Preserve permissions and times + * if 'pflag' is set + */ +int do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, + int pflag); diff --git a/crypto/openssh/sftp-common.c b/crypto/openssh/sftp-common.c new file mode 100644 index 0000000..3310eab --- /dev/null +++ b/crypto/openssh/sftp-common.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-common.c,v 1.2 2001/02/06 23:50:10 markus Exp $"); + +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "log.h" +#include "xmalloc.h" + +#include "sftp.h" +#include "sftp-common.h" + +void +attrib_clear(Attrib *a) +{ + a->flags = 0; + a->size = 0; + a->uid = 0; + a->gid = 0; + a->perm = 0; + a->atime = 0; + a->mtime = 0; +} + +void +stat_to_attrib(struct stat *st, Attrib *a) +{ + attrib_clear(a); + a->flags = 0; + a->flags |= SSH2_FILEXFER_ATTR_SIZE; + a->size = st->st_size; + a->flags |= SSH2_FILEXFER_ATTR_UIDGID; + a->uid = st->st_uid; + a->gid = st->st_gid; + a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a->perm = st->st_mode; + a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME; + a->atime = st->st_atime; + a->mtime = st->st_mtime; +} + +Attrib * +decode_attrib(Buffer *b) +{ + static Attrib a; + attrib_clear(&a); + a.flags = buffer_get_int(b); + if (a.flags & SSH2_FILEXFER_ATTR_SIZE) + a.size = buffer_get_int64(b); + if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { + a.uid = buffer_get_int(b); + a.gid = buffer_get_int(b); + } + if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + a.perm = buffer_get_int(b); + if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + a.atime = buffer_get_int(b); + a.mtime = buffer_get_int(b); + } + /* vendor-specific extensions */ + if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) { + char *type, *data; + int i, count; + count = buffer_get_int(b); + for (i = 0; i < count; i++) { + type = buffer_get_string(b, NULL); + data = buffer_get_string(b, NULL); + debug3("Got file attribute \"%s\"", type); + xfree(type); + xfree(data); + } + } + return &a; +} + +void +encode_attrib(Buffer *b, Attrib *a) +{ + buffer_put_int(b, a->flags); + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) + buffer_put_int64(b, a->size); + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + buffer_put_int(b, a->uid); + buffer_put_int(b, a->gid); + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + buffer_put_int(b, a->perm); + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + buffer_put_int(b, a->atime); + buffer_put_int(b, a->mtime); + } +} + +const char * +fx2txt(int status) +{ + switch (status) { + case SSH2_FX_OK: + return("No error"); + case SSH2_FX_EOF: + return("End of file"); + case SSH2_FX_NO_SUCH_FILE: + return("No such file or directory"); + case SSH2_FX_PERMISSION_DENIED: + return("Permission denied"); + case SSH2_FX_FAILURE: + return("Failure"); + case SSH2_FX_BAD_MESSAGE: + return("Bad message"); + case SSH2_FX_NO_CONNECTION: + return("No connection"); + case SSH2_FX_CONNECTION_LOST: + return("Connection lost"); + case SSH2_FX_OP_UNSUPPORTED: + return("Operation unsupported"); + default: + return("Unknown status"); + }; + /* NOTREACHED */ +} + diff --git a/crypto/openssh/sftp-common.h b/crypto/openssh/sftp-common.h new file mode 100644 index 0000000..6dc1a32 --- /dev/null +++ b/crypto/openssh/sftp-common.h @@ -0,0 +1,55 @@ +/* $OpenBSD: sftp-common.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Damien Miller. 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. + */ + +typedef struct Attrib Attrib; + +/* File attributes */ +struct Attrib { + u_int32_t flags; + u_int64_t size; + u_int32_t uid; + u_int32_t gid; + u_int32_t perm; + u_int32_t atime; + u_int32_t mtime; +}; + +/* Clear contents of attributes structure */ +void attrib_clear(Attrib *a); + +/* Convert from struct stat to filexfer attribs */ +void stat_to_attrib(struct stat *st, Attrib *a); + +/* Decode attributes in buffer */ +Attrib *decode_attrib(Buffer *b); + +/* Encode attributes to buffer */ +void encode_attrib(Buffer *b, Attrib *a); + +/* Convert from SSH2_FX_ status to text error message */ +const char *fx2txt(int status); + diff --git a/crypto/openssh/sftp-glob.c b/crypto/openssh/sftp-glob.c new file mode 100644 index 0000000..18d81c0 --- /dev/null +++ b/crypto/openssh/sftp-glob.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-glob.c,v 1.5 2001/04/15 08:43:46 markus Exp $"); + +#include <glob.h> + +#include "ssh.h" +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "xmalloc.h" +#include "log.h" +#include "atomicio.h" +#include "pathnames.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" +#include "sftp-glob.h" + +struct SFTP_OPENDIR { + SFTP_DIRENT **dir; + int offset; +}; + +static struct { + int fd_in; + int fd_out; +} cur; + +void *fudge_opendir(const char *path) +{ + struct SFTP_OPENDIR *r; + + r = xmalloc(sizeof(*r)); + + if (do_readdir(cur.fd_in, cur.fd_out, (char*)path, &r->dir)) + return(NULL); + + r->offset = 0; + + return((void*)r); +} + +struct dirent *fudge_readdir(struct SFTP_OPENDIR *od) +{ + static struct dirent ret; + + if (od->dir[od->offset] == NULL) + return(NULL); + + memset(&ret, 0, sizeof(ret)); + strlcpy(ret.d_name, od->dir[od->offset++]->filename, + sizeof(ret.d_name)); + + return(&ret); +} + +void fudge_closedir(struct SFTP_OPENDIR *od) +{ + free_sftp_dirents(od->dir); + xfree(od); +} + +void attrib_to_stat(Attrib *a, struct stat *st) +{ + memset(st, 0, sizeof(*st)); + + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) + st->st_size = a->size; + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + st->st_uid = a->uid; + st->st_gid = a->gid; + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + st->st_mode = a->perm; + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + st->st_atime = a->atime; + st->st_mtime = a->mtime; + } +} + +int fudge_lstat(const char *path, struct stat *st) +{ + Attrib *a; + + if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0))) + return(-1); + + attrib_to_stat(a, st); + + return(0); +} + +int fudge_stat(const char *path, struct stat *st) +{ + Attrib *a; + + if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0))) + return(-1); + + attrib_to_stat(a, st); + + return(0); +} + +int +remote_glob(int fd_in, int fd_out, const char *pattern, int flags, + int (*errfunc)(const char *, int), glob_t *pglob) +{ + pglob->gl_opendir = (void*)fudge_opendir; + pglob->gl_readdir = (void*)fudge_readdir; + pglob->gl_closedir = (void*)fudge_closedir; + pglob->gl_lstat = fudge_lstat; + pglob->gl_stat = fudge_stat; + + memset(&cur, 0, sizeof(cur)); + cur.fd_in = fd_in; + cur.fd_out = fd_out; + + return(glob(pattern, flags | GLOB_ALTDIRFUNC, (void*)errfunc, + pglob)); +} diff --git a/crypto/openssh/sftp-glob.h b/crypto/openssh/sftp-glob.h new file mode 100644 index 0000000..4206af4 --- /dev/null +++ b/crypto/openssh/sftp-glob.h @@ -0,0 +1,32 @@ +/* $OpenBSD: sftp-glob.h,v 1.3 2001/04/15 08:43:46 markus Exp $ */ + +/* + * Copyright (c) 2001 Damien Miller. 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. + */ + +/* Remote sftp filename globbing */ + +int +remote_glob(int fd_in, int fd_out, const char *pattern, int flags, + int (*errfunc)(const char *, int), glob_t *pglob); + diff --git a/crypto/openssh/sftp-int.c b/crypto/openssh/sftp-int.c new file mode 100644 index 0000000..3a71daa --- /dev/null +++ b/crypto/openssh/sftp-int.c @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2001 Damien Miller. 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. + */ + +/* XXX: globbed ls */ +/* XXX: recursive operations */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-int.c,v 1.36 2001/04/15 08:43:46 markus Exp $"); + +#include <glob.h> + +#include "buffer.h" +#include "xmalloc.h" +#include "log.h" +#include "pathnames.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-glob.h" +#include "sftp-client.h" +#include "sftp-int.h" + +/* File to read commands from */ +extern FILE *infile; + +/* Version of server we are speaking to */ +int version; + +/* Seperators for interactive commands */ +#define WHITESPACE " \t\r\n" + +/* Commands for interactive mode */ +#define I_CHDIR 1 +#define I_CHGRP 2 +#define I_CHMOD 3 +#define I_CHOWN 4 +#define I_GET 5 +#define I_HELP 6 +#define I_LCHDIR 7 +#define I_LLS 8 +#define I_LMKDIR 9 +#define I_LPWD 10 +#define I_LS 11 +#define I_LUMASK 12 +#define I_MKDIR 13 +#define I_PUT 14 +#define I_PWD 15 +#define I_QUIT 16 +#define I_RENAME 17 +#define I_RM 18 +#define I_RMDIR 19 +#define I_SHELL 20 +#define I_SYMLINK 21 +#define I_VERSION 22 + +struct CMD { + const char *c; + const int n; +}; + +const struct CMD cmds[] = { + { "cd", I_CHDIR }, + { "chdir", I_CHDIR }, + { "chgrp", I_CHGRP }, + { "chmod", I_CHMOD }, + { "chown", I_CHOWN }, + { "dir", I_LS }, + { "exit", I_QUIT }, + { "get", I_GET }, + { "mget", I_GET }, + { "help", I_HELP }, + { "lcd", I_LCHDIR }, + { "lchdir", I_LCHDIR }, + { "lls", I_LLS }, + { "lmkdir", I_LMKDIR }, + { "ln", I_SYMLINK }, + { "lpwd", I_LPWD }, + { "ls", I_LS }, + { "lumask", I_LUMASK }, + { "mkdir", I_MKDIR }, + { "put", I_PUT }, + { "mput", I_PUT }, + { "pwd", I_PWD }, + { "quit", I_QUIT }, + { "rename", I_RENAME }, + { "rm", I_RM }, + { "rmdir", I_RMDIR }, + { "symlink", I_SYMLINK }, + { "version", I_VERSION }, + { "!", I_SHELL }, + { "?", I_HELP }, + { NULL, -1} +}; + +void +help(void) +{ + printf("Available commands:\n"); + printf("cd path Change remote directory to 'path'\n"); + printf("lcd path Change local directory to 'path'\n"); + printf("chgrp grp path Change group of file 'path' to 'grp'\n"); + printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); + printf("chown own path Change owner of file 'path' to 'own'\n"); + printf("help Display this help text\n"); + printf("get remote-path [local-path] Download file\n"); + printf("lls [ls-options [path]] Display local directory listing\n"); + printf("ln oldpath newpath Symlink remote file\n"); + printf("lmkdir path Create local directory\n"); + printf("lpwd Print local working directory\n"); + printf("ls [path] Display remote directory listing\n"); + printf("lumask umask Set local umask to 'umask'\n"); + printf("mkdir path Create remote directory\n"); + printf("put local-path [remote-path] Upload file\n"); + printf("pwd Display remote working directory\n"); + printf("exit Quit sftp\n"); + printf("quit Quit sftp\n"); + printf("rename oldpath newpath Rename remote file\n"); + printf("rmdir path Remove remote directory\n"); + printf("rm path Delete remote file\n"); + printf("symlink oldpath newpath Symlink remote file\n"); + printf("version Show SFTP version\n"); + printf("!command Execute 'command' in local shell\n"); + printf("! Escape to local shell\n"); + printf("? Synonym for help\n"); +} + +void +local_do_shell(const char *args) +{ + int status; + char *shell; + pid_t pid; + + if (!*args) + args = NULL; + + if ((shell = getenv("SHELL")) == NULL) + shell = _PATH_BSHELL; + + if ((pid = fork()) == -1) + fatal("Couldn't fork: %s", strerror(errno)); + + if (pid == 0) { + /* XXX: child has pipe fds to ssh subproc open - issue? */ + if (args) { + debug3("Executing %s -c \"%s\"", shell, args); + execl(shell, shell, "-c", args, NULL); + } else { + debug3("Executing %s", shell); + execl(shell, shell, NULL); + } + fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, + strerror(errno)); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) + fatal("Couldn't wait for child: %s", strerror(errno)); + if (!WIFEXITED(status)) + error("Shell exited abormally"); + else if (WEXITSTATUS(status)) + error("Shell exited with status %d", WEXITSTATUS(status)); +} + +void +local_do_ls(const char *args) +{ + if (!args || !*args) + local_do_shell(_PATH_LS); + else { + int len = strlen(_PATH_LS " ") + strlen(args) + 1; + char *buf = xmalloc(len); + + /* XXX: quoting - rip quoting code from ftp? */ + snprintf(buf, len, _PATH_LS " %s", args); + local_do_shell(buf); + xfree(buf); + } +} + +char * +path_append(char *p1, char *p2) +{ + char *ret; + int len = strlen(p1) + strlen(p2) + 2; + + ret = xmalloc(len); + strlcpy(ret, p1, len); + strlcat(ret, "/", len); + strlcat(ret, p2, len); + + return(ret); +} + +char * +make_absolute(char *p, char *pwd) +{ + char *abs; + + /* Derelativise */ + if (p && p[0] != '/') { + abs = path_append(pwd, p); + xfree(p); + return(abs); + } else + return(p); +} + +int +infer_path(const char *p, char **ifp) +{ + char *cp; + + cp = strrchr(p, '/'); + if (cp == NULL) { + *ifp = xstrdup(p); + return(0); + } + + if (!cp[1]) { + error("Invalid path"); + return(-1); + } + + *ifp = xstrdup(cp + 1); + return(0); +} + +int +parse_getput_flags(const char **cpp, int *pflag) +{ + const char *cp = *cpp; + + /* Check for flags */ + if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { + switch (cp[1]) { + case 'p': + case 'P': + *pflag = 1; + break; + default: + error("Invalid flag -%c", cp[1]); + return(-1); + } + cp += 2; + *cpp = cp + strspn(cp, WHITESPACE); + } + + return(0); +} + +int +get_pathname(const char **cpp, char **path) +{ + const char *cp = *cpp, *end; + char quot; + int i; + + cp += strspn(cp, WHITESPACE); + if (!*cp) { + *cpp = cp; + *path = NULL; + return (0); + } + + /* Check for quoted filenames */ + if (*cp == '\"' || *cp == '\'') { + quot = *cp++; + + end = strchr(cp, quot); + if (end == NULL) { + error("Unterminated quote"); + goto fail; + } + if (cp == end) { + error("Empty quotes"); + goto fail; + } + *cpp = end + 1 + strspn(end + 1, WHITESPACE); + } else { + /* Read to end of filename */ + end = strpbrk(cp, WHITESPACE); + if (end == NULL) + end = strchr(cp, '\0'); + *cpp = end + strspn(end, WHITESPACE); + } + + i = end - cp; + + *path = xmalloc(i + 1); + memcpy(*path, cp, i); + (*path)[i] = '\0'; + return(0); + + fail: + *path = NULL; + return (-1); +} + +int +is_dir(char *path) +{ + struct stat sb; + + /* XXX: report errors? */ + if (stat(path, &sb) == -1) + return(0); + + return(sb.st_mode & S_IFDIR); +} + +int +remote_is_dir(int in, int out, char *path) +{ + Attrib *a; + + /* XXX: report errors? */ + if ((a = do_stat(in, out, path, 1)) == NULL) + return(0); + if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) + return(0); + return(a->perm & S_IFDIR); +} + +int +process_get(int in, int out, char *src, char *dst, char *pwd, int pflag) +{ + char *abs_src = NULL; + char *abs_dst = NULL; + char *tmp; + glob_t g; + int err = 0; + int i; + + abs_src = xstrdup(src); + abs_src = make_absolute(abs_src, pwd); + + memset(&g, 0, sizeof(g)); + debug3("Looking up %s", abs_src); + if (remote_glob(in, out, abs_src, 0, NULL, &g)) { + error("File \"%s\" not found.", abs_src); + err = -1; + goto out; + } + + /* Only one match, dst may be file, directory or unspecified */ + if (g.gl_pathv[0] && g.gl_matchc == 1) { + if (dst) { + /* If directory specified, append filename */ + if (is_dir(dst)) { + if (infer_path(g.gl_pathv[0], &tmp)) { + err = 1; + goto out; + } + abs_dst = path_append(dst, tmp); + xfree(tmp); + } else + abs_dst = xstrdup(dst); + } else if (infer_path(g.gl_pathv[0], &abs_dst)) { + err = -1; + goto out; + } + printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); + err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag); + goto out; + } + + /* Multiple matches, dst may be directory or unspecified */ + if (dst && !is_dir(dst)) { + error("Multiple files match, but \"%s\" is not a directory", + dst); + err = -1; + goto out; + } + + for(i = 0; g.gl_pathv[i]; i++) { + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + if (dst) { + abs_dst = path_append(dst, tmp); + xfree(tmp); + } else + abs_dst = tmp; + + printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); + if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + xfree(abs_dst); + abs_dst = NULL; + } + +out: + xfree(abs_src); + if (abs_dst) + xfree(abs_dst); + globfree(&g); + return(err); +} + +int +process_put(int in, int out, char *src, char *dst, char *pwd, int pflag) +{ + char *tmp_dst = NULL; + char *abs_dst = NULL; + char *tmp; + glob_t g; + int err = 0; + int i; + + if (dst) { + tmp_dst = xstrdup(dst); + tmp_dst = make_absolute(tmp_dst, pwd); + } + + memset(&g, 0, sizeof(g)); + debug3("Looking up %s", src); + if (glob(src, 0, NULL, &g)) { + error("File \"%s\" not found.", src); + err = -1; + goto out; + } + + /* Only one match, dst may be file, directory or unspecified */ + if (g.gl_pathv[0] && g.gl_matchc == 1) { + if (tmp_dst) { + /* If directory specified, append filename */ + if (remote_is_dir(in, out, tmp_dst)) { + if (infer_path(g.gl_pathv[0], &tmp)) { + err = 1; + goto out; + } + abs_dst = path_append(tmp_dst, tmp); + xfree(tmp); + } else + abs_dst = xstrdup(tmp_dst); + } else { + if (infer_path(g.gl_pathv[0], &abs_dst)) { + err = -1; + goto out; + } + abs_dst = make_absolute(abs_dst, pwd); + } + printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst); + err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag); + goto out; + } + + /* Multiple matches, dst may be directory or unspecified */ + if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) { + error("Multiple files match, but \"%s\" is not a directory", + tmp_dst); + err = -1; + goto out; + } + + for(i = 0; g.gl_pathv[i]; i++) { + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + if (tmp_dst) { + abs_dst = path_append(tmp_dst, tmp); + xfree(tmp); + } else + abs_dst = make_absolute(tmp, pwd); + + printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); + if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + } + +out: + if (abs_dst) + xfree(abs_dst); + if (tmp_dst) + xfree(tmp_dst); + return(err); +} + +int +parse_args(const char **cpp, int *pflag, unsigned long *n_arg, + char **path1, char **path2) +{ + const char *cmd, *cp = *cpp; + char *cp2; + int base = 0; + long l; + int i, cmdnum; + + /* Skip leading whitespace */ + cp = cp + strspn(cp, WHITESPACE); + + /* Ignore blank lines */ + if (!*cp) + return(-1); + + /* Figure out which command we have */ + for(i = 0; cmds[i].c; i++) { + int cmdlen = strlen(cmds[i].c); + + /* Check for command followed by whitespace */ + if (!strncasecmp(cp, cmds[i].c, cmdlen) && + strchr(WHITESPACE, cp[cmdlen])) { + cp += cmdlen; + cp = cp + strspn(cp, WHITESPACE); + break; + } + } + cmdnum = cmds[i].n; + cmd = cmds[i].c; + + /* Special case */ + if (*cp == '!') { + cp++; + cmdnum = I_SHELL; + } else if (cmdnum == -1) { + error("Invalid command."); + return(-1); + } + + /* Get arguments and parse flags */ + *pflag = *n_arg = 0; + *path1 = *path2 = NULL; + switch (cmdnum) { + case I_GET: + case I_PUT: + if (parse_getput_flags(&cp, pflag)) + return(-1); + /* Get first pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify at least one path after a " + "%s command.", cmd); + return(-1); + } + /* Try to get second pathname (optional) */ + if (get_pathname(&cp, path2)) + return(-1); + break; + case I_RENAME: + case I_SYMLINK: + if (get_pathname(&cp, path1)) + return(-1); + if (get_pathname(&cp, path2)) + return(-1); + if (!*path1 || !*path2) { + error("You must specify two paths after a %s " + "command.", cmd); + return(-1); + } + break; + case I_RM: + case I_MKDIR: + case I_RMDIR: + case I_CHDIR: + case I_LCHDIR: + case I_LMKDIR: + /* Get pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify a path after a %s command.", + cmd); + return(-1); + } + break; + case I_LS: + /* Path is optional */ + if (get_pathname(&cp, path1)) + return(-1); + break; + case I_LLS: + case I_SHELL: + /* Uses the rest of the line */ + break; + case I_LUMASK: + base = 8; + case I_CHMOD: + base = 8; + case I_CHOWN: + case I_CHGRP: + /* Get numeric arg (mandatory) */ + l = strtol(cp, &cp2, base); + if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) && + errno == ERANGE) || l < 0) { + error("You must supply a numeric argument " + "to the %s command.", cmd); + return(-1); + } + cp = cp2; + *n_arg = l; + if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp)) + break; + if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) { + error("You must supply a numeric argument " + "to the %s command.", cmd); + return(-1); + } + cp += strspn(cp, WHITESPACE); + + /* Get pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify a path after a %s command.", + cmd); + return(-1); + } + break; + case I_QUIT: + case I_PWD: + case I_LPWD: + case I_HELP: + case I_VERSION: + break; + default: + fatal("Command not implemented"); + } + + *cpp = cp; + return(cmdnum); +} + +int +parse_dispatch_command(int in, int out, const char *cmd, char **pwd) +{ + char *path1, *path2, *tmp; + int pflag, cmdnum, i; + unsigned long n_arg; + Attrib a, *aa; + char path_buf[MAXPATHLEN]; + int err = 0; + glob_t g; + + path1 = path2 = NULL; + cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); + + memset(&g, 0, sizeof(g)); + + /* Perform command */ + switch (cmdnum) { + case -1: + break; + case I_GET: + err = process_get(in, out, path1, path2, *pwd, pflag); + break; + case I_PUT: + err = process_put(in, out, path1, path2, *pwd, pflag); + break; + case I_RENAME: + path1 = make_absolute(path1, *pwd); + path2 = make_absolute(path2, *pwd); + err = do_rename(in, out, path1, path2); + break; + case I_SYMLINK: + if (version < 3) { + error("The server (version %d) does not support " + "this operation", version); + err = -1; + } else { + path2 = make_absolute(path2, *pwd); + err = do_symlink(in, out, path1, path2); + } + break; + case I_RM: + path1 = make_absolute(path1, *pwd); + remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); + for(i = 0; g.gl_pathv[i]; i++) { + printf("Removing %s\n", g.gl_pathv[i]); + if (do_rm(in, out, g.gl_pathv[i]) == -1) + err = -1; + } + break; + case I_MKDIR: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = 0777; + err = do_mkdir(in, out, path1, &a); + break; + case I_RMDIR: + path1 = make_absolute(path1, *pwd); + err = do_rmdir(in, out, path1); + break; + case I_CHDIR: + path1 = make_absolute(path1, *pwd); + if ((tmp = do_realpath(in, out, path1)) == NULL) { + err = 1; + break; + } + if ((aa = do_stat(in, out, tmp, 0)) == NULL) { + xfree(tmp); + err = 1; + break; + } + if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { + error("Can't change directory: Can't check target"); + xfree(tmp); + err = 1; + break; + } + if (!S_ISDIR(aa->perm)) { + error("Can't change directory: \"%s\" is not " + "a directory", tmp); + xfree(tmp); + err = 1; + break; + } + xfree(*pwd); + *pwd = tmp; + break; + case I_LS: + if (!path1) { + do_ls(in, out, *pwd); + break; + } + path1 = make_absolute(path1, *pwd); + if ((tmp = do_realpath(in, out, path1)) == NULL) + break; + xfree(path1); + path1 = tmp; + if ((aa = do_stat(in, out, path1, 0)) == NULL) + break; + if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + !S_ISDIR(aa->perm)) { + error("Can't ls: \"%s\" is not a directory", path1); + break; + } + do_ls(in, out, path1); + break; + case I_LCHDIR: + if (chdir(path1) == -1) { + error("Couldn't change local directory to " + "\"%s\": %s", path1, strerror(errno)); + err = 1; + } + break; + case I_LMKDIR: + if (mkdir(path1, 0777) == -1) { + error("Couldn't create local directory " + "\"%s\": %s", path1, strerror(errno)); + err = 1; + } + break; + case I_LLS: + local_do_ls(cmd); + break; + case I_SHELL: + local_do_shell(cmd); + break; + case I_LUMASK: + umask(n_arg); + printf("Local umask: %03lo\n", n_arg); + break; + case I_CHMOD: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = n_arg; + remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); + for(i = 0; g.gl_pathv[i]; i++) { + printf("Changing mode on %s\n", g.gl_pathv[i]); + do_setstat(in, out, g.gl_pathv[i], &a); + } + break; + case I_CHOWN: + path1 = make_absolute(path1, *pwd); + remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); + for(i = 0; g.gl_pathv[i]; i++) { + if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) + continue; + if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { + error("Can't get current ownership of " + "remote file \"%s\"", g.gl_pathv[i]); + continue; + } + printf("Changing owner on %s\n", g.gl_pathv[i]); + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; + aa->uid = n_arg; + do_setstat(in, out, g.gl_pathv[i], aa); + } + break; + case I_CHGRP: + path1 = make_absolute(path1, *pwd); + remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); + for(i = 0; g.gl_pathv[i]; i++) { + if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) + continue; + if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { + error("Can't get current ownership of " + "remote file \"%s\"", g.gl_pathv[i]); + continue; + } + printf("Changing group on %s\n", g.gl_pathv[i]); + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; + aa->gid = n_arg; + do_setstat(in, out, g.gl_pathv[i], aa); + } + break; + case I_PWD: + printf("Remote working directory: %s\n", *pwd); + break; + case I_LPWD: + if (!getcwd(path_buf, sizeof(path_buf))) + error("Couldn't get local cwd: %s", + strerror(errno)); + else + printf("Local working directory: %s\n", + path_buf); + break; + case I_QUIT: + return(-1); + case I_HELP: + help(); + break; + case I_VERSION: + printf("SFTP protocol version %d\n", version); + break; + default: + fatal("%d is not implemented", cmdnum); + } + + if (g.gl_pathc) + globfree(&g); + if (path1) + xfree(path1); + if (path2) + xfree(path2); + + /* If an error occurs in batch mode we should abort. */ + if (infile != stdin && err > 0) + return -1; + + return(0); +} + +void +interactive_loop(int fd_in, int fd_out, char *file1, char *file2) +{ + char *pwd; + char *dir = NULL; + char cmd[2048]; + + version = do_init(fd_in, fd_out); + if (version == -1) + fatal("Couldn't initialise connection to server"); + + pwd = do_realpath(fd_in, fd_out, "."); + if (pwd == NULL) + fatal("Need cwd"); + + if (file1 != NULL) { + dir = xstrdup(file1); + dir = make_absolute(dir, pwd); + + if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) { + printf("Changing to: %s\n", dir); + snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); + parse_dispatch_command(fd_in, fd_out, cmd, &pwd); + } else { + if (file2 == NULL) + snprintf(cmd, sizeof cmd, "get %s", dir); + else + snprintf(cmd, sizeof cmd, "get %s %s", dir, + file2); + + parse_dispatch_command(fd_in, fd_out, cmd, &pwd); + return; + } + } + setvbuf(stdout, NULL, _IOLBF, 0); + setvbuf(infile, NULL, _IOLBF, 0); + + for(;;) { + char *cp; + + printf("sftp> "); + + /* XXX: use libedit */ + if (fgets(cmd, sizeof(cmd), infile) == NULL) { + printf("\n"); + break; + } else if (infile != stdin) /* Bluff typing */ + printf("%s", cmd); + + cp = strrchr(cmd, '\n'); + if (cp) + *cp = '\0'; + + if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd)) + break; + } + xfree(pwd); +} diff --git a/crypto/openssh/sftp-int.h b/crypto/openssh/sftp-int.h new file mode 100644 index 0000000..b47f862 --- /dev/null +++ b/crypto/openssh/sftp-int.h @@ -0,0 +1,27 @@ +/* $OpenBSD: sftp-int.h,v 1.2 2001/04/12 23:17:54 mouring Exp $ */ + +/* + * Copyright (c) 2001 Damien Miller. 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. + */ + +void interactive_loop(int fd_in, int fd_out, char *file1, char *file2); diff --git a/crypto/openssh/sftp-server.8 b/crypto/openssh/sftp-server.8 index 41a698e..afb233e 100644 --- a/crypto/openssh/sftp-server.8 +++ b/crypto/openssh/sftp-server.8 @@ -1,6 +1,6 @@ -.\" $OpenBSD: sftp-server.8,v 1.3 2000/10/13 17:20:44 aaron Exp $ +.\" $OpenBSD: sftp-server.8,v 1.6 2001/04/22 13:32:26 markus Exp $ .\" -.\" Copyright (c) 2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -44,11 +44,18 @@ See .Xr sshd 8 for more information. .Sh SEE ALSO +.Xr sftp 1 , .Xr ssh 1 , -.Xr ssh-add 1 , -.Xr ssh-keygen 1 , .Xr sshd 8 -.Sh AUTHOR +.Rs +.%A T. Ylonen +.%A S. Lehtinen +.%T "SSH File Transfer Protocol" +.%N draft-ietf-secsh-filexfer-00.txt +.%D January 2001 +.%O work in progress material +.Re +.Sh AUTHORS Markus Friedl <markus@openbsd.org> .Sh HISTORY .Nm diff --git a/crypto/openssh/sftp-server.c b/crypto/openssh/sftp-server.c index 018a03c..b49f861 100644 --- a/crypto/openssh/sftp-server.c +++ b/crypto/openssh/sftp-server.c @@ -22,98 +22,35 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.6 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: sftp-server.c,v 1.25 2001/04/05 10:42:53 markus Exp $"); -#include "ssh.h" #include "buffer.h" #include "bufaux.h" #include "getput.h" +#include "log.h" #include "xmalloc.h" -/* version */ -#define SSH_FILEXFER_VERSION 2 - -/* client to server */ -#define SSH_FXP_INIT 1 -#define SSH_FXP_OPEN 3 -#define SSH_FXP_CLOSE 4 -#define SSH_FXP_READ 5 -#define SSH_FXP_WRITE 6 -#define SSH_FXP_LSTAT 7 -#define SSH_FXP_FSTAT 8 -#define SSH_FXP_SETSTAT 9 -#define SSH_FXP_FSETSTAT 10 -#define SSH_FXP_OPENDIR 11 -#define SSH_FXP_READDIR 12 -#define SSH_FXP_REMOVE 13 -#define SSH_FXP_MKDIR 14 -#define SSH_FXP_RMDIR 15 -#define SSH_FXP_REALPATH 16 -#define SSH_FXP_STAT 17 -#define SSH_FXP_RENAME 18 - -/* server to client */ -#define SSH_FXP_VERSION 2 -#define SSH_FXP_STATUS 101 -#define SSH_FXP_HANDLE 102 -#define SSH_FXP_DATA 103 -#define SSH_FXP_NAME 104 -#define SSH_FXP_ATTRS 105 - -/* portable open modes */ -#define SSH_FXF_READ 0x01 -#define SSH_FXF_WRITE 0x02 -#define SSH_FXF_APPEND 0x04 -#define SSH_FXF_CREAT 0x08 -#define SSH_FXF_TRUNC 0x10 -#define SSH_FXF_EXCL 0x20 - -/* attributes */ -#define SSH_FXA_HAVE_SIZE 0x01 -#define SSH_FXA_HAVE_UGID 0x02 -#define SSH_FXA_HAVE_PERM 0x04 -#define SSH_FXA_HAVE_TIME 0x08 - -/* status messages */ -#define SSH_FX_OK 0x00 -#define SSH_FX_EOF 0x01 -#define SSH_FX_NO_SUCH_FILE 0x02 -#define SSH_FX_PERMISSION_DENIED 0x03 -#define SSH_FX_FAILURE 0x04 -#define SSH_FX_BAD_MESSAGE 0x05 -#define SSH_FX_NO_CONNECTION 0x06 -#define SSH_FX_CONNECTION_LOST 0x07 - +#include "sftp.h" +#include "sftp-common.h" /* helper */ +#define get_int64() buffer_get_int64(&iqueue); #define get_int() buffer_get_int(&iqueue); #define get_string(lenp) buffer_get_string(&iqueue, lenp); -#define TRACE log +#define TRACE debug /* input and output queue */ Buffer iqueue; Buffer oqueue; +/* Version of client */ +int version; + /* portable attibutes, etc. */ -typedef struct Attrib Attrib; typedef struct Stat Stat; -struct Attrib -{ - u_int32_t flags; - u_int32_t size_high; - u_int32_t size_low; - u_int64_t size; - u_int32_t uid; - u_int32_t gid; - u_int32_t perm; - u_int32_t atime; - u_int32_t mtime; -}; - -struct Stat -{ +struct Stat { char *name; char *long_name; Attrib attrib; @@ -123,27 +60,28 @@ int errno_to_portable(int unixerrno) { int ret = 0; + switch (unixerrno) { case 0: - ret = SSH_FX_OK; + ret = SSH2_FX_OK; break; case ENOENT: case ENOTDIR: case EBADF: case ELOOP: - ret = SSH_FX_NO_SUCH_FILE; + ret = SSH2_FX_NO_SUCH_FILE; break; case EPERM: case EACCES: case EFAULT: - ret = SSH_FX_PERMISSION_DENIED; + ret = SSH2_FX_PERMISSION_DENIED; break; case ENAMETOOLONG: case EINVAL: - ret = SSH_FX_BAD_MESSAGE; + ret = SSH2_FX_BAD_MESSAGE; break; default: - ret = SSH_FX_FAILURE; + ret = SSH2_FX_FAILURE; break; } return ret; @@ -153,104 +91,24 @@ int flags_from_portable(int pflags) { int flags = 0; - if (pflags & SSH_FXF_READ && - pflags & SSH_FXF_WRITE) { + + if ((pflags & SSH2_FXF_READ) && + (pflags & SSH2_FXF_WRITE)) { flags = O_RDWR; - } else if (pflags & SSH_FXF_READ) { + } else if (pflags & SSH2_FXF_READ) { flags = O_RDONLY; - } else if (pflags & SSH_FXF_WRITE) { + } else if (pflags & SSH2_FXF_WRITE) { flags = O_WRONLY; } - if (pflags & SSH_FXF_CREAT) + if (pflags & SSH2_FXF_CREAT) flags |= O_CREAT; - if (pflags & SSH_FXF_TRUNC) + if (pflags & SSH2_FXF_TRUNC) flags |= O_TRUNC; - if (pflags & SSH_FXF_EXCL) + if (pflags & SSH2_FXF_EXCL) flags |= O_EXCL; return flags; } -void -attrib_clear(Attrib *a) -{ - a->flags = 0; - a->size_low = 0; - a->size_high = 0; - a->size = 0; - a->uid = 0; - a->gid = 0; - a->perm = 0; - a->atime = 0; - a->mtime = 0; -} - -Attrib * -decode_attrib(Buffer *b) -{ - static Attrib a; - attrib_clear(&a); - a.flags = buffer_get_int(b); - if (a.flags & SSH_FXA_HAVE_SIZE) { - a.size_high = buffer_get_int(b); - a.size_low = buffer_get_int(b); - a.size = (((u_int64_t) a.size_high) << 32) + a.size_low; - } - if (a.flags & SSH_FXA_HAVE_UGID) { - a.uid = buffer_get_int(b); - a.gid = buffer_get_int(b); - } - if (a.flags & SSH_FXA_HAVE_PERM) { - a.perm = buffer_get_int(b); - } - if (a.flags & SSH_FXA_HAVE_TIME) { - a.atime = buffer_get_int(b); - a.mtime = buffer_get_int(b); - } - return &a; -} - -void -encode_attrib(Buffer *b, Attrib *a) -{ - buffer_put_int(b, a->flags); - if (a->flags & SSH_FXA_HAVE_SIZE) { - buffer_put_int(b, a->size_high); - buffer_put_int(b, a->size_low); - } - if (a->flags & SSH_FXA_HAVE_UGID) { - buffer_put_int(b, a->uid); - buffer_put_int(b, a->gid); - } - if (a->flags & SSH_FXA_HAVE_PERM) { - buffer_put_int(b, a->perm); - } - if (a->flags & SSH_FXA_HAVE_TIME) { - buffer_put_int(b, a->atime); - buffer_put_int(b, a->mtime); - } -} - -Attrib * -stat_to_attrib(struct stat *st) -{ - static Attrib a; - attrib_clear(&a); - a.flags = 0; - a.flags |= SSH_FXA_HAVE_SIZE; - a.size = st->st_size; - a.size_low = a.size; - a.size_high = (u_int32_t) (a.size >> 32); - a.flags |= SSH_FXA_HAVE_UGID; - a.uid = st->st_uid; - a.gid = st->st_gid; - a.flags |= SSH_FXA_HAVE_PERM; - a.perm = st->st_mode; - a.flags |= SSH_FXA_HAVE_TIME; - a.atime = st->st_atime; - a.mtime = st->st_mtime; - return &a; -} - Attrib * get_attrib(void) { @@ -266,17 +124,20 @@ struct Handle { int fd; char *name; }; + enum { HANDLE_UNUSED, HANDLE_DIR, HANDLE_FILE }; + Handle handles[100]; void handle_init(void) { int i; + for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) handles[i].use = HANDLE_UNUSED; } @@ -285,6 +146,7 @@ int handle_new(int use, char *name, int fd, DIR *dirp) { int i; + for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { if (handles[i].use == HANDLE_UNUSED) { handles[i].use = use; @@ -300,30 +162,29 @@ handle_new(int use, char *name, int fd, DIR *dirp) int handle_is_ok(int i, int type) { - return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; + return i >= 0 && i < sizeof(handles)/sizeof(Handle) && + handles[i].use == type; } int handle_to_string(int handle, char **stringp, int *hlenp) { - char buf[1024]; if (stringp == NULL || hlenp == NULL) return -1; - snprintf(buf, sizeof buf, "%d", handle); - *stringp = xstrdup(buf); - *hlenp = strlen(*stringp); + *stringp = xmalloc(sizeof(int32_t)); + PUT_32BIT(*stringp, handle); + *hlenp = sizeof(int32_t); return 0; } int handle_from_string(char *handle, u_int hlen) { -/* XXX OVERFLOW ? */ - char *ep; - long lval = strtol(handle, &ep, 10); - int val = lval; - if (*ep != '\0') + int val; + + if (hlen != sizeof(int32_t)) return -1; + val = GET_32BIT(handle); if (handle_is_ok(val, HANDLE_FILE) || handle_is_ok(val, HANDLE_DIR)) return val; @@ -350,7 +211,7 @@ handle_to_dir(int handle) int handle_to_fd(int handle) { - if (handle_is_ok(handle, HANDLE_FILE)) + if (handle_is_ok(handle, HANDLE_FILE)) return handles[handle].fd; return -1; } @@ -359,6 +220,7 @@ int handle_close(int handle) { int ret = -1; + if (handle_is_ok(handle, HANDLE_FILE)) { ret = close(handles[handle].fd); handles[handle].use = HANDLE_UNUSED; @@ -375,10 +237,12 @@ int get_handle(void) { char *handle; - int val; + int val = -1; u_int hlen; + handle = get_string(&hlen); - val = handle_from_string(handle, hlen); + if (hlen < 256) + val = handle_from_string(handle, hlen); xfree(handle); return val; } @@ -389,6 +253,7 @@ void send_msg(Buffer *m) { int mlen = buffer_len(m); + buffer_put_int(&oqueue, mlen); buffer_append(&oqueue, buffer_ptr(m), mlen); buffer_consume(m, mlen); @@ -398,11 +263,29 @@ void send_status(u_int32_t id, u_int32_t error) { Buffer msg; + const char *status_messages[] = { + "Success", /* SSH_FX_OK */ + "End of file", /* SSH_FX_EOF */ + "No such file", /* SSH_FX_NO_SUCH_FILE */ + "Permission denied", /* SSH_FX_PERMISSION_DENIED */ + "Failure", /* SSH_FX_FAILURE */ + "Bad message", /* SSH_FX_BAD_MESSAGE */ + "No connection", /* SSH_FX_NO_CONNECTION */ + "Connection lost", /* SSH_FX_CONNECTION_LOST */ + "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ + "Unknown error" /* Others */ + }; + TRACE("sent status id %d error %d", id, error); buffer_init(&msg); - buffer_put_char(&msg, SSH_FXP_STATUS); + buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); buffer_put_int(&msg, error); + if (version >= 3) { + buffer_put_cstring(&msg, + status_messages[MIN(error,SSH2_FX_MAX)]); + buffer_put_cstring(&msg, ""); + } send_msg(&msg); buffer_free(&msg); } @@ -410,6 +293,7 @@ void send_data_or_handle(char type, u_int32_t id, char *data, int dlen) { Buffer msg; + buffer_init(&msg); buffer_put_char(&msg, type); buffer_put_int(&msg, id); @@ -422,7 +306,7 @@ void send_data(u_int32_t id, char *data, int dlen) { TRACE("sent data id %d len %d", id, dlen); - send_data_or_handle(SSH_FXP_DATA, id, data, dlen); + send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } void @@ -430,9 +314,10 @@ send_handle(u_int32_t id, int handle) { char *string; int hlen; + handle_to_string(handle, &string, &hlen); TRACE("sent handle id %d handle %d", id, handle); - send_data_or_handle(SSH_FXP_HANDLE, id, string, hlen); + send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); xfree(string); } @@ -441,8 +326,9 @@ send_names(u_int32_t id, int count, Stat *stats) { Buffer msg; int i; + buffer_init(&msg); - buffer_put_char(&msg, SSH_FXP_NAME); + buffer_put_char(&msg, SSH2_FXP_NAME); buffer_put_int(&msg, id); buffer_put_int(&msg, count); TRACE("sent names id %d count %d", id, count); @@ -459,9 +345,10 @@ void send_attrib(u_int32_t id, Attrib *a) { Buffer msg; + TRACE("sent attrib id %d have 0x%x", id, a->flags); buffer_init(&msg); - buffer_put_char(&msg, SSH_FXP_ATTRS); + buffer_put_char(&msg, SSH2_FXP_ATTRS); buffer_put_int(&msg, id); encode_attrib(&msg, a); send_msg(&msg); @@ -474,12 +361,12 @@ void process_init(void) { Buffer msg; - int version = buffer_get_int(&iqueue); + version = buffer_get_int(&iqueue); TRACE("client version %d", version); buffer_init(&msg); - buffer_put_char(&msg, SSH_FXP_VERSION); - buffer_put_int(&msg, SSH_FILEXFER_VERSION); + buffer_put_char(&msg, SSH2_FXP_VERSION); + buffer_put_int(&msg, SSH2_FILEXFER_VERSION); send_msg(&msg); buffer_free(&msg); } @@ -490,14 +377,14 @@ process_open(void) u_int32_t id, pflags; Attrib *a; char *name; - int handle, fd, flags, mode, status = SSH_FX_FAILURE; + int handle, fd, flags, mode, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); - pflags = get_int(); + pflags = get_int(); /* portable flags */ a = get_attrib(); flags = flags_from_portable(pflags); - mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm : 0666; + mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode); fd = open(name, flags, mode); if (fd < 0) { @@ -508,10 +395,10 @@ process_open(void) close(fd); } else { send_handle(id, handle); - status = SSH_FX_OK; + status = SSH2_FX_OK; } } - if (status != SSH_FX_OK) + if (status != SSH2_FX_OK) send_status(id, status); xfree(name); } @@ -520,13 +407,13 @@ void process_close(void) { u_int32_t id; - int handle, ret, status = SSH_FX_FAILURE; + int handle, ret, status = SSH2_FX_FAILURE; id = get_int(); handle = get_handle(); TRACE("close id %d handle %d", id, handle); ret = handle_close(handle); - status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); } @@ -534,18 +421,17 @@ void process_read(void) { char buf[64*1024]; - u_int32_t id, off_high, off_low, len; - int handle, fd, ret, status = SSH_FX_FAILURE; + u_int32_t id, len; + int handle, fd, ret, status = SSH2_FX_FAILURE; u_int64_t off; id = get_int(); handle = get_handle(); - off_high = get_int(); - off_low = get_int(); + off = get_int64(); len = get_int(); - off = (((u_int64_t) off_high) << 32) + off_low; - TRACE("read id %d handle %d off %qd len %d", id, handle, off, len); + TRACE("read id %d handle %d off %llu len %d", id, handle, + (unsigned long long)off, len); if (len > sizeof buf) { len = sizeof buf; log("read change len %d", len); @@ -560,34 +446,33 @@ process_read(void) if (ret < 0) { status = errno_to_portable(errno); } else if (ret == 0) { - status = SSH_FX_EOF; + status = SSH2_FX_EOF; } else { send_data(id, buf, ret); - status = SSH_FX_OK; + status = SSH2_FX_OK; } } } - if (status != SSH_FX_OK) + if (status != SSH2_FX_OK) send_status(id, status); } void process_write(void) { - u_int32_t id, off_high, off_low; + u_int32_t id; u_int64_t off; u_int len; - int handle, fd, ret, status = SSH_FX_FAILURE; + int handle, fd, ret, status = SSH2_FX_FAILURE; char *data; id = get_int(); handle = get_handle(); - off_high = get_int(); - off_low = get_int(); + off = get_int64(); data = get_string(&len); - off = (((u_int64_t) off_high) << 32) + off_low; - TRACE("write id %d handle %d off %qd len %d", id, handle, off, len); + TRACE("write id %d handle %d off %llu len %d", id, handle, + (unsigned long long)off, len); fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { @@ -600,7 +485,7 @@ process_write(void) error("process_write: write failed"); status = errno_to_portable(errno); } else if (ret == len) { - status = SSH_FX_OK; + status = SSH2_FX_OK; } else { log("nothing at all written"); } @@ -613,11 +498,11 @@ process_write(void) void process_do_stat(int do_lstat) { - Attrib *a; + Attrib a; struct stat st; u_int32_t id; char *name; - int ret, status = SSH_FX_FAILURE; + int ret, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); @@ -626,11 +511,11 @@ process_do_stat(int do_lstat) if (ret < 0) { status = errno_to_portable(errno); } else { - a = stat_to_attrib(&st); - send_attrib(id, a); - status = SSH_FX_OK; + stat_to_attrib(&st, &a); + send_attrib(id, &a); + status = SSH2_FX_OK; } - if (status != SSH_FX_OK) + if (status != SSH2_FX_OK) send_status(id, status); xfree(name); } @@ -650,10 +535,10 @@ process_lstat(void) void process_fstat(void) { - Attrib *a; + Attrib a; struct stat st; u_int32_t id; - int fd, ret, handle, status = SSH_FX_FAILURE; + int fd, ret, handle, status = SSH2_FX_FAILURE; id = get_int(); handle = get_handle(); @@ -664,12 +549,12 @@ process_fstat(void) if (ret < 0) { status = errno_to_portable(errno); } else { - a = stat_to_attrib(&st); - send_attrib(id, a); - status = SSH_FX_OK; + stat_to_attrib(&st, &a); + send_attrib(id, &a); + status = SSH2_FX_OK; } } - if (status != SSH_FX_OK) + if (status != SSH2_FX_OK) send_status(id, status); } @@ -677,6 +562,7 @@ struct timeval * attrib_to_tv(Attrib *a) { static struct timeval tv[2]; + tv[0].tv_sec = a->atime; tv[0].tv_usec = 0; tv[1].tv_sec = a->mtime; @@ -691,22 +577,27 @@ process_setstat(void) u_int32_t id; char *name; int ret; - int status = SSH_FX_OK; + int status = SSH2_FX_OK; id = get_int(); name = get_string(NULL); a = get_attrib(); TRACE("setstat id %d name %s", id, name); - if (a->flags & SSH_FXA_HAVE_PERM) { + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { ret = chmod(name, a->perm & 0777); if (ret == -1) status = errno_to_portable(errno); } - if (a->flags & SSH_FXA_HAVE_TIME) { + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { ret = utimes(name, attrib_to_tv(a)); if (ret == -1) status = errno_to_portable(errno); } + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + ret = chown(name, a->uid, a->gid); + if (ret == -1) + status = errno_to_portable(errno); + } send_status(id, status); xfree(name); } @@ -717,7 +608,7 @@ process_fsetstat(void) Attrib *a; u_int32_t id; int handle, fd, ret; - int status = SSH_FX_OK; + int status = SSH2_FX_OK; id = get_int(); handle = get_handle(); @@ -725,18 +616,23 @@ process_fsetstat(void) TRACE("fsetstat id %d handle %d", id, handle); fd = handle_to_fd(handle); if (fd < 0) { - status = SSH_FX_FAILURE; + status = SSH2_FX_FAILURE; } else { - if (a->flags & SSH_FXA_HAVE_PERM) { + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { ret = fchmod(fd, a->perm & 0777); if (ret == -1) status = errno_to_portable(errno); } - if (a->flags & SSH_FXA_HAVE_TIME) { + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { ret = futimes(fd, attrib_to_tv(a)); if (ret == -1) status = errno_to_portable(errno); } + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + ret = fchown(fd, a->uid, a->gid); + if (ret == -1) + status = errno_to_portable(errno); + } } send_status(id, status); } @@ -746,13 +642,13 @@ process_opendir(void) { DIR *dirp = NULL; char *path; - int handle, status = SSH_FX_FAILURE; + int handle, status = SSH2_FX_FAILURE; u_int32_t id; id = get_int(); path = get_string(NULL); TRACE("opendir id %d path %s", id, path); - dirp = opendir(path); + dirp = opendir(path); if (dirp == NULL) { status = errno_to_portable(errno); } else { @@ -761,22 +657,51 @@ process_opendir(void) closedir(dirp); } else { send_handle(id, handle); - status = SSH_FX_OK; + status = SSH2_FX_OK; } - + } - if (status != SSH_FX_OK) + if (status != SSH2_FX_OK) send_status(id, status); xfree(path); } +/* + * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh + */ char * ls_file(char *name, struct stat *st) { - char buf[1024]; - snprintf(buf, sizeof buf, "0%o %d %d %qd %d %s", - st->st_mode, st->st_uid, st->st_gid, (long long)st->st_size,(int) st->st_mtime, - name); + int sz = 0; + struct passwd *pw; + struct group *gr; + struct tm *ltime = localtime(&st->st_mtime); + char *user, *group; + char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; + + strmode(st->st_mode, mode); + if ((pw = getpwuid(st->st_uid)) != NULL) { + user = pw->pw_name; + } else { + snprintf(ubuf, sizeof ubuf, "%d", st->st_uid); + user = ubuf; + } + if ((gr = getgrgid(st->st_gid)) != NULL) { + group = gr->gr_name; + } else { + snprintf(gbuf, sizeof gbuf, "%d", st->st_gid); + group = gbuf; + } + if (ltime != NULL) { + if (time(NULL) - st->st_mtime < (365*24*60*60)/2) + sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); + else + sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); + } + if (sz == 0) + tbuf[0] = '\0'; + snprintf(buf, sizeof buf, "%s %3d %-8.8s %-8.8s %8llu %s %s", mode, + st->st_nlink, user, group, (unsigned long long)st->st_size, tbuf, name); return xstrdup(buf); } @@ -795,9 +720,8 @@ process_readdir(void) dirp = handle_to_dir(handle); path = handle_to_name(handle); if (dirp == NULL || path == NULL) { - send_status(id, SSH_FX_FAILURE); + send_status(id, SSH2_FX_FAILURE); } else { - Attrib *a; struct stat st; char pathname[1024]; Stat *stats; @@ -813,19 +737,23 @@ process_readdir(void) "%s/%s", path, dp->d_name); if (lstat(pathname, &st) < 0) continue; - a = stat_to_attrib(&st); - stats[count].attrib = *a; + stat_to_attrib(&st, &(stats[count].attrib)); stats[count].name = xstrdup(dp->d_name); stats[count].long_name = ls_file(dp->d_name, &st); count++; /* send up to 100 entries in one message */ + /* XXX check packet size instead */ if (count == 100) break; } - send_names(id, count, stats); - for(i = 0; i < count; i++) { - xfree(stats[i].name); - xfree(stats[i].long_name); + if (count > 0) { + send_names(id, count, stats); + for(i = 0; i < count; i++) { + xfree(stats[i].name); + xfree(stats[i].long_name); + } + } else { + send_status(id, SSH2_FX_EOF); } xfree(stats); } @@ -836,14 +764,14 @@ process_remove(void) { char *name; u_int32_t id; - int status = SSH_FX_FAILURE; + int status = SSH2_FX_FAILURE; int ret; id = get_int(); name = get_string(NULL); TRACE("remove id %d name %s", id, name); - ret = remove(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; + ret = unlink(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } @@ -854,15 +782,16 @@ process_mkdir(void) Attrib *a; u_int32_t id; char *name; - int ret, mode, status = SSH_FX_FAILURE; + int ret, mode, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); a = get_attrib(); - mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm & 0777 : 0777; + mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? + a->perm & 0777 : 0777; TRACE("mkdir id %d name %s mode 0%o", id, name, mode); ret = mkdir(name, mode); - status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } @@ -878,7 +807,7 @@ process_rmdir(void) name = get_string(NULL); TRACE("rmdir id %d name %s", id, name); ret = rmdir(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } @@ -892,6 +821,10 @@ process_realpath(void) id = get_int(); path = get_string(NULL); + if (path[0] == '\0') { + xfree(path); + path = xstrdup("."); + } TRACE("realpath id %d path %s", id, path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); @@ -908,33 +841,93 @@ void process_rename(void) { u_int32_t id; + struct stat st; char *oldpath, *newpath; - int ret, status; + int ret, status = SSH2_FX_FAILURE; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); TRACE("rename id %d old %s new %s", id, oldpath, newpath); - ret = rename(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; + /* fail if 'newpath' exists */ + if (stat(newpath, &st) == -1) { + ret = rename(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } + send_status(id, status); + xfree(oldpath); + xfree(newpath); +} + +void +process_readlink(void) +{ + u_int32_t id; + char link[MAXPATHLEN]; + char *path; + + id = get_int(); + path = get_string(NULL); + TRACE("readlink id %d path %s", id, path); + if (readlink(path, link, sizeof(link) - 1) == -1) + send_status(id, errno_to_portable(errno)); + else { + Stat s; + + link[sizeof(link) - 1] = '\0'; + attrib_clear(&s.attrib); + s.name = s.long_name = link; + send_names(id, 1, &s); + } + xfree(path); +} + +void +process_symlink(void) +{ + u_int32_t id; + struct stat st; + char *oldpath, *newpath; + int ret, status = SSH2_FX_FAILURE; + + id = get_int(); + oldpath = get_string(NULL); + newpath = get_string(NULL); + TRACE("symlink id %d old %s new %s", id, oldpath, newpath); + /* fail if 'newpath' exists */ + if (stat(newpath, &st) == -1) { + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(oldpath); xfree(newpath); } +void +process_extended(void) +{ + u_int32_t id; + char *request; + + id = get_int(); + request = get_string(NULL); + send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ + xfree(request); +} /* stolen from ssh-agent */ void process(void) { - unsigned int msg_len; - unsigned int type; - unsigned char *cp; + u_int msg_len; + u_int type; + u_char *cp; if (buffer_len(&iqueue) < 5) return; /* Incomplete message. */ - cp = (unsigned char *) buffer_ptr(&iqueue); + cp = (u_char *) buffer_ptr(&iqueue); msg_len = GET_32BIT(cp); if (msg_len > 256 * 1024) { error("bad message "); @@ -945,57 +938,66 @@ process(void) buffer_consume(&iqueue, 4); type = buffer_get_char(&iqueue); switch (type) { - case SSH_FXP_INIT: + case SSH2_FXP_INIT: process_init(); break; - case SSH_FXP_OPEN: + case SSH2_FXP_OPEN: process_open(); break; - case SSH_FXP_CLOSE: + case SSH2_FXP_CLOSE: process_close(); break; - case SSH_FXP_READ: + case SSH2_FXP_READ: process_read(); break; - case SSH_FXP_WRITE: + case SSH2_FXP_WRITE: process_write(); break; - case SSH_FXP_LSTAT: + case SSH2_FXP_LSTAT: process_lstat(); break; - case SSH_FXP_FSTAT: + case SSH2_FXP_FSTAT: process_fstat(); break; - case SSH_FXP_SETSTAT: + case SSH2_FXP_SETSTAT: process_setstat(); break; - case SSH_FXP_FSETSTAT: + case SSH2_FXP_FSETSTAT: process_fsetstat(); break; - case SSH_FXP_OPENDIR: + case SSH2_FXP_OPENDIR: process_opendir(); break; - case SSH_FXP_READDIR: + case SSH2_FXP_READDIR: process_readdir(); break; - case SSH_FXP_REMOVE: + case SSH2_FXP_REMOVE: process_remove(); break; - case SSH_FXP_MKDIR: + case SSH2_FXP_MKDIR: process_mkdir(); break; - case SSH_FXP_RMDIR: + case SSH2_FXP_RMDIR: process_rmdir(); break; - case SSH_FXP_REALPATH: + case SSH2_FXP_REALPATH: process_realpath(); break; - case SSH_FXP_STAT: + case SSH2_FXP_STAT: process_stat(); break; - case SSH_FXP_RENAME: + case SSH2_FXP_RENAME: process_rename(); break; + case SSH2_FXP_READLINK: + process_readlink(); + break; + case SSH2_FXP_SYMLINK: + process_symlink(); + break; + case SSH2_FXP_EXTENDED: + process_extended(); + break; default: error("Unknown message %d", type); break; @@ -1005,12 +1007,18 @@ process(void) int main(int ac, char **av) { - fd_set rset, wset; + fd_set *rset, *wset; int in, out, max; - ssize_t len, olen; + ssize_t len, olen, set_size; + + /* XXX should use getopt */ handle_init(); +#ifdef DEBUG_SFTP_SERVER + log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); +#endif + in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO); @@ -1023,23 +1031,27 @@ main(int ac, char **av) buffer_init(&iqueue); buffer_init(&oqueue); + set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); + rset = (fd_set *)xmalloc(set_size); + wset = (fd_set *)xmalloc(set_size); + for (;;) { - FD_ZERO(&rset); - FD_ZERO(&wset); + memset(rset, 0, set_size); + memset(wset, 0, set_size); - FD_SET(in, &rset); + FD_SET(in, rset); olen = buffer_len(&oqueue); if (olen > 0) - FD_SET(out, &wset); + FD_SET(out, wset); - if (select(max+1, &rset, &wset, NULL, NULL) < 0) { + if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; exit(2); } /* copy stdin to iqueue */ - if (FD_ISSET(in, &rset)) { + if (FD_ISSET(in, rset)) { char buf[4*4096]; len = read(in, buf, sizeof buf); if (len == 0) { @@ -1053,7 +1065,7 @@ main(int ac, char **av) } } /* send oqueue to stdout */ - if (FD_ISSET(out, &wset)) { + if (FD_ISSET(out, wset)) { len = write(out, buffer_ptr(&oqueue), olen); if (len < 0) { error("write error"); diff --git a/crypto/openssh/sftp-server/Makefile b/crypto/openssh/sftp-server/Makefile index 1999fec..e068239 100644 --- a/crypto/openssh/sftp-server/Makefile +++ b/crypto/openssh/sftp-server/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.5 2001/03/03 23:59:36 markus Exp $ + .PATH: ${.CURDIR}/.. PROG= sftp-server @@ -8,9 +10,9 @@ BINMODE?=555 BINDIR= /usr/libexec MAN= sftp-server.8 -SRCS= sftp-server.c log-server.c +SRCS= sftp-server.c sftp-common.c .include <bsd.prog.mk> -LDADD+= -lcrypto # -lutil -lz -DPADD+= ${LIBCRYPTO} # ${LIBDES} ${LIBUTIL} ${LIBZ} +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} diff --git a/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1 new file mode 100644 index 0000000..b482996 --- /dev/null +++ b/crypto/openssh/sftp.1 @@ -0,0 +1,222 @@ +.\" $OpenBSD: sftp.1,v 1.17 2001/04/22 13:32:27 markus Exp $ +.\" +.\" Copyright (c) 2001 Damien Miller. 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 February 4, 2001 +.Dt SFTP 1 +.Os +.Sh NAME +.Nm sftp +.Nd Secure file transfer program +.Sh SYNOPSIS +.Nm sftp +.Op Fl vC +.Op Fl b Ar batchfile +.Op Fl o Ar ssh_option +.Op Ar host +.Nm sftp +.Op [\fIuser\fR@]\fIhost\fR[:\fIfile\fR [\fIfile\fR]] +.Nm sftp +.Op [\fIuser\fR@]\fIhost\fR[:\fIdir\fR[\fI/\fR]] +.Sh DESCRIPTION +.Nm +is an interactive file transfer program, similar to +.Xr ftp 1 , +which performs all operations over an encrypted +.Xr ssh 1 +transport. +It may also use many features of ssh, such as public key authentication and +compression. +.Nm +connects and logs into the specified +.Ar hostname , +then enters an interactive command mode. +.Pp +The second usage format will fetch files automaticly if a non-interactive +authentication is used, else it do so after an interactive authentication +is used. +.Pp +The last usage format allows the sftp client to start in a remote directory. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b Ar batchfile +Batch mode reads a series of commands from an input +.Ar batchfile +instead of +.Em stdin . +Since it lacks user interaction it should be used in conjunction with +non-interactive authentication. +.Nm +will abort if any of the following +commands fail: +.Ic get , put , rename , ln , rm , mkdir , chdir , lchdir +and +.Ic lmkdir . +.It Fl C +Enables compression (via ssh's +.Fl C +flag) +.It Fl o Ar ssh_option +Specify an option to be directly passed to +.Xr ssh 1 . +.It Fl v +Raise logging level. This option is also passed to ssh. +.El +.Sh INTERACTIVE COMMANDS +Once in interactive mode, +.Nm +understands a set of commands similar to those of +.Xr ftp 1 . +Commands are case insensitive and pathnames may be enclosed in quotes if they +contain spaces. +.Bl -tag -width Ds +.It Ic cd Ar path +Change remote directory to +.Ar path . +.It Ic lcd Ar path +Change local directory to +.Ar path . +.It Ic chgrp Ar grp Ar path +Change group of file +.Ar path +to +.Ar grp . +.Ar grp +must be a numeric GID. +.It Ic chmod Ar mode Ar path +Change permissions of file +.Ar path +to +.Ar mode . +.It Ic chown Ar own Ar path +Change owner of file +.Ar path +to +.Ar own . +.Ar own +must be a numeric UID. +.It Ic exit +Quit sftp. +.It Xo Ic get +.Op Ar flags +.Ar remote-path +.Op Ar local-path +.Xc +Retrieve the +.Ar remote-path +and store it on the local machine. +If the local +path name is not specified, it is given the same name it has on the +remote machine. If the +.Fl P +flag is specified, then the file's full permission and access time are +copied too. +.It Ic help +Display help text. +.It Ic lls Op Ar ls-options Op Ar path +Display local directory listing of either +.Ar path +or current directory if +.Ar path +is not specified. +.It Ic lmkdir Ar path +Create local directory specified by +.Ar path . +.It Ic ln Ar oldpath Ar newpath +Create a symbolic link from +.Ar oldpath +to +.Ar newpath . +.It Ic lpwd +Print local working directory. +.It Ic ls Op Ar path +Display remote directory listing of either +.Ar path +or current directory if +.Ar path +is not specified. +.It Ic lumask Ar umask +Set local umask to +.Ar umask . +.It Ic mkdir Ar path +Create remote directory specified by +.Ar path . +.It Xo Ic put +.Op Ar flags +.Ar local-path +.Op Ar local-path +.Xc +Upload +.Ar local-path +and store it on the remote machine. If the remote path name is not +specified, it is given the same name it has on the local machine. If the +.Fl P +flag is specified, then the file's full permission and access time are +copied too. +.It Ic pwd +Display remote working directory. +.It Ic quit +Quit sftp. +.It Ic rename Ar oldpath Ar newpath +Rename remote file from +.Ar oldpath +to +.Ar newpath . +.It Ic rmdir Ar path +Remove remote directory specified by +.Ar path . +.It Ic rm Ar path +Delete remote file specified by +.Ar path . +.It Ic symlink Ar oldpath Ar newpath +Create a symbolic link from +.Ar oldpath +to +.Ar newpath . +.It Ic ! Ar command +Execute +.Ar command +in local shell. +.It Ic ! +Escape to local shell. +.It Ic ? +Synonym for help. +.El +.Sh AUTHORS +Damien Miller <djm@mindrot.org> +.Sh SEE ALSO +.Xr scp 1 , +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-keygen 1 , +.Xr sftp-server 8 , +.Xr sshd 8 +.Rs +.%A T. Ylonen +.%A S. Lehtinen +.%T "SSH File Transfer Protocol" +.%N draft-ietf-secsh-filexfer-00.txt +.%D January 2001 +.%O work in progress material +.Re diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c new file mode 100644 index 0000000..2c57bef --- /dev/null +++ b/crypto/openssh/sftp.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +RCSID("$OpenBSD: sftp.c,v 1.15 2001/04/16 02:31:44 mouring Exp $"); + +/* XXX: commandline mode */ +/* XXX: short-form remote directory listings (like 'ls -C') */ + +#include "buffer.h" +#include "xmalloc.h" +#include "log.h" +#include "pathnames.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" +#include "sftp-int.h" + +#include "scp-common.h" + +int use_ssh1 = 0; +char *ssh_program = _PATH_SSH_PROGRAM; +char *sftp_server = NULL; +FILE* infile; + +void +connect_to_server(char **args, int *in, int *out, pid_t *sshpid) +{ + int c_in, c_out; +#ifdef USE_PIPES + int pin[2], pout[2]; + if ((pipe(pin) == -1) || (pipe(pout) == -1)) + fatal("pipe: %s", strerror(errno)); + *in = pin[0]; + *out = pout[1]; + c_in = pout[0]; + c_out = pin[1]; +#else /* USE_PIPES */ + int inout[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) + fatal("socketpair: %s", strerror(errno)); + *in = *out = inout[0]; + c_in = c_out = inout[1]; +#endif /* USE_PIPES */ + + if ((*sshpid = fork()) == -1) + fatal("fork: %s", strerror(errno)); + else if (*sshpid == 0) { + if ((dup2(c_in, STDIN_FILENO) == -1) || + (dup2(c_out, STDOUT_FILENO) == -1)) { + fprintf(stderr, "dup2: %s\n", strerror(errno)); + exit(1); + } + close(*in); + close(*out); + close(c_in); + close(c_out); + execv(ssh_program, args); + fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); + exit(1); + } + + close(c_in); + close(c_out); +} + +char ** +make_ssh_args(char *add_arg) +{ + static char **args = NULL; + static int nargs = 0; + char debug_buf[4096]; + int i; + + /* Init args array */ + if (args == NULL) { + nargs = 2; + i = 0; + args = xmalloc(sizeof(*args) * nargs); + args[i++] = "ssh"; + args[i++] = NULL; + } + + /* If asked to add args, then do so and return */ + if (add_arg) { + i = nargs++ - 1; + args = xrealloc(args, sizeof(*args) * nargs); + args[i++] = add_arg; + args[i++] = NULL; + return(NULL); + } + + /* no subsystem if the server-spec contains a '/' */ + if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) + make_ssh_args("-s"); + make_ssh_args("-oForwardX11=no"); + make_ssh_args("-oForwardAgent=no"); + make_ssh_args(use_ssh1 ? "-oProtocol=1" : "-oProtocol=2"); + + /* Otherwise finish up and return the arg array */ + if (sftp_server != NULL) + make_ssh_args(sftp_server); + else + make_ssh_args("sftp"); + + /* XXX: overflow - doesn't grow debug_buf */ + debug_buf[0] = '\0'; + for(i = 0; args[i]; i++) { + if (i) + strlcat(debug_buf, " ", sizeof(debug_buf)); + + strlcat(debug_buf, args[i], sizeof(debug_buf)); + } + debug("SSH args \"%s\"", debug_buf); + + return(args); +} + +void +usage(void) +{ + fprintf(stderr, "usage: sftp [-1vC] [-b batchfile] [-osshopt=value] [user@]host[:file [file]]\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + int in, out, ch, debug_level, compress_flag; + pid_t sshpid; + char *file1 = NULL; + char *host, *userhost, *cp, *file2; + LogLevel ll; + extern int optind; + extern char *optarg; + + infile = stdin; /* Read from STDIN unless changed by -b */ + debug_level = compress_flag = 0; + + while ((ch = getopt(argc, argv, "1hvCo:s:S:b:")) != -1) { + switch (ch) { + case 'C': + compress_flag = 1; + break; + case 'v': + debug_level = MIN(3, debug_level + 1); + break; + case 'o': + make_ssh_args("-o"); + make_ssh_args(optarg); + break; + case '1': + use_ssh1 = 1; + if (sftp_server == NULL) + sftp_server = _PATH_SFTP_SERVER; + break; + case 's': + sftp_server = optarg; + break; + case 'S': + ssh_program = optarg; + break; + case 'b': + if (infile == stdin) { + infile = fopen(optarg, "r"); + if (infile == NULL) + fatal("%s (%s).", strerror(errno), optarg); + } else + fatal("Filename already specified."); + break; + case 'h': + default: + usage(); + } + } + + if (optind == argc || argc > (optind + 2)) + usage(); + + userhost = xstrdup(argv[optind]); + file2 = argv[optind+1]; + + if ((cp = colon(userhost)) != NULL) { + *cp++ = '\0'; + file1 = cp; + } + + if ((host = strchr(userhost, '@')) == NULL) + host = userhost; + else { + *host++ = '\0'; + if (!userhost[0]) { + fprintf(stderr, "Missing username\n"); + usage(); + } + make_ssh_args("-l"); + make_ssh_args(userhost); + } + + host = cleanhostname(host); + if (!*host) { + fprintf(stderr, "Missing hostname\n"); + usage(); + } + + /* Set up logging and debug '-d' arguments to ssh */ + ll = SYSLOG_LEVEL_INFO; + switch (debug_level) { + case 1: + ll = SYSLOG_LEVEL_DEBUG1; + make_ssh_args("-v"); + break; + case 2: + ll = SYSLOG_LEVEL_DEBUG2; + make_ssh_args("-v"); + make_ssh_args("-v"); + break; + case 3: + ll = SYSLOG_LEVEL_DEBUG3; + make_ssh_args("-v"); + make_ssh_args("-v"); + make_ssh_args("-v"); + break; + } + + if (compress_flag) + make_ssh_args("-C"); + + log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); + + make_ssh_args(host); + + fprintf(stderr, "Connecting to %s...\n", host); + + connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); + + interactive_loop(in, out, file1, file2); + + close(in); + close(out); + if (infile != stdin) + fclose(infile); + + if (waitpid(sshpid, NULL, 0) == -1) + fatal("Couldn't wait for ssh process: %s", strerror(errno)); + + exit(0); +} diff --git a/crypto/openssh/sftp.h b/crypto/openssh/sftp.h new file mode 100644 index 0000000..2ad9586 --- /dev/null +++ b/crypto/openssh/sftp.h @@ -0,0 +1,91 @@ +/* $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * draft-ietf-secsh-filexfer-01.txt + */ + +/* version */ +#define SSH2_FILEXFER_VERSION 3 + +/* client to server */ +#define SSH2_FXP_INIT 1 +#define SSH2_FXP_OPEN 3 +#define SSH2_FXP_CLOSE 4 +#define SSH2_FXP_READ 5 +#define SSH2_FXP_WRITE 6 +#define SSH2_FXP_LSTAT 7 +#define SSH2_FXP_FSTAT 8 +#define SSH2_FXP_SETSTAT 9 +#define SSH2_FXP_FSETSTAT 10 +#define SSH2_FXP_OPENDIR 11 +#define SSH2_FXP_READDIR 12 +#define SSH2_FXP_REMOVE 13 +#define SSH2_FXP_MKDIR 14 +#define SSH2_FXP_RMDIR 15 +#define SSH2_FXP_REALPATH 16 +#define SSH2_FXP_STAT 17 +#define SSH2_FXP_RENAME 18 +#define SSH2_FXP_READLINK 19 +#define SSH2_FXP_SYMLINK 20 + +/* server to client */ +#define SSH2_FXP_VERSION 2 +#define SSH2_FXP_STATUS 101 +#define SSH2_FXP_HANDLE 102 +#define SSH2_FXP_DATA 103 +#define SSH2_FXP_NAME 104 +#define SSH2_FXP_ATTRS 105 + +#define SSH2_FXP_EXTENDED 200 +#define SSH2_FXP_EXTENDED_REPLY 201 + +/* attributes */ +#define SSH2_FILEXFER_ATTR_SIZE 0x00000001 +#define SSH2_FILEXFER_ATTR_UIDGID 0x00000002 +#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004 +#define SSH2_FILEXFER_ATTR_ACMODTIME 0x00000008 +#define SSH2_FILEXFER_ATTR_EXTENDED 0x80000000 + +/* portable open modes */ +#define SSH2_FXF_READ 0x00000001 +#define SSH2_FXF_WRITE 0x00000002 +#define SSH2_FXF_APPEND 0x00000004 +#define SSH2_FXF_CREAT 0x00000008 +#define SSH2_FXF_TRUNC 0x00000010 +#define SSH2_FXF_EXCL 0x00000020 + +/* status messages */ +#define SSH2_FX_OK 0 +#define SSH2_FX_EOF 1 +#define SSH2_FX_NO_SUCH_FILE 2 +#define SSH2_FX_PERMISSION_DENIED 3 +#define SSH2_FX_FAILURE 4 +#define SSH2_FX_BAD_MESSAGE 5 +#define SSH2_FX_NO_CONNECTION 6 +#define SSH2_FX_CONNECTION_LOST 7 +#define SSH2_FX_OP_UNSUPPORTED 8 +#define SSH2_FX_MAX 8 diff --git a/crypto/openssh/sftp/Makefile b/crypto/openssh/sftp/Makefile new file mode 100644 index 0000000..83fa8dc --- /dev/null +++ b/crypto/openssh/sftp/Makefile @@ -0,0 +1,19 @@ +# $OpenBSD: Makefile,v 1.4 2001/04/16 02:31:52 mouring Exp $ + +.PATH: ${.CURDIR}/.. + +PROG= sftp +BINOWN= root + +BINMODE?=555 + +BINDIR= /usr/bin +MAN= sftp.1 + +SRCS= sftp.c sftp-client.c sftp-int.c sftp-common.c sftp-glob.c scp-common.c + +.include <bsd.prog.mk> + +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} + diff --git a/crypto/openssh/ssh-add.1 b/crypto/openssh/ssh-add.1 index d453fa2..d7725c6 100644 --- a/crypto/openssh/ssh-add.1 +++ b/crypto/openssh/ssh-add.1 @@ -1,3 +1,5 @@ +.\" $OpenBSD: ssh-add.1,v 1.24 2001/04/10 09:13:21 itojun Exp $ +.\" .\" -*- nroff -*- .\" .\" Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -11,9 +13,9 @@ .\" 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. +.\" 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 @@ -56,6 +58,8 @@ If any file requires a passphrase, .Nm asks for the passphrase from the user. The Passphrase it is read from the user's tty. +.Nm +retries the last passphrase if multiple identity files are given. .Pp The authentication agent must be running and must be an ancestor of the current process for @@ -76,7 +80,7 @@ Deletes all identities from the agent. .Sh FILES .Bl -tag -width Ds .It Pa $HOME/.ssh/identity -Contains the RSA authentication identity of the user. +Contains the protocol version 1 RSA authentication identity of the user. This file should not be readable by anyone but the user. Note that .Nm @@ -88,7 +92,9 @@ This is the default file added by .Nm when no other files have been specified. .It Pa $HOME/.ssh/id_dsa -Contains the DSA authentication identity of the user. +Contains the protocol version 2 DSA authentication identity of the user. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 RSA authentication identity of the user. .El .Sh ENVIRONMENT .Bl -tag -width Ds @@ -116,35 +122,17 @@ may be necessary to redirect the input from .Pa /dev/null to make this work.) .El -.Sh AUTHOR -Tatu Ylonen <ylo@cs.hut.fi> -.Pp -OpenSSH -is a derivative of the original (free) ssh 1.2.12 release, but with bugs -removed and newer features re-added. -Rapidly after the 1.2.12 release, -newer versions bore successively more restrictive licenses. -This version of OpenSSH -.Bl -bullet -.It -has all components of a restrictive nature (i.e., patents, see -.Xr ssl 8 ) -directly removed from the source code; any licensed or patented components -are chosen from -external libraries. -.It -has been updated to support ssh protocol 1.5. -.It -contains added support for -.Xr kerberos 8 -authentication and ticket passing. -.It -supports one-time password authentication with -.Xr skey 1 . -.El +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-agent 1 , .Xr ssh-keygen 1 , -.Xr sshd 8 , -.Xr ssl 8 +.Xr sshd 8 diff --git a/crypto/openssh/ssh-add/Makefile b/crypto/openssh/ssh-add/Makefile index d6dd175..2f7bf42 100644 --- a/crypto/openssh/ssh-add/Makefile +++ b/crypto/openssh/ssh-add/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.20 2001/03/04 00:51:25 markus Exp $ + .PATH: ${.CURDIR}/.. PROG= ssh-add @@ -8,9 +10,9 @@ BINMODE?=555 BINDIR= /usr/bin MAN= ssh-add.1 -SRCS= ssh-add.c log-client.c +SRCS= ssh-add.c .include <bsd.prog.mk> -LDADD+= -lcrypto -lutil -lz -DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ} +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} diff --git a/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1 index 23c699d..1d21469 100644 --- a/crypto/openssh/ssh-agent.1 +++ b/crypto/openssh/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.16 2000/09/07 20:27:54 deraadt Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.24 2001/04/10 09:13:21 itojun Exp $ .\" .\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -10,9 +10,9 @@ .\" 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. +.\" 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 @@ -42,12 +42,12 @@ .Nd authentication agent .Sh SYNOPSIS .Nm ssh-agent -.Op Fl c Li | Fl s -.Op Fl k -.Oo .Ar command -.Op Ar args ... -.Oc +.Ar args ... +.Nm ssh-agent +.Op Fl c Li | Fl s +.Nm ssh-agent +.Fl k .Sh DESCRIPTION .Nm is a program to hold private keys used for public key authentication @@ -121,7 +121,7 @@ or syntax can be generated) which can be evalled in the calling shell. Later .Xr ssh 1 -look at these variables and use them to establish a connection to the agent. +looks at these variables and uses them to establish a connection to the agent. .Pp A unix-domain socket is created .Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> , @@ -142,7 +142,7 @@ line terminates. .Sh FILES .Bl -tag -width Ds .It Pa $HOME/.ssh/identity -Contains the RSA authentication identity of the user. +Contains the protocol version 1 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 @@ -153,42 +153,26 @@ but is normally added to the agent using .Xr ssh-add 1 at login time. .It Pa $HOME/.ssh/id_dsa -Contains the DSA authentication identity of the user. -.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> , +Contains the protocol version 2 DSA authentication identity of the user. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 RSA authentication identity of the user. +.It Pa /tmp/ssh-XXXXXXXX/agent.<pid> Unix-domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El -.Sh AUTHOR -Tatu Ylonen <ylo@cs.hut.fi> -.Pp -OpenSSH -is a derivative of the original (free) ssh 1.2.12 release, but with bugs -removed and newer features re-added. -Rapidly after the 1.2.12 release, -newer versions bore successively more restrictive licenses. -This version of OpenSSH -.Bl -bullet -.It -has all components of a restrictive nature (i.e., patents, see -.Xr ssl 8 ) -directly removed from the source code; any licensed or patented components -are chosen from -external libraries. -.It -has been updated to support ssh protocol 1.5. -.It -contains added support for -.Xr kerberos 8 -authentication and ticket passing. -.It -supports one-time password authentication with -.Xr skey 1 . -.El +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , -.Xr sshd 8 , -.Xr ssl 8 +.Xr sshd 8 diff --git a/crypto/openssh/ssh-agent/Makefile b/crypto/openssh/ssh-agent/Makefile index 9301aef..e1a2e2c 100644 --- a/crypto/openssh/ssh-agent/Makefile +++ b/crypto/openssh/ssh-agent/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:25 markus Exp $ + .PATH: ${.CURDIR}/.. PROG= ssh-agent @@ -8,9 +10,9 @@ BINMODE?=555 BINDIR= /usr/bin MAN= ssh-agent.1 -SRCS= ssh-agent.c log-client.c +SRCS= ssh-agent.c .include <bsd.prog.mk> -LDADD+= -lcrypto -lutil -lz -DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ} +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} diff --git a/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c new file mode 100644 index 0000000..adc8f98 --- /dev/null +++ b/crypto/openssh/ssh-dss.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-dss.c,v 1.6 2001/02/08 19:30:52 itojun Exp $"); + +#include <openssl/bn.h> +#include <openssl/evp.h> + +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" +#include "log.h" +#include "key.h" +#include "ssh-dss.h" + +#define INTBLOB_LEN 20 +#define SIGBLOB_LEN (2*INTBLOB_LEN) + +int +ssh_dss_sign( + Key *key, + u_char **sigp, int *lenp, + u_char *data, int datalen) +{ + u_char *digest; + u_char *ret; + DSA_SIG *sig; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + u_int rlen; + u_int slen; + u_int len, dlen; + u_char sigblob[SIGBLOB_LEN]; + Buffer b; + + if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + error("ssh_dss_sign: no DSA key"); + return -1; + } + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + sig = DSA_do_sign(digest, dlen, key->dsa); + if (sig == NULL) { + fatal("ssh_dss_sign: cannot sign"); + } + memset(digest, 0, dlen); + xfree(digest); + + 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, "ssh-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 +ssh_dss_verify( + Key *key, + u_char *signature, int signaturelen, + u_char *data, int datalen) +{ + Buffer b; + u_char *digest; + DSA_SIG *sig; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + u_char *sigblob; + char *txt; + u_int len, dlen; + int rlen; + int ret; + + if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + error("ssh_dss_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("ssh-dss", ktype) != 0) { + error("ssh_dss_verify: cannot handle type %s", ktype); + buffer_free(&b); + return -1; + } + sigblob = (u_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 */ + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ret = DSA_do_verify(digest, dlen, sig, key->dsa); + + memset(digest, 0, dlen); + 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("ssh_dss_verify: signature %s", txt); + return ret; +} diff --git a/crypto/openssh/ssh-dss.h b/crypto/openssh/ssh-dss.h new file mode 100644 index 0000000..0e6a20a --- /dev/null +++ b/crypto/openssh/ssh-dss.h @@ -0,0 +1,41 @@ +/* $OpenBSD: ssh-dss.h,v 1.3 2001/01/29 01:58:18 niklas 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 + +int +ssh_dss_sign( + Key *key, + u_char **sigp, int *lenp, + u_char *data, int datalen); + +int +ssh_dss_verify( + Key *key, + u_char *signature, int signaturelen, + u_char *data, int datalen); + +#endif diff --git a/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1 index e1b1525..371fc5f 100644 --- a/crypto/openssh/ssh-keygen.1 +++ b/crypto/openssh/ssh-keygen.1 @@ -1,3 +1,5 @@ +.\" $OpenBSD: ssh-keygen.1,v 1.40 2001/04/23 21:57:07 markus Exp $ +.\" .\" -*- nroff -*- .\" .\" Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -11,9 +13,9 @@ .\" 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. +.\" 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 @@ -40,11 +42,12 @@ .Os .Sh NAME .Nm ssh-keygen -.Nd authentication key generation +.Nd authentication key generation, management and conversion .Sh SYNOPSIS .Nm ssh-keygen -.Op Fl dq +.Op Fl q .Op Fl b Ar bits +.Op Fl t Ar type .Op Fl N Ar new_passphrase .Op Fl C Ar comment .Op Fl f Ar output_keyfile @@ -54,10 +57,10 @@ .Op Fl N Ar new_passphrase .Op Fl f Ar keyfile .Nm ssh-keygen -.Fl x +.Fl i .Op Fl f Ar input_keyfile .Nm ssh-keygen -.Fl X +.Fl e .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl y @@ -71,23 +74,25 @@ .Fl l .Op Fl f Ar input_keyfile .Nm ssh-keygen -.Fl R +.Fl B +.Op Fl f Ar input_keyfile .Sh DESCRIPTION .Nm -generates and manages authentication keys for +generates, manages and converts authentication keys for .Xr ssh 1 . .Nm -defaults to generating an RSA key for use by protocols 1.3 and 1.5; +defaults to generating a RSA1 key for use by SSH protocol version 1. specifying the -.Fl d -flag will create a DSA key instead for use by protocol 2.0. +.Fl t +option allows you to create a key for use by SSH protocol version 2. .Pp Normally each user wishing to use SSH with RSA or DSA authentication runs this once to create the authentication key in -.Pa $HOME/.ssh/identity +.Pa $HOME/.ssh/identity , +.Pa $HOME/.ssh/id_dsa or -.Pa $HOME/.ssh/id_dsa . +.Pa $HOME/.ssh/id_rsa . Additionally, the system administrator may use this to generate host keys, as seen in .Pa /etc/rc . @@ -99,7 +104,7 @@ The public key is stored in a file with the same name but 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 +(host keys must have an 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 @@ -114,7 +119,8 @@ 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 +For RSA1 keys, +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 @@ -138,8 +144,24 @@ The default is 1024 bits. 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 e +This option will read a private or public OpenSSH key file and +print the key in a +.Sq SECSH Public Key File Format +to stdout. +This option allows exporting keys for use by several commercial +SSH implementations. .It Fl f Specifies the filename of the key file. +.It Fl i +This option will read an unencrypted private (or public) key file +in SSH2-compatible format and print an OpenSSH compatible private +(or public) key to stdout. +.Nm +also reads the +.Sq SECSH Public Key File Format . +This option allows importing keys from several commercial +SSH implementations. .It Fl l Show fingerprint of specified private or public key file. .It Fl p @@ -154,31 +176,33 @@ Silence Used by .Pa /etc/rc when creating a new key. +.It Fl y +This option will read a private +OpenSSH format file and print an OpenSSH public key to stdout. +.It Fl t Ar type +Specifies the type of the key to create. +The possible values are +.Dq rsa1 +for protocol version 1 and +.Dq rsa +or +.Dq dsa +for protocol version 2. +The default is +.Dq rsa1 . +.It Fl B +Show the bubblebabble digest of specified private or public key file. .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 DSA format file and print a SSH2-compatible public key to stdout. -.It Fl X -This option will read a unencrypted -SSH2-compatible private (or public) key file and -print an OpenSSH compatible private (or public) key to stdout. -.It Fl y -This option will read a private -OpenSSH DSA format file and print an OpenSSH 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. +Contains the protocol version 1 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 @@ -189,14 +213,14 @@ 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. +Contains the protocol version 1 RSA 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. +Contains the protocol version 2 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 @@ -207,42 +231,50 @@ 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. +Contains the protocol version 2 DSA 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. +where you wish to log in using public key authentication. +There is no need to keep the contents of this file secret. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 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/id_rsa.pub +Contains the protocol version 2 RSA 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 public key authentication. There is no need to keep the contents of this file secret. .El -.Sh AUTHOR -Tatu Ylonen <ylo@cs.hut.fi> -.Pp -OpenSSH -is a derivative of the original (free) ssh 1.2.12 release, but with bugs -removed and newer features re-added. -Rapidly after the 1.2.12 release, -newer versions bore successively more restrictive licenses. -This version of OpenSSH -.Bl -bullet -.It -has all components of a restrictive nature (i.e., patents, see -.Xr ssl 8 ) -directly removed from the source code; any licensed or patented components -are chosen from -external libraries. -.It -has been updated to support ssh protocol 1.5. -.It -contains added support for -.Xr kerberos 8 -authentication and ticket passing. -.It -supports one-time password authentication with -.Xr skey 1 . -.El +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , -.Xr sshd 8 , -.Xr ssl 8 +.Xr sshd 8 +.Rs +.%A J. Galbraith +.%A R. Thayer +.%T "SECSH Public Key File Format" +.%N draft-ietf-secsh-publickeyfile-01.txt +.%D March 2001 +.%O work in progress material +.Re diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index e7b057f..90d5ffa 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -12,23 +12,21 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.60 2001/04/23 22:14:13 markus Exp $"); #include <openssl/evp.h> #include <openssl/pem.h> -#include <openssl/rsa.h> -#include <openssl/dsa.h> -#include "ssh.h" #include "xmalloc.h" #include "key.h" #include "rsa.h" -#include "dsa.h" #include "authfile.h" #include "uuencode.h" - #include "buffer.h" #include "bufaux.h" +#include "pathnames.h" +#include "log.h" +#include "readpass.h" /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ int bits = 1024; @@ -49,6 +47,7 @@ int quiet = 0; /* Flag indicating that we just want to see the key fingerprint */ int print_fingerprint = 0; +int print_bubblebabble = 0; /* The identity file name, given on the command line or entered by the user. */ char identity_file[1024]; @@ -67,7 +66,9 @@ char *identity_comment = NULL; int convert_to_ssh2 = 0; int convert_from_ssh2 = 0; int print_public = 0; -int dsa_mode = 0; + +/* default to RSA for SSH-1 */ +char *key_type_name = "rsa1"; /* argv0 */ extern char *__progname; @@ -78,11 +79,26 @@ 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 ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY); - printf("%s (%s): ", prompt, identity_file); - fflush(stdout); + char *name = NULL; + + switch (key_type_from_name(key_type_name)) { + case KEY_RSA1: + name = _PATH_SSH_CLIENT_IDENTITY; + break; + case KEY_DSA: + name = _PATH_SSH_CLIENT_ID_DSA; + break; + case KEY_RSA: + name = _PATH_SSH_CLIENT_ID_RSA; + break; + default: + fprintf(stderr, "bad key type"); + exit(1); + break; + } + snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); + fprintf(stderr, "%s (%s): ", prompt, identity_file); + fflush(stderr); if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1); if (strchr(buf, '\n')) @@ -92,32 +108,33 @@ ask_filename(struct passwd *pw, const char *prompt) have_identity = 1; } -int -try_load_key(char *filename, Key *k) +Key * +try_load_pem_key(char *filename) { - 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; - } + char *pass; + Key *prv; + + prv = key_load_private(filename, "", NULL); + if (prv == NULL) { + pass = read_passphrase("Enter passphrase: ", 1); + prv = key_load_private(filename, pass, NULL); memset(pass, 0, strlen(pass)); xfree(pass); } - return success; + return prv; } #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" -#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb +#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb void do_convert_to_ssh2(struct passwd *pw) { Key *k; int len; - unsigned char *blob; + u_char *blob; struct stat st; if (!have_identity) @@ -126,12 +143,13 @@ do_convert_to_ssh2(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); - if (!try_load_key(identity_file, k)) { - fprintf(stderr, "load failed\n"); - exit(1); + if ((k = key_load_public(identity_file, NULL)) == NULL) { + if ((k = try_load_pem_key(identity_file)) == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } } - dsa_make_key_blob(k, &blob, &len); + key_to_blob(k, &blob, &len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", @@ -149,9 +167,11 @@ buffer_get_bignum_bits(Buffer *b, BIGNUM *value) { int bits = buffer_get_int(b); int bytes = (bits + 7) / 8; + if (buffer_len(b) < bytes) - fatal("buffer_get_bignum_bits: input buffer too small"); - BN_bin2bn((unsigned char *)buffer_ptr(b), bytes, value); + fatal("buffer_get_bignum_bits: input buffer too small: " + "need %d have %d", bytes, buffer_len(b)); + BN_bin2bn((u_char *)buffer_ptr(b), bytes, value); buffer_consume(b, bytes); } @@ -159,9 +179,8 @@ Key * do_convert_private_ssh2_from_blob(char *blob, int blen) { Buffer b; - DSA *dsa; Key *key = NULL; - int ignore, magic, rlen; + int ignore, magic, rlen, ktype; char *type, *cipher; buffer_init(&b); @@ -179,33 +198,64 @@ do_convert_private_ssh2_from_blob(char *blob, int blen) ignore = buffer_get_int(&b); ignore = buffer_get_int(&b); ignore = buffer_get_int(&b); - xfree(type); if (strcmp(cipher, "none") != 0) { error("unsupported cipher %s", cipher); xfree(cipher); buffer_free(&b); + xfree(type); return NULL; } xfree(cipher); - key = key_new(KEY_DSA); - dsa = key->dsa; - dsa->priv_key = BN_new(); - if (dsa->priv_key == NULL) { - error("alloc priv_key failed"); - key_free(key); + if (strstr(type, "dsa")) { + ktype = KEY_DSA; + } else if (strstr(type, "rsa")) { + ktype = KEY_RSA; + } else { + xfree(type); return NULL; } - buffer_get_bignum_bits(&b, dsa->p); - buffer_get_bignum_bits(&b, dsa->g); - buffer_get_bignum_bits(&b, dsa->q); - buffer_get_bignum_bits(&b, dsa->pub_key); - buffer_get_bignum_bits(&b, dsa->priv_key); + key = key_new_private(ktype); + xfree(type); + + switch (key->type) { + case KEY_DSA: + buffer_get_bignum_bits(&b, key->dsa->p); + buffer_get_bignum_bits(&b, key->dsa->g); + buffer_get_bignum_bits(&b, key->dsa->q); + buffer_get_bignum_bits(&b, key->dsa->pub_key); + buffer_get_bignum_bits(&b, key->dsa->priv_key); + break; + case KEY_RSA: + if (!BN_set_word(key->rsa->e, (u_long) buffer_get_char(&b))) { + buffer_free(&b); + key_free(key); + return NULL; + } + buffer_get_bignum_bits(&b, key->rsa->d); + buffer_get_bignum_bits(&b, key->rsa->n); + buffer_get_bignum_bits(&b, key->rsa->iqmp); + buffer_get_bignum_bits(&b, key->rsa->q); + buffer_get_bignum_bits(&b, key->rsa->p); + generate_additional_parameters(key->rsa); + break; + } rlen = buffer_len(&b); if(rlen != 0) - error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen); + error("do_convert_private_ssh2_from_blob: " + "remaining bytes in key blob %d", rlen); buffer_free(&b); +#ifdef DEBUG_PK + { + u_int slen; + u_char *sig, data[10] = "abcde12345"; + + key_sign(key, &sig, &slen, data, sizeof data); + key_verify(key, sig, slen, data, sizeof data); + xfree(sig); + } +#endif return key; } @@ -244,31 +294,33 @@ do_convert_from_ssh2(struct passwd *pw) strstr(line, ": ") != NULL) { if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) private = 1; - fprintf(stderr, "ignore: %s", line); + /* fprintf(stderr, "ignore: %s", line); */ continue; } if (escaped) { escaped--; - fprintf(stderr, "escaped: %s", line); + /* fprintf(stderr, "escaped: %s", line); */ continue; } *p = '\0'; strlcat(encoded, line, sizeof(encoded)); } - blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob)); + blen = uudecode(encoded, (u_char *)blob, sizeof(blob)); if (blen < 0) { fprintf(stderr, "uudecode failed.\n"); exit(1); } k = private ? do_convert_private_ssh2_from_blob(blob, blen) : - dsa_key_from_blob(blob, blen); + key_from_blob(blob, blen); if (k == NULL) { fprintf(stderr, "decode blob failed.\n"); exit(1); } ok = private ? - PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : + (k->type == KEY_DSA ? + PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : + PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : key_write(k, stdout); if (!ok) { fprintf(stderr, "key write failed"); @@ -283,9 +335,7 @@ do_convert_from_ssh2(struct passwd *pw) void do_print_public(struct passwd *pw) { - Key *k; - int len; - unsigned char *blob; + Key *prv; struct stat st; if (!have_identity) @@ -294,16 +344,14 @@ do_print_public(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); - if (!try_load_key(identity_file, k)) { + prv = try_load_pem_key(identity_file); + if (prv == NULL) { fprintf(stderr, "load failed\n"); exit(1); } - dsa_make_key_blob(k, &blob, &len); - if (!key_write(k, stdout)) + if (!key_write(prv, stdout)) fprintf(stderr, "key_write failed"); - key_free(k); - xfree(blob); + key_free(prv); fprintf(stdout, "\n"); exit(0); } @@ -311,28 +359,32 @@ do_print_public(struct passwd *pw) 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; + char *comment = NULL, *cp, *ep, line[16*1024], *fp; + int i, skip = 0, num = 1, invalid = 1, rep, fptype; struct stat st; + fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + 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); + public = key_load_public(identity_file, &comment); + if (public != NULL) { + fp = key_fingerprint(public, fptype, rep); + printf("%d %s %s\n", key_size(public), fp, comment); key_free(public); + xfree(comment); + xfree(fp); exit(0); } + if (comment) + xfree(comment); f = fopen(identity_file, "r"); if (f != NULL) { @@ -370,17 +422,26 @@ do_fingerprint(struct passwd *pw) *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"); + public = key_new(KEY_RSA1); + if (key_read(public, &cp) != 1) { + cp = ep; + key_free(public); + public = key_new(KEY_UNSPEC); + if (key_read(public, &cp) != 1) { + key_free(public); + continue; + } } + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); + printf("%d %s %s\n", key_size(public), fp, + comment ? comment : "no comment"); + xfree(fp); + key_free(public); + invalid = 0; } fclose(f); } - key_free(public); if (invalid) { printf("%s is not a valid key file.\n", identity_file); exit(1); @@ -399,8 +460,6 @@ do_change_passphrase(struct passwd *pw) 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"); @@ -408,33 +467,20 @@ do_change_passphrase(struct passwd *pw) 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)) { + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { 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); + private = key_load_private(identity_file, old_passphrase , &comment); + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + if (private == NULL) { printf("Bad passphrase.\n"); exit(1); } - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); } printf("Key has comment '%s'\n", comment); @@ -462,9 +508,8 @@ do_change_passphrase(struct passwd *pw) } /* 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)); + if (!key_save_private(private, identity_file, passphrase1, comment)) { + printf("Saving the key failed: %s.\n", identity_file); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); key_free(private); @@ -487,12 +532,12 @@ do_change_passphrase(struct passwd *pw) void do_change_comment(struct passwd *pw) { - char new_comment[1024], *comment; + char new_comment[1024], *comment, *passphrase; Key *private; Key *public; - char *passphrase; struct stat st; FILE *f; + int fd; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); @@ -500,20 +545,8 @@ do_change_comment(struct passwd *pw) 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 { + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { if (identity_passphrase) passphrase = xstrdup(identity_passphrase); else if (identity_new_passphrase) @@ -521,13 +554,21 @@ do_change_comment(struct passwd *pw) else passphrase = read_passphrase("Enter passphrase: ", 1); /* Try to load using the passphrase. */ - if (!load_private_key(identity_file, passphrase, private, &comment)) { + private = key_load_private(identity_file, passphrase, &comment); + if (private == NULL) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); printf("Bad passphrase.\n"); exit(1); } + } else { + passphrase = xstrdup(""); } + if (private->type != KEY_RSA1) { + fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); + key_free(private); + exit(1); + } printf("Key now has comment '%s'\n", comment); if (identity_comment) { @@ -545,9 +586,8 @@ do_change_comment(struct passwd *pw) } /* 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)); + if (!key_save_private(private, identity_file, passphrase, new_comment)) { + printf("Saving the key failed: %s.\n", identity_file); memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); key_free(private); @@ -556,14 +596,20 @@ do_change_comment(struct passwd *pw) } memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); + public = key_from_private(private); key_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); - f = fopen(identity_file, "w"); - if (!f) { + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } if (!key_write(public, f)) fprintf(stderr, "write key failed"); key_free(public); @@ -579,7 +625,8 @@ do_change_comment(struct passwd *pw) void usage(void) { - printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); + printf("Usage: %s [-ceilpqyB] [-t type] [-b bits] [-f file] [-C comment] " + "[-N new-pass] [-P pass]\n", __progname); exit(1); } @@ -590,12 +637,12 @@ int main(int ac, char **av) { char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2; + Key *private, *public; struct passwd *pw; - int opt; + int opt, type, fd; struct stat st; FILE *f; - Key *private; - Key *public; + extern int optind; extern char *optarg; @@ -612,7 +659,7 @@ main(int ac, char **av) exit(1); } - while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) { + while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:P:N:C:")) != -1) { switch (opt) { case 'b': bits = atoi(optarg); @@ -626,6 +673,10 @@ main(int ac, char **av) print_fingerprint = 1; break; + case 'B': + print_bubblebabble = 1; + break; + case 'p': change_passphrase = 1; break; @@ -656,17 +707,19 @@ main(int ac, char **av) break; case 'R': - if (rsa_alive() == 0) - exit(1); - else - exit(0); + /* unused */ + exit(0); break; + case 'e': case 'x': + /* export key */ convert_to_ssh2 = 1; break; + case 'i': case 'X': + /* import key */ convert_from_ssh2 = 1; break; @@ -675,7 +728,11 @@ main(int ac, char **av) break; case 'd': - dsa_mode = 1; + key_type_name = "dsa"; + break; + + case 't': + key_type_name = optarg; break; case '?': @@ -691,14 +748,7 @@ main(int ac, char **av) 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) + if (print_fingerprint || print_bubblebabble) do_fingerprint(pw); if (change_passphrase) do_change_passphrase(pw); @@ -713,28 +763,25 @@ main(int ac, char **av) arc4random_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); + type = key_type_from_name(key_type_name); + if (type == KEY_UNSPEC) { + fprintf(stderr, "unknown key type %s\n", key_type_name); + exit(1); + } + if (!quiet) + printf("Generating public/private %s key pair.\n", key_type_name); + private = key_generate(type, bits); + if (private == NULL) { + fprintf(stderr, "key_generate failed"); + exit(1); } + public = key_from_private(private); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn\'t already exist. */ - snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR); + 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) @@ -785,9 +832,8 @@ passphrase_again: } /* 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)); + if (!key_save_private(private, identity_file, passphrase1, comment)) { + printf("Saving the key failed: %s.\n", identity_file); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); exit(1); @@ -797,30 +843,35 @@ passphrase_again: xfree(passphrase1); /* Clear the private key and the random number generator. */ - if (private != public) { - key_free(private); - } + key_free(private); arc4random_stir(); if (!quiet) printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); - f = fopen(identity_file, "w"); - if (!f) { + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } if (!key_write(public, f)) fprintf(stderr, "write key failed"); fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { + char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 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); + printf("%s %s\n", fp, comment); + xfree(fp); } key_free(public); diff --git a/crypto/openssh/ssh-keygen/Makefile b/crypto/openssh/ssh-keygen/Makefile index f03f56b..b7c1151 100644 --- a/crypto/openssh/ssh-keygen/Makefile +++ b/crypto/openssh/ssh-keygen/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:26 markus Exp $ + .PATH: ${.CURDIR}/.. PROG= ssh-keygen @@ -8,9 +10,9 @@ BINMODE?=555 BINDIR= /usr/bin MAN= ssh-keygen.1 -SRCS= ssh-keygen.c log-client.c +SRCS= ssh-keygen.c .include <bsd.prog.mk> -LDADD+= -lcrypto -lutil -lz -DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ} +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} diff --git a/crypto/openssh/ssh-keyscan.1 b/crypto/openssh/ssh-keyscan.1 new file mode 100644 index 0000000..4db8c5f --- /dev/null +++ b/crypto/openssh/ssh-keyscan.1 @@ -0,0 +1,104 @@ +.\" $OpenBSD: ssh-keyscan.1,v 1.5 2001/04/18 16:21:05 ian Exp $ +.\" +.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. +.\" +.\" Modification and redistribution in source and binary forms is +.\" permitted provided that due credit is given to the author and the +.\" OpenBSD project (for instance by leaving this copyright notice +.\" intact). +.\" +.Dd January 1, 1996 +.Dt SSH-KEYSCAN 1 +.Os +.Sh NAME +.Nm ssh-keyscan +.Nd gather ssh public keys +.Sh SYNOPSIS +.Nm ssh-keyscan +.Op Fl t Ar timeout +.Op Ar -- | host | addrlist namelist +.Op Fl f Ar files ... +.Sh DESCRIPTION +.Nm +is a utility for gathering the public ssh host keys of a number of +hosts. It was designed to aid in building and verifying +.Pa ssh_known_hosts +files. +.Nm +provides a minimal interface suitable for use by shell and perl +scripts. +.Pp +.Nm +uses non-blocking socket I/O to contact as many hosts as possible in +parallel, so it is very efficient. The keys from a domain of 1,000 +hosts can be collected in tens of seconds, even when some of those +hosts are down or do not run ssh. You do not need login access to the +machines you are scanning, nor does the scanning process involve +any encryption. +.Sh SECURITY +If you make an ssh_known_hosts file using +.Nm +without verifying the keys, you will be vulnerable to +.I man in the middle +attacks. +On the other hand, if your security model allows such a risk, +.Nm +can help you detect tampered keyfiles or man in the middle attacks which +have begun after you created your ssh_known_hosts file. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl t +Set the timeout for connection attempts. If +.Pa timeout +seconds have elapsed since a connection was initiated to a host or since the +last time anything was read from that host, then the connection is +closed and the host in question considered unavailable. Default is 5 +seconds. +.It Fl f +Read hosts or +.Pa addrlist namelist +pairs from this file, one per line. +If +.Pa - +is supplied instead of a filename, +.Nm +will read hosts or +.Pa addrlist namelist +pairs from the standard input. +.El +.Sh EXAMPLES +.Pp +Print the host key for machine +.Pa hostname : +.Bd -literal +ssh-keyscan hostname +.Ed +.Pp +Find all hosts from the file +.Pa ssh_hosts +which have new or different keys from those in the sorted file +.Pa ssh_known_hosts : +.Bd -literal +$ ssh-keyscan -f ssh_hosts | sort -u - ssh_known_hosts | \e\ + diff ssh_known_hosts - +.Ed +.Pp +.Sh FILES +.Pp +.Pa Input format: +1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 +.Pp +.Pa Output format: +host-or-namelist bits exponent modulus +.Pp +.Pa /etc/ssh_known_hosts +.Sh BUGS +It generates "Connection closed by remote host" messages on the consoles +of all the machines it scans. +This is because it opens a connection to the ssh port, reads the public +key, and drops the connection as soon as it gets the key. +.Sh SEE ALSO +.Xr ssh 1 , +.Xr sshd 8 +.Sh AUTHOR +David Mazieres <dm@lcs.mit.edu> diff --git a/crypto/openssh/ssh-keyscan.c b/crypto/openssh/ssh-keyscan.c new file mode 100644 index 0000000..dba2d83 --- /dev/null +++ b/crypto/openssh/ssh-keyscan.c @@ -0,0 +1,625 @@ +/* + * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. + * + * Modification and redistribution in source and binary forms is + * permitted provided that due credit is given to the author and the + * OpenBSD project (for instance by leaving this copyright notice + * intact). + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-keyscan.c,v 1.22 2001/03/06 06:11:18 deraadt Exp $"); + +#include <sys/queue.h> +#include <errno.h> + +#include <openssl/bn.h> + +#include "xmalloc.h" +#include "ssh.h" +#include "ssh1.h" +#include "key.h" +#include "buffer.h" +#include "bufaux.h" +#include "log.h" +#include "atomicio.h" + +static int argno = 1; /* Number of argument currently being parsed */ + +int family = AF_UNSPEC; /* IPv4, IPv6 or both */ + +#define MAXMAXFD 256 + +/* The number of seconds after which to give up on a TCP connection */ +int timeout = 5; + +int maxfd; +#define MAXCON (maxfd - 10) + +extern char *__progname; +fd_set *read_wait; +size_t read_wait_size; +int ncon; + +/* + * Keep a connection structure for each file descriptor. The state + * associated with file descriptor n is held in fdcon[n]. + */ +typedef struct Connection { + u_char c_status; /* State of connection on this file desc. */ +#define CS_UNUSED 0 /* File descriptor unused */ +#define CS_CON 1 /* Waiting to connect/read greeting */ +#define CS_SIZE 2 /* Waiting to read initial packet size */ +#define CS_KEYS 3 /* Waiting to read public key packet */ + int c_fd; /* Quick lookup: c->c_fd == c - fdcon */ + int c_plen; /* Packet length field for ssh packet */ + int c_len; /* Total bytes which must be read. */ + int c_off; /* Length of data read so far. */ + char *c_namebase; /* Address to free for c_name and c_namelist */ + char *c_name; /* Hostname of connection for errors */ + char *c_namelist; /* Pointer to other possible addresses */ + char *c_output_name; /* Hostname of connection for output */ + char *c_data; /* Data read from this fd */ + struct timeval c_tv; /* Time at which connection gets aborted */ + TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ +} con; + +TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ +con *fdcon; + +/* + * This is just a wrapper around fgets() to make it usable. + */ + +/* Stress-test. Increase this later. */ +#define LINEBUF_SIZE 16 + +typedef struct { + char *buf; + u_int size; + int lineno; + const char *filename; + FILE *stream; + void (*errfun) (const char *,...); +} Linebuf; + +Linebuf * +Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) +{ + Linebuf *lb; + + if (!(lb = malloc(sizeof(*lb)))) { + if (errfun) + (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); + return (NULL); + } + if (filename) { + lb->filename = filename; + if (!(lb->stream = fopen(filename, "r"))) { + xfree(lb); + if (errfun) + (*errfun) ("%s: %s\n", filename, strerror(errno)); + return (NULL); + } + } else { + lb->filename = "(stdin)"; + lb->stream = stdin; + } + + if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) { + if (errfun) + (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); + xfree(lb); + return (NULL); + } + lb->errfun = errfun; + lb->lineno = 0; + return (lb); +} + +void +Linebuf_free(Linebuf * lb) +{ + fclose(lb->stream); + xfree(lb->buf); + xfree(lb); +} + +void +Linebuf_restart(Linebuf * lb) +{ + clearerr(lb->stream); + rewind(lb->stream); + lb->lineno = 0; +} + +int +Linebuf_lineno(Linebuf * lb) +{ + return (lb->lineno); +} + +char * +Linebuf_getline(Linebuf * lb) +{ + int n = 0; + + lb->lineno++; + for (;;) { + /* Read a line */ + if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { + if (ferror(lb->stream) && lb->errfun) + (*lb->errfun) ("%s: %s\n", lb->filename, + strerror(errno)); + return (NULL); + } + n = strlen(lb->buf); + + /* Return it or an error if it fits */ + if (n > 0 && lb->buf[n - 1] == '\n') { + lb->buf[n - 1] = '\0'; + return (lb->buf); + } + if (n != lb->size - 1) { + if (lb->errfun) + (*lb->errfun) ("%s: skipping incomplete last line\n", + lb->filename); + return (NULL); + } + /* Double the buffer if we need more space */ + if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) { + if (lb->errfun) + (*lb->errfun) ("linebuf (%s): realloc failed\n", + lb->filename); + return (NULL); + } + } +} + +int +fdlim_get(int hard) +{ + struct rlimit rlfd; + + if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) + return 10000; + else + return hard ? rlfd.rlim_max : rlfd.rlim_cur; +} + +int +fdlim_set(int lim) +{ + struct rlimit rlfd; + if (lim <= 0) + return (-1); + if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + rlfd.rlim_cur = lim; + if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + return (0); +} + +/* + * This is an strsep function that returns a null field for adjacent + * separators. This is the same as the 4.4BSD strsep, but different from the + * one in the GNU libc. + */ +char * +xstrsep(char **str, const char *delim) +{ + char *s, *e; + + if (!**str) + return (NULL); + + s = *str; + e = s + strcspn(s, delim); + + if (*e != '\0') + *e++ = '\0'; + *str = e; + + return (s); +} + +/* + * Get the next non-null token (like GNU strsep). Strsep() will return a + * null token for two adjacent separators, so we may have to loop. + */ +char * +strnnsep(char **stringp, char *delim) +{ + char *tok; + + do { + tok = xstrsep(stringp, delim); + } while (tok && *tok == '\0'); + return (tok); +} + +void +keyprint(char *host, char *output_name, char *kd, int len) +{ + static Key *rsa; + static Buffer msg; + + if (rsa == NULL) { + buffer_init(&msg); + rsa = key_new(KEY_RSA1); + } + buffer_append(&msg, kd, len); + buffer_consume(&msg, 8 - (len & 7)); /* padding */ + if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { + error("%s: invalid packet type", host); + buffer_clear(&msg); + return; + } + buffer_consume(&msg, 8); /* cookie */ + + /* server key */ + (void) buffer_get_int(&msg); + buffer_get_bignum(&msg, rsa->rsa->e); + buffer_get_bignum(&msg, rsa->rsa->n); + + /* host key */ + (void) buffer_get_int(&msg); + buffer_get_bignum(&msg, rsa->rsa->e); + buffer_get_bignum(&msg, rsa->rsa->n); + buffer_clear(&msg); + + fprintf(stdout, "%s ", output_name ? output_name : host); + key_write(rsa, stdout); + fputs("\n", stdout); +} + +int +tcpconnect(char *host) +{ + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr, s = -1; + + snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) + fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); + for (ai = aitop; ai; ai = ai->ai_next) { + s = socket(ai->ai_family, SOCK_STREAM, 0); + if (s < 0) { + error("socket: %s", strerror(errno)); + continue; + } + if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) + fatal("F_SETFL: %s", strerror(errno)); + if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 && + errno != EINPROGRESS) + error("connect (`%s'): %s", host, strerror(errno)); + else + break; + close(s); + s = -1; + } + freeaddrinfo(aitop); + return s; +} + +int +conalloc(char *iname, char *oname) +{ + int s; + char *namebase, *name, *namelist; + + namebase = namelist = xstrdup(iname); + + do { + name = xstrsep(&namelist, ","); + if (!name) { + xfree(namebase); + return (-1); + } + } while ((s = tcpconnect(name)) < 0); + + if (s >= maxfd) + fatal("conalloc: fdno %d too high", s); + if (fdcon[s].c_status) + fatal("conalloc: attempt to reuse fdno %d", s); + + fdcon[s].c_fd = s; + fdcon[s].c_status = CS_CON; + fdcon[s].c_namebase = namebase; + fdcon[s].c_name = name; + fdcon[s].c_namelist = namelist; + fdcon[s].c_output_name = xstrdup(oname); + fdcon[s].c_data = (char *) &fdcon[s].c_plen; + fdcon[s].c_len = 4; + fdcon[s].c_off = 0; + gettimeofday(&fdcon[s].c_tv, NULL); + fdcon[s].c_tv.tv_sec += timeout; + TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); + FD_SET(s, read_wait); + ncon++; + return (s); +} + +void +confree(int s) +{ + if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) + fatal("confree: attempt to free bad fdno %d", s); + close(s); + xfree(fdcon[s].c_namebase); + xfree(fdcon[s].c_output_name); + if (fdcon[s].c_status == CS_KEYS) + xfree(fdcon[s].c_data); + fdcon[s].c_status = CS_UNUSED; + TAILQ_REMOVE(&tq, &fdcon[s], c_link); + FD_CLR(s, read_wait); + ncon--; +} + +void +contouch(int s) +{ + TAILQ_REMOVE(&tq, &fdcon[s], c_link); + gettimeofday(&fdcon[s].c_tv, NULL); + fdcon[s].c_tv.tv_sec += timeout; + TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); +} + +int +conrecycle(int s) +{ + int ret; + con *c = &fdcon[s]; + char *iname, *oname; + + iname = xstrdup(c->c_namelist); + oname = xstrdup(c->c_output_name); + confree(s); + ret = conalloc(iname, oname); + xfree(iname); + xfree(oname); + return (ret); +} + +void +congreet(int s) +{ + char buf[80], *cp; + size_t bufsiz; + int n = 0; + con *c = &fdcon[s]; + + bufsiz = sizeof(buf); + cp = buf; + while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r') + cp++; + if (n < 0) { + if (errno != ECONNREFUSED) + error("read (%s): %s", c->c_name, strerror(errno)); + conrecycle(s); + return; + } + if (*cp != '\n' && *cp != '\r') { + error("%s: bad greeting", c->c_name); + confree(s); + return; + } + *cp = '\0'; + fprintf(stderr, "# %s %s\n", c->c_name, buf); + n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); + if (atomicio(write, s, buf, n) != n) { + error("write (%s): %s", c->c_name, strerror(errno)); + confree(s); + return; + } + c->c_status = CS_SIZE; + contouch(s); +} + +void +conread(int s) +{ + int n; + con *c = &fdcon[s]; + + if (c->c_status == CS_CON) { + congreet(s); + return; + } + n = read(s, c->c_data + c->c_off, c->c_len - c->c_off); + if (n < 0) { + error("read (%s): %s", c->c_name, strerror(errno)); + confree(s); + return; + } + c->c_off += n; + + if (c->c_off == c->c_len) + switch (c->c_status) { + case CS_SIZE: + c->c_plen = htonl(c->c_plen); + c->c_len = c->c_plen + 8 - (c->c_plen & 7); + c->c_off = 0; + c->c_data = xmalloc(c->c_len); + c->c_status = CS_KEYS; + break; + case CS_KEYS: + keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen); + confree(s); + return; + break; + default: + fatal("conread: invalid status %d", c->c_status); + break; + } + + contouch(s); +} + +void +conloop(void) +{ + fd_set *r, *e; + struct timeval seltime, now; + int i; + con *c; + + gettimeofday(&now, NULL); + c = tq.tqh_first; + + if (c && (c->c_tv.tv_sec > now.tv_sec || + (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) { + seltime = c->c_tv; + seltime.tv_sec -= now.tv_sec; + seltime.tv_usec -= now.tv_usec; + if (seltime.tv_usec < 0) { + seltime.tv_usec += 1000000; + seltime.tv_sec--; + } + } else + seltime.tv_sec = seltime.tv_usec = 0; + + r = xmalloc(read_wait_size); + memcpy(r, read_wait, read_wait_size); + e = xmalloc(read_wait_size); + memcpy(e, read_wait, read_wait_size); + + while (select(maxfd, r, NULL, e, &seltime) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; + + for (i = 0; i < maxfd; i++) { + if (FD_ISSET(i, e)) { + error("%s: exception!", fdcon[i].c_name); + confree(i); + } else if (FD_ISSET(i, r)) + conread(i); + } + xfree(r); + xfree(e); + + c = tq.tqh_first; + while (c && (c->c_tv.tv_sec < now.tv_sec || + (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { + int s = c->c_fd; + + c = c->c_link.tqe_next; + conrecycle(s); + } +} + +char * +nexthost(int argc, char **argv) +{ + static Linebuf *lb; + + for (;;) { + if (!lb) { + if (argno >= argc) + return (NULL); + if (argv[argno][0] != '-') + return (argv[argno++]); + if (!strcmp(argv[argno], "--")) { + if (++argno >= argc) + return (NULL); + return (argv[argno++]); + } else if (!strncmp(argv[argno], "-f", 2)) { + char *fname; + + if (argv[argno][2]) + fname = &argv[argno++][2]; + else if (++argno >= argc) { + error("missing filename for `-f'"); + return (NULL); + } else + fname = argv[argno++]; + if (!strcmp(fname, "-")) + fname = NULL; + lb = Linebuf_alloc(fname, error); + } else + error("ignoring invalid/misplaced option `%s'", + argv[argno++]); + } else { + char *line; + + line = Linebuf_getline(lb); + if (line) + return (line); + Linebuf_free(lb); + lb = NULL; + } + } +} + +void +usage(void) +{ + fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname); + return; +} + +int +main(int argc, char **argv) +{ + char *host = NULL; + + TAILQ_INIT(&tq); + + if (argc <= argno) + usage(); + + if (argv[1][0] == '-' && argv[1][1] == 't') { + argno++; + if (argv[1][2]) + timeout = atoi(&argv[1][2]); + else { + if (argno >= argc) + usage(); + timeout = atoi(argv[argno++]); + } + if (timeout <= 0) + usage(); + } + if (argc <= argno) + usage(); + + maxfd = fdlim_get(1); + if (maxfd < 0) + fatal("%s: fdlim_get: bad value", __progname); + if (maxfd > MAXMAXFD) + maxfd = MAXMAXFD; + if (MAXCON <= 0) + fatal("%s: not enough file descriptors", __progname); + if (maxfd > fdlim_get(0)) + fdlim_set(maxfd); + fdcon = xmalloc(maxfd * sizeof(con)); + memset(fdcon, 0, maxfd * sizeof(con)); + + read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + read_wait = xmalloc(read_wait_size); + memset(read_wait, 0, read_wait_size); + + do { + while (ncon < MAXCON) { + char *name; + + host = nexthost(argc, argv); + if (host == NULL) + break; + name = strnnsep(&host, " \t\n"); + conalloc(name, *host ? host : name); + } + conloop(); + } while (host); + while (ncon > 0) + conloop(); + + return (0); +} diff --git a/crypto/openssh/ssh-keyscan/Makefile b/crypto/openssh/ssh-keyscan/Makefile new file mode 100644 index 0000000..6748ed7 --- /dev/null +++ b/crypto/openssh/ssh-keyscan/Makefile @@ -0,0 +1,18 @@ +# $OpenBSD: Makefile,v 1.3 2001/03/03 23:59:39 markus Exp $ + +.PATH: ${.CURDIR}/.. + +PROG= ssh-keyscan +BINOWN= root + +BINMODE?=555 + +BINDIR= /usr/bin +MAN= ssh-keyscan.1 + +SRCS= ssh-keyscan.c + +.include <bsd.prog.mk> + +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c new file mode 100644 index 0000000..b502ddb --- /dev/null +++ b/crypto/openssh/ssh-rsa.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-rsa.c,v 1.8 2001/03/27 10:57:00 markus Exp $"); + +#include <openssl/evp.h> +#include <openssl/err.h> + +#include "xmalloc.h" +#include "log.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "ssh-rsa.h" +#include "compat.h" + +/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ +int +ssh_rsa_sign( + Key *key, + u_char **sigp, int *lenp, + u_char *data, int datalen) +{ + const EVP_MD *evp_md; + EVP_MD_CTX md; + u_char *digest, *sig, *ret; + u_int slen, dlen, len; + int ok, nid; + Buffer b; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_sign: no RSA key"); + return -1; + } + nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; + if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { + error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); + return -1; + } + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + slen = RSA_size(key->rsa); + sig = xmalloc(slen); + + ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + + if (ok != 1) { + int ecode = ERR_get_error(); + error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL)); + xfree(sig); + return -1; + } + if (len < slen) { + int diff = slen - len; + debug("slen %d > len %d", slen, len); + memmove(sig + diff, sig, len); + memset(sig, 0, diff); + } else if (len > slen) { + error("ssh_rsa_sign: slen %d slen2 %d", slen, len); + xfree(sig); + return -1; + } + /* encode signature */ + buffer_init(&b); + buffer_put_cstring(&b, "ssh-rsa"); + buffer_put_string(&b, sig, slen); + len = buffer_len(&b); + ret = xmalloc(len); + memcpy(ret, buffer_ptr(&b), len); + buffer_free(&b); + memset(sig, 's', slen); + xfree(sig); + + if (lenp != NULL) + *lenp = len; + if (sigp != NULL) + *sigp = ret; + debug2("ssh_rsa_sign: done"); + return 0; +} + +int +ssh_rsa_verify( + Key *key, + u_char *signature, int signaturelen, + u_char *data, int datalen) +{ + Buffer b; + const EVP_MD *evp_md; + EVP_MD_CTX md; + char *ktype; + u_char *sigblob, *digest; + u_int len, dlen; + int rlen, ret, nid; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_verify: no RSA key"); + return -1; + } + if (BN_num_bits(key->rsa->n) < 768) { + error("ssh_rsa_verify: n too small: %d bits", + BN_num_bits(key->rsa->n)); + return -1; + } + buffer_init(&b); + buffer_append(&b, (char *) signature, signaturelen); + ktype = buffer_get_string(&b, NULL); + if (strcmp("ssh-rsa", ktype) != 0) { + error("ssh_rsa_verify: cannot handle type %s", ktype); + buffer_free(&b); + xfree(ktype); + return -1; + } + xfree(ktype); + sigblob = (u_char *)buffer_get_string(&b, &len); + rlen = buffer_len(&b); + buffer_free(&b); + if(rlen != 0) { + xfree(sigblob); + error("ssh_rsa_verify: remaining bytes in signature %d", rlen); + return -1; + } + nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; + if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { + xfree(sigblob); + error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); + return -1; + } + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + memset(sigblob, 's', len); + xfree(sigblob); + if (ret == 0) { + int ecode = ERR_get_error(); + error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL)); + } + debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); + return ret; +} diff --git a/crypto/openssh/ssh-rsa.h b/crypto/openssh/ssh-rsa.h new file mode 100644 index 0000000..af2b2fe --- /dev/null +++ b/crypto/openssh/ssh-rsa.h @@ -0,0 +1,41 @@ +/* $OpenBSD: ssh-rsa.h,v 1.3 2001/01/29 01:58:18 niklas 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 SSH_RSA_H +#define SSH_RSA_H + +int +ssh_rsa_sign( + Key *key, + u_char **sigp, int *lenp, + u_char *data, int datalen); + +int +ssh_rsa_verify( + Key *key, + u_char *signature, int signaturelen, + u_char *data, int datalen); + +#endif diff --git a/crypto/openssh/ssh/Makefile b/crypto/openssh/ssh/Makefile index bd41531..2cf80e1 100644 --- a/crypto/openssh/ssh/Makefile +++ b/crypto/openssh/ssh/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.30 2001/04/14 16:33:20 stevesk Exp $ + .PATH: ${.CURDIR}/.. PROG= ssh @@ -10,7 +12,7 @@ MAN= ssh.1 LINKS= ${BINDIR}/ssh ${BINDIR}/slogin MLINKS= ssh.1 slogin.1 -SRCS= ssh.c log-client.c readconf.c clientloop.c \ +SRCS= ssh.c readconf.c clientloop.c sshtty.c \ sshconnect.c sshconnect1.c sshconnect2.c .include <bsd.own.mk> # for AFS @@ -28,5 +30,5 @@ DPADD+= ${LIBKRBAFS} .include <bsd.prog.mk> -LDADD+= -lutil -lz -lcrypto -DPADD+= ${LIBCRYPTO} ${LIBUTIL} ${LIBZ} +LDADD+= -lcrypto -lz +DPADD+= ${LIBCRYPTO} ${LIBZ} diff --git a/crypto/openssh/ssh1.h b/crypto/openssh/ssh1.h new file mode 100644 index 0000000..770c5e4 --- /dev/null +++ b/crypto/openssh/ssh1.h @@ -0,0 +1,86 @@ +/* $OpenBSD: ssh1.h,v 1.2 2001/01/29 01:58:18 niklas Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +/* + * Definition of message types. New values can be added, but old values + * should not be removed or without careful consideration of the consequences + * for compatibility. The maximum value is 254; value 255 is reserved for + * future extension. + */ +/* Message name */ /* msg code */ /* arguments */ +#define SSH_MSG_NONE 0 /* no message */ +#define SSH_MSG_DISCONNECT 1 /* cause (string) */ +#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ +#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */ +#define SSH_CMSG_USER 4 /* user (string) */ +#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */ +#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */ +#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */ +#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */ +#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */ +#define SSH_CMSG_EXEC_SHELL 12 /* */ +#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */ +#define SSH_SMSG_SUCCESS 14 /* */ +#define SSH_SMSG_FAILURE 15 /* */ +#define SSH_CMSG_STDIN_DATA 16 /* data (string) */ +#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */ +#define SSH_SMSG_STDERR_DATA 18 /* data (string) */ +#define SSH_CMSG_EOF 19 /* */ +#define SSH_SMSG_EXITSTATUS 20 /* status (int) */ +#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */ +#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */ +#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */ +#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */ +#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */ +/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */ +#define SSH_SMSG_X11_OPEN 27 /* channel (int) */ +#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */ +#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */ +#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */ +#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */ +#define SSH_MSG_IGNORE 32 /* string */ +#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */ +#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */ +#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */ +#define SSH_MSG_DEBUG 36 /* string */ +#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */ +#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */ +#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */ +#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */ +#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */ +#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */ +#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */ +#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */ +#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */ + +/* + * 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 */ + diff --git a/crypto/openssh/ssh2.h b/crypto/openssh/ssh2.h index fe0146c..e45aef2 100644 --- a/crypto/openssh/ssh2.h +++ b/crypto/openssh/ssh2.h @@ -52,7 +52,7 @@ * * 192-255 Local extensions */ -/* RCSID("$OpenBSD: ssh2.h,v 1.5 2000/10/11 04:02:17 provos Exp $"); */ +/* RCSID("$OpenBSD: ssh2.h,v 1.6 2001/03/27 17:46:49 provos Exp $"); */ /* transport layer: generic */ @@ -74,10 +74,11 @@ #define SSH2_MSG_KEXDH_REPLY 31 /* dh-group-exchange */ -#define SSH2_MSG_KEX_DH_GEX_REQUEST 30 +#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 #define SSH2_MSG_KEX_DH_GEX_GROUP 31 #define SSH2_MSG_KEX_DH_GEX_INIT 32 #define SSH2_MSG_KEX_DH_GEX_REPLY 33 +#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 /* user authentication: generic */ diff --git a/crypto/openssh/sshd/Makefile b/crypto/openssh/sshd/Makefile index 0a9fba8..5ccce8d 100644 --- a/crypto/openssh/sshd/Makefile +++ b/crypto/openssh/sshd/Makefile @@ -1,3 +1,5 @@ +# $OpenBSD: Makefile,v 1.38 2001/03/29 21:17:40 markus Exp $ + .PATH: ${.CURDIR}/.. PROG= sshd @@ -8,8 +10,9 @@ MAN= sshd.8 CFLAGS+=-DHAVE_LOGIN_CAP SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \ - pty.c log-server.c login.c servconf.c serverloop.c \ - auth.c auth1.c auth2.c auth-options.c session.c dh.c + sshpty.c sshlogin.c servconf.c serverloop.c \ + auth.c auth1.c auth2.c auth-options.c session.c \ + auth-chall.c auth2-chall.c groupaccess.c .include <bsd.own.mk> # for KERBEROS and AFS @@ -25,10 +28,6 @@ LDADD+= -lkrb DPADD+= ${LIBKRB} .endif # KERBEROS -.if (${SKEY:L} == "yes") -SRCS+= auth-skey.c auth2-skey.c -.endif - .include <bsd.prog.mk> LDADD+= -lcrypto -lutil -lz diff --git a/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c new file mode 100644 index 0000000..a8a76c6 --- /dev/null +++ b/crypto/openssh/sshlogin.c @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#include "includes.h" +RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $"); + +#include <util.h> +#include <utmp.h> +#include "sshlogin.h" +#include "log.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. + */ + +u_long +get_last_login_time(uid_t uid, const char *logname, + char *buf, u_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; + + /* 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)); + + 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, "", ""); +} diff --git a/crypto/openssh/sshlogin.h b/crypto/openssh/sshlogin.h new file mode 100644 index 0000000..7285bc2 --- /dev/null +++ b/crypto/openssh/sshlogin.h @@ -0,0 +1,40 @@ +/* $OpenBSD: sshlogin.h,v 1.1 2001/03/04 01:46:30 djm 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 SSHLOGIN_H +#define SSHLOGIN_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 from which the user logged in is stored in buf. + */ +u_long +get_last_login_time(uid_t uid, const char *logname, + char *buf, u_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); + +#endif diff --git a/crypto/openssh/sshpty.c b/crypto/openssh/sshpty.c new file mode 100644 index 0000000..d0f2554 --- /dev/null +++ b/crypto/openssh/sshpty.c @@ -0,0 +1,297 @@ +/* + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $"); + +#include <util.h> +#include "sshpty.h" +#include "log.h" + +/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ +#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) +#undef HAVE_DEV_PTMX +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +/* + * Allocates and opens a pty. Returns 0 if no pty could be allocated, or + * nonzero if a pty was successfully allocated. On success, open file + * descriptors for the pty and tty sides and the name of the tty side are + * returned (the buffer must be able to hold at least 64 characters). + */ + +int +pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) +{ +#if defined(HAVE_OPENPTY) || defined(BSD4_4) + /* openpty(3) exists in OSF/1 and some other os'es */ + char buf[64]; + int i; + + i = openpty(ptyfd, ttyfd, buf, NULL, NULL); + if (i < 0) { + error("openpty: %.100s", strerror(errno)); + return 0; + } + strlcpy(namebuf, buf, namebuflen); /* possible truncation */ + return 1; +#else /* HAVE_OPENPTY */ +#ifdef HAVE__GETPTY + /* + * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more + * pty's automagically when needed + */ + char *slave; + + slave = _getpty(ptyfd, O_RDWR, 0622, 0); + if (slave == NULL) { + error("_getpty: %.100s", strerror(errno)); + return 0; + } + strlcpy(namebuf, slave, namebuflen); + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); + if (*ttyfd < 0) { + error("%.200s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; +#else /* HAVE__GETPTY */ +#ifdef HAVE_DEV_PTMX + /* + * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 + * also has bsd-style ptys, but they simply do not work.) + */ + int ptm; + char *pts; + + ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (ptm < 0) { + error("/dev/ptmx: %.100s", strerror(errno)); + return 0; + } + if (grantpt(ptm) < 0) { + error("grantpt: %.100s", strerror(errno)); + return 0; + } + if (unlockpt(ptm) < 0) { + error("unlockpt: %.100s", strerror(errno)); + return 0; + } + pts = ptsname(ptm); + if (pts == NULL) + error("Slave pty side name could not be obtained."); + strlcpy(namebuf, pts, namebuflen); + *ptyfd = ptm; + + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); + if (*ttyfd < 0) { + error("%.100s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + /* Push the appropriate streams modules, as described in Solaris pts(7). */ + if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) + error("ioctl I_PUSH ptem: %.100s", strerror(errno)); + if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) + error("ioctl I_PUSH ldterm: %.100s", strerror(errno)); + if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0) + error("ioctl I_PUSH ttcompat: %.100s", strerror(errno)); + return 1; +#else /* HAVE_DEV_PTMX */ +#ifdef HAVE_DEV_PTS_AND_PTC + /* AIX-style pty code. */ + const char *name; + + *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY); + if (*ptyfd < 0) { + error("Could not open /dev/ptc: %.100s", strerror(errno)); + return 0; + } + name = ttyname(*ptyfd); + if (!name) + fatal("Open of /dev/ptc returns device for which ttyname fails."); + strlcpy(namebuf, name, namebuflen); + *ttyfd = open(name, O_RDWR | O_NOCTTY); + if (*ttyfd < 0) { + error("Could not open pty slave side %.100s: %.100s", + name, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; +#else /* HAVE_DEV_PTS_AND_PTC */ + /* BSD-style pty code. */ + char buf[64]; + int i; + const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char *ptyminors = "0123456789abcdef"; + int num_minors = strlen(ptyminors); + int num_ptys = strlen(ptymajors) * num_minors; + + for (i = 0; i < num_ptys; i++) { + snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors], + ptyminors[i % num_minors]); + *ptyfd = open(buf, O_RDWR | O_NOCTTY); + if (*ptyfd < 0) + continue; + snprintf(namebuf, namebuflen, "/dev/tty%c%c", + ptymajors[i / num_minors], ptyminors[i % num_minors]); + + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); + if (*ttyfd < 0) { + error("%.100s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; + } + return 0; +#endif /* HAVE_DEV_PTS_AND_PTC */ +#endif /* HAVE_DEV_PTMX */ +#endif /* HAVE__GETPTY */ +#endif /* HAVE_OPENPTY */ +} + +/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */ + +void +pty_release(const char *ttyname) +{ + if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0) + error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno)); + if (chmod(ttyname, (mode_t) 0666) < 0) + error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno)); +} + +/* Makes the tty the processes controlling tty and sets it to sane modes. */ + +void +pty_make_controlling_tty(int *ttyfd, const char *ttyname) +{ + int fd; + + /* First disconnect from the old controlling tty. */ +#ifdef TIOCNOTTY + fd = open(_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."); + if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) + error("ioctl(TIOCSCTTY): %.100s", strerror(errno)); +#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 /dev/tty failed - could not set controlling tty: %.100s", + strerror(errno)); + else { + close(fd); + } +} + +/* Changes the window size associated with the pty. */ + +void +pty_change_window_size(int ptyfd, int row, int col, + int xpixel, int ypixel) +{ + struct winsize w; + w.ws_row = row; + w.ws_col = col; + w.ws_xpixel = xpixel; + w.ws_ypixel = ypixel; + (void) ioctl(ptyfd, TIOCSWINSZ, &w); +} + +void +pty_setowner(struct passwd *pw, const char *ttyname) +{ + struct group *grp; + gid_t gid; + mode_t mode; + struct stat st; + + /* 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 owner and mode of the tty as required. + * Warn but continue if filesystem is read-only and the uids match. + */ + if (stat(ttyname, &st)) + fatal("stat(%.100s) failed: %.100s", ttyname, + strerror(errno)); + + if (st.st_uid != pw->pw_uid || st.st_gid != gid) { + if (chown(ttyname, pw->pw_uid, gid) < 0) { + if (errno == EROFS && st.st_uid == pw->pw_uid) + error("chown(%.100s, %d, %d) failed: %.100s", + ttyname, pw->pw_uid, gid, + strerror(errno)); + else + fatal("chown(%.100s, %d, %d) failed: %.100s", + ttyname, pw->pw_uid, gid, + strerror(errno)); + } + } + + if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { + if (chmod(ttyname, mode) < 0) { + if (errno == EROFS && + (st.st_mode & (S_IRGRP | S_IROTH)) == 0) + error("chmod(%.100s, 0%o) failed: %.100s", + ttyname, mode, strerror(errno)); + else + fatal("chmod(%.100s, 0%o) failed: %.100s", + ttyname, mode, strerror(errno)); + } + } +} diff --git a/crypto/openssh/sshpty.h b/crypto/openssh/sshpty.h new file mode 100644 index 0000000..d7aac0f --- /dev/null +++ b/crypto/openssh/sshpty.h @@ -0,0 +1,47 @@ +/* + * 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". + */ + +/* RCSID("$OpenBSD: sshpty.h,v 1.1 2001/03/04 01:46:30 djm Exp $"); */ + +#ifndef SSHPTY_H +#define SSHPTY_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 /* SSHPTY_H */ diff --git a/crypto/openssh/sshtty.c b/crypto/openssh/sshtty.c new file mode 100644 index 0000000..7849890 --- /dev/null +++ b/crypto/openssh/sshtty.c @@ -0,0 +1,96 @@ +/* $OpenBSD: sshtty.c,v 1.1 2001/04/14 16:33:20 stevesk Exp $ */ +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include "sshtty.h" +#include "log.h" + +static struct termios _saved_tio; +static int _in_raw_mode = 0; + +int +in_raw_mode(void) +{ + return _in_raw_mode; +} + +struct termios +get_saved_tio(void) +{ + return _saved_tio; +} + +void +leave_raw_mode(void) +{ + if (!_in_raw_mode) + return; + if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) + perror("tcsetattr"); + else + _in_raw_mode = 0; + + fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL); +} + +void +enter_raw_mode(void) +{ + struct termios tio; + + if (tcgetattr(fileno(stdin), &tio) == -1) { + perror("tcgetattr"); + return; + } + _saved_tio = tio; + tio.c_iflag |= IGNPAR; + tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); +#ifdef IEXTEN + tio.c_lflag &= ~IEXTEN; +#endif + tio.c_oflag &= ~OPOST; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) + perror("tcsetattr"); + else + _in_raw_mode = 1; + + fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL); +} diff --git a/crypto/openssh/sshtty.h b/crypto/openssh/sshtty.h new file mode 100644 index 0000000..e29385e --- /dev/null +++ b/crypto/openssh/sshtty.h @@ -0,0 +1,65 @@ +/* $OpenBSD: sshtty.h,v 1.1 2001/04/14 16:33:20 stevesk Exp $ */ +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SSHTTY_H +#define SSHTTY_H + +#include <termios.h> + +/* + * Accessor function indicating whether we are in raw mode. Set by + * enter_raw_mode() and leave_raw_mode(). + */ +int in_raw_mode(void); + +/* + * Return terminal modes, as saved by enter_raw_mode(). + */ +struct termios get_saved_tio(void); + +/* + * Returns the user's terminal to normal mode if it had been + * put in raw mode. + */ +void leave_raw_mode(void); + +/* + * Puts the user's terminal in raw mode. + */ +void enter_raw_mode(void); + +#endif diff --git a/crypto/openssh/tildexpand.c b/crypto/openssh/tildexpand.c index f25f7d9..46bdaae 100644 --- a/crypto/openssh/tildexpand.c +++ b/crypto/openssh/tildexpand.c @@ -11,10 +11,11 @@ */ #include "includes.h" -RCSID("$OpenBSD: tildexpand.c,v 1.8 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: tildexpand.c,v 1.11 2001/02/08 19:30:53 itojun Exp $"); #include "xmalloc.h" -#include "ssh.h" +#include "log.h" +#include "tildexpand.h" /* * Expands tildes in the file name. Returns data allocated by xmalloc. @@ -24,7 +25,7 @@ char * tilde_expand_filename(const char *filename, uid_t my_uid) { const char *cp; - unsigned int userlen; + u_int userlen; char *expanded; struct passwd *pw; char user[100]; diff --git a/crypto/openssh/tildexpand.h b/crypto/openssh/tildexpand.h new file mode 100644 index 0000000..88734f4 --- /dev/null +++ b/crypto/openssh/tildexpand.h @@ -0,0 +1,19 @@ +/* $OpenBSD: tildexpand.h,v 1.2 2001/01/29 01:58:19 niklas Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +/* + * 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); diff --git a/crypto/openssh/ttymodes.c b/crypto/openssh/ttymodes.c index a7a3e93..6124cb4 100644 --- a/crypto/openssh/ttymodes.c +++ b/crypto/openssh/ttymodes.c @@ -2,10 +2,6 @@ * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved - * Encoding and decoding of terminal modes in a portable way. - * Much of the format is defined in ttymodes.h; it is included multiple times - * into this file with the appropriate macro definitions to generate the - * suitable code. * * 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 @@ -14,15 +10,56 @@ * called by a name other than "ssh" or "Secure Shell". */ +/* + * SSH2 tty modes support by Kevin Steves. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Encoding and decoding of terminal modes in a portable way. + * Much of the format is defined in ttymodes.h; it is included multiple times + * into this file with the appropriate macro definitions to generate the + * suitable code. + */ + #include "includes.h" -RCSID("$OpenBSD: ttymodes.c,v 1.8 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: ttymodes.c,v 1.13 2001/04/15 01:35:22 stevesk Exp $"); #include "packet.h" -#include "ssh.h" +#include "log.h" +#include "ssh1.h" +#include "compat.h" +#include "buffer.h" +#include "bufaux.h" -#define TTY_OP_END 0 -#define TTY_OP_ISPEED 192 /* int follows */ -#define TTY_OP_OSPEED 193 /* int follows */ +#define TTY_OP_END 0 +/* + * uint32 (u_int) follows speed in SSH1 and SSH2 + */ +#define TTY_OP_ISPEED_PROTO1 192 +#define TTY_OP_OSPEED_PROTO1 193 +#define TTY_OP_ISPEED_PROTO2 128 +#define TTY_OP_OSPEED_PROTO2 129 /* * Converts POSIX speed_t to a baud rate. The values of the @@ -121,7 +158,7 @@ static speed_t baud_to_speed(int baud) { switch (baud) { - case 0: + case 0: return B0; case 50: return B50; @@ -205,47 +242,72 @@ baud_to_speed(int baud) /* * Encodes terminal modes for the terminal referenced by fd - * in a portable manner, and appends the modes to a packet + * or tiop in a portable manner, and appends the modes to a packet * being constructed. */ void -tty_make_modes(int fd) +tty_make_modes(int fd, struct termios *tiop) { struct termios tio; int baud; + Buffer buf; + int tty_op_ospeed, tty_op_ispeed; + void (*put_arg)(Buffer *, u_int); - if (tcgetattr(fd, &tio) < 0) { - packet_put_char(TTY_OP_END); - log("tcgetattr: %.100s", strerror(errno)); - return; + buffer_init(&buf); + if (compat20) { + tty_op_ospeed = TTY_OP_OSPEED_PROTO2; + tty_op_ispeed = TTY_OP_ISPEED_PROTO2; + put_arg = buffer_put_int; + } else { + tty_op_ospeed = TTY_OP_OSPEED_PROTO1; + tty_op_ispeed = TTY_OP_ISPEED_PROTO1; + put_arg = (void (*)(Buffer *, u_int)) buffer_put_char; } + + if (tiop == NULL) { + if (tcgetattr(fd, &tio) == -1) { + log("tcgetattr: %.100s", strerror(errno)); + goto end; + } + } else + tio = *tiop; + /* Store input and output baud rates. */ baud = speed_to_baud(cfgetospeed(&tio)); - packet_put_char(TTY_OP_OSPEED); - packet_put_int(baud); + debug2("tty_make_modes: ospeed %d", baud); + buffer_put_char(&buf, tty_op_ospeed); + buffer_put_int(&buf, baud); baud = speed_to_baud(cfgetispeed(&tio)); - packet_put_char(TTY_OP_ISPEED); - packet_put_int(baud); + debug2("tty_make_modes: ispeed %d", baud); + buffer_put_char(&buf, tty_op_ispeed); + buffer_put_int(&buf, baud); /* Store values of mode flags. */ #define TTYCHAR(NAME, OP) \ - packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); + debug2("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, tio.c_cc[NAME]); + #define TTYMODE(NAME, FIELD, OP) \ - packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); -#define SGTTYCHAR(NAME, OP) -#define SGTTYMODE(NAME, FIELD, OP) -#define SGTTYMODEN(NAME, FIELD, OP) + debug2("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, ((tio.FIELD & NAME) != 0)); #include "ttymodes.h" #undef TTYCHAR #undef TTYMODE -#undef SGTTYCHAR -#undef SGTTYMODE -#undef SGTTYMODEN +end: /* Mark end of mode data. */ - packet_put_char(TTY_OP_END); + buffer_put_char(&buf, TTY_OP_END); + if (compat20) + packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); + else + packet_put_raw(buffer_ptr(&buf), buffer_len(&buf)); + buffer_free(&buf); + return; } /* @@ -259,14 +321,30 @@ tty_parse_modes(int fd, int *n_bytes_ptr) int opcode, baud; int n_bytes = 0; int failure = 0; + u_int (*get_arg)(void); + int arg, arg_size; + + if (compat20) { + *n_bytes_ptr = packet_get_int(); + debug2("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr); + if (*n_bytes_ptr == 0) + return; + get_arg = packet_get_int; + arg_size = 4; + } else { + get_arg = packet_get_char; + arg_size = 1; + } /* * Get old attributes for the terminal. We will modify these * flags. I am hoping that if there are any machine-specific * modes, they will initially have reasonable values. */ - if (tcgetattr(fd, &tio) < 0) + if (tcgetattr(fd, &tio) == -1) { + log("tcgetattr: %.100s", strerror(errno)); failure = -1; + } for (;;) { n_bytes += 1; @@ -275,90 +353,110 @@ tty_parse_modes(int fd, int *n_bytes_ptr) case TTY_OP_END: goto set; - case TTY_OP_ISPEED: + /* XXX: future conflict possible */ + case TTY_OP_ISPEED_PROTO1: + case TTY_OP_ISPEED_PROTO2: n_bytes += 4; baud = packet_get_int(); - if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) + debug2("tty_parse_modes: ispeed %d", baud); + if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1) error("cfsetispeed failed for %d", baud); break; - case TTY_OP_OSPEED: + /* XXX: future conflict possible */ + case TTY_OP_OSPEED_PROTO1: + case TTY_OP_OSPEED_PROTO2: n_bytes += 4; baud = packet_get_int(); - if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) + debug2("tty_parse_modes: ospeed %d", baud); + if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1) error("cfsetospeed failed for %d", baud); break; -#define TTYCHAR(NAME, OP) \ - case OP: \ - n_bytes += 1; \ - tio.c_cc[NAME] = packet_get_char(); \ +#define TTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += arg_size; \ + tio.c_cc[NAME] = get_arg(); \ + debug2("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \ break; -#define TTYMODE(NAME, FIELD, OP) \ - case OP: \ - n_bytes += 1; \ - if (packet_get_char()) \ - tio.FIELD |= NAME; \ - else \ - tio.FIELD &= ~NAME; \ +#define TTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += arg_size; \ + if ((arg = get_arg())) \ + tio.FIELD |= NAME; \ + else \ + tio.FIELD &= ~NAME; \ + debug2("tty_parse_modes: %d %d", OP, arg); \ break; -#define SGTTYCHAR(NAME, OP) -#define SGTTYMODE(NAME, FIELD, OP) -#define SGTTYMODEN(NAME, FIELD, OP) #include "ttymodes.h" #undef TTYCHAR #undef TTYMODE -#undef SGTTYCHAR -#undef SGTTYMODE -#undef SGTTYMODEN default: debug("Ignoring unsupported tty mode opcode %d (0x%x)", opcode, opcode); - /* - * Opcodes 0 to 127 are defined to have - * a one-byte argument. - */ - if (opcode >= 0 && opcode < 128) { - n_bytes += 1; - (void) packet_get_char(); - break; + if (!compat20) { + /* + * SSH1: + * Opcodes 1 to 127 are defined to have + * a one-byte argument. + * Opcodes 128 to 159 are defined to have + * an integer argument. + */ + if (opcode > 0 && opcode < 128) { + n_bytes += 1; + (void) packet_get_char(); + break; + } else if (opcode >= 128 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + /* + * It is a truly undefined opcode (160 to 255). + * We have no idea about its arguments. So we + * must stop parsing. Note that some data may be + * left in the packet; hopefully there is nothing + * more coming after the mode data. + */ + log("parse_tty_modes: unknown opcode %d", opcode); + packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); + goto set; + } } else { /* - * Opcodes 128 to 159 are defined to have - * an integer argument. + * SSH2: + * Opcodes 1 to 159 are defined to have + * a uint32 argument. + * Opcodes 160 to 255 are undefined and + * cause parsing to stop. */ - if (opcode >= 128 && opcode < 160) { + if (opcode > 0 && opcode < 160) { n_bytes += 4; (void) packet_get_int(); break; + } else { + log("parse_tty_modes: unknown opcode %d", opcode); + goto set; } - } - /* - * It is a truly undefined opcode (160 to 255). - * We have no idea about its arguments. So we - * must stop parsing. Note that some data may be - * left in the packet; hopefully there is nothing - * more coming after the mode data. - */ - log("parse_tty_modes: unknown opcode %d", opcode); - packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); - goto set; + } } } set: if (*n_bytes_ptr != n_bytes) { *n_bytes_ptr = n_bytes; + log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", + *n_bytes_ptr, n_bytes); return; /* Don't process bytes passed */ } if (failure == -1) - return; /* Packet parsed ok but tty stuff failed */ + return; /* Packet parsed ok but tcgetattr() failed */ /* Set the new modes for the terminal. */ - if (tcsetattr(fd, TCSANOW, &tio) < 0) + if (tcsetattr(fd, TCSANOW, &tio) == -1) log("Setting tty modes failed: %.100s", strerror(errno)); return; } diff --git a/crypto/openssh/ttymodes.h b/crypto/openssh/ttymodes.h index a26e4fa..ad980e9 100644 --- a/crypto/openssh/ttymodes.h +++ b/crypto/openssh/ttymodes.h @@ -1,6 +1,6 @@ +/* RCSID("$OpenBSD: ttymodes.h,v 1.11 2001/04/14 16:33:20 stevesk Exp $"); */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> - * SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved * @@ -11,14 +11,47 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: ttymodes.h,v 1.9 2000/09/07 20:27:55 deraadt Exp $"); */ +/* + * SSH2 tty modes support by Kevin Steves. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -/* The tty mode description is a stream of bytes. The stream consists of +/* + * SSH1: + * The tty mode description is a stream of bytes. The stream consists of * opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0). * Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer * arguments. Opcodes 160-255 are not yet defined, and cause parsing to * stop (they should only be used after any other data). * + * SSH2: + * Differences between SSH1 and SSH2 terminal mode encoding include: + * 1. Encoded terminal modes are represented as a string, and a stream + * of bytes within that string. + * 2. Opcode arguments are uint32 (1-159); 160-255 remain undefined. + * 3. The values for TTY_OP_ISPEED and TTY_OP_OSPEED are different; + * 128 and 129 vs. 192 and 193 respectively. + * * The client puts in the stream any modes it knows about, and the * server ignores any modes it does not know about. This allows some degree * of machine-independence, at least between systems that use a posix-like @@ -31,110 +64,109 @@ * is only intended for including from ttymodes.c. */ -/* termios macro */ /* sgtty macro */ +/* termios macro */ /* name, op */ -TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1) -TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2) -TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3) +TTYCHAR(VINTR, 1) +TTYCHAR(VQUIT, 2) +TTYCHAR(VERASE, 3) #if defined(VKILL) -TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4) +TTYCHAR(VKILL, 4) #endif /* VKILL */ -TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5) +TTYCHAR(VEOF, 5) #if defined(VEOL) -TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6) +TTYCHAR(VEOL, 6) #endif /* VEOL */ -#ifdef VEOL2 /* n/a */ +#ifdef VEOL2 TTYCHAR(VEOL2, 7) #endif /* VEOL2 */ -TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8) -TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9) +TTYCHAR(VSTART, 8) +TTYCHAR(VSTOP, 9) #if defined(VSUSP) -TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10) +TTYCHAR(VSUSP, 10) #endif /* VSUSP */ #if defined(VDSUSP) -TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11) +TTYCHAR(VDSUSP, 11) #endif /* VDSUSP */ #if defined(VREPRINT) -TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12) +TTYCHAR(VREPRINT, 12) #endif /* VREPRINT */ #if defined(VWERASE) -TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13) +TTYCHAR(VWERASE, 13) #endif /* VWERASE */ #if defined(VLNEXT) -TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14) +TTYCHAR(VLNEXT, 14) #endif /* VLNEXT */ #if defined(VFLUSH) -TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15) +TTYCHAR(VFLUSH, 15) #endif /* VFLUSH */ #ifdef VSWTCH -TTYCHAR(VSWTCH, 16) /* n/a */ +TTYCHAR(VSWTCH, 16) #endif /* VSWTCH */ #if defined(VSTATUS) -TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17) +TTYCHAR(VSTATUS, 17) #endif /* VSTATUS */ #ifdef VDISCARD -TTYCHAR(VDISCARD, 18) /* n/a */ +TTYCHAR(VDISCARD, 18) #endif /* VDISCARD */ /* name, field, op */ -TTYMODE(IGNPAR, c_iflag, 30) /* n/a */ -TTYMODE(PARMRK, c_iflag, 31) /* n/a */ -TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32) -TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33) -TTYMODE(INLCR, c_iflag, 34) /* n/a */ -TTYMODE(IGNCR, c_iflag, 35) /* n/a */ -TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36) +TTYMODE(IGNPAR, c_iflag, 30) +TTYMODE(PARMRK, c_iflag, 31) +TTYMODE(INPCK, c_iflag, 32) +TTYMODE(ISTRIP, c_iflag, 33) +TTYMODE(INLCR, c_iflag, 34) +TTYMODE(IGNCR, c_iflag, 35) +TTYMODE(ICRNL, c_iflag, 36) #if defined(IUCLC) -TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37) +TTYMODE(IUCLC, c_iflag, 37) #endif -TTYMODE(IXON, c_iflag, 38) /* n/a */ -TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39) -TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40) +TTYMODE(IXON, c_iflag, 38) +TTYMODE(IXANY, c_iflag, 39) +TTYMODE(IXOFF, c_iflag, 40) #ifdef IMAXBEL -TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */ +TTYMODE(IMAXBEL,c_iflag, 41) #endif /* IMAXBEL */ -TTYMODE(ISIG, c_lflag, 50) /* n/a */ -TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51) +TTYMODE(ISIG, c_lflag, 50) +TTYMODE(ICANON, c_lflag, 51) #ifdef XCASE -TTYMODE(XCASE, c_lflag, 52) /* n/a */ +TTYMODE(XCASE, c_lflag, 52) #endif -TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53) -TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54) -TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55) -TTYMODE(ECHONL, c_lflag, 56) /* n/a */ -TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57) -TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58) +TTYMODE(ECHO, c_lflag, 53) +TTYMODE(ECHOE, c_lflag, 54) +TTYMODE(ECHOK, c_lflag, 55) +TTYMODE(ECHONL, c_lflag, 56) +TTYMODE(NOFLSH, c_lflag, 57) +TTYMODE(TOSTOP, c_lflag, 58) #ifdef IEXTEN -TTYMODE(IEXTEN, c_lflag, 59) /* n/a */ +TTYMODE(IEXTEN, c_lflag, 59) #endif /* IEXTEN */ #if defined(ECHOCTL) -TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60) +TTYMODE(ECHOCTL,c_lflag, 60) #endif /* ECHOCTL */ #ifdef ECHOKE -TTYMODE(ECHOKE, c_lflag, 61) /* n/a */ +TTYMODE(ECHOKE, c_lflag, 61) #endif /* ECHOKE */ #if defined(PENDIN) -TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62) +TTYMODE(PENDIN, c_lflag, 62) #endif /* PENDIN */ -TTYMODE(OPOST, c_oflag, 70) /* n/a */ +TTYMODE(OPOST, c_oflag, 70) #if defined(OLCUC) -TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71) +TTYMODE(OLCUC, c_oflag, 71) #endif -TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72) +TTYMODE(ONLCR, c_oflag, 72) #ifdef OCRNL -TTYMODE(OCRNL, c_oflag, 73) /* n/a */ +TTYMODE(OCRNL, c_oflag, 73) #endif #ifdef ONOCR -TTYMODE(ONOCR, c_oflag, 74) /* n/a */ +TTYMODE(ONOCR, c_oflag, 74) #endif #ifdef ONLRET -TTYMODE(ONLRET, c_oflag, 75) /* n/a */ +TTYMODE(ONLRET, c_oflag, 75) #endif -TTYMODE(CS7, c_cflag, 90) /* n/a */ -TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91) -TTYMODE(PARENB, c_cflag, 92) /* n/a */ -TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93) - +TTYMODE(CS7, c_cflag, 90) +TTYMODE(CS8, c_cflag, 91) +TTYMODE(PARENB, c_cflag, 92) +TTYMODE(PARODD, c_cflag, 93) diff --git a/crypto/openssh/uidswap.c b/crypto/openssh/uidswap.c index 8e7c479..39952e2 100644 --- a/crypto/openssh/uidswap.c +++ b/crypto/openssh/uidswap.c @@ -12,9 +12,9 @@ */ #include "includes.h" -RCSID("$OpenBSD: uidswap.c,v 1.9 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: uidswap.c,v 1.16 2001/04/20 16:32:22 markus Exp $"); -#include "ssh.h" +#include "log.h" #include "uidswap.h" /* @@ -26,58 +26,80 @@ RCSID("$OpenBSD: uidswap.c,v 1.9 2000/09/07 20:27:55 deraadt Exp $"); * POSIX saved uids or not. */ -#ifdef _POSIX_SAVED_IDS /* Lets assume that posix saved ids also work with seteuid, even though that is not part of the posix specification. */ -#define SAVED_IDS_WORK_WITH_SETEUID -#endif /* _POSIX_SAVED_IDS */ /* Saved effective uid. */ -static uid_t saved_euid = 0; +static int privileged = 0; +static int temporarily_use_uid_effective = 0; +static uid_t saved_euid = 0; +static gid_t saved_egid; +static gid_t saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX]; +static int saved_egroupslen = -1, user_groupslen = -1; /* * Temporarily changes to the given uid. If the effective user * id is not root, this does nothing. This call cannot be nested. */ void -temporarily_use_uid(uid_t uid) +temporarily_use_uid(struct passwd *pw) { -#ifdef SAVED_IDS_WORK_WITH_SETEUID - /* Save the current euid. */ + /* Save the current euid, and egroups. */ saved_euid = geteuid(); + debug("temporarily_use_uid: %d/%d (e=%d)", + pw->pw_uid, pw->pw_gid, saved_euid); + if (saved_euid != 0) { + privileged = 0; + return; + } + privileged = 1; + temporarily_use_uid_effective = 1; + saved_egid = getegid(); + saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups); + if (saved_egroupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + /* set and save the user's groups */ + if (user_groupslen == -1) { + if (initgroups(pw->pw_name, pw->pw_gid) < 0) + fatal("initgroups: %s: %.100s", pw->pw_name, + strerror(errno)); + user_groupslen = getgroups(NGROUPS_MAX, user_groups); + if (user_groupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + } /* Set the effective uid to the given (unprivileged) uid. */ - if (seteuid(uid) == -1) - debug("seteuid %u: %.100s", (u_int) uid, strerror(errno)); -#else /* SAVED_IDS_WORK_WITH_SETUID */ - /* Propagate the privileged uid to all of our uids. */ - if (setuid(geteuid()) < 0) - debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno)); - - /* Set the effective uid to the given (unprivileged) uid. */ - if (seteuid(uid) == -1) - debug("seteuid %u: %.100s", (u_int) uid, strerror(errno)); -#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + if (setgroups(user_groupslen, user_groups) < 0) + fatal("setgroups: %.100s", strerror(errno)); + pw->pw_gid = pw->pw_gid; + if (setegid(pw->pw_gid) < 0) + fatal("setegid %u: %.100s", (u_int) pw->pw_gid, + strerror(errno)); + if (seteuid(pw->pw_uid) == -1) + fatal("seteuid %u: %.100s", (u_int) pw->pw_uid, + strerror(errno)); } /* - * Restores to the original uid. + * Restores to the original (privileged) uid. */ void -restore_uid() +restore_uid(void) { -#ifdef SAVED_IDS_WORK_WITH_SETEUID - /* Set the effective uid back to the saved uid. */ + debug("restore_uid"); + /* it's a no-op unless privileged */ + if (!privileged) + return; + if (!temporarily_use_uid_effective) + fatal("restore_uid: temporarily_use_uid not effective"); + /* Set the effective uid back to the saved privileged uid. */ if (seteuid(saved_euid) < 0) - debug("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); -#else /* SAVED_IDS_WORK_WITH_SETEUID */ - /* - * We are unable to restore the real uid to its unprivileged value. - * Propagate the real uid (usually more privileged) to effective uid - * as well. - */ - setuid(getuid()); -#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); + if (setgroups(saved_egroupslen, saved_egroups) < 0) + fatal("setgroups: %.100s", strerror(errno)); + if (setegid(saved_egid) < 0) + fatal("setegid %u: %.100s", (u_int) saved_egid, strerror(errno)); + temporarily_use_uid_effective = 0; } /* @@ -85,8 +107,12 @@ restore_uid() * called while temporarily_use_uid is effective. */ void -permanently_set_uid(uid_t uid) +permanently_set_uid(struct passwd *pw) { - if (setuid(uid) < 0) - debug("setuid %u: %.100s", (u_int) uid, strerror(errno)); + if (temporarily_use_uid_effective) + fatal("restore_uid: temporarily_use_uid effective"); + if (setgid(pw->pw_gid) < 0) + fatal("setgid %u: %.100s", (u_int) pw->pw_gid, strerror(errno)); + if (setuid(pw->pw_uid) < 0) + fatal("setuid %u: %.100s", (u_int) pw->pw_uid, strerror(errno)); } diff --git a/crypto/openssh/uidswap.h b/crypto/openssh/uidswap.h index ff6fad4..228e5a5 100644 --- a/crypto/openssh/uidswap.h +++ b/crypto/openssh/uidswap.h @@ -1,3 +1,5 @@ +/* $OpenBSD: uidswap.h,v 1.7 2001/04/06 21:00:17 markus Exp $ */ + /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -17,18 +19,18 @@ * Temporarily changes to the given uid. If the effective user id is not * root, this does nothing. This call cannot be nested. */ -void temporarily_use_uid(uid_t uid); +void temporarily_use_uid(struct passwd *pw); /* * Restores the original effective user id after temporarily_use_uid(). * This should only be called while temporarily_use_uid is effective. */ -void restore_uid(); +void restore_uid(void); /* * Permanently sets all uids to the given uid. This cannot be called while * temporarily_use_uid is effective. This must also clear any saved uids. */ -void permanently_set_uid(uid_t uid); +void permanently_set_uid(struct passwd *pw); #endif /* UIDSWAP_H */ diff --git a/crypto/openssh/uuencode.c b/crypto/openssh/uuencode.c index 38de418..1be975a 100644 --- a/crypto/openssh/uuencode.c +++ b/crypto/openssh/uuencode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uuencode.c,v 1.7 2000/09/07 20:27:55 deraadt Exp $ */ +/* $OpenBSD: uuencode.c,v 1.12 2001/03/01 02:27:18 deraadt Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -26,20 +26,21 @@ #include "includes.h" #include "xmalloc.h" +#include "uuencode.h" #include <resolv.h> -RCSID("$OpenBSD: uuencode.c,v 1.7 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: uuencode.c,v 1.12 2001/03/01 02:27:18 deraadt Exp $"); int -uuencode(unsigned char *src, unsigned int srclength, +uuencode(u_char *src, u_int srclength, char *target, size_t targsize) { return __b64_ntop(src, srclength, target, targsize); } int -uudecode(const char *src, unsigned char *target, size_t targsize) +uudecode(const char *src, u_char *target, size_t targsize) { int len; char *encoded, *p; @@ -59,10 +60,11 @@ uudecode(const char *src, unsigned char *target, size_t targsize) } void -dump_base64(FILE *fp, unsigned char *data, int len) +dump_base64(FILE *fp, u_char *data, int len) { - unsigned char *buf = xmalloc(2*len); + u_char *buf = xmalloc(2*len); int i, n; + n = uuencode(data, len, buf, 2*len); for (i = 0; i < n; i++) { fprintf(fp, "%c", buf[i]); diff --git a/crypto/openssh/uuencode.h b/crypto/openssh/uuencode.h index dca80ec..42f83c2 100644 --- a/crypto/openssh/uuencode.h +++ b/crypto/openssh/uuencode.h @@ -1,3 +1,5 @@ +/* $OpenBSD: uuencode.h,v 1.5 2001/01/29 01:58:19 niklas Exp $ */ + /* * Copyright (c) 1999 Markus Friedl. All rights reserved. * @@ -24,7 +26,7 @@ #ifndef UUENCODE_H #define UUENCODE_H -int uuencode(unsigned char *src, unsigned int srclength, char *target, size_t targsize); -int uudecode(const char *src, unsigned char *target, size_t targsize); -void dump_base64(FILE *fp, unsigned char *data, int len); +int uuencode(u_char *src, u_int srclength, char *target, size_t targsize); +int uudecode(const char *src, u_char *target, size_t targsize); +void dump_base64(FILE *fp, u_char *data, int len); #endif diff --git a/crypto/openssh/xmalloc.c b/crypto/openssh/xmalloc.c index 738c9cd..5046627 100644 --- a/crypto/openssh/xmalloc.c +++ b/crypto/openssh/xmalloc.c @@ -4,7 +4,7 @@ * All rights reserved * Versions of malloc and friends that check their results, and never return * failure (they call fatal if they encounter an error). - * + * * 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 @@ -13,16 +13,21 @@ */ #include "includes.h" -RCSID("$OpenBSD: xmalloc.c,v 1.8 2000/09/07 20:27:55 deraadt Exp $"); +RCSID("$OpenBSD: xmalloc.c,v 1.15 2001/04/16 08:05:34 deraadt Exp $"); -#include "ssh.h" +#include "xmalloc.h" +#include "log.h" void * xmalloc(size_t size) { - void *ptr = malloc(size); + void *ptr; + + if (size == 0) + fatal("xmalloc: zero size"); + ptr = malloc(size); if (ptr == NULL) - fatal("xmalloc: out of memory (allocating %d bytes)", (int) size); + fatal("xmalloc: out of memory (allocating %lu bytes)", (u_long) size); return ptr; } @@ -31,11 +36,14 @@ xrealloc(void *ptr, size_t new_size) { void *new_ptr; + if (new_size == 0) + fatal("xrealloc: zero size"); if (ptr == NULL) - fatal("xrealloc: NULL pointer given as argument"); - new_ptr = realloc(ptr, new_size); + new_ptr = malloc(new_size); + else + new_ptr = realloc(ptr, new_size); if (new_ptr == NULL) - fatal("xrealloc: out of memory (new_size %d bytes)", (int) new_size); + fatal("xrealloc: out of memory (new_size %lu bytes)", (u_long) new_size); return new_ptr; } @@ -50,9 +58,12 @@ xfree(void *ptr) char * xstrdup(const char *str) { - int len = strlen(str) + 1; + size_t len = strlen(str) + 1; + char *cp; - char *cp = xmalloc(len); + if (len == 0) + fatal("xstrdup: zero size"); + cp = xmalloc(len); strlcpy(cp, str, len); return cp; } |