diff --git a/crypto/openssh/ChangeLog b/crypto/openssh/ChangeLog index 30b8ef2cc359..67cd6caba29e 100644 --- a/crypto/openssh/ChangeLog +++ b/crypto/openssh/ChangeLog @@ -1,1007 +1,1170 @@ +20020626 + - (stevesk) [monitor.c] remove duplicate proto15 dispatch entry for PAM + - (bal) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2002/06/23 21:34:07 + [channels.c] + tcode is u_int + - markus@cvs.openbsd.org 2002/06/24 13:12:23 + [ssh-agent.1] + the socket name contains ssh-agent's ppid; via mpech@ from form@ + - markus@cvs.openbsd.org 2002/06/24 14:33:27 + [channels.c channels.h clientloop.c serverloop.c] + move channel counter to u_int + - markus@cvs.openbsd.org 2002/06/24 14:55:38 + [authfile.c kex.c ssh-agent.c] + cat to (void) when output from buffer_get_X is ignored + - itojun@cvs.openbsd.org 2002/06/24 15:49:22 + [msg.c] + printf type pedant + - deraadt@cvs.openbsd.org 2002/06/24 17:57:20 + [sftp-server.c sshpty.c] + explicit (u_int) for uid and gid + - markus@cvs.openbsd.org 2002/06/25 16:22:42 + [authfd.c] + unnecessary cast + - markus@cvs.openbsd.org 2002/06/25 18:51:04 + [sshd.c] + lightweight do_setusercontext after chroot() + - (bal) Updated AIX package build. Patch by dtucker@zip.com.au + - (tim) [Makefile.in] fix test on installing ssh-rand-helper.8 + - (bal) added back in error check for mmap(). I screwed up, Pointed + out by stevesk@ + - (tim) [README.privsep] UnixWare tip no longer needed. + - (bal) fixed NeXTStep missing munmap() issue. It defines HAVE_MMAP, + but it all damned lies. + - (stevesk) [README.privsep] more for sshd pseudo-account. + - (tim) [contrib/caldera/openssh.spec] add support for privsep + - (djm) setlogin needs pgid==pid on BSD/OS; from itojun@ + - (djm) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2002/06/26 08:53:12 + [bufaux.c] + limit size of BNs to 8KB; ok provos/deraadt + - markus@cvs.openbsd.org 2002/06/26 08:54:18 + [buffer.c] + limit append to 1MB and buffers to 10MB + - markus@cvs.openbsd.org 2002/06/26 08:55:02 + [channels.c] + limit # of channels to 10000 + - markus@cvs.openbsd.org 2002/06/26 08:58:26 + [session.c] + limit # of env vars to 1000; ok deraadt/djm + - deraadt@cvs.openbsd.org 2002/06/26 13:20:57 + [monitor.c] + be careful in mm_zalloc + - deraadt@cvs.openbsd.org 2002/06/26 13:49:26 + [session.c] + disclose less information from environment files; based on input + from djm, and dschultz@uclink.Berkeley.EDU + - markus@cvs.openbsd.org 2002/06/26 13:55:37 + [auth2-chall.c] + make sure # of response matches # of queries, fixes int overflow; + from ISS + - markus@cvs.openbsd.org 2002/06/26 13:56:27 + [version.h] + 3.4 + - (djm) Require krb5 devel for RPM build w/ KrbV + - (djm) Improve PAMAuthenticationViaKbdInt text from Nalin Dahyabhai + + - (djm) Update spec files for release + - (djm) Fix int overflow in auth2-pam.c, similar to one discovered by ISS + - (djm) Release 3.4p1 + +20020625 + - (stevesk) [INSTALL acconfig.h configure.ac defines.h] remove --with-rsh + - (stevesk) [README.privsep] minor updates + - (djm) Create privsep directory and warn if privsep user is missing + during make install + - (bal) Started list of PrivSep issues in TODO + - (bal) if mmap() is substandard, don't allow compression on server side. + Post 'event' we will add more options. + - (tim) [contrib/caldera/openssh.spec] Sync with Caldera + - (bal) moved aix_usrinfo() and noted not setting real TTY. Patch by + dtucker@zip.com.au + - (tim) [acconfig.h configure.ac sshd.c] BROKEN_FD_PASSING fix from Markus + for Cygwin, Cray, & SCO + +20020624 + - OpenBSD CVS Sync + - deraadt@cvs.openbsd.org 2002/06/23 03:25:50 + [tildexpand.c] + KNF + - deraadt@cvs.openbsd.org 2002/06/23 03:26:19 + [cipher.c key.c] + KNF + - deraadt@cvs.openbsd.org 2002/06/23 03:30:58 + [scard.c ssh-dss.c ssh-rsa.c sshconnect.c sshconnect2.c sshd.c sshlogin.c + sshpty.c] + various KNF and %d for unsigned + - deraadt@cvs.openbsd.org 2002/06/23 09:30:14 + [sftp-client.c sftp-client.h sftp-common.c sftp-int.c sftp-server.c + sftp.c] + bunch of u_int vs int stuff + - deraadt@cvs.openbsd.org 2002/06/23 09:39:55 + [ssh-keygen.c] + u_int stuff + - deraadt@cvs.openbsd.org 2002/06/23 09:46:51 + [bufaux.c servconf.c] + minor KNF. things the fingers do while you read + - deraadt@cvs.openbsd.org 2002/06/23 10:29:52 + [ssh-agent.c sshd.c] + some minor KNF and %u + - deraadt@cvs.openbsd.org 2002/06/23 20:39:45 + [session.c] + compression_level is u_int + - deraadt@cvs.openbsd.org 2002/06/23 21:06:13 + [sshpty.c] + KNF + - deraadt@cvs.openbsd.org 2002/06/23 21:06:41 + [channels.c channels.h session.c session.h] + display, screen, row, col, xpixel, ypixel are u_int; markus ok + - deraadt@cvs.openbsd.org 2002/06/23 21:10:02 + [packet.c] + packet_get_int() returns unsigned for reason & seqnr + - (bal) Also fixed IPADDR_IN_DISPLAY case where display, screen, row, col, + xpixel are u_int. + + +20020623 + - (stevesk) [configure.ac] bug #255 LOGIN_NEEDS_UTMPX for AIX. + - (bal) removed GNUism for getops in ssh-agent since glibc lacks optreset. + - (bal) add extern char *getopt. Based on report by dtucker@zip.com.au + - OpenBSD CVS Sync + - stevesk@cvs.openbsd.org 2002/06/22 02:00:29 + [ssh.h] + correct comment + - stevesk@cvs.openbsd.org 2002/06/22 02:40:23 + [ssh.1] + section 5 not 4 for ssh_config + - naddy@cvs.openbsd.org 2002/06/22 11:51:39 + [ssh.1] + typo + - stevesk@cvs.openbsd.org 2002/06/22 16:32:54 + [sshd.8] + add /var/empty in FILES section + - stevesk@cvs.openbsd.org 2002/06/22 16:40:19 + [sshd.c] + check /var/empty owner mode; ok provos@ + - stevesk@cvs.openbsd.org 2002/06/22 16:41:57 + [scp.1] + typo + - stevesk@cvs.openbsd.org 2002/06/22 16:45:29 + [ssh-agent.1 sshd.8 sshd_config.5] + use process ID vs. pid/PID/process identifier + - stevesk@cvs.openbsd.org 2002/06/22 20:05:27 + [sshd.c] + don't call setsid() if debugging or run from inetd; no "Operation not + permitted" errors now; ok millert@ markus@ + - stevesk@cvs.openbsd.org 2002/06/22 23:09:51 + [monitor.c] + save auth method before monitor_reset_key_state(); bugzilla bug #284; + ok provos@ + 20020622 - (djm) Update README.privsep; spotted by fries@ - (djm) Release 3.3p1 + - (bal) getopt now can be staticly compiled on those platforms missing + optreset. Patch by binder@arago.de 20020621 - (djm) Sync: - djm@cvs.openbsd.org 2002/06/21 05:50:51 [monitor.c] Don't initialise compression buffers when compression=no in sshd_config; ok Niels@ - ID sync for auth-passwd.c - (djm) Warn and disable compression on platforms which can't handle both useprivilegeseparation=yes and compression=yes - (djm) contrib/redhat/openssh.spec hacking: - Merge in spec changes from seba@iq.pl (Sebastian Pachuta) - Add new {ssh,sshd}_config.5 manpages - Add new ssh-keysign program and remove setuid from ssh client 20020620 - (bal) Fixed AIX environment handling, use setpcred() instead of existing code. (Bugzilla Bug 261) - (bal) OpenBSD CVS Sync - todd@cvs.openbsd.org 2002/06/14 21:35:00 [monitor_wrap.c] spelling; from Brian Poole - markus@cvs.openbsd.org 2002/06/15 00:01:36 [authfd.c authfd.h ssh-add.c ssh-agent.c] break agent key lifetime protocol and allow other contraints for key usage. - markus@cvs.openbsd.org 2002/06/15 00:07:38 [authfd.c authfd.h ssh-add.c ssh-agent.c] fix stupid typo - markus@cvs.openbsd.org 2002/06/15 01:27:48 [authfd.c authfd.h ssh-add.c ssh-agent.c] remove the CONSTRAIN_IDENTITY messages and introduce a new ADD_ID message with contraints instead. contraints can be only added together with the private key. - itojun@cvs.openbsd.org 2002/06/16 21:30:58 [ssh-keyscan.c] use TAILQ_xx macro. from lukem@netbsd. markus ok - deraadt@cvs.openbsd.org 2002/06/17 06:05:56 [scp.c] make usage like man page - deraadt@cvs.openbsd.org 2002/06/19 00:27:55 [auth-bsdauth.c auth-skey.c auth1.c auth2-chall.c auth2-none.c authfd.c authfd.h monitor_wrap.c msg.c nchan.c radix.c readconf.c scp.c sftp.1 ssh-add.1 ssh-add.c ssh-agent.1 ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh-keysign.c ssh.1 sshconnect.c sshconnect.h sshconnect2.c ttymodes.c xmalloc.h] KNF done automatically while reading.... - markus@cvs.openbsd.org 2002/06/19 18:01:00 [cipher.c monitor.c monitor_wrap.c packet.c packet.h] make the monitor sync the transfer ssh1 session key; transfer keycontext only for RC4 (this is still depends on EVP implementation details and is broken). - stevesk@cvs.openbsd.org 2002/06/20 19:56:07 [ssh.1 sshd.8] move configuration file options from ssh.1/sshd.8 to ssh_config.5/sshd_config.5; ok deraadt@ millert@ - stevesk@cvs.openbsd.org 2002/06/20 20:00:05 [scp.1 sftp.1] ssh_config(5) - stevesk@cvs.openbsd.org 2002/06/20 20:03:34 [ssh_config sshd_config] refer to config file man page - markus@cvs.openbsd.org 2002/06/20 23:05:56 [servconf.c servconf.h session.c sshd.c] allow Compression=yes/no in sshd_config - markus@cvs.openbsd.org 2002/06/20 23:37:12 [sshd_config] add Compression - stevesk@cvs.openbsd.org 2002/05/25 20:40:08 [LICENCE] missed Per Allansson (auth2-chall.c) - (bal) Cygwin special handling of empty passwords wrong. Patch by vinschen@redhat.com - (bal) Missed integrating ssh_config.5 and sshd_config.5 - (bal) Still more Makefile.in updates for ssh{d}_config.5 20020613 - (bal) typo of setgroup for cygwin. Patch by vinschen@redhat.com 20020612 - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/06/11 23:03:54 [ssh.c] remove unused cruft. - markus@cvs.openbsd.org 2002/06/12 01:09:52 [ssh.c] ssh_connect returns 0 on success - (bal) Build noop setgroups() for cygwin to clean up code (For other platforms without the setgroups() requirement, you MUST define SETGROUPS_NOOP in the configure.ac) Based on patch by vinschen@redhat.com - (bal) Some platforms don't have ONLCR (Notable Mint) 20020611 - (bal) ssh-agent.c RCSD fix (|unexpand already done) - (bal) OpenBSD CVS Sync - stevesk@cvs.openbsd.org 2002/06/09 22:15:15 [ssh.1] update for no setuid root and ssh-keysign; ok deraadt@ - itojun@cvs.openbsd.org 2002/06/09 22:17:21 [sshconnect.c] pass salen to sockaddr_ntop so that we are happy on linux/solaris - stevesk@cvs.openbsd.org 2002/06/10 16:53:06 [auth-rsa.c ssh-rsa.c] display minimum RSA modulus in error(); ok markus@ - stevesk@cvs.openbsd.org 2002/06/10 16:56:30 [ssh-keysign.8] merge in stuff from my man page; ok markus@ - stevesk@cvs.openbsd.org 2002/06/10 17:36:23 [ssh-add.1 ssh-add.c] use convtime() to parse and validate key lifetime. can now use '-t 2h' etc. ok markus@ provos@ - stevesk@cvs.openbsd.org 2002/06/10 17:45:20 [readconf.c ssh.1] change RhostsRSAAuthentication and RhostsAuthentication default to no since ssh is no longer setuid root by default; ok markus@ - stevesk@cvs.openbsd.org 2002/06/10 21:21:10 [ssh_config] update defaults for RhostsRSAAuthentication and RhostsAuthentication here too (all options commented out with default value). - markus@cvs.openbsd.org 2002/06/10 22:28:41 [channels.c channels.h session.c] move creation of agent socket to session.c; no need for uidswapping in channel.c. - markus@cvs.openbsd.org 2002/06/11 04:14:26 [ssh.c sshconnect.c sshconnect.h] no longer use uidswap.[ch] from the ssh client run less code with euid==0 if ssh is installed setuid root just switch the euid, don't switch the complete set of groups (this is only needed by sshd). ok provos@ - mpech@cvs.openbsd.org 2002/06/11 05:46:20 [auth-krb4.c monitor.h serverloop.c session.c ssh-agent.c sshd.c] pid_t cleanup. Markus need this now to keep hacking. markus@, millert@ ok - itojun@cvs.openbsd.org 2002/06/11 08:11:45 [canohost.c] use "ntop" only after initialized - (bal) Cygwin fix up from swap uid clean up in ssh.c patch by vinschen@redhat.com 20020609 - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/06/08 05:07:56 [ssh.c] nuke ptrace comment - markus@cvs.openbsd.org 2002/06/08 05:07:09 [ssh-keysign.c] only accept 20 byte session ids - markus@cvs.openbsd.org 2002/06/08 05:17:01 [readconf.c readconf.h ssh.1 ssh.c] deprecate FallBackToRsh and UseRsh; patch from djm@ - markus@cvs.openbsd.org 2002/06/08 05:40:01 [readconf.c] just warn about Deprecated options for now - markus@cvs.openbsd.org 2002/06/08 05:41:18 [ssh_config] remove FallBackToRsh/UseRsh - markus@cvs.openbsd.org 2002/06/08 12:36:53 [scp.c] remove FallBackToRsh - markus@cvs.openbsd.org 2002/06/08 12:46:14 [readconf.c] silently ignore deprecated options, since FallBackToRsh might be passed by remote scp commands. - itojun@cvs.openbsd.org 2002/06/08 21:15:27 [sshconnect.c] always use getnameinfo. (diag message only) - markus@cvs.openbsd.org 2002/06/09 04:33:27 [sshconnect.c] abort() - > fatal() - (bal) RCSID tag updates on channels.c, clientloop.c, nchan.c, sftp-client.c, ssh-agenet.c, ssh-keygen.c and connect.h (we did unexpand independant of them) 20020607 - (bal) Removed --{enable/disable}-suid-ssh - (bal) Missed __progname in ssh-keysign.c patch by dtucker@zip.com.au - (bal) use 'LOGIN_PROGRAM' not '/usr/bin/login' in session.c patch by Bertrand.Velle@apogee-com.fr 20020606 - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/05/15 21:56:38 [servconf.c sshd.8 sshd_config] re-enable privsep and disable setuid for post-3.2.2 - markus@cvs.openbsd.org 2002/05/16 22:02:50 [cipher.c kex.h mac.c] fix warnings (openssl 0.9.7 requires const) - stevesk@cvs.openbsd.org 2002/05/16 22:09:59 [session.c ssh.c] don't limit xauth pathlen on client side and longer print length on server when debug; ok markus@ - deraadt@cvs.openbsd.org 2002/05/19 20:54:52 [log.h] extra commas in enum not 100% portable - deraadt@cvs.openbsd.org 2002/05/22 23:18:25 [ssh.c sshd.c] spelling; abishoff@arc.nasa.gov - markus@cvs.openbsd.org 2002/05/23 19:24:30 [authfile.c authfile.h pathnames.h ssh.c sshconnect.c sshconnect.h sshconnect1.c sshconnect2.c ssh-keysign.8 ssh-keysign.c Makefile.in] add /usr/libexec/ssh-keysign: a setuid helper program for hostbased authentication in protocol v2 (needs to access the hostkeys). - markus@cvs.openbsd.org 2002/05/23 19:39:34 [ssh.c] add comment about ssh-keysign - markus@cvs.openbsd.org 2002/05/24 08:45:14 [sshconnect2.c] stat ssh-keysign first, print error if stat fails; some debug->error; fix comment - markus@cvs.openbsd.org 2002/05/25 08:50:39 [sshconnect2.c] execlp->execl; from stevesk - markus@cvs.openbsd.org 2002/05/25 18:51:07 [auth.h auth2.c auth2-hostbased.c auth2-kbdint.c auth2-none.c auth2-passwd.c auth2-pubkey.c Makefile.in] split auth2.c into one file per method; ok provos@/deraadt@ - stevesk@cvs.openbsd.org 2002/05/26 20:35:10 [ssh.1] sort ChallengeResponseAuthentication; ok markus@ - stevesk@cvs.openbsd.org 2002/05/28 16:45:27 [monitor_mm.c] print strerror(errno) on mmap/munmap error; ok markus@ - stevesk@cvs.openbsd.org 2002/05/28 17:28:02 [uidswap.c] format spec change/casts and some KNF; ok markus@ - stevesk@cvs.openbsd.org 2002/05/28 21:24:00 [uidswap.c] use correct function name in fatal() - stevesk@cvs.openbsd.org 2002/05/29 03:06:30 [ssh.1 sshd.8] spelling - markus@cvs.openbsd.org 2002/05/29 11:21:57 [sshd.c] don't start if privsep is enabled and SSH_PRIVSEP_USER or _PATH_PRIVSEP_CHROOT_DIR are missing; ok deraadt@ - markus@cvs.openbsd.org 2002/05/30 08:07:31 [cipher.c] use rijndael/aes from libcrypto (openssl >= 0.9.7) instead of our own implementation. allow use of AES hardware via libcrypto, ok deraadt@ - markus@cvs.openbsd.org 2002/05/31 10:30:33 [sshconnect2.c] extent ssh-keysign protocol: pass # of socket-fd to ssh-keysign, keysign verfies locally used ip-address using this socket-fd, restricts fake local hostnames to actual local hostnames; ok stevesk@ - markus@cvs.openbsd.org 2002/05/31 11:35:15 [auth.h auth2.c] move Authmethod definitons to per-method file. - markus@cvs.openbsd.org 2002/05/31 13:16:48 [key.c] add comment: key_verify returns 1 for a correct signature, 0 for an incorrect signature and -1 on error. - markus@cvs.openbsd.org 2002/05/31 13:20:50 [ssh-rsa.c] pad received signature with leading zeros, because RSA_verify expects a signature of RSA_size. the drafts says the signature is transmitted unpadded (e.g. putty does not pad), reported by anakin@pobox.com - deraadt@cvs.openbsd.org 2002/06/03 12:04:07 [ssh.h] compatiblity -> compatibility decriptor -> descriptor authentciated -> authenticated transmition -> transmission - markus@cvs.openbsd.org 2002/06/04 19:42:35 [monitor.c] only allow enabled authentication methods; ok provos@ - markus@cvs.openbsd.org 2002/06/04 19:53:40 [monitor.c] save the session id (hash) for ssh2 (it will be passed with the initial sign request) and verify that this value is used during authentication; ok provos@ - markus@cvs.openbsd.org 2002/06/04 23:02:06 [packet.c] remove __FUNCTION__ - markus@cvs.openbsd.org 2002/06/04 23:05:49 [cipher.c monitor.c monitor_fdpass.c monitor_mm.c monitor_wrap.c] __FUNCTION__ -> __func__ - markus@cvs.openbsd.org 2002/06/05 16:08:07 [ssh-agent.1 ssh-agent.c] '-a bind_address' binds the agent to user-specified unix-domain socket instead of /tmp/ssh-XXXXXXXX/agent.; ok djm@ (some time ago). - markus@cvs.openbsd.org 2002/06/05 16:08:07 [ssh-agent.1 ssh-agent.c] '-a bind_address' binds the agent to user-specified unix-domain socket instead of /tmp/ssh-XXXXXXXX/agent.; ok djm@ (some time ago). - markus@cvs.openbsd.org 2002/06/05 16:48:54 [ssh-agent.c] copy current request into an extra buffer and just flush this request on errors, ok provos@ - markus@cvs.openbsd.org 2002/06/05 19:57:12 [authfd.c authfd.h ssh-add.1 ssh-add.c ssh-agent.c] ssh-add -x for lock and -X for unlocking the agent. todo: encrypt private keys with locked... - markus@cvs.openbsd.org 2002/06/05 20:56:39 [ssh-add.c] add -x/-X to usage - markus@cvs.openbsd.org 2002/06/05 21:55:44 [authfd.c authfd.h ssh-add.1 ssh-add.c ssh-agent.c] ssh-add -t life, Set lifetime (in seconds) when adding identities; ok provos@ - stevesk@cvs.openbsd.org 2002/06/06 01:09:41 [monitor.h] no trailing comma in enum; china@thewrittenword.com - markus@cvs.openbsd.org 2002/06/06 17:12:44 [sftp-server.c] discard remaining bytes of current request; ok provos@ - markus@cvs.openbsd.org 2002/06/06 17:30:11 [sftp-server.c] use get_int() macro (hide iqueue) - (bal) Missed msg.[ch] in merge. Required for ssh-keysign. - (bal) Forgot to add msg.c Makefile.in. - (bal) monitor_mm.c typos. - (bal) Refixed auth2.c. It was never fully commited while spliting out authentication to different files. - (bal) ssh-keysign should build and install correctly now. Phase two would be to clean out any dead wood and disable ssh setuid on install. - (bal) Reverse logic, use __func__ first since it's C99 20020604 - (stevesk) [channels.c] bug #164 patch from YOSHIFUJI Hideaki (changed setsockopt from debug to error for now). 20020527 - (tim) [configure.ac.orig monitor_fdpass.c] Enahnce msghdr tests to address build problem on Irix reported by Dave Love . Back out last monitor_fdpass.c changes that are no longer needed with new tests. Patch tested on Irix by Jan-Frode Myklebust 20020522 - (djm) Fix spelling mistakes, spotted by Solar Designer i - Sync scard/ (not sure when it drifted) - (djm) OpenBSD CVS Sync: [auth.c] Fix typo/thinko. Pass in as to auth_approval(), not NULL. Closes PR 2659. - Crank version - Crank RPM spec versions 20020521 - (stevesk) [sshd.c] bug 245; disable setsid() for now - (stevesk) [sshd.c] #ifndef HAVE_CYGWIN for setgroups() 20020517 - (tim) [configure.ac] remove extra MD5_MSG="no" line. 20020515 - (bal) CVS ID fix up on auth-passwd.c - (bal) OpenBSD CVS Sync - deraadt@cvs.openbsd.org 2002/05/07 19:54:36 [ssh.h] use ssh uid - deraadt@cvs.openbsd.org 2002/05/08 21:06:34 [ssh.h] move to sshd.sshd instead - stevesk@cvs.openbsd.org 2002/05/11 20:24:48 [ssh.h] typo in comment - itojun@cvs.openbsd.org 2002/05/13 02:37:39 [auth-skey.c auth2.c] less warnings. skey_{respond,query} are public (in auth.h) - markus@cvs.openbsd.org 2002/05/13 20:44:58 [auth-options.c auth.c auth.h] move the packet_send_debug handling from auth-options.c to auth.c; ok provos@ - millert@cvs.openbsd.org 2002/05/13 15:53:19 [sshd.c] Call setsid() in the child after sshd accepts the connection and forks. This is needed for privsep which calls setlogin() when it changes uids. Without this, there is a race where the login name of an existing connection, as returned by getlogin(), may be changed to the privsep user (sshd). markus@ OK - markus@cvs.openbsd.org 2002/05/13 21:26:49 [auth-rhosts.c] handle debug messages during rhosts-rsa and hostbased authentication; ok provos@ - mouring@cvs.openbsd.org 2002/05/15 15:47:49 [kex.c monitor.c monitor_wrap.c sshd.c] 'monitor' variable clashes with at least one lame platform (NeXT). i Renamed to 'pmonitor'. provos@ - deraadt@cvs.openbsd.org 2002/05/04 02:39:35 [servconf.c sshd.8 sshd_config] enable privsep by default; provos ok - millert@cvs.openbsd.org 2002/05/06 23:34:33 [ssh.1 sshd.8] Kill/adjust r(login|exec)d? references now that those are no longer in the tree. - markus@cvs.openbsd.org 2002/05/15 21:02:53 [servconf.c sshd.8 sshd_config] disable privsep and enable setuid for the 3.2.2 release - (bal) Fixed up PAM case. I think. - (bal) Clarified openbsd-compat/*-cray.* Licence provided by Wendy - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/05/15 21:05:29 [version.h] enter OpenSSH_3.2.2 - (bal) Caldara, Suse, and Redhat openssh.specs updated. 20020514 - (stevesk) [README.privsep] PAM+privsep works with Solaris 8. - (tim) [sshpty.c] set tty modes when allocating old style bsd ptys to match what newer style ptys have when allocated. Based on a patch by Roger Cornelius - (tim) [README.privsep] UnixWare 7 and OpenUNIX 8 work. - (tim) [README.privsep] remove reference to UnixWare 7 and OpenUNIX 8 from PAM-enabled pragraph. UnixWare has no PAM. - (tim) [contrib/caldera/openssh.spec] update version. 20020513 - (stevesk) add initial README.privsep - (stevesk) [configure.ac] nicer message: --with-privsep-user=user - (djm) Add --with-superuser-path=xxx configure option to specify what $PATH the superuser receives. - (djm) Bug #231: UsePrivilegeSeparation turns off Banner. - (djm) Add --with-privsep-path configure option - (djm) Update RPM spec file: different superuser path, use /var/empty/sshd for privsep - (djm) Bug #234: missing readpassphrase declaration and defines - (djm) Add INSTALL warning about SSH protocol 1 blowfish w/ OpenSSL < 0.9.6 20020511 - (tim) [configure.ac] applied a rework of djm's OpenSSL search cleanup patch. Now only searches system and /usr/local/ssl (OpenSSL's default install path) Others must use --with-ssl-dir=.... - (tim) [monitor_fdpass.c] fix for systems that have both HAVE_ACCRIGHTS_IN_MSGHDR and HAVE_CONTROL_IN_MSGHDR. Ie. sys/socket.h has #define msg_accrights msg_control 20020510 - (stevesk) [auth.c] Shadow account and expiration cleanup. Now check for root forced expire. Still don't check for inactive. - (djm) Rework RedHat RPM files. Based on spec from Nalin Dahyabhai and patches from Pekka Savola - (djm) Try to drop supplemental groups at daemon startup. Patch from RedHat - (bal) Back all the way out of auth-passwd.c changes. Breaks too many things that don't set pw->pw_passwd. 20020509 - (tim) [Makefile.in] Unbreak make -f Makefile.in distprep 20020508 - (tim) [openbsd-compat/bsd-arc4random.c] fix logic on when seed_rng() is called. Report by Chris Maxwell - (tim) [Makefile.in configure.ac] set SHELL variable in Makefile - (djm) Disable PAM kbd-int auth if privsep is turned on (it doesn't work) 20020507 - (tim) [configure.ac openbsd-compat/bsd-misc.c openbsd-compat/bsd-misc.h] Add truncate() emulation to address Bug 208 20020506 - (djm) Unbreak auth-passwd.c for PAM and SIA - (djm) Unbreak PAM auth for protocol 1. Report from Pekka Savola - (djm) Don't reinitialise PAM credentials before we have started PAM. Report from Pekka Savola 20020506 - (bal) Fixed auth-passwd.c to resolve PermitEmptyPassword issue 20020501 - (djm) Import OpenBSD regression tests. Requires BSD make to run - (djm) Fix readpassphase compilation for systems which have it 20020429 - (tim) [contrib/caldera/openssh.spec] update fixUP to reflect changes in sshd_config. - (tim) [contrib/cygwin/README] remove reference to regex. patch from Corinna Vinschen 20020426 - (djm) Bug #137, #209: fix make problems for scard/Ssh.bin, do uudecode during distprep only - (djm) Disable PAM password expiry until a complete fix for bug #188 exists - (djm) Bug #180: Set ToS bits on IPv4-in-IPv6 mapped addresses. Based on patch from openssh@misc.tecq.org 20020425 - (stevesk) [defines.h] remove USE_TIMEVAL; unused - (stevesk) [acconfig.h auth-passwd.c configure.ac sshd.c] HP-UX 10.26 support. bug #184. most from dcole@keysoftsys.com. 20020424 - (djm) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/04/23 12:54:10 [version.h] 3.2.1 - djm@cvs.openbsd.org 2002/04/23 22:16:29 [sshd.c] Improve error message; ok markus@ stevesk@ 20020423 - (stevesk) [acconfig.h configure.ac session.c] LOGIN_NO_ENDOPT for HP-UX - (stevesk) [acconfig.h] NEED_IN_SYSTM_H unused - (markus) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/04/23 12:58:26 [radix.c] send complete ticket; semerad@ss1000.ms.mff.cuni.cz - (djm) Trim ChangeLog to include only post-3.1 changes - (djm) Update RPM spec file versions - (djm) Redhat spec enables KrbV by default - (djm) Applied OpenSC smartcard updates from Markus & Antti Tapaninen - (djm) Define BROKEN_REALPATH for AIX, patch from Antti Tapaninen - (djm) Bug #214: Fix utmp for Irix (don't strip "tty"). Patch from Kevin Taylor (??) via Philipp Grau - (djm) Bug #213: Simplify CMSG_ALIGN macros to avoid symbol clashes. Reported by Doug Manton - (djm) Bug #222: Fix tests for getaddrinfo on OSF/1. Spotted by Robert Urban - (djm) Bug #206 - blibpath isn't always needed for AIX ld, avoid sizeof(long long int) == 4 breakage. Patch from Matthew Clarke - (djm) Make privsep work with PAM (still experimental) - (djm) OpenBSD CVS Sync - deraadt@cvs.openbsd.org 2002/04/20 09:02:03 [servconf.c] No, afs requires explicit enabling - markus@cvs.openbsd.org 2002/04/20 09:14:58 [bufaux.c bufaux.h] add buffer_{get,put}_short - markus@cvs.openbsd.org 2002/04/20 09:17:19 [radix.c] rewrite using the buffer_* API, fixes overflow; ok deraadt@ - stevesk@cvs.openbsd.org 2002/04/21 16:19:27 [sshd.8 sshd_config] document default AFSTokenPassing no; ok deraadt@ - stevesk@cvs.openbsd.org 2002/04/21 16:25:06 [sshconnect1.c] spelling in error message; ok markus@ - markus@cvs.openbsd.org 2002/04/22 06:15:47 [radix.c] fix check for overflow - markus@cvs.openbsd.org 2002/04/22 16:16:53 [servconf.c sshd.8 sshd_config] do not auto-enable KerberosAuthentication; ok djm@, provos@, deraadt@ - markus@cvs.openbsd.org 2002/04/22 21:04:52 [channels.c clientloop.c clientloop.h ssh.c] request reply (success/failure) for -R style fwd in protocol v2, depends on ordered replies. fixes http://bugzilla.mindrot.org/show_bug.cgi?id=215; ok provos@ 20020421 - (tim) [entropy.c.] Portability fix for SCO Unix 3.2v4.x (SCO OSR 3.0). entropy.c needs seteuid(getuid()) for the setuid(original_uid) to succeed. Patch by gert@greenie.muc.de. This fixes one part of Bug 208 20020418 - (djm) Avoid SIGCHLD breakage when run from rsync. Fix from Sturle Sunde 20020417 - (djm) Tell users to configure /dev/random support into OpenSSL in INSTALL - (djm) Fix .Nm in mdoc2man.pl from pspencer@fields.utoronto.ca - (tim) [configure.ac] Issue warning on --with-default-path=/some_path if LOGIN_CAP is enabled. Report & testing by Tuc 20020415 - (djm) Unbreak "make install". Fix from Darren Tucker - (stevesk) bsd-cygwin_util.[ch] BSD license from Corinna Vinschen - (tim) [configure.ac] add tests for recvmsg and sendmsg. [monitor_fdpass.c] add checks for HAVE_SENDMSG and HAVE_RECVMSG for systems that HAVE_ACCRIGHTS_IN_MSGHDR but no recvmsg or sendmsg. 20020414 - (djm) ssh-rand-helper improvements - Add commandline debugging options - Don't write binary data if stdout is a tty (use hex instead) - Give it a manpage - (djm) Random number collection doc fixes from Ben 20020413 - (djm) Add KrbV support patch from Simon Wilkinson 20020412 - (stevesk) [auth-sia.[ch]] add BSD license from Chris Adams - (tim) [configure.ac] add to msghdr tests. Change -L to -h on testing for /bin being symbolic link - (bal) Mistaken in Cygwin scripts for ssh starting. Patch by Corinna Vinschen - (bal) disable privsep if no MAP_ANON. We can re-enable it after the release when we can do more testing. 20020411 - (stevesk) [auth-sia.c] cleanup - (tim) [acconfig.h defines.h includes.h] put includes in includes.h and defines in defines.h [rijndael.c openbsd-compat/fake-socket.h openbsd-compat/inet_aton.c] include "includes.h" instead of "config.h" ok stevesk@ 20020410 - (stevesk) [configure.ac monitor.c] HAVE_SOCKETPAIR - (stevesk) [auth-sia.c] compile fix Chris Adams - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/04/10 08:21:47 [auth1.c compat.c compat.h] strip '@' from username only for KerbV and known broken clients, bug #204 - markus@cvs.openbsd.org 2002/04/10 08:56:01 [version.h] OpenSSH_3.2 - Added p1 to idenify Portable release version. 20020408 - (bal) Minor OpenSC updates. Fix up header locations and update README.smartcard provided by Juha Yrjölä 20020407 - (stevesk) HAVE_CONTROL_IN_MSGHDR; not used right now. Future: we may want to test if fd passing works correctly. - (stevesk) [monitor_fdpass.c] fatal() for UsePrivilegeSeparation=yes and no fd passing support. - (stevesk) HAVE_MMAP and HAVE_SYS_MMAN_H and use them in monitor_mm.c - (stevesk) remove configure support for poll.h; it was removed from sshd.c a long time ago. - (stevesk) --with-privsep-user; default sshd - (stevesk) wrap munmap() with HAVE_MMAP also. 20020406 - (djm) Typo in Suse SPEC file. Fix from Carsten Grohmann - (bal) Added MAP_FAILED to allow AIX and Trusted HP to compile. - (bal) OpenBSD CVS Sync - djm@cvs.openbsd.org 2002/04/06 00:30:08 [sftp-client.c] Fix occasional corruption on upload due to bad reuse of request id, spotted by chombier@mac.com; ok markus@ - mouring@cvs.openbsd.org 2002/04/06 18:24:09 [scp.c] Fixes potental double // within path. http://bugzilla.mindrot.org/show_bug.cgi?id=76 - (bal) Slight update to OpenSC support. Better version checking. patch by Juha Yrjölä - (bal) Revered out of runtime IRIX detection of joblimits. Code is incomplete. - (bal) Quiet down configure.ac if /bin/test does not exist. - (bal) We no longer use atexit()/xatexit()/on_exit() 20020405 - (bal) Patch for OpenSC SmartCard library; ok markus@; patch by Juha Yrjölä - (bal) Minor documentation update to reflect smartcard library support changes. - (bal) Too many issues. Remove all workarounds and using internal version only. - (bal) OpenBSD CVS Sync - stevesk@cvs.openbsd.org 2002/04/05 20:56:21 [sshd.8] clarify sshrc some and handle X11UseLocalhost=yes; ok markus@ 20020404 - (stevesk) [auth-pam.c auth-pam.h auth-passwd.c auth-sia.c auth-sia.h auth1.c auth2.c] PAM, OSF_SIA password auth cleanup; from djm. - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/04/03 09:26:11 [cipher.c myproposal.h] re-add rijndael-cbc@lysator.liu.se for MacSSH; ash@lab.poc.net 20020402 - (bal) Hand Sync of scp.c (reverted to upstream code) - deraadt@cvs.openbsd.org 2002/03/30 17:45:46 [scp.c] stretch banners - (bal) CVS ID sync of uidswap.c - (bal) OpenBSD CVS Sync (now for the real sync) - markus@cvs.openbsd.org 2002/03/27 22:21:45 [ssh-keygen.c] try to import keys with extra trailing === (seen with ssh.com < 2.0.12) - markus@cvs.openbsd.org 2002/03/28 15:34:51 [session.c] do not call record_login twice (for use_privsep) - markus@cvs.openbsd.org 2002/03/29 18:59:32 [session.c session.h] retrieve last login time before the pty is allocated, store per session - stevesk@cvs.openbsd.org 2002/03/29 19:16:22 [sshd.8] RSA key modulus size minimum 768; ok markus@ - stevesk@cvs.openbsd.org 2002/03/29 19:18:33 [auth-rsa.c ssh-rsa.c ssh.h] make RSA modulus minimum #define; ok markus@ - markus@cvs.openbsd.org 2002/03/30 18:51:15 [monitor.c serverloop.c sftp-int.c sftp.c sshd.c] check waitpid for EINTR; based on patch from peter@ifm.liu.se - markus@cvs.openbsd.org 2002/04/01 22:02:16 [sftp-client.c] 20480 is an upper limit for older server - markus@cvs.openbsd.org 2002/04/01 22:07:17 [sftp-client.c] fallback to stat if server does not support lstat - markus@cvs.openbsd.org 2002/04/02 11:49:39 [ssh-agent.c] check $SHELL for -k and -d, too; http://bugzilla.mindrot.org/show_bug.cgi?id=199 - markus@cvs.openbsd.org 2002/04/02 17:37:48 [sftp.c] always call log_init() - markus@cvs.openbsd.org 2002/04/02 20:11:38 [ssh-rsa.c] ignore SSH_BUG_SIGBLOB for ssh-rsa; #187 - (bal) mispelling in uidswap.c (portable only) 20020401 - (stevesk) [monitor.c] PAM should work again; will *not* work with UsePrivilegeSeparation=yes. - (stevesk) [auth1.c] fix password auth for protocol 1 when !USE_PAM && !HAVE_OSF_SIA; merge issue. 20020331 - (tim) [configure.ac] use /bin/test -L to work around broken builtin on Solaris 8 - (tim) [sshconnect2.c] change uint32_t to u_int32_t 20020330 - (stevesk) [configure.ac] remove header check for sys/ttcompat.h bug 167 20020327 - (bal) 'pw' should be 'authctxt->pw' in auth1.c spotted by kent@lysator.liu.se - (bal) OpenBSD CVS Sync - markus@cvs.openbsd.org 2002/03/26 11:34:49 [ssh.1 sshd.8] update to recent drafts - markus@cvs.openbsd.org 2002/03/26 11:37:05 [ssh.c] update Copyright - markus@cvs.openbsd.org 2002/03/26 15:23:40 [bufaux.c] do not talk about packets in bufaux - rees@cvs.openbsd.org 2002/03/26 18:46:59 [scard.c] try_AUT0 in read_pubkey too, for those paranoid few who want to acl 'sh' - markus@cvs.openbsd.org 2002/03/26 22:50:39 [channels.h] CHANNEL_EFD_OUTPUT_ACTIVE is false for CHAN_CLOSE_RCVD, too - markus@cvs.openbsd.org 2002/03/26 23:13:03 [auth-rsa.c] disallow RSA keys < 768 for protocol 1, too (rhosts-rsa and rsa auth) - markus@cvs.openbsd.org 2002/03/26 23:14:51 [kex.c] generate a new cookie for each SSH2_MSG_KEXINIT message we send out - mouring@cvs.openbsd.org 2002/03/27 11:45:42 [monitor.c] monitor_allowed_key() returns int instead of pointer. ok markus@ 20020325 - (stevesk) import OpenBSD as "openbsd-compat/tree.h" - (bal) OpenBSD CVS Sync - stevesk@cvs.openbsd.org 2002/03/23 20:57:26 [sshd.c] setproctitle() after preauth child; ok markus@ - markus@cvs.openbsd.org 2002/03/24 16:00:27 [serverloop.c] remove unused debug - markus@cvs.openbsd.org 2002/03/24 16:01:13 [packet.c] debug->debug3 for extra padding - stevesk@cvs.openbsd.org 2002/03/24 17:27:03 [kexgex.c] typo; ok markus@ - stevesk@cvs.openbsd.org 2002/03/24 17:53:16 [monitor_fdpass.c] minor cleanup and more error checking; ok markus@ - markus@cvs.openbsd.org 2002/03/24 18:05:29 [scard.c] we need to figure out AUT0 for sc_private_encrypt, too - stevesk@cvs.openbsd.org 2002/03/24 23:20:00 [monitor.c] remove "\n" from fatal() - markus@cvs.openbsd.org 2002/03/25 09:21:13 [auth-rsa.c] return 0 (not NULL); tomh@po.crl.go.jp - markus@cvs.openbsd.org 2002/03/25 09:25:06 [auth-rh-rsa.c] rm bogus comment - markus@cvs.openbsd.org 2002/03/25 17:34:27 [scard.c scard.h ssh-agent.c ssh-keygen.c ssh.c] change sc_get_key to sc_get_keys and hide smartcard details in scard.c - stevesk@cvs.openbsd.org 2002/03/25 20:12:10 [monitor_mm.c monitor_wrap.c] ssize_t args use "%ld" and cast to (long) size_t args use "%lu" and cast to (u_long) ok markus@ and thanks millert@ - markus@cvs.openbsd.org 2002/03/25 21:04:02 [ssh.c] simplify num_identity_files handling - markus@cvs.openbsd.org 2002/03/25 21:13:51 [channels.c channels.h compat.c compat.h nchan.c] don't send stderr data after EOF, accept this from older known (broken) sshd servers only, fixes http://bugzilla.mindrot.org/show_bug.cgi?id=179 - stevesk@cvs.openbsd.org 2002/03/26 03:24:01 [monitor.h monitor_fdpass.h monitor_mm.h monitor_wrap.h] $OpenBSD$ 20020324 - (stevesk) [session.c] disable LOGIN_NEEDS_TERM until we are sure it can be removed. only used on solaris. will no longer compile with privsep shuffling. 20020322 - (stevesk) HAVE_ACCRIGHTS_IN_MSGHDR configure support - (stevesk) [monitor.c monitor_wrap.c] #ifdef HAVE_PW_CLASS_IN_PASSWD - (stevesk) configure and cpp __FUNCTION__ gymnastics to handle nielsisms - (stevesk) [monitor_fdpass.c] support for access rights style file descriptor passing - (stevesk) [auth2.c] merge cleanup/sync - (stevesk) [defines.h] hp-ux 11 has ancillary data style fd passing, but is missing CMSG_LEN() and CMSG_SPACE() macros. - (stevesk) [defines.h] #define MAP_ANON MAP_ANONYMOUS for HP-UX; other platforms may need this--I'm not sure. mmap() issues will need to be addressed further. - (tim) [cipher.c] fix problem with OpenBSD sync - (stevesk) [LICENCE] OpenBSD sync 20020321 - (bal) OpenBSD CVS Sync - itojun@cvs.openbsd.org 2002/03/08 06:10:16 [sftp-client.c] printf type mismatch - itojun@cvs.openbsd.org 2002/03/11 03:18:49 [sftp-client.c] correct type mismatches (u_int64_t != unsigned long long) - itojun@cvs.openbsd.org 2002/03/11 03:19:53 [sftp-client.c] indent - markus@cvs.openbsd.org 2002/03/14 15:24:27 [sshconnect1.c] don't trust size sent by (rogue) server; noted by s.esser@e-matters.de - markus@cvs.openbsd.org 2002/03/14 16:38:26 [sshd.c] split out ssh1 session key decryption; ok provos@ - markus@cvs.openbsd.org 2002/03/14 16:56:33 [auth-rh-rsa.c auth-rsa.c auth.h] split auth_rsa() for better readability and privsep; ok provos@ - itojun@cvs.openbsd.org 2002/03/15 11:00:38 [auth.c] fix file type checking (use S_ISREG). ok by markus - markus@cvs.openbsd.org 2002/03/16 11:24:53 [compress.c] skip inflateEnd if inflate fails; ok provos@ - markus@cvs.openbsd.org 2002/03/16 17:22:09 [auth-rh-rsa.c auth.h] split auth_rhosts_rsa(), ok provos@ - stevesk@cvs.openbsd.org 2002/03/16 17:41:25 [auth-krb5.c] BSD license. from Daniel Kouril via Dug Song. ok markus@ - provos@cvs.openbsd.org 2002/03/17 20:25:56 [auth.c auth.h auth1.c auth2.c] getpwnamallow returns struct passwd * only if user valid; okay markus@ - provos@cvs.openbsd.org 2002/03/18 01:12:14 [auth.h auth1.c auth2.c sshd.c] have the authentication functions return the authentication context and then do_authenticated; okay millert@ - dugsong@cvs.openbsd.org 2002/03/18 01:30:10 [auth-krb4.c] set client to NULL after xfree(), from Rolf Braun - provos@cvs.openbsd.org 2002/03/18 03:41:08 [auth.c session.c] move auth_approval into getpwnamallow with help from millert@ - markus@cvs.openbsd.org 2002/03/18 17:13:15 [cipher.c cipher.h] export/import cipher states; needed by ssh-privsep - markus@cvs.openbsd.org 2002/03/18 17:16:38 [packet.c packet.h] export/import cipher state, iv and ssh2 seqnr; needed by ssh-privsep - markus@cvs.openbsd.org 2002/03/18 17:23:31 [key.c key.h] add key_demote() for ssh-privsep - provos@cvs.openbsd.org 2002/03/18 17:25:29 [bufaux.c bufaux.h] buffer_skip_string and extra sanity checking; needed by ssh-privsep - provos@cvs.openbsd.org 2002/03/18 17:31:54 [compress.c] export compression streams for ssh-privsep - provos@cvs.openbsd.org 2002/03/18 17:50:31 [auth-bsdauth.c auth-options.c auth-rh-rsa.c auth-rsa.c] [auth-skey.c auth.h auth1.c auth2-chall.c auth2.c kex.c kex.h kexdh.c] [kexgex.c servconf.c] [session.h servconf.h serverloop.c session.c sshd.c] integrate privilege separated openssh; its turned off by default for now. work done by me and markus@ - provos@cvs.openbsd.org 2002/03/18 17:53:08 [sshd.8] credits for privsep - provos@cvs.openbsd.org 2002/03/18 17:59:09 [sshd.8] document UsePrivilegeSeparation - stevesk@cvs.openbsd.org 2002/03/18 23:52:51 [servconf.c] UnprivUser/UnprivGroup usable now--specify numeric user/group; ok provos@ - stevesk@cvs.openbsd.org 2002/03/19 03:03:43 [pathnames.h servconf.c servconf.h sshd.c] _PATH_PRIVSEP_CHROOT_DIR; ok provos@ - stevesk@cvs.openbsd.org 2002/03/19 05:23:08 [sshd.8] Banner has no default. - mpech@cvs.openbsd.org 2002/03/19 06:32:56 [sftp-int.c] use xfree() after xstrdup(). markus@ ok - markus@cvs.openbsd.org 2002/03/19 10:35:39 [auth-options.c auth.h session.c session.h sshd.c] clean up prototypes - markus@cvs.openbsd.org 2002/03/19 10:49:35 [auth-krb5.c auth-rh-rsa.c auth.c cipher.c key.c misc.h] [packet.c session.c sftp-client.c sftp-glob.h sftp.c ssh-add.c ssh.c] [sshconnect2.c sshd.c ttymodes.c] KNF whitespace - markus@cvs.openbsd.org 2002/03/19 14:27:39 [auth.c auth1.c auth2.c] make getpwnamallow() allways call pwcopy() - markus@cvs.openbsd.org 2002/03/19 15:31:47 [auth.c] check for NULL; from provos@ - stevesk@cvs.openbsd.org 2002/03/20 19:12:25 [servconf.c servconf.h ssh.h sshd.c] for unprivileged user, group do: pw=getpwnam(SSH_PRIVSEP_USER); do_setusercontext(pw). ok provos@ - stevesk@cvs.openbsd.org 2002/03/20 21:08:08 [sshd.c] strerror() on chdir() fail; ok provos@ - markus@cvs.openbsd.org 2002/03/21 10:21:20 [ssh-add.c] ignore errors for nonexisting default keys in ssh-add, fixes http://bugzilla.mindrot.org/show_bug.cgi?id=158 - jakob@cvs.openbsd.org 2002/03/21 15:17:26 [clientloop.c ssh.1] add built-in command line for adding new port forwardings on the fly. based on a patch from brian wellington. ok markus@. - markus@cvs.openbsd.org 2002/03/21 16:38:06 [scard.c] make compile w/ openssl 0.9.7 - markus@cvs.openbsd.org 2002/03/21 16:54:53 [scard.c scard.h ssh-keygen.c] move key upload to scard.[ch] - markus@cvs.openbsd.org 2002/03/21 16:57:15 [scard.c] remove const - markus@cvs.openbsd.org 2002/03/21 16:58:13 [clientloop.c] remove unused - rees@cvs.openbsd.org 2002/03/21 18:08:15 [scard.c] In sc_put_key(), sc_reader_id should be id. - markus@cvs.openbsd.org 2002/03/21 20:51:12 [sshd_config] add privsep (off) - markus@cvs.openbsd.org 2002/03/21 21:23:34 [sshd.c] add privsep_preauth() and remove 1 goto; ok provos@ - rees@cvs.openbsd.org 2002/03/21 21:54:34 [scard.c scard.h ssh-keygen.c] Add PIN-protection for secret key. - rees@cvs.openbsd.org 2002/03/21 22:44:05 [authfd.c authfd.h ssh-add.c ssh-agent.c ssh.c] Add PIN-protection for secret key. - markus@cvs.openbsd.org 2002/03/21 23:07:37 [clientloop.c] remove unused, sync w/ cmdline patch in my tree. 20020317 - (tim) [configure.ac] Assume path given with --with-pid-dir=PATH is wanted, warn if directory does not exist. Put system directories in front of PATH for finding entorpy commands. - (tim) [contrib/aix/buildbff.sh contrib/aix/inventory.sh] AIX package build fixes. Patch by Darren Tucker [contrib/solaris/buildpkg.sh] add missing dirs to SYSTEM_DIR. Have postinstall check for $piddir and add if necessary. 20020311 - (tim) [contrib/solaris/buildpkg.sh, contrib/solaris/README] Updated to build on all platforms that support SVR4 style package tools. Now runs from build dir. Parts are based on patches from Antonio Navarro, and Darren Tucker. 20020308 - (djm) Revert bits of Markus' OpenSSL compat patch which was accidentally committed. - (djm) Add Markus' patch for compat wih OpenSSL < 0.9.6. Known issue: Blowfish for SSH1 does not work - (stevesk) entropy.c: typo in debug message - (djm) ssh-keygen -i needs seeded RNG; report from markus@ -$Id: ChangeLog,v 1.2240 2002/06/21 15:44:45 djm Exp $ +$Id: ChangeLog,v 1.2301 2002/06/26 13:59:10 djm Exp $ diff --git a/crypto/openssh/INSTALL b/crypto/openssh/INSTALL index a7f73e6489f3..07da06b5615d 100644 --- a/crypto/openssh/INSTALL +++ b/crypto/openssh/INSTALL @@ -1,229 +1,224 @@ 1. Prerequisites ---------------- You will need working installations of Zlib and OpenSSL. Zlib: http://www.gzip.org/zlib/ OpenSSL 0.9.6 or greater: http://www.openssl.org/ (OpenSSL 0.9.5a is partially supported, but some ciphers (SSH protocol 1 Blowfish included) do not work correctly.) RPMs of OpenSSL are available at http://violet.ibs.com.au/openssh/files/support. For Red Hat Linux 6.2, they have been released as errata. RHL7 includes these. OpenSSH can utilise Pluggable Authentication Modules (PAM) if your system supports it. PAM is standard on Redhat and Debian Linux, Solaris and HP-UX 11. NB. If you operating system supports /dev/random, you should configure OpenSSL to use it. OpenSSH relies on OpenSSL's direct support of /dev/random. If you don't you will have to rely on ssh-rand-helper, which is inferior to a good kernel-based solution. PAM: http://www.kernel.org/pub/linux/libs/pam/ If you wish to build the GNOME passphrase requester, you will need the GNOME libraries and headers. GNOME: http://www.gnome.org/ Alternatively, Jim Knoble has written an excellent X11 passphrase requester. This is maintained separately at: http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/index.html PRNGD: If your system lacks Kernel based random collection, the use of Lutz Jaenicke's PRNGd is recommended. http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html EGD: The Entropy Gathering Daemon (EGD) is supported if you have a system which lacks /dev/random and don't want to use OpenSSH's internal entropy collection. http://www.lothar.com/tech/crypto/ S/Key Libraries: http://www.sparc.spb.su/solaris/skey/ If you wish to use --with-skey then you will need the above library installed. No other current S/Key library is currently known to be supported. 2. Building / Installation -------------------------- To install OpenSSH with default options: ./configure make make install This will install the OpenSSH binaries in /usr/local/bin, configuration files in /usr/local/etc, the server in /usr/local/sbin, etc. To specify a different installation prefix, use the --prefix option to configure: ./configure --prefix=/opt make make install Will install OpenSSH in /opt/{bin,etc,lib,sbin}. You can also override specific paths, for example: ./configure --prefix=/opt --sysconfdir=/etc/ssh make make install This will install the binaries in /opt/{bin,lib,sbin}, but will place the configuration files in /etc/ssh. If you are using PAM, you may need to manually install a PAM control file as "/etc/pam.d/sshd" (or wherever your system prefers to keep them). Note that the service name used to start PAM is __progname, which is the basename of the path of your sshd (e.g., the service name for /usr/sbin/osshd will be osshd). If you have renamed your sshd executable, your PAM configuration may need to be modified. A generic PAM configuration is included as "contrib/sshd.pam.generic", you may need to edit it before using it on your system. If you are using a recent version of Red Hat Linux, the config file in contrib/redhat/sshd.pam should be more useful. Failure to install a valid PAM file may result in an inability to use password authentication. On HP-UX 11 and Solaris, the standard /etc/pam.conf configuration will work with sshd (sshd will match the other service name). There are a few other options to the configure script: ---with-rsh=PATH allows you to specify the path to your rsh program. -Normally ./configure will search the current $PATH for 'rsh'. You -may need to specify this option if rsh is not in your path or has a -different name. - --with-pam enables PAM support. --enable-gnome-askpass will build the GNOME passphrase dialog. You need a working installation of GNOME, including the development headers, for this to work. --with-prngd-socket=/some/file allows you to enable EGD or PRNGD support and to specify a PRNGd socket. Use this if your Unix lacks /dev/random and you don't want to use OpenSSH's builtin entropy collection support. --with-prngd-port=portnum allows you to enable EGD or PRNGD support and to specify a EGD localhost TCP port. Use this if your Unix lacks /dev/random and you don't want to use OpenSSH's builtin entropy collection support. --with-lastlog=FILE will specify the location of the lastlog file. ./configure searches a few locations for lastlog, but may not find it if lastlog is installed in a different place. --without-lastlog will disable lastlog support entirely. --with-sia, --without-sia will enable or disable OSF1's Security Integration Architecture. The default for OSF1 machines is enable. --with-kerberos4=PATH will enable Kerberos IV support. You will need to have the Kerberos libraries and header files installed for this to work. Use the optional PATH argument to specify the root of your Kerberos installation. --with-afs=PATH will enable AFS support. You will need to have the Kerberos IV and the AFS libraries and header files installed for this to work. Use the optional PATH argument to specify the root of your AFS installation. AFS requires Kerberos support to be enabled. --with-skey=PATH will enable S/Key one time password support. You will need the S/Key libraries and header files installed for this to work. --with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny) support. You will need libwrap.a and tcpd.h installed. --with-md5-passwords will enable the use of MD5 passwords. Enable this if your operating system uses MD5 passwords without using PAM. --with-utmpx enables utmpx support. utmpx support is automatic for some platforms. --without-shadow disables shadow password support. --with-ipaddr-display forces the use of a numeric IP address in the $DISPLAY environment variable. Some broken systems need this. --with-default-path=PATH allows you to specify a default $PATH for sessions started by sshd. This replaces the standard path entirely. --with-pid-dir=PATH specifies the directory in which the ssh.pid file is created. --with-xauth=PATH specifies the location of the xauth binary --with-ipv4-default instructs OpenSSH to use IPv4 by default for new connections. Normally OpenSSH will try attempt to lookup both IPv6 and IPv4 addresses. On Linux/glibc-2.1.2 this causes long delays in name resolution. If this option is specified, you can still attempt to connect to IPv6 addresses using the command line option '-6'. --with-ssl-dir=DIR allows you to specify where your OpenSSL libraries are installed. --with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to real (AF_INET) IPv4 addresses. Works around some quirks on Linux. --with-opensc=DIR --with-sectok=DIR allows for OpenSC or sectok smartcard libraries to be used with OpenSSH. See 'README.smartcard' for more details. If you need to pass special options to the compiler or linker, you can specify these as environment variables before running ./configure. For example: CFLAGS="-O -m486" LDFLAGS="-s" LIBS="-lrubbish" LD="/usr/foo/ld" ./configure 3. Configuration ---------------- The runtime configuration files are installed by in ${prefix}/etc or whatever you specified as your --sysconfdir (/usr/local/etc by default). The default configuration should be instantly usable, though you should review it to ensure that it matches your security requirements. To generate a host key, run "make host-key". Alternately you can do so manually using the following commands: ssh-keygen -t rsa1 -f /etc/ssh/ssh_host_key -N "" ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N "" ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N "" Replacing /etc/ssh with the correct path to the configuration directory. (${prefix}/etc or whatever you specified with --sysconfdir during configuration) If you have configured OpenSSH with EGD support, ensure that EGD is running and has collected some Entropy. For more information on configuration, please refer to the manual pages for sshd, ssh and ssh-agent. 4. Problems? ------------ If you experience problems compiling, installing or running OpenSSH. Please refer to the "reporting bugs" section of the webpage at http://www.openssh.com/ -$Id: INSTALL,v 1.53 2002/05/13 05:22:21 djm Exp $ +$Id: INSTALL,v 1.54 2002/06/24 16:26:49 stevesk Exp $ diff --git a/crypto/openssh/Makefile.in b/crypto/openssh/Makefile.in index 4b3e278658b8..e7faa1591297 100644 --- a/crypto/openssh/Makefile.in +++ b/crypto/openssh/Makefile.in @@ -1,339 +1,346 @@ -# $Id: Makefile.in,v 1.215 2002/06/21 01:38:53 mouring Exp $ +# $Id: Makefile.in,v 1.217 2002/06/25 23:45:42 tim Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ AUTORECONF=autoreconf prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ libexecdir=@libexecdir@ datadir=@datadir@ mandir=@mandir@ mansubdir=@mansubdir@ sysconfdir=@sysconfdir@ piddir=@piddir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ DESTDIR= VPATH=@srcdir@ SSH_PROGRAM=@bindir@/ssh ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign RAND_HELPER=$(libexecdir)/ssh-rand-helper PRIVSEP_PATH=@PRIVSEP_PATH@ +SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \ -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \ -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \ -D_PATH_SSH_PIDDIR=\"$(piddir)\" \ -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \ -DSSH_RAND_HELPER=\"$(RAND_HELPER)\" CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ LIBS=@LIBS@ LIBPAM=@LIBPAM@ LIBWRAP=@LIBWRAP@ AR=@AR@ RANLIB=@RANLIB@ INSTALL=@INSTALL@ PERL=@PERL@ ENT=@ENT@ XAUTH_PATH=@XAUTH_PATH@ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ EXEEXT=@EXEEXT@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ @NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT) TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS) LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth2-hostbased.o auth2-kbdint.o auth2-none.o auth2-passwd.o auth2-pubkey.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-krb5.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o monitor_mm.o monitor.o MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5 MANTYPE = @MANTYPE@ CONFIGFILES=sshd_config.out ssh_config.out moduli.out CONFIGFILES_IN=sshd_config ssh_config moduli PATHSUBS = \ -D/etc/ssh/ssh_prng_cmds=$(sysconfdir)/ssh_prng_cmds \ -D/etc/ssh/ssh_config=$(sysconfdir)/ssh_config \ -D/etc/ssh/ssh_known_hosts=$(sysconfdir)/ssh_known_hosts \ -D/etc/ssh/sshd_config=$(sysconfdir)/sshd_config \ -D/usr/libexec=$(libexecdir) \ -D/etc/shosts.equiv=$(sysconfdir)/shosts.equiv \ -D/etc/ssh/ssh_host_key=$(sysconfdir)/ssh_host_key \ -D/etc/ssh/ssh_host_dsa_key=$(sysconfdir)/ssh_host_dsa_key \ -D/etc/ssh/ssh_host_rsa_key=$(sysconfdir)/ssh_host_rsa_key \ -D/var/run/sshd.pid=$(piddir)/sshd.pid \ -D/etc/ssh/moduli=$(sysconfdir)/moduli \ -D/etc/ssh/sshrc=$(sysconfdir)/sshrc \ -D/usr/X11R6/bin/xauth=$(XAUTH_PATH) \ -D/var/empty=$(PRIVSEP_PATH) \ -D/usr/bin:/bin:/usr/sbin:/sbin=@user_path@ FIXPATHSCMD = $(PERL) $(srcdir)/fixpaths $(PATHSUBS) all: $(CONFIGFILES) $(MANPAGES) $(TARGETS) $(LIBSSH_OBJS): config.h $(SSHOBJS): config.h $(SSHDOBJS): config.h .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< LIBCOMPAT=openbsd-compat/libopenbsd-compat.a $(LIBCOMPAT): always (cd openbsd-compat && $(MAKE)) always: libssh.a: $(LIBSSH_OBJS) $(AR) rv $@ $(LIBSSH_OBJS) $(RANLIB) $@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBWRAP) $(LIBPAM) $(LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o $(LD) -o $@ scp.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o $(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o $(LD) -o $@ ssh-keysign.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o $(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o $(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) # test driver for the loginrec code - not built by default logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) $(MANPAGES): $(MANPAGES_IN) if test "$(MANTYPE)" = "cat"; then \ manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ else \ manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \ fi; \ if test "$(MANTYPE)" = "man"; then \ $(FIXPATHSCMD) $${manpage} | $(PERL) $(srcdir)/mdoc2man.pl > $@; \ else \ $(FIXPATHSCMD) $${manpage} > $@; \ fi $(CONFIGFILES): $(CONFIGFILES_IN) conffile=`echo $@ | sed 's/.out$$//'`; \ $(FIXPATHSCMD) $(srcdir)/$${conffile} > $@ clean: rm -f *.o *.a $(TARGETS) logintest config.cache config.log rm -f *.out core (cd openbsd-compat && $(MAKE) clean) distclean: rm -f *.o *.a $(TARGETS) logintest config.cache config.log rm -f *.out core rm -f Makefile config.h config.status ssh_prng_cmds *~ rm -rf autom4te.cache (cd openbsd-compat && $(MAKE) distclean) (cd scard && $(MAKE) distclean) veryclean: rm -f configure config.h.in *.0 rm -f *.o *.a $(TARGETS) logintest config.cache config.log rm -f *.out core rm -f Makefile config.h config.status ssh_prng_cmds *~ (cd openbsd-compat && $(MAKE) distclean) (cd scard && $(MAKE) distclean) mrproper: distclean catman-do: @for f in $(MANPAGES_IN) ; do \ base=`echo $$f | sed 's/\..*$$//'` ; \ echo "$$f -> $$base.0" ; \ nroff -mandoc $$f | cat -v | sed -e 's/.\^H//g' \ >$$base.0 ; \ done distprep: catman-do $(AUTORECONF) (cd scard && $(MAKE) -f Makefile.in distprep) -install: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files host-key +install: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files host-key check-user install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files +check-user: + id $(SSH_PRIVSEP_USER) || \ + echo "WARNING: Privilege separation user \"$(SSH_PRIVSEP_USER)\" does not exist" + scard-install: (cd scard && $(MAKE) DESTDIR=$(DESTDIR) install) install-files: scard-install $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir) $(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir) $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir) $(srcdir)/mkinstalldirs $(DESTDIR)$(datadir) $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)1 $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)5 $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)8 $(srcdir)/mkinstalldirs $(DESTDIR)$(libexecdir) + $(srcdir)/mkinstalldirs $(DESTDIR)$(PRIVSEP_PATH) + chmod 0700 $(DESTDIR)$(PRIVSEP_PATH) $(INSTALL) -m 0755 -s ssh $(DESTDIR)$(bindir)/ssh $(INSTALL) -m 0755 -s scp $(DESTDIR)$(bindir)/scp $(INSTALL) -m 0755 -s ssh-add $(DESTDIR)$(bindir)/ssh-add $(INSTALL) -m 0755 -s ssh-agent $(DESTDIR)$(bindir)/ssh-agent $(INSTALL) -m 0755 -s ssh-keygen $(DESTDIR)$(bindir)/ssh-keygen $(INSTALL) -m 0755 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd if test ! -z "$(INSTALL_SSH_RAND_HELPER)" ; then \ $(INSTALL) -m 0755 -s ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \ fi $(INSTALL) -m 4711 -s ssh-keysign $(DESTDIR)$(SSH_KEYSIGN) @NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER) $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 $(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 $(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5 $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 - if [ ! -z "$(INSTALL_SSH_PRNG_CMDS)" ]; then \ + if [ ! -z "$(INSTALL_SSH_RAND_HELPER)" ]; then \ $(INSTALL) -m 644 ssh-rand-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8 ; \ fi @NO_SFTP@$(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 @NO_SFTP@$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 -rm -f $(DESTDIR)$(bindir)/slogin ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ $(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \ fi if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config ]; then \ $(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \ else \ echo "$(DESTDIR)$(sysconfdir)/ssh_config already exists, install will not overwrite"; \ fi if [ ! -f $(DESTDIR)$(sysconfdir)/sshd_config ]; then \ $(INSTALL) -m 644 sshd_config.out $(DESTDIR)$(sysconfdir)/sshd_config; \ else \ echo "$(DESTDIR)$(sysconfdir)/sshd_config already exists, install will not overwrite"; \ fi if [ -f ssh_prng_cmds -a ! -z "$(INSTALL_SSH_PRNG_CMDS)" ]; then \ $(PERL) $(srcdir)/fixprogs ssh_prng_cmds $(ENT); \ if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_prng_cmds ] ; then \ $(INSTALL) -m 644 ssh_prng_cmds.out $(DESTDIR)$(sysconfdir)/ssh_prng_cmds; \ else \ echo "$(DESTDIR)$(sysconfdir)/ssh_prng_cmds already exists, install will not overwrite"; \ fi ; \ fi if [ ! -f $(DESTDIR)$(sysconfdir)/moduli ]; then \ if [ -f $(DESTDIR)$(sysconfdir)/primes ]; then \ echo "moving $(DESTDIR)$(sysconfdir)/primes to $(DESTDIR)$(sysconfdir)/moduli"; \ mv "$(DESTDIR)$(sysconfdir)/primes" "$(DESTDIR)$(sysconfdir)/moduli"; \ else \ $(INSTALL) -m 644 moduli.out $(DESTDIR)$(sysconfdir)/moduli; \ fi ; \ else \ echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ fi host-key: ssh-keygen$(EXEEXT) if [ -z "$(DESTDIR)" ] ; then \ if [ -f "$(DESTDIR)$(sysconfdir)/ssh_host_key" ] ; then \ echo "$(DESTDIR)$(sysconfdir)/ssh_host_key already exists, skipping." ; \ else \ ./ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" ; \ fi ; \ if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key ] ; then \ echo "$(DESTDIR)$(sysconfdir)/ssh_host_dsa_key already exists, skipping." ; \ else \ ./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ; \ fi ; \ if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key ] ; then \ echo "$(DESTDIR)$(sysconfdir)/ssh_host_rsa_key already exists, skipping." ; \ else \ ./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" ; \ fi ; \ fi ; host-key-force: ssh-keygen$(EXEEXT) ./ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" ./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" uninstallall: uninstall -rm -f $(DESTDIR)$(sysconfdir)/ssh_config -rm -f $(DESTDIR)$(sysconfdir)/sshd_config -rm -f $(DESTDIR)$(sysconfdir)/ssh_prng_cmds -rmdir $(DESTDIR)$(sysconfdir) -rmdir $(DESTDIR)$(bindir) -rmdir $(DESTDIR)$(sbindir) -rmdir $(DESTDIR)$(mandir)/$(mansubdir)1 -rmdir $(DESTDIR)$(mandir)/$(mansubdir)8 -rmdir $(DESTDIR)$(mandir) -rmdir $(DESTDIR)$(libexecdir) uninstall: -rm -f $(DESTDIR)$(bindir)/slogin -rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT) -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)$(SFTP_SERVER)$(EXEEXT) -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) -rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT) -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 -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/ssh-rand-helper.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 diff --git a/crypto/openssh/README.privsep b/crypto/openssh/README.privsep index 6c798f3a4e4b..ced943f262fe 100644 --- a/crypto/openssh/README.privsep +++ b/crypto/openssh/README.privsep @@ -1,60 +1,61 @@ Privilege separation, or privsep, is method in OpenSSH by which operations that require root privilege are performed by a separate privileged monitor process. Its purpose is to prevent privilege escalation by containing corruption to an unprivileged process. More information is available at: http://www.citi.umich.edu/u/provos/ssh/privsep.html Privilege separation is now enabled by default; see the UsePrivilegeSeparation option in sshd_config(5). On systems which lack mmap or anonymous (MAP_ANON) memory mapping, compression must be disabled in order for privilege separation to function. -When privsep is enabled, the pre-authentication sshd process will +When privsep is enabled, during the pre-authentication phase sshd will chroot(2) to "/var/empty" and change its privileges to the "sshd" user -and its primary group. You should do something like the following to -prepare the privsep preauth environment: +and its primary group. sshd is a pseudo-account that should not be +used by other daemons, and must be locked and should contain a +"nologin" or invalid shell. + +You should do something like the following to prepare the privsep +preauth environment: # mkdir /var/empty # chown root:sys /var/empty # chmod 755 /var/empty # groupadd sshd - # useradd -g sshd sshd - -If you are on UnixWare 7 or OpenUNIX 8 do this additional step. - # ln /usr/lib/.ns.so /usr/lib/ns.so.1 + # useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd /var/empty should not contain any files. configure supports the following options to change the default privsep user and chroot directory: --with-privsep-path=xxx Path for privilege separation chroot --with-privsep-user=user Specify non-privileged user for privilege separation -Privsep requires operating system support for file descriptor passing -and mmap(MAP_ANON). +Privsep requires operating system support for file descriptor passing. +Compression will be disabled on systems without a working mmap MAP_ANON. PAM-enabled OpenSSH is known to function with privsep on Linux. It does not function on HP-UX with a trusted system configuration. PAMAuthenticationViaKbdInt does not function with privsep. Note that for a normal interactive login with a shell, enabling privsep will require 1 additional process per login session. Given the following process listing (from HP-UX): UID PID PPID C STIME TTY TIME COMMAND root 1005 1 0 10:45:17 ? 0:08 /opt/openssh/sbin/sshd -u0 root 6917 1005 0 15:19:16 ? 0:00 sshd: stevesk [priv] stevesk 6919 6917 0 15:19:17 ? 0:03 sshd: stevesk@2 stevesk 6921 6919 0 15:19:17 pts/2 0:00 -bash process 1005 is the sshd process listening for new connections. process 6917 is the privileged monitor process, 6919 is the user owned sshd process and 6921 is the shell process. -$Id: README.privsep,v 1.7 2002/06/21 14:48:02 djm Exp $ +$Id: README.privsep,v 1.10 2002/06/26 00:43:57 stevesk Exp $ diff --git a/crypto/openssh/TODO b/crypto/openssh/TODO index d094942ea622..4331a1364be0 100644 --- a/crypto/openssh/TODO +++ b/crypto/openssh/TODO @@ -1,90 +1,106 @@ Programming: - Grep for 'XXX' comments and fix - Link order is incorrect for some systems using Kerberos 4 and AFS. Result is multiple inclusion of DES symbols. Holger Trapp reports that changing the configure generated link order from: -lresolv -lkrb -lz -lnsl -lutil -lkafs -lkrb -ldes -lcrypto to: -lresolv -lkrb -lz -lnsl -lutil -lcrypto -lkafs -lkrb -ldes fixing the problem. - Write a test program that calls stat() to search for EGD/PRNGd socket rather than use the (non-portable) "test -S". - Replacement for setproctitle() - HP-UX support only currently - Handle changing passwords for the non-PAM expired password case - Improve PAM support (a pam_lastlog module will cause sshd to exit) and maybe support alternate forms of authenications like OPIE via pam? - Rework PAM ChallengeResponseAuthentication - Use kbdint request packet with 0 prompts for informational messages - Use different PAM service name for kbdint vs regular auth (suggest from Solar Designer) - Ability to select which ChallengeResponseAuthentications may be used and order to try them in e.g. "ChallengeResponseAuthentication skey, pam" - Complete Tru64 SIA support - It looks like we could merge it into the password auth code to cut down on diff size. Maybe PAM password auth too? - Finish integrating kernel-level auditing code for IRIX and SOLARIS (Gilbert.r.loomis@saic.com) - sftp-server: Rework to step down to 32bit ints if the platform lacks 'long long' == 64bit (Notable SCO w/ SCO compiler) - Linux hangs for 20 seconds when you do "sleep 20&exit". All current solutions break scp or leaves processes hanging around after the ssh connection has ended. It seems to be linked to two things. One select() under Linux is not as nice as others, and two the children of the shell are not killed on exiting the shell. Redhat have an excellent description of this in their RPM package. - Build an automated test suite - 64-bit builds on HP-UX 11.X (stevesk@pobox.com): - utmp/wtmp get corrupted (something in loginrec?) - can't build with PAM (no 64-bit libpam yet) Documentation: - More and better - Install FAQ? - General FAQ on S/Key, TIS, RSA, RSA2, DSA, etc and suggestions on when it would be best to use them. - Create a Documentation/ directory? Clean up configure/makefiles: - Clean up configure.ac - There are a few double #defined variables left to do. HAVE_LOGIN is one of them. Consider NOT looking for information in wtmpx or utmpx or any of that stuff if it's not detected from the start - Fails to compile when cross compile. (vinschen@redhat.com) - Replace the whole u_intXX_t evilness in acconfig.h with something better??? - Consider splitting the u_intXX_t test for sys/bitype.h into seperate test to allow people to (right/wrongfully) link against Bind directly. - Consider splitting configure.ac into seperate files which do logically similar tests. E.g move all the type detection stuff into one file, entropy related stuff into another. Packaging: - Solaris: Update packaging scripts and build new sysv startup scripts Ideally the package metadata should be generated by autoconf. (gilbert.r.loomis@saic.com) - HP-UX: Provide DEPOT package scripts. (gilbert.r.loomis@saic.com) -$Id: TODO,v 1.46 2002/01/22 11:26:20 djm Exp $ + +PrivSep Issues: +- mmap() issues. + + /dev/zero solution (Solaris) + + No/broken MAP_ANON (Irix) + + broken /dev/zero parse (Linux) +- PAM + + See above PAM notes +- AIX + + usrinfo() does not set TTY, but only required for legicy systems. Works + with PrivSep. +- OSF + + SIA is broken +- Cygwin + + Privsep for Pre-auth only (no fd passing) + +$Id: TODO,v 1.50 2002/06/25 17:12:27 mouring Exp $ diff --git a/crypto/openssh/buffer.c b/crypto/openssh/buffer.c index 40572e5ac30e..ad04b267e0d8 100644 --- a/crypto/openssh/buffer.c +++ b/crypto/openssh/buffer.c @@ -1,168 +1,174 @@ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Functions for manipulating fifo buffers (that can grow if needed). * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" -RCSID("$OpenBSD: buffer.c,v 1.15 2002/01/18 18:14:17 stevesk Exp $"); +RCSID("$OpenBSD: buffer.c,v 1.16 2002/06/26 08:54:18 markus Exp $"); #include "xmalloc.h" #include "buffer.h" #include "log.h" /* Initializes the buffer structure. */ void buffer_init(Buffer *buffer) { buffer->alloc = 4096; buffer->buf = xmalloc(buffer->alloc); buffer->offset = 0; buffer->end = 0; } /* Frees any memory used for the buffer. */ void buffer_free(Buffer *buffer) { memset(buffer->buf, 0, buffer->alloc); xfree(buffer->buf); } /* * Clears any data from the buffer, making it empty. This does not actually * zero the memory. */ void buffer_clear(Buffer *buffer) { buffer->offset = 0; buffer->end = 0; } /* Appends data to the buffer, expanding it if necessary. */ void buffer_append(Buffer *buffer, const void *data, u_int len) { void *p; p = buffer_append_space(buffer, len); memcpy(p, data, len); } /* * Appends space to the buffer, expanding the buffer if necessary. This does * not actually copy the data into the buffer, but instead returns a pointer * to the allocated region. */ void * buffer_append_space(Buffer *buffer, u_int len) { void *p; + if (len > 0x100000) + fatal("buffer_append_space: len %u not supported", len); + /* If the buffer is empty, start using it from the beginning. */ if (buffer->offset == buffer->end) { buffer->offset = 0; buffer->end = 0; } restart: /* If there is enough space to store all data, store it now. */ if (buffer->end + len < buffer->alloc) { p = buffer->buf + buffer->end; buffer->end += len; return p; } /* * If the buffer is quite empty, but all data is at the end, move the * data to the beginning and retry. */ if (buffer->offset > buffer->alloc / 2) { memmove(buffer->buf, buffer->buf + buffer->offset, buffer->end - buffer->offset); buffer->end -= buffer->offset; buffer->offset = 0; goto restart; } /* Increase the size of the buffer and retry. */ buffer->alloc += len + 32768; + if (buffer->alloc > 0xa00000) + fatal("buffer_append_space: alloc %u not supported", + buffer->alloc); buffer->buf = xrealloc(buffer->buf, buffer->alloc); goto restart; /* NOTREACHED */ } /* Returns the number of bytes of data in the buffer. */ u_int buffer_len(Buffer *buffer) { return buffer->end - buffer->offset; } /* Gets data from the beginning of the buffer. */ void buffer_get(Buffer *buffer, void *buf, u_int len) { if (len > buffer->end - buffer->offset) fatal("buffer_get: trying to get more bytes %d than in buffer %d", len, buffer->end - buffer->offset); memcpy(buf, buffer->buf + buffer->offset, len); buffer->offset += len; } /* Consumes the given number of bytes from the beginning of the buffer. */ void buffer_consume(Buffer *buffer, u_int bytes) { if (bytes > buffer->end - buffer->offset) fatal("buffer_consume: trying to get more bytes than in buffer"); buffer->offset += bytes; } /* Consumes the given number of bytes from the end of the buffer. */ void buffer_consume_end(Buffer *buffer, u_int bytes) { if (bytes > buffer->end - buffer->offset) fatal("buffer_consume_end: trying to get more bytes than in buffer"); buffer->end -= bytes; } /* Returns a pointer to the first used byte in the buffer. */ void * buffer_ptr(Buffer *buffer) { return buffer->buf + buffer->offset; } /* Dumps the contents of the buffer to stderr. */ void buffer_dump(Buffer *buffer) { int i; u_char *ucp = buffer->buf; for (i = buffer->offset; i < buffer->end; i++) { fprintf(stderr, "%02x", ucp[i]); if ((i-buffer->offset)%16==15) fprintf(stderr, "\r\n"); else if ((i-buffer->offset)%2==1) fprintf(stderr, " "); } fprintf(stderr, "\r\n"); } diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index 75d24ace2b41..cd2eab77a9c0 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -1,1371 +1,1369 @@ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * The main loop for the interactive session (client side). * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * * Copyright (c) 1999 Theo de Raadt. All rights reserved. * * 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. * * * SSH2 support added by Markus Friedl. * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.101 2002/06/09 13:32:01 markus Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.102 2002/06/24 14:33:27 markus Exp $"); #include "ssh.h" #include "ssh1.h" #include "ssh2.h" #include "xmalloc.h" #include "packet.h" #include "buffer.h" #include "compat.h" #include "channels.h" #include "dispatch.h" #include "buffer.h" #include "bufaux.h" #include "key.h" #include "kex.h" #include "log.h" #include "readconf.h" #include "clientloop.h" #include "authfd.h" #include "atomicio.h" #include "sshtty.h" #include "misc.h" #include "readpass.h" /* import options */ extern Options options; /* Flag indicating that stdin should be redirected from /dev/null. */ extern int stdin_null_flag; /* * Name of the host we are connecting to. This is the name given on the * command line, or the HostName specified for the user-supplied name in a * configuration file. */ extern char *host; /* * Flag to indicate that we have received a window change signal which has * not yet been processed. This will cause a message indicating the new * window size to be sent to the server a little later. This is volatile * because this is updated in a signal handler. */ static volatile sig_atomic_t received_window_change_signal = 0; static volatile sig_atomic_t received_signal = 0; /* Flag indicating whether the user\'s terminal is in non-blocking mode. */ static int in_non_blocking_mode = 0; /* Common data for the client loop code. */ static int quit_pending; /* Set to non-zero to quit the client loop. */ static int escape_char; /* Escape character. */ static int escape_pending; /* Last character was the escape character */ static int last_was_cr; /* Last character was a newline. */ static int exit_status; /* Used to store the exit status of the command. */ static int stdin_eof; /* EOF has been encountered on standard error. */ static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ static Buffer stderr_buffer; /* Buffer for stderr data. */ static u_long stdin_bytes, stdout_bytes, stderr_bytes; static u_int buffer_high;/* Soft max buffer size. */ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ static int need_rekeying; /* Set to non-zero if rekeying is requested. */ static int session_closed = 0; /* In SSH2: login session closed. */ static void client_init_dispatch(void); int session_ident = -1; /*XXX*/ extern Kex *xxx_kex; /* Restores stdin to blocking mode. */ static void leave_non_blocking(void) { if (in_non_blocking_mode) { (void) fcntl(fileno(stdin), F_SETFL, 0); in_non_blocking_mode = 0; fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL); } } /* Puts stdin terminal in non-blocking mode. */ static void enter_non_blocking(void) { in_non_blocking_mode = 1; (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL); } /* * Signal handler for the window change signal (SIGWINCH). This just sets a * flag indicating that the window has changed. */ static void window_change_handler(int sig) { received_window_change_signal = 1; signal(SIGWINCH, window_change_handler); } /* * Signal handler for signals that cause the program to terminate. These * signals must be trapped to restore terminal modes. */ static void signal_handler(int sig) { received_signal = sig; quit_pending = 1; } /* * Returns current time in seconds from Jan 1, 1970 with the maximum * available resolution. */ static double get_current_time(void) { struct timeval tv; gettimeofday(&tv, NULL); return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; } /* * This is called when the interactive is entered. This checks if there is * an EOF coming on stdin. We must check this explicitly, as select() does * not appear to wake up when redirecting from /dev/null. */ static void client_check_initial_eof_on_stdin(void) { int len; char buf[1]; /* * If standard input is to be "redirected from /dev/null", we simply * mark that we have seen an EOF and send an EOF message to the * server. Otherwise, we try to read a single character; it appears * that for some files, such /dev/null, select() never wakes up for * read for this descriptor, which means that we never get EOF. This * way we will get the EOF if stdin comes from /dev/null or similar. */ if (stdin_null_flag) { /* Fake EOF on stdin. */ debug("Sending eof."); stdin_eof = 1; packet_start(SSH_CMSG_EOF); packet_send(); } else { enter_non_blocking(); /* Check for immediate EOF on stdin. */ len = read(fileno(stdin), buf, 1); if (len == 0) { /* EOF. Record that we have seen it and send EOF to server. */ debug("Sending eof."); stdin_eof = 1; packet_start(SSH_CMSG_EOF); packet_send(); } else if (len > 0) { /* * Got data. We must store the data in the buffer, * and also process it as an escape character if * appropriate. */ if ((u_char) buf[0] == escape_char) escape_pending = 1; else buffer_append(&stdin_buffer, buf, 1); } leave_non_blocking(); } } /* * Make packets from buffered stdin data, and buffer them for sending to the * connection. */ static void client_make_packets_from_stdin_data(void) { u_int len; /* Send buffered stdin data to the server. */ while (buffer_len(&stdin_buffer) > 0 && packet_not_very_much_data_to_write()) { len = buffer_len(&stdin_buffer); /* Keep the packets at reasonable size. */ if (len > packet_get_maxsize()) len = packet_get_maxsize(); packet_start(SSH_CMSG_STDIN_DATA); packet_put_string(buffer_ptr(&stdin_buffer), len); packet_send(); buffer_consume(&stdin_buffer, len); stdin_bytes += len; /* If we have a pending EOF, send it now. */ if (stdin_eof && buffer_len(&stdin_buffer) == 0) { packet_start(SSH_CMSG_EOF); packet_send(); } } } /* * Checks if the client window has changed, and sends a packet about it to * the server if so. The actual change is detected elsewhere (by a software * interrupt on Unix); this just checks the flag and sends a message if * appropriate. */ static void client_check_window_change(void) { struct winsize ws; if (! received_window_change_signal) return; /** XXX race */ received_window_change_signal = 0; if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) return; debug2("client_check_window_change: changed"); if (compat20) { channel_request_start(session_ident, "window-change", 0); packet_put_int(ws.ws_col); packet_put_int(ws.ws_row); packet_put_int(ws.ws_xpixel); packet_put_int(ws.ws_ypixel); packet_send(); } else { packet_start(SSH_CMSG_WINDOW_SIZE); packet_put_int(ws.ws_row); packet_put_int(ws.ws_col); packet_put_int(ws.ws_xpixel); packet_put_int(ws.ws_ypixel); packet_send(); } } /* * Waits until the client can do something (some data becomes available on * one of the file descriptors). */ static void client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, int *nallocp, int rekeying) { /* Add any selections by the channel mechanism. */ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); if (!compat20) { /* Read from the connection, unless our buffers are full. */ if (buffer_len(&stdout_buffer) < buffer_high && buffer_len(&stderr_buffer) < buffer_high && channel_not_very_much_buffered_data()) FD_SET(connection_in, *readsetp); /* * Read from stdin, unless we have seen EOF or have very much * buffered data to send to the server. */ if (!stdin_eof && packet_not_very_much_data_to_write()) FD_SET(fileno(stdin), *readsetp); /* Select stdout/stderr if have data in buffer. */ if (buffer_len(&stdout_buffer) > 0) FD_SET(fileno(stdout), *writesetp); if (buffer_len(&stderr_buffer) > 0) FD_SET(fileno(stderr), *writesetp); } else { /* channel_prepare_select could have closed the last channel */ if (session_closed && !channel_still_open() && !packet_have_data_to_write()) { /* clear mask since we did not call select() */ memset(*readsetp, 0, *nallocp); memset(*writesetp, 0, *nallocp); return; } else { FD_SET(connection_in, *readsetp); } } /* Select server connection if have data to write to the server. */ if (packet_have_data_to_write()) FD_SET(connection_out, *writesetp); /* * Wait for something to happen. This will suspend the process until * some selected descriptor can be read, written, or has some other * event pending. Note: if you want to implement SSH_MSG_IGNORE * messages to fool traffic analysis, this might be the place to do * it: just have a random timeout for the select, and send a random * SSH_MSG_IGNORE packet when the timeout expires. */ if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { char buf[100]; /* * We have to clear the select masks, because we return. * We have to return, because the mainloop checks for the flags * set by the signal handlers. */ memset(*readsetp, 0, *nallocp); memset(*writesetp, 0, *nallocp); if (errno == EINTR) return; /* Note: we might still have data in the buffers. */ snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; } } static void client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) { struct winsize oldws, newws; /* Flush stdout and stderr buffers. */ if (buffer_len(bout) > 0) atomicio(write, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); if (buffer_len(berr) > 0) atomicio(write, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); leave_raw_mode(); /* * Free (and clear) the buffer to reduce the amount of data that gets * written to swap. */ buffer_free(bin); buffer_free(bout); buffer_free(berr); /* Save old window size. */ ioctl(fileno(stdin), TIOCGWINSZ, &oldws); /* Send the suspend signal to the program itself. */ kill(getpid(), SIGTSTP); /* Check if the window size has changed. */ if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && (oldws.ws_row != newws.ws_row || oldws.ws_col != newws.ws_col || oldws.ws_xpixel != newws.ws_xpixel || oldws.ws_ypixel != newws.ws_ypixel)) received_window_change_signal = 1; /* OK, we have been continued by the user. Reinitialize buffers. */ buffer_init(bin); buffer_init(bout); buffer_init(berr); enter_raw_mode(); } static void client_process_net_input(fd_set * readset) { int len; char buf[8192]; /* * Read input from the server, and add any such data to the buffer of * the packet subsystem. */ if (FD_ISSET(connection_in, readset)) { /* Read as much as possible. */ len = read(connection_in, buf, sizeof(buf)); if (len == 0) { /* Received EOF. The remote host has closed the connection. */ snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", host); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; return; } /* * There is a kernel bug on Solaris that causes select to * sometimes wake up even though there is no data available. */ if (len < 0 && (errno == EAGAIN || errno == EINTR)) len = 0; if (len < 0) { /* An error has encountered. Perhaps there is a network problem. */ snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", host, strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; return; } packet_process_incoming(buf, len); } } static void process_cmdline(void) { void (*handler)(int); char *s, *cmd; u_short fwd_port, fwd_host_port; char buf[1024], sfwd_port[6], sfwd_host_port[6]; int local = 0; leave_raw_mode(); handler = signal(SIGINT, SIG_IGN); cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); if (s == NULL) goto out; while (*s && isspace(*s)) s++; if (*s == 0) goto out; if (strlen(s) < 2 || s[0] != '-' || !(s[1] == 'L' || s[1] == 'R')) { log("Invalid command."); goto out; } if (s[1] == 'L') local = 1; if (!local && !compat20) { log("Not supported for SSH protocol version 1."); goto out; } s += 2; while (*s && isspace(*s)) s++; if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]", sfwd_port, buf, sfwd_host_port) != 3 && sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]", sfwd_port, buf, sfwd_host_port) != 3) { log("Bad forwarding specification."); goto out; } if ((fwd_port = a2port(sfwd_port)) == 0 || (fwd_host_port = a2port(sfwd_host_port)) == 0) { log("Bad forwarding port(s)."); goto out; } if (local) { if (channel_setup_local_fwd_listener(fwd_port, buf, fwd_host_port, options.gateway_ports) < 0) { log("Port forwarding failed."); goto out; } } else channel_request_remote_forwarding(fwd_port, buf, fwd_host_port); log("Forwarding port."); out: signal(SIGINT, handler); enter_raw_mode(); if (cmd) xfree(cmd); } /* process the characters one by one */ static int process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) { char string[1024]; pid_t pid; int bytes = 0; u_int i; u_char ch; char *s; for (i = 0; i < len; i++) { /* Get one character at a time. */ ch = buf[i]; if (escape_pending) { /* We have previously seen an escape character. */ /* Clear the flag now. */ escape_pending = 0; /* Process the escaped character. */ switch (ch) { case '.': /* Terminate the connection. */ snprintf(string, sizeof string, "%c.\r\n", escape_char); buffer_append(berr, string, strlen(string)); quit_pending = 1; return -1; case 'Z' - 64: /* Suspend the program. */ /* Print a message to that effect to the user. */ snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); buffer_append(berr, string, strlen(string)); /* Restore terminal modes and suspend. */ client_suspend_self(bin, bout, berr); /* We have been continued. */ continue; case 'R': if (compat20) { if (datafellows & SSH_BUG_NOREKEY) log("Server does not support re-keying"); else need_rekeying = 1; } continue; case '&': /* * Detach the program (continue to serve connections, * but put in background and no more new connections). */ /* Restore tty modes. */ leave_raw_mode(); /* Stop listening for new connections. */ channel_stop_listening(); snprintf(string, sizeof string, "%c& [backgrounded]\n", escape_char); buffer_append(berr, string, strlen(string)); /* Fork into background. */ pid = fork(); if (pid < 0) { error("fork: %.100s", strerror(errno)); continue; } if (pid != 0) { /* This is the parent. */ /* The parent just exits. */ exit(0); } /* The child continues serving connections. */ if (compat20) { buffer_append(bin, "\004", 1); /* fake EOF on stdin */ return -1; } else if (!stdin_eof) { /* * Sending SSH_CMSG_EOF alone does not always appear * to be enough. So we try to send an EOF character * first. */ packet_start(SSH_CMSG_STDIN_DATA); packet_put_string("\004", 1); packet_send(); /* Close stdin. */ stdin_eof = 1; if (buffer_len(bin) == 0) { packet_start(SSH_CMSG_EOF); packet_send(); } } continue; case '?': snprintf(string, sizeof string, "%c?\r\n\ Supported escape sequences:\r\n\ ~. - terminate connection\r\n\ ~C - open a command line\r\n\ ~R - Request rekey (SSH protocol 2 only)\r\n\ ~^Z - suspend ssh\r\n\ ~# - list forwarded connections\r\n\ ~& - background ssh (when waiting for connections to terminate)\r\n\ ~? - this message\r\n\ ~~ - send the escape character by typing it twice\r\n\ (Note that escapes are only recognized immediately after newline.)\r\n", escape_char); buffer_append(berr, string, strlen(string)); continue; case '#': snprintf(string, sizeof string, "%c#\r\n", escape_char); buffer_append(berr, string, strlen(string)); s = channel_open_message(); buffer_append(berr, s, strlen(s)); xfree(s); continue; case 'C': process_cmdline(); continue; default: if (ch != escape_char) { buffer_put_char(bin, escape_char); bytes++; } /* Escaped characters fall through here */ break; } } else { /* * The previous character was not an escape char. Check if this * is an escape. */ if (last_was_cr && ch == escape_char) { /* It is. Set the flag and continue to next character. */ escape_pending = 1; continue; } } /* * Normal character. Record whether it was a newline, * and append it to the buffer. */ last_was_cr = (ch == '\r' || ch == '\n'); buffer_put_char(bin, ch); bytes++; } return bytes; } static void client_process_input(fd_set * readset) { int len; char buf[8192]; /* Read input from stdin. */ if (FD_ISSET(fileno(stdin), readset)) { /* Read as much as possible. */ len = read(fileno(stdin), buf, sizeof(buf)); if (len < 0 && (errno == EAGAIN || errno == EINTR)) return; /* we'll try again later */ if (len <= 0) { /* * Received EOF or error. They are treated * similarly, except that an error message is printed * if it was an error condition. */ if (len < 0) { snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); } /* Mark that we have seen EOF. */ stdin_eof = 1; /* * Send an EOF message to the server unless there is * data in the buffer. If there is data in the * buffer, no message will be sent now. Code * elsewhere will send the EOF when the buffer * becomes empty if stdin_eof is set. */ if (buffer_len(&stdin_buffer) == 0) { packet_start(SSH_CMSG_EOF); packet_send(); } } else if (escape_char == SSH_ESCAPECHAR_NONE) { /* * Normal successful read, and no escape character. * Just append the data to buffer. */ buffer_append(&stdin_buffer, buf, len); } else { /* * Normal, successful read. But we have an escape character * and have to process the characters one by one. */ if (process_escapes(&stdin_buffer, &stdout_buffer, &stderr_buffer, buf, len) == -1) return; } } } static void client_process_output(fd_set * writeset) { int len; char buf[100]; /* Write buffered output to stdout. */ if (FD_ISSET(fileno(stdout), writeset)) { /* Write as much data as possible. */ len = write(fileno(stdout), buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer)); if (len <= 0) { if (errno == EINTR || errno == EAGAIN) len = 0; else { /* * An error or EOF was encountered. Put an * error message to stderr buffer. */ snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; return; } } /* Consume printed data from the buffer. */ buffer_consume(&stdout_buffer, len); stdout_bytes += len; } /* Write buffered output to stderr. */ if (FD_ISSET(fileno(stderr), writeset)) { /* Write as much data as possible. */ len = write(fileno(stderr), buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer)); if (len <= 0) { if (errno == EINTR || errno == EAGAIN) len = 0; else { /* EOF or error, but can't even print error message. */ quit_pending = 1; return; } } /* Consume printed characters from the buffer. */ buffer_consume(&stderr_buffer, len); stderr_bytes += len; } } /* * Get packets from the connection input buffer, and process them as long as * there are packets available. * * Any unknown packets received during the actual * session cause the session to terminate. This is * intended to make debugging easier since no * confirmations are sent. Any compatible protocol * extensions must be negotiated during the * preparatory phase. */ static void client_process_buffered_input_packets(void) { dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); } /* scan buf[] for '~' before sending data to the peer */ static int simple_escape_filter(Channel *c, char *buf, int len) { /* XXX we assume c->extended is writeable */ return process_escapes(&c->input, &c->output, &c->extended, buf, len); } static void client_channel_closed(int id, void *arg) { if (id != session_ident) error("client_channel_closed: id %d != session_ident %d", id, session_ident); channel_cancel_cleanup(id); session_closed = 1; if (in_raw_mode()) leave_raw_mode(); } /* * Implements the interactive session with the server. This is called after * the user has been authenticated, and a command has been started on the * remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character * used as an escape character for terminating or suspending the session. */ int client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) { fd_set *readset = NULL, *writeset = NULL; double start_time, total_time; int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0; char buf[100]; debug("Entering interactive session."); start_time = get_current_time(); /* Initialize variables. */ escape_pending = 0; last_was_cr = 1; exit_status = -1; stdin_eof = 0; buffer_high = 64 * 1024; connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); max_fd = MAX(connection_in, connection_out); if (!compat20) { /* enable nonblocking unless tty */ if (!isatty(fileno(stdin))) set_nonblock(fileno(stdin)); if (!isatty(fileno(stdout))) set_nonblock(fileno(stdout)); if (!isatty(fileno(stderr))) set_nonblock(fileno(stderr)); max_fd = MAX(max_fd, fileno(stdin)); max_fd = MAX(max_fd, fileno(stdout)); max_fd = MAX(max_fd, fileno(stderr)); } stdin_bytes = 0; stdout_bytes = 0; stderr_bytes = 0; quit_pending = 0; escape_char = escape_char_arg; /* Initialize buffers. */ buffer_init(&stdin_buffer); buffer_init(&stdout_buffer); buffer_init(&stderr_buffer); client_init_dispatch(); /* Set signal handlers to restore non-blocking mode. */ signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); if (have_pty) signal(SIGWINCH, window_change_handler); if (have_pty) enter_raw_mode(); if (compat20) { session_ident = ssh2_chan_id; if (escape_char != SSH_ESCAPECHAR_NONE) channel_register_filter(session_ident, simple_escape_filter); if (session_ident != -1) channel_register_cleanup(session_ident, client_channel_closed); } else { /* Check if we should immediately send eof on stdin. */ client_check_initial_eof_on_stdin(); } /* Main loop of the client for the interactive session mode. */ while (!quit_pending) { /* Process buffered packets sent by the server. */ client_process_buffered_input_packets(); if (compat20 && session_closed && !channel_still_open()) break; rekeying = (xxx_kex != NULL && !xxx_kex->done); if (rekeying) { debug("rekeying in progress"); } else { /* * Make packets of buffered stdin data, and buffer * them for sending to the server. */ if (!compat20) client_make_packets_from_stdin_data(); /* * Make packets from buffered channel data, and * enqueue them for sending to the server. */ if (packet_not_very_much_data_to_write()) channel_output_poll(); /* * Check if the window size has changed, and buffer a * message about it to the server if so. */ client_check_window_change(); if (quit_pending) break; } /* * Wait until we have something to do (something becomes * available on one of the descriptors). */ max_fd2 = max_fd; client_wait_until_can_do_something(&readset, &writeset, &max_fd2, &nalloc, rekeying); if (quit_pending) break; /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); if (need_rekeying) { debug("user requests rekeying"); xxx_kex->done = 0; kex_send_kexinit(xxx_kex); need_rekeying = 0; } } /* Buffer input from the connection. */ client_process_net_input(readset); if (quit_pending) break; if (!compat20) { /* Buffer data from stdin */ client_process_input(readset); /* * Process output to stdout and stderr. Output to * the connection is processed elsewhere (above). */ client_process_output(writeset); } /* Send as much buffered packet data as possible to the sender. */ if (FD_ISSET(connection_out, writeset)) packet_write_poll(); } if (readset) xfree(readset); if (writeset) xfree(writeset); /* Terminate the session. */ /* Stop watching for window change. */ if (have_pty) signal(SIGWINCH, SIG_DFL); channel_free_all(); if (have_pty) leave_raw_mode(); /* restore blocking io */ if (!isatty(fileno(stdin))) unset_nonblock(fileno(stdin)); if (!isatty(fileno(stdout))) unset_nonblock(fileno(stdout)); if (!isatty(fileno(stderr))) unset_nonblock(fileno(stderr)); if (received_signal) { if (in_non_blocking_mode) /* XXX */ leave_non_blocking(); fatal("Killed by signal %d.", (int) received_signal); } /* * In interactive mode (with pseudo tty) display a message indicating * that the connection has been closed. */ if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); buffer_append(&stderr_buffer, buf, strlen(buf)); } /* Output any buffered data for stdout. */ while (buffer_len(&stdout_buffer) > 0) { len = write(fileno(stdout), buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer)); if (len <= 0) { error("Write failed flushing stdout buffer."); break; } buffer_consume(&stdout_buffer, len); stdout_bytes += len; } /* Output any buffered data for stderr. */ while (buffer_len(&stderr_buffer) > 0) { len = write(fileno(stderr), buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer)); if (len <= 0) { error("Write failed flushing stderr buffer."); break; } buffer_consume(&stderr_buffer, len); stderr_bytes += len; } /* Clear and free any buffers. */ memset(buf, 0, sizeof(buf)); buffer_free(&stdin_buffer); buffer_free(&stdout_buffer); buffer_free(&stderr_buffer); /* Report bytes transferred, and transfer rates. */ total_time = get_current_time() - start_time; debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", stdin_bytes, stdout_bytes, stderr_bytes, total_time); if (total_time > 0) debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", stdin_bytes / total_time, stdout_bytes / total_time, stderr_bytes / total_time); /* Return the exit status of the program. */ debug("Exit status %d", exit_status); return exit_status; } /*********/ static void client_input_stdout_data(int type, u_int32_t seq, void *ctxt) { u_int data_len; char *data = packet_get_string(&data_len); packet_check_eom(); buffer_append(&stdout_buffer, data, data_len); memset(data, 0, data_len); xfree(data); } static void client_input_stderr_data(int type, u_int32_t seq, void *ctxt) { u_int data_len; char *data = packet_get_string(&data_len); packet_check_eom(); buffer_append(&stderr_buffer, data, data_len); memset(data, 0, data_len); xfree(data); } static void client_input_exit_status(int type, u_int32_t seq, void *ctxt) { exit_status = packet_get_int(); packet_check_eom(); /* Acknowledge the exit. */ packet_start(SSH_CMSG_EXIT_CONFIRMATION); packet_send(); /* * Must wait for packet to be sent since we are * exiting the loop. */ packet_write_wait(); /* Flag that we want to exit. */ quit_pending = 1; } static Channel * client_request_forwarded_tcpip(const char *request_type, int rchan) { Channel* c = NULL; char *listen_address, *originator_address; int listen_port, originator_port; int sock; /* Get rest of the packet */ listen_address = packet_get_string(NULL); listen_port = packet_get_int(); originator_address = packet_get_string(NULL); originator_port = packet_get_int(); packet_check_eom(); debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", listen_address, listen_port, originator_address, originator_port); sock = channel_connect_by_listen_address(listen_port); if (sock < 0) { xfree(originator_address); xfree(listen_address); return NULL; } c = channel_new("forwarded-tcpip", SSH_CHANNEL_CONNECTING, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, xstrdup(originator_address), 1); xfree(originator_address); xfree(listen_address); return c; } static Channel* client_request_x11(const char *request_type, int rchan) { Channel *c = NULL; char *originator; int originator_port; int sock; if (!options.forward_x11) { error("Warning: ssh server tried X11 forwarding."); error("Warning: this is probably a break in attempt by a malicious server."); return NULL; } originator = packet_get_string(NULL); if (datafellows & SSH_BUG_X11FWD) { debug2("buggy server: x11 request w/o originator_port"); originator_port = 0; } else { originator_port = packet_get_int(); } packet_check_eom(); /* XXX check permission */ debug("client_request_x11: request from %s %d", originator, originator_port); xfree(originator); sock = x11_connect_display(); if (sock < 0) return NULL; c = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1); c->force_drain = 1; return c; } static Channel* client_request_agent(const char *request_type, int rchan) { Channel *c = NULL; int sock; if (!options.forward_agent) { error("Warning: ssh server tried agent forwarding."); error("Warning: this is probably a break in attempt by a malicious server."); return NULL; } sock = ssh_get_authentication_socket(); if (sock < 0) return NULL; c = channel_new("authentication agent connection", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, xstrdup("authentication agent connection"), 1); c->force_drain = 1; return c; } /* XXXX move to generic input handler */ static void client_input_channel_open(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; char *ctype; - u_int len; int rchan; - int rmaxpack; - int rwindow; + u_int rmaxpack, rwindow, len; ctype = packet_get_string(&len); rchan = packet_get_int(); rwindow = packet_get_int(); rmaxpack = packet_get_int(); debug("client_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "forwarded-tcpip") == 0) { c = client_request_forwarded_tcpip(ctype, rchan); } else if (strcmp(ctype, "x11") == 0) { c = client_request_x11(ctype, rchan); } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { c = client_request_agent(ctype, rchan); } /* XXX duplicate : */ if (c != NULL) { debug("confirm %s", ctype); c->remote_id = rchan; c->remote_window = rwindow; c->remote_maxpacket = rmaxpack; if (c->type != SSH_CHANNEL_CONNECTING) { packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); packet_put_int(c->remote_id); packet_put_int(c->self); packet_put_int(c->local_window); packet_put_int(c->local_maxpacket); packet_send(); } } else { debug("failure %s", ctype); packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(rchan); packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); if (!(datafellows & SSH_BUG_OPENFAILURE)) { packet_put_cstring("open failed"); packet_put_cstring(""); } packet_send(); } xfree(ctype); } static void client_input_channel_req(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; int id, reply, success = 0; char *rtype; id = packet_get_int(); rtype = packet_get_string(NULL); reply = packet_get_char(); debug("client_input_channel_req: channel %d rtype %s reply %d", id, rtype, reply); if (session_ident == -1) { error("client_input_channel_req: no channel %d", session_ident); } else if (id != session_ident) { error("client_input_channel_req: channel %d: wrong channel: %d", session_ident, id); } c = channel_lookup(id); if (c == NULL) { error("client_input_channel_req: channel %d: unknown channel", id); } else if (strcmp(rtype, "exit-status") == 0) { success = 1; exit_status = packet_get_int(); packet_check_eom(); } if (reply) { packet_start(success ? SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); packet_put_int(c->remote_id); packet_send(); } xfree(rtype); } static void client_input_global_request(int type, u_int32_t seq, void *ctxt) { char *rtype; int want_reply; int success = 0; rtype = packet_get_string(NULL); want_reply = packet_get_char(); debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply); if (want_reply) { packet_start(success ? SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); packet_send(); packet_write_wait(); } xfree(rtype); } static void client_init_dispatch_20(void) { dispatch_init(&dispatch_protocol_error); dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open); dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); /* rekeying */ dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); /* global request reply messages */ dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); } static void client_init_dispatch_13(void) { dispatch_init(NULL); dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? &auth_input_open_request : &deny_input_open); dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? &x11_input_open : &deny_input_open); } static void client_init_dispatch_15(void) { client_init_dispatch_13(); dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); } static void client_init_dispatch(void) { if (compat20) client_init_dispatch_20(); else if (compat13) client_init_dispatch_13(); else client_init_dispatch_15(); } diff --git a/crypto/openssh/defines.h b/crypto/openssh/defines.h index 1f52c545cae3..b87dbc51e325 100644 --- a/crypto/openssh/defines.h +++ b/crypto/openssh/defines.h @@ -1,542 +1,545 @@ #ifndef _DEFINES_H #define _DEFINES_H -/* $Id: defines.h,v 1.90 2002/06/07 03:19:36 mouring Exp $ */ +/* $Id: defines.h,v 1.92 2002/06/24 16:26:49 stevesk Exp $ */ /* Constants */ #ifndef SHUT_RDWR enum { SHUT_RD = 0, /* No more receptions. */ SHUT_WR, /* No more transmissions. */ SHUT_RDWR /* No more receptions or transmissions. */ }; # define SHUT_RD SHUT_RD # define SHUT_WR SHUT_WR # define SHUT_RDWR SHUT_RDWR #endif #ifndef IPTOS_LOWDELAY # define IPTOS_LOWDELAY 0x10 # define IPTOS_THROUGHPUT 0x08 # define IPTOS_RELIABILITY 0x04 # define IPTOS_LOWCOST 0x02 # define IPTOS_MINCOST IPTOS_LOWCOST #endif /* IPTOS_LOWDELAY */ #ifndef MAXPATHLEN # ifdef PATH_MAX # define MAXPATHLEN PATH_MAX # else /* PATH_MAX */ # define MAXPATHLEN 64 /* Should be safe */ # endif /* PATH_MAX */ #endif /* MAXPATHLEN */ #ifndef STDIN_FILENO # define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO # define STDERR_FILENO 2 #endif #ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */ #ifdef NGROUPS #define NGROUPS_MAX NGROUPS #else #define NGROUPS_MAX 0 #endif #endif #ifndef O_NONBLOCK /* Non Blocking Open */ # define O_NONBLOCK 00004 #endif #ifndef S_ISDIR # define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) #endif /* S_ISDIR */ #ifndef S_ISREG # define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) #endif /* S_ISREG */ #ifndef S_ISLNK # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #endif /* S_ISLNK */ #ifndef S_IXUSR # define S_IXUSR 0000100 /* execute/search permission, */ # define S_IXGRP 0000010 /* execute/search permission, */ # define S_IXOTH 0000001 /* execute/search permission, */ # define _S_IWUSR 0000200 /* write permission, */ # define S_IWUSR _S_IWUSR /* write permission, owner */ # define S_IWGRP 0000020 /* write permission, group */ # define S_IWOTH 0000002 /* write permission, other */ # define S_IRUSR 0000400 /* read permission, owner */ # define S_IRGRP 0000040 /* read permission, group */ # define S_IROTH 0000004 /* read permission, other */ # define S_IRWXU 0000700 /* read, write, execute */ # define S_IRWXG 0000070 /* read, write, execute */ # define S_IRWXO 0000007 /* read, write, execute */ #endif /* S_IXUSR */ #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) #define MAP_ANON MAP_ANONYMOUS #endif #ifndef MAP_FAILED # define MAP_FAILED ((void *)-1) #endif /* *-*-nto-qnx doesn't define this constant in the system headers */ #ifdef MISSING_NFDBITS # define NFDBITS (8 * sizeof(unsigned long)) #endif /* SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but including rpc/rpc.h breaks Solaris 6 */ #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK ((ulong)0x7f000001) #endif /* Types */ /* If sys/types.h does not supply intXX_t, supply them ourselves */ /* (or die trying) */ #ifndef HAVE_U_INT typedef unsigned int u_int; #endif #ifndef HAVE_INTXX_T # if (SIZEOF_CHAR == 1) typedef char int8_t; # else # error "8 bit int type not found." # endif # if (SIZEOF_SHORT_INT == 2) typedef short int int16_t; # else # ifdef _CRAY # if (SIZEOF_SHORT_INT == 4) typedef short int16_t; # else typedef long int16_t; # endif # else # error "16 bit int type not found." # endif /* _CRAY */ # endif # if (SIZEOF_INT == 4) typedef int int32_t; # else # ifdef _CRAY typedef long int32_t; # else # error "32 bit int type not found." # endif /* _CRAY */ # endif #endif /* If sys/types.h does not supply u_intXX_t, supply them ourselves */ #ifndef HAVE_U_INTXX_T # ifdef HAVE_UINTXX_T typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; # define HAVE_U_INTXX_T 1 # else # if (SIZEOF_CHAR == 1) typedef unsigned char u_int8_t; # else # error "8 bit int type not found." # endif # if (SIZEOF_SHORT_INT == 2) typedef unsigned short int u_int16_t; # else # ifdef _CRAY # if (SIZEOF_SHORT_INT == 4) typedef unsigned short u_int16_t; # else typedef unsigned long u_int16_t; # endif # else # error "16 bit int type not found." # endif # endif # if (SIZEOF_INT == 4) typedef unsigned int u_int32_t; # else # ifdef _CRAY typedef unsigned long u_int32_t; # else # error "32 bit int type not found." # endif # endif # endif #define __BIT_TYPES_DEFINED__ #endif /* 64-bit types */ #ifndef HAVE_INT64_T # if (SIZEOF_LONG_INT == 8) typedef long int int64_t; # define HAVE_INT64_T 1 # else # if (SIZEOF_LONG_LONG_INT == 8) typedef long long int int64_t; # define HAVE_INT64_T 1 # endif # endif #endif #ifndef HAVE_U_INT64_T # if (SIZEOF_LONG_INT == 8) typedef unsigned long int u_int64_t; # define HAVE_U_INT64_T 1 # else # if (SIZEOF_LONG_LONG_INT == 8) typedef unsigned long long int u_int64_t; # define HAVE_U_INT64_T 1 # endif # endif #endif #if !defined(HAVE_LONG_LONG_INT) && (SIZEOF_LONG_LONG_INT == 8) # define HAVE_LONG_LONG_INT 1 #endif #ifndef HAVE_U_CHAR typedef unsigned char u_char; # define HAVE_U_CHAR #endif /* HAVE_U_CHAR */ #ifndef HAVE_SIZE_T typedef unsigned int size_t; # define HAVE_SIZE_T #endif /* HAVE_SIZE_T */ #ifndef HAVE_SSIZE_T typedef int ssize_t; # define HAVE_SSIZE_T #endif /* HAVE_SSIZE_T */ #ifndef HAVE_CLOCK_T typedef long clock_t; # define HAVE_CLOCK_T #endif /* HAVE_CLOCK_T */ #ifndef HAVE_SA_FAMILY_T typedef int sa_family_t; # define HAVE_SA_FAMILY_T #endif /* HAVE_SA_FAMILY_T */ #ifndef HAVE_PID_T typedef int pid_t; # define HAVE_PID_T #endif /* HAVE_PID_T */ #ifndef HAVE_SIG_ATOMIC_T typedef int sig_atomic_t; # define HAVE_SIG_ATOMIC_T #endif /* HAVE_SIG_ATOMIC_T */ #ifndef HAVE_MODE_T typedef int mode_t; # define HAVE_MODE_T #endif /* HAVE_MODE_T */ #if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS) # define ss_family __ss_family #endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */ #ifndef HAVE_SYS_UN_H struct sockaddr_un { short sun_family; /* AF_UNIX */ char sun_path[108]; /* path name (gag) */ }; #endif /* HAVE_SYS_UN_H */ #if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE) #define _STRUCT_WINSIZE struct winsize { unsigned short ws_row; /* rows, in characters */ unsigned short ws_col; /* columns, in character */ unsigned short ws_xpixel; /* horizontal size, pixels */ unsigned short ws_ypixel; /* vertical size, pixels */ }; #endif /* *-*-nto-qnx does not define this type in the system headers */ #ifdef MISSING_FD_MASK typedef unsigned long int fd_mask; #endif /* Paths */ #ifndef _PATH_BSHELL # define _PATH_BSHELL "/bin/sh" #endif #ifndef _PATH_CSHELL # define _PATH_CSHELL "/bin/csh" #endif #ifndef _PATH_SHELLS # define _PATH_SHELLS "/etc/shells" #endif #ifdef USER_PATH # ifdef _PATH_STDPATH # undef _PATH_STDPATH # endif # define _PATH_STDPATH USER_PATH #endif #ifndef _PATH_STDPATH # define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" #endif #ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" #endif #ifndef MAIL_DIRECTORY # define MAIL_DIRECTORY "/var/spool/mail" #endif #ifndef MAILDIR # define MAILDIR MAIL_DIRECTORY #endif #if !defined(_PATH_MAILDIR) && defined(MAILDIR) # define _PATH_MAILDIR MAILDIR #endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */ -#ifndef _PATH_RSH -# ifdef RSH_PATH -# define _PATH_RSH RSH_PATH -# else /* RSH_PATH */ -# define _PATH_RSH "/usr/bin/rsh" -# endif /* RSH_PATH */ -#endif /* _PATH_RSH */ - #ifndef _PATH_NOLOGIN # define _PATH_NOLOGIN "/etc/nologin" #endif /* Define this to be the path of the xauth program. */ #ifdef XAUTH_PATH #define _PATH_XAUTH XAUTH_PATH #endif /* XAUTH_PATH */ /* derived from XF4/xc/lib/dps/Xlibnet.h */ #ifndef X_UNIX_PATH # ifdef __hpux # define X_UNIX_PATH "/var/spool/sockets/X11/%u" # else # define X_UNIX_PATH "/tmp/.X11-unix/X%u" # endif #endif /* X_UNIX_PATH */ #define _PATH_UNIX_X X_UNIX_PATH #ifndef _PATH_TTY # define _PATH_TTY "/dev/tty" #endif /* Macros */ #if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H) # define HAVE_LOGIN_CAP #endif #ifndef MAX # define MAX(a,b) (((a)>(b))?(a):(b)) # define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef roundup # define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #ifndef timersub #define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif #ifndef __P # define __P(x) x #endif #if !defined(IN6_IS_ADDR_V4MAPPED) # define IN6_IS_ADDR_V4MAPPED(a) \ ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ (((u_int32_t *) (a))[2] == htonl (0xffff))) #endif /* !defined(IN6_IS_ADDR_V4MAPPED) */ #if !defined(__GNUC__) || (__GNUC__ < 2) # define __attribute__(x) #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ /* *-*-nto-qnx doesn't define this macro in the system headers */ #ifdef MISSING_HOWMANY # define howmany(x,y) (((x)+((y)-1))/(y)) #endif #ifndef OSSH_ALIGNBYTES #define OSSH_ALIGNBYTES (sizeof(int) - 1) #endif #ifndef __CMSG_ALIGN #define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES) #endif /* Length of the contents of a control message of length len */ #ifndef CMSG_LEN #define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) #endif /* Length of the space taken up by a padded control message of length len */ #ifndef CMSG_SPACE #define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len)) #endif /* Function replacement / compatibility hacks */ #if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO)) # define HAVE_GETADDRINFO #endif #ifndef HAVE_GETOPT_OPTRESET -#define getopt(ac, av, o) BSDgetopt(ac, av, o) +# undef getopt +# undef opterr +# undef optind +# undef optopt +# undef optreset +# undef optarg +# define getopt(ac, av, o) BSDgetopt(ac, av, o) +# define opterr BSDopterr +# define optind BSDoptind +# define optopt BSDoptopt +# define optreset BSDoptreset +# define optarg BSDoptarg #endif /* In older versions of libpam, pam_strerror takes a single argument */ #ifdef HAVE_OLD_PAM # define PAM_STRERROR(a,b) pam_strerror((b)) #else # define PAM_STRERROR(a,b) pam_strerror((a),(b)) #endif #ifdef PAM_SUN_CODEBASE # define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member) #else # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member) #endif #if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) # undef HAVE_GETADDRINFO #endif #if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO) # undef HAVE_FREEADDRINFO #endif #if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR) # undef HAVE_GAI_STRERROR #endif #if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) # define memmove(s1, s2, n) bcopy((s2), (s1), (n)) #endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ #if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) # define USE_VHANGUP #endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */ #ifndef GETPGRP_VOID # define getpgrp() getpgrp(0) #endif /* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ #if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) # define OPENSSL_free(x) Free(x) #endif #if !defined(HAVE___func__) && defined(HAVE___FUNCTION__) # define __func__ __FUNCTION__ #elif !defined(HAVE___func__) # define __func__ "" #endif /* * Define this to use pipes instead of socketpairs for communicating with the * client program. Socketpairs do not seem to work on all systems. * * configure.ac sets this for a few OS's which are known to have problems * but you may need to set it yourself */ /* #define USE_PIPES 1 */ /** ** login recorder definitions **/ /* FIXME: put default paths back in */ #ifndef UTMP_FILE # ifdef _PATH_UTMP # define UTMP_FILE _PATH_UTMP # else # ifdef CONF_UTMP_FILE # define UTMP_FILE CONF_UTMP_FILE # endif # endif #endif #ifndef WTMP_FILE # ifdef _PATH_WTMP # define WTMP_FILE _PATH_WTMP # else # ifdef CONF_WTMP_FILE # define WTMP_FILE CONF_WTMP_FILE # endif # endif #endif /* pick up the user's location for lastlog if given */ #ifndef LASTLOG_FILE # ifdef _PATH_LASTLOG # define LASTLOG_FILE _PATH_LASTLOG # else # ifdef CONF_LASTLOG_FILE # define LASTLOG_FILE CONF_LASTLOG_FILE # endif # endif #endif /* The login() library function in libutil is first choice */ #if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN) # define USE_LOGIN #else /* Simply select your favourite login types. */ /* Can't do if-else because some systems use several... */ # if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX) # define USE_UTMPX # endif # if defined(UTMP_FILE) && !defined(DISABLE_UTMP) # define USE_UTMP # endif # if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) # define USE_WTMPX # endif # if defined(WTMP_FILE) && !defined(DISABLE_WTMP) # define USE_WTMP # endif #endif /* I hope that the presence of LASTLOG_FILE is enough to detect this */ #if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG) # define USE_LASTLOG #endif /** end of login recorder definitions */ #endif /* _DEFINES_H */ diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c index d079ab0e388a..bdbf3882c82b 100644 --- a/crypto/openssh/kex.c +++ b/crypto/openssh/kex.c @@ -1,473 +1,473 @@ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.50 2002/05/15 15:47:49 mouring Exp $"); +RCSID("$OpenBSD: kex.c,v 1.51 2002/06/24 14:55:38 markus Exp $"); #include #include "ssh2.h" #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" #include "packet.h" #include "compat.h" #include "cipher.h" #include "kex.h" #include "key.h" #include "log.h" #include "mac.h" #include "match.h" #include "dispatch.h" #include "monitor.h" #define KEX_COOKIE_LEN 16 /* Use privilege separation for sshd */ int use_privsep; struct monitor *pmonitor; /* prototype */ static void kex_kexinit_finish(Kex *); static void kex_choose_conf(Kex *); /* put algorithm proposal into buffer */ static void kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) { int i; buffer_clear(b); /* * add a dummy cookie, the cookie will be overwritten by * kex_send_kexinit(), each time a kexinit is set */ for (i = 0; i < KEX_COOKIE_LEN; i++) buffer_put_char(b, 0); for (i = 0; i < PROPOSAL_MAX; i++) buffer_put_cstring(b, proposal[i]); buffer_put_char(b, 0); /* first_kex_packet_follows */ buffer_put_int(b, 0); /* uint32 reserved */ } /* parse buffer and return algorithm proposal */ static char ** kex_buf2prop(Buffer *raw) { Buffer b; int i; char **proposal; proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); buffer_init(&b); buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); /* skip cookie */ for (i = 0; i < KEX_COOKIE_LEN; i++) buffer_get_char(&b); /* extract kex init proposal strings */ for (i = 0; i < PROPOSAL_MAX; i++) { proposal[i] = buffer_get_string(&b,NULL); debug2("kex_parse_kexinit: %s", proposal[i]); } /* first kex follows / reserved */ i = buffer_get_char(&b); debug2("kex_parse_kexinit: first_kex_follows %d ", i); i = buffer_get_int(&b); debug2("kex_parse_kexinit: reserved %d ", i); buffer_free(&b); return proposal; } static void kex_prop_free(char **proposal) { int i; for (i = 0; i < PROPOSAL_MAX; i++) xfree(proposal[i]); xfree(proposal); } static void kex_protocol_error(int type, u_int32_t seq, void *ctxt) { error("Hm, kex protocol error: type %d seq %u", type, seq); } static void kex_reset_dispatch(void) { dispatch_range(SSH2_MSG_TRANSPORT_MIN, SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); } void kex_finish(Kex *kex) { kex_reset_dispatch(); packet_start(SSH2_MSG_NEWKEYS); packet_send(); /* packet_write_wait(); */ debug("SSH2_MSG_NEWKEYS sent"); debug("waiting for SSH2_MSG_NEWKEYS"); packet_read_expect(SSH2_MSG_NEWKEYS); packet_check_eom(); debug("SSH2_MSG_NEWKEYS received"); kex->done = 1; buffer_clear(&kex->peer); /* buffer_clear(&kex->my); */ kex->flags &= ~KEX_INIT_SENT; xfree(kex->name); kex->name = NULL; } void kex_send_kexinit(Kex *kex) { u_int32_t rand = 0; u_char *cookie; int i; if (kex == NULL) { error("kex_send_kexinit: no kex, cannot rekey"); return; } if (kex->flags & KEX_INIT_SENT) { debug("KEX_INIT_SENT"); return; } kex->done = 0; /* generate a random cookie */ if (buffer_len(&kex->my) < KEX_COOKIE_LEN) fatal("kex_send_kexinit: kex proposal too short"); cookie = buffer_ptr(&kex->my); for (i = 0; i < KEX_COOKIE_LEN; i++) { if (i % 4 == 0) rand = arc4random(); cookie[i] = rand; rand >>= 8; } packet_start(SSH2_MSG_KEXINIT); packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); packet_send(); debug("SSH2_MSG_KEXINIT sent"); kex->flags |= KEX_INIT_SENT; } void kex_input_kexinit(int type, u_int32_t seq, void *ctxt) { char *ptr; int dlen; int i; Kex *kex = (Kex *)ctxt; debug("SSH2_MSG_KEXINIT received"); if (kex == NULL) fatal("kex_input_kexinit: no kex, cannot rekey"); ptr = packet_get_raw(&dlen); buffer_append(&kex->peer, ptr, dlen); /* discard packet */ for (i = 0; i < KEX_COOKIE_LEN; i++) packet_get_char(); for (i = 0; i < PROPOSAL_MAX; i++) xfree(packet_get_string(NULL)); - packet_get_char(); - packet_get_int(); + (void) packet_get_char(); + (void) packet_get_int(); packet_check_eom(); kex_kexinit_finish(kex); } Kex * kex_setup(char *proposal[PROPOSAL_MAX]) { Kex *kex; kex = xmalloc(sizeof(*kex)); memset(kex, 0, sizeof(*kex)); buffer_init(&kex->peer); buffer_init(&kex->my); kex_prop2buf(&kex->my, proposal); kex->done = 0; kex_send_kexinit(kex); /* we start */ kex_reset_dispatch(); return kex; } static void kex_kexinit_finish(Kex *kex) { if (!(kex->flags & KEX_INIT_SENT)) kex_send_kexinit(kex); kex_choose_conf(kex); switch (kex->kex_type) { case DH_GRP1_SHA1: kexdh(kex); break; case DH_GEX_SHA1: kexgex(kex); break; default: fatal("Unsupported key exchange %d", kex->kex_type); } } static void choose_enc(Enc *enc, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); if ((enc->cipher = cipher_by_name(name)) == NULL) fatal("matching cipher is not supported: %s", name); enc->name = name; enc->enabled = 0; enc->iv = NULL; enc->key = NULL; enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); } static void choose_mac(Mac *mac, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching mac found: client %s server %s", client, server); if (mac_init(mac, name) < 0) fatal("unsupported mac %s", name); /* truncate the key */ if (datafellows & SSH_BUG_HMAC) mac->key_len = 16; mac->name = name; mac->key = NULL; mac->enabled = 0; } static void choose_comp(Comp *comp, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching comp found: client %s server %s", client, server); if (strcmp(name, "zlib") == 0) { comp->type = 1; } else if (strcmp(name, "none") == 0) { comp->type = 0; } else { fatal("unsupported comp %s", name); } comp->name = name; } static void choose_kex(Kex *k, char *client, char *server) { k->name = match_list(client, server, NULL); if (k->name == NULL) fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { k->kex_type = DH_GRP1_SHA1; } else if (strcmp(k->name, KEX_DHGEX) == 0) { k->kex_type = DH_GEX_SHA1; } else fatal("bad kex alg %s", k->name); } static void choose_hostkeyalg(Kex *k, char *client, char *server) { char *hostkeyalg = match_list(client, server, NULL); if (hostkeyalg == NULL) fatal("no hostkey alg"); k->hostkey_type = key_type_from_name(hostkeyalg); if (k->hostkey_type == KEY_UNSPEC) fatal("bad hostkey alg '%s'", hostkeyalg); xfree(hostkeyalg); } static void kex_choose_conf(Kex *kex) { Newkeys *newkeys; char **my, **peer; char **cprop, **sprop; int nenc, nmac, ncomp; int mode; int ctos; /* direction: if true client-to-server */ int need; my = kex_buf2prop(&kex->my); peer = kex_buf2prop(&kex->peer); if (kex->server) { cprop=peer; sprop=my; } else { cprop=my; sprop=peer; } /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { newkeys = xmalloc(sizeof(*newkeys)); memset(newkeys, 0, sizeof(*newkeys)); kex->newkeys[mode] = newkeys; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); } choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); need = 0; for (mode = 0; mode < MODE_MAX; mode++) { newkeys = kex->newkeys[mode]; if (need < newkeys->enc.key_len) need = newkeys->enc.key_len; if (need < newkeys->enc.block_size) need = newkeys->enc.block_size; if (need < newkeys->mac.key_len) need = newkeys->mac.key_len; } /* XXX need runden? */ kex->we_need = need; kex_prop_free(my); kex_prop_free(peer); } static u_char * derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) { Buffer b; const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; char c = id; int have; int mdsz = EVP_MD_size(evp_md); u_char *digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); buffer_put_bignum2(&b, shared_secret); /* K1 = HASH(K || H || "A" || session_id) */ EVP_DigestInit(&md, evp_md); if (!(datafellows & SSH_BUG_DERIVEKEY)) EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); EVP_DigestUpdate(&md, hash, mdsz); EVP_DigestUpdate(&md, &c, 1); EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); EVP_DigestFinal(&md, digest, NULL); /* * expand key: * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { EVP_DigestInit(&md, evp_md); if (!(datafellows & SSH_BUG_DERIVEKEY)) EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); EVP_DigestUpdate(&md, hash, mdsz); EVP_DigestUpdate(&md, digest, have); EVP_DigestFinal(&md, digest + have, NULL); } buffer_free(&b); #ifdef DEBUG_KEX fprintf(stderr, "key '%c'== ", c); dump_digest("key", digest, need); #endif return digest; } Newkeys *current_keys[MODE_MAX]; #define NKEYS 6 void kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) { u_char *keys[NKEYS]; int i, mode, ctos; for (i = 0; i < NKEYS; i++) keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); debug("kex_derive_keys"); for (mode = 0; mode < MODE_MAX; mode++) { current_keys[mode] = kex->newkeys[mode]; kex->newkeys[mode] = NULL; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; } } Newkeys * kex_get_newkeys(int mode) { Newkeys *ret; ret = current_keys[mode]; current_keys[mode] = NULL; return ret; } #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) void dump_digest(char *msg, u_char *digest, int len) { int i; fprintf(stderr, "%s\n", msg); for (i = 0; i< len; i++) { fprintf(stderr, "%02x", digest[i]); if (i%32 == 31) fprintf(stderr, "\n"); else if (i%8 == 7) fprintf(stderr, " "); } fprintf(stderr, "\n"); } #endif diff --git a/crypto/openssh/monitor_fdpass.h b/crypto/openssh/monitor_fdpass.h index cb12c41e2820..31d080e21ed6 100644 --- a/crypto/openssh/monitor_fdpass.h +++ b/crypto/openssh/monitor_fdpass.h @@ -1,34 +1,34 @@ -/* $OpenBSD: monitor_fdpass.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ +/* $OpenBSD: monitor_fdpass.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _MM_FDPASS_H_ #define _MM_FDPASS_H_ void mm_send_fd(int, int); int mm_receive_fd(int); #endif /* _MM_FDPASS_H_ */ diff --git a/crypto/openssh/monitor_mm.c b/crypto/openssh/monitor_mm.c index 0076c4210d79..c363036e6720 100644 --- a/crypto/openssh/monitor_mm.c +++ b/crypto/openssh/monitor_mm.c @@ -1,342 +1,342 @@ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" RCSID("$OpenBSD: monitor_mm.c,v 1.6 2002/06/04 23:05:49 markus Exp $"); #ifdef HAVE_SYS_MMAN_H #include #endif #include "ssh.h" #include "xmalloc.h" #include "log.h" #include "monitor_mm.h" static int mm_compare(struct mm_share *a, struct mm_share *b) { return ((char *)a->address - (char *)b->address); } RB_GENERATE(mmtree, mm_share, next, mm_compare) static struct mm_share * mm_make_entry(struct mm_master *mm, struct mmtree *head, void *address, size_t size) { struct mm_share *tmp, *tmp2; if (mm->mmalloc == NULL) tmp = xmalloc(sizeof(struct mm_share)); else tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); tmp->address = address; tmp->size = size; tmp2 = RB_INSERT(mmtree, head, tmp); if (tmp2 != NULL) fatal("mm_make_entry(%p): double address %p->%p(%lu)", mm, tmp2, address, (u_long)size); return (tmp); } /* Creates a shared memory area of a certain size */ struct mm_master * mm_create(struct mm_master *mmalloc, size_t size) { void *address; struct mm_master *mm; if (mmalloc == NULL) mm = xmalloc(sizeof(struct mm_master)); else mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); /* * If the memory map has a mm_master it can be completely * shared including authentication between the child * and the client. */ mm->mmalloc = mmalloc; -#if defined(HAVE_MMAP) && defined(MAP_ANON) +#ifdef HAVE_MMAP_ANON_SHARED address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, -1, 0); if (address == MAP_FAILED) fatal("mmap(%lu): %s", (u_long)size, strerror(errno)); #else - fatal("%s: UsePrivilegeSeparation=yes not supported", + fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", __func__); #endif mm->address = address; mm->size = size; RB_INIT(&mm->rb_free); RB_INIT(&mm->rb_allocated); mm_make_entry(mm, &mm->rb_free, address, size); return (mm); } /* Frees either the allocated or the free list */ static void mm_freelist(struct mm_master *mmalloc, struct mmtree *head) { struct mm_share *mms, *next; for (mms = RB_ROOT(head); mms; mms = next) { next = RB_NEXT(mmtree, head, mms); RB_REMOVE(mmtree, head, mms); if (mmalloc == NULL) xfree(mms); else mm_free(mmalloc, mms); } } /* Destroys a memory mapped area */ void mm_destroy(struct mm_master *mm) { mm_freelist(mm->mmalloc, &mm->rb_free); mm_freelist(mm->mmalloc, &mm->rb_allocated); -#ifdef HAVE_MMAP +#ifdef HAVE_MMAP_ANON_SHARED if (munmap(mm->address, mm->size) == -1) fatal("munmap(%p, %lu): %s", mm->address, (u_long)mm->size, strerror(errno)); #else - fatal("%s: UsePrivilegeSeparation=yes not supported", + fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", __func__); #endif if (mm->mmalloc == NULL) xfree(mm); else mm_free(mm->mmalloc, mm); } void * mm_xmalloc(struct mm_master *mm, size_t size) { void *address; address = mm_malloc(mm, size); if (address == NULL) fatal("%s: mm_malloc(%lu)", __func__, (u_long)size); return (address); } /* Allocates data from a memory mapped area */ void * mm_malloc(struct mm_master *mm, size_t size) { struct mm_share *mms, *tmp; if (size == 0) fatal("mm_malloc: try to allocate 0 space"); size = ((size + MM_MINSIZE - 1) / MM_MINSIZE) * MM_MINSIZE; RB_FOREACH(mms, mmtree, &mm->rb_free) { if (mms->size >= size) break; } if (mms == NULL) return (NULL); /* Debug */ memset(mms->address, 0xd0, size); tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); /* Does not change order in RB tree */ mms->size -= size; mms->address = (u_char *)mms->address + size; if (mms->size == 0) { RB_REMOVE(mmtree, &mm->rb_free, mms); if (mm->mmalloc == NULL) xfree(mms); else mm_free(mm->mmalloc, mms); } return (tmp->address); } /* Frees memory in a memory mapped area */ void mm_free(struct mm_master *mm, void *address) { struct mm_share *mms, *prev, tmp; tmp.address = address; mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); if (mms == NULL) fatal("mm_free(%p): can not find %p", mm, address); /* Debug */ memset(mms->address, 0xd0, mms->size); /* Remove from allocated list and insert in free list */ RB_REMOVE(mmtree, &mm->rb_allocated, mms); if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) fatal("mm_free(%p): double address %p", mm, address); /* Find previous entry */ prev = mms; if (RB_LEFT(prev, next)) { prev = RB_LEFT(prev, next); while (RB_RIGHT(prev, next)) prev = RB_RIGHT(prev, next); } else { if (RB_PARENT(prev, next) && (prev == RB_RIGHT(RB_PARENT(prev, next), next))) prev = RB_PARENT(prev, next); else { while (RB_PARENT(prev, next) && (prev == RB_LEFT(RB_PARENT(prev, next), next))) prev = RB_PARENT(prev, next); prev = RB_PARENT(prev, next); } } /* Check if range does not overlap */ if (prev != NULL && MM_ADDRESS_END(prev) > address) fatal("mm_free: memory corruption: %p(%lu) > %p", prev->address, (u_long)prev->size, address); /* See if we can merge backwards */ if (prev != NULL && MM_ADDRESS_END(prev) == address) { prev->size += mms->size; RB_REMOVE(mmtree, &mm->rb_free, mms); if (mm->mmalloc == NULL) xfree(mms); else mm_free(mm->mmalloc, mms); } else prev = mms; if (prev == NULL) return; /* Check if we can merge forwards */ mms = RB_NEXT(mmtree, &mm->rb_free, prev); if (mms == NULL) return; if (MM_ADDRESS_END(prev) > mms->address) fatal("mm_free: memory corruption: %p < %p(%lu)", mms->address, prev->address, (u_long)prev->size); if (MM_ADDRESS_END(prev) != mms->address) return; prev->size += mms->size; RB_REMOVE(mmtree, &mm->rb_free, mms); if (mm->mmalloc == NULL) xfree(mms); else mm_free(mm->mmalloc, mms); } static void mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, struct mm_master *mm, struct mm_master *mmold) { struct mm_master *mmalloc = mm->mmalloc; struct mm_share *mms, *new; /* Sync free list */ RB_FOREACH(mms, mmtree, oldtree) { /* Check the values */ mm_memvalid(mmold, mms, sizeof(struct mm_share)); mm_memvalid(mm, mms->address, mms->size); new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); memcpy(new, mms, sizeof(struct mm_share)); RB_INSERT(mmtree, newtree, new); } } void mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) { struct mm_master *mm; struct mm_master *mmalloc; struct mm_master *mmold; struct mmtree rb_free, rb_allocated; debug3("%s: Share sync", __func__); mm = *pmm; mmold = mm->mmalloc; mm_memvalid(mmold, mm, sizeof(*mm)); mmalloc = mm_create(NULL, mm->size); mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); memcpy(mm, *pmm, sizeof(struct mm_master)); mm->mmalloc = mmalloc; rb_free = mm->rb_free; rb_allocated = mm->rb_allocated; RB_INIT(&mm->rb_free); RB_INIT(&mm->rb_allocated); mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); mm_destroy(mmold); *pmm = mm; *pmmalloc = mmalloc; debug3("%s: Share sync end", __func__); } void mm_memvalid(struct mm_master *mm, void *address, size_t size) { void *end = (u_char *)address + size; if (address < mm->address) fatal("mm_memvalid: address too small: %p", address); if (end < address) fatal("mm_memvalid: end < address: %p < %p", end, address); if (end > (void *)((u_char *)mm->address + mm->size)) fatal("mm_memvalid: address too large: %p", address); } diff --git a/crypto/openssh/monitor_mm.h b/crypto/openssh/monitor_mm.h index c0af432d0ef3..c0a66d5e7c94 100644 --- a/crypto/openssh/monitor_mm.h +++ b/crypto/openssh/monitor_mm.h @@ -1,66 +1,66 @@ -/* $OpenBSD: monitor_mm.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ +/* $OpenBSD: monitor_mm.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _MM_H_ #define _MM_H_ #include "openbsd-compat/tree.h" struct mm_share { RB_ENTRY(mm_share) next; void *address; size_t size; }; struct mm_master { RB_HEAD(mmtree, mm_share) rb_free; struct mmtree rb_allocated; void *address; size_t size; struct mm_master *mmalloc; /* Used to completely share */ int write; /* used to writing to other party */ int read; /* used for reading from other party */ }; RB_PROTOTYPE(mmtree, mm_share, next, mm_compare) #define MM_MINSIZE 128 #define MM_ADDRESS_END(x) (void *)((u_char *)(x)->address + (x)->size) struct mm_master *mm_create(struct mm_master *, size_t); void mm_destroy(struct mm_master *); void mm_share_sync(struct mm_master **, struct mm_master **); void *mm_malloc(struct mm_master *, size_t); void *mm_xmalloc(struct mm_master *, size_t); void mm_free(struct mm_master *, void *); void mm_memvalid(struct mm_master *, void *, size_t); #endif /* _MM_H_ */ diff --git a/crypto/openssh/msg.c b/crypto/openssh/msg.c index 103aed2cde2c..7275c847dabb 100644 --- a/crypto/openssh/msg.c +++ b/crypto/openssh/msg.c @@ -1,73 +1,73 @@ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: msg.c,v 1.2 2002/06/19 00:27:55 deraadt Exp $"); +RCSID("$OpenBSD: msg.c,v 1.3 2002/06/24 15:49:22 itojun Exp $"); #include "buffer.h" #include "getput.h" #include "log.h" #include "atomicio.h" #include "msg.h" void msg_send(int fd, u_char type, Buffer *m) { u_char buf[5]; u_int mlen = buffer_len(m); - debug3("msg_send: type %d", type); + debug3("msg_send: type %u", (unsigned int)type & 0xff); PUT_32BIT(buf, mlen + 1); buf[4] = type; /* 1st byte of payload is mesg-type */ if (atomicio(write, fd, buf, sizeof(buf)) != sizeof(buf)) fatal("msg_send: write"); if (atomicio(write, fd, buffer_ptr(m), mlen) != mlen) fatal("msg_send: write"); } int msg_recv(int fd, Buffer *m) { u_char buf[4]; ssize_t res; u_int msg_len; debug3("msg_recv entering"); res = atomicio(read, fd, buf, sizeof(buf)); if (res != sizeof(buf)) { if (res == 0) return -1; - fatal("msg_recv: read: header %d", res); + fatal("msg_recv: read: header %ld", (long)res); } msg_len = GET_32BIT(buf); if (msg_len > 256 * 1024) fatal("msg_recv: read: bad msg_len %d", msg_len); buffer_clear(m); buffer_append_space(m, msg_len); res = atomicio(read, fd, buffer_ptr(m), msg_len); if (res != msg_len) fatal("msg_recv: read: %ld != msg_len", (long)res); return 0; } diff --git a/crypto/openssh/openbsd-compat/getopt.c b/crypto/openssh/openbsd-compat/getopt.c index 9e13504a0e4c..f4fbc9bac3ec 100644 --- a/crypto/openssh/openbsd-compat/getopt.c +++ b/crypto/openssh/openbsd-compat/getopt.c @@ -1,122 +1,122 @@ /* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: getopt.c,v 1.2 1996/08/19 08:33:32 tholo Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include -int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt, /* character checked for validity */ - optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ +int BSDopterr = 1, /* if error message should be printed */ + BSDoptind = 1, /* index into parent argv vector */ + BSDoptopt, /* character checked for validity */ + BSDoptreset; /* reset getopt */ +char *BSDoptarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int BSDgetopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { extern char *__progname; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc || *(place = nargv[optind]) != '-') { + if (BSDoptreset || !*place) { /* update scanning pointer */ + BSDoptreset = 0; + if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ - ++optind; + ++BSDoptind; place = EMSG; return (-1); } } /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, optopt))) { + if ((BSDoptopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, BSDoptopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ - if (optopt == (int)'-') + if (BSDoptopt == (int)'-') return (-1); if (!*place) - ++optind; - if (opterr && *ostr != ':') + ++BSDoptind; + if (BSDopterr && *ostr != ':') (void)fprintf(stderr, - "%s: illegal option -- %c\n", __progname, optopt); + "%s: illegal option -- %c\n", __progname, BSDoptopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ - optarg = NULL; + BSDoptarg = NULL; if (!*place) - ++optind; + ++BSDoptind; } else { /* need an argument */ if (*place) /* no white space */ - optarg = place; - else if (nargc <= ++optind) { /* no arg */ + BSDoptarg = place; + else if (nargc <= ++BSDoptind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); - if (opterr) + if (BSDopterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", - __progname, optopt); + __progname, BSDoptopt); return (BADCH); } else /* white space */ - optarg = nargv[optind]; + BSDoptarg = nargv[BSDoptind]; place = EMSG; - ++optind; + ++BSDoptind; } - return (optopt); /* dump back option letter */ + return (BSDoptopt); /* dump back option letter */ } #endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index 86511276f963..a5b2ab61a9c6 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -1,1417 +1,1418 @@ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * This file contains code implementing the packet protocol and communication * with the other side. This same code is used both on client and server side. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * * SSH2 packet format added by Markus Friedl. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: packet.c,v 1.95 2002/06/19 18:01:00 markus Exp $"); +RCSID("$OpenBSD: packet.c,v 1.96 2002/06/23 21:10:02 deraadt Exp $"); #include "xmalloc.h" #include "buffer.h" #include "packet.h" #include "bufaux.h" #include "crc32.h" #include "getput.h" #include "compress.h" #include "deattack.h" #include "channels.h" #include "compat.h" #include "ssh1.h" #include "ssh2.h" #include "cipher.h" #include "kex.h" #include "mac.h" #include "log.h" #include "canohost.h" #include "misc.h" #include "ssh.h" #ifdef PACKET_DEBUG #define DBG(x) x #else #define DBG(x) #endif /* * This variable contains the file descriptors used for communicating with * the other side. connection_in is used for reading; connection_out for * writing. These can be the same descriptor, in which case it is assumed to * be a socket. */ static int connection_in = -1; static int connection_out = -1; /* Protocol flags for the remote side. */ static u_int remote_protocol_flags = 0; /* Encryption context for receiving data. This is only used for decryption. */ static CipherContext receive_context; /* Encryption context for sending data. This is only used for encryption. */ static CipherContext send_context; /* Buffer for raw input data from the socket. */ Buffer input; /* Buffer for raw output data going to the socket. */ Buffer output; /* Buffer for the partial outgoing packet being constructed. */ static Buffer outgoing_packet; /* Buffer for the incoming packet currently being processed. */ static Buffer incoming_packet; /* Scratch buffer for packet compression/decompression. */ static Buffer compression_buffer; static int compression_buffer_ready = 0; /* Flag indicating whether packet compression/decompression is enabled. */ static int packet_compression = 0; /* default maximum packet size */ int max_packet_size = 32768; /* Flag indicating whether this module has been initialized. */ static int initialized = 0; /* Set to true if the connection is interactive. */ static int interactive_mode = 0; /* Session key information for Encryption and MAC */ Newkeys *newkeys[MODE_MAX]; static u_int32_t read_seqnr = 0; static u_int32_t send_seqnr = 0; /* Session key for protocol v1 */ static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; static u_int ssh1_keylen; /* roundup current message to extra_pad bytes */ static u_char extra_pad = 0; /* * Sets the descriptors used for communication. Disables encryption until * packet_set_encryption_key is called. */ void packet_set_connection(int fd_in, int fd_out) { Cipher *none = cipher_by_name("none"); if (none == NULL) fatal("packet_set_connection: cannot load cipher 'none'"); connection_in = fd_in; connection_out = fd_out; cipher_init(&send_context, none, "", 0, NULL, 0, CIPHER_ENCRYPT); cipher_init(&receive_context, none, "", 0, NULL, 0, CIPHER_DECRYPT); newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; if (!initialized) { initialized = 1; buffer_init(&input); buffer_init(&output); buffer_init(&outgoing_packet); buffer_init(&incoming_packet); } /* Kludge: arrange the close function to be called from fatal(). */ fatal_add_cleanup((void (*) (void *)) packet_close, NULL); } /* Returns 1 if remote host is connected via socket, 0 if not. */ int packet_connection_is_on_socket(void) { struct sockaddr_storage from, to; socklen_t fromlen, tolen; /* filedescriptors in and out are the same, so it's a socket */ if (connection_in == connection_out) return 1; fromlen = sizeof(from); memset(&from, 0, sizeof(from)); if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) return 0; tolen = sizeof(to); memset(&to, 0, sizeof(to)); if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) return 0; if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) return 0; if (from.ss_family != AF_INET && from.ss_family != AF_INET6) return 0; return 1; } /* * Exports an IV from the CipherContext required to export the key * state back from the unprivileged child to the privileged parent * process. */ void packet_get_keyiv(int mode, u_char *iv, u_int len) { CipherContext *cc; if (mode == MODE_OUT) cc = &send_context; else cc = &receive_context; cipher_get_keyiv(cc, iv, len); } int packet_get_keycontext(int mode, u_char *dat) { CipherContext *cc; if (mode == MODE_OUT) cc = &send_context; else cc = &receive_context; return (cipher_get_keycontext(cc, dat)); } void packet_set_keycontext(int mode, u_char *dat) { CipherContext *cc; if (mode == MODE_OUT) cc = &send_context; else cc = &receive_context; cipher_set_keycontext(cc, dat); } int packet_get_keyiv_len(int mode) { CipherContext *cc; if (mode == MODE_OUT) cc = &send_context; else cc = &receive_context; return (cipher_get_keyiv_len(cc)); } void packet_set_iv(int mode, u_char *dat) { CipherContext *cc; if (mode == MODE_OUT) cc = &send_context; else cc = &receive_context; cipher_set_keyiv(cc, dat); } int packet_get_ssh1_cipher() { return (cipher_get_number(receive_context.cipher)); } u_int32_t packet_get_seqnr(int mode) { return (mode == MODE_IN ? read_seqnr : send_seqnr); } void packet_set_seqnr(int mode, u_int32_t seqnr) { if (mode == MODE_IN) read_seqnr = seqnr; else if (mode == MODE_OUT) send_seqnr = seqnr; else fatal("packet_set_seqnr: bad mode %d", mode); } /* returns 1 if connection is via ipv4 */ int packet_connection_is_ipv4(void) { struct sockaddr_storage to; socklen_t tolen = sizeof(to); memset(&to, 0, sizeof(to)); if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) return 0; if (to.ss_family == AF_INET) return 1; #ifdef IPV4_IN_IPV6 if (to.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) return 1; #endif return 0; } /* Sets the connection into non-blocking mode. */ void packet_set_nonblocking(void) { /* Set the socket into non-blocking mode. */ if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) error("fcntl O_NONBLOCK: %.100s", strerror(errno)); if (connection_out != connection_in) { if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) error("fcntl O_NONBLOCK: %.100s", strerror(errno)); } } /* Returns the socket used for reading. */ int packet_get_connection_in(void) { return connection_in; } /* Returns the descriptor used for writing. */ int packet_get_connection_out(void) { return connection_out; } /* Closes the connection and clears and frees internal data structures. */ void packet_close(void) { if (!initialized) return; initialized = 0; if (connection_in == connection_out) { shutdown(connection_out, SHUT_RDWR); close(connection_out); } else { close(connection_in); close(connection_out); } buffer_free(&input); buffer_free(&output); buffer_free(&outgoing_packet); buffer_free(&incoming_packet); if (compression_buffer_ready) { buffer_free(&compression_buffer); buffer_compress_uninit(); } cipher_cleanup(&send_context); cipher_cleanup(&receive_context); } /* Sets remote side protocol flags. */ void packet_set_protocol_flags(u_int protocol_flags) { remote_protocol_flags = protocol_flags; } /* Returns the remote protocol flags set earlier by the above function. */ u_int packet_get_protocol_flags(void) { return remote_protocol_flags; } /* * Starts packet compression from the next packet on in both directions. * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ static void packet_init_compression(void) { if (compression_buffer_ready == 1) return; compression_buffer_ready = 1; buffer_init(&compression_buffer); } void packet_start_compression(int level) { if (packet_compression && !compat20) fatal("Compression already enabled."); packet_compression = 1; packet_init_compression(); buffer_compress_init_send(level); buffer_compress_init_recv(); } /* * Causes any further packets to be encrypted using the given key. The same * key is used for both sending and reception. However, both directions are * encrypted independently of each other. */ void packet_set_encryption_key(const u_char *key, u_int keylen, int number) { Cipher *cipher = cipher_by_number(number); if (cipher == NULL) fatal("packet_set_encryption_key: unknown cipher number %d", number); if (keylen < 20) fatal("packet_set_encryption_key: keylen too small: %d", keylen); if (keylen > SSH_SESSION_KEY_LENGTH) fatal("packet_set_encryption_key: keylen too big: %d", keylen); memcpy(ssh1_key, key, keylen); ssh1_keylen = keylen; cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT); cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT); } u_int packet_get_encryption_key(u_char *key) { if (key == NULL) return (ssh1_keylen); memcpy(key, ssh1_key, ssh1_keylen); return (ssh1_keylen); } /* Start constructing a packet to send. */ void packet_start(u_char type) { u_char buf[9]; int len; DBG(debug("packet_start[%d]", type)); len = compat20 ? 6 : 9; memset(buf, 0, len - 1); buf[len - 1] = type; buffer_clear(&outgoing_packet); buffer_append(&outgoing_packet, buf, len); } /* Append payload. */ void packet_put_char(int value) { char ch = value; buffer_append(&outgoing_packet, &ch, 1); } void packet_put_int(u_int value) { buffer_put_int(&outgoing_packet, value); } void packet_put_string(const void *buf, u_int len) { buffer_put_string(&outgoing_packet, buf, len); } void packet_put_cstring(const char *str) { buffer_put_cstring(&outgoing_packet, str); } void packet_put_raw(const void *buf, u_int len) { buffer_append(&outgoing_packet, buf, len); } void packet_put_bignum(BIGNUM * value) { buffer_put_bignum(&outgoing_packet, value); } void packet_put_bignum2(BIGNUM * value) { buffer_put_bignum2(&outgoing_packet, value); } /* * Finalizes and sends the packet. If the encryption key has been set, * encrypts the packet before sending. */ static void packet_send1(void) { u_char buf[8], *cp; int i, padding, len; u_int checksum; u_int32_t rand = 0; /* * If using packet compression, compress the payload of the outgoing * packet. */ if (packet_compression) { buffer_clear(&compression_buffer); /* Skip padding. */ buffer_consume(&outgoing_packet, 8); /* padding */ buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); buffer_compress(&outgoing_packet, &compression_buffer); buffer_clear(&outgoing_packet); buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), buffer_len(&compression_buffer)); } /* Compute packet length without padding (add checksum, remove padding). */ len = buffer_len(&outgoing_packet) + 4 - 8; /* Insert padding. Initialized to zero in packet_start1() */ padding = 8 - len % 8; if (!send_context.plaintext) { cp = buffer_ptr(&outgoing_packet); for (i = 0; i < padding; i++) { if (i % 4 == 0) rand = arc4random(); cp[7 - i] = rand & 0xff; rand >>= 8; } } buffer_consume(&outgoing_packet, 8 - padding); /* Add check bytes. */ checksum = ssh_crc32(buffer_ptr(&outgoing_packet), buffer_len(&outgoing_packet)); PUT_32BIT(buf, checksum); buffer_append(&outgoing_packet, buf, 4); #ifdef PACKET_DEBUG fprintf(stderr, "packet_send plain: "); buffer_dump(&outgoing_packet); #endif /* Append to output. */ PUT_32BIT(buf, len); buffer_append(&output, buf, 4); cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), buffer_len(&outgoing_packet)); #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); buffer_dump(&output); #endif buffer_clear(&outgoing_packet); /* * Note that the packet is now only buffered in output. It won\'t be * actually sent until packet_write_wait or packet_write_poll is * called. */ } void set_newkeys(int mode) { Enc *enc; Mac *mac; Comp *comp; CipherContext *cc; int encrypt; debug("newkeys: mode %d", mode); if (mode == MODE_OUT) { cc = &send_context; encrypt = CIPHER_ENCRYPT; } else { cc = &receive_context; encrypt = CIPHER_DECRYPT; } if (newkeys[mode] != NULL) { debug("newkeys: rekeying"); cipher_cleanup(cc); enc = &newkeys[mode]->enc; mac = &newkeys[mode]->mac; comp = &newkeys[mode]->comp; memset(mac->key, 0, mac->key_len); xfree(enc->name); xfree(enc->iv); xfree(enc->key); xfree(mac->name); xfree(mac->key); xfree(comp->name); xfree(newkeys[mode]); } newkeys[mode] = kex_get_newkeys(mode); if (newkeys[mode] == NULL) fatal("newkeys: no keys for mode %d", mode); enc = &newkeys[mode]->enc; mac = &newkeys[mode]->mac; comp = &newkeys[mode]->comp; if (mac->md != NULL) mac->enabled = 1; DBG(debug("cipher_init_context: %d", mode)); cipher_init(cc, enc->cipher, enc->key, enc->key_len, enc->iv, enc->block_size, encrypt); /* Deleting the keys does not gain extra security */ /* memset(enc->iv, 0, enc->block_size); memset(enc->key, 0, enc->key_len); */ if (comp->type != 0 && comp->enabled == 0) { packet_init_compression(); if (mode == MODE_OUT) buffer_compress_init_send(6); else buffer_compress_init_recv(); comp->enabled = 1; } } /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ static void packet_send2(void) { u_char type, *cp, *macbuf = NULL; u_char padlen, pad; u_int packet_length = 0; u_int i, len; u_int32_t rand = 0; Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; int block_size; if (newkeys[MODE_OUT] != NULL) { enc = &newkeys[MODE_OUT]->enc; mac = &newkeys[MODE_OUT]->mac; comp = &newkeys[MODE_OUT]->comp; } block_size = enc ? enc->block_size : 8; cp = buffer_ptr(&outgoing_packet); type = cp[5]; #ifdef PACKET_DEBUG fprintf(stderr, "plain: "); buffer_dump(&outgoing_packet); #endif if (comp && comp->enabled) { len = buffer_len(&outgoing_packet); /* skip header, compress only payload */ buffer_consume(&outgoing_packet, 5); buffer_clear(&compression_buffer); buffer_compress(&outgoing_packet, &compression_buffer); buffer_clear(&outgoing_packet); buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), buffer_len(&compression_buffer)); DBG(debug("compression: raw %d compressed %d", len, buffer_len(&outgoing_packet))); } /* sizeof (packet_len + pad_len + payload) */ len = buffer_len(&outgoing_packet); /* * calc size of padding, alloc space, get random data, * minimum padding is 4 bytes */ padlen = block_size - (len % block_size); if (padlen < 4) padlen += block_size; if (extra_pad) { /* will wrap if extra_pad+padlen > 255 */ extra_pad = roundup(extra_pad, block_size); pad = extra_pad - ((len + padlen) % extra_pad); debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", pad, len, padlen, extra_pad); padlen += pad; extra_pad = 0; } cp = buffer_append_space(&outgoing_packet, padlen); if (enc && !send_context.plaintext) { /* random padding */ for (i = 0; i < padlen; i++) { if (i % 4 == 0) rand = arc4random(); cp[i] = rand & 0xff; rand >>= 8; } } else { /* clear padding */ memset(cp, 0, padlen); } /* packet_length includes payload, padding and padding length field */ packet_length = buffer_len(&outgoing_packet) - 4; cp = buffer_ptr(&outgoing_packet); PUT_32BIT(cp, packet_length); cp[4] = padlen; DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); /* compute MAC over seqnr and packet(length fields, payload, padding) */ if (mac && mac->enabled) { macbuf = mac_compute(mac, send_seqnr, buffer_ptr(&outgoing_packet), buffer_len(&outgoing_packet)); DBG(debug("done calc MAC out #%d", send_seqnr)); } /* encrypt packet and append to output buffer. */ cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), buffer_len(&outgoing_packet)); /* append unencrypted MAC */ if (mac && mac->enabled) buffer_append(&output, (char *)macbuf, mac->mac_len); #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); buffer_dump(&output); #endif /* increment sequence number for outgoing packets */ if (++send_seqnr == 0) log("outgoing seqnr wraps around"); buffer_clear(&outgoing_packet); if (type == SSH2_MSG_NEWKEYS) set_newkeys(MODE_OUT); } void packet_send(void) { if (compat20) packet_send2(); else packet_send1(); DBG(debug("packet_send done")); } /* * Waits until a packet has been received, and returns its type. Note that * no other data is processed until this returns, so this function should not * be used during the interactive session. */ int packet_read_seqnr(u_int32_t *seqnr_p) { int type, len; fd_set *setp; char buf[8192]; DBG(debug("packet_read()")); setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) * sizeof(fd_mask)); /* Since we are blocking, ensure that all written packets have been sent. */ packet_write_wait(); /* Stay in the loop until we have received a complete packet. */ for (;;) { /* Try to read a packet from the buffer. */ type = packet_read_poll_seqnr(seqnr_p); if (!compat20 && ( type == SSH_SMSG_SUCCESS || type == SSH_SMSG_FAILURE || type == SSH_CMSG_EOF || type == SSH_CMSG_EXIT_CONFIRMATION)) packet_check_eom(); /* If we got a packet, return it. */ if (type != SSH_MSG_NONE) { xfree(setp); return type; } /* * Otherwise, wait for some data to arrive, add it to the * buffer, and try again. */ memset(setp, 0, howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask)); FD_SET(connection_in, setp); /* Wait for some data to arrive. */ while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 && (errno == EAGAIN || errno == EINTR)) ; /* Read data from the socket. */ len = read(connection_in, buf, sizeof(buf)); if (len == 0) { log("Connection closed by %.200s", get_remote_ipaddr()); fatal_cleanup(); } if (len < 0) fatal("Read from socket failed: %.100s", strerror(errno)); /* Append it to the buffer. */ packet_process_incoming(buf, len); } /* NOTREACHED */ } int packet_read(void) { return packet_read_seqnr(NULL); } /* * Waits until a packet has been received, verifies that its type matches * that given, and gives a fatal error and exits if there is a mismatch. */ void packet_read_expect(int expected_type) { int type; type = packet_read(); if (type != expected_type) packet_disconnect("Protocol error: expected packet type %d, got %d", expected_type, type); } /* Checks if a full packet is available in the data received so far via * packet_process_incoming. If so, reads the packet; otherwise returns * SSH_MSG_NONE. This does not wait for data from the connection. * * SSH_MSG_DISCONNECT is handled specially here. Also, * SSH_MSG_IGNORE messages are skipped by this function and are never returned * to higher levels. */ static int packet_read_poll1(void) { u_int len, padded_len; u_char *cp, type; u_int checksum, stored_checksum; /* Check if input size is less than minimum packet size. */ if (buffer_len(&input) < 4 + 8) return SSH_MSG_NONE; /* Get length of incoming packet. */ cp = buffer_ptr(&input); len = GET_32BIT(cp); if (len < 1 + 2 + 2 || len > 256 * 1024) packet_disconnect("Bad packet length %d.", len); padded_len = (len + 8) & ~7; /* Check if the packet has been entirely received. */ if (buffer_len(&input) < 4 + padded_len) return SSH_MSG_NONE; /* The entire packet is in buffer. */ /* Consume packet length. */ buffer_consume(&input, 4); /* * Cryptographic attack detector for ssh * (C)1998 CORE-SDI, Buenos Aires Argentina * Ariel Futoransky(futo@core-sdi.com) */ if (!receive_context.plaintext && detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED) packet_disconnect("crc32 compensation attack: network attack detected"); /* Decrypt data to incoming_packet. */ buffer_clear(&incoming_packet); cp = buffer_append_space(&incoming_packet, padded_len); cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len); buffer_consume(&input, padded_len); #ifdef PACKET_DEBUG fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet); #endif /* Compute packet checksum. */ checksum = ssh_crc32(buffer_ptr(&incoming_packet), buffer_len(&incoming_packet) - 4); /* Skip padding. */ buffer_consume(&incoming_packet, 8 - len % 8); /* Test check bytes. */ if (len != buffer_len(&incoming_packet)) packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", len, buffer_len(&incoming_packet)); cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; stored_checksum = GET_32BIT(cp); if (checksum != stored_checksum) packet_disconnect("Corrupted check bytes on input."); buffer_consume_end(&incoming_packet, 4); if (packet_compression) { buffer_clear(&compression_buffer); buffer_uncompress(&incoming_packet, &compression_buffer); buffer_clear(&incoming_packet); buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), buffer_len(&compression_buffer)); } type = buffer_get_char(&incoming_packet); return type; } static int packet_read_poll2(u_int32_t *seqnr_p) { static u_int packet_length = 0; u_int padlen, need; u_char *macbuf, *cp, type; int maclen, block_size; Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; if (newkeys[MODE_IN] != NULL) { enc = &newkeys[MODE_IN]->enc; mac = &newkeys[MODE_IN]->mac; comp = &newkeys[MODE_IN]->comp; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->block_size : 8; if (packet_length == 0) { /* * check if input size is less than the cipher block size, * decrypt first block and extract length of incoming packet */ if (buffer_len(&input) < block_size) return SSH_MSG_NONE; buffer_clear(&incoming_packet); cp = buffer_append_space(&incoming_packet, block_size); cipher_crypt(&receive_context, cp, buffer_ptr(&input), block_size); cp = buffer_ptr(&incoming_packet); packet_length = GET_32BIT(cp); if (packet_length < 1 + 4 || packet_length > 256 * 1024) { buffer_dump(&incoming_packet); packet_disconnect("Bad packet length %d.", packet_length); } DBG(debug("input: packet len %d", packet_length+4)); buffer_consume(&input, block_size); } /* we have a partial packet of block_size bytes */ need = 4 + packet_length - block_size; DBG(debug("partial packet %d, need %d, maclen %d", block_size, need, maclen)); if (need % block_size != 0) fatal("padding error: need %d block %d mod %d", need, block_size, need % block_size); /* * check if the entire packet has been received and * decrypt into incoming_packet */ if (buffer_len(&input) < need + maclen) return SSH_MSG_NONE; #ifdef PACKET_DEBUG fprintf(stderr, "read_poll enc/full: "); buffer_dump(&input); #endif cp = buffer_append_space(&incoming_packet, need); cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); buffer_consume(&input, need); /* * compute MAC over seqnr and packet, * increment sequence number for incoming packet */ if (mac && mac->enabled) { macbuf = mac_compute(mac, read_seqnr, buffer_ptr(&incoming_packet), buffer_len(&incoming_packet)); if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) packet_disconnect("Corrupted MAC on input."); DBG(debug("MAC #%d ok", read_seqnr)); buffer_consume(&input, mac->mac_len); } if (seqnr_p != NULL) *seqnr_p = read_seqnr; if (++read_seqnr == 0) log("incoming seqnr wraps around"); /* get padlen */ cp = buffer_ptr(&incoming_packet); padlen = cp[4]; DBG(debug("input: padlen %d", padlen)); if (padlen < 4) packet_disconnect("Corrupted padlen %d on input.", padlen); /* skip packet size + padlen, discard padding */ buffer_consume(&incoming_packet, 4 + 1); buffer_consume_end(&incoming_packet, padlen); DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); if (comp && comp->enabled) { buffer_clear(&compression_buffer); buffer_uncompress(&incoming_packet, &compression_buffer); buffer_clear(&incoming_packet); buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), buffer_len(&compression_buffer)); DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet))); } /* * get packet type, implies consume. * return length of payload (without type field) */ type = buffer_get_char(&incoming_packet); if (type == SSH2_MSG_NEWKEYS) set_newkeys(MODE_IN); #ifdef PACKET_DEBUG fprintf(stderr, "read/plain[%d]:\r\n", type); buffer_dump(&incoming_packet); #endif /* reset for next packet */ packet_length = 0; return type; } int packet_read_poll_seqnr(u_int32_t *seqnr_p) { - int reason, seqnr; + u_int reason, seqnr; u_char type; char *msg; for (;;) { if (compat20) { type = packet_read_poll2(seqnr_p); if (type) DBG(debug("received packet type %d", type)); switch (type) { case SSH2_MSG_IGNORE: break; case SSH2_MSG_DEBUG: packet_get_char(); msg = packet_get_string(NULL); debug("Remote: %.900s", msg); xfree(msg); msg = packet_get_string(NULL); xfree(msg); break; case SSH2_MSG_DISCONNECT: reason = packet_get_int(); msg = packet_get_string(NULL); - log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(), - reason, msg); + log("Received disconnect from %s: %u: %.400s", + get_remote_ipaddr(), reason, msg); xfree(msg); fatal_cleanup(); break; case SSH2_MSG_UNIMPLEMENTED: seqnr = packet_get_int(); - debug("Received SSH2_MSG_UNIMPLEMENTED for %d", seqnr); + debug("Received SSH2_MSG_UNIMPLEMENTED for %u", + seqnr); break; default: return type; break; } } else { type = packet_read_poll1(); switch (type) { case SSH_MSG_IGNORE: break; case SSH_MSG_DEBUG: msg = packet_get_string(NULL); debug("Remote: %.900s", msg); xfree(msg); break; case SSH_MSG_DISCONNECT: msg = packet_get_string(NULL); - log("Received disconnect from %s: %.400s", get_remote_ipaddr(), - msg); + log("Received disconnect from %s: %.400s", + get_remote_ipaddr(), msg); fatal_cleanup(); xfree(msg); break; default: if (type) DBG(debug("received packet type %d", type)); return type; break; } } } } int packet_read_poll(void) { return packet_read_poll_seqnr(NULL); } /* * Buffers the given amount of input characters. This is intended to be used * together with packet_read_poll. */ void packet_process_incoming(const char *buf, u_int len) { buffer_append(&input, buf, len); } /* Returns a character from the packet. */ u_int packet_get_char(void) { char ch; buffer_get(&incoming_packet, &ch, 1); return (u_char) ch; } /* Returns an integer from the packet data. */ u_int packet_get_int(void) { return buffer_get_int(&incoming_packet); } /* * Returns an arbitrary precision integer from the packet data. The integer * must have been initialized before this call. */ void packet_get_bignum(BIGNUM * value) { buffer_get_bignum(&incoming_packet, value); } void packet_get_bignum2(BIGNUM * value) { buffer_get_bignum2(&incoming_packet, value); } void * packet_get_raw(int *length_ptr) { int bytes = buffer_len(&incoming_packet); if (length_ptr != NULL) *length_ptr = bytes; return buffer_ptr(&incoming_packet); } int packet_remaining(void) { return buffer_len(&incoming_packet); } /* * Returns a string from the packet data. The string is allocated using * xmalloc; it is the responsibility of the calling program to free it when * no longer needed. The length_ptr argument may be NULL, or point to an * integer into which the length of the string is stored. */ void * packet_get_string(u_int *length_ptr) { return buffer_get_string(&incoming_packet, length_ptr); } /* * Sends a diagnostic message from the server to the client. This message * can be sent at any time (but not while constructing another message). The * message is printed immediately, but only if the client is being executed * in verbose mode. These messages are primarily intended to ease debugging * authentication problems. The length of the formatted message must not * exceed 1024 bytes. This will automatically call packet_write_wait. */ void packet_send_debug(const char *fmt,...) { char buf[1024]; va_list args; if (compat20 && (datafellows & SSH_BUG_DEBUG)) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (compat20) { packet_start(SSH2_MSG_DEBUG); packet_put_char(0); /* bool: always display */ packet_put_cstring(buf); packet_put_cstring(""); } else { packet_start(SSH_MSG_DEBUG); packet_put_cstring(buf); } packet_send(); packet_write_wait(); } /* * Logs the error plus constructs and sends a disconnect packet, closes the * connection, and exits. This function never returns. The error message * should not contain a newline. The length of the formatted message must * not exceed 1024 bytes. */ void packet_disconnect(const char *fmt,...) { char buf[1024]; va_list args; static int disconnecting = 0; if (disconnecting) /* Guard against recursive invocations. */ fatal("packet_disconnect called recursively."); disconnecting = 1; /* * Format the message. Note that the caller must make sure the * message is of limited size. */ va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); /* Send the disconnect message to the other side, and wait for it to get sent. */ if (compat20) { packet_start(SSH2_MSG_DISCONNECT); packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR); packet_put_cstring(buf); packet_put_cstring(""); } else { packet_start(SSH_MSG_DISCONNECT); packet_put_cstring(buf); } packet_send(); packet_write_wait(); /* Stop listening for connections. */ channel_close_all(); /* Close the connection. */ packet_close(); /* Display the error locally and exit. */ log("Disconnecting: %.100s", buf); fatal_cleanup(); } /* Checks if there is any buffered output, and tries to write some of the output. */ void packet_write_poll(void) { int len = buffer_len(&output); if (len > 0) { len = write(connection_out, buffer_ptr(&output), len); if (len <= 0) { if (errno == EAGAIN) return; else fatal("Write failed: %.100s", strerror(errno)); } buffer_consume(&output, len); } } /* * Calls packet_write_poll repeatedly until all pending output data has been * written. */ void packet_write_wait(void) { fd_set *setp; setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); packet_write_poll(); while (packet_have_data_to_write()) { memset(setp, 0, howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); FD_SET(connection_out, setp); while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && (errno == EAGAIN || errno == EINTR)) ; packet_write_poll(); } xfree(setp); } /* Returns true if there is buffered data to write to the connection. */ int packet_have_data_to_write(void) { return buffer_len(&output) != 0; } /* Returns true if there is not too much data to write to the connection. */ int packet_not_very_much_data_to_write(void) { if (interactive_mode) return buffer_len(&output) < 16384; else return buffer_len(&output) < 128 * 1024; } /* Informs that the current session is interactive. Sets IP flags for that. */ void packet_set_interactive(int interactive) { static int called = 0; #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) int lowdelay = IPTOS_LOWDELAY; int throughput = IPTOS_THROUGHPUT; #endif if (called) return; called = 1; /* Record that we are in interactive mode. */ interactive_mode = interactive; /* Only set socket options if using a socket. */ if (!packet_connection_is_on_socket()) return; /* * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only */ if (interactive) { /* * Set IP options for an interactive connection. Use * IPTOS_LOWDELAY and TCP_NODELAY. */ #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) if (packet_connection_is_ipv4()) { if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &lowdelay, sizeof(lowdelay)) < 0) error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); } #endif set_nodelay(connection_in); } else if (packet_connection_is_ipv4()) { /* * Set IP options for a non-interactive connection. Use * IPTOS_THROUGHPUT. */ #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput, sizeof(throughput)) < 0) error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); #endif } } /* Returns true if the current connection is interactive. */ int packet_is_interactive(void) { return interactive_mode; } int packet_set_maxsize(int s) { static int called = 0; if (called) { log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s); return -1; } if (s < 4 * 1024 || s > 1024 * 1024) { log("packet_set_maxsize: bad size %d", s); return -1; } called = 1; debug("packet_set_maxsize: setting to %d", s); max_packet_size = s; return s; } /* roundup current message to pad bytes */ void packet_add_padding(u_char pad) { extra_pad = pad; } /* * 9.2. Ignored Data Message * * byte SSH_MSG_IGNORE * string data * * All implementations MUST understand (and ignore) this message at any * time (after receiving the protocol version). No implementation is * required to send them. This message can be used as an additional * protection measure against advanced traffic analysis techniques. */ void packet_send_ignore(int nbytes) { u_int32_t rand = 0; int i; packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE); packet_put_int(nbytes); for (i = 0; i < nbytes; i++) { if (i % 4 == 0) rand = arc4random(); packet_put_char(rand & 0xff); rand >>= 8; } } diff --git a/crypto/openssh/scard.c b/crypto/openssh/scard.c index db0cc4a80ca2..9791938c0b5a 100644 --- a/crypto/openssh/scard.c +++ b/crypto/openssh/scard.c @@ -1,557 +1,557 @@ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #if defined(SMARTCARD) && defined(USE_SECTOK) -RCSID("$OpenBSD: scard.c,v 1.25 2002/03/26 18:46:59 rees Exp $"); +RCSID("$OpenBSD: scard.c,v 1.26 2002/06/23 03:30:17 deraadt Exp $"); #include #include #include "key.h" #include "log.h" #include "xmalloc.h" #include "readpass.h" #include "scard.h" #if OPENSSL_VERSION_NUMBER < 0x00907000L #define USE_ENGINE #define RSA_get_default_method RSA_get_default_openssl_method #else #endif #ifdef USE_ENGINE #include #define sc_get_rsa sc_get_engine #else #define sc_get_rsa sc_get_rsa_method #endif #define CLA_SSH 0x05 #define INS_DECRYPT 0x10 #define INS_GET_KEYLENGTH 0x20 #define INS_GET_PUBKEY 0x30 #define INS_GET_RESPONSE 0xc0 #define MAX_BUF_SIZE 256 u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63}; static int sc_fd = -1; static char *sc_reader_id = NULL; static char *sc_pin = NULL; static int cla = 0x00; /* class */ static void sc_mk_digest(const char *pin, u_char *digest); static int get_AUT0(u_char *aut0); static int try_AUT0(void); /* interface to libsectok */ static int sc_open(void) { int sw; if (sc_fd >= 0) return sc_fd; sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw); if (sc_fd < 0) { error("sectok_open failed: %s", sectok_get_sw(sw)); return SCARD_ERROR_FAIL; } if (! sectok_cardpresent(sc_fd)) { debug("smartcard in reader %s not present, skipping", sc_reader_id); sc_close(); return SCARD_ERROR_NOCARD; } if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) { error("sectok_reset failed: %s", sectok_get_sw(sw)); sc_fd = -1; return SCARD_ERROR_FAIL; } if ((cla = cyberflex_inq_class(sc_fd)) < 0) cla = 0; debug("sc_open ok %d", sc_fd); return sc_fd; } static int sc_enable_applet(void) { static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e}; int sw = 0; /* select applet id */ sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw); if (!sectok_swOK(sw)) { error("sectok_apdu failed: %s", sectok_get_sw(sw)); sc_close(); return -1; } return 0; } static int sc_init(void) { int status; status = sc_open(); if (status == SCARD_ERROR_NOCARD) { return SCARD_ERROR_NOCARD; } if (status < 0 ) { error("sc_open failed"); return status; } if (sc_enable_applet() < 0) { error("sc_enable_applet failed"); return SCARD_ERROR_APPLET; } return 0; } static int sc_read_pubkey(Key * k) { u_char buf[2], *n; char *p; int len, sw, status = -1; len = sw = 0; n = NULL; if (sc_fd < 0) { if (sc_init() < 0) goto err; } /* get key size */ sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL, sizeof(buf), buf, &sw); if (!sectok_swOK(sw)) { error("could not obtain key length: %s", sectok_get_sw(sw)); goto err; } len = (buf[0] << 8) | buf[1]; len /= 8; debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw)); n = xmalloc(len); /* get n */ sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); if (sw == 0x6982) { if (try_AUT0() < 0) goto err; sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); } if (!sectok_swOK(sw)) { error("could not obtain public key: %s", sectok_get_sw(sw)); goto err; } debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw)); if (BN_bin2bn(n, len, k->rsa->n) == NULL) { error("c_read_pubkey: BN_bin2bn failed"); goto err; } /* currently the java applet just stores 'n' */ if (!BN_set_word(k->rsa->e, 35)) { error("c_read_pubkey: BN_set_word(e, 35) failed"); goto err; } status = 0; p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); - debug("fingerprint %d %s", key_size(k), p); + debug("fingerprint %u %s", key_size(k), p); xfree(p); err: if (n != NULL) xfree(n); sc_close(); return status; } /* private key operations */ static int sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding) { u_char *padded = NULL; int sw, len, olen, status = -1; debug("sc_private_decrypt called"); olen = len = sw = 0; if (sc_fd < 0) { status = sc_init(); if (status < 0 ) goto err; } if (padding != RSA_PKCS1_PADDING) goto err; len = BN_num_bytes(rsa->n); padded = xmalloc(len); sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw); if (sw == 0x6982) { if (try_AUT0() < 0) goto err; sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw); } if (!sectok_swOK(sw)) { error("sc_private_decrypt: INS_DECRYPT failed: %s", sectok_get_sw(sw)); goto err; } olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1, len); err: if (padded) xfree(padded); sc_close(); return (olen >= 0 ? olen : status); } static int sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding) { u_char *padded = NULL; int sw, len, status = -1; len = sw = 0; if (sc_fd < 0) { status = sc_init(); if (status < 0 ) goto err; } if (padding != RSA_PKCS1_PADDING) goto err; debug("sc_private_encrypt called"); len = BN_num_bytes(rsa->n); padded = xmalloc(len); if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) { error("RSA_padding_add_PKCS1_type_1 failed"); goto err; } sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw); if (sw == 0x6982) { if (try_AUT0() < 0) goto err; sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw); } if (!sectok_swOK(sw)) { error("sc_private_encrypt: INS_DECRYPT failed: %s", sectok_get_sw(sw)); goto err; } err: if (padded) xfree(padded); sc_close(); return (len >= 0 ? len : status); } /* called on free */ static int (*orig_finish)(RSA *rsa) = NULL; static int sc_finish(RSA *rsa) { if (orig_finish) orig_finish(rsa); sc_close(); return 1; } /* engine for overloading private key operations */ static RSA_METHOD * sc_get_rsa_method(void) { static RSA_METHOD smart_rsa; const RSA_METHOD *def = RSA_get_default_method(); /* use the OpenSSL version */ memcpy(&smart_rsa, def, sizeof(smart_rsa)); smart_rsa.name = "sectok"; /* overload */ smart_rsa.rsa_priv_enc = sc_private_encrypt; smart_rsa.rsa_priv_dec = sc_private_decrypt; /* save original */ orig_finish = def->finish; smart_rsa.finish = sc_finish; return &smart_rsa; } #ifdef USE_ENGINE static ENGINE * sc_get_engine(void) { static ENGINE *smart_engine = NULL; if ((smart_engine = ENGINE_new()) == NULL) fatal("ENGINE_new failed"); ENGINE_set_id(smart_engine, "sectok"); ENGINE_set_name(smart_engine, "libsectok"); ENGINE_set_RSA(smart_engine, sc_get_rsa_method()); ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method()); ENGINE_set_DH(smart_engine, DH_get_default_openssl_method()); ENGINE_set_RAND(smart_engine, RAND_SSLeay()); ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp); return smart_engine; } #endif void sc_close(void) { if (sc_fd >= 0) { sectok_close(sc_fd); sc_fd = -1; } } Key ** sc_get_keys(const char *id, const char *pin) { Key *k, *n, **keys; int status, nkeys = 2; if (sc_reader_id != NULL) xfree(sc_reader_id); sc_reader_id = xstrdup(id); if (sc_pin != NULL) xfree(sc_pin); sc_pin = (pin == NULL) ? NULL : xstrdup(pin); k = key_new(KEY_RSA); if (k == NULL) { return NULL; } status = sc_read_pubkey(k); if (status == SCARD_ERROR_NOCARD) { key_free(k); return NULL; } if (status < 0 ) { error("sc_read_pubkey failed"); key_free(k); return NULL; } keys = xmalloc((nkeys+1) * sizeof(Key *)); n = key_new(KEY_RSA1); BN_copy(n->rsa->n, k->rsa->n); BN_copy(n->rsa->e, k->rsa->e); RSA_set_method(n->rsa, sc_get_rsa()); n->flags |= KEY_FLAG_EXT; keys[0] = n; n = key_new(KEY_RSA); BN_copy(n->rsa->n, k->rsa->n); BN_copy(n->rsa->e, k->rsa->e); RSA_set_method(n->rsa, sc_get_rsa()); n->flags |= KEY_FLAG_EXT; keys[1] = n; keys[2] = NULL; key_free(k); return keys; } #define NUM_RSA_KEY_ELEMENTS 5+1 #define COPY_RSA_KEY(x, i) \ do { \ len = BN_num_bytes(prv->rsa->x); \ elements[i] = xmalloc(len); \ debug("#bytes %d", len); \ if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \ goto done; \ } while (0) static void sc_mk_digest(const char *pin, u_char *digest) { const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, pin, strlen(pin)); EVP_DigestFinal(&md, digest, NULL); } static int get_AUT0(u_char *aut0) { char *pass; pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); if (pass == NULL) return -1; if (!strcmp(pass, "-")) { memcpy(aut0, DEFAUT0, sizeof DEFAUT0); return 0; } sc_mk_digest(pass, aut0); memset(pass, 0, strlen(pass)); xfree(pass); return 0; } static int try_AUT0(void) { u_char aut0[EVP_MAX_MD_SIZE]; /* permission denied; try PIN if provided */ if (sc_pin && strlen(sc_pin) > 0) { sc_mk_digest(sc_pin, aut0); if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) { error("smartcard passphrase incorrect"); return (-1); } } else { /* try default AUT0 key */ if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) { /* default AUT0 key failed; prompt for passphrase */ if (get_AUT0(aut0) < 0 || cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) { error("smartcard passphrase incorrect"); return (-1); } } } return (0); } int sc_put_key(Key *prv, const char *id) { u_char *elements[NUM_RSA_KEY_ELEMENTS]; u_char key_fid[2]; u_char AUT0[EVP_MAX_MD_SIZE]; int len, status = -1, i, fd = -1, ret; int sw = 0, cla = 0x00; for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++) elements[i] = NULL; COPY_RSA_KEY(q, 0); COPY_RSA_KEY(p, 1); COPY_RSA_KEY(iqmp, 2); COPY_RSA_KEY(dmq1, 3); COPY_RSA_KEY(dmp1, 4); COPY_RSA_KEY(n, 5); len = BN_num_bytes(prv->rsa->n); fd = sectok_friendly_open(id, STONOWAIT, &sw); if (fd < 0) { error("sectok_open failed: %s", sectok_get_sw(sw)); goto done; } if (! sectok_cardpresent(fd)) { error("smartcard in reader %s not present", id); goto done; } ret = sectok_reset(fd, 0, NULL, &sw); if (ret <= 0) { error("sectok_reset failed: %s", sectok_get_sw(sw)); goto done; } if ((cla = cyberflex_inq_class(fd)) < 0) { error("cyberflex_inq_class failed"); goto done; } memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0)); if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) { if (get_AUT0(AUT0) < 0 || cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) { memset(AUT0, 0, sizeof(DEFAUT0)); error("smartcard passphrase incorrect"); goto done; } } memset(AUT0, 0, sizeof(DEFAUT0)); key_fid[0] = 0x00; key_fid[1] = 0x12; if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements, &sw) < 0) { error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw)); goto done; } if (!sectok_swOK(sw)) goto done; log("cyberflex_load_rsa_priv done"); key_fid[0] = 0x73; key_fid[1] = 0x68; if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5], &sw) < 0) { error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw)); goto done; } if (!sectok_swOK(sw)) goto done; log("cyberflex_load_rsa_pub done"); status = 0; done: memset(elements[0], '\0', BN_num_bytes(prv->rsa->q)); memset(elements[1], '\0', BN_num_bytes(prv->rsa->p)); memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp)); memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1)); memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1)); memset(elements[5], '\0', BN_num_bytes(prv->rsa->n)); for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++) if (elements[i]) xfree(elements[i]); if (fd != -1) sectok_close(fd); return (status); } #endif /* SMARTCARD && USE_SECTOK */ diff --git a/crypto/openssh/scp.1 b/crypto/openssh/scp.1 index c0caff4cc8c1..396ab64beae5 100644 --- a/crypto/openssh/scp.1 +++ b/crypto/openssh/scp.1 @@ -1,156 +1,156 @@ .\" -*- nroff -*- .\" .\" scp.1 .\" .\" Author: Tatu Ylonen .\" .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland .\" All rights reserved .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.22 2002/06/20 20:00:05 stevesk Exp $ +.\" $OpenBSD: scp.1,v 1.23 2002/06/22 16:41:57 stevesk Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 .Os .Sh NAME .Nm scp .Nd secure copy (remote file copy program) .Sh SYNOPSIS .Nm scp .Op Fl pqrvBC46 .Op Fl F Ar ssh_config .Op Fl S Ar program .Op Fl P Ar port .Op Fl c Ar cipher .Op Fl i Ar identity_file .Op Fl o Ar ssh_option .Sm off .Oo .Op Ar user@ .Ar host1 No : .Oc Ns Ar file1 .Sm on .Op Ar ... .Sm off .Oo .Op Ar user@ .Ar host2 No : .Oc Ar file2 .Sm on .Sh DESCRIPTION .Nm copies files between hosts on a network. It uses .Xr ssh 1 for data transfer, and uses the same authentication and provides the same security as .Xr ssh 1 . Unlike .Xr rcp 1 , .Nm will ask for passwords or passphrases if they are needed for authentication. .Pp Any file name may contain a host and user specification to indicate that the file is to be copied to/from that host. Copies between two remote hosts are permitted. .Pp The options are as follows: .Bl -tag -width Ds .It Fl c Ar cipher Selects the cipher to use for encrypting the data transfer. This option is directly passed to .Xr ssh 1 . .It Fl i Ar identity_file Selects the file from which the identity (private key) for RSA authentication is read. This option is directly passed to .Xr ssh 1 . .It Fl p Preserves modification times, access times, and modes from the original file. .It Fl r Recursively copy entire directories. .It Fl v Verbose mode. Causes .Nm and .Xr ssh 1 to print debugging messages about their progress. This is helpful in debugging connection, authentication, and configuration problems. .It Fl B Selects batch mode (prevents asking for passwords or passphrases). .It Fl q Disables the progress meter. .It Fl C Compression enable. Passes the .Fl C flag to .Xr ssh 1 to enable compression. .It Fl F Ar ssh_config Specifies an alternative per-user configuration file for .Nm ssh . This option is directly passed to .Xr ssh 1 . .It Fl P Ar port Specifies the port to connect to on the remote host. Note that this option is written with a capital .Sq P , because .Fl p is already reserved for preserving the times and modes of the file in .Xr rcp 1 . .It Fl S Ar program Name of .Ar program to use for the encrypted connection. The program must understand .Xr ssh 1 options. .It Fl o Ar ssh_option Can be used to pass options to .Nm ssh in the format used in .Xr ssh_config 5 . This is useful for specifying options for which there is no separate .Nm scp command-line flag. For example, forcing the use of protocol version 1 is specified using .Ic scp -oProtocol=1 . .It Fl 4 Forces .Nm to use IPv4 addresses only. .It Fl 6 Forces .Nm to use IPv6 addresses only. .El .Sh DIAGNOSTICS .Nm exits with 0 on success or >0 if an error occurred. .Sh AUTHORS Timo Rinne and Tatu Ylonen .Sh HISTORY .Nm is based on the .Xr rcp 1 program in BSD source code from the Regents of the University of California. .Sh SEE ALSO .Xr rcp 1 , .Xr sftp 1 , .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , .Xr ssh-keygen 1 , -.Xr ssh_config 5 +.Xr ssh_config 5 , .Xr sshd 8 diff --git a/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c index 779ef2fe8950..10b7992d0939 100644 --- a/crypto/openssh/sftp-client.c +++ b/crypto/openssh/sftp-client.c @@ -1,1121 +1,1122 @@ /* * Copyright (c) 2001,2002 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: remove all logging, only return status codes */ /* XXX: copy between two remote sites */ #include "includes.h" -RCSID("$OpenBSD: sftp-client.c,v 1.32 2002/06/09 13:32:01 markus Exp $"); +RCSID("$OpenBSD: sftp-client.c,v 1.33 2002/06/23 09:30:14 deraadt Exp $"); #include "openbsd-compat/fake-queue.h" #include "buffer.h" #include "bufaux.h" #include "getput.h" #include "xmalloc.h" #include "log.h" #include "atomicio.h" #include "sftp.h" #include "sftp-common.h" #include "sftp-client.h" /* Minimum amount of data to read at at time */ #define MIN_READ_SIZE 512 struct sftp_conn { int fd_in; int fd_out; u_int transfer_buflen; u_int num_requests; u_int version; u_int msg_id; }; static 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); } static void get_msg(int fd, Buffer *m) { u_int len, msg_len; unsigned char buf[4096]; len = atomicio(read, fd, buf, 4); if (len == 0) fatal("Connection closed"); else if (len == -1) fatal("Couldn't read packet: %s", strerror(errno)); msg_len = GET_32BIT(buf); if (msg_len > 256 * 1024) - fatal("Received message too long %d", msg_len); + fatal("Received message too long %u", msg_len); while (msg_len) { len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); if (len == 0) fatal("Connection closed"); else if (len == -1) fatal("Couldn't read packet: %s", strerror(errno)); msg_len -= len; buffer_append(m, buf, len); } } static 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); + debug3("Sent message fd %d T:%u I:%u", fd, code, id); buffer_free(&msg); } static 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); + debug3("Sent message fd %d T:%u I:%u", fd, code, id); buffer_free(&msg); } static u_int -get_status(int fd, int expected_id) +get_status(int fd, u_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); + fatal("ID mismatch (%u != %u)", id, expected_id); if (type != SSH2_FXP_STATUS) - fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d", + fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", SSH2_FXP_STATUS, type); status = buffer_get_int(&msg); buffer_free(&msg); - debug3("SSH2_FXP_STATUS %d", status); + debug3("SSH2_FXP_STATUS %u", status); return(status); } static 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); + fatal("ID mismatch (%u != %u)", 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", + fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", SSH2_FXP_HANDLE, type); handle = buffer_get_string(&msg, len); buffer_free(&msg); return(handle); } static Attrib * get_decode_stat(int fd, u_int expected_id, int quiet) { Buffer msg; u_int type, id; Attrib *a; buffer_init(&msg); get_msg(fd, &msg); type = buffer_get_char(&msg); id = buffer_get_int(&msg); - debug3("Received stat reply T:%d I:%d", type, id); + debug3("Received stat reply T:%u I:%u", type, id); if (id != expected_id) - fatal("ID mismatch (%d != %d)", id, expected_id); + fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { int status = buffer_get_int(&msg); if (quiet) debug("Couldn't stat remote file: %s", fx2txt(status)); else error("Couldn't stat remote file: %s", fx2txt(status)); return(NULL); } else if (type != SSH2_FXP_ATTRS) { - fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d", + fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", SSH2_FXP_ATTRS, type); } a = decode_attrib(&msg); buffer_free(&msg); return(a); } struct sftp_conn * do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) { - int type, version; + u_int type; + int version; Buffer msg; struct sftp_conn *ret; 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)", + error("Invalid packet back from SSH2_FXP_INIT (type %u)", type); buffer_free(&msg); return(NULL); } 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); ret = xmalloc(sizeof(*ret)); ret->fd_in = fd_in; ret->fd_out = fd_out; ret->transfer_buflen = transfer_buflen; ret->num_requests = num_requests; ret->version = version; ret->msg_id = 1; /* Some filexfer v.0 servers don't support large packets */ if (version == 0) ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); return(ret); } u_int sftp_proto_version(struct sftp_conn *conn) { return(conn->version); } int do_close(struct sftp_conn *conn, char *handle, u_int handle_len) { u_int id, status; Buffer msg; buffer_init(&msg); id = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_CLOSE); buffer_put_int(&msg, id); buffer_put_string(&msg, handle, handle_len); send_msg(conn->fd_out, &msg); - debug3("Sent message SSH2_FXP_CLOSE I:%d", id); + debug3("Sent message SSH2_FXP_CLOSE I:%u", id); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't close file: %s", fx2txt(status)); buffer_free(&msg); return(status); } static int do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, SFTP_DIRENT ***dir) { Buffer msg; u_int type, id, handle_len, i, expected_id, ents = 0; char *handle; id = conn->msg_id++; buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_OPENDIR); buffer_put_int(&msg, id); buffer_put_cstring(&msg, path); send_msg(conn->fd_out, &msg); buffer_clear(&msg); handle = get_handle(conn->fd_in, id, &handle_len); if (handle == NULL) return(-1); if (dir) { ents = 0; *dir = xmalloc(sizeof(**dir)); (*dir)[0] = NULL; } for (;;) { int count; id = expected_id = conn->msg_id++; - debug3("Sending SSH2_FXP_READDIR I:%d", id); + debug3("Sending SSH2_FXP_READDIR I:%u", 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(conn->fd_out, &msg); buffer_clear(&msg); get_msg(conn->fd_in, &msg); type = buffer_get_char(&msg); id = buffer_get_int(&msg); - debug3("Received reply T:%d I:%d", type, id); + debug3("Received reply T:%u I:%u", type, id); if (id != expected_id) - fatal("ID mismatch (%d != %d)", id, expected_id); + fatal("ID mismatch (%u != %u)", 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(conn, handle, handle_len); return(status); } } else if (type != SSH2_FXP_NAME) - fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); count = buffer_get_int(&msg); if (count == 0) break; debug3("Received %d SSH2_FXP_NAME responses", count); for (i = 0; i < count; i++) { char *filename, *longname; Attrib *a; filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); a = decode_attrib(&msg); if (printflag) printf("%s\n", longname); if (dir) { *dir = xrealloc(*dir, sizeof(**dir) * (ents + 2)); (*dir)[ents] = xmalloc(sizeof(***dir)); (*dir)[ents]->filename = xstrdup(filename); (*dir)[ents]->longname = xstrdup(longname); memcpy(&(*dir)[ents]->a, a, sizeof(*a)); (*dir)[++ents] = NULL; } xfree(filename); xfree(longname); } } buffer_free(&msg); do_close(conn, handle, handle_len); xfree(handle); return(0); } int do_ls(struct sftp_conn *conn, char *path) { return(do_lsreaddir(conn, path, 1, NULL)); } int do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) { return(do_lsreaddir(conn, path, 0, dir)); } void free_sftp_dirents(SFTP_DIRENT **s) { int i; for (i = 0; s[i]; i++) { xfree(s[i]->filename); xfree(s[i]->longname); xfree(s[i]); } xfree(s); } int do_rm(struct sftp_conn *conn, char *path) { u_int status, id; debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't delete file: %s", fx2txt(status)); return(status); } int do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) { u_int status, id; id = conn->msg_id++; send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, strlen(path), a); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't create directory: %s", fx2txt(status)); return(status); } int do_rmdir(struct sftp_conn *conn, char *path) { u_int status, id; id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't remove directory: %s", fx2txt(status)); return(status); } Attrib * do_stat(struct sftp_conn *conn, char *path, int quiet) { u_int id; id = conn->msg_id++; send_string_request(conn->fd_out, id, conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, path, strlen(path)); return(get_decode_stat(conn->fd_in, id, quiet)); } Attrib * do_lstat(struct sftp_conn *conn, char *path, int quiet) { u_int id; if (conn->version == 0) { if (quiet) debug("Server version does not support lstat operation"); else log("Server version does not support lstat operation"); return(do_stat(conn, path, quiet)); } id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); return(get_decode_stat(conn->fd_in, id, quiet)); } Attrib * do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) { u_int id; id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); return(get_decode_stat(conn->fd_in, id, quiet)); } int do_setstat(struct sftp_conn *conn, char *path, Attrib *a) { u_int status, id; id = conn->msg_id++; send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, strlen(path), a); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't setstat on \"%s\": %s", path, fx2txt(status)); return(status); } int do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, Attrib *a) { u_int status, id; id = conn->msg_id++; send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, handle_len, a); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't fsetstat: %s", fx2txt(status)); return(status); } char * do_realpath(struct sftp_conn *conn, char *path) { Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; Attrib *a; expected_id = id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); buffer_init(&msg); get_msg(conn->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); + fatal("ID mismatch (%u != %u)", 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", + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 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(struct sftp_conn *conn, char *oldpath, char *newpath) { Buffer msg; u_int status, id; buffer_init(&msg); /* Send rename request */ id = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_RENAME); buffer_put_int(&msg, id); buffer_put_cstring(&msg, oldpath); buffer_put_cstring(&msg, newpath); send_msg(conn->fd_out, &msg); debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, newpath); buffer_free(&msg); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); return(status); } int do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) { Buffer msg; u_int status, id; if (conn->version < 3) { error("This server does not support the symlink operation"); return(SSH2_FX_OP_UNSUPPORTED); } buffer_init(&msg); /* Send rename request */ id = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_SYMLINK); buffer_put_int(&msg, id); buffer_put_cstring(&msg, oldpath); buffer_put_cstring(&msg, newpath); send_msg(conn->fd_out, &msg); debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, newpath); buffer_free(&msg); status = get_status(conn->fd_in, id); if (status != SSH2_FX_OK) error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); return(status); } char * do_readlink(struct sftp_conn *conn, char *path) { Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; Attrib *a; expected_id = id = conn->msg_id++; send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); buffer_init(&msg); get_msg(conn->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); + fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { u_int status = buffer_get_int(&msg); error("Couldn't readlink: %s", fx2txt(status)); return(NULL); } else if (type != SSH2_FXP_NAME) - fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); count = buffer_get_int(&msg); if (count != 1) fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); a = decode_attrib(&msg); debug3("SSH_FXP_READLINK %s -> %s", path, filename); xfree(longname); buffer_free(&msg); return(filename); } static void send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, char *handle, u_int handle_len) { Buffer msg; buffer_init(&msg); 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, len); send_msg(fd_out, &msg); buffer_free(&msg); } int do_download(struct sftp_conn *conn, char *remote_path, char *local_path, int pflag) { Attrib junk, *a; Buffer msg; char *handle; int local_fd, status, num_req, max_req, write_error; int read_error, write_errno; u_int64_t offset, size; u_int handle_len, mode, type, id, buflen; struct request { u_int id; u_int len; u_int64_t offset; TAILQ_ENTRY(request) tq; }; TAILQ_HEAD(reqhead, request) requests; struct request *req; TAILQ_INIT(&requests); a = do_stat(conn, remote_path, 0); if (a == NULL) return(-1); /* XXX: should we preserve set[ug]id? */ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) mode = S_IWRITE | (a->perm & 0777); else mode = 0666; if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && (a->perm & S_IFDIR)) { error("Cannot download a directory: %s", remote_path); return(-1); } if (a->flags & SSH2_FILEXFER_ATTR_SIZE) size = a->size; else size = 0; buflen = conn->transfer_buflen; buffer_init(&msg); /* Send open request */ id = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_OPEN); buffer_put_int(&msg, id); buffer_put_cstring(&msg, remote_path); buffer_put_int(&msg, SSH2_FXF_READ); attrib_clear(&junk); /* Send empty attributes */ encode_attrib(&msg, &junk); send_msg(conn->fd_out, &msg); - debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); + debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); handle = get_handle(conn->fd_in, id, &handle_len); if (handle == NULL) { buffer_free(&msg); return(-1); } local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); if (local_fd == -1) { error("Couldn't open local file \"%s\" for writing: %s", local_path, strerror(errno)); buffer_free(&msg); xfree(handle); return(-1); } /* Read from remote and write to local */ write_error = read_error = write_errno = num_req = offset = 0; max_req = 1; while (num_req > 0 || max_req > 0) { char *data; u_int len; /* Send some more requests */ while (num_req < max_req) { debug3("Request range %llu -> %llu (%d/%d)", (unsigned long long)offset, (unsigned long long)offset + buflen - 1, num_req, max_req); req = xmalloc(sizeof(*req)); req->id = conn->msg_id++; req->len = buflen; req->offset = offset; offset += buflen; num_req++; TAILQ_INSERT_TAIL(&requests, req, tq); send_read_request(conn->fd_out, req->id, req->offset, req->len, handle, handle_len); } buffer_clear(&msg); get_msg(conn->fd_in, &msg); type = buffer_get_char(&msg); id = buffer_get_int(&msg); - debug3("Received reply T:%d I:%d R:%d", type, id, max_req); + debug3("Received reply T:%u I:%u R:%d", type, id, max_req); /* Find the request in our queue */ for(req = TAILQ_FIRST(&requests); req != NULL && req->id != id; req = TAILQ_NEXT(req, tq)) ; if (req == NULL) fatal("Unexpected reply %u", id); switch (type) { case SSH2_FXP_STATUS: status = buffer_get_int(&msg); if (status != SSH2_FX_EOF) read_error = 1; max_req = 0; TAILQ_REMOVE(&requests, req, tq); xfree(req); num_req--; break; case SSH2_FXP_DATA: data = buffer_get_string(&msg, &len); debug3("Received data %llu -> %llu", (unsigned long long)req->offset, (unsigned long long)req->offset + len - 1); if (len > req->len) fatal("Received more data than asked for " - "%d > %d", len, req->len); + "%u > %u", len, req->len); if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || atomicio(write, local_fd, data, len) != len) && !write_error) { write_errno = errno; write_error = 1; max_req = 0; } xfree(data); if (len == req->len) { TAILQ_REMOVE(&requests, req, tq); xfree(req); num_req--; } else { /* Resend the request for the missing data */ debug3("Short data block, re-requesting " "%llu -> %llu (%2d)", (unsigned long long)req->offset + len, (unsigned long long)req->offset + req->len - 1, num_req); req->id = conn->msg_id++; req->len -= len; req->offset += len; send_read_request(conn->fd_out, req->id, req->offset, req->len, handle, handle_len); /* Reduce the request size */ if (len < buflen) buflen = MAX(MIN_READ_SIZE, len); } if (max_req > 0) { /* max_req = 0 iff EOF received */ if (size > 0 && offset > size) { /* Only one request at a time * after the expected EOF */ debug3("Finish at %llu (%2d)", (unsigned long long)offset, num_req); max_req = 1; } else if (max_req < conn->num_requests + 1) { ++max_req; } } break; default: - fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", + fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", SSH2_FXP_DATA, type); } } /* Sanity check */ if (TAILQ_FIRST(&requests) != NULL) fatal("Transfer complete, but requests still in queue"); if (read_error) { error("Couldn't read from remote file \"%s\" : %s", remote_path, fx2txt(status)); do_close(conn, handle, handle_len); } else if (write_error) { error("Couldn't write to \"%s\": %s", local_path, strerror(write_errno)); status = -1; do_close(conn, handle, handle_len); } else { status = do_close(conn, handle, handle_len); /* Override umask and utimes if asked */ #ifdef HAVE_FCHMOD if (pflag && fchmod(local_fd, mode) == -1) #else if (pflag && chmod(local_path, mode) == -1) #endif /* HAVE_FCHMOD */ error("Couldn't set mode on \"%s\": %s", local_path, strerror(errno)); if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { struct timeval tv[2]; tv[0].tv_sec = a->atime; tv[1].tv_sec = a->mtime; tv[0].tv_usec = tv[1].tv_usec = 0; if (utimes(local_path, tv) == -1) error("Can't set times on \"%s\": %s", local_path, strerror(errno)); } } close(local_fd); buffer_free(&msg); xfree(handle); return(status); } int do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, int pflag) { int local_fd, status; u_int handle_len, id, type; u_int64_t offset; char *handle, *data; Buffer msg; struct stat sb; Attrib a; u_int32_t startid; u_int32_t ackid; struct outstanding_ack { u_int id; u_int len; u_int64_t offset; TAILQ_ENTRY(outstanding_ack) tq; }; TAILQ_HEAD(ackhead, outstanding_ack) acks; struct outstanding_ack *ack; TAILQ_INIT(&acks); 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 = conn->msg_id++; buffer_put_char(&msg, SSH2_FXP_OPEN); buffer_put_int(&msg, id); buffer_put_cstring(&msg, remote_path); buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); encode_attrib(&msg, &a); send_msg(conn->fd_out, &msg); - debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); + debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); buffer_clear(&msg); handle = get_handle(conn->fd_in, id, &handle_len); if (handle == NULL) { close(local_fd); buffer_free(&msg); return(-1); } startid = ackid = id + 1; data = xmalloc(conn->transfer_buflen); /* Read from local and write to remote */ offset = 0; for (;;) { int len; /* * 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, conn->transfer_buflen); while ((len == -1) && (errno == EINTR || errno == EAGAIN)); if (len == -1) fatal("Couldn't read from \"%s\": %s", local_path, strerror(errno)); if (len != 0) { ack = xmalloc(sizeof(*ack)); ack->id = ++id; ack->offset = offset; ack->len = len; TAILQ_INSERT_TAIL(&acks, ack, tq); buffer_clear(&msg); buffer_put_char(&msg, SSH2_FXP_WRITE); buffer_put_int(&msg, ack->id); buffer_put_string(&msg, handle, handle_len); buffer_put_int64(&msg, offset); buffer_put_string(&msg, data, len); send_msg(conn->fd_out, &msg); - debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", + debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", id, (unsigned long long)offset, len); } else if (TAILQ_FIRST(&acks) == NULL) break; if (ack == NULL) fatal("Unexpected ACK %u", id); if (id == startid || len == 0 || id - ackid >= conn->num_requests) { u_int r_id; buffer_clear(&msg); get_msg(conn->fd_in, &msg); type = buffer_get_char(&msg); r_id = buffer_get_int(&msg); if (type != SSH2_FXP_STATUS) fatal("Expected SSH2_FXP_STATUS(%d) packet, " "got %d", SSH2_FXP_STATUS, type); status = buffer_get_int(&msg); debug3("SSH2_FXP_STATUS %d", status); /* Find the request in our queue */ for(ack = TAILQ_FIRST(&acks); ack != NULL && ack->id != r_id; ack = TAILQ_NEXT(ack, tq)) ; if (ack == NULL) - fatal("Can't find request for ID %d", r_id); + fatal("Can't find request for ID %u", r_id); TAILQ_REMOVE(&acks, ack, tq); if (status != SSH2_FX_OK) { error("Couldn't write to remote file \"%s\": %s", remote_path, fx2txt(status)); do_close(conn, handle, handle_len); close(local_fd); goto done; } - debug3("In write loop, ack for %u %d bytes at %llu", + debug3("In write loop, ack for %u %u bytes at %llu", ack->id, ack->len, (unsigned long long)ack->offset); ++ackid; free(ack); } offset += len; } xfree(data); if (close(local_fd) == -1) { error("Couldn't close local file \"%s\": %s", local_path, strerror(errno)); do_close(conn, handle, handle_len); status = -1; goto done; } /* Override umask and utimes if asked */ if (pflag) do_fsetstat(conn, handle, handle_len, &a); status = do_close(conn, handle, handle_len); done: xfree(handle); buffer_free(&msg); return(status); } diff --git a/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h index ceda879b9283..b0617116816b 100644 --- a/crypto/openssh/sftp-client.h +++ b/crypto/openssh/sftp-client.h @@ -1,112 +1,110 @@ -/* $OpenBSD: sftp-client.h,v 1.9 2002/02/13 00:59:23 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.10 2002/06/23 09:30:14 deraadt Exp $ */ /* * Copyright (c) 2001,2002 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 */ #ifndef _SFTP_CLIENT_H #define _SFTP_CLIENT_H typedef struct SFTP_DIRENT SFTP_DIRENT; struct SFTP_DIRENT { char *filename; char *longname; Attrib a; }; /* * Initialiase a SSH filexfer connection. Returns -1 on error or * protocol version on success. */ -struct sftp_conn * -do_init(int, int, u_int, u_int); +struct sftp_conn *do_init(int, int, u_int, u_int); -u_int -sftp_proto_version(struct sftp_conn *); +u_int sftp_proto_version(struct sftp_conn *); /* Close file referred to by 'handle' */ int do_close(struct sftp_conn *, char *, u_int); /* List contents of directory 'path' to stdout */ int do_ls(struct sftp_conn *, char *); /* Read contents of 'path' to NULL-terminated array 'dir' */ int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ void free_sftp_dirents(SFTP_DIRENT **); /* Delete file 'path' */ int do_rm(struct sftp_conn *, char *); /* Create directory 'path' */ int do_mkdir(struct sftp_conn *, char *, Attrib *); /* Remove directory 'path' */ int do_rmdir(struct sftp_conn *, char *); /* Get file attributes of 'path' (follows symlinks) */ Attrib *do_stat(struct sftp_conn *, char *, int); /* Get file attributes of 'path' (does not follow symlinks) */ Attrib *do_lstat(struct sftp_conn *, char *, int); /* Get file attributes of open file 'handle' */ Attrib *do_fstat(struct sftp_conn *, char *, u_int, int); /* Set file attributes of 'path' */ int do_setstat(struct sftp_conn *, char *, Attrib *); /* Set file attributes of open file 'handle' */ int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *); /* Canonicalise 'path' - caller must free result */ char *do_realpath(struct sftp_conn *, char *); /* Rename 'oldpath' to 'newpath' */ int do_rename(struct sftp_conn *, char *, char *); /* Rename 'oldpath' to 'newpath' */ int do_symlink(struct sftp_conn *, char *, char *); /* Return target of symlink 'path' - caller must free result */ char *do_readlink(struct sftp_conn *, char *); /* 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(struct sftp_conn *, char *, char *, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times * if 'pflag' is set */ int do_upload(struct sftp_conn *, char *, char *, int); #endif diff --git a/crypto/openssh/sftp-common.c b/crypto/openssh/sftp-common.c index 4fb4496555ce..6bed0ab8a06d 100644 --- a/crypto/openssh/sftp-common.c +++ b/crypto/openssh/sftp-common.c @@ -1,149 +1,151 @@ /* * 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.5 2001/12/02 02:08:32 deraadt Exp $"); +RCSID("$OpenBSD: sftp-common.c,v 1.6 2002/06/23 09:30:14 deraadt Exp $"); #include "buffer.h" #include "bufaux.h" #include "log.h" #include "xmalloc.h" #include "sftp.h" #include "sftp-common.h" /* Clear contents of attributes structure */ 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; } /* Convert from struct stat to filexfer attribs */ 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; } /* Decode attributes in buffer */ 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; } /* Encode attributes to buffer */ 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); } } /* Convert from SSH2_FX_ status to text error message */ const char * fx2txt(int status) { switch (status) { case SSH2_FX_OK: return("No error"); case SSH2_FX_EOF: return("End of file"); case SSH2_FX_NO_SUCH_FILE: return("No such file or directory"); case SSH2_FX_PERMISSION_DENIED: return("Permission denied"); case SSH2_FX_FAILURE: return("Failure"); case SSH2_FX_BAD_MESSAGE: return("Bad message"); case SSH2_FX_NO_CONNECTION: return("No connection"); case SSH2_FX_CONNECTION_LOST: return("Connection lost"); case SSH2_FX_OP_UNSUPPORTED: return("Operation unsupported"); default: return("Unknown status"); } /* NOTREACHED */ } diff --git a/crypto/openssh/sftp-int.c b/crypto/openssh/sftp-int.c index 5b1d3848e828..b13e5da5d5b3 100644 --- a/crypto/openssh/sftp-int.c +++ b/crypto/openssh/sftp-int.c @@ -1,923 +1,923 @@ /* * Copyright (c) 2001,2002 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* XXX: globbed ls */ /* XXX: recursive operations */ #include "includes.h" -RCSID("$OpenBSD: sftp-int.c,v 1.46 2002/03/30 18:51:15 markus Exp $"); +RCSID("$OpenBSD: sftp-int.c,v 1.47 2002/06/23 09:30:14 deraadt Exp $"); #include "buffer.h" #include "xmalloc.h" #include "log.h" #include "pathnames.h" #include "sftp.h" #include "sftp-common.h" #include "sftp-glob.h" #include "sftp-client.h" #include "sftp-int.h" /* File to read commands from */ extern FILE *infile; /* Size of buffer used when copying files */ extern size_t copy_buffer_len; /* Number of concurrent outstanding requests */ extern int num_requests; /* Seperators for interactive commands */ #define WHITESPACE " \t\r\n" /* Commands for interactive mode */ #define I_CHDIR 1 #define I_CHGRP 2 #define I_CHMOD 3 #define I_CHOWN 4 #define I_GET 5 #define I_HELP 6 #define I_LCHDIR 7 #define I_LLS 8 #define I_LMKDIR 9 #define I_LPWD 10 #define I_LS 11 #define I_LUMASK 12 #define I_MKDIR 13 #define I_PUT 14 #define I_PWD 15 #define I_QUIT 16 #define I_RENAME 17 #define I_RM 18 #define I_RMDIR 19 #define I_SHELL 20 #define I_SYMLINK 21 #define I_VERSION 22 struct CMD { const char *c; const int n; }; const struct CMD cmds[] = { { "bye", I_QUIT }, { "cd", I_CHDIR }, { "chdir", I_CHDIR }, { "chgrp", I_CHGRP }, { "chmod", I_CHMOD }, { "chown", I_CHOWN }, { "dir", I_LS }, { "exit", I_QUIT }, { "get", I_GET }, { "mget", I_GET }, { "help", I_HELP }, { "lcd", I_LCHDIR }, { "lchdir", I_LCHDIR }, { "lls", I_LLS }, { "lmkdir", I_LMKDIR }, { "ln", I_SYMLINK }, { "lpwd", I_LPWD }, { "ls", I_LS }, { "lumask", I_LUMASK }, { "mkdir", I_MKDIR }, { "put", I_PUT }, { "mput", I_PUT }, { "pwd", I_PWD }, { "quit", I_QUIT }, { "rename", I_RENAME }, { "rm", I_RM }, { "rmdir", I_RMDIR }, { "symlink", I_SYMLINK }, { "version", I_VERSION }, { "!", I_SHELL }, { "?", I_HELP }, { NULL, -1} }; static void help(void) { printf("Available commands:\n"); printf("cd path Change remote directory to 'path'\n"); printf("lcd path Change local directory to 'path'\n"); printf("chgrp grp path Change group of file 'path' to 'grp'\n"); printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); printf("chown own path Change owner of file 'path' to 'own'\n"); printf("help Display this help text\n"); printf("get remote-path [local-path] Download file\n"); printf("lls [ls-options [path]] Display local directory listing\n"); printf("ln oldpath newpath Symlink remote file\n"); printf("lmkdir path Create local directory\n"); printf("lpwd Print local working directory\n"); printf("ls [path] Display remote directory listing\n"); printf("lumask umask Set local umask to 'umask'\n"); printf("mkdir path Create remote directory\n"); printf("put local-path [remote-path] Upload file\n"); printf("pwd Display remote working directory\n"); printf("exit Quit sftp\n"); printf("quit Quit sftp\n"); printf("rename oldpath newpath Rename remote file\n"); printf("rmdir path Remove remote directory\n"); printf("rm path Delete remote file\n"); printf("symlink oldpath newpath Symlink remote file\n"); printf("version Show SFTP version\n"); printf("!command Execute 'command' in local shell\n"); printf("! Escape to local shell\n"); printf("? Synonym for help\n"); } static void local_do_shell(const char *args) { int status; char *shell; pid_t pid; if (!*args) args = NULL; if ((shell = getenv("SHELL")) == NULL) shell = _PATH_BSHELL; if ((pid = fork()) == -1) fatal("Couldn't fork: %s", strerror(errno)); if (pid == 0) { /* XXX: child has pipe fds to ssh subproc open - issue? */ if (args) { debug3("Executing %s -c \"%s\"", shell, args); execl(shell, shell, "-c", args, (char *)NULL); } else { debug3("Executing %s", shell); execl(shell, shell, (char *)NULL); } fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, strerror(errno)); _exit(1); } while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) 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)); } static void local_do_ls(const char *args) { if (!args || !*args) local_do_shell(_PATH_LS); else { int len = strlen(_PATH_LS " ") + strlen(args) + 1; char *buf = xmalloc(len); /* XXX: quoting - rip quoting code from ftp? */ snprintf(buf, len, _PATH_LS " %s", args); local_do_shell(buf); xfree(buf); } } static char * path_append(char *p1, char *p2) { char *ret; int len = strlen(p1) + strlen(p2) + 2; ret = xmalloc(len); strlcpy(ret, p1, len); if (strcmp(p1, "/") != 0) strlcat(ret, "/", len); strlcat(ret, p2, len); return(ret); } static char * make_absolute(char *p, char *pwd) { char *abs; /* Derelativise */ if (p && p[0] != '/') { abs = path_append(pwd, p); xfree(p); return(abs); } else return(p); } static int infer_path(const char *p, char **ifp) { char *cp; cp = strrchr(p, '/'); if (cp == NULL) { *ifp = xstrdup(p); return(0); } if (!cp[1]) { error("Invalid path"); return(-1); } *ifp = xstrdup(cp + 1); return(0); } static int parse_getput_flags(const char **cpp, int *pflag) { const char *cp = *cpp; /* Check for flags */ if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { switch (cp[1]) { case 'p': case 'P': *pflag = 1; break; default: error("Invalid flag -%c", cp[1]); return(-1); } cp += 2; *cpp = cp + strspn(cp, WHITESPACE); } return(0); } static int get_pathname(const char **cpp, char **path) { const char *cp = *cpp, *end; char quot; int i; cp += strspn(cp, WHITESPACE); if (!*cp) { *cpp = cp; *path = NULL; return (0); } /* Check for quoted filenames */ if (*cp == '\"' || *cp == '\'') { quot = *cp++; end = strchr(cp, quot); if (end == NULL) { error("Unterminated quote"); goto fail; } if (cp == end) { error("Empty quotes"); goto fail; } *cpp = end + 1 + strspn(end + 1, WHITESPACE); } else { /* Read to end of filename */ end = strpbrk(cp, WHITESPACE); if (end == NULL) end = strchr(cp, '\0'); *cpp = end + strspn(end, WHITESPACE); } i = end - cp; *path = xmalloc(i + 1); memcpy(*path, cp, i); (*path)[i] = '\0'; return(0); fail: *path = NULL; return (-1); } static int is_dir(char *path) { struct stat sb; /* XXX: report errors? */ if (stat(path, &sb) == -1) return(0); return(sb.st_mode & S_IFDIR); } static int remote_is_dir(struct sftp_conn *conn, char *path) { Attrib *a; /* XXX: report errors? */ if ((a = do_stat(conn, path, 1)) == NULL) return(0); if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) return(0); return(a->perm & S_IFDIR); } static int process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) { char *abs_src = NULL; char *abs_dst = NULL; char *tmp; glob_t g; int err = 0; int i; abs_src = xstrdup(src); abs_src = make_absolute(abs_src, pwd); memset(&g, 0, sizeof(g)); debug3("Looking up %s", abs_src); if (remote_glob(conn, abs_src, 0, NULL, &g)) { error("File \"%s\" not found.", abs_src); err = -1; goto out; } /* Only one match, dst may be file, directory or unspecified */ if (g.gl_pathv[0] && g.gl_matchc == 1) { if (dst) { /* If directory specified, append filename */ if (is_dir(dst)) { if (infer_path(g.gl_pathv[0], &tmp)) { err = 1; goto out; } abs_dst = path_append(dst, tmp); xfree(tmp); } else abs_dst = xstrdup(dst); } else if (infer_path(g.gl_pathv[0], &abs_dst)) { err = -1; goto out; } printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); err = do_download(conn, g.gl_pathv[0], abs_dst, pflag); goto out; } /* Multiple matches, dst may be directory or unspecified */ if (dst && !is_dir(dst)) { error("Multiple files match, but \"%s\" is not a directory", dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i]; i++) { if (infer_path(g.gl_pathv[i], &tmp)) { err = -1; goto out; } if (dst) { abs_dst = path_append(dst, tmp); xfree(tmp); } else abs_dst = tmp; printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) err = -1; xfree(abs_dst); abs_dst = NULL; } out: xfree(abs_src); if (abs_dst) xfree(abs_dst); globfree(&g); return(err); } static int process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) { char *tmp_dst = NULL; char *abs_dst = NULL; char *tmp; glob_t g; int err = 0; int i; if (dst) { tmp_dst = xstrdup(dst); tmp_dst = make_absolute(tmp_dst, pwd); } memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); if (glob(src, 0, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; } /* Only one match, dst may be file, directory or unspecified */ if (g.gl_pathv[0] && g.gl_matchc == 1) { if (tmp_dst) { /* If directory specified, append filename */ if (remote_is_dir(conn, tmp_dst)) { if (infer_path(g.gl_pathv[0], &tmp)) { err = 1; goto out; } abs_dst = path_append(tmp_dst, tmp); xfree(tmp); } else abs_dst = xstrdup(tmp_dst); } else { if (infer_path(g.gl_pathv[0], &abs_dst)) { err = -1; goto out; } abs_dst = make_absolute(abs_dst, pwd); } printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst); err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag); goto out; } /* Multiple matches, dst may be directory or unspecified */ if (tmp_dst && !remote_is_dir(conn, tmp_dst)) { error("Multiple files match, but \"%s\" is not a directory", tmp_dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i]; i++) { if (infer_path(g.gl_pathv[i], &tmp)) { err = -1; goto out; } if (tmp_dst) { abs_dst = path_append(tmp_dst, tmp); xfree(tmp); } else abs_dst = make_absolute(tmp, pwd); printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) err = -1; } out: if (abs_dst) xfree(abs_dst); if (tmp_dst) xfree(tmp_dst); return(err); } static int parse_args(const char **cpp, int *pflag, unsigned long *n_arg, char **path1, char **path2) { const char *cmd, *cp = *cpp; char *cp2; int base = 0; long l; int i, cmdnum; /* Skip leading whitespace */ cp = cp + strspn(cp, WHITESPACE); /* Ignore blank lines */ if (!*cp) return(-1); /* Figure out which command we have */ for (i = 0; cmds[i].c; i++) { int cmdlen = strlen(cmds[i].c); /* Check for command followed by whitespace */ if (!strncasecmp(cp, cmds[i].c, cmdlen) && strchr(WHITESPACE, cp[cmdlen])) { cp += cmdlen; cp = cp + strspn(cp, WHITESPACE); break; } } cmdnum = cmds[i].n; cmd = cmds[i].c; /* Special case */ if (*cp == '!') { cp++; cmdnum = I_SHELL; } else if (cmdnum == -1) { error("Invalid command."); return(-1); } /* Get arguments and parse flags */ *pflag = *n_arg = 0; *path1 = *path2 = NULL; switch (cmdnum) { case I_GET: case I_PUT: if (parse_getput_flags(&cp, pflag)) return(-1); /* Get first pathname (mandatory) */ if (get_pathname(&cp, path1)) return(-1); if (*path1 == NULL) { error("You must specify at least one path after a " "%s command.", cmd); return(-1); } /* Try to get second pathname (optional) */ if (get_pathname(&cp, path2)) return(-1); break; case I_RENAME: case I_SYMLINK: if (get_pathname(&cp, path1)) return(-1); if (get_pathname(&cp, path2)) return(-1); if (!*path1 || !*path2) { error("You must specify two paths after a %s " "command.", cmd); return(-1); } break; case I_RM: case I_MKDIR: case I_RMDIR: case I_CHDIR: case I_LCHDIR: case I_LMKDIR: /* Get pathname (mandatory) */ if (get_pathname(&cp, path1)) return(-1); if (*path1 == NULL) { error("You must specify a path after a %s command.", cmd); return(-1); } break; case I_LS: /* Path is optional */ if (get_pathname(&cp, path1)) return(-1); break; case I_LLS: case I_SHELL: /* Uses the rest of the line */ break; case I_LUMASK: base = 8; case I_CHMOD: base = 8; case I_CHOWN: case I_CHGRP: /* Get numeric arg (mandatory) */ l = strtol(cp, &cp2, base); if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || l < 0) { error("You must supply a numeric argument " "to the %s command.", cmd); return(-1); } cp = cp2; *n_arg = l; if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp)) break; if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) { error("You must supply a numeric argument " "to the %s command.", cmd); return(-1); } cp += strspn(cp, WHITESPACE); /* Get pathname (mandatory) */ if (get_pathname(&cp, path1)) return(-1); if (*path1 == NULL) { error("You must specify a path after a %s command.", cmd); return(-1); } break; case I_QUIT: case I_PWD: case I_LPWD: case I_HELP: case I_VERSION: break; default: fatal("Command not implemented"); } *cpp = cp; return(cmdnum); } static int parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) { char *path1, *path2, *tmp; int pflag, cmdnum, i; unsigned long n_arg; Attrib a, *aa; char path_buf[MAXPATHLEN]; int err = 0; glob_t g; path1 = path2 = NULL; cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); memset(&g, 0, sizeof(g)); /* Perform command */ switch (cmdnum) { case -1: break; case I_GET: err = process_get(conn, path1, path2, *pwd, pflag); break; case I_PUT: err = process_put(conn, path1, path2, *pwd, pflag); break; case I_RENAME: path1 = make_absolute(path1, *pwd); path2 = make_absolute(path2, *pwd); err = do_rename(conn, path1, path2); break; case I_SYMLINK: path2 = make_absolute(path2, *pwd); err = do_symlink(conn, path1, path2); break; case I_RM: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i]; i++) { printf("Removing %s\n", g.gl_pathv[i]); if (do_rm(conn, g.gl_pathv[i]) == -1) err = -1; } break; case I_MKDIR: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; err = do_mkdir(conn, path1, &a); break; case I_RMDIR: path1 = make_absolute(path1, *pwd); err = do_rmdir(conn, path1); break; case I_CHDIR: path1 = make_absolute(path1, *pwd); if ((tmp = do_realpath(conn, path1)) == NULL) { err = 1; break; } if ((aa = do_stat(conn, tmp, 0)) == NULL) { xfree(tmp); err = 1; break; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); xfree(tmp); err = 1; break; } if (!S_ISDIR(aa->perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); xfree(tmp); err = 1; break; } xfree(*pwd); *pwd = tmp; break; case I_LS: if (!path1) { do_ls(conn, *pwd); break; } path1 = make_absolute(path1, *pwd); if ((tmp = do_realpath(conn, path1)) == NULL) break; xfree(path1); path1 = tmp; if ((aa = do_stat(conn, path1, 0)) == NULL) break; if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && !S_ISDIR(aa->perm)) { error("Can't ls: \"%s\" is not a directory", path1); break; } do_ls(conn, path1); break; case I_LCHDIR: if (chdir(path1) == -1) { error("Couldn't change local directory to " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LMKDIR: if (mkdir(path1, 0777) == -1) { error("Couldn't create local directory " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LLS: local_do_ls(cmd); break; case I_SHELL: local_do_shell(cmd); break; case I_LUMASK: umask(n_arg); printf("Local umask: %03lo\n", n_arg); break; case I_CHMOD: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = n_arg; remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i]; i++) { printf("Changing mode on %s\n", g.gl_pathv[i]); do_setstat(conn, g.gl_pathv[i], &a); } break; case I_CHOWN: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i]; i++) { if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) continue; if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); continue; } printf("Changing owner on %s\n", g.gl_pathv[i]); aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; aa->uid = n_arg; do_setstat(conn, g.gl_pathv[i], aa); } break; case I_CHGRP: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i]; i++) { if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) continue; if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); continue; } printf("Changing group on %s\n", g.gl_pathv[i]); aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; aa->gid = n_arg; do_setstat(conn, g.gl_pathv[i], aa); } break; case I_PWD: printf("Remote working directory: %s\n", *pwd); break; case I_LPWD: if (!getcwd(path_buf, sizeof(path_buf))) error("Couldn't get local cwd: %s", strerror(errno)); else printf("Local working directory: %s\n", path_buf); break; case I_QUIT: return(-1); case I_HELP: help(); break; case I_VERSION: - printf("SFTP protocol version %d\n", sftp_proto_version(conn)); + printf("SFTP protocol version %u\n", sftp_proto_version(conn)); break; default: fatal("%d is not implemented", cmdnum); } if (g.gl_pathc) globfree(&g); if (path1) xfree(path1); if (path2) xfree(path2); /* If an error occurs in batch mode we should abort. */ if (infile != stdin && err > 0) return -1; return(0); } void interactive_loop(int fd_in, int fd_out, char *file1, char *file2) { char *pwd; char *dir = NULL; char cmd[2048]; struct sftp_conn *conn; conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); if (conn == NULL) fatal("Couldn't initialise connection to server"); pwd = do_realpath(conn, "."); if (pwd == NULL) fatal("Need cwd"); if (file1 != NULL) { dir = xstrdup(file1); dir = make_absolute(dir, pwd); if (remote_is_dir(conn, dir) && file2 == NULL) { printf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); parse_dispatch_command(conn, cmd, &pwd); } else { if (file2 == NULL) snprintf(cmd, sizeof cmd, "get %s", dir); else snprintf(cmd, sizeof cmd, "get %s %s", dir, file2); parse_dispatch_command(conn, cmd, &pwd); xfree(dir); return; } xfree(dir); } #if HAVE_SETVBUF setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); #else setlinebuf(stdout); setlinebuf(infile); #endif for (;;) { char *cp; printf("sftp> "); /* XXX: use libedit */ if (fgets(cmd, sizeof(cmd), infile) == NULL) { printf("\n"); break; } else if (infile != stdin) /* Bluff typing */ printf("%s", cmd); cp = strrchr(cmd, '\n'); if (cp) *cp = '\0'; if (parse_dispatch_command(conn, cmd, &pwd)) break; } xfree(pwd); } diff --git a/crypto/openssh/sftp-server.c b/crypto/openssh/sftp-server.c index 9db28e7d3c8b..a5c325561efb 100644 --- a/crypto/openssh/sftp-server.c +++ b/crypto/openssh/sftp-server.c @@ -1,1132 +1,1132 @@ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.35 2002/06/06 17:30:11 markus Exp $"); +RCSID("$OpenBSD: sftp-server.c,v 1.37 2002/06/24 17:57:20 deraadt Exp $"); #include "buffer.h" #include "bufaux.h" #include "getput.h" #include "log.h" #include "xmalloc.h" #include "sftp.h" #include "sftp-common.h" /* helper */ #define get_int64() buffer_get_int64(&iqueue); #define get_int() buffer_get_int(&iqueue); #define get_string(lenp) buffer_get_string(&iqueue, lenp); #define TRACE debug #ifdef HAVE___PROGNAME extern char *__progname; #else char *__progname; #endif /* input and output queue */ Buffer iqueue; Buffer oqueue; /* Version of client */ int version; /* portable attibutes, etc. */ typedef struct Stat Stat; struct Stat { char *name; char *long_name; Attrib attrib; }; static int errno_to_portable(int unixerrno) { int ret = 0; switch (unixerrno) { case 0: ret = SSH2_FX_OK; break; case ENOENT: case ENOTDIR: case EBADF: case ELOOP: ret = SSH2_FX_NO_SUCH_FILE; break; case EPERM: case EACCES: case EFAULT: ret = SSH2_FX_PERMISSION_DENIED; break; case ENAMETOOLONG: case EINVAL: ret = SSH2_FX_BAD_MESSAGE; break; default: ret = SSH2_FX_FAILURE; break; } return ret; } static int flags_from_portable(int pflags) { int flags = 0; if ((pflags & SSH2_FXF_READ) && (pflags & SSH2_FXF_WRITE)) { flags = O_RDWR; } else if (pflags & SSH2_FXF_READ) { flags = O_RDONLY; } else if (pflags & SSH2_FXF_WRITE) { flags = O_WRONLY; } if (pflags & SSH2_FXF_CREAT) flags |= O_CREAT; if (pflags & SSH2_FXF_TRUNC) flags |= O_TRUNC; if (pflags & SSH2_FXF_EXCL) flags |= O_EXCL; return flags; } static Attrib * get_attrib(void) { return decode_attrib(&iqueue); } /* handle handles */ typedef struct Handle Handle; struct Handle { int use; DIR *dirp; int fd; char *name; }; enum { HANDLE_UNUSED, HANDLE_DIR, HANDLE_FILE }; Handle handles[100]; static void handle_init(void) { int i; for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) handles[i].use = HANDLE_UNUSED; } static int handle_new(int use, char *name, int fd, DIR *dirp) { int i; for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) { if (handles[i].use == HANDLE_UNUSED) { handles[i].use = use; handles[i].dirp = dirp; handles[i].fd = fd; handles[i].name = name; return i; } } return -1; } static int handle_is_ok(int i, int type) { return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; } static int handle_to_string(int handle, char **stringp, int *hlenp) { if (stringp == NULL || hlenp == NULL) return -1; *stringp = xmalloc(sizeof(int32_t)); PUT_32BIT(*stringp, handle); *hlenp = sizeof(int32_t); return 0; } static int handle_from_string(char *handle, u_int hlen) { int val; if (hlen != sizeof(int32_t)) return -1; val = GET_32BIT(handle); if (handle_is_ok(val, HANDLE_FILE) || handle_is_ok(val, HANDLE_DIR)) return val; return -1; } static char * handle_to_name(int handle) { if (handle_is_ok(handle, HANDLE_DIR)|| handle_is_ok(handle, HANDLE_FILE)) return handles[handle].name; return NULL; } static DIR * handle_to_dir(int handle) { if (handle_is_ok(handle, HANDLE_DIR)) return handles[handle].dirp; return NULL; } static int handle_to_fd(int handle) { if (handle_is_ok(handle, HANDLE_FILE)) return handles[handle].fd; return -1; } static int handle_close(int handle) { int ret = -1; if (handle_is_ok(handle, HANDLE_FILE)) { ret = close(handles[handle].fd); handles[handle].use = HANDLE_UNUSED; } else if (handle_is_ok(handle, HANDLE_DIR)) { ret = closedir(handles[handle].dirp); handles[handle].use = HANDLE_UNUSED; } else { errno = ENOENT; } return ret; } static int get_handle(void) { char *handle; int val = -1; u_int hlen; handle = get_string(&hlen); if (hlen < 256) val = handle_from_string(handle, hlen); xfree(handle); return val; } /* send replies */ static void send_msg(Buffer *m) { int mlen = buffer_len(m); buffer_put_int(&oqueue, mlen); buffer_append(&oqueue, buffer_ptr(m), mlen); buffer_consume(m, mlen); } static void send_status(u_int32_t id, u_int32_t error) { Buffer msg; const char *status_messages[] = { "Success", /* SSH_FX_OK */ "End of file", /* SSH_FX_EOF */ "No such file", /* SSH_FX_NO_SUCH_FILE */ "Permission denied", /* SSH_FX_PERMISSION_DENIED */ "Failure", /* SSH_FX_FAILURE */ "Bad message", /* SSH_FX_BAD_MESSAGE */ "No connection", /* SSH_FX_NO_CONNECTION */ "Connection lost", /* SSH_FX_CONNECTION_LOST */ "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ "Unknown error" /* Others */ }; - TRACE("sent status id %d error %d", id, error); + TRACE("sent status id %u error %u", id, error); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); buffer_put_int(&msg, error); if (version >= 3) { buffer_put_cstring(&msg, status_messages[MIN(error,SSH2_FX_MAX)]); buffer_put_cstring(&msg, ""); } send_msg(&msg); buffer_free(&msg); } static void send_data_or_handle(char type, u_int32_t id, char *data, int dlen) { Buffer msg; buffer_init(&msg); buffer_put_char(&msg, type); buffer_put_int(&msg, id); buffer_put_string(&msg, data, dlen); send_msg(&msg); buffer_free(&msg); } static void send_data(u_int32_t id, char *data, int dlen) { - TRACE("sent data id %d len %d", id, dlen); + TRACE("sent data id %u len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } static void send_handle(u_int32_t id, int handle) { char *string; int hlen; handle_to_string(handle, &string, &hlen); - TRACE("sent handle id %d handle %d", id, handle); + TRACE("sent handle id %u handle %d", id, handle); send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); xfree(string); } static void send_names(u_int32_t id, int count, Stat *stats) { Buffer msg; int i; buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_NAME); buffer_put_int(&msg, id); buffer_put_int(&msg, count); - TRACE("sent names id %d count %d", id, count); + TRACE("sent names id %u count %d", id, count); for (i = 0; i < count; i++) { buffer_put_cstring(&msg, stats[i].name); buffer_put_cstring(&msg, stats[i].long_name); encode_attrib(&msg, &stats[i].attrib); } send_msg(&msg); buffer_free(&msg); } static void send_attrib(u_int32_t id, Attrib *a) { Buffer msg; - TRACE("sent attrib id %d have 0x%x", id, a->flags); + TRACE("sent attrib id %u have 0x%x", id, a->flags); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_ATTRS); buffer_put_int(&msg, id); encode_attrib(&msg, a); send_msg(&msg); buffer_free(&msg); } /* parse incoming */ static void process_init(void) { Buffer msg; version = get_int(); TRACE("client version %d", version); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_VERSION); buffer_put_int(&msg, SSH2_FILEXFER_VERSION); send_msg(&msg); buffer_free(&msg); } static void process_open(void) { u_int32_t id, pflags; Attrib *a; char *name; int handle, fd, flags, mode, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); pflags = get_int(); /* portable flags */ a = get_attrib(); flags = flags_from_portable(pflags); mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; - TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode); + TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); fd = open(name, flags, mode); if (fd < 0) { status = errno_to_portable(errno); } else { handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); if (handle < 0) { close(fd); } else { send_handle(id, handle); status = SSH2_FX_OK; } } if (status != SSH2_FX_OK) send_status(id, status); xfree(name); } static void process_close(void) { u_int32_t id; int handle, ret, status = SSH2_FX_FAILURE; id = get_int(); handle = get_handle(); - TRACE("close id %d handle %d", id, handle); + TRACE("close id %u handle %d", id, handle); ret = handle_close(handle); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); } static void process_read(void) { char buf[64*1024]; u_int32_t id, len; int handle, fd, ret, status = SSH2_FX_FAILURE; u_int64_t off; id = get_int(); handle = get_handle(); off = get_int64(); len = get_int(); - TRACE("read id %d handle %d off %llu len %d", id, handle, + TRACE("read id %u handle %d off %llu len %d", id, handle, (u_int64_t)off, len); if (len > sizeof buf) { len = sizeof buf; log("read change len %d", len); } fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { error("process_read: seek failed"); status = errno_to_portable(errno); } else { ret = read(fd, buf, len); if (ret < 0) { status = errno_to_portable(errno); } else if (ret == 0) { status = SSH2_FX_EOF; } else { send_data(id, buf, ret); status = SSH2_FX_OK; } } } if (status != SSH2_FX_OK) send_status(id, status); } static void process_write(void) { u_int32_t id; u_int64_t off; u_int len; int handle, fd, ret, status = SSH2_FX_FAILURE; char *data; id = get_int(); handle = get_handle(); off = get_int64(); data = get_string(&len); - TRACE("write id %d handle %d off %llu len %d", id, handle, + TRACE("write id %u handle %d off %llu len %d", id, handle, (u_int64_t)off, len); fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { status = errno_to_portable(errno); error("process_write: seek failed"); } else { /* XXX ATOMICIO ? */ ret = write(fd, data, len); if (ret == -1) { error("process_write: write failed"); status = errno_to_portable(errno); } else if (ret == len) { status = SSH2_FX_OK; } else { log("nothing at all written"); } } } send_status(id, status); xfree(data); } static void process_do_stat(int do_lstat) { Attrib a; struct stat st; u_int32_t id; char *name; int ret, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); - TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name); + TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); ret = do_lstat ? lstat(name, &st) : stat(name, &st); if (ret < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); send_attrib(id, &a); status = SSH2_FX_OK; } if (status != SSH2_FX_OK) send_status(id, status); xfree(name); } static void process_stat(void) { process_do_stat(0); } static void process_lstat(void) { process_do_stat(1); } static void process_fstat(void) { Attrib a; struct stat st; u_int32_t id; int fd, ret, handle, status = SSH2_FX_FAILURE; id = get_int(); handle = get_handle(); - TRACE("fstat id %d handle %d", id, handle); + TRACE("fstat id %u handle %d", id, handle); fd = handle_to_fd(handle); if (fd >= 0) { ret = fstat(fd, &st); if (ret < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); send_attrib(id, &a); status = SSH2_FX_OK; } } if (status != SSH2_FX_OK) send_status(id, status); } static struct timeval * attrib_to_tv(Attrib *a) { static struct timeval tv[2]; tv[0].tv_sec = a->atime; tv[0].tv_usec = 0; tv[1].tv_sec = a->mtime; tv[1].tv_usec = 0; return tv; } static void process_setstat(void) { Attrib *a; u_int32_t id; char *name; - int ret; - int status = SSH2_FX_OK; + int status = SSH2_FX_OK, ret; id = get_int(); name = get_string(NULL); a = get_attrib(); - TRACE("setstat id %d name %s", id, name); + TRACE("setstat id %u name %s", id, name); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { ret = truncate(name, a->size); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { ret = chmod(name, a->perm & 0777); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { ret = utimes(name, attrib_to_tv(a)); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { ret = chown(name, a->uid, a->gid); if (ret == -1) status = errno_to_portable(errno); } send_status(id, status); xfree(name); } static void process_fsetstat(void) { Attrib *a; u_int32_t id; int handle, fd, ret; int status = SSH2_FX_OK; char *name; id = get_int(); handle = get_handle(); a = get_attrib(); - TRACE("fsetstat id %d handle %d", id, handle); + TRACE("fsetstat id %u handle %d", id, handle); fd = handle_to_fd(handle); name = handle_to_name(handle); if (fd < 0 || name == NULL) { status = SSH2_FX_FAILURE; } else { if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { ret = ftruncate(fd, a->size); if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { #ifdef HAVE_FCHMOD ret = fchmod(fd, a->perm & 0777); #else ret = chmod(name, a->perm & 0777); #endif if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { #ifdef HAVE_FUTIMES ret = futimes(fd, attrib_to_tv(a)); #else ret = utimes(name, attrib_to_tv(a)); #endif if (ret == -1) status = errno_to_portable(errno); } if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { #ifdef HAVE_FCHOWN ret = fchown(fd, a->uid, a->gid); #else ret = chown(name, a->uid, a->gid); #endif if (ret == -1) status = errno_to_portable(errno); } } send_status(id, status); } static void process_opendir(void) { DIR *dirp = NULL; char *path; int handle, status = SSH2_FX_FAILURE; u_int32_t id; id = get_int(); path = get_string(NULL); - TRACE("opendir id %d path %s", id, path); + TRACE("opendir id %u path %s", id, path); dirp = opendir(path); if (dirp == NULL) { status = errno_to_portable(errno); } else { handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); if (handle < 0) { closedir(dirp); } else { send_handle(id, handle); status = SSH2_FX_OK; } } if (status != SSH2_FX_OK) send_status(id, status); xfree(path); } /* * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh */ static char * ls_file(char *name, struct stat *st) { int ulen, glen, sz = 0; struct passwd *pw; struct group *gr; struct tm *ltime = localtime(&st->st_mtime); char *user, *group; char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; strmode(st->st_mode, mode); if ((pw = getpwuid(st->st_uid)) != NULL) { user = pw->pw_name; } else { - snprintf(ubuf, sizeof ubuf, "%d", st->st_uid); + snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); user = ubuf; } if ((gr = getgrgid(st->st_gid)) != NULL) { group = gr->gr_name; } else { - snprintf(gbuf, sizeof gbuf, "%d", st->st_gid); + snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); group = gbuf; } if (ltime != NULL) { if (time(NULL) - st->st_mtime < (365*24*60*60)/2) sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); else sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); } if (sz == 0) tbuf[0] = '\0'; ulen = MAX(strlen(user), 8); glen = MAX(strlen(group), 8); snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode, st->st_nlink, ulen, user, glen, group, (u_int64_t)st->st_size, tbuf, name); return xstrdup(buf); } static void process_readdir(void) { DIR *dirp; struct dirent *dp; char *path; int handle; u_int32_t id; id = get_int(); handle = get_handle(); - TRACE("readdir id %d handle %d", id, handle); + TRACE("readdir id %u handle %d", id, handle); dirp = handle_to_dir(handle); path = handle_to_name(handle); if (dirp == NULL || path == NULL) { send_status(id, SSH2_FX_FAILURE); } else { struct stat st; char pathname[1024]; Stat *stats; int nstats = 10, count = 0, i; + stats = xmalloc(nstats * sizeof(Stat)); while ((dp = readdir(dirp)) != NULL) { if (count >= nstats) { nstats *= 2; stats = xrealloc(stats, nstats * sizeof(Stat)); } /* XXX OVERFLOW ? */ snprintf(pathname, sizeof pathname, "%s%s%s", path, strcmp(path, "/") ? "/" : "", dp->d_name); if (lstat(pathname, &st) < 0) continue; stat_to_attrib(&st, &(stats[count].attrib)); stats[count].name = xstrdup(dp->d_name); stats[count].long_name = ls_file(dp->d_name, &st); count++; /* send up to 100 entries in one message */ /* XXX check packet size instead */ if (count == 100) break; } if (count > 0) { send_names(id, count, stats); for (i = 0; i < count; i++) { xfree(stats[i].name); xfree(stats[i].long_name); } } else { send_status(id, SSH2_FX_EOF); } xfree(stats); } } static void process_remove(void) { char *name; u_int32_t id; int status = SSH2_FX_FAILURE; int ret; id = get_int(); name = get_string(NULL); - TRACE("remove id %d name %s", id, name); + TRACE("remove id %u name %s", id, name); ret = unlink(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } static void process_mkdir(void) { Attrib *a; u_int32_t id; char *name; int ret, mode, status = SSH2_FX_FAILURE; id = get_int(); name = get_string(NULL); a = get_attrib(); mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm & 0777 : 0777; - TRACE("mkdir id %d name %s mode 0%o", id, name, mode); + TRACE("mkdir id %u name %s mode 0%o", id, name, mode); ret = mkdir(name, mode); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } static void process_rmdir(void) { u_int32_t id; char *name; int ret, status; id = get_int(); name = get_string(NULL); - TRACE("rmdir id %d name %s", id, name); + TRACE("rmdir id %u name %s", id, name); ret = rmdir(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); xfree(name); } static void process_realpath(void) { char resolvedname[MAXPATHLEN]; u_int32_t id; char *path; id = get_int(); path = get_string(NULL); if (path[0] == '\0') { xfree(path); path = xstrdup("."); } - TRACE("realpath id %d path %s", id, path); + TRACE("realpath id %u path %s", id, path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { Stat s; attrib_clear(&s.attrib); s.name = s.long_name = resolvedname; send_names(id, 1, &s); } xfree(path); } static void process_rename(void) { u_int32_t id; struct stat st; char *oldpath, *newpath; int ret, status = SSH2_FX_FAILURE; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - TRACE("rename id %d old %s new %s", id, oldpath, newpath); + TRACE("rename id %u old %s new %s", id, oldpath, newpath); /* fail if 'newpath' exists */ if (stat(newpath, &st) == -1) { ret = rename(oldpath, newpath); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; } send_status(id, status); xfree(oldpath); xfree(newpath); } static void process_readlink(void) { u_int32_t id; int len; char link[MAXPATHLEN]; char *path; id = get_int(); path = get_string(NULL); - TRACE("readlink id %d path %s", id, path); + TRACE("readlink id %u path %s", id, path); if ((len = readlink(path, link, sizeof(link) - 1)) == -1) send_status(id, errno_to_portable(errno)); else { Stat s; link[len] = '\0'; attrib_clear(&s.attrib); s.name = s.long_name = link; send_names(id, 1, &s); } xfree(path); } static void process_symlink(void) { u_int32_t id; struct stat st; char *oldpath, *newpath; int ret, status = SSH2_FX_FAILURE; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - TRACE("symlink id %d old %s new %s", id, oldpath, newpath); + TRACE("symlink id %u old %s new %s", id, oldpath, newpath); /* fail if 'newpath' exists */ if (stat(newpath, &st) == -1) { ret = symlink(oldpath, newpath); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; } send_status(id, status); xfree(oldpath); xfree(newpath); } static void process_extended(void) { u_int32_t id; char *request; id = get_int(); request = get_string(NULL); send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ xfree(request); } /* stolen from ssh-agent */ static void process(void) { u_int msg_len; u_int buf_len; u_int consumed; u_int type; u_char *cp; buf_len = buffer_len(&iqueue); if (buf_len < 5) return; /* Incomplete message. */ cp = buffer_ptr(&iqueue); msg_len = GET_32BIT(cp); if (msg_len > 256 * 1024) { error("bad message "); exit(11); } if (buf_len < msg_len + 4) return; buffer_consume(&iqueue, 4); buf_len -= 4; type = buffer_get_char(&iqueue); switch (type) { case SSH2_FXP_INIT: process_init(); break; case SSH2_FXP_OPEN: process_open(); break; case SSH2_FXP_CLOSE: process_close(); break; case SSH2_FXP_READ: process_read(); break; case SSH2_FXP_WRITE: process_write(); break; case SSH2_FXP_LSTAT: process_lstat(); break; case SSH2_FXP_FSTAT: process_fstat(); break; case SSH2_FXP_SETSTAT: process_setstat(); break; case SSH2_FXP_FSETSTAT: process_fsetstat(); break; case SSH2_FXP_OPENDIR: process_opendir(); break; case SSH2_FXP_READDIR: process_readdir(); break; case SSH2_FXP_REMOVE: process_remove(); break; case SSH2_FXP_MKDIR: process_mkdir(); break; case SSH2_FXP_RMDIR: process_rmdir(); break; case SSH2_FXP_REALPATH: process_realpath(); break; case SSH2_FXP_STAT: process_stat(); break; case SSH2_FXP_RENAME: process_rename(); break; case SSH2_FXP_READLINK: process_readlink(); break; case SSH2_FXP_SYMLINK: process_symlink(); break; case SSH2_FXP_EXTENDED: process_extended(); break; default: error("Unknown message %d", type); break; } /* discard the remaining bytes from the current packet */ if (buf_len < buffer_len(&iqueue)) fatal("iqueue grows"); consumed = buf_len - buffer_len(&iqueue); if (msg_len < consumed) fatal("msg_len %d < consumed %d", msg_len, consumed); if (msg_len > consumed) buffer_consume(&iqueue, msg_len - consumed); } int main(int ac, char **av) { fd_set *rset, *wset; int in, out, max; ssize_t len, olen, set_size; /* XXX should use getopt */ __progname = get_progname(av[0]); handle_init(); #ifdef DEBUG_SFTP_SERVER log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); #endif in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO); #ifdef HAVE_CYGWIN setmode(in, O_BINARY); setmode(out, O_BINARY); #endif max = 0; if (in > max) max = in; if (out > max) max = out; buffer_init(&iqueue); buffer_init(&oqueue); set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); rset = (fd_set *)xmalloc(set_size); wset = (fd_set *)xmalloc(set_size); for (;;) { memset(rset, 0, set_size); memset(wset, 0, set_size); FD_SET(in, rset); olen = buffer_len(&oqueue); if (olen > 0) FD_SET(out, wset); if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; exit(2); } /* copy stdin to iqueue */ if (FD_ISSET(in, rset)) { char buf[4*4096]; len = read(in, buf, sizeof buf); if (len == 0) { debug("read eof"); exit(0); } else if (len < 0) { error("read error"); exit(1); } else { buffer_append(&iqueue, buf, len); } } /* send oqueue to stdout */ if (FD_ISSET(out, wset)) { len = write(out, buffer_ptr(&oqueue), olen); if (len < 0) { error("write error"); exit(1); } else { buffer_consume(&oqueue, len); } } /* process requests from client */ process(); } } diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index f941d18faae5..fac2564ded5d 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,256 +1,259 @@ /* * Copyright (c) 2001,2002 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.29 2002/04/02 17:37:48 markus Exp $"); +RCSID("$OpenBSD: sftp.c,v 1.30 2002/06/23 09:30:14 deraadt Exp $"); /* XXX: short-form remote directory listings (like 'ls -C') */ #include "buffer.h" #include "xmalloc.h" #include "log.h" #include "pathnames.h" #include "misc.h" #include "sftp.h" #include "sftp-common.h" #include "sftp-client.h" #include "sftp-int.h" #ifdef HAVE___PROGNAME extern char *__progname; #else char *__progname; #endif FILE* infile; size_t copy_buffer_len = 32768; size_t num_requests = 16; static void connect_to_server(char *path, 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, args); fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); exit(1); } close(c_in); close(c_out); } static void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" " [-F config] [-P direct server path] [-S program]\n" " [user@]host[:file [file]]\n", __progname); exit(1); } int main(int argc, char **argv) { int in, out, ch; pid_t sshpid; char *host, *userhost, *cp, *file2; int debug_level = 0, sshver = 2; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; LogLevel ll = SYSLOG_LEVEL_INFO; arglist args; extern int optind; extern char *optarg; __progname = get_progname(argv[0]); args.list = NULL; addargs(&args, "ssh"); /* overwritten with ssh_program */ addargs(&args, "-oFallBackToRsh no"); addargs(&args, "-oForwardX11 no"); addargs(&args, "-oForwardAgent no"); addargs(&args, "-oClearAllForwardings yes"); ll = SYSLOG_LEVEL_INFO; infile = stdin; /* Read from STDIN unless changed by -b */ while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { switch (ch) { case 'C': addargs(&args, "-C"); break; case 'v': if (debug_level < 3) { addargs(&args, "-v"); ll = SYSLOG_LEVEL_DEBUG1 + debug_level; } debug_level++; break; case 'F': case 'o': addargs(&args, "-%c%s", ch, optarg); break; case '1': sshver = 1; if (sftp_server == NULL) sftp_server = _PATH_SFTP_SERVER; break; case 's': sftp_server = optarg; break; case 'S': ssh_program = optarg; break; case 'b': if (infile == stdin) { infile = fopen(optarg, "r"); if (infile == NULL) fatal("%s (%s).", strerror(errno), optarg); } else fatal("Filename already specified."); break; case 'P': sftp_direct = optarg; break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') fatal("Invalid buffer size \"%s\"", optarg); break; case 'R': num_requests = strtol(optarg, &cp, 10); if (num_requests == 0 || *cp != '\0') fatal("Invalid number of requests \"%s\"", optarg); break; case 'h': default: usage(); } } log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); if (sftp_direct == NULL) { if (optind == argc || argc > (optind + 2)) usage(); userhost = xstrdup(argv[optind]); file2 = argv[optind+1]; if ((cp = colon(userhost)) != NULL) { *cp++ = '\0'; file1 = cp; } if ((host = strchr(userhost, '@')) == NULL) host = userhost; else { *host++ = '\0'; if (!userhost[0]) { fprintf(stderr, "Missing username\n"); usage(); } addargs(&args, "-l%s",userhost); } host = cleanhostname(host); if (!*host) { fprintf(stderr, "Missing hostname\n"); usage(); } addargs(&args, "-oProtocol %d", sshver); /* no subsystem if the server-spec contains a '/' */ if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); args.list[0] = ssh_program; fprintf(stderr, "Connecting to %s...\n", host); connect_to_server(ssh_program, args.list, &in, &out, &sshpid); } else { args.list = NULL; addargs(&args, "sftp-server"); fprintf(stderr, "Attaching to %s...\n", sftp_direct); connect_to_server(sftp_direct, args.list, &in, &out, &sshpid); } interactive_loop(in, out, file1, file2); #if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); shutdown(out, SHUT_RDWR); #endif close(in); close(out); if (infile != stdin) fclose(infile); while (waitpid(sshpid, NULL, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for ssh process: %s", strerror(errno)); exit(0); } diff --git a/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1 index e5ea1e325580..0227436c1719 100644 --- a/crypto/openssh/ssh-agent.1 +++ b/crypto/openssh/ssh-agent.1 @@ -1,185 +1,185 @@ -.\" $OpenBSD: ssh-agent.1,v 1.33 2002/06/19 00:27:55 deraadt Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.35 2002/06/24 13:12:23 markus Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland .\" All rights reserved .\" .\" As far as I am concerned, the code I have written for this software .\" can be used freely for any purpose. Any derived versions of this .\" software must be clearly marked as such, and if the derived work is .\" incompatible with the protocol description in the RFC file, it must be .\" called by a name other than "ssh" or "Secure Shell". .\" .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd September 25, 1999 .Dt SSH-AGENT 1 .Os .Sh NAME .Nm ssh-agent .Nd authentication agent .Sh SYNOPSIS .Nm ssh-agent .Op Fl a Ar bind_address .Op Fl c Li | Fl s .Op Fl d .Op Ar command Op Ar args ... .Nm ssh-agent .Op Fl c Li | Fl s .Fl k .Sh DESCRIPTION .Nm is a program to hold private keys used for public key authentication (RSA, DSA). The idea is that .Nm is started in the beginning of an X-session or a login session, and all other windows or programs are started as clients to the ssh-agent program. Through use of environment variables the agent can be located and automatically used for authentication when logging in to other machines using .Xr ssh 1 . .Pp The options are as follows: .Bl -tag -width Ds .It Fl a Ar bind_address Bind the agent to the unix-domain socket .Ar bind_address . The default is -.Pa /tmp/ssh-XXXXXXXX/agent. . +.Pa /tmp/ssh-XXXXXXXX/agent. . .It Fl c Generate C-shell commands on .Dv stdout . This is the default if .Ev SHELL looks like it's a csh style of shell. .It Fl s Generate Bourne shell commands on .Dv stdout . This is the default if .Ev SHELL does not look like it's a csh style of shell. .It Fl k Kill the current agent (given by the .Ev SSH_AGENT_PID environment variable). .It Fl d Debug mode. When this option is specified .Nm will not fork. .El .Pp If a commandline is given, this is executed as a subprocess of the agent. When the command dies, so does the agent. .Pp The agent initially does not have any private keys. Keys are added using .Xr ssh-add 1 . When executed without arguments, .Xr ssh-add 1 adds the files .Pa $HOME/.ssh/id_rsa , .Pa $HOME/.ssh/id_dsa and .Pa $HOME/.ssh/identity . If the identity has a passphrase, .Xr ssh-add 1 asks for the passphrase (using a small X11 application if running under X11, or from the terminal if running without X). It then sends the identity to the agent. Several identities can be stored in the agent; the agent can automatically use any of these identities. .Ic ssh-add -l displays the identities currently held by the agent. .Pp The idea is that the agent is run in the user's local PC, laptop, or terminal. Authentication data need not be stored on any other machine, and authentication passphrases never go over the network. However, the connection to the agent is forwarded over SSH remote logins, and the user can thus use the privileges given by the identities anywhere in the network in a secure way. .Pp There are two main ways to get an agent setup: Either the agent starts a new subcommand into which some environment variables are exported, or the agent prints the needed shell commands (either .Xr sh 1 or .Xr csh 1 syntax can be generated) which can be evalled in the calling shell. Later .Xr ssh 1 looks at these variables and uses them to establish a connection to the agent. .Pp The agent will never send a private key over its request channel. Instead, operations that require a private key will be performed by the agent, and the result will be returned to the requester. This way, private keys are not exposed to clients using the agent. .Pp A unix-domain socket is created and the name of this socket is stored in the .Ev SSH_AUTH_SOCK environment variable. The socket is made accessible only to the current user. This method is easily abused by root or another instance of the same user. .Pp The .Ev SSH_AGENT_PID -environment variable holds the agent's PID. +environment variable holds the agent's process ID. .Pp The agent exits automatically when the command given on the command line terminates. .Sh FILES .Bl -tag -width Ds .It Pa $HOME/.ssh/identity Contains the protocol version 1 RSA authentication identity of the user. .It Pa $HOME/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of the user. .It Pa $HOME/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. -.It Pa /tmp/ssh-XXXXXXXX/agent. +.It Pa /tmp/ssh-XXXXXXXX/agent. Unix-domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El .Sh AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , .Xr sshd 8 diff --git a/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c index 02403f550afc..dbf8465bae54 100644 --- a/crypto/openssh/ssh-dss.c +++ b/crypto/openssh/ssh-dss.c @@ -1,185 +1,181 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: ssh-dss.c,v 1.14 2002/02/28 15:46:33 markus Exp $"); +RCSID("$OpenBSD: ssh-dss.c,v 1.15 2002/06/23 03:30:17 deraadt Exp $"); #include #include #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" #include "compat.h" #include "log.h" #include "key.h" #include "ssh-dss.h" #define INTBLOB_LEN 20 #define SIGBLOB_LEN (2*INTBLOB_LEN) int -ssh_dss_sign( - Key *key, - u_char **sigp, u_int *lenp, +ssh_dss_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) { DSA_SIG *sig; const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; u_char *ret, digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; u_int rlen, slen, len, dlen; Buffer b; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { error("ssh_dss_sign: no DSA key"); return -1; } EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); sig = DSA_do_sign(digest, dlen, key->dsa); memset(digest, 'd', sizeof(digest)); if (sig == NULL) { error("ssh_dss_sign: sign failed"); return -1; } rlen = BN_num_bytes(sig->r); slen = BN_num_bytes(sig->s); if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { - error("bad sig size %d %d", rlen, slen); + error("bad sig size %u %u", rlen, slen); DSA_SIG_free(sig); return -1; } memset(sigblob, 0, SIGBLOB_LEN); BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); DSA_SIG_free(sig); if (datafellows & SSH_BUG_SIGBLOB) { ret = xmalloc(SIGBLOB_LEN); memcpy(ret, sigblob, SIGBLOB_LEN); if (lenp != NULL) *lenp = SIGBLOB_LEN; if (sigp != NULL) *sigp = ret; } else { /* ietf-drafts */ buffer_init(&b); buffer_put_cstring(&b, "ssh-dss"); buffer_put_string(&b, sigblob, SIGBLOB_LEN); len = buffer_len(&b); ret = xmalloc(len); memcpy(ret, buffer_ptr(&b), len); buffer_free(&b); if (lenp != NULL) *lenp = len; if (sigp != NULL) *sigp = ret; } return 0; } int -ssh_dss_verify( - Key *key, - u_char *signature, u_int signaturelen, +ssh_dss_verify(Key *key, u_char *signature, u_int signaturelen, u_char *data, u_int datalen) { DSA_SIG *sig; const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; u_char digest[EVP_MAX_MD_SIZE], *sigblob; u_int len, dlen; int rlen, ret; Buffer b; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { error("ssh_dss_verify: no DSA key"); return -1; } /* fetch signature */ if (datafellows & SSH_BUG_SIGBLOB) { sigblob = signature; len = signaturelen; } else { /* ietf-drafts */ char *ktype; buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_string(&b, NULL); if (strcmp("ssh-dss", ktype) != 0) { error("ssh_dss_verify: cannot handle type %s", ktype); buffer_free(&b); xfree(ktype); return -1; } xfree(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("ssh_dss_verify: " "remaining bytes in signature %d", rlen); xfree(sigblob); return -1; } } if (len != SIGBLOB_LEN) { - fatal("bad sigbloblen %d != SIGBLOB_LEN", len); + fatal("bad sigbloblen %u != SIGBLOB_LEN", len); } /* parse signature */ if ((sig = DSA_SIG_new()) == NULL) fatal("ssh_dss_verify: DSA_SIG_new failed"); if ((sig->r = BN_new()) == NULL) fatal("ssh_dss_verify: BN_new failed"); if ((sig->s = BN_new()) == NULL) fatal("ssh_dss_verify: BN_new failed"); BN_bin2bn(sigblob, INTBLOB_LEN, sig->r); BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s); if (!(datafellows & SSH_BUG_SIGBLOB)) { memset(sigblob, 0, len); xfree(sigblob); } /* sha1 the data */ EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); ret = DSA_do_verify(digest, dlen, sig, key->dsa); memset(digest, 'd', sizeof(digest)); DSA_SIG_free(sig); debug("ssh_dss_verify: signature %s", ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); return ret; } diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index df8c90afb756..4273c11321c8 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -1,1003 +1,1004 @@ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland * All rights reserved * Identity and host key generation and maintenance. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.101 2002/06/23 09:39:55 deraadt Exp $"); #include #include #include "xmalloc.h" #include "key.h" #include "rsa.h" #include "authfile.h" #include "uuencode.h" #include "buffer.h" #include "bufaux.h" #include "pathnames.h" #include "log.h" #include "readpass.h" #ifdef SMARTCARD #include "scard.h" #endif /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ int bits = 1024; /* * Flag indicating that we just want to change the passphrase. This can be * set on the command line. */ int change_passphrase = 0; /* * Flag indicating that we just want to change the comment. This can be set * on the command line. */ int change_comment = 0; int quiet = 0; /* Flag indicating that we just want to see the key fingerprint */ int print_fingerprint = 0; int print_bubblebabble = 0; /* The identity file name, given on the command line or entered by the user. */ char identity_file[1024]; int have_identity = 0; /* This is set to the passphrase if given on the command line. */ char *identity_passphrase = NULL; /* This is set to the new passphrase if given on the command line. */ char *identity_new_passphrase = NULL; /* This is set to the new comment if given on the command line. */ char *identity_comment = NULL; /* Dump public key file in format used by real and the original SSH 2 */ int convert_to_ssh2 = 0; int convert_from_ssh2 = 0; int print_public = 0; char *key_type_name = NULL; /* argv0 */ #ifdef HAVE___PROGNAME extern char *__progname; #else char *__progname; #endif char hostname[MAXHOSTNAMELEN]; static void ask_filename(struct passwd *pw, const char *prompt) { char buf[1024]; char *name = NULL; if (key_type_name == NULL) name = _PATH_SSH_CLIENT_ID_RSA; else switch (key_type_from_name(key_type_name)) { case KEY_RSA1: name = _PATH_SSH_CLIENT_IDENTITY; break; case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; break; case KEY_RSA: name = _PATH_SSH_CLIENT_ID_RSA; break; default: fprintf(stderr, "bad key type"); exit(1); break; } snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); fprintf(stderr, "%s (%s): ", prompt, identity_file); fflush(stderr); if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1); if (strchr(buf, '\n')) *strchr(buf, '\n') = 0; if (strcmp(buf, "") != 0) strlcpy(identity_file, buf, sizeof(identity_file)); have_identity = 1; } static Key * load_identity(char *filename) { char *pass; Key *prv; prv = key_load_private(filename, "", NULL); if (prv == NULL) { if (identity_passphrase) pass = xstrdup(identity_passphrase); else pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); prv = key_load_private(filename, pass, NULL); memset(pass, 0, strlen(pass)); xfree(pass); } return prv; } #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb static void do_convert_to_ssh2(struct passwd *pw) { Key *k; u_int len; u_char *blob; struct stat st; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } if ((k = key_load_public(identity_file, NULL)) == NULL) { if ((k = load_identity(identity_file)) == NULL) { fprintf(stderr, "load failed\n"); exit(1); } } if (key_to_blob(k, &blob, &len) <= 0) { fprintf(stderr, "key_to_blob failed\n"); exit(1); } fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, - "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", + "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n", key_size(k), key_type(k), pw->pw_name, hostname); dump_base64(stdout, blob, len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); key_free(k); xfree(blob); exit(0); } static void buffer_get_bignum_bits(Buffer *b, BIGNUM *value) { int bits = buffer_get_int(b); int bytes = (bits + 7) / 8; if (buffer_len(b) < bytes) fatal("buffer_get_bignum_bits: input buffer too small: " "need %d have %d", bytes, buffer_len(b)); BN_bin2bn(buffer_ptr(b), bytes, value); buffer_consume(b, bytes); } static Key * do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) { Buffer b; Key *key = NULL; char *type, *cipher; u_char *sig, data[] = "abcde12345"; int magic, rlen, ktype, i1, i2, i3, i4; u_int slen; u_long e; buffer_init(&b); buffer_append(&b, blob, blen); magic = buffer_get_int(&b); if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); buffer_free(&b); return NULL; } i1 = buffer_get_int(&b); type = buffer_get_string(&b, NULL); cipher = buffer_get_string(&b, NULL); i2 = buffer_get_int(&b); i3 = buffer_get_int(&b); i4 = buffer_get_int(&b); debug("ignore (%d %d %d %d)", i1,i2,i3,i4); if (strcmp(cipher, "none") != 0) { error("unsupported cipher %s", cipher); xfree(cipher); buffer_free(&b); xfree(type); return NULL; } xfree(cipher); if (strstr(type, "dsa")) { ktype = KEY_DSA; } else if (strstr(type, "rsa")) { ktype = KEY_RSA; } else { xfree(type); return NULL; } key = key_new_private(ktype); xfree(type); switch (key->type) { case KEY_DSA: buffer_get_bignum_bits(&b, key->dsa->p); buffer_get_bignum_bits(&b, key->dsa->g); buffer_get_bignum_bits(&b, key->dsa->q); buffer_get_bignum_bits(&b, key->dsa->pub_key); buffer_get_bignum_bits(&b, key->dsa->priv_key); break; case KEY_RSA: e = buffer_get_char(&b); debug("e %lx", e); if (e < 30) { e <<= 8; e += buffer_get_char(&b); debug("e %lx", e); e <<= 8; e += buffer_get_char(&b); debug("e %lx", e); } if (!BN_set_word(key->rsa->e, e)) { buffer_free(&b); key_free(key); return NULL; } buffer_get_bignum_bits(&b, key->rsa->d); buffer_get_bignum_bits(&b, key->rsa->n); buffer_get_bignum_bits(&b, key->rsa->iqmp); buffer_get_bignum_bits(&b, key->rsa->q); buffer_get_bignum_bits(&b, key->rsa->p); rsa_generate_additional_parameters(key->rsa); break; } rlen = buffer_len(&b); if (rlen != 0) error("do_convert_private_ssh2_from_blob: " "remaining bytes in key blob %d", rlen); buffer_free(&b); /* try the key */ key_sign(key, &sig, &slen, data, sizeof(data)); key_verify(key, sig, slen, data, sizeof(data)); xfree(sig); return key; } static void do_convert_from_ssh2(struct passwd *pw) { Key *k; int blen; u_int len; char line[1024], *p; u_char blob[8096]; char encoded[8096]; struct stat st; int escaped = 0, private = 0, ok; FILE *fp; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } fp = fopen(identity_file, "r"); if (fp == NULL) { perror(identity_file); exit(1); } encoded[0] = '\0'; while (fgets(line, sizeof(line), fp)) { if (!(p = strchr(line, '\n'))) { fprintf(stderr, "input line too long.\n"); exit(1); } if (p > line && p[-1] == '\\') escaped++; if (strncmp(line, "----", 4) == 0 || strstr(line, ": ") != NULL) { if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) private = 1; if (strstr(line, " END ") != NULL) { break; } /* fprintf(stderr, "ignore: %s", line); */ continue; } if (escaped) { escaped--; /* fprintf(stderr, "escaped: %s", line); */ continue; } *p = '\0'; strlcat(encoded, line, sizeof(encoded)); } len = strlen(encoded); if (((len % 4) == 3) && (encoded[len-1] == '=') && (encoded[len-2] == '=') && (encoded[len-3] == '=')) encoded[len-3] = '\0'; blen = uudecode(encoded, blob, sizeof(blob)); if (blen < 0) { fprintf(stderr, "uudecode failed.\n"); exit(1); } k = private ? do_convert_private_ssh2_from_blob(blob, blen) : key_from_blob(blob, blen); if (k == NULL) { fprintf(stderr, "decode blob failed.\n"); exit(1); } ok = private ? (k->type == KEY_DSA ? PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : key_write(k, stdout); if (!ok) { fprintf(stderr, "key write failed"); exit(1); } key_free(k); if (!private) fprintf(stdout, "\n"); fclose(fp); exit(0); } static void do_print_public(struct passwd *pw) { Key *prv; struct stat st; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } prv = load_identity(identity_file); if (prv == NULL) { fprintf(stderr, "load failed\n"); exit(1); } if (!key_write(prv, stdout)) fprintf(stderr, "key_write failed"); key_free(prv); fprintf(stdout, "\n"); exit(0); } #ifdef SMARTCARD static void do_upload(struct passwd *pw, const char *sc_reader_id) { Key *prv = NULL; struct stat st; int ret; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } prv = load_identity(identity_file); if (prv == NULL) { error("load failed"); exit(1); } ret = sc_put_key(prv, sc_reader_id); key_free(prv); if (ret < 0) exit(1); log("loading key done"); exit(0); } static void do_download(struct passwd *pw, const char *sc_reader_id) { Key **keys = NULL; int i; keys = sc_get_keys(sc_reader_id, NULL); if (keys == NULL) fatal("cannot read public key from smartcard"); for (i = 0; keys[i]; i++) { key_write(keys[i], stdout); key_free(keys[i]); fprintf(stdout, "\n"); } xfree(keys); exit(0); } #endif /* SMARTCARD */ static void do_fingerprint(struct passwd *pw) { FILE *f; Key *public; char *comment = NULL, *cp, *ep, line[16*1024], *fp; int i, skip = 0, num = 1, invalid = 1; enum fp_rep rep; enum fp_type fptype; struct stat st; fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } public = key_load_public(identity_file, &comment); if (public != NULL) { fp = key_fingerprint(public, fptype, rep); - printf("%d %s %s\n", key_size(public), fp, comment); + printf("%u %s %s\n", key_size(public), fp, comment); key_free(public); xfree(comment); xfree(fp); exit(0); } if (comment) xfree(comment); f = fopen(identity_file, "r"); if (f != NULL) { while (fgets(line, sizeof(line), f)) { i = strlen(line) - 1; if (line[i] != '\n') { error("line %d too long: %.40s...", num, line); skip = 1; continue; } num++; if (skip) { skip = 0; continue; } line[i] = '\0'; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue ; i = strtol(cp, &ep, 10); if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { int quoted = 0; comment = cp; - for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + for (; *cp && (quoted || (*cp != ' ' && + *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } if (!*cp) continue; *cp++ = '\0'; } ep = cp; public = key_new(KEY_RSA1); if (key_read(public, &cp) != 1) { cp = ep; key_free(public); public = key_new(KEY_UNSPEC); if (key_read(public, &cp) != 1) { key_free(public); continue; } } comment = *cp ? cp : comment; fp = key_fingerprint(public, fptype, rep); - printf("%d %s %s\n", key_size(public), fp, + printf("%u %s %s\n", key_size(public), fp, comment ? comment : "no comment"); xfree(fp); key_free(public); invalid = 0; } fclose(f); } if (invalid) { printf("%s is not a public key file.\n", identity_file); exit(1); } exit(0); } /* * Perform changing a passphrase. The argument is the passwd structure * for the current user. */ static void do_change_passphrase(struct passwd *pw) { char *comment; char *old_passphrase, *passphrase1, *passphrase2; struct stat st; Key *private; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } /* Try to load the file with empty passphrase. */ private = key_load_private(identity_file, "", &comment); if (private == NULL) { if (identity_passphrase) old_passphrase = xstrdup(identity_passphrase); else old_passphrase = read_passphrase("Enter old passphrase: ", RP_ALLOW_STDIN); private = key_load_private(identity_file, old_passphrase, &comment); memset(old_passphrase, 0, strlen(old_passphrase)); xfree(old_passphrase); if (private == NULL) { printf("Bad passphrase.\n"); exit(1); } } printf("Key has comment '%s'\n", comment); /* Ask the new passphrase (twice). */ if (identity_new_passphrase) { passphrase1 = xstrdup(identity_new_passphrase); passphrase2 = NULL; } else { passphrase1 = read_passphrase("Enter new passphrase (empty for no " "passphrase): ", RP_ALLOW_STDIN); passphrase2 = read_passphrase("Enter same passphrase again: ", RP_ALLOW_STDIN); /* Verify that they are the same. */ if (strcmp(passphrase1, passphrase2) != 0) { memset(passphrase1, 0, strlen(passphrase1)); memset(passphrase2, 0, strlen(passphrase2)); xfree(passphrase1); xfree(passphrase2); printf("Pass phrases do not match. Try again.\n"); exit(1); } /* Destroy the other copy. */ memset(passphrase2, 0, strlen(passphrase2)); xfree(passphrase2); } /* Save the file using the new passphrase. */ if (!key_save_private(private, identity_file, passphrase1, comment)) { printf("Saving the key failed: %s.\n", identity_file); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); key_free(private); xfree(comment); exit(1); } /* Destroy the passphrase and the copy of the key in memory. */ memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); key_free(private); /* Destroys contents */ xfree(comment); printf("Your identification has been saved with the new passphrase.\n"); exit(0); } /* * Change the comment of a private key file. */ static void do_change_comment(struct passwd *pw) { char new_comment[1024], *comment, *passphrase; Key *private; Key *public; struct stat st; FILE *f; int fd; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } private = key_load_private(identity_file, "", &comment); if (private == NULL) { if (identity_passphrase) passphrase = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase = xstrdup(identity_new_passphrase); else passphrase = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); /* Try to load using the passphrase. */ private = key_load_private(identity_file, passphrase, &comment); if (private == NULL) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); printf("Bad passphrase.\n"); exit(1); } } else { passphrase = xstrdup(""); } if (private->type != KEY_RSA1) { fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); key_free(private); exit(1); } printf("Key now has comment '%s'\n", comment); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); } else { printf("Enter new comment: "); fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { memset(passphrase, 0, strlen(passphrase)); key_free(private); exit(1); } if (strchr(new_comment, '\n')) *strchr(new_comment, '\n') = 0; } /* Save the file using the new passphrase. */ if (!key_save_private(private, identity_file, passphrase, new_comment)) { printf("Saving the key failed: %s.\n", identity_file); memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); key_free(private); xfree(comment); exit(1); } memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); public = key_from_private(private); key_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } f = fdopen(fd, "w"); if (f == NULL) { printf("fdopen %s failed", identity_file); exit(1); } if (!key_write(public, f)) fprintf(stderr, "write key failed"); key_free(public); fprintf(f, " %s\n", new_comment); fclose(f); xfree(comment); printf("The comment in your key file has been changed.\n"); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n", __progname); fprintf(stderr, "Options:\n"); fprintf(stderr, " -b bits Number of bits in the key to create.\n"); fprintf(stderr, " -c Change comment in private and public key files.\n"); fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n"); fprintf(stderr, " -f filename Filename of the key file.\n"); fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n"); fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -y Read private key file and print public key.\n"); fprintf(stderr, " -t type Specify type of key to create.\n"); fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); fprintf(stderr, " -C comment Provide new comment.\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n"); #ifdef SMARTCARD fprintf(stderr, " -D reader Download public key from smartcard.\n"); fprintf(stderr, " -U reader Upload private key to smartcard.\n"); #endif /* SMARTCARD */ exit(1); } /* * Main program for key management. */ int main(int ac, char **av) { char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; char *reader_id = NULL; Key *private, *public; struct passwd *pw; struct stat st; int opt, type, fd, download = 0; FILE *f; extern int optind; extern char *optarg; __progname = get_progname(av[0]); SSLeay_add_all_algorithms(); /* we need this for the home * directory. */ pw = getpwuid(getuid()); if (!pw) { printf("You don't exist, go away!\n"); exit(1); } if (gethostname(hostname, sizeof(hostname)) < 0) { perror("gethostname"); exit(1); } while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) { switch (opt) { case 'b': bits = atoi(optarg); if (bits < 512 || bits > 32768) { printf("Bits has bad value.\n"); exit(1); } break; case 'l': print_fingerprint = 1; break; case 'B': print_bubblebabble = 1; break; case 'p': change_passphrase = 1; break; case 'c': change_comment = 1; break; case 'f': strlcpy(identity_file, optarg, sizeof(identity_file)); have_identity = 1; break; case 'P': identity_passphrase = optarg; break; case 'N': identity_new_passphrase = optarg; break; case 'C': identity_comment = optarg; break; case 'q': quiet = 1; break; case 'R': /* unused */ exit(0); break; case 'e': case 'x': /* export key */ convert_to_ssh2 = 1; break; case 'i': case 'X': /* import key */ convert_from_ssh2 = 1; break; case 'y': print_public = 1; break; case 'd': key_type_name = "dsa"; break; case 't': key_type_name = optarg; break; case 'D': download = 1; case 'U': reader_id = optarg; break; case '?': default: usage(); } } if (optind < ac) { printf("Too many arguments.\n"); usage(); } if (change_passphrase && change_comment) { printf("Can only have one of -p and -c.\n"); usage(); } if (print_fingerprint || print_bubblebabble) do_fingerprint(pw); if (change_passphrase) do_change_passphrase(pw); if (convert_to_ssh2) do_convert_to_ssh2(pw); if (change_comment) do_change_comment(pw); if (print_public) do_print_public(pw); if (reader_id != NULL) { #ifdef SMARTCARD if (download) do_download(pw, reader_id); else do_upload(pw, reader_id); #else /* SMARTCARD */ fatal("no support for smartcards."); #endif /* SMARTCARD */ } init_rng(); seed_rng(); arc4random_stir(); if (convert_from_ssh2) do_convert_from_ssh2(pw); if (key_type_name == NULL) { printf("You must specify a key type (-t).\n"); usage(); } type = key_type_from_name(key_type_name); if (type == KEY_UNSPEC) { fprintf(stderr, "unknown key type %s\n", key_type_name); exit(1); } if (!quiet) printf("Generating public/private %s key pair.\n", key_type_name); private = key_generate(type, bits); if (private == NULL) { fprintf(stderr, "key_generate failed"); exit(1); } public = key_from_private(private); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn\'t already exist. */ snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); if (strstr(identity_file, dotsshdir) != NULL && stat(dotsshdir, &st) < 0) { if (mkdir(dotsshdir, 0700) < 0) error("Could not create directory '%s'.", dotsshdir); else if (!quiet) printf("Created directory '%s'.\n", dotsshdir); } /* If the file already exists, ask the user to confirm. */ if (stat(identity_file, &st) >= 0) { char yesno[3]; printf("%s already exists.\n", identity_file); printf("Overwrite (y/n)? "); fflush(stdout); if (fgets(yesno, sizeof(yesno), stdin) == NULL) exit(1); if (yesno[0] != 'y' && yesno[0] != 'Y') exit(1); } /* Ask for a passphrase (twice). */ if (identity_passphrase) passphrase1 = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase1 = xstrdup(identity_new_passphrase); else { passphrase_again: passphrase1 = read_passphrase("Enter passphrase (empty for no " "passphrase): ", RP_ALLOW_STDIN); passphrase2 = read_passphrase("Enter same passphrase again: ", RP_ALLOW_STDIN); if (strcmp(passphrase1, passphrase2) != 0) { /* * The passphrases do not match. Clear them and * retry. */ memset(passphrase1, 0, strlen(passphrase1)); memset(passphrase2, 0, strlen(passphrase2)); xfree(passphrase1); xfree(passphrase2); printf("Passphrases do not match. Try again.\n"); goto passphrase_again; } /* Clear the other copy of the passphrase. */ memset(passphrase2, 0, strlen(passphrase2)); xfree(passphrase2); } if (identity_comment) { strlcpy(comment, identity_comment, sizeof(comment)); } else { /* Create default commend field for the passphrase. */ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } /* Save the key with the given passphrase and comment. */ if (!key_save_private(private, identity_file, passphrase1, comment)) { printf("Saving the key failed: %s.\n", identity_file); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); exit(1); } /* Clear the passphrase. */ memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); /* Clear the private key and the random number generator. */ key_free(private); arc4random_stir(); if (!quiet) printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } f = fdopen(fd, "w"); if (f == NULL) { printf("fdopen %s failed", identity_file); exit(1); } if (!key_write(public, f)) fprintf(stderr, "write key failed"); fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); printf("Your public key has been saved in %s.\n", identity_file); printf("The key fingerprint is:\n"); printf("%s %s\n", fp, comment); xfree(fp); } key_free(public); exit(0); } diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c index 3e66294e9f8c..782279bad23b 100644 --- a/crypto/openssh/ssh-rsa.c +++ b/crypto/openssh/ssh-rsa.c @@ -1,183 +1,181 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: ssh-rsa.c,v 1.20 2002/06/10 16:53:06 stevesk Exp $"); +RCSID("$OpenBSD: ssh-rsa.c,v 1.21 2002/06/23 03:30:17 deraadt Exp $"); #include #include #include "xmalloc.h" #include "log.h" #include "buffer.h" #include "bufaux.h" #include "key.h" #include "ssh-rsa.h" #include "compat.h" #include "ssh.h" /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int -ssh_rsa_sign( - Key *key, - u_char **sigp, u_int *lenp, +ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) { const EVP_MD *evp_md; EVP_MD_CTX md; u_char digest[EVP_MAX_MD_SIZE], *sig, *ret; u_int slen, dlen, len; int ok, nid; Buffer b; if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { error("ssh_rsa_sign: no RSA key"); return -1; } nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); return -1; } EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); slen = RSA_size(key->rsa); sig = xmalloc(slen); ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); memset(digest, 'd', sizeof(digest)); if (ok != 1) { int ecode = ERR_get_error(); - error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL)); + error("ssh_rsa_sign: RSA_sign failed: %s", + ERR_error_string(ecode, NULL)); xfree(sig); return -1; } if (len < slen) { int diff = slen - len; - debug("slen %d > len %d", slen, len); + debug("slen %u > len %u", slen, len); memmove(sig + diff, sig, len); memset(sig, 0, diff); } else if (len > slen) { - error("ssh_rsa_sign: slen %d slen2 %d", slen, len); + error("ssh_rsa_sign: slen %u slen2 %u", slen, len); xfree(sig); return -1; } /* encode signature */ buffer_init(&b); buffer_put_cstring(&b, "ssh-rsa"); buffer_put_string(&b, sig, slen); len = buffer_len(&b); ret = xmalloc(len); memcpy(ret, buffer_ptr(&b), len); buffer_free(&b); memset(sig, 's', slen); xfree(sig); if (lenp != NULL) *lenp = len; if (sigp != NULL) *sigp = ret; return 0; } int -ssh_rsa_verify( - Key *key, - u_char *signature, u_int signaturelen, +ssh_rsa_verify(Key *key, u_char *signature, u_int signaturelen, u_char *data, u_int datalen) { Buffer b; const EVP_MD *evp_md; EVP_MD_CTX md; char *ktype; u_char digest[EVP_MAX_MD_SIZE], *sigblob; u_int len, dlen, modlen; int rlen, ret, nid; if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { error("ssh_rsa_verify: no RSA key"); return -1; } if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); return -1; } buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_string(&b, NULL); if (strcmp("ssh-rsa", ktype) != 0) { error("ssh_rsa_verify: cannot handle type %s", ktype); buffer_free(&b); xfree(ktype); return -1; } xfree(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("ssh_rsa_verify: remaining bytes in signature %d", rlen); xfree(sigblob); return -1; } /* RSA_verify expects a signature of RSA_size */ modlen = RSA_size(key->rsa); if (len > modlen) { - error("ssh_rsa_verify: len %d > modlen %d", len, modlen); + error("ssh_rsa_verify: len %u > modlen %u", len, modlen); xfree(sigblob); return -1; } else if (len < modlen) { int diff = modlen - len; - debug("ssh_rsa_verify: add padding: modlen %d > len %d", + debug("ssh_rsa_verify: add padding: modlen %u > len %u", modlen, len); sigblob = xrealloc(sigblob, modlen); memmove(sigblob + diff, sigblob, len); memset(sigblob, 0, diff); len = modlen; } nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); xfree(sigblob); return -1; } EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); memset(digest, 'd', sizeof(digest)); memset(sigblob, 's', len); xfree(sigblob); if (ret == 0) { int ecode = ERR_get_error(); - error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL)); + error("ssh_rsa_verify: RSA_verify failed: %s", + ERR_error_string(ecode, NULL)); } debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); return ret; } diff --git a/crypto/openssh/tildexpand.c b/crypto/openssh/tildexpand.c index e89a7ade8acd..cbe981146730 100644 --- a/crypto/openssh/tildexpand.c +++ b/crypto/openssh/tildexpand.c @@ -1,72 +1,73 @@ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" -RCSID("$OpenBSD: tildexpand.c,v 1.12 2001/08/11 22:51:27 jakob Exp $"); +RCSID("$OpenBSD: tildexpand.c,v 1.13 2002/06/23 03:25:50 deraadt Exp $"); #include "xmalloc.h" #include "log.h" #include "tildexpand.h" /* * Expands tildes in the file name. Returns data allocated by xmalloc. * Warning: this calls getpw*. */ char * tilde_expand_filename(const char *filename, uid_t my_uid) { const char *cp; u_int userlen; char *expanded; struct passwd *pw; char user[100]; int len; /* Return immediately if no tilde. */ if (filename[0] != '~') return xstrdup(filename); /* Skip the tilde. */ filename++; /* Find where the username ends. */ cp = strchr(filename, '/'); if (cp) userlen = cp - filename; /* Something after username. */ else userlen = strlen(filename); /* Nothing after username. */ if (userlen == 0) pw = getpwuid(my_uid); /* Own home directory. */ else { /* Tilde refers to someone elses home directory. */ if (userlen > sizeof(user) - 1) fatal("User name after tilde too long."); memcpy(user, filename, userlen); user[userlen] = 0; pw = getpwnam(user); } if (!pw) fatal("Unknown user %100s.", user); /* If referring to someones home directory, return it now. */ if (!cp) { /* Only home directory specified */ return xstrdup(pw->pw_dir); } /* Build a path combining the specified directory and path. */ len = strlen(pw->pw_dir) + strlen(cp + 1) + 2; if (len > MAXPATHLEN) fatal("Home directory too long (%d > %d", len-1, MAXPATHLEN-1); expanded = xmalloc(len); - snprintf(expanded, len, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", cp + 1); + snprintf(expanded, len, "%s%s%s", pw->pw_dir, + strcmp(pw->pw_dir, "/") ? "/" : "", cp + 1); return expanded; }