From 61e9624802b421b3087730b8dbb768af2021dc6d Mon Sep 17 00:00:00 2001 From: djm Date: Sun, 4 Feb 2001 12:20:18 +0000 Subject: [PATCH] NB: big update - may break stuff. Please test! - (djm) OpenBSD CVS sync: - markus@cvs.openbsd.org 2001/02/03 03:08:38 [auth-options.c auth-rh-rsa.c auth-rhosts.c auth.c canohost.c] [canohost.h servconf.c servconf.h session.c sshconnect1.c sshd.8] [sshd_config] make ReverseMappingCheck optional in sshd_config; ok djm@,dugsong@ - markus@cvs.openbsd.org 2001/02/03 03:19:51 [ssh.1 sshd.8 sshd_config] Skey is now called ChallengeResponse - markus@cvs.openbsd.org 2001/02/03 03:43:09 [sshd.8] use no-pty option in .ssh/authorized_keys* if you need a 8-bit clean channel. note from Erik.Anggard@cygate.se (pr/1659) - stevesk@cvs.openbsd.org 2001/02/03 10:03:06 [ssh.1] typos; ok markus@ - djm@cvs.openbsd.org 2001/02/04 04:11:56 [scp.1 sftp-server.c ssh.1 sshd.8 sftp-client.c sftp-client.h] [sftp-common.c sftp-common.h sftp-int.c sftp-int.h sftp.1 sftp.c] Basic interactive sftp client; ok theo@ - (djm) Update RPM specs for new sftp binary - (djm) Update several bits for new optional reverse lookup stuff. I think I got them all. --- ChangeLog | 243 ++++++----- Makefile.in | 20 +- TODO | 2 + auth-options.c | 122 +++--- auth-pam.c | 6 +- auth-rh-rsa.c | 5 +- auth-rhosts.c | 4 +- auth.c | 4 +- auth1.c | 12 +- auth2.c | 13 +- canohost.c | 199 ++++----- canohost.h | 11 +- channels.c | 12 +- contrib/caldera/openssh.spec | 4 + contrib/redhat/openssh.spec | 4 + contrib/suse/openssh.spec | 2 + scp.1 | 3 +- servconf.c | 12 +- servconf.h | 3 +- session.c | 6 +- sftp-client.c | 792 +++++++++++++++++++++++++++++++++++ sftp-client.h | 84 ++++ sftp-common.c | 146 +++++++ sftp-common.h | 55 +++ sftp-int.c | 583 ++++++++++++++++++++++++++ sftp-int.h | 27 ++ sftp-server.c | 102 +---- sftp.1 | 156 +++++++ sftp.c | 222 ++++++++++ ssh.1 | 12 +- ssh_config | 8 +- sshconnect1.c | 8 +- sshd.8 | 24 +- sshd_config | 10 +- 34 files changed, 2488 insertions(+), 428 deletions(-) create mode 100644 sftp-client.c create mode 100644 sftp-client.h create mode 100644 sftp-common.c create mode 100644 sftp-common.h create mode 100644 sftp-int.c create mode 100644 sftp-int.h create mode 100644 sftp.1 create mode 100644 sftp.c diff --git a/ChangeLog b/ChangeLog index 766c8803..5afaf69a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,9 +2,32 @@ - (bal) I think this is the last of the bsd-*.h that don't belong. - (bal) Minor Makefile fix - (bal) openbsd-compat/Makefile minor fix. Ensure dependancies are done - right. + right. - (bal) Changed order of LIB="" in -with-skey due to library resolving. - (bal) next-posix.h changed to bsd-nextstep.h + - (djm) OpenBSD CVS sync: + - markus@cvs.openbsd.org 2001/02/03 03:08:38 + [auth-options.c auth-rh-rsa.c auth-rhosts.c auth.c canohost.c] + [canohost.h servconf.c servconf.h session.c sshconnect1.c sshd.8] + [sshd_config] + make ReverseMappingCheck optional in sshd_config; ok djm@,dugsong@ + - markus@cvs.openbsd.org 2001/02/03 03:19:51 + [ssh.1 sshd.8 sshd_config] + Skey is now called ChallengeResponse + - markus@cvs.openbsd.org 2001/02/03 03:43:09 + [sshd.8] + use no-pty option in .ssh/authorized_keys* if you need a 8-bit clean + channel. note from Erik.Anggard@cygate.se (pr/1659) + - stevesk@cvs.openbsd.org 2001/02/03 10:03:06 + [ssh.1] + typos; ok markus@ + - djm@cvs.openbsd.org 2001/02/04 04:11:56 + [scp.1 sftp-server.c ssh.1 sshd.8 sftp-client.c sftp-client.h] + [sftp-common.c sftp-common.h sftp-int.c sftp-int.h sftp.1 sftp.c] + Basic interactive sftp client; ok theo@ + - (djm) Update RPM specs for new sftp binary + - (djm) Update several bits for new optional reverse lookup stuff. I + think I got them all. 20010103 - (bal) Cygwin clean up by Corinna Vinschen @@ -14,7 +37,7 @@ platforms so builds fail. (NeXT being a well known one) 20010102 - - (bal) Makefile fix where sourcedir != builddir by Corinna Vinschen + - (bal) Makefile fix where sourcedir != builddir by Corinna Vinschen - (bal) Makefile fix to use $(MAKE) instead of 'make' for platforms that use 'gmake'. Patch by Tim Rice @@ -75,7 +98,7 @@ ``StrictHostKeyChecking ask'' documentation and small cleanup. ok markus@ - stevesk@cvs.openbsd.org 2001/01/28 20:43:25 - [sshd.8] + [sshd.8] spelling. ok markus@ - stevesk@cvs.openbsd.org 2001/01/28 20:53:21 [xmalloc.c] @@ -94,7 +117,7 @@ - (bal) Minor auth2.c resync. Whitespace and moving of an #include. 20010126 - - (bal) SSH_PROGRAM vs _PATH_SSH_PROGRAM fix pointed out by Roumen + - (bal) SSH_PROGRAM vs _PATH_SSH_PROGRAM fix pointed out by Roumen Petrov - (bal) OpenBSD Sync - deraadt@cvs.openbsd.org 2001/01/25 8:06:33 @@ -105,12 +128,12 @@ - (djm) Sync bsd-* support files: - deraadt@cvs.openbsd.org 2000/01/26 03:43:20 [rresvport.c bindresvport.c] - new bindresvport() semantics that itojun, shin, jean-luc and i have + new bindresvport() semantics that itojun, shin, jean-luc and i have agreed on, which will be happy for the future. bindresvport_sa() for sockaddr *, too. docs later.. - deraadt@cvs.openbsd.org 2000/01/24 02:24:21 [bindresvport.c] - in bindresvport(), if sin is non-NULL, example sin->sin_family for + in bindresvport(), if sin is non-NULL, example sin->sin_family for the actual family being processed - (djm) Mention PRNGd in documentation, it is nicer than EGD - (djm) Automatically search for "well-known" EGD/PRNGd sockets in autoconf @@ -124,7 +147,7 @@ - (bal) OpenBSD Resync - markus@cvs.openbsd.org 2001/01/23 10:45:10 [ssh.h] - nuke comment + nuke comment - (bal) no 64bit support patch from Tim Rice - (bal) #ifdef around S_IFSOCK if platform does not support it. patch by Tim Rice @@ -134,7 +157,7 @@ 20010123 - (bal) regexp.h typo in configure.in. Should have been regex.h - (bal) SSH_USER_DIR to _PATH_SSH_USER_DIR patch by stevesk@ - - (bal) SSH_ASKPASS_DEFAULT to _PATH_SSH_ASKPASS_DEFAULT + - (bal) SSH_ASKPASS_DEFAULT to _PATH_SSH_ASKPASS_DEFAULT - (bal) OpenBSD Resync - markus@cvs.openbsd.org 2001/01/22 8:15:00 [auth-krb4.c sshconnect1.c] @@ -172,12 +195,12 @@ fix typo; from stevesk@ - markus@cvs.openbsd.org 2001/01/19 16:50:58 [ssh-dss.c] - clear and free digest, make consistent with other code (use dlen); from + clear and free digest, make consistent with other code (use dlen); from stevesk@ - markus@cvs.openbsd.org 2001/01/20 15:55:20 GMT 2001 by markus [auth-options.c auth-options.h auth-rsa.c auth2.c] pass the filename to auth_parse_options() - - markus@cvs.openbsd.org 2001/01/20 17:59:40 GMT 2001 + - markus@cvs.openbsd.org 2001/01/20 17:59:40 GMT 2001 [readconf.c] fix SIGSEGV from -o ""; problem noted by jehsom@togetherweb.com - stevesk@cvs.openbsd.org 2001/01/20 18:20:29 @@ -185,7 +208,7 @@ dh_new_group() does not return NULL. ok markus@ - markus@cvs.openbsd.org 2001/01/20 21:33:42 [ssh-add.c] - do not loop forever if askpass does not exist; from + do not loop forever if askpass does not exist; from andrew@pimlott.ne.mediaone.net - djm@cvs.openbsd.org 2001/01/20 23:00:56 [servconf.c] @@ -207,13 +230,13 @@ match.c misc.c misc.h nchan.c packet.c pty.c radix.h readconf.c readpass.c readpass.h rsa.c scp.c servconf.c serverloop.c serverloop.h session.c sftp-server.c ssh-add.c ssh-agent.c ssh-dss.c ssh-keygen.c - ssh-keyscan.c ssh-rsa.c ssh.c ssh.h sshconnect.c sshconnect.h + ssh-keyscan.c ssh-rsa.c ssh.c ssh.h sshconnect.c sshconnect.h sshconnect1.c sshconnect2.c sshd.c tildexpand.c tildexpand.h ttysmodes.c uidswap.c xmalloc.c] - split ssh.h and try to cleanup the #include mess. remove unnecessary + split ssh.h and try to cleanup the #include mess. remove unnecessary #includes. rename util.[ch] -> misc.[ch] - (bal) renamed 'PIDDIR' to '_PATH_SSH_PIDDIR' to match OpenBSD tree - - (bal) Moved #ifdef KRB4 in auth-krb4.c above the #include to resolve + - (bal) Moved #ifdef KRB4 in auth-krb4.c above the #include to resolve conflict when compiling for non-kerb install - (bal) removed the #ifdef SKEY in auth1.c to match Markus' changes on 1/19. @@ -233,7 +256,7 @@ - markus@cvs.openbsd.org 2001/01/18 16:20:21 [log-client.c log-server.c log.c readconf.c servconf.c ssh.1 ssh.h sshd.8 sshd.c] - log() is at pri=LOG_INFO, since LOG_NOTICE goes to /dev/console on many + log() is at pri=LOG_INFO, since LOG_NOTICE goes to /dev/console on many systems - markus@cvs.openbsd.org 2001/01/18 16:59:59 [auth-passwd.c auth.c auth.h auth1.c auth2.c serverloop.c session.c @@ -250,7 +273,7 @@ to fix NULL pointer deref and fake authloop breakage in PAM code. - (bal) Updated contrib/cygwin/ by Corinna Vinschen - (bal) Minor cygwin patch to auth1.c. Suggested by djm. - + 20010118 - (bal) Super Sized OpenBSD Resync - markus@cvs.openbsd.org 2001/01/11 22:14:20 GMT 2001 by markus @@ -272,7 +295,7 @@ [ssh-add.c] typo, from stevesk@sweden.hp.com - markus@cvs.openbsd.org 2001/01/13 18:32:50 - [packet.c session.c ssh.c sshconnect.c sshd.c] + [packet.c session.c ssh.c sshconnect.c sshd.c] split out keepalive from packet_interactive (from dale@accentre.com) set IPTOS_LOWDELAY TCP_NODELAY IPTOS_THROUGHPUT for ssh2, too. - markus@cvs.openbsd.org 2001/01/13 18:36:45 @@ -284,7 +307,7 @@ - markus@cvs.openbsd.org 2001/01/13 18:43:31 [session.c] Wall - - markus@cvs.openbsd.org 2001/01/13 19:14:08 + - markus@cvs.openbsd.org 2001/01/13 19:14:08 [clientloop.h clientloop.c ssh.c] move callback to headerfile - markus@cvs.openbsd.org 2001/01/15 21:40:10 @@ -301,12 +324,12 @@ readable long listing for sftp-server, ok deraadt@ - markus@cvs.openbsd.org 2001/01/16 19:20:06 [key.c ssh-rsa.c] - make "ssh-rsa" key format for ssh2 confirm to the ietf-drafts; from - galb@vandyke.com. note that you have to delete older ssh2-rsa keys, - since they are in the wrong format, too. they must be removed from + make "ssh-rsa" key format for ssh2 confirm to the ietf-drafts; from + galb@vandyke.com. note that you have to delete older ssh2-rsa keys, + since they are in the wrong format, too. they must be removed from .ssh/authorized_keys2 and .ssh/known_hosts2, etc. - (cd; grep -v ssh-rsa .ssh/authorized_keys2 > TMP && mv TMP - .ssh/authorized_keys2) additionally, we now check that + (cd; grep -v ssh-rsa .ssh/authorized_keys2 > TMP && mv TMP + .ssh/authorized_keys2) additionally, we now check that BN_num_bits(rsa->n) >= 768. - markus@cvs.openbsd.org 2001/01/16 20:54:27 [sftp-server.c] @@ -317,15 +340,15 @@ - (bal) Added bsd-strmode.[ch] since some non-OpenBSD platforms may be missing such feature. - + 20010117 - (djm) Only write random seed file at exit - (djm) Make PAM support optional, enable with --with-pam - - (djm) Try to use libcrypt on Linux, but link it after OpenSSL (which + - (djm) Try to use libcrypt on Linux, but link it after OpenSSL (which provides a crypt() of its own) - (djm) Avoid a warning in bsd-bindresvport.c - (djm) Try to avoid adding -I/usr/include to CPPFLAGS during SSL tests. This - can cause weird segfaults errors on Solaris + can cause weird segfaults errors on Solaris - (djm) Avoid warning in PAM code by making read_passphrase arguments const - (djm) Add --with-pam to RPM spec files @@ -345,7 +368,7 @@ [auth.c sshd.8] support supplementary group in {Allow,Deny}Groups from stevesk@pobox.com - + 20010112 - (bal) OpenBSD Sync - markus@cvs.openbsd.org 2001/01/10 22:56:22 @@ -358,11 +381,11 @@ use #defines from the draft move #definations to sftp.h more info: - http://www.ietf.org/internet-drafts/draft-ietf-secsh-filexfer-00.txt + http://www.ietf.org/internet-drafts/draft-ietf-secsh-filexfer-00.txt - markus@cvs.openbsd.org 2001/01/10 19:43:20 [sshd.c] XXX - generate_empheral_server_key() is not safe against races, - because it calls log() + because it calls log() - markus@cvs.openbsd.org 2001/01/09 21:19:50 [packet.c] allow TCP_NDELAY for ipv6; from netbsd via itojun@ @@ -446,7 +469,7 @@ [sshconnect2.c] handle SSH2_MSG_USERAUTH_BANNER; fixes bug when connecting to a server that prints a banner (e.g. /etc/issue.net) - + 20010105 - (bal) contrib/caldera/ provided by Tim Rice - (bal) bsd-getcwd.c and bsd-setenv.c changed from bcopy() to memmove() @@ -464,9 +487,9 @@ log remote ip on disconnect; PR 1600 from jcs@rt.fm - markus@cvs.openbsd.org 2001/01/02 20:50:56 [sshconnect.c] - strict_host_key_checking for host_status != HOST_CHANGED && + strict_host_key_checking for host_status != HOST_CHANGED && ip_status == HOST_CHANGED - - (bal) authfile.c: Synced CVS ID tag + - (bal) authfile.c: Synced CVS ID tag - (bal) UnixWare 2.0 fixes by Tim Rice - (bal) Disable sftp-server if no 64bit int support exists. Based on patch by Tim Rice @@ -496,11 +519,11 @@ - (bal) if no MAXHOSTNAMELEN is defined. Default to 64 character defination. Suggested by Christian Kurz - (bal) Add in '.c.o' section to Makefile.in to address make programs that - don't honor CPPFLAGS by default. Suggested by Lutz Jaenicke + don't honor CPPFLAGS by default. Suggested by Lutz Jaenicke 20001229 - - (bal) Fixed spelling of 'authorized_keys' in ssh-copy-id.1 by Christian + - (bal) Fixed spelling of 'authorized_keys' in ssh-copy-id.1 by Christian Kurz - (bal) OpenBSD CVS Update - markus@cvs.openbsd.org 2000/12/28 14:25:51 @@ -544,21 +567,21 @@ bad reference to 'NeXT including it else were' on the #ifdef version. 20001227 - - (bal) Typo in configure.in: entut?ent should be endut?ent. Suggested by + - (bal) Typo in configure.in: entut?ent should be endut?ent. Suggested by Takumi Yamane - (bal) Checks for getrlimit(), sysconf(), and setdtablesize(). Patch by Corinna Vinschen - (djm) Fix catman-do target for non-bash - - (bal) Typo in configure.in: entut?ent should be endut?ent. Suggested by + - (bal) Typo in configure.in: entut?ent should be endut?ent. Suggested by Takumi Yamane - (bal) Checks for getrlimit(), sysconf(), and setdtablesize(). Patch by Corinna Vinschen - (djm) Fix catman-do target for non-bash - - (bal) Fixed NeXT's lack of CPPFLAGS honoring. - - (bal) ssh-keyscan.c: NeXT (and older BSDs) don't support getrlimit() w/ + - (bal) Fixed NeXT's lack of CPPFLAGS honoring. + - (bal) ssh-keyscan.c: NeXT (and older BSDs) don't support getrlimit() w/ 'RLIMIT_NOFILE' - - (djm) Remove *.Ylonen files. They are no longer in the OpenBSD tree, - the info in COPYING.Ylonen has been moved to the start of each + - (djm) Remove *.Ylonen files. They are no longer in the OpenBSD tree, + the info in COPYING.Ylonen has been moved to the start of each SSH1-derived file and README.Ylonen is well out of date. 20001223 @@ -609,9 +632,9 @@ - markus@cvs.openbsd.org 2000/12/17 02:33:40 [uidswap.c] typo; from wsanchez@apple.com - + 20001220 - - (djm) Workaround PAM inconsistencies between Solaris derived PAM code + - (djm) Workaround PAM inconsistencies between Solaris derived PAM code and Linux-PAM. Based on report and fix from Andrew Morgan @@ -672,7 +695,7 @@ - (stevesk) OpenBSD CVS update: - markus@cvs.openbsd.org 2000/12/12 15:30:02 [ssh-keyscan.c ssh.c sshd.c] - consistently use __progname; from stevesk@pobox.com + consistently use __progname; from stevesk@pobox.com 20001211 - (bal) Applied patch to include ssh-keyscan into Redhat's package, and @@ -686,16 +709,16 @@ 20001210 - (bal) OpenBSD CVS updates - - markus@cvs.openbsd.org 2000/12/09 13:41:51 + - markus@cvs.openbsd.org 2000/12/09 13:41:51 [cipher.c cipher.h rijndael.c rijndael.h rijndael_boxes.h] undo rijndael changes - - markus@cvs.openbsd.org 2000/12/09 13:48:31 + - markus@cvs.openbsd.org 2000/12/09 13:48:31 [rijndael.c] fix byte order bug w/o introducing new implementation - - markus@cvs.openbsd.org 2000/12/09 14:08:27 + - markus@cvs.openbsd.org 2000/12/09 14:08:27 [sftp-server.c] "" -> "." for realpath; from vinschen@redhat.com - - markus@cvs.openbsd.org 2000/12/09 14:06:54 + - markus@cvs.openbsd.org 2000/12/09 14:06:54 [ssh-agent.c] extern int optind; from stevesk@sweden.hp.com - provos@cvs.openbsd.org 2000/12/09 23:51:11 @@ -704,19 +727,19 @@ 20001209 - (bal) OpenBSD CVS updates: - - djm@cvs.openbsd.org 2000/12/07 4:24:59 + - djm@cvs.openbsd.org 2000/12/07 4:24:59 [ssh.1] Typo fix from Wilfredo Sanchez ; ok theo 20001207 - (bal) OpenBSD CVS updates: - - markus@cvs.openbsd.org 2000/12/06 22:58:14 + - markus@cvs.openbsd.org 2000/12/06 22:58:14 [compat.c compat.h packet.c] disable debug messages for ssh.com/f-secure 2.0.1x, 2.1.0 - markus@cvs.openbsd.org 2000/12/06 23:10:39 [rijndael.c] unexpand(1) - - markus@cvs.openbsd.org 2000/12/06 23:05:43 + - markus@cvs.openbsd.org 2000/12/06 23:05:43 [cipher.c cipher.h rijndael.c rijndael.h rijndael_boxes.h] new rijndael implementation. fixes endian bugs @@ -746,14 +769,14 @@ 20001204 - (bal) More C functions defined in NeXT that are unaccessable without - defining -POSIX. - - (bal) OpenBSD CVS updates: - - markus@cvs.openbsd.org 2000/12/03 11:29:04 + defining -POSIX. + - (bal) OpenBSD CVS updates: + - markus@cvs.openbsd.org 2000/12/03 11:29:04 [compat.c] remove fallback to SSH_BUG_HMAC now that the drafts are updated - markus@cvs.openbsd.org 2000/12/03 11:27:55 [compat.c] - correctly match "2.1.0.pl2 SSH" etc; from + correctly match "2.1.0.pl2 SSH" etc; from pekkas@netcore.fi/bugzilla.redhat - markus@cvs.openbsd.org 2000/12/03 11:15:03 [auth2.c compat.c compat.h sshconnect2.c] @@ -763,7 +786,7 @@ - (bal) OpenBSD CVS updates: - markus@cvs.openbsd.org 2000/11/30 22:54:31 [channels.c] - debug->warn if tried to do -R style fwd w/o client requesting this; + debug->warn if tried to do -R style fwd w/o client requesting this; ok neils@ - markus@cvs.openbsd.org 2000/11/29 20:39:17 [cipher.c] @@ -771,7 +794,7 @@ - markus@cvs.openbsd.org 2000/11/30 18:33:05 [ssh-agent.c] agents must not dump core, ok niels@ - - markus@cvs.openbsd.org 2000/11/30 07:04:02 + - markus@cvs.openbsd.org 2000/11/30 07:04:02 [ssh.1] T is for both protocols - markus@cvs.openbsd.org 2000/12/01 00:00:51 @@ -782,7 +805,7 @@ check -T before isatty() - provos@cvs.openbsd.org 2000/11/29 13:51:27 [sshconnect.c] - show IP address and hostname when new key is encountered. okay markus@ + show IP address and hostname when new key is encountered. okay markus@ - markus@cvs.openbsd.org 2000/11/30 22:53:35 [sshconnect.c] disable agent/x11/port fwding if hostkey has changed; ok niels@ @@ -796,14 +819,14 @@ 20001202 - (bal) Backed out of part of Alain St-Denis' loginrec.c patch. - - (bal) Irix need some sort of mansubdir, patch by Michael Stone + - (bal) Irix need some sort of mansubdir, patch by Michael Stone 20001129 - (djm) Back out all the serverloop.c hacks. sshd will now hang again if there are background children with open fds. - (djm) bsd-rresvport.c bzero -> memset - - (djm) Don't fail in defines.h on absence of 64 bit types (we will + - (djm) Don't fail in defines.h on absence of 64 bit types (we will still fail during compilation of sftp-server). - (djm) Fail if ar is not found during configure - (djm) OpenBSD CVS updates: @@ -833,7 +856,7 @@ - (bal) Merge OpenBSD changes: - markus@cvs.openbsd.org 2000/11/15 22:31:36 [auth-options.c] - case insensitive key options; from stevesk@sweeden.hp.com + case insensitive key options; from stevesk@sweeden.hp.com - markus@cvs.openbsd.org 2000/11/16 17:55:43 [dh.c] do not use perror() in sshd, after child is forked() @@ -851,7 +874,7 @@ do not reorder keys if a key is removed - markus@cvs.openbsd.org 2000/11/15 19:58:08 [ssh.c] - just ignore non existing user keys + just ignore non existing user keys - millert@cvs.openbsd.org 200/11/15 20:24:43 [ssh-keygen.c] Add missing \n at end of error message. @@ -864,7 +887,7 @@ 20001117 - (bal) Changed from 'primes' to 'primes.out' for consistancy sake. It has no affect the output. Patch by Corinna Vinschen - - (stevesk) Reworked progname support. + - (stevesk) Reworked progname support. - (bal) Misplaced #include "includes.h" in bsd-setproctitle.c. Patch by Shinichi Maruyama @@ -875,7 +898,7 @@ 20001113 - - (djm) Add pointer to http://www.imasy.or.jp/~gotoh/connect.c to + - (djm) Add pointer to http://www.imasy.or.jp/~gotoh/connect.c to contrib/README - (djm) Merge OpenBSD changes: - markus@cvs.openbsd.org 2000/11/06 16:04:56 @@ -902,7 +925,7 @@ [readconf.c readconf.h rsa.c rsa.h servconf.c servconf.h ssh-add.c] [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config] [sshconnect1.c sshconnect2.c sshd.8 sshd.c sshd_config ssh-dss.c] - [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h] + [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h] add support for RSA to SSH2. please test. there are now 3 types of keys: RSA1 is used by ssh-1 only, RSA and DSA are used by SSH2. @@ -926,10 +949,10 @@ - (djm) Added /etc/primes for kex DH group neg, fixup Makefile.in and packaging files - (djm) Fix new Makefile.in warnings - - (djm) Fix vsprintf("%h") in bsd-snprintf.c, short int va_args are - promoted to type int. Report and fix from Dan Astoorian + - (djm) Fix vsprintf("%h") in bsd-snprintf.c, short int va_args are + promoted to type int. Report and fix from Dan Astoorian - - (djm) Hardwire sysconfdir in RPM spec files as some RPM versions get + - (djm) Hardwire sysconfdir in RPM spec files as some RPM versions get it wrong. Report from Bennett Todd 20001110 @@ -937,10 +960,10 @@ - (bal) Changed from --with-skey to --with-skey=PATH in configure.in - (bal) Added in check to verify S/Key library is being detected in configure.in - - (bal) next-posix.h - added another prototype wrapped in POSIX ifdef/endif. + - (bal) next-posix.h - added another prototype wrapped in POSIX ifdef/endif. Patch by Mark Miller - (bal) Added 'util.h' header to loginrec.c only if HAVE_UTIL_H is defined - to remove warnings under MacOS X. Patch by Mark Miller + to remove warnings under MacOS X. Patch by Mark Miller - (bal) Fixed LDFLAG mispelling in configure.in for --with-afs 20001107 @@ -954,7 +977,7 @@ 20001106 - (djm) Use Jim's new 1.0.3 askpass in Redhat RPMs - (djm) Manually fix up missed diff hunks (mainly RCS idents) - - (djm) Remove UPGRADING document in favour of a link to the better + - (djm) Remove UPGRADING document in favour of a link to the better maintained FAQ on www.openssh.com - (djm) Fix multiple dependancy on gnome-libs from Pekka Savola @@ -989,10 +1012,10 @@ - (bal) next-posix.h - spelling and forgot a prototype 20001028 - - (djm) fix select hack in serverloop.c from Philippe WILLEM + - (djm) fix select hack in serverloop.c from Philippe WILLEM - (djm) Fix mangled AIXAUTHENTICATE code - - (djm) authctxt->pw may be NULL. Fix from Markus Friedl + - (djm) authctxt->pw may be NULL. Fix from Markus Friedl - (djm) Sync with OpenBSD: - markus@cvs.openbsd.org 2000/10/16 15:46:32 @@ -1029,7 +1052,7 @@ - markus@cvs.openbsd.org 2000/10/27 01:32:19 [channels.c channels.h clientloop.c serverloop.c session.c] [ssh.c util.c] - enable non-blocking IO on channels, and tty's (except for the + enable non-blocking IO on channels, and tty's (except for the client ttys). 20001027 @@ -1060,7 +1083,7 @@ supplied passphrase. Problem report from Lutz Jaenicke - (bal) Changed from GNU rx to PCRE on suggestion from djm. - - (bal) Integrated Sony NEWS-OS patches from NAKAJI Hirouyuki + - (bal) Integrated Sony NEWS-OS patches from NAKAJI Hirouyuki 20001016 @@ -1079,7 +1102,7 @@ AllowTcpForwarding; from naddy@ - markus@cvs.openbsd.org 2000/10/14 06:16:56 [auth2.c compat.c compat.h sshconnect2.c version.h] - OpenSSH_2.3; note that is is not complete, but the version number + OpenSSH_2.3; note that is is not complete, but the version number needs to be changed for interoperability reasons - markus@cvs.openbsd.org 2000/10/14 06:19:45 [auth-rsa.c] @@ -1091,12 +1114,12 @@ - markus@cvs.openbsd.org 2000/10/15 08:18:31 [rijndael.c] typo - - (djm) Copy manpages back over from OpenBSD - too tedious to wade + - (djm) Copy manpages back over from OpenBSD - too tedious to wade through diffs - - (djm) Added condrestart to Redhat init script. Patch from Pekka Savola + - (djm) Added condrestart to Redhat init script. Patch from Pekka Savola - (djm) Update version in Redhat spec file - - (djm) Merge some of Nalin Dahyabhai changes from the + - (djm) Merge some of Nalin Dahyabhai changes from the Redhat 7.0 spec file - (djm) Make inability to read/write PRNG seedfile non-fatal @@ -1108,7 +1131,7 @@ - (bal) Add support for realpath and getcwd for platforms with broken or missing realpath implementations for sftp-server. - (bal) Corrected mistake in INSTALL in regards to GNU rx library - - (bal) Add support for GNU rx library for those lacking regexp support + - (bal) Add support for GNU rx library for those lacking regexp support - (djm) Don't accept PAM_PROMPT_ECHO_ON messages during initial auth - (djm) Revert SSH2 serverloop hack, will find a better way. - (djm) Add workaround for Linux 2.4's gratuitious errno change. Patch @@ -1214,11 +1237,11 @@ 20000930 - (djm) Irix ssh_prng_cmds path fix from Pekka Savola - - (djm) Support in bsd-snprintf.c for long long conversions from + - (djm) Support in bsd-snprintf.c for long long conversions from Ben Lindstrom - (djm) Cleanup NeXT support from Ben Lindstrom - (djm) Ignore SIGPIPEs from serverloop to child. Fixes crashes with - very short lived X connections. Bug report from Tobias Oetiker + very short lived X connections. Bug report from Tobias Oetiker . Fix from Markus Friedl - (djm) Add recent InitScripts as a RPM dependancy for openssh-server patch from Pekka Savola @@ -1234,27 +1257,27 @@ - markus@cvs.openbsd.org 2000/09/28 12:03:18 [channels.c] debug -> debug2 cleanup - - (djm) Irix strips "/dev/tty" from [uw]tmp entries (other systems only + - (djm) Irix strips "/dev/tty" from [uw]tmp entries (other systems only strip "/dev/"). Fix loginrec.c based on patch from Alain St-Denis - - (djm) Fix 9 character passphrase failure with gnome-ssh-askpass. - Problem was caused by interrupted read in ssh-add. Report from Donald + - (djm) Fix 9 character passphrase failure with gnome-ssh-askpass. + Problem was caused by interrupted read in ssh-add. Report from Donald J. Barry 20000929 - (djm) Fix SSH2 not terminating until all background tasks done problem. - - (djm) Another off-by-one fix from Pavel Kankovsky - + - (djm) Another off-by-one fix from Pavel Kankovsky + - (djm) Clean up. Strip some unnecessary differences with OpenBSD's code, tidy necessary differences. Use Markus' new debugN() in entropy.c - - (djm) Merged big SCO portability patch from Tim Rice + - (djm) Merged big SCO portability patch from Tim Rice 20000926 - (djm) Update X11-askpass to 1.0.2 in RPM spec file - (djm) Define _REENTRANT to pickup strtok_r() on HP/UX - - (djm) Security: fix off-by-one buffer overrun in fake-getnameinfo.c. - Report and fix from Pavel Kankovsky + - (djm) Security: fix off-by-one buffer overrun in fake-getnameinfo.c. + Report and fix from Pavel Kankovsky 20000924 - (djm) Merged cleanup patch from Mark Miller @@ -1263,14 +1286,14 @@ 20000923 - - (djm) Fix address logging in utmp from Kevin Steves + - (djm) Fix address logging in utmp from Kevin Steves - (djm) Redhat spec and manpage fixes from Pekka Savola - (djm) Seperate tests for int64_t and u_int64_t types - - (djm) Tweak password expiry checking at suggestion of Kevin Steves + - (djm) Tweak password expiry checking at suggestion of Kevin Steves - (djm) NeXT patch from Ben Lindstrom - - (djm) Use printf %lld instead of %qd in sftp-server.c. Fix from + - (djm) Use printf %lld instead of %qd in sftp-server.c. Fix from Michael Stone - (djm) OpenBSD CVS sync: - markus@cvs.openbsd.org 2000/09/17 09:38:59 @@ -1304,13 +1327,13 @@ 20000916 - - (djm) Fix SSL search order from Lutz Jaenicke + - (djm) Fix SSL search order from Lutz Jaenicke - (djm) New SuSE spec from Corinna Vinschen - (djm) Update CygWin support from Corinna Vinschen - (djm) Use a real struct sockaddr inside the fake struct sockaddr_storage. Patch from Larry Jones - - (djm) Add Steve VanDevender's PAM + - (djm) Add Steve VanDevender's PAM password change patch. - (djm) Bring licenses on my stuff in line with OpenBSD's - (djm) Cleanup auth-passwd.c and unify HP/UX authentication. Patch from @@ -1321,9 +1344,9 @@ - (djm) Update Redhat SPEC file accordingly - (djm) Add Kevin Steves HP/UX contrib files - (djm) Add Charles Levert getpgrp patch - - (djm) Fix password auth on HP/UX 10.20. Patch from Dirk De Wachter + - (djm) Fix password auth on HP/UX 10.20. Patch from Dirk De Wachter - - (djm) Fixprogs and entropy list fixes from Larry Jones + - (djm) Fixprogs and entropy list fixes from Larry Jones - (djm) Fix for SuSE spec file from Takashi YOSHIDA @@ -1342,10 +1365,10 @@ prototype - deraadt@cvs.openbsd.org 2000/09/07 14:27:56 [ALL] - cleanup copyright notices on all files. I have attempted to be - accurate with the details. everything is now under Tatu's licence - (which I copied from his readme), and/or the core-sdi bsd-ish thing - for deattack, or various openbsd developers under a 2-term bsd + cleanup copyright notices on all files. I have attempted to be + accurate with the details. everything is now under Tatu's licence + (which I copied from his readme), and/or the core-sdi bsd-ish thing + for deattack, or various openbsd developers under a 2-term bsd licence. We're not changing any rules, just being accurate. - markus@cvs.openbsd.org 2000/09/07 14:40:30 [channels.c channels.h clientloop.c serverloop.c ssh.c] @@ -1799,7 +1822,7 @@ - (djm) Added 'distprep' make target to simplify packaging - (djm) Added patch from Chris Adams to add OSF SIA support. Enable using "USE_SIA=1 ./configure [options]" - + 20000627 - (djm) Fixes to login code - not setting li->uid, cleanups - (djm) Formatting @@ -1921,7 +1944,7 @@ - Don't try to retrieve lastlog from wtmp/wtmpx if DISABLE_LASTLOG is def'd - Set AIX to use preformatted manpages - + 20000610 - (djm) Minor doc tweaks - (djm) Fix for configure on bash2 from Jim Knoble @@ -1947,7 +1970,7 @@ teach protocol v2 to count login failures properly and also enable an explanation of why the password prompt comes up again like v1; this is NOT crypto - - markus@cvs.openbsd.org + - markus@cvs.openbsd.org [readconf.c readconf.h servconf.c servconf.h session.c ssh.1 ssh.c sshd.8] xauth_location support; pr 1234 [readconf.c sshconnect2.c] @@ -1978,7 +2001,7 @@ - (andre) New login code - Remove bsd-login.[ch] and all the OpenBSD-derived code in login.c - Add loginrec.[ch], logintest.c and autoconf code - + 20000531 - Cleanup of auth.c, login.c and fake-* - Cleanup of auth-pam.c, save and print "account expired" error messages @@ -2383,7 +2406,7 @@ no adjust after close - [sshd.c compat.c ] interop w/ latest ssh.com windows client. - + 20000406 - OpenBSD CVS update: - [channels.c] @@ -2704,7 +2727,7 @@ - [readpass.c] instead of blocking SIGINT, catch it ourselves, so that we can clean the tty modes up and kill ourselves -- instead of our process group - leader (scp, cvs, ...) going away and leaving us in noecho mode. + leader (scp, cvs, ...) going away and leaving us in noecho mode. people with cbreak shells never even noticed.. - [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8] ie. -> i.e., @@ -2741,7 +2764,7 @@ 20000118 - Fixed --with-pid-dir option - Makefile fix from Gary E. Miller - - Compile fix for HPUX and Solaris from Andre Lucas + - Compile fix for HPUX and Solaris from Andre Lucas 20000117 @@ -2844,7 +2867,7 @@ 20000103 - Add explicit make rules for files proccessed by fixpaths. - - Fix "make install" in RPM spec files. Report from Tenkou N. Hattori + - Fix "make install" in RPM spec files. Report from Tenkou N. Hattori - Removed "nullok" directive from default PAM configuration files. Added information on enabling EmptyPasswords on openssh+PAM in @@ -3019,7 +3042,7 @@ - Use LDFLAGS correctly - Fix SIGIO error in scp - Simplify status line printing in scp - - Added better test for inline functions compiler support from + - Added better test for inline functions compiler support from Darren_Hall@progressive.com 19991214 @@ -3247,7 +3270,7 @@ print usage() everytime we get bad options - [ssh-keygen.c] overflow, djm@mindrot.org - [sshd.c] fix sigchld race; cjc5@po.cwru.edu - + 19991120 - Merged more Solaris support from Marc G. Fournier diff --git a/Makefile.in b/Makefile.in index c3cd580e..8ea71915 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,9 +33,9 @@ SSH_MODE= @SSHMODE@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ -@NO_SFTP@SFTP-SERVER=sftp-server$(EXEEXT) +@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT) -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP-SERVER) +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP_PROGS) LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o deattack.o dispatch.o hmac.o hostfile.o key.o kex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o @@ -43,8 +43,8 @@ SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o -TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 -CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh-keyscan.0 ssh.0 sshd.0 sftp-server.0 +TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 +CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh-keyscan.0 ssh.0 sshd.0 sftp-server.0 sftp.1 MANPAGES = @MANTYPE@ CONFIGFILES=sshd_config ssh_config primes @@ -105,8 +105,12 @@ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o log-client.o ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a log-client.o ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp-server.o log-server.o - $(LD) -o $@ sftp-server.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp-server.o sftp-common.o log-server.o + $(LD) -o $@ sftp-server.o sftp-common.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + +# XXX: need to -lssh twice here! +sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o log-client.o + $(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) # test driver for the loginrec code - not built by default logintest: logintest.o $(LIBCOMPAT) libssh.a log-client.o loginrec.o @@ -156,6 +160,7 @@ install-files: $(INSTALL) -m 0755 -s ssh-keygen $(DESTDIR)$(bindir)/ssh-keygen $(INSTALL) -m 0775 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd + @NO_SFTP@$$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(libexecdir)/sftp-server $(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 @@ -164,6 +169,7 @@ install-files: $(INSTALL) -m 644 ssh-keygen.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 $(INSTALL) -m 644 ssh-keyscan.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 $(INSTALL) -m 644 sshd.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 + @NO_SFTP@$$(INSTALL) -m 644 sftp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 @NO_SFTP@$(INSTALL) -m 644 sftp-server.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 -rm -f $(DESTDIR)$(bindir)/slogin ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin @@ -241,6 +247,7 @@ uninstall: -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) -rm -r $(DESTDIR)$(libexecdir)/sftp-server$(EXEEXT) -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 @@ -248,6 +255,7 @@ uninstall: -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 diff --git a/TODO b/TODO index 62c51e15..1165a0d9 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,6 @@ Programming: +- Grep for 'XXX' comments and fix + - Replacement for setproctitle() - HP/UX support only currently - Improve PAM support (a pam_lastlog module will cause sshd to exit) diff --git a/auth-options.c b/auth-options.c index 5457d9b1..04d2f085 100644 --- a/auth-options.c +++ b/auth-options.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-options.c,v 1.11 2001/01/21 19:05:41 markus Exp $"); +RCSID("$OpenBSD: auth-options.c,v 1.12 2001/02/03 10:08:36 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -18,6 +18,7 @@ RCSID("$OpenBSD: auth-options.c,v 1.11 2001/01/21 19:05:41 markus Exp $"); #include "log.h" #include "canohost.h" #include "auth-options.h" +#include "servconf.h" /* Flags set authorized_keys flags */ int no_port_forwarding_flag = 0; @@ -31,6 +32,8 @@ char *forced_command = NULL; /* "environment=" options. */ struct envstring *custom_environment = NULL; +extern ServerOptions options; + void auth_clear_options(void) { @@ -55,61 +58,61 @@ auth_clear_options(void) * side effect: sets key option flags */ int -auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum) +auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { const char *cp; - if (!options) + if (!opts) return 1; /* reset options */ auth_clear_options(); - while (*options && *options != ' ' && *options != '\t') { + while (*opts && *opts != ' ' && *opts != '\t') { cp = "no-port-forwarding"; - if (strncasecmp(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 (strncasecmp(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 (strncasecmp(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 (strncasecmp(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 (strncasecmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { int i; - options += strlen(cp); - forced_command = xmalloc(strlen(options) + 1); + 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", file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", @@ -118,28 +121,28 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum) } forced_command[i] = 0; packet_send_debug("Forced command: %.900s", forced_command); - options++; + opts++; goto next_option; } cp = "environment=\""; - if (strncasecmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { int i; 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", file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", @@ -149,7 +152,7 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum) 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; @@ -157,23 +160,26 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum) goto next_option; } cp = "from=\""; - if (strncasecmp(options, cp, strlen(cp)) == 0) { + if (strncasecmp(opts, cp, strlen(cp)) == 0) { int mname, mip; - char *patterns = xmalloc(strlen(options) + 1); + const char *remote_ip = get_remote_ipaddr(); + const char *remote_host = get_canonical_hostname( + options.reverse_mapping_check); + char *patterns = xmalloc(strlen(opts) + 1); int i; - options += strlen(cp); + 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", file, linenum); packet_send_debug("%.100s, line %lu: missing end quote", @@ -181,24 +187,26 @@ auth_parse_options(struct passwd *pw, char *options, char *file, u_long linenum) continue; } 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; } @@ -210,13 +218,13 @@ 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 */ @@ -224,9 +232,9 @@ next_option: bad_option: log("Bad options in %.100s file, line %lu: %.50s", - file, linenum, options); + file, linenum, opts); packet_send_debug("Bad options in %.100s file, line %lu: %.50s", - file, linenum, options); + file, linenum, opts); /* deny access */ return 0; } diff --git a/auth-pam.c b/auth-pam.c index fcf3b690..3980861f 100644 --- a/auth-pam.c +++ b/auth-pam.c @@ -211,10 +211,12 @@ int auth_pam_password(struct passwd *pw, const char *password) int do_pam_account(char *username, char *remote_user) { int pam_retval; + extern ServerOptions options; - debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname()); + debug("PAM setting rhost to \"%.200s\"", + get_canonical_hostname(options.reverse_mapping_check)); pam_retval = pam_set_item(pamh, PAM_RHOST, - get_canonical_hostname()); + get_canonical_hostname(options.reverse_mapping_check)); if (pam_retval != PAM_SUCCESS) { fatal("PAM set rhost failed[%d]: %.200s", pam_retval, PAM_STRERROR(pamh, pam_retval)); diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index 87d51549..0edbdb5f 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.21 2001/01/21 19:05:42 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.22 2001/02/03 10:08:36 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -49,7 +49,8 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key if (!auth_rhosts(pw, client_user)) return 0; - canonical_hostname = get_canonical_hostname(); + canonical_hostname = get_canonical_hostname( + options.reverse_mapping_check); debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); diff --git a/auth-rhosts.c b/auth-rhosts.c index 4f9ea886..d8d10ffc 100644 --- a/auth-rhosts.c +++ b/auth-rhosts.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rhosts.c,v 1.19 2001/01/21 19:05:42 markus Exp $"); +RCSID("$OpenBSD: auth-rhosts.c,v 1.20 2001/02/03 10:08:36 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -183,7 +183,7 @@ auth_rhosts(struct passwd *pw, const char *client_user) stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) return 0; - hostname = get_canonical_hostname(); + hostname = get_canonical_hostname(options.reverse_mapping_check); ipaddr = get_remote_ipaddr(); /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ diff --git a/auth.c b/auth.c index 187216d2..4e3cf675 100644 --- a/auth.c +++ b/auth.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth.c,v 1.14 2001/01/21 19:05:43 markus Exp $"); +RCSID("$OpenBSD: auth.c,v 1.15 2001/02/03 10:08:37 markus Exp $"); #ifdef HAVE_LOGIN_H #include @@ -228,7 +228,7 @@ auth_root_allowed(void) log("Root login accepted for forced command."); return 1; } else { - log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); + log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); return 0; } } diff --git a/auth1.c b/auth1.c index 6e9808e5..1986b2d8 100644 --- a/auth1.c +++ b/auth1.c @@ -266,8 +266,8 @@ do_authloop(Authctxt *authctxt) #elif defined(HAVE_OSF_SIA) /* Do SIA auth with password */ if (sia_validate_user(NULL, saved_argc, saved_argv, - get_canonical_hostname(), pw->pw_name, NULL, 0, - NULL, password) == SIASUCCESS) { + get_canonical_hostname(options.reverse_mapping_check), + pw->pw_name, NULL, 0, NULL, password) == SIASUCCESS) { authenticated = 1; } #else /* !USE_PAM && !HAVE_OSF_SIA */ @@ -347,7 +347,9 @@ do_authloop(Authctxt *authctxt) if (authctxt->failures++ > AUTH_FAIL_MAX) { #ifdef WITH_AIXAUTHENTICATE - loginfailed(user,get_canonical_hostname(),"ssh"); + loginfailed(user, + get_canonical_hostname(options.reverse_mapping_check), + "ssh"); #endif /* WITH_AIXAUTHENTICATE */ packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } @@ -433,7 +435,9 @@ do_authentication() #ifdef WITH_AIXAUTHENTICATE /* We don't have a pty yet, so just label the line as "ssh" */ - if (loginsuccess(authctxt->user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0) + if (loginsuccess(authctxt->user, + get_canonical_hostname(options.reverse_mapping_check), + "ssh", &aixloginmsg) < 0) aixloginmsg = NULL; #endif /* WITH_AIXAUTHENTICATE */ diff --git a/auth2.c b/auth2.c index cff34c60..5f8b4234 100644 --- a/auth2.c +++ b/auth2.c @@ -310,7 +310,8 @@ userauth_reply(Authctxt *authctxt, int authenticated) #ifdef WITH_AIXAUTHENTICATE /* We don't have a pty yet, so just label the line as "ssh" */ if (loginsuccess(authctxt->user?authctxt->user:"NOUSER", - get_canonical_hostname(), "ssh", &aixloginmsg) < 0) + get_canonical_hostname(options.reverse_mapping_check), + "ssh", &aixloginmsg) < 0) aixloginmsg = NULL; #endif /* WITH_AIXAUTHENTICATE */ /* turn off userauth */ @@ -354,8 +355,9 @@ userauth_none(Authctxt *authctxt) return auth_pam_password(authctxt->pw, ""); #elif defined(HAVE_OSF_SIA) return (sia_validate_user(NULL, saved_argc, saved_argv, - get_canonical_hostname(), authctxt->user?authctxt->user:"NOUSER", - NULL, 0, NULL, "") == SIASUCCESS); + get_canonical_hostname(options.reverse_mapping_check), + authctxt->user?authctxt->user:"NOUSER", NULL, 0, + NULL, "") == SIASUCCESS); #else /* !HAVE_OSF_SIA && !USE_PAM */ return auth_password(authctxt->pw, ""); #endif /* USE_PAM */ @@ -381,8 +383,9 @@ userauth_passwd(Authctxt *authctxt) auth_pam_password(authctxt->pw, password) == 1) #elif defined(HAVE_OSF_SIA) sia_validate_user(NULL, saved_argc, saved_argv, - get_canonical_hostname(), authctxt->user?authctxt->user:"NOUSER", - NULL, 0, NULL, password) == SIASUCCESS) + get_canonical_hostname(options.reverse_mapping_check), + authctxt->user?authctxt->user:"NOUSER", NULL, 0, NULL, + password) == SIASUCCESS) #else /* !USE_PAM && !HAVE_OSF_SIA */ auth_password(authctxt->pw, password) == 1) #endif /* USE_PAM */ diff --git a/canohost.c b/canohost.c index f3a65932..8253e9b6 100644 --- a/canohost.c +++ b/canohost.c @@ -12,35 +12,35 @@ */ #include "includes.h" -RCSID("$OpenBSD: canohost.c,v 1.19 2001/01/29 19:42:33 markus Exp $"); +RCSID("$OpenBSD: canohost.c,v 1.20 2001/02/03 10:08:37 markus Exp $"); #include "packet.h" #include "xmalloc.h" #include "log.h" +void check_ip_options(int socket, char *ipaddr); + /* * Return the canonical name of the host at the other end of the socket. The * caller should free the returned string with xfree. */ char * -get_remote_hostname(int socket) +get_remote_hostname(int socket, int reverse_mapping_check) { struct sockaddr_storage from; int i; socklen_t fromlen; struct addrinfo hints, *ai, *aitop; - char name[MAXHOSTNAMELEN]; - char ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; + char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; /* Get IP address of client. */ fromlen = sizeof(from); memset(&from, 0, sizeof(from)); - if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { + if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) { debug("getpeername failed: %.100s", strerror(errno)); fatal_cleanup(); } - #ifdef IPV4_IN_IPV6 if (from.ss_family == AF_INET6) { struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from; @@ -63,6 +63,8 @@ get_remote_hostname(int socket) } } #endif + if (from.ss_family == AF_INET) + check_ip_options(socket, ntop); if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) @@ -70,99 +72,99 @@ get_remote_hostname(int socket) /* Map the IP address to a host name. */ if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), - NULL, 0, NI_NAMEREQD) == 0) { - /* Got host name. */ - name[sizeof(name) - 1] = '\0'; - /* - * Convert it to all lowercase (which is expected by the rest - * of this software). - */ - for (i = 0; name[i]; i++) - if (isupper(name[i])) - name[i] = tolower(name[i]); - - /* - * Map it back to an IP address and check that the given - * address actually is an address of this host. This is - * necessary because anyone with access to a name server can - * define arbitrary names for an IP address. Mapping from - * name to IP address can be trusted better (but can still be - * fooled if the intruder has access to the name server of - * the domain). - */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = from.ss_family; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { - log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); - strlcpy(name, ntop, sizeof name); - goto check_ip_options; - } - /* Look for the address from the list of addresses. */ - for (ai = aitop; ai; ai = ai->ai_next) { - if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, - sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && - (strcmp(ntop, ntop2) == 0)) - break; - } - freeaddrinfo(aitop); - /* If we reached the end of the list, the address was not there. */ - if (!ai) { - /* Address not found for the host name. */ - log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", - ntop, name); - strlcpy(name, ntop, sizeof name); - goto check_ip_options; - } - /* Address was found for the host name. We accept the host name. */ - } else { - /* Host name not found. Use ascii representation of the address. */ - strlcpy(name, ntop, sizeof name); - log("Could not reverse map address %.100s.", name); + NULL, 0, NI_NAMEREQD) != 0) { + /* Host name not found. Use ip address. */ + log("Could not reverse map address %.100s.", ntop); + return xstrdup(ntop); } -check_ip_options: + /* Got host name. */ + name[sizeof(name) - 1] = '\0'; + /* + * Convert it to all lowercase (which is expected by the rest + * of this software). + */ + for (i = 0; name[i]; i++) + if (isupper(name[i])) + name[i] = tolower(name[i]); + if (!reverse_mapping_check) + return xstrdup(name); /* - * If IP options are supported, make sure there are none (log and - * disconnect them if any are found). Basically we are worried about - * source routing; it can be used to pretend you are somebody - * (ip-address) you are not. That itself may be "almost acceptable" - * under certain circumstances, but rhosts autentication is useless - * if source routing is accepted. Notice also that if we just dropped - * source routing here, the other side could use IP spoofing to do - * rest of the interaction and could still bypass security. So we - * exit here if we detect any IP options. + * Map it back to an IP address and check that the given + * address actually is an address of this host. This is + * necessary because anyone with access to a name server can + * define arbitrary names for an IP address. Mapping from + * name to IP address can be trusted better (but can still be + * fooled if the intruder has access to the name server of + * the domain). */ - /* IP options -- IPv4 only */ - if (from.ss_family == AF_INET) { - u_char options[200], *ucp; - char text[1024], *cp; - socklen_t option_size; - int ipproto; - struct protoent *ip; - - if ((ip = getprotobyname("ip")) != NULL) - ipproto = ip->p_proto; - else - ipproto = IPPROTO_IP; - option_size = sizeof(options); - if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options, - &option_size) >= 0 && option_size != 0) { - cp = text; - /* Note: "text" buffer must be at least 3x as big as options. */ - for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) - sprintf(cp, " %2.2x", *ucp); - log("Connection from %.100s with IP options:%.800s", - ntop, text); - packet_disconnect("Connection from %.100s with IP options:%.800s", - ntop, text); - } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = from.ss_family; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { + log("reverse mapping checking getaddrinfo for %.700s " + "failed - POSSIBLE BREAKIN ATTEMPT!", name); + return xstrdup(ntop); + } + /* Look for the address from the list of addresses. */ + for (ai = aitop; ai; ai = ai->ai_next) { + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, + sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && + (strcmp(ntop, ntop2) == 0)) + break; + } + freeaddrinfo(aitop); + /* If we reached the end of the list, the address was not there. */ + if (!ai) { + /* Address not found for the host name. */ + log("Address %.100s maps to %.600s, but this does not " + "map back to the address - POSSIBLE BREAKIN ATTEMPT!", + ntop, name); + return xstrdup(ntop); } - return xstrdup(name); } +/* + * If IP options are supported, make sure there are none (log and + * disconnect them if any are found). Basically we are worried about + * source routing; it can be used to pretend you are somebody + * (ip-address) you are not. That itself may be "almost acceptable" + * under certain circumstances, but rhosts autentication is useless + * if source routing is accepted. Notice also that if we just dropped + * source routing here, the other side could use IP spoofing to do + * rest of the interaction and could still bypass security. So we + * exit here if we detect any IP options. + */ +/* IPv4 only */ +void +check_ip_options(int socket, char *ipaddr) +{ + u_char options[200], *ucp; + char text[1024], *cp; + socklen_t option_size; + int ipproto; + struct protoent *ip; + + if ((ip = getprotobyname("ip")) != NULL) + ipproto = ip->p_proto; + else + ipproto = IPPROTO_IP; + option_size = sizeof(options); + if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options, + &option_size) >= 0 && option_size != 0) { + cp = text; + /* Note: "text" buffer must be at least 3x as big as options. */ + for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) + sprintf(cp, " %2.2x", *ucp); + log("Connection from %.100s with IP options:%.800s", + ipaddr, text); + packet_disconnect("Connection from %.100s with IP options:%.800s", + ipaddr, text); + } +} + /* * Return the canonical name of the host in the other side of the current * connection. The host name is cached, so it is efficient to call this @@ -170,20 +172,27 @@ check_ip_options: */ const char * -get_canonical_hostname() +get_canonical_hostname(int reverse_mapping_check) { static char *canonical_host_name = NULL; + static int reverse_mapping_checked = 0; - /* Check if we have previously retrieved this same name. */ - if (canonical_host_name != NULL) - return canonical_host_name; + /* Check if we have previously retrieved name with same option. */ + if (canonical_host_name != NULL) { + if (reverse_mapping_checked != reverse_mapping_check) + xfree(canonical_host_name); + else + return canonical_host_name; + } /* Get the real hostname if socket; otherwise return UNKNOWN. */ if (packet_connection_is_on_socket()) - canonical_host_name = get_remote_hostname(packet_get_connection_in()); + canonical_host_name = get_remote_hostname( + packet_get_connection_in(), reverse_mapping_check); else canonical_host_name = xstrdup("UNKNOWN"); + reverse_mapping_checked = reverse_mapping_check; return canonical_host_name; } diff --git a/canohost.h b/canohost.h index 982ec594..da60b3af 100644 --- a/canohost.h +++ b/canohost.h @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.h,v 1.3 2001/01/29 19:42:35 markus Exp $ */ +/* $OpenBSD: canohost.h,v 1.4 2001/02/03 10:08:37 markus Exp $ */ /* * Author: Tatu Ylonen @@ -11,22 +11,17 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ -/* - * Returns the name of the machine at the other end of the socket. The - * returned string should be freed by the caller. - */ -char *get_remote_hostname(int socket); /* * Return the canonical name of the host in the other side of the current * connection (as returned by packet_get_connection). The host name is * cached, so it is efficient to call this several times. */ -const char *get_canonical_hostname(void); +const char *get_canonical_hostname(int reverse_mapping_check); /* * Returns the IP-address of the remote host as a string. The returned - * string must not be freed. + * string is cached and must not be freed. */ const char *get_remote_ipaddr(void); diff --git a/channels.c b/channels.c index 82a2db05..d343ac89 100644 --- a/channels.c +++ b/channels.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.85 2001/01/29 19:42:35 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.88 2001/02/01 21:58:08 markus Exp $"); #include #include @@ -600,7 +600,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) struct sockaddr addr; int newsock, newch; socklen_t addrlen; - char buf[1024], *remote_hostname, *rtype; + char buf[1024], *remote_ipaddr, *rtype; int remote_port; rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? @@ -616,13 +616,13 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) error("accept: %.100s", strerror(errno)); return; } - remote_hostname = get_remote_hostname(newsock); + remote_ipaddr = get_peer_ipaddr(newsock); remote_port = get_peer_port(newsock); snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, " "connect from %.200s port %d", c->listening_port, c->path, c->host_port, - remote_hostname, remote_port); + remote_ipaddr, remote_port); newch = channel_new(rtype, SSH_CHANNEL_OPENING, newsock, newsock, -1, @@ -644,7 +644,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) packet_put_int(c->host_port); } /* originator host and port */ - packet_put_cstring(remote_hostname); + packet_put_cstring(remote_ipaddr); packet_put_int(remote_port); packet_send(); } else { @@ -657,7 +657,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) } packet_send(); } - xfree(remote_hostname); + xfree(remote_ipaddr); } } diff --git a/contrib/caldera/openssh.spec b/contrib/caldera/openssh.spec index 557770d7..6bba4d36 100644 --- a/contrib/caldera/openssh.spec +++ b/contrib/caldera/openssh.spec @@ -253,9 +253,13 @@ fi %attr(4755,root,root) %{_bindir}/ssh %attr(0755,root,root) %{_bindir}/ssh-agent %attr(0755,root,root) %{_bindir}/ssh-add +%attr(0755,root,root) %{_bindir}/ssh-keyscan +%attr(0755,root,root) %{_bindir}/sftp %attr(0644,root,root) %{_mandir}/man1/ssh.1* %attr(0644,root,root) %{_mandir}/man1/ssh-agent.1* %attr(0644,root,root) %{_mandir}/man1/ssh-add.1* +%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1* +%attr(0644,root,root) %{_mandir}/man1/sftp.1* %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh_config %attr(-,root,root) %{_bindir}/slogin %attr(-,root,root) %{_mandir}/man1/slogin.1* diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec index 482306f8..c6574a27 100644 --- a/contrib/redhat/openssh.spec +++ b/contrib/redhat/openssh.spec @@ -223,9 +223,13 @@ fi %attr(4755,root,root) %{_bindir}/ssh %attr(0755,root,root) %{_bindir}/ssh-agent %attr(0755,root,root) %{_bindir}/ssh-add +%attr(0755,root,root) %{_bindir}/ssh-keyscan +%attr(0755,root,root) %{_bindir}/sftp %attr(0644,root,root) %{_mandir}/man1/ssh.1* %attr(0644,root,root) %{_mandir}/man1/ssh-agent.1* %attr(0644,root,root) %{_mandir}/man1/ssh-add.1* +%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1* +%attr(0644,root,root) %{_mandir}/man1/sftp.1* %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh_config %attr(-,root,root) %{_bindir}/slogin %attr(-,root,root) %{_mandir}/man1/slogin.1* diff --git a/contrib/suse/openssh.spec b/contrib/suse/openssh.spec index b4cc2d92..01ff204e 100644 --- a/contrib/suse/openssh.spec +++ b/contrib/suse/openssh.spec @@ -180,6 +180,8 @@ fi %attr(-,root,root) /usr/bin/slogin %attr(0755,root,root) /usr/bin/ssh-agent %attr(0755,root,root) /usr/bin/ssh-add +%attr(0755,root,root) /usr/bin/ssh-keyscan +%attr(0755,root,root) /usr/bin/sftp %attr(0755,root,root) /usr/sbin/sshd %attr(-,root,root) /usr/sbin/rcsshd %attr(0755,root,root) %dir /usr/lib/ssh diff --git a/scp.1 b/scp.1 index 0a2ca1a3..10e67aa3 100644 --- a/scp.1 +++ b/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/servconf.c b/servconf.c index 9f292b6a..5fa41e02 100644 --- a/servconf.c +++ b/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.63 2001/01/22 23:06:39 markus Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.64 2001/02/03 10:08:37 markus Exp $"); #ifdef KRB4 #include @@ -92,6 +92,7 @@ initialize_server_options(ServerOptions *options) options->max_startups_rate = -1; options->max_startups = -1; options->banner = NULL; + options->reverse_mapping_check = -1; } void @@ -186,6 +187,8 @@ fill_default_server_options(ServerOptions *options) options->max_startups_rate = 100; /* 100% */ if (options->max_startups_begin == -1) options->max_startups_begin = options->max_startups; + if (options->reverse_mapping_check == -1) + options->reverse_mapping_check = 0; } /* Keyword tokens. */ @@ -208,7 +211,7 @@ typedef enum { sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sProtocol, sPidFile, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, - sBanner + sBanner, sReverseMappingCheck } ServerOpCodes; /* Textual representation of the tokens. */ @@ -268,6 +271,7 @@ static struct { { "subsystem", sSubsystem }, { "maxstartups", sMaxStartups }, { "banner", sBanner }, + { "reversemappingcheck", sReverseMappingCheck }, { NULL, 0 } }; @@ -577,6 +581,10 @@ parse_flag: intptr = &options->gateway_ports; goto parse_flag; + case sReverseMappingCheck: + intptr = &options->reverse_mapping_check; + goto parse_flag; + case sLogFacility: intptr = (int *) &options->log_facility; arg = strdelim(&cp); diff --git a/servconf.h b/servconf.h index e3163670..e7abb94d 100644 --- a/servconf.h +++ b/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.35 2001/01/22 23:06:40 markus Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.36 2001/02/03 10:08:37 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -102,6 +102,7 @@ typedef struct { int max_startups_rate; int max_startups; char *banner; /* SSH-2 banner message */ + int reverse_mapping_check; /* cross-check ip and dns */ } ServerOptions; /* diff --git a/session.c b/session.c index b6ab8873..51b661af 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.51 2001/01/21 19:05:56 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.52 2001/02/03 10:08:37 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -683,7 +683,7 @@ get_remote_name_or_ip(void) { static const char *remote = ""; if (utmp_len > 0) - remote = get_canonical_hostname(); + remote = get_canonical_hostname(options.reverse_mapping_check); if (utmp_len == 0 || strlen(remote) > utmp_len) remote = get_remote_ipaddr(); return remote; @@ -1061,7 +1061,7 @@ do_child(const char *command, struct passwd * pw, const char *term, #ifdef HAVE_OSF_SIA extern char **saved_argv; extern int saved_argc; - char *host = get_canonical_hostname (); + char *host = get_canonical_hostname(options.reverse_mapping_check); if (sia_become_user(NULL, saved_argc, saved_argv, host, pw->pw_name, ttyname, 0, NULL, NULL, SIA_BEU_SETLUID) != diff --git a/sftp-client.c b/sftp-client.c new file mode 100644 index 00000000..458d7364 --- /dev/null +++ b/sftp-client.c @@ -0,0 +1,792 @@ +/* + * 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.1 2001/02/04 11:11:54 djm 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 + +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 != 4) + 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("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) +{ + 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); + + 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(0); +} + +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 = arc4random(); + 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_ls(int fd_in, int fd_out, char *path) +{ + Buffer msg; + u_int type, id, handle_len, i, expected_id; + char *handle; + + id = arc4random(); + + 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); + + for(;;) { + int count; + + expected_id = ++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(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); + debug3("Received %i 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); + + printf("%s\n", longname); + + xfree(filename); + xfree(longname); + } + } + + buffer_free(&msg); + do_close(fd_in, fd_out, handle, handle_len); + xfree(handle); + + return(0); +} + +int +do_rm(int fd_in, int fd_out, char *path) +{ + u_int status, id; + + debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); + + id = arc4random(); + 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 = arc4random(); + 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 = arc4random(); + 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) +{ + u_int id; + + id = arc4random(); + send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); + return(get_decode_stat(fd_in, id)); +} + +Attrib * +do_lstat(int fd_in, int fd_out, char *path) +{ + u_int id; + + id = arc4random(); + send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); + return(get_decode_stat(fd_in, id)); +} + +Attrib * +do_fstat(int fd_in, int fd_out, char *handle, + u_int handle_len) +{ + u_int id; + + id = arc4random(); + send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); + return(get_decode_stat(fd_in, id)); +} + +int +do_setstat(int fd_in, int fd_out, char *path, Attrib *a) +{ + u_int status, id; + + id = arc4random(); + 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 = arc4random(); + 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 = arc4random(); + 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 = arc4random(); + 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_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; + + a = do_stat(fd_in, fd_out, remote_path); + 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; + + 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(errno); + } + + /* 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; + + tv.tv_sec = a->atime; + tv.tv_usec = a->mtime; + if (utimes(local_path, &tv) == -1) + error("Can't set times on \"%s\": %s", local_path, + strerror(errno)); + } + + buffer_init(&msg); + + /* Send open request */ + id = arc4random(); + 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; + + expected_id = ++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, 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) { + int 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); + xfree(handle); + close(local_fd); + buffer_free(&msg); + return(status); + } + } 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 %lld", len, 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); + xfree(handle); + close(local_fd); + xfree(data); + buffer_free(&msg); + return(-1); + } + + offset += len; + xfree(data); + } + xfree(handle); + buffer_free(&msg); + close(local_fd); + + return(do_close(fd_in, fd_out, handle, handle_len)); +} + +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; + + 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 = arc4random(); + 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); + } + + /* Override umask and utimes if asked */ + if (pflag) + do_fsetstat(fd_in, fd_out, handle, handle_len, &a); + + /* Read from local and write to remote */ + offset = 0; + for(;;) { + int len; + char data[COPY_SIZE]; + u_int status; + + /* + * 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, 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); + xfree(handle); + close(local_fd); + return(-1); + } + debug3("In write loop, got %d offset %lld", len, offset); + + offset += len; + } + xfree(handle); + buffer_free(&msg); + + 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); + return(-1); + } + + return(do_close(fd_in, fd_out, handle, handle_len)); +} diff --git a/sftp-client.h b/sftp-client.h new file mode 100644 index 00000000..838b46b0 --- /dev/null +++ b/sftp-client.h @@ -0,0 +1,84 @@ +/* $OpenBSD: sftp-client.h,v 1.1 2001/02/04 11:11:54 djm 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 */ + +/* Initialiase a SSH filexfer connection */ +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); + +/* 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); + +/* Get file attributes of 'path' (does not follow symlinks) */ +Attrib *do_lstat(int fd_in, int fd_out, char *path); + +/* Get file attributes of open file 'handle' */ +Attrib *do_fstat(int fd_in, int fd_out, char *handle, + u_int handle_len); + +/* 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); + +/* 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/sftp-common.c b/sftp-common.c new file mode 100644 index 00000000..aed9b339 --- /dev/null +++ b/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.1 2001/02/04 11:11:54 djm 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"); + 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/sftp-common.h b/sftp-common.h new file mode 100644 index 00000000..6dc1a32f --- /dev/null +++ b/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/sftp-int.c b/sftp-int.c new file mode 100644 index 00000000..f050c098 --- /dev/null +++ b/sftp-int.c @@ -0,0 +1,583 @@ +/* + * 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: finish implementation of all commands */ +/* XXX: do fnmatch() instead of using raw pathname */ +/* XXX: recursive operations */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-int.c,v 1.1 2001/02/04 11:11:54 djm Exp $"); + +#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" + +/* 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 + +struct CMD { + const int n; + const char *c; +}; + +const struct CMD cmds[] = { + { I_CHDIR, "CD" }, + { I_CHDIR, "CHDIR" }, + { I_CHDIR, "LCD" }, + { I_CHGRP, "CHGRP" }, + { I_CHMOD, "CHMOD" }, + { I_CHOWN, "CHOWN" }, + { I_HELP, "HELP" }, + { I_GET, "GET" }, + { I_LCHDIR, "LCHDIR" }, + { I_LLS, "LLS" }, + { I_LMKDIR, "LMKDIR" }, + { I_LPWD, "LPWD" }, + { I_LS, "LS" }, + { I_LUMASK, "LUMASK" }, + { I_MKDIR, "MKDIR" }, + { I_PUT, "PUT" }, + { I_PWD, "PWD" }, + { I_QUIT, "EXIT" }, + { I_QUIT, "QUIT" }, + { I_RENAME, "RENAME" }, + { I_RMDIR, "RMDIR" }, + { I_RM, "RM" }, + { I_SHELL, "!" }, + { -1, NULL} +}; + +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("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("!command Execute 'command' in local shell\n"); + printf("! Escape to local shell\n"); +} + +void +local_do_shell(const char *args) +{ + int ret, 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); + ret = execl(shell, shell, "-c", args, NULL); + } else { + debug3("Executing %s", shell); + ret = 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("ls"); + else { + char *buf = xmalloc(8 + strlen(args) + 1); + + /* XXX: quoting - rip quoting code from ftp? */ + sprintf(buf, "/bin/ls %s", args); + local_do_shell(buf); + } +} + +char * +make_absolute(char *p, char *pwd) +{ + char buf[2048]; + + /* Derelativise */ + if (p && p[0] != '/') { + snprintf(buf, sizeof(buf), "%s/%s", pwd, p); + xfree(p); + p = xstrdup(buf); + } + + return(p); +} + +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) { + case 'P': + *pflag = 1; + break; + default: + error("Invalid flag -%c", *cp); + return(-1); + } + cp += 2; + *cpp = cp + strspn(cp, WHITESPACE); + } + + return(0); +} + +int +get_pathname(const char **cpp, char **path) +{ + const char *quot, *cp = *cpp; + int i; + + cp += strspn(cp, WHITESPACE); + if (!*cp) { + *cpp = cp; + *path = NULL; + return(0); + } + + /* Check for quoted filenames */ + if (*cp == '\"' || *cp == '\'') { + quot = cp++; + for(i = 0; cp[i] && cp[i] != *quot; i++) + ; + if (!cp[i]) { + error("Unterminated quote"); + *path = NULL; + return(-1); + } + if (i == 0) { + error("Empty quotes"); + *path = NULL; + return(-1); + } + *path = xmalloc(i + 1); + memcpy(*path, cp, i); + (*path)[i] = '\0'; + cp += i + 1; + *cpp = cp + strspn(cp, WHITESPACE); + return(0); + } + + /* Read to end of filename */ + for(i = 0; cp[i] && cp[i] != ' '; i++) + ; + + *path = xmalloc(i + 1); + memcpy(*path, cp, i); + (*path)[i] = '\0'; + cp += i; + *cpp = cp + strspn(cp, WHITESPACE); + + return(0); +} + +int +infer_path(const char *p, char **ifp) +{ + char *cp; + + debug("XXX: P = \"%s\"", p); + + 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_args(const char **cpp, int *pflag, unsigned long *n_arg, + char **path1, char **path2) +{ + const char *cmd, *cp = *cpp; + 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); + /* Otherwise try to guess it from first path */ + if (*path2 == NULL && infer_path(*path1, path2)) + return(-1); + break; + case I_RENAME: + /* Get first pathname (mandatory) */ + 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: + case I_CHMOD: + case I_CHOWN: + case I_CHGRP: + /* Get numeric arg (mandatory) */ + if (*cp < '0' && *cp > '9') { + error("You must supply a numeric argument " + "to the %s command.", cmd); + return(-1); + } + *n_arg = strtoul(cp, (char**)&cp, 0); + if (!*cp || !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: + 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; + int pflag, cmdnum; + unsigned long n_arg; + Attrib a, *aa; + char path_buf[PATH_MAX]; + + path1 = path2 = NULL; + cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); + + /* Perform command */ + switch (cmdnum) { + case -1: + break; + case I_GET: + path1 = make_absolute(path1, *pwd); + do_download(in, out, path1, path2, pflag); + break; + case I_PUT: + path2 = make_absolute(path2, *pwd); + do_upload(in, out, path1, path2, pflag); + break; + case I_RENAME: + path1 = make_absolute(path1, *pwd); + path2 = make_absolute(path2, *pwd); + do_rename(in, out, path1, path2); + break; + case I_RM: + path1 = make_absolute(path1, *pwd); + do_rm(in, out, path1); + break; + case I_MKDIR: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = 0777; + do_mkdir(in, out, path1, &a); + break; + case I_RMDIR: + path1 = make_absolute(path1, *pwd); + do_rmdir(in, out, path1); + break; + case I_CHDIR: + path1 = make_absolute(path1, *pwd); + xfree(*pwd); + *pwd = do_realpath(in, out, path1); + break; + case I_LS: + path1 = make_absolute(path1, *pwd); + do_ls(in, out, path1?path1:*pwd); + break; + case I_LCHDIR: + if (chdir(path1) == -1) + error("Couldn't change local directory to " + "\"%s\": %s", path1, strerror(errno)); + break; + case I_LMKDIR: + if (mkdir(path1, 0777) == -1) + error("Couldn't create local directory to " + "\"%s\": %s", path1, strerror(errno)); + break; + case I_LLS: + local_do_ls(cmd); + break; + case I_SHELL: + local_do_shell(cmd); + break; + case I_LUMASK: + umask(n_arg); + break; + case I_CHMOD: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = n_arg; + do_setstat(in, out, path1, &a); + case I_CHOWN: + path1 = make_absolute(path1, *pwd); + aa = do_stat(in, out, path1); + if (!aa->flags & SSH2_FILEXFER_ATTR_UIDGID) { + error("Can't get current ownership of " + "remote file \"%s\"", path1); + break; + } + aa->uid = n_arg; + do_setstat(in, out, path1, aa); + break; + case I_CHGRP: + path1 = make_absolute(path1, *pwd); + aa = do_stat(in, out, path1); + if (!aa->flags & SSH2_FILEXFER_ATTR_UIDGID) { + error("Can't get current ownership of " + "remote file \"%s\"", path1); + break; + } + aa->gid = n_arg; + do_setstat(in, out, path1, 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\n", + strerror(errno)); + else + printf("Local working directory: %s\n", + path_buf); + break; + case I_QUIT: + return(-1); + case I_HELP: + help(); + break; + default: + fatal("%d is not implemented", cmdnum); + } + + if (path1) + xfree(path1); + if (path2) + xfree(path2); + + return(0); +} + +void +interactive_loop(int fd_in, int fd_out) +{ + char *pwd; + char cmd[2048]; + + pwd = do_realpath(fd_in, fd_out, "."); + if (pwd == NULL) + fatal("Need cwd"); + + setlinebuf(stdout); + setlinebuf(stdin); + + for(;;) { + char *cp; + + printf("sftp> "); + + /* XXX: use libedit */ + if (fgets(cmd, sizeof(cmd), stdin) == NULL) { + printf("\n"); + break; + } + cp = strrchr(cmd, '\n'); + if (cp) + *cp = '\0'; + if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd)) + break; + } + xfree(pwd); +} diff --git a/sftp-int.h b/sftp-int.h new file mode 100644 index 00000000..234d8003 --- /dev/null +++ b/sftp-int.h @@ -0,0 +1,27 @@ +/* $OpenBSD: sftp-int.h,v 1.1 2001/02/04 11:11:54 djm 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); diff --git a/sftp-server.c b/sftp-server.c index a3e11ce5..0e004009 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.14 2001/01/21 19:05:56 markus Exp $"); +RCSID("$OpenBSD: sftp-server.c,v 1.15 2001/02/04 11:11:54 djm Exp $"); #include "buffer.h" #include "bufaux.h" @@ -31,6 +31,7 @@ RCSID("$OpenBSD: sftp-server.c,v 1.14 2001/01/21 19:05:56 markus Exp $"); #include "xmalloc.h" #include "sftp.h" +#include "sftp-common.h" /* helper */ #define get_int64() buffer_get_int64(&iqueue); @@ -50,22 +51,9 @@ Buffer oqueue; /* portable attibutes, etc. */ -typedef struct Attrib Attrib; typedef struct Stat Stat; -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; -}; - -struct Stat -{ +struct Stat { char *name; char *long_name; Attrib attrib; @@ -122,90 +110,6 @@ flags_from_portable(int pflags) return flags; } -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; -} - -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); - 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); - } -} - -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 * get_attrib(void) { diff --git a/sftp.1 b/sftp.1 new file mode 100644 index 00000000..59206b65 --- /dev/null +++ b/sftp.1 @@ -0,0 +1,156 @@ +.\" $OpenBSD: sftp.1,v 1.1 2001/02/04 11:11:54 djm 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 Febuary 4, 2001 +.Dt SFTP 1 +.Os +.Sh NAME +.Nm sftp +.Nd Secure file tranfer program +.Sh SYNOPSIS +.Nm sftp +.Op Fl v Li | Fl C +.Op Fl o Ar ssh_option +.Op Ar hostname | user@hostname +.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 options are as follows: +.Bl -tag -width Ds +.It Fl C +Enables compression (via ssh's +.Fl C +flag) +.It Fl v +Raise logging level. This option is also passed to ssh. +.It Fl o Ar ssh_option +Specify an option to be directly passed to +.Xr ssh 1 . +.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. +.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 numeric. +.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 HELP +Display help text +.It Ic GET Ar remote-file Op Ar local-file +Retrieve the +.Ar remote-file +and store it on the local machine. +If the local +file name is not specified, it is given the same name it has on the +remote machine. +.It Ic LLS Op Ar ls-options Op Ar path +Display local directory listing of either +.Ar path +or current directory if +.Ar path +was not specified. +.It Ic LMKDIR Ar path +Create local directory specified by +.Ar path +.It Ic LPWD +Print local working directory +.It Ic LS Op Ar path +Display remote directory listing of either +.Ar path +or current directory, is +.Ar path 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 Ic PUT local-file Op Ar remote-file +Upload +.Ar local-file +and store it on the remote machine. If the local file name is not specified, +it is given the same name it has on the local machine. +.It Ic PWD +Display remote working directory +.It Ic EXIT +Quit sftp +.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 ! Ar command +Execute +.Ar command +in local shell +.It Ic ! +Escape to local shell +.Sh AUTHORS +Damien Miller +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-keygen 1 , +.Xr sshd 8 diff --git a/sftp.c b/sftp.c new file mode 100644 index 00000000..0dca12d8 --- /dev/null +++ b/sftp.c @@ -0,0 +1,222 @@ +/* + * 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.1 2001/02/04 11:11:54 djm Exp $"); + +/* XXX: commandline mode */ +/* XXX: copy between two remote hosts (commandline) */ +/* 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" + +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(_PATH_SSH_PROGRAM, args); + fprintf(stderr, "exec: %s", 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 = 4; + i = 0; + args = xmalloc(sizeof(*args) * nargs); + args[i++] = "ssh"; + args[i++] = "-oProtocol=2"; + args[i++] = "-s"; + 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); + } + + /* Otherwise finish up and return the arg array */ + 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 [-vC] [-osshopt=value] [user@]host\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + int in, out, i, debug_level, compress_flag; + pid_t sshpid; + char *cp; + LogLevel ll; + + debug_level = compress_flag = 0; + for(i = 1; i < argc && argv[i][0] == '-'; i++) { + if (!strcmp(argv[i], "-v")) + debug_level = MIN(3, debug_level + 1); + else if (!strcmp(argv[i], "-C")) + compress_flag = 1; + else if (!strncmp(argv[i], "-o", 2)) { + make_ssh_args(argv[i]); + } else { + fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); + usage(); + } + } + + if (i == argc || argc > (i + 1)) + usage(); + + if ((cp = strchr(argv[i], '@')) == NULL) + cp = argv[i]; + else { + *cp = '\0'; + if (!argv[i][0]) { + fprintf(stderr, "Missing username\n"); + usage(); + } + make_ssh_args("-l"); + make_ssh_args(argv[i]); + cp++; + } + + if (!*cp) { + 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(cp); + + fprintf(stderr, "Connecting to %s...\n", cp); + + connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); + + do_init(in, out); + + interactive_loop(in, out); + + close(in); + close(out); + + if (kill(sshpid, SIGHUP) == -1) + fatal("Couldn't terminate ssh process: %s", strerror(errno)); + + /* XXX: wait? */ + + exit(0); +} diff --git a/ssh.1 b/ssh.1 index 6f10436a..99fb8c7c 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.80 2001/01/29 12:36:10 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.83 2001/02/04 11:11:55 djm Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -753,8 +753,8 @@ Specifies a file to use instead of .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key -the kown_hosts files. -This option is useful for tunneling ssh connection +in the known_hosts files. +This option is useful for tunneling ssh connections or if you have multiple servers running on a single host. .It Cm HostName Specifies the real host name to log into. @@ -914,8 +914,9 @@ RSA authentication will only be attempted if the identity file exists, or an authentication agent is running. Note that this option applies to protocol version 1 only. -.It Cm SkeyAuthentication -Specifies whether to use +.It Cm ChallengeResponseAuthentication +Specifies whether to use challenge response authentication. +Currently there is only support for .Xr skey 1 authentication. The argument to this keyword must be @@ -1270,6 +1271,7 @@ protocol versions 1.5 and 2.0. .Xr rlogin 1 , .Xr rsh 1 , .Xr scp 1 , +.Xr sftp 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , .Xr ssh-keygen 1 , diff --git a/ssh_config b/ssh_config index e7dabbf5..cfaf2313 100644 --- a/ssh_config +++ b/ssh_config @@ -1,8 +1,8 @@ -# $OpenBSD: ssh_config,v 1.7 2001/01/29 01:58:18 niklas Exp $ +# $OpenBSD: ssh_config,v 1.8 2001/02/02 12:57:51 deraadt Exp $ -# This is ssh client systemwide configuration file. This file provides -# defaults for users, and the values can be changed in per-user configuration -# files or on the command line. +# This is ssh client systemwide configuration file. See ssh(1) for more +# information. This file provides defaults for users, and the values can +# be changed in per-user configuration files or on the command line. # Configuration data is parsed as follows: # 1. command line options diff --git a/sshconnect1.c b/sshconnect1.c index e732806f..80b769b4 100644 --- a/sshconnect1.c +++ b/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.21 2001/01/29 19:47:31 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.22 2001/02/03 10:08:37 markus Exp $"); #include #include @@ -399,11 +399,11 @@ try_kerberos_authentication() if (stat(tkt_string(), &st) < 0) return 0; - strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); + strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ); - realm = (char *) krb_realmofhost(get_canonical_hostname()); + realm = (char *) krb_realmofhost(get_canonical_hostname(1)); if (!realm) { - debug("Kerberos V4: no realm for %s", get_canonical_hostname()); + debug("Kerberos V4: no realm for %s", get_canonical_hostname(1)); return 0; } /* This can really be anything. */ diff --git a/sshd.8 b/sshd.8 index 1aad0fc8..c71ecb2a 100644 --- a/sshd.8 +++ b/sshd.8 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.86 2001/01/28 20:43:25 stevesk Exp $ +.\" $OpenBSD: sshd.8,v 1.90 2001/02/04 11:11:55 djm Exp $ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -593,6 +593,14 @@ The default is .It Cm RandomSeed Obsolete. Random number generation uses other techniques. +.It Cm ReverseMappingCheck +Specifies whether +.Nm +should try to verify the remote host name and check that +the resolved host name for the remote IP address maps back to the +very same IP address. +The default is +.Dq no . .It Cm RhostsAuthentication Specifies whether authentication using rhosts or /etc/hosts.equiv files is sufficient. @@ -616,15 +624,15 @@ Note that this option applies to protocol version 1 only. .It Cm ServerKeyBits Defines the number of bits in the server key. The minimum value is 512, and the default is 768. -.It Cm SkeyAuthentication +.It Cm ChallengeResponseAuthentication Specifies whether -.Xr skey 1 +challenge reponse authentication is allowed. +Currently there is only support for +.Xr skey 1 +authentication. The default is .Dq yes . -Note that s/key authentication is enabled only if -.Cm PasswordAuthentication -is allowed, too. .It Cm StrictModes Specifies whether .Nm @@ -797,6 +805,9 @@ authentication. The command supplied by the user (if any) is ignored. The command is run on a pty if the connection requests a pty; otherwise it is run without a tty. +Note that if you want a 8-bit clean channel, +you must not request a pty or should specify +.Cm no-pty . A quote may be included in the command by quoting it with a backslash. This option might be useful to restrict certain RSA keys to perform just a specific operation. @@ -1076,6 +1087,7 @@ Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. .Sh SEE ALSO .Xr scp 1 , +.Xr sftp 1 , .Xr sftp-server 8 , .Xr ssh 1 , .Xr ssh-add 1 , diff --git a/sshd_config b/sshd_config index 25c0ec3f..9ba1789a 100644 --- a/sshd_config +++ b/sshd_config @@ -1,6 +1,7 @@ -# $OpenBSD: sshd_config,v 1.27 2001/01/29 01:58:19 niklas Exp $ +# $OpenBSD: sshd_config,v 1.30 2001/02/03 10:19:51 markus Exp $ -# This is ssh server systemwide configuration file. +# This is the sshd server system-wide configuration file. See sshd(8) +# for more information. Port 22 #Protocol 2,1 @@ -39,9 +40,9 @@ RSAAuthentication yes # To disable tunneled clear text passwords, change to no here! PasswordAuthentication yes PermitEmptyPasswords no + # Uncomment to disable s/key passwords -#SkeyAuthentication no -#KbdInteractiveAuthentication yes +#ChallengeResposeAuthentication no # To change Kerberos options #KerberosAuthentication no @@ -59,3 +60,4 @@ PermitEmptyPasswords no #Subsystem sftp /usr/libexec/sftp-server #MaxStartups 10:30:60 #Banner /etc/issue.net +#ReverseMappingCheck yes -- 2.45.2